summaryrefslogtreecommitdiff
path: root/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2024-01-10 03:03:23 +0000
committerNorbert Preining <norbert@preining.info>2024-01-10 03:03:23 +0000
commitcdb8117b8f1ac752d1927b82759c5be9f0ec0ab5 (patch)
treeebd07d36ab12076de3523b744cc87f975747f3e0 /macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi
parent140e2f7f1509acd423172e2895d0d7839e5b88c6 (diff)
CTAN sync 202401100303
Diffstat (limited to 'macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi')
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.c93
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.pm150
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.xs61
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.c717
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.h5
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/close.c255
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.awk71
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.c511
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.txt573
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_ids.h7
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.c48
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.h31
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.c9
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.h4
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.c162
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.h37
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.c136
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.h1
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.c2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.h2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.c103
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.h18
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.c381
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.h2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.awk2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.c24
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.h24
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.txt28
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/end_line.c1598
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/errors.c23
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/extra.c148
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.c806
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.h19
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.c107
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.h5
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.c421
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.h17
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.c328
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.h21
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.c737
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.h5
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/menus.c289
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/multitable.c131
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.c1481
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.h76
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/separator.c405
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.c272
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.h31
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.c2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.h2
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.c238
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.h5
-rw-r--r--macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree_types.h107
53 files changed, 6300 insertions, 4431 deletions
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.c
index 565c42e7b4..3966f5b244 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.c
@@ -7,6 +7,21 @@
*/
#line 1 "parsetexi/Parsetexi.xs"
+/* Copyright 2014-2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
#include <config.h>
/* Avoid namespace conflicts. */
@@ -15,6 +30,9 @@
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
+#if defined _WIN32 && !defined __CYGWIN__
+# undef free
+#endif
#include "XSUB.h"
#undef context
@@ -26,7 +44,7 @@
#include "indices.h"
#include "input.h"
-#line 30 "parsetexi/Parsetexi.c"
+#line 48 "parsetexi/Parsetexi.c"
#ifndef PERL_UNUSED_VAR
# define PERL_UNUSED_VAR(var) if (0) var = var
#endif
@@ -170,7 +188,7 @@ S_croak_xs_usage(const CV *const cv, const char *const params)
# define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif
-#line 174 "parsetexi/Parsetexi.c"
+#line 192 "parsetexi/Parsetexi.c"
XS_EUPXS(XS_Texinfo__Parser_init); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Texinfo__Parser_init)
@@ -181,8 +199,7 @@ XS_EUPXS(XS_Texinfo__Parser_init)
{
int texinfo_uninstalled = (int)SvIV(ST(0))
;
- char * srcdir = (char *)SvPV_nolen(ST(1))
-;
+ char * srcdir = (char *)SvPVbyte_nolen(ST(1));
int RETVAL;
dXSTARG;
@@ -214,8 +231,7 @@ XS_EUPXS(XS_Texinfo__Parser_parse_file)
if (items != 1)
croak_xs_usage(cv, "filename");
{
- char * filename = (char *)SvPV_nolen(ST(0))
-;
+ char * filename = (char *)SvPVbyte_nolen(ST(0));
int RETVAL;
dXSTARG;
@@ -233,8 +249,7 @@ XS_EUPXS(XS_Texinfo__Parser_parse_piece)
if (items != 2)
croak_xs_usage(cv, "string, line_nr");
{
- char * string = (char *)SvPV_nolen(ST(0))
-;
+ char * string = (char *)SvPVbyte_nolen(ST(0));
int line_nr = (int)SvIV(ST(1))
;
@@ -251,8 +266,7 @@ XS_EUPXS(XS_Texinfo__Parser_parse_string)
if (items != 2)
croak_xs_usage(cv, "string, line_nr");
{
- char * string = (char *)SvPV_nolen(ST(0))
-;
+ char * string = (char *)SvPVbyte_nolen(ST(0));
int line_nr = (int)SvIV(ST(1))
;
@@ -269,8 +283,7 @@ XS_EUPXS(XS_Texinfo__Parser_parse_text)
if (items != 2)
croak_xs_usage(cv, "string, line_nr");
{
- char * string = (char *)SvPV_nolen(ST(0))
-;
+ char * string = (char *)SvPVbyte_nolen(ST(0));
int line_nr = (int)SvIV(ST(1))
;
@@ -287,10 +300,8 @@ XS_EUPXS(XS_Texinfo__Parser_store_value)
if (items != 2)
croak_xs_usage(cv, "name, value");
{
- char * name = (char *)SvPV_nolen(ST(0))
-;
- char * value = (char *)SvPV_nolen(ST(1))
-;
+ char * name = (char *)SvPVbyte_nolen(ST(0));
+ char * value = (char *)SvPVbyte_nolen(ST(1));
store_value(name, value);
}
@@ -347,8 +358,7 @@ XS_EUPXS(XS_Texinfo__Parser_add_include_directory)
if (items != 1)
croak_xs_usage(cv, "filename");
{
- char * filename = (char *)SvPV_nolen(ST(0))
-;
+ char * filename = (char *)SvPVbyte_nolen(ST(0));
add_include_directory(filename);
}
@@ -377,8 +387,8 @@ XS_EUPXS(XS_Texinfo__Parser_build_texinfo_tree)
}
-XS_EUPXS(XS_Texinfo__Parser_build_label_list); /* prototype to pass -Wmissing-prototypes */
-XS_EUPXS(XS_Texinfo__Parser_build_label_list)
+XS_EUPXS(XS_Texinfo__Parser_build_target_elements_list); /* prototype to pass -Wmissing-prototypes */
+XS_EUPXS(XS_Texinfo__Parser_build_target_elements_list)
{
dVAR; dXSARGS;
if (items != 0)
@@ -386,7 +396,7 @@ XS_EUPXS(XS_Texinfo__Parser_build_label_list)
{
AV * RETVAL;
- RETVAL = build_label_list();
+ RETVAL = build_target_elements_list();
{
SV * RETVALSV;
RETVALSV = newRV((SV*)RETVAL);
@@ -507,11 +517,13 @@ XS_EUPXS(XS_Texinfo__Parser_reset_parser); /* prototype to pass -Wmissing-protot
XS_EUPXS(XS_Texinfo__Parser_reset_parser)
{
dVAR; dXSARGS;
- if (items != 0)
- croak_xs_usage(cv, "");
+ if (items != 1)
+ croak_xs_usage(cv, "debug_output");
{
+ int debug_output = (int)SvIV(ST(0))
+;
- reset_parser();
+ reset_parser(debug_output);
}
XSRETURN_EMPTY;
}
@@ -538,8 +550,7 @@ XS_EUPXS(XS_Texinfo__Parser_add_expanded_format)
if (items != 1)
croak_xs_usage(cv, "format");
{
- char * format = (char *)SvPV_nolen(ST(0))
-;
+ char * format = (char *)SvPVbyte_nolen(ST(0));
add_expanded_format(format);
}
@@ -595,6 +606,22 @@ XS_EUPXS(XS_Texinfo__Parser_conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME)
}
+XS_EUPXS(XS_Texinfo__Parser_conf_set_MAX_MACRO_CALL_NESTING); /* prototype to pass -Wmissing-prototypes */
+XS_EUPXS(XS_Texinfo__Parser_conf_set_MAX_MACRO_CALL_NESTING)
+{
+ dVAR; dXSARGS;
+ if (items != 1)
+ croak_xs_usage(cv, "i");
+ {
+ int i = (int)SvIV(ST(0))
+;
+
+ conf_set_MAX_MACRO_CALL_NESTING(i);
+ }
+ XSRETURN_EMPTY;
+}
+
+
XS_EUPXS(XS_Texinfo__Parser_set_DOC_ENCODING_FOR_INPUT_FILE_NAME); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Texinfo__Parser_set_DOC_ENCODING_FOR_INPUT_FILE_NAME)
{
@@ -618,8 +645,7 @@ XS_EUPXS(XS_Texinfo__Parser_conf_set_input_file_name_encoding)
if (items != 1)
croak_xs_usage(cv, "value");
{
- char * value = (char *)SvPV_nolen(ST(0))
-;
+ char * value = (char *)SvPVbyte_nolen(ST(0));
conf_set_input_file_name_encoding(value);
}
@@ -634,8 +660,7 @@ XS_EUPXS(XS_Texinfo__Parser_conf_set_locale_encoding)
if (items != 1)
croak_xs_usage(cv, "value");
{
- char * value = (char *)SvPV_nolen(ST(0))
-;
+ char * value = (char *)SvPVbyte_nolen(ST(0));
conf_set_locale_encoding(value);
}
@@ -650,8 +675,7 @@ XS_EUPXS(XS_Texinfo__Parser_conf_set_documentlanguage_override)
if (items != 1)
croak_xs_usage(cv, "value");
{
- char * value = (char *)SvPV_nolen(ST(0))
-;
+ char * value = (char *)SvPVbyte_nolen(ST(0));
conf_set_documentlanguage_override(value);
}
@@ -749,18 +773,19 @@ XS_EXTERNAL(boot_Texinfo__Parser)
(void)newXSproto_portable("Texinfo::Parser::init_index_commands", XS_Texinfo__Parser_init_index_commands, file, "");
(void)newXSproto_portable("Texinfo::Parser::add_include_directory", XS_Texinfo__Parser_add_include_directory, file, "$");
(void)newXSproto_portable("Texinfo::Parser::build_texinfo_tree", XS_Texinfo__Parser_build_texinfo_tree, file, "");
- (void)newXSproto_portable("Texinfo::Parser::build_label_list", XS_Texinfo__Parser_build_label_list, file, "");
+ (void)newXSproto_portable("Texinfo::Parser::build_target_elements_list", XS_Texinfo__Parser_build_target_elements_list, file, "");
(void)newXSproto_portable("Texinfo::Parser::build_internal_xref_list", XS_Texinfo__Parser_build_internal_xref_list, file, "");
(void)newXSproto_portable("Texinfo::Parser::build_float_list", XS_Texinfo__Parser_build_float_list, file, "");
(void)newXSproto_portable("Texinfo::Parser::build_index_data", XS_Texinfo__Parser_build_index_data, file, "");
(void)newXSproto_portable("Texinfo::Parser::build_global_info", XS_Texinfo__Parser_build_global_info, file, "");
(void)newXSproto_portable("Texinfo::Parser::build_global_info2", XS_Texinfo__Parser_build_global_info2, file, "");
- (void)newXSproto_portable("Texinfo::Parser::reset_parser", XS_Texinfo__Parser_reset_parser, file, "");
+ (void)newXSproto_portable("Texinfo::Parser::reset_parser", XS_Texinfo__Parser_reset_parser, file, "$");
(void)newXSproto_portable("Texinfo::Parser::clear_expanded_formats", XS_Texinfo__Parser_clear_expanded_formats, file, "");
(void)newXSproto_portable("Texinfo::Parser::add_expanded_format", XS_Texinfo__Parser_add_expanded_format, file, "$");
(void)newXSproto_portable("Texinfo::Parser::conf_set_show_menu", XS_Texinfo__Parser_conf_set_show_menu, file, "$");
(void)newXSproto_portable("Texinfo::Parser::conf_set_CPP_LINE_DIRECTIVES", XS_Texinfo__Parser_conf_set_CPP_LINE_DIRECTIVES, file, "$");
(void)newXSproto_portable("Texinfo::Parser::conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME", XS_Texinfo__Parser_conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME, file, "$");
+ (void)newXSproto_portable("Texinfo::Parser::conf_set_MAX_MACRO_CALL_NESTING", XS_Texinfo__Parser_conf_set_MAX_MACRO_CALL_NESTING, file, "$");
(void)newXSproto_portable("Texinfo::Parser::set_DOC_ENCODING_FOR_INPUT_FILE_NAME", XS_Texinfo__Parser_set_DOC_ENCODING_FOR_INPUT_FILE_NAME, file, "$");
(void)newXSproto_portable("Texinfo::Parser::conf_set_input_file_name_encoding", XS_Texinfo__Parser_conf_set_input_file_name_encoding, file, "$");
(void)newXSproto_portable("Texinfo::Parser::conf_set_locale_encoding", XS_Texinfo__Parser_conf_set_locale_encoding, file, "$");
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.pm b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.pm
index 25f3672ae1..d516e8b911 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.pm
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.pm
@@ -1,4 +1,4 @@
-# Copyright 2014-2022 Free Software Foundation, Inc.
+# Copyright 2014-2023 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@
package Texinfo::Parser;
-use 5.00405;
+use 5.008;
use strict;
use warnings;
@@ -54,6 +54,7 @@ use warnings;
use Storable qw(dclone); # standard in 5.007003
use Encode qw(decode);
+use File::Basename; # for fileparse
use Texinfo::Common;
use Texinfo::Report;
@@ -94,7 +95,6 @@ sub parser (;$$)
my $parser = dclone(\%parser_default_configuration);
- reset_parser ();
if (defined($conf)) {
foreach my $key (keys (%$conf)) {
# Copy conf to parser object.
@@ -104,28 +104,42 @@ sub parser (;$$)
} else {
$parser->{$key} = $conf->{$key};
}
+ }
+ }
+ # pass directly DEBUG configuration to reset_parser to override previous
+ # parser configuration, as the configuration isn't already reset and the new
+ # configuration is set afterwards.
+ my $debug = 0;
+ $debug = $parser->{'DEBUG'} if ($parser->{'DEBUG'});
+ reset_parser ($debug);
+
+ if (defined($conf)) {
+ foreach my $key (keys (%$conf)) {
if ($key eq 'INCLUDE_DIRECTORIES') {
+ # the directories from the command line or the input file name
+ # are already byte strings (or ascii). The encoding was detected
+ # as COMMAND_LINE_ENCODING, but it is not useful for the XS parser.
foreach my $d (@{$conf->{'INCLUDE_DIRECTORIES'}}) {
add_include_directory ($d);
}
} elsif ($key eq 'values') {
- for my $v (keys %{$conf->{'values'}}) {
- if (ref($conf->{'values'}->{$v}) eq '') {
- store_value ($v, $conf->{'values'}->{$v});
- } else {
- warn "bug: non-scalar \@value\n";
- }
+ for my $flag (keys %{$conf->{'values'}}) {
+ my $bytes_flag = Encode::encode('utf-8', $flag);
+ my $bytes_value = Encode::encode('utf-8', $conf->{'values'}->{$flag});
+ store_value ($bytes_flag, $bytes_value);
}
} elsif ($key eq 'EXPANDED_FORMATS') {
clear_expanded_formats ();
for my $f (@{$conf->{$key}}) {
- add_expanded_format ($f);
+ my $utf8_bytes = Encode::encode('utf-8', $f);
+ add_expanded_format ($utf8_bytes);
}
} elsif ($key eq 'documentlanguage') {
if (defined ($conf->{$key})) {
- conf_set_documentlanguage_override ($conf->{$key});
+ my $utf8_bytes = Encode::encode('utf-8', $conf->{$key});
+ conf_set_documentlanguage_override ($utf8_bytes);
}
} elsif ($key eq 'FORMAT_MENU') {
if ($conf->{$key} eq 'menu') {
@@ -137,14 +151,18 @@ sub parser (;$$)
conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME ($conf->{$key});
} elsif ($key eq 'CPP_LINE_DIRECTIVES') {
conf_set_CPP_LINE_DIRECTIVES($conf->{$key});
+ } elsif ($key eq 'MAX_MACRO_CALL_NESTING') {
+ conf_set_MAX_MACRO_CALL_NESTING($conf->{$key});
} elsif ($key eq 'DEBUG') {
set_debug($conf->{$key}) if $conf->{$key};
} elsif ($key eq 'DOC_ENCODING_FOR_INPUT_FILE_NAME') {
set_DOC_ENCODING_FOR_INPUT_FILE_NAME ($conf->{$key});
} elsif ($key eq 'INPUT_FILE_NAME_ENCODING' and defined($conf->{$key})) {
- conf_set_input_file_name_encoding ($conf->{$key});
+ my $utf8_bytes = Encode::encode('utf-8', $conf->{$key});
+ conf_set_input_file_name_encoding ($utf8_bytes);
} elsif ($key eq 'LOCALE_ENCODING' and defined($conf->{$key})) {
- conf_set_locale_encoding ($conf->{$key});
+ my $utf8_bytes = Encode::encode('utf-8', $conf->{$key});
+ conf_set_locale_encoding ($utf8_bytes);
} elsif ($key eq 'accept_internalvalue') {
set_accept_internalvalue();
} elsif ($key eq 'registrar' or $key eq 'COMMAND_LINE_ENCODING') {
@@ -175,18 +193,18 @@ sub _find_menus_of_node {
}
}
-# Set 'menus' array for each node. This accounts for malformed input where
-# the number of sectioning commands between @node and @menu is not exactly 1.
+# Set 'menus' array for each node. This accounts for input where
+# the number of sectioning commands between @node and @menu is not 1.
sub _associate_node_menus {
my $self = shift;
my $root = shift;
- my $node;
+ my $current_node;
foreach my $child (@{$root->{'contents'}}) {
if ($child->{'cmdname'} and $child->{'cmdname'} eq 'node') {
- $node = $child;
+ $current_node = $child;
}
- _find_menus_of_node ($node, $child) unless !defined $node;
+ _find_menus_of_node ($current_node, $child) if (defined($current_node));
}
}
@@ -207,13 +225,14 @@ sub _set_errors_node_lists_labels_indices($)
{
my $self = shift;
- my $TARGETS = build_label_list ();
+ my $TARGETS = build_target_elements_list ();
$self->{'targets'} = $TARGETS;
_get_errors ($self);
# Setup labels info and nodes list based on 'targets'
Texinfo::Convert::NodeNameNormalization::set_nodes_list_labels($self,
$self->{'registrar'}, $self);
+ Texinfo::Convert::NodeNameNormalization::set_float_types($self);
my $INDEX_NAMES = build_index_data ();
$self->{'index_names'} = $INDEX_NAMES;
@@ -226,27 +245,39 @@ sub get_parser_info {
my ($INTL_XREFS, $FLOATS, $ERRORS, $GLOBAL_INFO, $GLOBAL_INFO2);
$INTL_XREFS = build_internal_xref_list ();
- $FLOATS = build_float_list ();
+ # done for now in _set_errors_node_lists_labels_indices, could
+ # be redone here when float types are set in the parser
+ #$FLOATS = build_float_list ();
$GLOBAL_INFO = build_global_info ();
$GLOBAL_INFO2 = build_global_info2 ();
$self->{'internal_references'} = $INTL_XREFS;
- $self->{'floats'} = $FLOATS;
+ #$self->{'floats'} = $FLOATS;
$self->{'info'} = $GLOBAL_INFO;
$self->{'commands_info'} = $GLOBAL_INFO2;
_set_errors_node_lists_labels_indices($self);
-}
-use File::Basename; # for fileparse
+ my ($registrar, $configuration_information)
+ = _get_error_registrar($self);
+
+ $self->{'info'}->{'input_perl_encoding'} = 'utf-8';
+ my $perl_encoding
+ = Texinfo::Common::get_perl_encoding($self->{'commands_info'},
+ $registrar, $configuration_information);
+ $self->{'info'}->{'input_perl_encoding'} = $perl_encoding
+ if (defined($perl_encoding));
+}
-# Replacement for Texinfo::Parser::parse_texi_file
sub parse_texi_file ($$)
{
my $self = shift;
my $input_file_path = shift;
my $tree_stream;
+ # the file is already a byte string, taken as is from the command
+ # line. The encoding was detected as COMMAND_LINE_ENCODING, but
+ # it is not useful for the XS parser.
my $status = parse_file ($input_file_path);
if ($status) {
my ($registrar, $configuration_information) = _get_error_registrar($self);
@@ -287,40 +318,36 @@ sub _get_errors($)
my $ERRORS = get_errors ();
for my $error (@{$ERRORS}) {
+ # The message output in case of debugging set is already issued by
+ # the parser, therefore we set the optional argument to silence
+ # the same message that could be output here.
if ($error->{'type'} eq 'error') {
$registrar->line_error ($configuration_information,
- $error->{'message'}, $error->{'source_info'});
+ $error->{'message'}, $error->{'source_info'},
+ undef, 1);
} else {
$registrar->line_warn ($configuration_information,
- $error->{'message'}, $error->{'source_info'});
+ $error->{'message'}, $error->{'source_info'},
+ undef, 1);
}
}
}
-# Replacement for Texinfo::Parser::parse_texi_piece
-#
# Used in tests under tp/t.
-sub parse_texi_piece($$;$$$$)
+sub parse_texi_piece($$;$)
{
- my $self = shift;
- my $text = shift;
- my $lines_nr = shift;
- my $file = shift;
- my $macro = shift;
- my $fixed_line_number = shift;
+ my ($self, $text, $line_nr) = @_;
return undef if (!defined($text));
- $lines_nr = 1 if (not defined($lines_nr));
+ $line_nr = 1 if (not defined($line_nr));
$self = parser() if (!defined($self));
- # make sure that internal byte buffer is in UTF-8 before we pass
- # it in to the XS code.
- utf8::upgrade($text);
-
- parse_piece($text, $lines_nr);
+ # pass a binary UTF-8 encoded string to C code
+ my $utf8_bytes = Encode::encode('utf-8', $text);
+ parse_piece($utf8_bytes, $line_nr);
my $tree = build_texinfo_tree ();
get_parser_info($self);
@@ -329,29 +356,20 @@ sub parse_texi_piece($$;$$$$)
return $tree;
}
-# Replacement for Texinfo::Parser::parse_texi_text
-#
# Used in tests under tp/t.
-sub parse_texi_text($$;$$$$)
+sub parse_texi_text($$;$)
{
- my $self = shift;
- my $text = shift;
- my $lines_nr = shift;
- my $file = shift;
- my $macro = shift;
- my $fixed_line_number = shift;
+ my ($self, $text, $line_nr) = @_;
return undef if (!defined($text));
- $lines_nr = 1 if (not defined($lines_nr));
+ $line_nr = 1 if (not defined($line_nr));
$self = parser() if (!defined($self));
- # make sure that internal byte buffer is in UTF-8 before we pass
- # it in to the XS code.
- utf8::upgrade($text);
-
- parse_text($text, $lines_nr);
+ # pass a binary UTF-8 encoded string to C code
+ my $utf8_bytes = Encode::encode('utf-8', $text);
+ parse_text($utf8_bytes, $line_nr);
my $tree = build_texinfo_tree ();
get_parser_info($self);
@@ -364,23 +382,19 @@ sub parse_texi_text($$;$$$$)
return $tree;
}
-# Replacement for Texinfo::Parser::parse_texi_line
-sub parse_texi_line($$;$$$$)
+sub parse_texi_line($$;$)
{
- my $self = shift;
- my $text = shift;
- my $lines_nr = shift;
- my $file = shift;
- my $macro = shift;
- my $fixed_line_number = shift;
+ my ($self, $text, $line_nr) = @_;
return undef if (!defined($text));
- $lines_nr = 1 if (not defined($lines_nr));
+ $line_nr = 1 if (not defined($line_nr));
$self = parser() if (!defined($self));
- utf8::upgrade($text);
- parse_string($text, $lines_nr);
+
+ # pass a binary UTF-8 encoded string to C code
+ my $utf8_bytes = Encode::encode('utf-8', $text);
+ parse_string($utf8_bytes, $line_nr);
my $tree = build_texinfo_tree ();
_set_errors_node_lists_labels_indices($self);
@@ -388,7 +402,7 @@ sub parse_texi_line($$;$$$$)
return $tree;
}
-# Public interfaces of Texinfo::Parser
+# Public interfaces of Texinfo::Parser to gather information
sub indices_information($)
{
my $self = shift;
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.xs b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.xs
index d5972061fa..86c9aa78ae 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.xs
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/Parsetexi.xs
@@ -1,3 +1,18 @@
+/* Copyright 2014-2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
#include <config.h>
/* Avoid namespace conflicts. */
@@ -6,6 +21,9 @@
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
+#if defined _WIN32 && !defined __CYGWIN__
+# undef free
+#endif
#include "XSUB.h"
#undef context
@@ -21,37 +39,48 @@ MODULE = Texinfo::Parser PACKAGE = Texinfo::Parser
PROTOTYPES: ENABLE
+# Except for file paths, strings should be UTF-8 encoded.
+# In the declarations below, a comment shows that input string
+# is a file path, other input strings should be UTF-8 encoded.
+#
+# There is no need for the parser to know the file paths
+# encodings, they are never decoded/encoded but used as is
+# and passed as byte strings.
+
+# Called from Texinfo::XSLoader.pm. The arguments are not actually used.
+# file path, can be in any encoding
int
init (texinfo_uninstalled, srcdir)
int texinfo_uninstalled
- char *srcdir
+ char *srcdir = (char *)SvPVbyte_nolen($arg);
void
wipe_errors ()
+# file path, can be in any encoding
int
parse_file(filename)
- char * filename
+ char *filename = (char *)SvPVbyte_nolen($arg);
void
parse_piece(string, line_nr)
- char * string
+ char *string = (char *)SvPVbyte_nolen($arg);
int line_nr
void
parse_string(string, line_nr)
- char * string
+ char *string = (char *)SvPVbyte_nolen($arg);
int line_nr
void
parse_text(string, line_nr)
- char * string
+ char *string = (char *)SvPVbyte_nolen($arg);
int line_nr
void
store_value (name, value)
- char *name
- char *value
+ char *name = (char *)SvPVbyte_nolen($arg);
+ char *value = (char *)SvPVbyte_nolen($arg);
void
wipe_values ()
@@ -62,15 +91,16 @@ reset_context_stack ()
void
init_index_commands ()
+# file path, can be in any encoding
void
add_include_directory (filename)
- char *filename
+ char *filename = (char *)SvPVbyte_nolen($arg);
HV *
build_texinfo_tree ()
AV *
-build_label_list ()
+build_target_elements_list ()
AV *
build_internal_xref_list ()
@@ -88,14 +118,14 @@ HV *
build_global_info2 ()
void
-reset_parser ()
+reset_parser (int debug_output)
void
clear_expanded_formats ()
void
add_expanded_format (format)
- char *format
+ char *format = (char *)SvPVbyte_nolen($arg);
void
conf_set_show_menu (int i)
@@ -107,19 +137,22 @@ void
conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME (int i)
void
+conf_set_MAX_MACRO_CALL_NESTING (int i)
+
+void
set_DOC_ENCODING_FOR_INPUT_FILE_NAME (int i)
void
conf_set_input_file_name_encoding (value)
- char *value
+ char *value = (char *)SvPVbyte_nolen($arg);
void
conf_set_locale_encoding (value)
- char *value
+ char *value = (char *)SvPVbyte_nolen($arg);
void
conf_set_documentlanguage_override (value)
- char *value
+ char *value = (char *)SvPVbyte_nolen($arg);
void
set_debug (int i)
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.c
index 8066dcad0c..bc88640925 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -38,13 +38,15 @@
#include <string.h>
#include "parser.h"
+#include "debug.h"
+#include "tree.h"
#include "input.h"
+#include "source_marks.h"
#include "labels.h"
#include "indices.h"
+#include "errors.h"
#include "api.h"
-ELEMENT *Root;
-
#ifdef ENABLE_NLS
#define LOCALEDIR DATADIR "/locale"
@@ -111,12 +113,15 @@ reset_floats ()
floats_number = 0;
}
+static ELEMENT *Root;
+
void
reset_parser_except_conf (void)
{
- /* do before destroying tree because index entries usually refer to in-tree
+ /* do before destroying tree because index entries refer to in-tree
elements. */
wipe_indices ();
+
if (Root)
{
destroy_element_and_children (Root);
@@ -127,27 +132,50 @@ reset_parser_except_conf (void)
init_index_commands ();
wipe_errors ();
reset_context_stack ();
- reset_region_stack ();
+ reset_command_stack (&nesting_context.basic_inline_stack);
+ reset_command_stack (&nesting_context.basic_inline_stack_on_line);
+ reset_command_stack (&nesting_context.basic_inline_stack_block);
+ reset_command_stack (&nesting_context.regions_stack);
+ memset (&nesting_context, 0, sizeof (nesting_context));
reset_floats ();
wipe_global_info ();
+ /* it is not totally obvious that is it better to reset the
+ list to avoid memory leaks rather than reuse the iconv
+ opened handlers */
+ reset_encoding_list ();
set_input_encoding ("utf-8");
reset_internal_xrefs ();
reset_labels ();
input_reset_input_stack ();
+ source_marks_reset_counters ();
free_small_strings ();
+ reset_obstacks ();
+
current_node = current_section = current_part = 0;
}
void
-reset_parser (void)
+reset_parser (int debug_output)
{
- /* NOTE: Do not call 'malloc' or 'free' in this function or in any function
- called in this file. Since this file (api.c) includes the Perl headers,
+ dTHX;
+
+ /* NOTE: Do not call 'malloc' or 'free' in this function.
+
+ Since this file (api.c) includes the Perl headers,
we get the Perl redefinitions, which we do not want, as we don't use
them throughout the rest of the program. */
+ /* We cannot call debug() here, because the configuration of the previous
+ parser invokation has not been reset already, and new configuration has
+ not been read, so we need to pass the configuration information
+ directly */
+ /*
debug ("!!!!!!!!!!!!!!!! RESETTING THE PARSER !!!!!!!!!!!!!!!!!!!!!");
+ */
+ if (debug_output)
+ fprintf (stderr,
+ "!!!!!!!!!!!!!!!! RESETTING THE PARSER !!!!!!!!!!!!!!!!!!!!!\n");
reset_parser_except_conf ();
wipe_values ();
@@ -175,7 +203,6 @@ parse_file (char *filename)
debug_output = 0;
*/
char *p, *q;
- char c;
int status;
@@ -195,10 +222,10 @@ parse_file (char *filename)
if (p)
{
- c = *p;
+ char saved = *p;
*p = '\0';
add_include_directory (filename);
- *p = c;
+ *p = saved;
}
Root = parse_texi_document ();
@@ -212,7 +239,7 @@ void
parse_text (char *string, int line_nr)
{
reset_parser_except_conf ();
- input_push_text_with_line_nos (strdup (string), line_nr);
+ input_push_text (strdup (string), line_nr, 0, 0);
Root = parse_texi_document ();
}
@@ -221,10 +248,11 @@ parse_text (char *string, int line_nr)
void
parse_string (char *string, int line_nr)
{
- ELEMENT *root_elt = new_element (ET_root_line);
+ ELEMENT *root_elt;
reset_parser_except_conf ();
- input_push_text_with_line_nos (strdup (string), line_nr);
+ root_elt = new_element (ET_root_line);
+ input_push_text (strdup (string), line_nr, 0, 0);
Root = parse_texi (root_elt, root_elt);
}
@@ -232,11 +260,13 @@ parse_string (char *string, int line_nr)
void
parse_piece (char *string, int line_nr)
{
- ELEMENT *before_node_section = setup_document_root_and_before_node_section ();
- ELEMENT *document_root = before_node_section->parent;
+ ELEMENT *before_node_section, *document_root;
reset_parser_except_conf ();
- input_push_text_with_line_nos (strdup (string), line_nr);
+ before_node_section = setup_document_root_and_before_node_section ();
+ document_root = before_node_section->parent;
+
+ input_push_text (strdup (string), line_nr, 0, 0);
Root = parse_texi (document_root, before_node_section);
}
@@ -246,7 +276,11 @@ static void element_to_perl_hash (ELEMENT *e);
/* Return reference to Perl array built from e. If any of
the elements in E don't have 'hv' set, set it to an empty
hash table, or create it if there is no parent element, indicating the
- element is not in the tree. */
+ element is not in the tree.
+ Note that not having 'hv' set should be rare (actually never happen),
+ as the contents and args children are processed before the extra
+ information where build_perl_array is called.
+ */
static SV *
build_perl_array (ELEMENT_LIST *e)
{
@@ -258,10 +292,9 @@ build_perl_array (ELEMENT_LIST *e)
av = newAV ();
sv = newRV_inc ((SV *) av);
+
for (i = 0; i < e->number; i++)
{
- if (!e->list[i]) /* For arrays only, allow elements to be undef. */
- av_push (av, newSV (0));
if (!e->list[i]->hv)
{
if (e->list[i]->parent)
@@ -273,39 +306,11 @@ build_perl_array (ELEMENT_LIST *e)
element_to_perl_hash (e->list[i]);
}
}
- av_push (av, newRV_inc ((SV *) e->list[i]->hv));
+ av_store (av, i, newRV_inc ((SV *) e->list[i]->hv));
}
return sv;
}
-/* Return reference to hash corresponding to VALUE. */
-static SV *
-build_node_spec (NODE_SPEC_EXTRA *value)
-{
- HV *hv;
-
- dTHX;
-
- if (!value->manual_content && !value->node_content)
- return newSV(0); /* Perl 'undef' */
-
- hv = newHV ();
-
- if (value->manual_content)
- {
- hv_store (hv, "manual_content", strlen ("manual_content"),
- build_perl_array (&value->manual_content->contents), 0);
- }
-
- if (value->node_content)
- {
- hv_store (hv, "node_content", strlen ("node_content"),
- build_perl_array (&value->node_content->contents), 0);
- }
-
- return newRV_inc ((SV *)hv);
-}
-
/* Used to create a "Perl-internal" string that represents a sequence
of Unicode codepoints with no specific encoding. */
static SV *
@@ -319,143 +324,62 @@ newSVpv_utf8 (char *str, STRLEN len)
return sv;
}
-/* Set E->hv and 'hv' on E's descendants. e->parent->hv is assumed
- to already exist. */
static void
-element_to_perl_hash (ELEMENT *e)
+store_additional_info (ELEMENT *e, ASSOCIATED_INFO* a, char *key)
{
- SV *sv;
-
dTHX;
- /* e->hv may already exist if there was an extra value elsewhere
- referring to e. */
- if (!e->hv)
- {
- e->hv = newHV ();
- }
-
- if (e->parent)
- {
- if (!e->parent->hv)
- e->parent->hv = newHV ();
- sv = newRV_inc ((SV *) e->parent->hv);
- hv_store (e->hv, "parent", strlen ("parent"), sv, 0);
- }
-
- if (e->type)
- {
- sv = newSVpv (element_type_names[e->type], 0);
- hv_store (e->hv, "type", strlen ("type"), sv, 0);
- }
-
- if (e->cmd)
- {
- sv = newSVpv (command_name(e->cmd), 0);
- hv_store (e->hv, "cmdname", strlen ("cmdname"), sv, 0);
-
- /* Note we could optimize the call to newSVpv here and
- elsewhere by passing an appropriate second argument. */
- }
-
- if (e->contents.number > 0)
- {
- AV *av;
- int i;
-
- av = newAV ();
- sv = newRV_inc ((SV *) av);
- hv_store (e->hv, "contents", strlen ("contents"), sv, 0);
- for (i = 0; i < e->contents.number; i++)
- {
- element_to_perl_hash (e->contents.list[i]);
- sv = newRV_inc ((SV *) e->contents.list[i]->hv);
- av_push (av, sv);
- }
- }
-
- if (e->args.number > 0)
+ if (a->info_number > 0)
{
- AV *av;
+ HV *extra;
int i;
+ int nr_info = 0; /* number of info type stored */
- av = newAV ();
- sv = newRV_inc ((SV *) av);
- hv_store (e->hv, "args", strlen ("args"), sv, 0);
- for (i = 0; i < e->args.number; i++)
- {
- element_to_perl_hash (e->args.list[i]);
- sv = newRV_inc ((SV *) e->args.list[i]->hv);
- av_push (av, sv);
- }
- }
- if (e->text.space > 0)
- {
- sv = newSVpv_utf8 (e->text.text, e->text.end);
- hv_store (e->hv, "text", strlen ("text"), sv, 0);
- }
-
- if (e->extra_number > 0)
- {
- HV *extra;
- int i;
- int all_deleted = 1;
- extra = newHV ();
+ /* Use sv_2mortal so that reference count is decremented if
+ the hash is not saved. */
+ extra = (HV *) sv_2mortal((SV *)newHV ());
- for (i = 0; i < e->extra_number; i++)
+ for (i = 0; i < a->info_number; i++)
{
#define STORE(sv) hv_store (extra, key, strlen (key), sv, 0)
- char *key = e->extra[i].key;
- ELEMENT *f = e->extra[i].value;
+ char *key = a->info[i].key;
+ ELEMENT *f = (ELEMENT *) a->info[i].value;
- if (e->extra[i].type == extra_deleted)
+ if (a->info[i].type == extra_deleted)
continue;
- all_deleted = 0;
+ nr_info++;
- switch (e->extra[i].type)
+ switch (a->info[i].type)
{
case extra_element:
/* For references to other parts of the tree, create the hash so
- we can point to it. */
+ we can point to it. */
+ /* Note that this does not happen much, as the contents
+ and args are processed before the extra information. It only
+ happens for root commands (sections, nodes) and associated
+ commands, and could also happen for subentry as it is not
+ a children of the associated index command */
if (!f->hv)
f->hv = newHV ();
STORE(newRV_inc ((SV *)f->hv));
break;
case extra_element_oot:
- if (!f->hv)
- element_to_perl_hash (f);
+ /* Note that this is only used for info hash, with simple
+ elements that are associated to one element only, should
+ not be referred to elsewhere (and should not contain other
+ commands or containers) */
+ if (f->hv)
+ fatal ("element_to_perl_hash extra_element_oot twice\n");
+ element_to_perl_hash (f);
STORE(newRV_inc ((SV *)f->hv));
break;
case extra_contents:
- case extra_contents_oot:
{
if (f)
STORE(build_perl_array (&f->contents));
break;
}
- case extra_contents_array:
- {
- /* Like extra_contents, but this time output an array
- of arrays (instead of an array). */
- int j;
- AV *av;
- av = newAV ();
- STORE(newRV_inc ((SV *)av));
- for (j = 0; j < f->contents.number; j++)
- {
- SV *array;
- ELEMENT *g;
-
- g = f->contents.list[j];
- if (g)
- array = build_perl_array (&g->contents);
- else
- array = newSV (0); /* undef */
- av_push (av, array);
- }
- break;
- }
case extra_string:
{ /* A simple string. */
char *value = (char *) f;
@@ -475,90 +399,33 @@ element_to_perl_hash (ELEMENT *e)
int j;
AV *av;
av = newAV ();
+ av_unshift (av, f->contents.number);
+
STORE(newRV_inc ((SV *)av));
- /* An array of strings. */
+ /* An array of strings or integers. */
for (j = 0; j < f->contents.number; j++)
{
- if (f->contents.list[j]->text.end > 0)
+ KEY_PAIR *k;
+ k = lookup_extra (f->contents.list[j], "integer");
+ if (k)
+ {
+ IV value = (IV) (intptr_t) k->value;
+ av_store (av, j, newSViv (value));
+ }
+ else if (f->contents.list[j]->text.end > 0)
{
SV *sv = newSVpv_utf8 (f->contents.list[j]->text.text,
f->contents.list[j]->text.end);
- av_push (av, sv);
+ av_store (av, j, sv);
}
else
{
/* Empty strings permitted. */
- av_push (av, newSVpv ("", 0));
+ av_store (av, j, newSVpv ("", 0));
}
}
break;
}
- case extra_node_spec:
- /* A complex structure - see "parse_node_manual" function
- in end_line.c */
- if (f)
- STORE(build_node_spec ((NODE_SPEC_EXTRA *) f));
- break;
- case extra_node_spec_array:
- {
- AV *av;
- NODE_SPEC_EXTRA **array;
- av = newAV ();
- STORE(newRV_inc ((SV *)av));
- array = (NODE_SPEC_EXTRA **) f;
- while (*array)
- {
- av_push (av, build_node_spec (*array));
- array++;
- }
- break;
- }
- case extra_index_entry:
- /* A "index_entry" extra key on a command defining an index
- entry. Unlike the other keys, the value is not in the
- main parse tree, but in the indices_information. It would
- be much nicer if we could get rid of the need for this key.
- We set this afterwards in build_index_data. */
- break;
- case extra_def_info:
- {
- DEF_INFO *d = (DEF_INFO *) f;
- HV *def_parsed_hash;
-
- /* Create a "def_parsed_hash" extra value. */
- def_parsed_hash = newHV ();
- STORE(newRV_inc ((SV *)def_parsed_hash));
-
-#define SAVE_DEF(X) { if (!d->X->hv) \
- element_to_perl_hash (d->X); \
- hv_store (def_parsed_hash, #X, strlen (#X), \
- newRV_inc ((SV *)d->X->hv), 0) ; }
-
- if (d->category)
- SAVE_DEF(category)
- if (d->class)
- SAVE_DEF(class)
- if (d->type)
- SAVE_DEF(type)
- if (d->name)
- SAVE_DEF(name)
- break;
- }
- case extra_float_type:
- {
- EXTRA_FLOAT_TYPE *eft = (EXTRA_FLOAT_TYPE *) f;
- HV *type = newHV ();
- if (eft->content)
- hv_store (type, "content", strlen ("content"),
- build_perl_array (&eft->content->contents), 0);
- if (eft->normalized)
- {
- SV *sv = newSVpv_utf8 (eft->normalized, 0);
- hv_store (type, "normalized", strlen ("normalized"), sv, 0);
- }
- STORE(newRV_inc ((SV *)type));
- break;
- }
default:
fatal ("unknown extra type");
break;
@@ -566,37 +433,250 @@ element_to_perl_hash (ELEMENT *e)
}
#undef STORE
- if (!all_deleted)
- hv_store (e->hv, "extra", strlen ("extra"),
+ if (nr_info > 0)
+ hv_store (e->hv, key, strlen (key),
newRV_inc((SV *)extra), 0);
}
+}
+
+static void
+store_source_mark_list (ELEMENT *e)
+{
+ dTHX;
+
+ if (e->source_mark_list.number > 0)
+ {
+ AV *av;
+ SV *sv;
+ int i;
+ av = newAV ();
+ sv = newRV_noinc ((SV *) av);
+ hv_store (e->hv, "source_marks", strlen ("source_marks"), sv, 0);
+
+ for (i = 0; i < e->source_mark_list.number; i++)
+ {
+ HV *source_mark;
+ SV *sv;
+ SOURCE_MARK *s_mark = e->source_mark_list.list[i];
+ IV source_mark_position;
+ IV source_mark_counter;
+ source_mark = newHV ();
+#define STORE(key, value) hv_store (source_mark, key, strlen (key), value, 0)
+ /* A simple integer. The intptr_t cast here prevents
+ a warning on MinGW ("cast from pointer to integer of
+ different size"). */
+ source_mark_counter = (IV) (intptr_t) s_mark->counter;
+ STORE("counter", newSViv (source_mark_counter));
+ if (s_mark->position > 0)
+ {
+ source_mark_position = (IV) (intptr_t) s_mark->position;
+ STORE("position", newSViv (source_mark_position));
+ }
+ if (s_mark->element)
+ {
+ ELEMENT *e = s_mark->element;
+ /* should only be referred to in one source mark */
+ if (e->hv)
+ fatal ("element_to_perl_hash source mark elt twice");
+ element_to_perl_hash (e);
+ STORE("element", newRV_inc ((SV *)e->hv));
+ }
+ if (s_mark->line)
+ {
+ SV *sv = newSVpv_utf8 (s_mark->line, 0);
+ STORE("line", sv);
+ }
+
+#define SAVE_S_M_STATUS(X) \
+ case SM_status_ ## X: \
+ sv = newSVpv_utf8 (#X, 0);\
+ STORE("status", sv); \
+ break;
+
+ switch (s_mark->status)
+ {
+ SAVE_S_M_STATUS (start)
+ SAVE_S_M_STATUS (end)
+
+ /* for SM_status_none */
+ default:
+ break;
+ }
+
+#define SAVE_S_M_TYPE(X) \
+ case SM_type_ ## X: \
+ sv = newSVpv_utf8 (#X, 0);\
+ STORE("sourcemark_type", sv); \
+ break;
+
+ switch (s_mark->type)
+ {
+ SAVE_S_M_TYPE (include)
+ SAVE_S_M_TYPE (setfilename)
+ SAVE_S_M_TYPE (delcomment)
+ SAVE_S_M_TYPE (defline_continuation)
+ SAVE_S_M_TYPE (macro_expansion)
+ SAVE_S_M_TYPE (linemacro_expansion)
+ SAVE_S_M_TYPE (value_expansion)
+ SAVE_S_M_TYPE (ignored_conditional_block)
+ SAVE_S_M_TYPE (expanded_conditional_command)
+
+ /* for SM_type_none */
+ default:
+ break;
+ }
+
+ av_push (av, newRV_noinc ((SV *)source_mark));
+#undef STORE
+ }
+ }
+}
+
+static int hashes_ready = 0;
+static U32 HSH_parent = 0;
+static U32 HSH_type = 0;
+static U32 HSH_cmdname = 0;
+static U32 HSH_contents = 0;
+static U32 HSH_args = 0;
+static U32 HSH_text = 0;
+static U32 HSH_extra = 0;
+static U32 HSH_info = 0;
+static U32 HSH_source_info = 0;
+static U32 HSH_file_name = 0;
+static U32 HSH_line_nr = 0;
+static U32 HSH_macro = 0;
+
+/* Set E->hv and 'hv' on E's descendants. e->parent->hv is assumed
+ to already exist. */
+static void
+element_to_perl_hash (ELEMENT *e)
+{
+ SV *sv;
+
+ dTHX;
+
+ /* e->hv may already exist if there was an extra value elsewhere
+ referring to e. */
+ if (!e->hv)
+ {
+ e->hv = newHV ();
+ }
+
+ if (!hashes_ready)
+ {
+ hashes_ready = 1;
+ PERL_HASH(HSH_parent, "parent", strlen ("parent"));
+ PERL_HASH(HSH_type, "type", strlen ("type"));
+ PERL_HASH(HSH_cmdname, "cmdname", strlen ("cmdname"));
+ PERL_HASH(HSH_contents, "contents", strlen ("contents"));
+ PERL_HASH(HSH_args, "args", strlen ("args"));
+ PERL_HASH(HSH_text, "text", strlen ("text"));
+ PERL_HASH(HSH_extra, "extra", strlen ("extra"));
+ PERL_HASH(HSH_info, "info", strlen ("info"));
+ PERL_HASH(HSH_source_info, "source_info", strlen ("source_info"));
+
+ PERL_HASH(HSH_file_name, "file_name", strlen ("file_name"));
+ PERL_HASH(HSH_line_nr, "line_nr", strlen ("line_nr"));
+ PERL_HASH(HSH_macro, "macro", strlen ("macro"));
+ }
+
+ if (e->parent)
+ {
+ if (!e->parent->hv)
+ fatal ("parent hv not already set\n");
+ sv = newRV_inc ((SV *) e->parent->hv);
+ hv_store (e->hv, "parent", strlen ("parent"), sv, HSH_parent);
+ }
+
+ if (e->type)
+ {
+ sv = newSVpv (element_type_names[e->type], 0);
+ hv_store (e->hv, "type", strlen ("type"), sv, HSH_type);
+ }
+
+ if (e->cmd)
+ {
+ sv = newSVpv (command_name(e->cmd), 0);
+ hv_store (e->hv, "cmdname", strlen ("cmdname"), sv, HSH_cmdname);
+
+ /* Note we could optimize the call to newSVpv here and
+ elsewhere by passing an appropriate second argument. */
+ }
+
+ if (e->contents.number > 0)
+ {
+ AV *av;
+ int i;
+
+ av = newAV ();
+ sv = newRV_noinc ((SV *) av);
+ av_unshift (av, e->contents.number);
+
+ hv_store (e->hv, "contents", strlen ("contents"), sv, HSH_contents);
+ for (i = 0; i < e->contents.number; i++)
+ {
+ element_to_perl_hash (e->contents.list[i]);
+ sv = newRV_noinc ((SV *) e->contents.list[i]->hv);
+ av_store (av, i, sv);
+ }
+ }
+
+ if (e->args.number > 0)
+ {
+ AV *av;
+ int i;
+
+ av = newAV ();
+ sv = newRV_noinc ((SV *) av);
+ av_unshift (av, e->args.number);
+
+ hv_store (e->hv, "args", strlen ("args"), sv, HSH_args);
+ for (i = 0; i < e->args.number; i++)
+ {
+ element_to_perl_hash (e->args.list[i]);
+ sv = newRV_inc ((SV *) e->args.list[i]->hv);
+ av_store (av, i, sv);
+ }
+ }
+
+ if (e->text.space > 0)
+ {
+ sv = newSVpv_utf8 (e->text.text, e->text.end);
+ hv_store (e->hv, "text", strlen ("text"), sv, HSH_text);
+ }
+
+ store_additional_info (e, &e->extra_info, "extra");
+ store_additional_info (e, &e->info_info, "info");
+
+ store_source_mark_list (e);
if (e->source_info.line_nr)
{
-#define STORE(key, sv) hv_store (hv, key, strlen (key), sv, 0)
+#define STORE(key, sv, hsh) hv_store (hv, key, strlen (key), sv, hsh)
SOURCE_INFO *source_info = &e->source_info;
HV *hv = newHV ();
hv_store (e->hv, "source_info", strlen ("source_info"),
- newRV_inc((SV *)hv), 0);
+ newRV_noinc((SV *)hv), HSH_source_info);
if (source_info->file_name)
{
- STORE("file_name", newSVpv (source_info->file_name, 0));
+ STORE("file_name", newSVpv (source_info->file_name, 0),
+ HSH_file_name);
}
else
- STORE("file_name", newSVpv ("", 0));
+ STORE("file_name", newSVpv ("", 0), HSH_file_name);
if (source_info->line_nr)
{
- STORE("line_nr", newSViv (source_info->line_nr));
+ STORE("line_nr", newSViv (source_info->line_nr), HSH_line_nr);
}
if (source_info->macro)
{
- STORE("macro", newSVpv_utf8 (source_info->macro, 0));
+ STORE("macro", newSVpv_utf8 (source_info->macro, 0), HSH_macro);
}
else
- STORE("macro", newSVpv ("", 0));
+ STORE("macro", newSVpv ("", 0), HSH_macro);
#undef STORE
}
}
@@ -618,7 +698,7 @@ build_texinfo_tree (void)
/* Return array of target elements. build_texinfo_tree must
be called first. */
AV *
-build_label_list (void)
+build_target_elements_list (void)
{
AV *target_array;
SV *sv;
@@ -627,11 +707,12 @@ build_label_list (void)
dTHX;
target_array = newAV ();
+ av_unshift (target_array, labels_number);
for (i = 0; i < labels_number; i++)
{
- sv = newRV_inc (labels_list[i].target->hv);
- av_push (target_array, sv);
+ sv = newRV_inc (target_elements_list[i]->hv);
+ av_store (target_array, i, sv);
}
return target_array;
@@ -647,17 +728,20 @@ build_internal_xref_list (void)
dTHX;
list_av = newAV ();
+ av_unshift (list_av, internal_xref_number);
for (i = 0; i < internal_xref_number; i++)
{
sv = newRV_inc (internal_xref_list[i]->hv);
- av_push (list_av, sv);
+ av_store (list_av, i, sv);
}
return list_av;
}
/* Return hash for list of @float's that appeared in the file. */
+/* not used for now, since the normalization of of float type is done
+ outside of the barser. Could be done here again when possible */
HV *
build_float_list (void)
{
@@ -683,7 +767,7 @@ build_float_list (void)
hv_store (float_hash,
floats_list[i].type,
strlen (floats_list[i].type),
- newRV_inc ((SV *)av),
+ newRV_noinc ((SV *)av),
0);
}
else
@@ -770,111 +854,30 @@ build_single_index_data (INDEX *i)
if (i->index_number > 0)
{
entries = newAV ();
- STORE("index_entries", newRV_inc ((SV *) entries));
- }
+ av_unshift (entries, i->index_number);
+ STORE("index_entries", newRV_noinc ((SV *) entries));
#undef STORE
- entry_number = 1;
- if (i->index_number > 0)
- for (j = 0; j < i->index_number; j++)
- {
-#define STORE2(key, value) hv_store (entry, key, strlen (key), value, 0)
- HV *entry;
- INDEX_ENTRY *e;
-
- e = &i->index_entries[j];
- entry = newHV ();
-
- STORE2("index_name", newSVpv_utf8 (i->name, 0));
- STORE2("index_at_command",
- newSVpv (command_name(e->index_at_command), 0));
- STORE2("index_type_command",
- newSVpv (command_name(e->index_type_command), 0));
- STORE2("entry_element",
- newRV_inc ((SV *)e->command->hv));
- STORE2("entry_number", newSViv (entry_number));
- if (e->region)
+ entry_number = 1;
+ for (j = 0; j < i->index_number; j++)
{
- STORE2("entry_region", newRV_inc ((SV *)e->region->hv));
- }
- if (e->content)
- {
- SV **contents_array;
- if (!e->content->hv)
- {
- if (e->content->parent)
- fatal ("index element should not be in-tree");
- element_to_perl_hash (e->content);
- }
- contents_array = hv_fetch (e->content->hv,
- "contents", strlen ("contents"), 0);
+#define STORE2(key, value) hv_store (entry, key, strlen (key), value, 0)
+ HV *entry;
+ INDEX_ENTRY *e;
- if (!contents_array)
- {
- element_to_perl_hash (e->content);
- contents_array = hv_fetch (e->content->hv,
- "contents", strlen ("contents"), 0);
- }
+ e = &i->index_entries[j];
+ entry = newHV ();
- if (contents_array)
- {
- /* Copy the reference to the array. */
- STORE2("entry_content", newRV_inc ((SV *)(AV *)SvRV(*contents_array)));
+ STORE2("index_name", newSVpv_utf8 (i->name, 0));
+ STORE2("entry_element",
+ newRV_inc ((SV *)e->command->hv));
+ STORE2("entry_number", newSViv (entry_number));
- STORE2("content_normalized",
- newRV_inc ((SV *)(AV *)SvRV(*contents_array)));
- }
- else
- {
- STORE2("entry_content", newRV_inc ((SV *)newAV ()));
- STORE2("content_normalized", newRV_inc ((SV *)newAV ()));
- }
- }
- else
- ; /* will be set in Texinfo::Common::complete_indices */
-
- if (e->node)
- STORE2("entry_node", newRV_inc ((SV *)e->node->hv));
- if (e->sortas)
- STORE2("sortas", newSVpv_utf8 (e->sortas, 0));
-
- /* Create ignored_chars hash. */
- {
-#define STORE3(key) hv_store (hv, key, strlen (key), newSViv(1), 0)
- HV *hv = newHV ();
- if (e->ignored_chars.backslash)
- STORE3("\\");
- if (e->ignored_chars.hyphen)
- STORE3("-");
- if (e->ignored_chars.lessthan)
- STORE3("<");
- if (e->ignored_chars.atsign)
- STORE3("@");
-#undef STORE3
-
- STORE2("index_ignore_chars", newRV_inc ((SV *)hv));
- }
-
- av_push (entries, newRV_inc ((SV *)entry));
- entry_number++;
-
- /* We set this now because the index data structures don't
- exist at the time that the main tree is built. */
- {
- SV **extra_hash;
- extra_hash = hv_fetch (e->command->hv, "extra", strlen ("extra"), 0);
- if (!extra_hash)
- {
- /* There's no guarantee that the "extra" value was set on
- the element. */
- extra_hash = hv_store (e->command->hv, "extra", strlen ("extra"),
- newRV_inc ((SV *)newHV ()), 0);
- }
+ av_store (entries, j, newRV_noinc ((SV *)entry));
- hv_store ((HV *)SvRV(*extra_hash), "index_entry", strlen ("index_entry"),
- newRV_inc ((SV *)entry), 0);
- }
+ entry_number++;
#undef STORE2
+ }
}
}
@@ -896,7 +899,7 @@ build_index_data (void)
HV *hv2;
build_single_index_data (idx);
hv2 = idx->hv;
- hv_store (hv, idx->name, strlen (idx->name), newRV_inc ((SV *)hv2), 0);
+ hv_store (hv, idx->name, strlen (idx->name), newRV_noinc ((SV *)hv2), 0);
}
return hv;
@@ -915,18 +918,15 @@ build_global_info (void)
dTHX;
hv = newHV ();
- if (global_info.input_encoding_name)
+ if (global_input_encoding_name)
hv_store (hv, "input_encoding_name", strlen ("input_encoding_name"),
- newSVpv (global_info.input_encoding_name, 0), 0);
- if (global_info.input_perl_encoding)
- hv_store (hv, "input_perl_encoding", strlen ("input_perl_encoding"),
- newSVpv (global_info.input_perl_encoding, 0), 0);
+ newSVpv (global_input_encoding_name, 0), 0);
if (global_info.dircategory_direntry.contents.number > 0)
{
AV *av = newAV ();
hv_store (hv, "dircategory_direntry", strlen ("dircategory_direntry"),
- newRV_inc ((SV *) av), 0);
+ newRV_noinc ((SV *) av), 0);
for (i = 0; i < global_info.dircategory_direntry.contents.number; i++)
{
e = contents_child_by_index (&global_info.dircategory_direntry, i);
@@ -997,7 +997,7 @@ build_global_info2 (void)
{
av = newAV ();
hv_store (hv, "footnote", strlen ("footnote"),
- newRV_inc ((SV *) av), 0);
+ newRV_noinc ((SV *) av), 0);
for (i = 0; i < global_info.footnotes.contents.number; i++)
{
e = contents_child_by_index (&global_info.footnotes, i);
@@ -1006,12 +1006,26 @@ build_global_info2 (void)
}
}
+ /* float is a type, it does not work there, use floats instead */
+ if (global_info.floats.contents.number > 0)
+ {
+ av = newAV ();
+ hv_store (hv, "float", strlen ("float"),
+ newRV_noinc ((SV *) av), 0);
+ for (i = 0; i < global_info.floats.contents.number; i++)
+ {
+ e = contents_child_by_index (&global_info.floats, i);
+ if (e->hv)
+ av_push (av, newRV_inc ((SV *) e->hv));
+ }
+ }
+
#define BUILD_GLOBAL_ARRAY(cmd) \
if (global_info.cmd.contents.number > 0) \
{ \
av = newAV (); \
hv_store (hv, #cmd, strlen (#cmd), \
- newRV_inc ((SV *) av), 0); \
+ newRV_noinc ((SV *) av), 0); \
for (i = 0; i < global_info.cmd.contents.number; i++) \
{ \
e = contents_child_by_index (&global_info.cmd, i); \
@@ -1020,14 +1034,15 @@ build_global_info2 (void)
} \
}
+ BUILD_GLOBAL_ARRAY(author);
+ BUILD_GLOBAL_ARRAY(detailmenu);
BUILD_GLOBAL_ARRAY(hyphenation);
BUILD_GLOBAL_ARRAY(insertcopying);
+ BUILD_GLOBAL_ARRAY(listoffloats);
+ BUILD_GLOBAL_ARRAY(part);
BUILD_GLOBAL_ARRAY(printindex);
BUILD_GLOBAL_ARRAY(subtitle);
BUILD_GLOBAL_ARRAY(titlefont);
- BUILD_GLOBAL_ARRAY(listoffloats);
- BUILD_GLOBAL_ARRAY(detailmenu);
- BUILD_GLOBAL_ARRAY(part);
/* from Common.pm %document_settable_multiple_at_commands */
BUILD_GLOBAL_ARRAY(allowcodebreaks);
@@ -1118,7 +1133,7 @@ build_source_info_hash (SOURCE_INFO source_info)
newSVpv_utf8 ("", 0), 0);
}
- return newRV_inc ((SV *) hv);
+ return newRV_noinc ((SV *) hv);
}
static SV *
@@ -1144,7 +1159,7 @@ convert_error (int i)
hv_store (hv, "source_info", strlen ("source_info"),
build_source_info_hash(e.source_info), 0);
- return newRV_inc ((SV *) hv);
+ return newRV_noinc ((SV *) hv);
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.h
index 626c3b4c7d..4a440af655 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/api.h
@@ -1,7 +1,6 @@
/* api.h - declarations for api.c */
#ifndef API_H
#define API_H
-extern ELEMENT *Root;
int init (int texinfo_uninstalled, char *srcdir_in);
@@ -9,7 +8,7 @@ int parse_file (char *filename);
void parse_piece (char *, int line_nr);
void parse_string (char *, int line_nr);
void parse_text (char *, int line_nr);
-void reset_parser (void);
+void reset_parser (int debug_output);
void reset_parser_except_conf (void);
void set_debug (int);
void wipe_values (void);
@@ -21,7 +20,7 @@ void conf_set_locale_encoding (char *value);
void conf_set_documentlanguage_override (char *value);
HV *build_texinfo_tree (void);
-AV *build_label_list (void);
+AV *build_target_elements_list (void);
AV *build_internal_xref_list (void);
HV *build_float_list (void);
HV *build_index_data (void);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/close.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/close.c
index 08b2113a08..e7c8aa223e 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/close.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/close.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,24 +19,47 @@
#include <string.h>
#include "parser.h"
+#include "def.h"
+#include "debug.h"
+#include "source_marks.h"
-/* Possibly print an error message, and return CURRENT->parent. */
-static ELEMENT *
+/* Return CURRENT->parent. The other arguments are used if an error message
+ should be printed. */
+ELEMENT *
close_brace_command (ELEMENT *current,
enum command_id closed_block_command,
- enum command_id interrupting_command)
+ enum command_id interrupting_command,
+ int missing_brace)
{
KEY_PAIR *k;
+ if (command_data(current->cmd).data == BRACE_context)
+ {
+ if (current->cmd == CM_math)
+ {
+ if (pop_context () != ct_math)
+ fatal ("math context expected");
+ }
+ else if (pop_context () != ct_brace_command)
+ fatal ("context brace command context expected");
+ if (current->cmd == CM_footnote)
+ nesting_context.footnote--;
+ if (current->cmd == CM_caption || current->cmd == CM_shortcaption)
+ nesting_context.caption--;
+ }
+
+ if (command_flags(current) & CF_contain_basic_inline)
+ (void) pop_command (&nesting_context.basic_inline_stack);
+
if (current->cmd != CM_verb)
goto yes;
- k = lookup_extra (current, "delimiter");
+ k = lookup_info (current, "delimiter");
if (!k || !*(char *)k->value)
goto yes;
if (0)
{
-yes:
+ yes:
if (closed_block_command)
command_error (current,
"@end %s seen before @%s closing brace",
@@ -47,12 +70,12 @@ yes:
"@%s seen before @%s closing brace",
command_name(interrupting_command),
command_name(current->cmd));
- else
- command_error (current,
+ else if (missing_brace)
+ command_error (current,
"@%s missing closing brace",
command_name(current->cmd));
}
- else
+ else if (missing_brace)
{
command_error (current,
"@%s missing closing delimiter sequence: %s}",
@@ -73,9 +96,88 @@ close_all_style_commands (ELEMENT *current,
while (current->parent
&& (command_flags(current->parent) & CF_brace)
&& !(command_data(current->parent->cmd).data == BRACE_context))
- current = close_brace_command (current->parent,
- closed_block_command, interrupting_command);
+ {
+ debug ("CLOSING(all_style_commands) @%s",
+ command_name(current->parent->cmd));
+ current = close_brace_command (current->parent,
+ closed_block_command, interrupting_command, 1);
+ }
+
+ return current;
+}
+
+int
+is_container_empty (ELEMENT *current)
+{
+ if (current->contents.number == 0
+ && current->args.number == 0
+ && current->text.end == 0
+ && current->info_info.info_number == 0)
+ return 1;
+ return 0;
+}
+
+/* remove an empty content that only holds source marks */
+void
+remove_empty_content (ELEMENT *current)
+{
+ if (current->contents.number == 1)
+ {
+ ELEMENT *child_element = last_contents_child (current);
+ if ((!child_element->cmd) && is_container_empty (child_element))
+ {
+ transfer_source_marks (child_element, current);
+
+ debug_nonl ("REMOVE empty child ");
+ debug_print_element (child_element, 0); debug_nonl (" from ");
+ debug_print_element (current, 0); debug ("");
+ destroy_element (pop_element_from_contents (current));
+ }
+ }
+}
+/* this should only be called for non @-command elements otherwise
+ empty command elements will be removed */
+ELEMENT *
+close_container (ELEMENT *current)
+{
+ ELEMENT *element_to_remove = 0;
+
+ remove_empty_content (current);
+
+ /* remove element without contents nor associated information */
+ if (is_container_empty (current))
+ {
+ debug_nonl ("CONTAINER EMPTY ");
+ debug_print_element (current, 1);
+ debug_nonl (" (%d source marks)",
+ current->source_mark_list.number); debug ("");
+ if (current->source_mark_list.number > 0)
+ {
+ /* Keep the element to keep the source mark, but remove some types.
+ Keep before_item in order not to add empty table definition in
+ gather_previous_item. */
+ if (current->type != ET_before_item)
+ current->type = ET_NONE;
+ }
+ else
+ element_to_remove = current;
+ }
+
+ current = current->parent;
+ if (element_to_remove)
+ {
+ ELEMENT *last_child = last_contents_child (current);
+ /* this is to avoid removing empty containers in args,
+ happens with brace commands not closed at the end of
+ a manual */
+ if (last_child == element_to_remove)
+ {
+ debug_nonl ("REMOVE empty type ");
+ debug_print_element (last_child, 1); debug ("");
+ destroy_element (pop_element_from_contents (current));
+ }
+ }
return current;
}
@@ -142,7 +244,8 @@ close_command_cleanup (ELEMENT *current)
/* Put everything after the last @def*x command in a def_item type
container. */
- if (command_data(current->cmd).flags & CF_def)
+ if (command_data(current->cmd).flags & CF_def
+ || current->cmd == CM_defblock)
{
gather_def_item (current, 0);
}
@@ -186,7 +289,8 @@ close_command_cleanup (ELEMENT *current)
}
/* Now if the ET_before_item is empty, remove it. */
- if (before_item->contents.number == 0)
+ if (is_container_empty (before_item)
+ && before_item->source_mark_list.number == 0)
{
destroy_element (remove_from_contents (current,
have_leading_spaces ? 1 : 0));
@@ -215,11 +319,11 @@ close_command_cleanup (ELEMENT *current)
ELEMENT *e = current->contents.list[i];
if (e == before_item)
continue;
- if (e->cmd != CM_NONE
- && (e->cmd != CM_c && e->cmd != CM_comment
- && e->cmd != CM_end)
- || e->type != ET_NONE
- && e->type != ET_ignorable_spaces_after_command)
+ if ((e->cmd != CM_NONE
+ && (e->cmd != CM_c && e->cmd != CM_comment
+ && e->cmd != CM_end))
+ || (e->type != ET_NONE
+ && e->type != ET_ignorable_spaces_after_command))
{
empty_format = 0;
break;
@@ -256,10 +360,22 @@ pop_block_command_contexts (enum command_id cmd)
}
else if (command_data(cmd).data == BLOCK_region)
{
- pop_region ();
+ (void) pop_command (&nesting_context.regions_stack);
}
}
+void
+close_ignored_block_conditional (ELEMENT *current)
+{
+ SOURCE_MARK *source_mark
+ = new_source_mark (SM_type_ignored_conditional_block);
+ ELEMENT *conditional = pop_element_from_contents (current);
+
+ conditional->parent = 0;
+ source_mark->element = conditional;
+ register_source_mark (current, source_mark);
+}
+
ELEMENT *
close_current (ELEMENT *current,
enum command_id closed_block_command,
@@ -268,55 +384,38 @@ close_current (ELEMENT *current,
/* Element is a command */
if (current->cmd)
{
- debug ("CLOSING (close_current) %s", command_name(current->cmd));
+ enum command_id cmd = current->cmd;
+ debug ("CLOSING(close_current) @%s", command_name(cmd));
if (command_flags(current) & CF_brace)
{
- if (command_data(current->cmd).data == BRACE_context)
- {
- if (current->cmd == CM_math)
- {
- if (pop_context () != ct_math)
- fatal ("math context expected");
- }
- else if (pop_context () != ct_brace_command)
- fatal ("context brace command context expected");
- }
current = close_brace_command (current, closed_block_command,
- interrupting_command);
+ interrupting_command, 1);
}
else if (command_flags(current) & CF_block)
{
- enum command_id cmd = current->cmd;
- ELEMENT *parent = 0;
if (closed_block_command)
{
line_error ("`@end' expected `%s', but saw `%s'",
- command_name(current->cmd),
+ command_name(cmd),
command_name(closed_block_command));
}
else if (interrupting_command)
{
line_error ("@%s seen before @end %s",
command_name(interrupting_command),
- command_name(current->cmd));
+ command_name(cmd));
}
else
{
line_error ("no matching `@end %s'",
- command_name(current->cmd));
+ command_name(cmd));
- /* Ignored conditional. */
- if (command_data(current->cmd).data == BLOCK_conditional)
- {
- parent = current->parent;
- destroy_element_and_children (pop_element_from_contents
- (parent));
- }
}
pop_block_command_contexts (cmd);
- if (!parent)
- parent = current->parent;
- current = parent;
+ current = current->parent;
+ /* In ignored conditional. */
+ if (command_data(cmd).data == BLOCK_conditional)
+ close_ignored_block_conditional (current);
}
else
{
@@ -327,11 +426,24 @@ close_current (ELEMENT *current,
}
else if (current->type != ET_NONE)
{
- enum context c;
- debug ("CLOSING type %s", element_type_names[current->type]);
+ ELEMENT *close_brace;
+
+ debug ("CLOSING type %s", element_type_name (current));
+
switch (current->type)
{
- case ET_bracketed:
+ case ET_balanced_braces:
+ close_brace = new_element (ET_NONE);
+ command_error (current, "misplaced {");
+ /* We prefer adding an element to merging because we may
+ be at the end of the document after an empty line we
+ do not want to modify */
+ /* current = merge_text (current, "}", 0); */
+ text_append (&close_brace->text, "}");
+ add_to_element_contents (current, close_brace);
+ current = current->parent;
+ break;
+ case ET_bracketed_arg:
command_error (current, "misplaced {");
if (current->contents.number > 0
&& current->contents.list[0]->type
@@ -339,35 +451,17 @@ close_current (ELEMENT *current,
{
/* remove spaces element from tree and update extra values */
abort_empty_line (&current, 0);
- }
- current = current->parent;
-
- break;
- case ET_menu_comment:
- case ET_menu_entry_description:
- /* Remove empty menu_comment */
- if (current->type == ET_menu_comment
- && current->contents.number == 0)
- {
- current = current->parent;
- destroy_element (pop_element_from_contents (current));
}
- else
- current = current->parent;
-
+ current = current->parent;
break;
case ET_line_arg:
+ current = end_line_misc_line (current);
+ break;
case ET_block_line_arg:
- c = pop_context ();
- if (c != ct_line && c != ct_def)
- {
- /* error */
- fatal ("line or def context expected");
- }
- current = current->parent;
+ current = end_line_starting_block (current);
break;
default:
- current = current->parent;
+ current = close_container (current);
break;
}
}
@@ -413,10 +507,23 @@ close_commands (ELEMENT *current, enum command_id closed_block_command,
pop_block_command_contexts (current->cmd);
*closed_element = current;
current = current->parent;
+
+ if (command_data((*closed_element)->cmd).data == BLOCK_conditional)
+ /* In ignored conditional. */
+ close_ignored_block_conditional (current);
}
- else if (closed_block_command)
+ else
{
- line_error ("unmatched `@end %s'", command_name(closed_block_command));
+ if (closed_block_command)
+ line_error ("unmatched `@end %s'", command_name(closed_block_command));
+ if (! ((current->cmd && command_flags(current) & CF_root)
+ || (current->type == ET_before_node_section)
+ || (current->type == ET_root_line)
+ || (current->type == ET_document_root)))
+ {
+ debug_nonl ("close_commands unexpectedly stopped ");
+ debug_print_element (current, 1); debug ("");
+ }
}
return current;
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.awk b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.awk
index 133a1c044e..9ee98955aa 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.awk
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.awk
@@ -1,4 +1,4 @@
-# Copyright 2010-2021 Free Software Foundation, Inc.
+# Copyright 2010-2023 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -142,10 +142,47 @@ END {
}
if (commands[c] != "") {
- flags = "CF_" commands[c]
- gsub (/,/, " | CF_", flags)
- } else {
+ split(commands[c], flags_array, ",")
+ flags_str = ""
+ for (flag_idx in flags_array) {
+ if (flag_idx == 1) {
+ # first flag is always kept, corresponds to the category
+ flags_str = flags_array[flag_idx]
+ # all the line and block commands have the no_paragraph flag
+ if (flags_str == "line" || flags_str == "block") {
+ old_str = flags_str
+ flags_str = old_str "," "no_paragraph"
+ }
+ } else {
+ # filter out flags not relevant for the XS parser. Use
+ # an array and not a regexp because word boundary matching
+ # does not seems to be portable and we want to be sure to
+ # match correctly even if an ignored flag is a substring of
+ # another flag
+ if (flags_array[flag_idx] != "letter_no_arg" \
+ && flags_array[flag_idx] != "inline_format" \
+ && flags_array[flag_idx] != "inline_conditional" \
+ && flags_array[flag_idx] != "in_index" \
+ && flags_array[flag_idx] != "in_def" \
+ && flags_array[flag_idx] != "brace_code" \
+ && flags_array[flag_idx] != "explained" \
+ && flags_array[flag_idx] != "formatted_line" \
+ && flags_array[flag_idx] != "formatted_nobrace" \
+ && flags_array[flag_idx] != "formattable_line" \
+ && flags_array[flag_idx] != "non_formatted_block" \
+ && flags_array[flag_idx] != "preamble") {
+ old_str = flags_str
+ flags_str = old_str "," flags_array[flag_idx]
+ }
+ }
+ }
+ }
+
+ if (flags_str == "") {
flags = "0"
+ } else {
+ flags = "CF_" flags_str
+ gsub (/,/, " | CF_", flags)
}
if (data[c] != "") {
@@ -157,24 +194,18 @@ END {
if (args_nr[c] != "") {
args_nr_data = args_nr[c]
} else {
- # backward compatibility, remove when updated
- where_digit = match(data[c], /^[0-9]$/)
- if (where_digit != 0) {
- args_nr_data = data[c]
- } else {
- where = 0
- if (commands[c] != "") {
- where = match(commands[c], /block/)
- if (where == 0) {
- where = match(commands[c], /^nobrace$/)
- }
- }
- if (where != 0 || command_data == "BRACE_noarg") {
- args_nr_data = "0"
- } else {
- args_nr_data = "1"
+ where = 0
+ if (commands[c] != "") {
+ where = match(commands[c], /block/)
+ if (where == 0) {
+ where = match(command_data, /^NOBRACE_/)
}
}
+ if (where != 0 || command_data == "BRACE_noarg" || command_data == "LINE_lineraw" ) {
+ args_nr_data = "0"
+ } else {
+ args_nr_data = "1"
+ }
}
print "\"" c2 "\", " flags ", " command_data ", " args_nr_data "," > CD
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.c
index 19a2a22cf2..e40f74333a 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.c
@@ -7,7 +7,7 @@ COMMAND builtin_command_data[] = {
"\"", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"&", CF_nobrace, NOBRACE_symbol, 0,
"'", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"*", CF_nobrace, NOBRACE_symbol, 0,
+"*", CF_nobrace | CF_no_paragraph, NOBRACE_symbol, 0,
",", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"-", CF_nobrace, NOBRACE_symbol, 0,
".", CF_nobrace, NOBRACE_symbol, 0,
@@ -16,164 +16,167 @@ COMMAND builtin_command_data[] = {
"=", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"?", CF_nobrace, NOBRACE_symbol, 0,
"@", CF_nobrace, NOBRACE_symbol, 0,
-"AA", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"AE", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"DH", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
+"AA", CF_brace, BRACE_noarg, 0,
+"AE", CF_brace, BRACE_noarg, 0,
+"DH", CF_brace, BRACE_noarg, 0,
"H", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"L", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
+"L", CF_brace, BRACE_noarg, 0,
"LaTeX", CF_brace, BRACE_noarg, 0,
-"O", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"OE", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"TH", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
+"O", CF_brace, BRACE_noarg, 0,
+"OE", CF_brace, BRACE_noarg, 0,
+"TH", CF_brace, BRACE_noarg, 0,
"TeX", CF_brace, BRACE_noarg, 0,
"U", CF_brace, BRACE_arguments, 1,
"\\", CF_nobrace, NOBRACE_symbol, 0,
"^", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"`", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"aa", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"abbr", CF_brace | CF_contain_simple_text, BRACE_arguments, 2,
-"acronym", CF_brace | CF_contain_simple_text, BRACE_arguments, 2,
-"ae", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"afivepaper", CF_line | CF_global_unique, LINE_skipline, 1,
-"afourlatex", CF_line | CF_global_unique, LINE_skipline, 1,
-"afourpaper", CF_line | CF_global_unique, LINE_skipline, 1,
-"afourwide", CF_line | CF_global_unique, LINE_skipline, 1,
-"alias", CF_line | CF_contain_plain_text, LINE_specific, 2,
-"allowcodebreaks", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"aa", CF_brace, BRACE_noarg, 0,
+"abbr", CF_brace | CF_contain_basic_inline, BRACE_arguments, 2,
+"acronym", CF_brace | CF_contain_basic_inline, BRACE_arguments, 2,
+"ae", CF_brace, BRACE_noarg, 0,
+"afivepaper", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"afourlatex", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"afourpaper", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"afourwide", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"alias", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 2,
+"allowcodebreaks", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
"ampchar", CF_brace, BRACE_noarg, 0,
-"anchor", CF_brace | CF_contain_simple_text, BRACE_arguments, 1,
-"appendix", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"appendixsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"appendixsection", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"appendixsubsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"appendixsubsubsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
+"anchor", CF_brace | CF_contain_basic_inline | CF_no_paragraph, BRACE_arguments, 1,
+"appendix", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"appendixsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"appendixsection", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"appendixsubsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"appendixsubsubsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
"arrow", CF_brace, BRACE_noarg, 0,
"asis", CF_brace, BRACE_style_other, 1,
"atchar", CF_brace, BRACE_noarg, 0,
-"author", CF_line | CF_global | CF_contain_simple_text, LINE_line, 1,
+"author", CF_line | CF_no_paragraph | CF_global | CF_contain_basic_inline, LINE_line, 1,
"b", CF_brace, BRACE_style_other, 1,
"backslashchar", CF_brace, BRACE_noarg, 0,
-"bsixpaper", CF_line | CF_global_unique, LINE_skipline, 1,
+"bsixpaper", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
"bullet", CF_brace, BRACE_noarg, 0,
-"bye", CF_line, LINE_skipline, 1,
-"c", CF_line, LINE_lineraw, 1,
-"caption", CF_brace | CF_close_paragraph, BRACE_context, 1,
-"cartouche", CF_block | CF_close_paragraph, 0, 0,
-"center", CF_line | CF_close_paragraph, LINE_line, 1,
-"centerchap", CF_line | CF_root | CF_sectioning_heading | CF_deprecated, LINE_line, 1,
-"chapheading", CF_line | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
-"chapter", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
+"bye", CF_line | CF_no_paragraph, LINE_lineraw, 0,
+"c", CF_line | CF_no_paragraph, LINE_lineraw, 1,
+"caption", CF_brace | CF_close_paragraph | CF_no_paragraph, BRACE_context, 1,
+"cartouche", CF_block | CF_no_paragraph | CF_close_paragraph, BLOCK_other, 1,
+"center", CF_line | CF_no_paragraph | CF_close_paragraph, LINE_line, 1,
+"centerchap", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading | CF_deprecated, LINE_line, 1,
+"chapheading", CF_line | CF_no_paragraph | CF_contain_basic_inline | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
+"chapter", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
"cite", CF_brace, BRACE_style_other, 1,
-"clear", CF_line, LINE_special, 1,
+"clear", CF_line | CF_no_paragraph, LINE_lineraw, 1,
"click", CF_brace, BRACE_noarg, 0,
"clicksequence", CF_brace, BRACE_style_other, 1,
-"clickstyle", CF_line | CF_global, LINE_special, 1,
+"clickstyle", CF_line | CF_no_paragraph | CF_global, LINE_lineraw, 1,
"code", CF_brace, BRACE_style_code, 1,
-"codequotebacktick", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"codequoteundirected", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"columnfractions", CF_line | CF_contain_plain_text, LINE_specific, 1,
+"codequotebacktick", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"codequoteundirected", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"columnfractions", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 1,
"comma", CF_brace, BRACE_noarg, 0,
"command", CF_brace, BRACE_style_code, 1,
-"comment", CF_line, LINE_lineraw, 1,
-"contents", CF_line | CF_close_paragraph | CF_global, LINE_skipline, 1,
-"copying", CF_block | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
+"comment", CF_line | CF_no_paragraph, LINE_lineraw, 1,
+"contents", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global, LINE_lineraw, 0,
+"copying", CF_block | CF_no_paragraph | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
"copyright", CF_brace, BRACE_noarg, 0,
-"defcodeindex", CF_line | CF_contain_plain_text, LINE_specific, 1,
-"defcv", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"defcvx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"deffn", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deffnx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"defindex", CF_line | CF_contain_plain_text, LINE_specific, 1,
-"definfoenclose", CF_line | CF_contain_plain_text | CF_deprecated, LINE_specific, 3,
-"defivar", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defivarx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defmac", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defmacx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defmethod", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defmethodx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defop", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"defopt", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defoptx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defopx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"defspec", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defspecx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"deftp", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deftpx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"deftypecv", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deftypecvx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"deftypefn", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deftypefnnewline", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"deftypefnx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"deftypefun", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"deftypefunx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"deftypeivar", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"deftypeivarx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"deftypemethod", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"deftypemethodx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"deftypeop", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deftypeopx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"deftypevar", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"deftypevarx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"deftypevr", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"deftypevrx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"defun", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defunx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defvar", CF_block | CF_def | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
-"defvarx", CF_line | CF_def | CF_def_alias | CF_close_paragraph, LINE_line, 1,
-"defvr", CF_block | CF_def | CF_close_paragraph, BLOCK_def, 0,
-"defvrx", CF_line | CF_def | CF_close_paragraph, LINE_line, 1,
-"detailmenu", CF_block | CF_close_paragraph | CF_global, BLOCK_menu, 0,
+"defblock", CF_block | CF_no_paragraph | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"defcodeindex", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 1,
+"defcv", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"defcvx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deffn", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deffnx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"defindex", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 1,
+"definfoenclose", CF_line | CF_no_paragraph | CF_contain_plain_text | CF_deprecated, LINE_specific, 3,
+"defivar", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defivarx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defline", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"defmac", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defmacx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defmethod", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defmethodx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defop", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"defopt", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defoptx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defopx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"defspec", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defspecx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"deftp", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deftpx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deftypecv", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deftypecvx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deftypefn", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deftypefnnewline", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"deftypefnx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deftypefun", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"deftypefunx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"deftypeivar", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"deftypeivarx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"deftypeline", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deftypemethod", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"deftypemethodx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"deftypeop", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deftypeopx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"deftypevar", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"deftypevarx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"deftypevr", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"deftypevrx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"defun", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defunx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defvar", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, BLOCK_def, 0,
+"defvarx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_def_alias | CF_close_paragraph, LINE_line, 1,
+"defvr", CF_block | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, BLOCK_def, 0,
+"defvrx", CF_line | CF_no_paragraph | CF_def | CF_contain_basic_inline | CF_close_paragraph, LINE_line, 1,
+"detailmenu", CF_block | CF_no_paragraph | CF_close_paragraph | CF_global, BLOCK_menu, 0,
"dfn", CF_brace, BRACE_style_other, 1,
-"dh", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"dircategory", CF_line | CF_close_paragraph | CF_contain_simple_text, LINE_line, 1,
-"direntry", CF_block | CF_close_paragraph, BLOCK_menu, 0,
-"display", CF_block | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
-"displaymath", CF_block | CF_close_paragraph | CF_math, BLOCK_math, 0,
+"dh", CF_brace, BRACE_noarg, 0,
+"dircategory", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_basic_inline, LINE_line, 1,
+"direntry", CF_block | CF_no_paragraph | CF_close_paragraph, BLOCK_menu, 0,
+"display", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
+"displaymath", CF_block | CF_no_paragraph | CF_close_paragraph | CF_math, BLOCK_math, 0,
"dmn", CF_brace | CF_contain_plain_text, BRACE_other, 1,
-"docbook", CF_block, BLOCK_format_raw, 0,
-"documentdescription", CF_block | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
-"documentencoding", CF_line | CF_global | CF_contain_plain_text, LINE_text, 1,
-"documentlanguage", CF_line | CF_global | CF_contain_plain_text | CF_contain_plain_text, LINE_text, 1,
+"docbook", CF_block | CF_no_paragraph, BLOCK_format_raw, 0,
+"documentdescription", CF_block | CF_no_paragraph | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
+"documentencoding", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_text, 1,
+"documentlanguage", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_text, 1,
"dotaccent", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"dotless", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"dots", CF_brace, BRACE_noarg, 0,
-"email", CF_brace | CF_contain_simple_text, BRACE_arguments, 2,
+"email", CF_brace | CF_contain_basic_inline, BRACE_arguments, 2,
"emph", CF_brace, BRACE_style_other, 1,
-"end", CF_line | CF_contain_plain_text, LINE_text, 1,
+"end", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_text, 1,
"enddots", CF_brace, BRACE_noarg, 0,
-"enumerate", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_item_container, 1,
+"enumerate", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_item_container, 1,
"env", CF_brace, BRACE_style_code, 1,
"equiv", CF_brace, BRACE_noarg, 0,
"error", CF_brace, BRACE_noarg, 0,
-"errormsg", CF_brace | CF_contain_simple_text, BRACE_arguments, 1,
+"errormsg", CF_brace | CF_contain_basic_inline | CF_no_paragraph, BRACE_arguments, 1,
"euro", CF_brace, BRACE_noarg, 0,
-"evenfooting", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"evenfootingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"evenheading", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"evenheadingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"everyfooting", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"everyfootingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"everyheading", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"everyheadingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"example", CF_block | CF_close_paragraph | CF_preformatted | CF_preformatted_code | CF_variadic | CF_contain_simple_text, BLOCK_preformatted, 0,
-"exampleindent", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"evenfooting", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"evenfootingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"evenheading", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"evenheadingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"everyfooting", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"everyfootingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"everyheading", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"everyheadingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"example", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted | CF_preformatted_code | CF_variadic | CF_contain_basic_inline, BLOCK_preformatted, 0,
+"exampleindent", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
"exclamdown", CF_brace, BRACE_noarg, 0,
-"exdent", CF_line | CF_close_paragraph, LINE_line, 1,
+"exdent", CF_line | CF_no_paragraph | CF_close_paragraph, LINE_line, 1,
"expansion", CF_brace, BRACE_noarg, 0,
"file", CF_brace, BRACE_style_code, 1,
-"finalout", CF_line, LINE_skipline, 1,
-"firstparagraphindent", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"float", CF_block | CF_close_paragraph | CF_contain_simple_text, BLOCK_float, 2,
-"flushleft", CF_block | CF_close_paragraph, 0, 0,
-"flushright", CF_block | CF_close_paragraph, 0, 0,
-"fonttextsize", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"finalout", CF_line | CF_no_paragraph, LINE_lineraw, 0,
+"firstparagraphindent", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"float", CF_block | CF_no_paragraph | CF_close_paragraph | CF_global | CF_contain_basic_inline, BLOCK_float, 2,
+"flushleft", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
+"flushright", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
+"fonttextsize", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
"footnote", CF_brace | CF_global, BRACE_context, 1,
-"footnotestyle", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"format", CF_block | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
-"frenchspacing", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"ftable", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_item_line, 1,
+"footnotestyle", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"format", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
+"frenchspacing", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"ftable", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_item_line, 1,
"geq", CF_brace, BRACE_noarg, 0,
-"group", CF_block | CF_close_paragraph, 0, 0,
+"group", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
"guillemetleft", CF_brace, BRACE_noarg, 0,
"guillemetright", CF_brace, BRACE_noarg, 0,
"guillemotleft", CF_brace, BRACE_noarg, 0,
@@ -181,90 +184,94 @@ COMMAND builtin_command_data[] = {
"guilsinglleft", CF_brace, BRACE_noarg, 0,
"guilsinglright", CF_brace, BRACE_noarg, 0,
"hashchar", CF_brace, BRACE_noarg, 0,
-"heading", CF_line | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
-"headings", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"headitem", CF_nobrace | CF_close_paragraph, NOBRACE_skipspace, 1,
+"heading", CF_line | CF_no_paragraph | CF_contain_basic_inline | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
+"headings", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"headitem", CF_nobrace | CF_close_paragraph | CF_no_paragraph, NOBRACE_skipspace, 0,
"headitemfont", CF_brace, BRACE_style_other, 1,
-"html", CF_block, BLOCK_format_raw, 0,
-"hyphenation", CF_brace | CF_global | CF_contain_plain_text, BRACE_arguments, 1,
+"html", CF_block | CF_no_paragraph, BLOCK_format_raw, 0,
+"hyphenation", CF_brace | CF_global | CF_contain_plain_text | CF_no_paragraph, BRACE_arguments, 1,
"i", CF_brace, BRACE_style_other, 1,
-"ifclear", CF_block, BLOCK_conditional, 0,
-"ifcommanddefined", CF_block, BLOCK_conditional, 0,
-"ifcommandnotdefined", CF_block, BLOCK_conditional, 0,
-"ifdocbook", CF_block, BLOCK_conditional, 0,
-"ifhtml", CF_block, BLOCK_conditional, 0,
-"ifinfo", CF_block, BLOCK_conditional, 0,
-"iflatex", CF_block, BLOCK_conditional, 0,
-"ifnotdocbook", CF_block, BLOCK_conditional, 0,
-"ifnothtml", CF_block, BLOCK_conditional, 0,
-"ifnotinfo", CF_block, BLOCK_conditional, 0,
-"ifnotlatex", CF_block, BLOCK_conditional, 0,
-"ifnotplaintext", CF_block, BLOCK_conditional, 0,
-"ifnottex", CF_block, BLOCK_conditional, 0,
-"ifnotxml", CF_block, BLOCK_conditional, 0,
-"ifplaintext", CF_block, BLOCK_conditional, 0,
-"ifset", CF_block, BLOCK_conditional, 0,
-"iftex", CF_block, BLOCK_conditional, 0,
-"ifxml", CF_block, BLOCK_conditional, 0,
-"ignore", CF_block, BLOCK_raw, 0,
-"image", CF_brace | CF_contain_simple_text, BRACE_arguments, 5,
-"include", CF_line | CF_contain_plain_text, LINE_text, 1,
-"indent", CF_nobrace, NOBRACE_skipspace, 0,
-"indentedblock", CF_block | CF_close_paragraph, 0, 0,
+"ifclear", CF_block | CF_no_paragraph, BLOCK_conditional, 1,
+"ifcommanddefined", CF_block | CF_no_paragraph, BLOCK_conditional, 1,
+"ifcommandnotdefined", CF_block | CF_no_paragraph, BLOCK_conditional, 1,
+"ifdocbook", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifhtml", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifinfo", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"iflatex", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnotdocbook", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnothtml", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnotinfo", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnotlatex", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnotplaintext", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnottex", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifnotxml", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifplaintext", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifset", CF_block | CF_no_paragraph, BLOCK_conditional, 1,
+"iftex", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ifxml", CF_block | CF_no_paragraph, BLOCK_conditional, 0,
+"ignore", CF_block | CF_no_paragraph, BLOCK_raw, 0,
+"image", CF_brace | CF_contain_basic_inline | CF_no_paragraph, BRACE_arguments, 5,
+"include", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_text, 1,
+"indent", CF_nobrace | CF_no_paragraph, NOBRACE_skipspace, 0,
+"indentedblock", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
"indicateurl", CF_brace, BRACE_style_code, 1,
-"inforef", CF_brace | CF_ref | CF_contain_simple_text | CF_deprecated, BRACE_arguments, 3,
+"inforef", CF_brace | CF_ref | CF_contain_basic_inline | CF_deprecated, BRACE_arguments, 3,
"inlinefmt", CF_brace, BRACE_inline, 2,
"inlinefmtifelse", CF_brace, BRACE_inline, 3,
"inlineifclear", CF_brace, BRACE_inline, 2,
"inlineifset", CF_brace, BRACE_inline, 2,
"inlineraw", CF_brace, BRACE_inline, 2,
-"insertcopying", CF_line | CF_close_paragraph | CF_global, LINE_skipline, 1,
-"item", CF_nobrace | CF_close_paragraph, NOBRACE_skipspace, 1,
-"item_LINE", CF_line | CF_close_paragraph | CF_contain_simple_text, LINE_line, 1,
-"itemize", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_item_container, 1,
-"itemx", CF_line | CF_close_paragraph | CF_contain_simple_text, LINE_line, 1,
+"insertcopying", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global, LINE_lineraw, 0,
+"item", CF_nobrace | CF_close_paragraph | CF_no_paragraph, NOBRACE_skipspace, 0,
+"item_LINE", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_basic_inline, LINE_line, 1,
+"itemize", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_item_container, 1,
+"itemx", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_basic_inline, LINE_line, 1,
"kbd", CF_brace, BRACE_style_code, 1,
-"kbdinputstyle", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"kbdinputstyle", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
"key", CF_brace | CF_contain_plain_text, BRACE_style_code, 1,
-"l", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"latex", CF_block, BLOCK_format_raw, 0,
+"l", CF_brace, BRACE_noarg, 0,
+"latex", CF_block | CF_no_paragraph, BLOCK_format_raw, 0,
"lbracechar", CF_brace, BRACE_noarg, 0,
"leq", CF_brace, BRACE_noarg, 0,
-"lisp", CF_block | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
-"listoffloats", CF_line | CF_close_paragraph | CF_global | CF_contain_simple_text, LINE_line, 1,
-"lowersections", CF_line, LINE_skipline, 1,
-"macro", CF_block, BLOCK_raw, 0,
-"majorheading", CF_line | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
-"math", CF_brace | CF_math | CF_contain_simple_text, BRACE_context, 1,
-"menu", CF_block | CF_close_paragraph, BLOCK_menu, 0,
-"microtype", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"linemacro", CF_block | CF_no_paragraph, BLOCK_raw, 0,
+"link", CF_brace | CF_ref | CF_contain_basic_inline, BRACE_arguments, 3,
+"lisp", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
+"listoffloats", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global | CF_contain_basic_inline, LINE_line, 1,
+"lowersections", CF_line | CF_no_paragraph, LINE_lineraw, 0,
+"macro", CF_block | CF_no_paragraph, BLOCK_raw, 0,
+"majorheading", CF_line | CF_no_paragraph | CF_contain_basic_inline | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
+"math", CF_brace | CF_math | CF_contain_basic_inline, BRACE_context, 1,
+"menu", CF_block | CF_no_paragraph | CF_close_paragraph, BLOCK_menu, 0,
+"microtype", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
"minus", CF_brace, BRACE_noarg, 0,
-"multitable", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_multitable, 0,
-"need", CF_line | CF_close_paragraph | CF_contain_plain_text, LINE_specific, 1,
-"node", CF_line | CF_root | CF_contain_simple_text, LINE_line, 4,
-"noindent", CF_nobrace, NOBRACE_skipspace, 0,
-"novalidate", CF_line | CF_global_unique, LINE_skipline, 1,
-"o", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"oddfooting", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"oddfootingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"oddheading", CF_line | CF_global | CF_heading_spec | CF_contain_simple_text, LINE_line, 1,
-"oddheadingmarks", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"oe", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
+"multitable", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_multitable, 0,
+"need", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_plain_text, LINE_specific, 1,
+"node", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline, LINE_line, 4,
+"nodedescription", CF_line | CF_no_paragraph | CF_close_paragraph, LINE_line, 1,
+"nodedescriptionblock", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
+"noindent", CF_nobrace | CF_no_paragraph, NOBRACE_skipspace, 0,
+"novalidate", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"o", CF_brace, BRACE_noarg, 0,
+"oddfooting", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"oddfootingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"oddheading", CF_line | CF_no_paragraph | CF_global | CF_heading_spec | CF_contain_basic_inline, LINE_line, 1,
+"oddheadingmarks", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"oe", CF_brace, BRACE_noarg, 0,
"ogonek", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"option", CF_brace, BRACE_style_code, 1,
"ordf", CF_brace, BRACE_noarg, 0,
"ordm", CF_brace, BRACE_noarg, 0,
-"page", CF_line | CF_close_paragraph, LINE_skipline, 1,
-"pagesizes", CF_line | CF_global_unique | CF_contain_plain_text, LINE_line, 1,
-"paragraphindent", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"part", CF_line | CF_root | CF_sectioning_heading | CF_global, LINE_line, 1,
+"page", CF_line | CF_no_paragraph | CF_close_paragraph, LINE_lineraw, 0,
+"pagesizes", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_line, 1,
+"paragraphindent", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"part", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading | CF_global, LINE_line, 1,
"point", CF_brace, BRACE_noarg, 0,
"pounds", CF_brace, BRACE_noarg, 0,
"print", CF_brace, BRACE_noarg, 0,
-"printindex", CF_line | CF_close_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"pxref", CF_brace | CF_ref | CF_contain_simple_text, BRACE_arguments, 5,
+"printindex", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"pxref", CF_brace | CF_ref | CF_contain_basic_inline, BRACE_arguments, 5,
"questiondown", CF_brace, BRACE_noarg, 0,
-"quotation", CF_block | CF_close_paragraph | CF_contain_simple_text, BLOCK_quotation, 1,
+"quotation", CF_block | CF_no_paragraph | CF_close_paragraph | CF_contain_basic_inline, BLOCK_quotation, 1,
"quotedblbase", CF_brace, BRACE_noarg, 0,
"quotedblleft", CF_brace, BRACE_noarg, 0,
"quotedblright", CF_brace, BRACE_noarg, 0,
@@ -272,99 +279,99 @@ COMMAND builtin_command_data[] = {
"quoteright", CF_brace, BRACE_noarg, 0,
"quotesinglbase", CF_brace, BRACE_noarg, 0,
"r", CF_brace, BRACE_style_no_code, 1,
-"raggedright", CF_block | CF_close_paragraph, 0, 0,
-"raisesections", CF_line, LINE_skipline, 1,
+"raggedright", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
+"raisesections", CF_line | CF_no_paragraph, LINE_lineraw, 0,
"rbracechar", CF_brace, BRACE_noarg, 0,
-"ref", CF_brace | CF_ref | CF_contain_simple_text, BRACE_arguments, 5,
-"refill", CF_nobrace | CF_deprecated, NOBRACE_other, 1,
+"ref", CF_brace | CF_ref | CF_contain_basic_inline, BRACE_arguments, 5,
+"refill", CF_nobrace | CF_deprecated | CF_no_paragraph, NOBRACE_other, 0,
"registeredsymbol", CF_brace, BRACE_noarg, 0,
"result", CF_brace, BRACE_noarg, 0,
"ringaccent", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"rmacro", CF_block, BLOCK_raw, 0,
+"rmacro", CF_block | CF_no_paragraph, BLOCK_raw, 0,
"samp", CF_brace, BRACE_style_code, 1,
"sansserif", CF_brace, BRACE_style_other, 1,
"sc", CF_brace, BRACE_style_other, 1,
-"section", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"seealso", CF_brace | CF_contain_simple_text, BRACE_arguments, 1,
-"seeentry", CF_brace | CF_contain_simple_text, BRACE_arguments, 1,
-"set", CF_line, LINE_special, 1,
-"setchapternewpage", CF_line | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
-"setfilename", CF_line | CF_close_paragraph | CF_global_unique | CF_contain_plain_text, LINE_text, 1,
-"settitle", CF_line | CF_global_unique | CF_contain_simple_text, LINE_line, 1,
-"shortcaption", CF_brace | CF_close_paragraph | CF_contain_simple_text, BRACE_context, 1,
-"shortcontents", CF_line | CF_close_paragraph | CF_global, LINE_skipline, 1,
-"shorttitlepage", CF_line | CF_global_unique | CF_contain_simple_text, LINE_line, 1,
+"section", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"seealso", CF_brace | CF_contain_basic_inline, BRACE_arguments, 1,
+"seeentry", CF_brace | CF_contain_basic_inline, BRACE_arguments, 1,
+"set", CF_line | CF_no_paragraph, LINE_lineraw, 2,
+"setchapternewpage", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_plain_text, LINE_specific, 1,
+"setfilename", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global_unique | CF_contain_plain_text, LINE_text, 1,
+"settitle", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_basic_inline, LINE_line, 1,
+"shortcaption", CF_brace | CF_close_paragraph | CF_contain_basic_inline | CF_no_paragraph, BRACE_context, 1,
+"shortcontents", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global, LINE_lineraw, 0,
+"shorttitlepage", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_basic_inline, LINE_line, 1,
"slanted", CF_brace, BRACE_style_other, 1,
-"smallbook", CF_line | CF_global_unique, LINE_skipline, 1,
-"smalldisplay", CF_block | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
-"smallexample", CF_block | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
-"smallformat", CF_block | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
-"smallindentedblock", CF_block | CF_close_paragraph, 0, 0,
-"smalllisp", CF_block | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
-"smallquotation", CF_block | CF_close_paragraph | CF_contain_simple_text, BLOCK_quotation, 1,
+"smallbook", CF_line | CF_no_paragraph | CF_global_unique, LINE_lineraw, 0,
+"smalldisplay", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
+"smallexample", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
+"smallformat", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted, BLOCK_preformatted, 0,
+"smallindentedblock", CF_block | CF_no_paragraph | CF_close_paragraph, 0, 0,
+"smalllisp", CF_block | CF_no_paragraph | CF_close_paragraph | CF_preformatted | CF_preformatted_code, BLOCK_preformatted, 0,
+"smallquotation", CF_block | CF_no_paragraph | CF_close_paragraph | CF_contain_basic_inline, BLOCK_quotation, 1,
"sortas", CF_brace | CF_contain_plain_text, BRACE_arguments, 1,
-"sp", CF_line | CF_close_paragraph | CF_contain_plain_text, LINE_specific, 1,
-"ss", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
+"sp", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_plain_text, LINE_specific, 1,
+"ss", CF_brace, BRACE_noarg, 0,
"strong", CF_brace, BRACE_style_other, 1,
"sub", CF_brace, BRACE_style_other, 1,
-"subentry", CF_line | CF_contain_simple_text, LINE_line, 1,
-"subheading", CF_line | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
-"subsection", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"subsubheading", CF_line | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
-"subsubsection", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"subtitle", CF_line | CF_global | CF_contain_simple_text, LINE_line, 1,
-"summarycontents", CF_line | CF_close_paragraph | CF_global, LINE_skipline, 1,
+"subentry", CF_line | CF_no_paragraph | CF_contain_basic_inline, LINE_line, 1,
+"subheading", CF_line | CF_no_paragraph | CF_contain_basic_inline | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
+"subsection", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"subsubheading", CF_line | CF_no_paragraph | CF_contain_basic_inline | CF_sectioning_heading | CF_close_paragraph, LINE_line, 1,
+"subsubsection", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"subtitle", CF_line | CF_no_paragraph | CF_global | CF_contain_basic_inline, LINE_line, 1,
+"summarycontents", CF_line | CF_no_paragraph | CF_close_paragraph | CF_global, LINE_lineraw, 0,
"sup", CF_brace, BRACE_style_other, 1,
-"syncodeindex", CF_line | CF_contain_plain_text, LINE_specific, 2,
-"synindex", CF_line | CF_contain_plain_text, LINE_specific, 2,
+"syncodeindex", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 2,
+"synindex", CF_line | CF_no_paragraph | CF_contain_plain_text, LINE_specific, 2,
"t", CF_brace, BRACE_style_code, 1,
-"tab", CF_nobrace | CF_close_paragraph, NOBRACE_skipspace, 1,
-"table", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_item_line, 1,
-"tex", CF_block, BLOCK_format_raw, 0,
+"tab", CF_nobrace | CF_close_paragraph | CF_no_paragraph, NOBRACE_skipspace, 0,
+"table", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_item_line, 1,
+"tex", CF_block | CF_no_paragraph, BLOCK_format_raw, 0,
"textdegree", CF_brace, BRACE_noarg, 0,
-"th", CF_brace | CF_letter_no_arg, BRACE_noarg, 0,
-"thischapter", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thischaptername", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thischapternum", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thisfile", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thispage", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thissection", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thissectionname", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thissectionnum", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
-"thistitle", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 1,
+"th", CF_brace, BRACE_noarg, 0,
+"thischapter", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thischaptername", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thischapternum", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thisfile", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thispage", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thissection", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thissectionname", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thissectionnum", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
+"thistitle", CF_nobrace | CF_in_heading_spec, NOBRACE_other, 0,
"tie", CF_brace, BRACE_noarg, 0,
"tieaccent", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"title", CF_line | CF_global_unique | CF_contain_simple_text, LINE_line, 1,
-"titlefont", CF_brace | CF_close_paragraph | CF_global | CF_contain_simple_text, BRACE_other, 1,
-"titlepage", CF_block | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
+"title", CF_line | CF_no_paragraph | CF_global_unique | CF_contain_basic_inline, LINE_line, 1,
+"titlefont", CF_brace | CF_close_paragraph | CF_global | CF_contain_basic_inline | CF_no_paragraph, BRACE_other, 1,
+"titlepage", CF_block | CF_no_paragraph | CF_close_paragraph | CF_global_unique, BLOCK_region, 0,
"today", CF_brace, BRACE_noarg, 0,
-"top", CF_line | CF_root | CF_sectioning_heading | CF_global_unique, LINE_line, 1,
+"top", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading | CF_global_unique, LINE_line, 1,
"txiinternalvalue", CF_internal | CF_brace, INTERNAL_brace, 1,
"u", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"ubaraccent", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"udotaccent", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
-"unmacro", CF_line, LINE_special, 1,
-"unnumbered", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"unnumberedsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"unnumberedsubsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"unnumberedsubsubsec", CF_line | CF_root | CF_sectioning_heading, LINE_line, 1,
-"uref", CF_brace | CF_contain_simple_text, BRACE_arguments, 3,
-"urefbreakstyle", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
-"url", CF_brace | CF_contain_simple_text, BRACE_arguments, 3,
+"unmacro", CF_line | CF_no_paragraph, LINE_lineraw, 1,
+"unnumbered", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"unnumberedsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"unnumberedsubsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"unnumberedsubsubsec", CF_line | CF_no_paragraph | CF_root | CF_contain_basic_inline | CF_sectioning_heading, LINE_line, 1,
+"uref", CF_brace | CF_contain_basic_inline, BRACE_arguments, 3,
+"urefbreakstyle", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"url", CF_brace | CF_contain_basic_inline, BRACE_arguments, 3,
"v", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
"value", CF_brace, BRACE_special, 1,
"var", CF_brace, BRACE_style_other, 1,
"verb", CF_brace, BRACE_special, 1,
-"verbatim", CF_block | CF_close_paragraph, BLOCK_raw, 0,
-"verbatiminclude", CF_line | CF_close_paragraph | CF_contain_plain_text, LINE_text, 1,
-"vskip", CF_line, LINE_lineraw, 1,
-"vtable", CF_block | CF_close_paragraph | CF_blockitem | CF_contain_simple_text, BLOCK_item_line, 1,
-"w", CF_brace | CF_contain_simple_text, BRACE_special, 1,
-"xml", CF_block, BLOCK_format_raw, 0,
-"xref", CF_brace | CF_ref | CF_contain_simple_text, BRACE_arguments, 5,
-"xrefautomaticsectiontitle", CF_line | CF_global | CF_contain_plain_text, LINE_specific, 1,
+"verbatim", CF_block | CF_no_paragraph | CF_close_paragraph, BLOCK_raw, 0,
+"verbatiminclude", CF_line | CF_no_paragraph | CF_close_paragraph | CF_contain_plain_text, LINE_text, 1,
+"vskip", CF_line | CF_no_paragraph, LINE_lineraw, 1,
+"vtable", CF_block | CF_no_paragraph | CF_close_paragraph | CF_blockitem | CF_contain_basic_inline, BLOCK_item_line, 1,
+"w", CF_brace | CF_contain_basic_inline, BRACE_special, 1,
+"xml", CF_block | CF_no_paragraph, BLOCK_format_raw, 0,
+"xref", CF_brace | CF_ref | CF_contain_basic_inline, BRACE_arguments, 5,
+"xrefautomaticsectiontitle", CF_line | CF_no_paragraph | CF_global | CF_contain_plain_text, LINE_specific, 1,
"{", CF_nobrace, NOBRACE_symbol, 0,
-"|", CF_nobrace | CF_in_heading_spec, NOBRACE_symbol, 1,
+"|", CF_nobrace | CF_in_heading_spec, NOBRACE_symbol, 0,
"}", CF_nobrace, NOBRACE_symbol, 0,
"~", CF_brace | CF_accent | CF_contain_plain_text, BRACE_accent, 1,
};
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.txt b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.txt
deleted file mode 100644
index db884cb5fb..0000000000
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_data.txt
+++ /dev/null
@@ -1,573 +0,0 @@
-# Copyright 2010-2020 Free Software Foundation, Inc.
-#
-# This file is part of GNU Texinfo.
-#
-# GNU Texinfo is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License,
-# or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# this information is used to setup both the XS Parser commands
-# builtin_command_data and the perl Parser commands classification
-# hashes.
-
-# Some documentation of the flags (second column) is in commands.h.
-
-##############################################################
-# Internal commands
-# invalid if not accept_internalvalue set in configuration
-txiinternalvalue internal,brace INTERNAL_brace
-
-# nobrace:
-# commands never taking braces nor arguments on the line
-#
-# symbol: non-alphabetical one letter commands without braces.
-# skipspace: following spaces are skipped.
-# other: other.
-
-
-##############################################################
-# no brace commands - single letter commands
-
-* nobrace NOBRACE_symbol
-# space
-\x20 nobrace NOBRACE_symbol
-\t nobrace NOBRACE_symbol
-\n nobrace NOBRACE_symbol
-- nobrace NOBRACE_symbol
-| nobrace,in_heading_spec NOBRACE_symbol
-/ nobrace NOBRACE_symbol
-: nobrace NOBRACE_symbol
-! nobrace NOBRACE_symbol
-? nobrace NOBRACE_symbol
-. nobrace NOBRACE_symbol
-@ nobrace NOBRACE_symbol
-& nobrace NOBRACE_symbol
-} nobrace NOBRACE_symbol
-{ nobrace NOBRACE_symbol
-\\ nobrace NOBRACE_symbol
-
-##########################################################
-#
-# line commands
-#
-##########################################################
-
-# commands taking a line as argument or no argument.
-# index commands are added dynamically.
-#
-# The values signification is:
-# special: no value and macro expansion, all the line is used, and
-# analysed during parsing (_parse_special_misc_command)
-# lineraw: no value and macro expansion, the line is kept as-is, not
-# analysed
-# skipline: no argument, everything else on the line is skipped
-# text: the line is parsed as texinfo, and the argument is converted
-# to simple text with convert_to_text allowing only a few @-commands
-# line: the line is parsed as texinfo
-# specific: the line is parsed as texinfo and the result should be plain
-# text maybe followed by a comment; the result is analysed
-# during parsing (parse_line_command_args).
-#
-# Beware that @item may be a 'line' command or a 'nobrace' command
-# depending on the context.
-
-# line commands number of arguments is only set for LINE_specific commands
-# and is not used anywhere in the code, it is here as documentation only
-bye line LINE_skipline
-end line,contain_plain_text LINE_text
-# set, clear, special argument
-set line LINE_special
-clear line LINE_special
-unmacro line LINE_special
-# comments
-c line LINE_lineraw
-comment line LINE_lineraw
-# special
-definfoenclose line,contain_plain_text,deprecated LINE_specific 3
-alias line,contain_plain_text LINE_specific 2
-# number of arguments is not known in advance.
-columnfractions line,contain_plain_text LINE_specific
-# file names.
-setfilename line,close_paragraph,global_unique,contain_plain_text LINE_text
-verbatiminclude line,close_paragraph,contain_plain_text LINE_text
-include line,contain_plain_text LINE_text
-
-raisesections line LINE_skipline
-lowersections line LINE_skipline
-contents line,close_paragraph,global LINE_skipline
-shortcontents line,close_paragraph,global LINE_skipline
-summarycontents line,close_paragraph,global LINE_skipline
-insertcopying line,close_paragraph,global LINE_skipline
-# arg should be an @-command
-clickstyle line,global LINE_special
-# more relevant in preamble
-documentencoding line,global,contain_plain_text LINE_text
-novalidate line,global_unique LINE_skipline
-# Position with regard with direntry is significant
-dircategory line,close_paragraph,contain_simple_text LINE_line
-# arg like 200mm,150mm or 11.5in
-pagesizes line,global_unique,contain_plain_text LINE_line
-finalout line LINE_skipline
-# arg none asis
-# or a number and forbids anything else on the line
-paragraphindent line,global,contain_plain_text LINE_specific 1
-# arg none insert
-firstparagraphindent line,global,contain_plain_text LINE_specific 1
-# arg on off
-frenchspacing line,global,contain_plain_text LINE_specific 1
-# arg on off
-codequoteundirected line,global,contain_plain_text LINE_specific 1
-# arg on off
-codequotebacktick line,global,contain_plain_text LINE_specific 1
-# arg on off
-xrefautomaticsectiontitle line,global,contain_plain_text LINE_specific 1
-# arg on off
-deftypefnnewline line,global,contain_plain_text LINE_specific 1
-# arg 10 11
-fonttextsize line,global_unique,contain_plain_text LINE_specific 1
-# arg false or true
-allowcodebreaks line,global,contain_plain_text LINE_specific 1
-# arg asis or a number
-exampleindent line,global,contain_plain_text LINE_specific 1
-# args end and separate, nothing else on the line
-footnotestyle line,global_unique,contain_plain_text LINE_specific 1
-# arg after|before|none
-urefbreakstyle line,global,contain_plain_text LINE_specific 1
-smallbook line,global_unique LINE_skipline
-afourpaper line,global_unique LINE_skipline
-afivepaper line,global_unique LINE_skipline
-afourlatex line,global_unique LINE_skipline
-afourwide line,global_unique LINE_skipline
-bsixpaper line,global_unique LINE_skipline
-# arg off on single double singleafter doubleafter
-# interacts with setchapternewpage
-headings line,global,contain_plain_text LINE_specific 1
-# arg off on odd
-setchapternewpage line,global_unique,contain_plain_text LINE_specific 1
-# arg on off
-microtype line,global,contain_plain_text LINE_specific 1
-
-everyheading line,global,heading_spec,contain_simple_text LINE_line
-everyfooting line,global,heading_spec,contain_simple_text LINE_line
-evenheading line,global,heading_spec,contain_simple_text LINE_line
-evenfooting line,global,heading_spec,contain_simple_text LINE_line
-oddheading line,global,heading_spec,contain_simple_text LINE_line
-oddfooting line,global,heading_spec,contain_simple_text LINE_line
-
-# args are index identifiers
-syncodeindex line,contain_plain_text LINE_specific 2
-synindex line,contain_plain_text LINE_specific 2
-# one identifier arg
-defindex line,contain_plain_text LINE_specific 1
-# one identifier arg
-defcodeindex line,contain_plain_text LINE_specific 1
-# language code arg
-documentlanguage line,global,contain_plain_text,contain_plain_text LINE_text
-# arg code example distinct
-kbdinputstyle line,global,contain_plain_text LINE_specific 1
-# arg top bottom
-everyheadingmarks line,global_unique,contain_plain_text LINE_specific 1
-everyfootingmarks line,global_unique,contain_plain_text LINE_specific 1
-evenheadingmarks line,global_unique,contain_plain_text LINE_specific 1
-oddheadingmarks line,global_unique,contain_plain_text LINE_specific 1
-evenfootingmarks line,global_unique,contain_plain_text LINE_specific 1
-oddfootingmarks line,global_unique,contain_plain_text LINE_specific 1
-
-# formatting
-center line,close_paragraph LINE_line
-printindex line,close_paragraph,global,contain_plain_text LINE_specific 1
-listoffloats line,close_paragraph,global,contain_simple_text LINE_line
-# especially in titlepage
-# shorttitle
-shorttitlepage line,global_unique,contain_simple_text LINE_line
-settitle line,global_unique,contain_simple_text LINE_line
-author line,global,contain_simple_text LINE_line
-subtitle line,global,contain_simple_text LINE_line
-title line,global_unique,contain_simple_text LINE_line
-# numerical arg
-sp line,close_paragraph,contain_plain_text LINE_specific 1
-page line,close_paragraph LINE_skipline
-# one numerical/real arg
-need line,close_paragraph,contain_plain_text LINE_specific 1
-
-# not valid for info (should be in @iftex)
-vskip line LINE_lineraw
-
-exdent line,close_paragraph LINE_line
-
-# or nobrace skipspace, depending on the context
-item_LINE line,close_paragraph,contain_simple_text LINE_line
-itemx line,close_paragraph,contain_simple_text LINE_line
-
-subentry line,contain_simple_text LINE_line
-
-##########################################################
-#
-# no brace commands - miscellaneous commands
-#
-##########################################################
-
-# formatting
-noindent nobrace NOBRACE_skipspace
-indent nobrace NOBRACE_skipspace
-headitem nobrace,close_paragraph NOBRACE_skipspace
-item nobrace,close_paragraph NOBRACE_skipspace
-tab nobrace,close_paragraph NOBRACE_skipspace
-# only valid in heading or footing
-thischapter nobrace,in_heading_spec NOBRACE_other
-thischaptername nobrace,in_heading_spec NOBRACE_other
-thischapternum nobrace,in_heading_spec NOBRACE_other
-thissection nobrace,in_heading_spec NOBRACE_other
-thissectionname nobrace,in_heading_spec NOBRACE_other
-thissectionnum nobrace,in_heading_spec NOBRACE_other
-thisfile nobrace,in_heading_spec NOBRACE_other
-thispage nobrace,in_heading_spec NOBRACE_other
-thistitle nobrace,in_heading_spec NOBRACE_other
-# obsolete @-commands.
-refill nobrace,deprecated NOBRACE_other
-
-
-
-##########################################################
-#
-# brace commands
-#
-##########################################################
-
-# letter_no_arg_commands
-aa brace,letter_no_arg BRACE_noarg
-AA brace,letter_no_arg BRACE_noarg
-ae brace,letter_no_arg BRACE_noarg
-oe brace,letter_no_arg BRACE_noarg
-AE brace,letter_no_arg BRACE_noarg
-OE brace,letter_no_arg BRACE_noarg
-o brace,letter_no_arg BRACE_noarg
-O brace,letter_no_arg BRACE_noarg
-ss brace,letter_no_arg BRACE_noarg
-l brace,letter_no_arg BRACE_noarg
-L brace,letter_no_arg BRACE_noarg
-DH brace,letter_no_arg BRACE_noarg
-dh brace,letter_no_arg BRACE_noarg
-TH brace,letter_no_arg BRACE_noarg
-th brace,letter_no_arg BRACE_noarg
-
-# no arg commands
-TeX brace BRACE_noarg
-LaTeX brace BRACE_noarg
-bullet brace BRACE_noarg
-copyright brace BRACE_noarg
-registeredsymbol brace BRACE_noarg
-dots brace BRACE_noarg
-enddots brace BRACE_noarg
-equiv brace BRACE_noarg
-error brace BRACE_noarg
-expansion brace BRACE_noarg
-arrow brace BRACE_noarg
-minus brace BRACE_noarg
-point brace BRACE_noarg
-print brace BRACE_noarg
-result brace BRACE_noarg
-today brace BRACE_noarg
-exclamdown brace BRACE_noarg
-questiondown brace BRACE_noarg
-pounds brace BRACE_noarg
-ordf brace BRACE_noarg
-ordm brace BRACE_noarg
-atchar brace BRACE_noarg
-ampchar brace BRACE_noarg
-lbracechar brace BRACE_noarg
-rbracechar brace BRACE_noarg
-backslashchar brace BRACE_noarg
-hashchar brace BRACE_noarg
-comma brace BRACE_noarg
-euro brace BRACE_noarg
-geq brace BRACE_noarg
-leq brace BRACE_noarg
-tie brace BRACE_noarg
-textdegree brace BRACE_noarg
-click brace BRACE_noarg
-quotedblleft brace BRACE_noarg
-quotedblright brace BRACE_noarg
-quoteleft brace BRACE_noarg
-quoteright brace BRACE_noarg
-quotedblbase brace BRACE_noarg
-quotesinglbase brace BRACE_noarg
-guillemetleft brace BRACE_noarg
-guillemetright brace BRACE_noarg
-guillemotleft brace BRACE_noarg
-guillemotright brace BRACE_noarg
-guilsinglleft brace BRACE_noarg
-guilsinglright brace BRACE_noarg
-
-# accent commands - can be called with or without braces
-\" brace,accent,contain_plain_text BRACE_accent
-~ brace,accent,contain_plain_text BRACE_accent
-^ brace,accent,contain_plain_text BRACE_accent
-` brace,accent,contain_plain_text BRACE_accent
-' brace,accent,contain_plain_text BRACE_accent
-, brace,accent,contain_plain_text BRACE_accent
-= brace,accent,contain_plain_text BRACE_accent
-ringaccent brace,accent,contain_plain_text BRACE_accent
-H brace,accent,contain_plain_text BRACE_accent
-dotaccent brace,accent,contain_plain_text BRACE_accent
-u brace,accent,contain_plain_text BRACE_accent
-ubaraccent brace,accent,contain_plain_text BRACE_accent
-udotaccent brace,accent,contain_plain_text BRACE_accent
-v brace,accent,contain_plain_text BRACE_accent
-ogonek brace,accent,contain_plain_text BRACE_accent
-tieaccent brace,accent,contain_plain_text BRACE_accent
-dotless brace,accent,contain_plain_text BRACE_accent
-
-# Style commands
-asis brace BRACE_style_other
-i brace BRACE_style_other
-b brace BRACE_style_other
-sansserif brace BRACE_style_other
-slanted brace BRACE_style_other
-cite brace BRACE_style_other
-clicksequence brace BRACE_style_other
-dfn brace BRACE_style_other
-emph brace BRACE_style_other
-sc brace BRACE_style_other
-var brace BRACE_style_other
-headitemfont brace BRACE_style_other
-strong brace BRACE_style_other
-sub brace BRACE_style_other
-sup brace BRACE_style_other
-
-# code style commands
-code brace BRACE_style_code
-command brace BRACE_style_code
-env brace BRACE_style_code
-file brace BRACE_style_code
-indicateurl brace BRACE_style_code
-kbd brace BRACE_style_code
-key brace,contain_plain_text BRACE_style_code
-option brace BRACE_style_code
-samp brace BRACE_style_code
-t brace BRACE_style_code
-
-# No code style commands
-r brace BRACE_style_no_code
-
-# in this category, the leading and trailing spaces are put in specific
-# text with type, but commas do not delimitate arguments.
-# As other arguments brace_commands, they can only contain simple text,
-# ie not ref, footnote, titlefont, anchor, verb.
-# Parsers have specific checks for U content.
-U brace BRACE_arguments 1
-hyphenation brace,global,contain_plain_text BRACE_arguments 1
-anchor brace,contain_simple_text BRACE_arguments 1
-errormsg brace,contain_simple_text BRACE_arguments 1
-sortas brace,contain_plain_text BRACE_arguments 1
-seeentry brace,contain_simple_text BRACE_arguments 1
-seealso brace,contain_simple_text BRACE_arguments 1
-
-# Leading and trailing spaces kept in main text.
-# verb is treated especially, it should not matter much in which category it is.
-# value also is treated especially.
-value brace BRACE_special
-verb brace BRACE_special
-w brace,contain_simple_text BRACE_special
-
-# other brace commands, leading and trailing spaces kept in main text
-dmn brace,contain_plain_text BRACE_other 1
-titlefont brace,close_paragraph,global,contain_simple_text BRACE_other 1
-
-# context brace commands - commands that enclose full texts
-# not in the main document context. They can contain multiple paragraphs.
-footnote brace,global BRACE_context
-caption brace,close_paragraph BRACE_context
-shortcaption brace,close_paragraph,contain_simple_text BRACE_context
-# Commands that enclose math content, and, because of that, are not in the
-# main document context.
-math brace,math,contain_simple_text BRACE_context
-
-# explained commands
-abbr brace,contain_simple_text BRACE_arguments 2
-acronym brace,contain_simple_text BRACE_arguments 2
-
-# leading space is ignored in inline brace commands, not trailing space
-# inline format command
-inlineraw brace BRACE_inline 2
-inlinefmt brace BRACE_inline 2
-inlinefmtifelse brace BRACE_inline 3
-
-# inline conditional commands
-inlineifclear brace BRACE_inline 2
-inlineifset brace BRACE_inline 2
-
-email brace,contain_simple_text BRACE_arguments 2
-
-uref brace,contain_simple_text BRACE_arguments 3
-url brace,contain_simple_text BRACE_arguments 3
-inforef brace,ref,contain_simple_text,deprecated BRACE_arguments 3
-
-xref brace,ref,contain_simple_text BRACE_arguments 5
-ref brace,ref,contain_simple_text BRACE_arguments 5
-pxref brace,ref,contain_simple_text BRACE_arguments 5
-image brace,contain_simple_text BRACE_arguments 5
-
-
-##########################################################
-# commands delimiting blocks, with an @end.
-
-# def* commands
-deffn block,def,close_paragraph BLOCK_def
-defvr block,def,close_paragraph BLOCK_def
-deftypefn block,def,close_paragraph BLOCK_def
-deftypeop block,def,close_paragraph BLOCK_def
-deftypevr block,def,close_paragraph BLOCK_def
-defcv block,def,close_paragraph BLOCK_def
-deftypecv block,def,close_paragraph BLOCK_def
-defop block,def,close_paragraph BLOCK_def
-deftp block,def,close_paragraph BLOCK_def
-# shortcuts
-defun block,def,def_alias,close_paragraph BLOCK_def
-defmac block,def,def_alias,close_paragraph BLOCK_def
-defspec block,def,def_alias,close_paragraph BLOCK_def
-defvar block,def,def_alias,close_paragraph BLOCK_def
-defopt block,def,def_alias,close_paragraph BLOCK_def
-deftypefun block,def,def_alias,close_paragraph BLOCK_def
-deftypevar block,def,def_alias,close_paragraph BLOCK_def
-defivar block,def,def_alias,close_paragraph BLOCK_def
-deftypeivar block,def,def_alias,close_paragraph BLOCK_def
-defmethod block,def,def_alias,close_paragraph BLOCK_def
-deftypemethod block,def,def_alias,close_paragraph BLOCK_def
-
-# def*x
-deffnx line,def,close_paragraph LINE_line
-defvrx line,def,close_paragraph LINE_line
-deftypefnx line,def,close_paragraph LINE_line
-deftypeopx line,def,close_paragraph LINE_line
-deftypevrx line,def,close_paragraph LINE_line
-defcvx line,def,close_paragraph LINE_line
-deftypecvx line,def,close_paragraph LINE_line
-defopx line,def,close_paragraph LINE_line
-deftpx line,def,close_paragraph LINE_line
-# shortcuts
-defunx line,def,def_alias,close_paragraph LINE_line
-defmacx line,def,def_alias,close_paragraph LINE_line
-defspecx line,def,def_alias,close_paragraph LINE_line
-defvarx line,def,def_alias,close_paragraph LINE_line
-defoptx line,def,def_alias,close_paragraph LINE_line
-deftypefunx line,def,def_alias,close_paragraph LINE_line
-deftypevarx line,def,def_alias,close_paragraph LINE_line
-defivarx line,def,def_alias,close_paragraph LINE_line
-deftypeivarx line,def,def_alias,close_paragraph LINE_line
-defmethodx line,def,def_alias,close_paragraph LINE_line
-deftypemethodx line,def,def_alias,close_paragraph LINE_line
-
-multitable block,close_paragraph,blockitem,contain_simple_text BLOCK_multitable
-
-# menu commands in which menu entry and menu comments appear
-menu block,close_paragraph BLOCK_menu
-detailmenu block,close_paragraph,global BLOCK_menu
-direntry block,close_paragraph BLOCK_menu
-
-# align commands
-raggedright block,close_paragraph
-flushleft block,close_paragraph
-flushright block,close_paragraph
-indentedblock block,close_paragraph
-smallindentedblock block,close_paragraph
-
-cartouche block,close_paragraph
-group block,close_paragraph
-
-# region commands
-titlepage block,close_paragraph,global_unique BLOCK_region
-copying block,close_paragraph,global_unique BLOCK_region
-documentdescription block,close_paragraph,global_unique BLOCK_region
-
-# preformatted commands
-example block,close_paragraph,preformatted,preformatted_code,variadic,contain_simple_text BLOCK_preformatted
-smallexample block,close_paragraph,preformatted,preformatted_code BLOCK_preformatted
-lisp block,close_paragraph,preformatted,preformatted_code BLOCK_preformatted
-smalllisp block,close_paragraph,preformatted,preformatted_code BLOCK_preformatted
-display block,close_paragraph,preformatted BLOCK_preformatted
-smalldisplay block,close_paragraph,preformatted BLOCK_preformatted
-format block,close_paragraph,preformatted BLOCK_preformatted
-smallformat block,close_paragraph,preformatted BLOCK_preformatted
-
-# format raw commands
-html block BLOCK_format_raw
-tex block BLOCK_format_raw
-xml block BLOCK_format_raw
-docbook block BLOCK_format_raw
-latex block BLOCK_format_raw
-
-# raw commands
-verbatim block,close_paragraph BLOCK_raw
-ignore block BLOCK_raw
-macro block BLOCK_raw
-rmacro block BLOCK_raw
-
-table block,close_paragraph,blockitem,contain_simple_text BLOCK_item_line 1
-ftable block,close_paragraph,blockitem,contain_simple_text BLOCK_item_line 1
-vtable block,close_paragraph,blockitem,contain_simple_text BLOCK_item_line 1
-itemize block,close_paragraph,blockitem,contain_simple_text BLOCK_item_container 1
-enumerate block,close_paragraph,blockitem,contain_simple_text BLOCK_item_container 1
-quotation block,close_paragraph,contain_simple_text BLOCK_quotation 1
-smallquotation block,close_paragraph,contain_simple_text BLOCK_quotation 1
-
-float block,close_paragraph,contain_simple_text BLOCK_float 2
-
-displaymath block,close_paragraph,math BLOCK_math
-
-##################################################################
-# Conditional commands
-ifhtml block BLOCK_conditional
-ifnothtml block BLOCK_conditional
-iftex block BLOCK_conditional
-ifnottex block BLOCK_conditional
-ifxml block BLOCK_conditional
-ifnotxml block BLOCK_conditional
-ifdocbook block BLOCK_conditional
-ifnotdocbook block BLOCK_conditional
-ifinfo block BLOCK_conditional
-ifnotinfo block BLOCK_conditional
-ifplaintext block BLOCK_conditional
-ifnotplaintext block BLOCK_conditional
-iflatex block BLOCK_conditional
-ifnotlatex block BLOCK_conditional
-ifset block BLOCK_conditional
-ifclear block BLOCK_conditional
-ifcommanddefined block BLOCK_conditional
-ifcommandnotdefined block BLOCK_conditional
-
-##########################################################
-# Root commands
-node line,root,contain_simple_text LINE_line 4
-top line,root,sectioning_heading,global_unique LINE_line
-chapter line,root,sectioning_heading LINE_line
-unnumbered line,root,sectioning_heading LINE_line
-chapheading line,sectioning_heading,close_paragraph LINE_line
-appendix line,root,sectioning_heading LINE_line
-section line,root,sectioning_heading LINE_line
-unnumberedsec line,root,sectioning_heading LINE_line
-heading line,sectioning_heading,close_paragraph LINE_line
-appendixsec line,root,sectioning_heading LINE_line
-subsection line,root,sectioning_heading LINE_line
-unnumberedsubsec line,root,sectioning_heading LINE_line
-subheading line,sectioning_heading,close_paragraph LINE_line
-appendixsubsec line,root,sectioning_heading LINE_line
-subsubsection line,root,sectioning_heading LINE_line
-unnumberedsubsubsec line,root,sectioning_heading LINE_line
-subsubheading line,sectioning_heading,close_paragraph LINE_line
-appendixsubsubsec line,root,sectioning_heading LINE_line
-
-part line,root,sectioning_heading,global LINE_line
-appendixsection line,root,sectioning_heading LINE_line
-majorheading line,sectioning_heading,close_paragraph LINE_line
-centerchap line,root,sectioning_heading,deprecated LINE_line
-
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_ids.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_ids.h
index a2c8542ad2..a5f17b72ce 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_ids.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/command_ids.h
@@ -110,6 +110,7 @@ CM_comment,
CM_contents,
CM_copying,
CM_copyright,
+CM_defblock,
CM_defcodeindex,
CM_defcv,
CM_defcvx,
@@ -119,6 +120,7 @@ CM_defindex,
CM_definfoenclose,
CM_defivar,
CM_defivarx,
+CM_defline,
CM_defmac,
CM_defmacx,
CM_defmethod,
@@ -140,6 +142,7 @@ CM_deftypefun,
CM_deftypefunx,
CM_deftypeivar,
CM_deftypeivarx,
+CM_deftypeline,
CM_deftypemethod,
CM_deftypemethodx,
CM_deftypeop,
@@ -262,6 +265,8 @@ CM_l,
CM_latex,
CM_lbracechar,
CM_leq,
+CM_linemacro,
+CM_link,
CM_lisp,
CM_listoffloats,
CM_lowersections,
@@ -274,6 +279,8 @@ CM_minus,
CM_multitable,
CM_need,
CM_node,
+CM_nodedescription,
+CM_nodedescriptionblock,
CM_noindent,
CM_novalidate,
CM_o,
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.c
index 943afa42fa..30b4cf89ac 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,10 +21,6 @@
#include "command_ids.h"
#include "commands.h"
#include "errors.h"
-
-/* FIXME pass global_accept_internalvalue to lookup_command instead of
- * #include parser.h to get the global variable value? */
-
/* for global_accept_internalvalue */
#include "parser.h"
@@ -95,6 +91,30 @@ lookup_command (char *cmdname)
enum command_id
add_texinfo_command (char *name)
{
+ enum command_id existing_cmd = lookup_command (name);
+
+ if (existing_cmd & USER_COMMAND_BIT)
+ {
+ enum command_id user_data_cmd = existing_cmd & ~USER_COMMAND_BIT;
+ /* FIXME it is consistent with silent replacement of macro
+ by another user-defined command to remove the information
+ on a previously defined macro, but it may not be right, or
+ at least there could be a warning as there is a warning when
+ a macro is redefined. */
+ if (user_defined_command_data[user_data_cmd].flags & CF_MACRO)
+ {
+ MACRO *m = lookup_macro (existing_cmd);
+ unset_macro_record (m);
+ }
+ if (user_defined_command_data[user_data_cmd].flags & CF_REGISTERED)
+ user_defined_command_data[user_data_cmd].flags = (0 & CF_REGISTERED);
+ else
+ user_defined_command_data[user_data_cmd].flags = 0;
+ user_defined_command_data[user_data_cmd].data = 0;
+ user_defined_command_data[user_data_cmd].args_number = 0;
+ return existing_cmd;
+ }
+
if (user_defined_number == user_defined_space)
{
user_defined_command_data
@@ -117,8 +137,19 @@ void
remove_texinfo_command (enum command_id cmd)
{
cmd &= ~USER_COMMAND_BIT;
- free (user_defined_command_data[cmd].cmdname);
- user_defined_command_data[cmd].cmdname = strdup ("");
+ /* only pretend to remove if REGISTERED, but reset */
+ if (user_defined_command_data[cmd].flags & CF_REGISTERED)
+ {
+ user_defined_command_data[cmd].data = 0;
+ user_defined_command_data[cmd].flags = (0 | CF_REGISTERED | CF_UNKNOWN);
+ user_defined_command_data[cmd].args_number = 0;
+ }
+ else
+ {
+ /* FIXME the cmd is never reused */
+ free (user_defined_command_data[cmd].cmdname);
+ user_defined_command_data[cmd].cmdname = strdup ("");
+ }
}
void
@@ -134,7 +165,8 @@ int
close_preformatted_command (enum command_id cmd_id)
{
return cmd_id != CM_sp
- && command_data(cmd_id).flags & CF_close_paragraph;
+ && command_data(cmd_id).flags & CF_close_paragraph
+ && !(command_data(cmd_id).flags & CF_index_entry_command);
}
int
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.h
index 60a119e284..1bc39bf8c3 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/commands.h
@@ -1,7 +1,7 @@
-/* commands.h - declarations for commands.c */
+/* commands.h - declarations for commands.c and command_data.c */
#ifndef COMMANDS_H
#define COMMANDS_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -73,6 +73,7 @@ void wipe_user_commands (void);
/* CF_internal is not used in code, but it should be kept as internal
* commands marker */
#define CF_internal 0x8000
+/* command that affect the document as a whole and can appear more than once */
#define CF_global 0x00010000
#define CF_def 0x00020000
#define CF_def_alias 0x00040000
@@ -82,20 +83,21 @@ void wipe_user_commands (void);
#define CF_close_paragraph 0x00100000
/* for commands containing simple text only, corresponding to paragraph
text without @ref, @footnote, @titlefont, @anchor nor @verb. */
-#define CF_contain_simple_text 0x00200000
+#define CF_contain_basic_inline 0x00200000
#define CF_preformatted 0x00400000
#define CF_preformatted_code 0x00800000
-/* CF_item_container is not used */
-#define CF_item_container 0x01000000
-/* CF_item_line is not used */
-#define CF_item_line 0x02000000
+#define CF_no_paragraph 0x01000000
+/* a user-defined command that is referenced to by another command,
+ which should keep its place in the user_defined_command_data table */
+#define CF_REGISTERED 0x02000000
#define CF_nobrace 0x04000000
/* blockitem commands have a possible content before an item */
#define CF_blockitem 0x08000000
-/* CF_inline is not used */
-#define CF_inline 0x10000000
+/* used for REGISTERED commands before they have been set to something */
+#define CF_UNKNOWN 0x10000000
#define CF_MACRO 0x20000000
#define CF_index_entry_command 0x40000000
+/* command that affect the document as a whole and should appear only once */
#define CF_global_unique 0x80000000
/* NOTE: We often run out of spaces for flags
@@ -104,12 +106,10 @@ void wipe_user_commands (void);
*/
/* Types of line command (has CF_line flag). Values for COMMAND.data. */
-#define LINE_special -1
-#define LINE_lineraw -2
-#define LINE_skipline -3
-#define LINE_specific -4
-#define LINE_text -6
-#define LINE_line -7
+#define LINE_lineraw -1
+#define LINE_specific -2
+#define LINE_text -3
+#define LINE_line -4
/* Types of command without brace nor argument on line (has CF_nobrace flag). */
#define NOBRACE_symbol 0
@@ -135,6 +135,7 @@ void wipe_user_commands (void);
#define BLOCK_preformatted -12
/* not used in code but consistent with type in perl hash */
#define BLOCK_math -13
+#define BLOCK_other -14
/* Types of brace command (CF_brace). */
#define BRACE_arguments 1
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.c
index 5797e12853..c591ecd6bb 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -41,11 +41,18 @@ conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME (int i)
}
void
+conf_set_MAX_MACRO_CALL_NESTING (int i)
+{
+ conf.max_macro_call_nesting = i;
+}
+
+void
reset_conf (void)
{
memset (&conf, 0, sizeof (conf));
conf.show_menu = 1;
conf.cpp_line_directives = 1;
conf.ignore_space_after_braced_command_name = 1;
+ conf.max_macro_call_nesting = 100000;
conf.doc_encoding_for_input_file_name = 1;
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.h
index 33ce3b7fbf..41b033a76f 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/conf.h
@@ -1,7 +1,7 @@
/* conf.h - declarations for conf.c */
#ifndef CONF_H
#define CONF_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@ typedef struct CONF {
int show_menu;
int cpp_line_directives;
int ignore_space_after_braced_command_name;
+ int max_macro_call_nesting;
int doc_encoding_for_input_file_name;
} CONF;
@@ -28,6 +29,7 @@ extern CONF conf;
void conf_set_show_menu (int i);
void conf_set_CPP_LINE_DIRECTIVES (int i);
void conf_set_IGNORE_SPACE_AFTER_BRACED_COMMAND_NAME (int i);
+void conf_set_MAX_MACRO_CALL_NESTING (int i);
void reset_conf (void);
#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.c
index 0ecd1dec6e..fc142f541d 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,57 +16,59 @@
#include <config.h>
#include <stdlib.h>
-#include "parser.h"
+#include "debug.h"
+#include "context_stack.h"
+#include "commands.h"
+#include "errors.h"
-static enum context *stack;
-static enum command_id *commands_stack;
+static enum context *context_stack;
static size_t top; /* One above last pushed context. */
static size_t space;
+/* Kept in sync with context_stack. */
+static COMMAND_STACK command_stack;
+
+/* Generic command stack functions */
+
void
-reset_context_stack (void)
+reset_command_stack (COMMAND_STACK *stack)
{
- top = 0;
+ stack->top = 0;
+ stack->space = 0;
+ free (stack->stack);
+ stack->stack = 0;
}
void
-push_context (enum context c, enum command_id cmd)
+push_command (COMMAND_STACK *stack, enum command_id cmd)
{
- if (top >= space)
+ if (stack->top >= stack->space)
{
- stack = realloc (stack, (space += 5) * sizeof (enum context));
- commands_stack
- = realloc (commands_stack, (space += 5) * sizeof (enum command_id));
+ stack->stack
+ = realloc (stack->stack,
+ (stack->space += 5) * sizeof (enum command_id));
}
- debug (">>>>>>>>>>>>>>>>>PUSHING STACK AT %d -- %s @%s", top,
- c == ct_preformatted ? "preformatted"
- : c == ct_line ? "line"
- : c == ct_def ? "def"
- : c == ct_brace_command ? "brace_command"
- : "", command_name(cmd));
- stack[top] = c;
- commands_stack[top] = cmd;
- top++;
+ stack->stack[stack->top] = cmd;
+ stack->top++;
}
-enum context
-pop_context ()
+enum command_id
+pop_command (COMMAND_STACK *stack)
{
- if (top == 0)
- fatal ("context stack empty");
+ if (stack->top == 0)
+ fatal ("command stack empty");
- debug (">>>>>>>>>>>>>POPPING STACK AT %d", top - 1);
- return stack[--top];
+ return stack->stack[--stack->top];
}
-enum context
-current_context (void)
+enum command_id
+top_command (COMMAND_STACK *stack)
{
- if (top == 0)
- return ct_NONE;
+ if (stack->top == 0)
+ fatal ("command stack empty for top");
- return stack[top - 1];
+ return stack->stack[stack->top - 1];
}
enum command_id
@@ -78,69 +80,95 @@ current_context_command (void)
return CM_NONE;
for (i = top -1; i >= 0; i--)
{
- if (commands_stack[i] != CM_NONE)
- return commands_stack[i];
+ if (command_stack.stack[i] != CM_NONE)
+ return command_stack.stack[i];
}
return CM_NONE;
}
-
-/* The valid regions are 'titlepage', 'copying', and 'documentdescription'.
- This stack isn't used that much. */
-
-static ELEMENT **region_stack;
-static size_t region_top; /* One above last pushed region. */
-static size_t region_space;
+/* Context stacks */
void
-reset_region_stack (void)
+reset_context_stack (void)
{
- region_top = 0;
+ top = 0;
+ reset_command_stack (&command_stack);
+}
+
+char *
+context_name (enum context c)
+{
+ return c == ct_preformatted ? "ct_preformatted"
+ : c == ct_line ? "ct_line"
+ : c == ct_def ? "ct_def"
+ : c == ct_brace_command ? "ct_brace_command"
+ : "";
}
void
-push_region (ELEMENT *e)
+push_context (enum context c, enum command_id cmd)
{
- if (region_top >= region_space)
- {
- region_stack = realloc (region_stack,
- (region_space += 5) * sizeof (*region_stack));
- }
+ if (top >= space)
+ context_stack = realloc (context_stack,
+ (space += 5) * sizeof (enum context));
- debug (">>>>>>>>>>>>>>>>>PUSHING REGION STACK AT %d", region_top);
+ /* debug not in perl parser
+ debug (">>>>>>>>>>>>>>>>>PUSHING STACK AT %d -- %s @%s", top,
+ context_name (c), command_name(cmd));
+ */
+ context_stack[top] = c;
+ top++;
- region_stack[region_top++] = e;
+ push_command (&command_stack, cmd);
}
-ELEMENT *
-pop_region ()
+enum context
+pop_context ()
{
- if (region_top == 0)
- fatal ("region stack empty");
+ if (top == 0)
+ fatal ("context stack empty");
- debug (">>>>>>>>>>>>>POPPING REGION STACK AT %d", region_top - 1);
- return region_stack[--region_top];
+ (void) pop_command (&command_stack);
+
+ /* debug not in perl parser
+ debug (">>>>>>>>>>>>>POPPING STACK AT %d", top - 1);
+ */
+ return context_stack[--top];
}
-enum command_id
-current_region_cmd (void)
+enum context
+current_context (void)
{
- if (region_top == 0)
- return CM_NONE;
+ if (top == 0)
+ return ct_NONE;
- return region_stack[region_top - 1]->cmd;
+ return context_stack[top - 1];
}
-ELEMENT *
-current_region (void)
+int
+in_context (enum context context)
{
- if (region_top == 0)
+ int i;
+
+ if (top == 0)
return 0;
- return region_stack[region_top - 1];
+ for (i = 0; i < top; i++)
+ {
+ if (context_stack[i] == context)
+ return 1;
+ }
+ return 0;
}
+
+/* Command nesting context. */
+
+NESTING_CONTEXT nesting_context;
+
+
+
/* used for @kbd */
int
in_preformatted_context_not_menu()
@@ -153,10 +181,10 @@ in_preformatted_context_not_menu()
{
enum context ct;
enum command_id cmd;
- ct = stack[i];
+ ct = context_stack[i];
if (ct != ct_line && ct != ct_preformatted)
return 0;
- cmd = commands_stack[i];
+ cmd = command_stack.stack[i];
if (command_data(cmd).flags & CF_block
&& command_data(cmd).data != BLOCK_menu
&& ct == ct_preformatted)
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.h
index 3d8444e657..0ef0dc5a38 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/context_stack.h
@@ -1,7 +1,7 @@
/* context_stack.h - declarations for context_stack.c */
#ifndef CONTEXT_STACK_H
#define CONTEXT_STACK_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@ enum context {
ct_rawpreformatted,
ct_math,
ct_brace_command,
- ct_inlineraw
+ ct_inlineraw,
};
/* Contexts where an empty line doesn't start a new paragraph. */
@@ -40,16 +40,37 @@ enum context {
void push_context (enum context c, enum command_id cmd);
enum context pop_context (void);
enum context current_context (void);
-enum command_id current_context_command (void);
void reset_context_stack (void);
+int in_context (enum context context);
+char *context_name (enum context c);
+
-void push_region (ELEMENT *r);
-ELEMENT *pop_region (void);
-ELEMENT *current_region (void);
-enum command_id current_region_cmd (void);
-void reset_region_stack (void);
+typedef struct {
+ enum command_id *stack;
+ size_t top; /* One above last pushed context. */
+ size_t space;
+} COMMAND_STACK;
+
+void reset_command_stack (COMMAND_STACK *stack);
+void push_command (COMMAND_STACK *stack, enum command_id cmd);
+enum command_id pop_command (COMMAND_STACK *stack);
+enum command_id top_command (COMMAND_STACK *stack);
+enum command_id current_context_command (void);
+
+
+/* Used to check indirect nesting, e.g. @footnote{@emph{@footnote{...}}} */
+typedef struct {
+ int footnote;
+ int caption;
+ COMMAND_STACK basic_inline_stack;
+ COMMAND_STACK basic_inline_stack_on_line;
+ COMMAND_STACK basic_inline_stack_block;
+ COMMAND_STACK regions_stack;
+} NESTING_CONTEXT;
+
+extern NESTING_CONTEXT nesting_context;
int in_preformatted_context_not_menu(void);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.c
index 697f5a2bfb..2e1b77f513 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,6 +30,8 @@ static void convert_to_texinfo_internal (ELEMENT *e, TEXT *result);
#define ADD(x) text_append (result, x)
+/* Currently unused, but could be used to implement link_element_to_texi
+ from Texinfo::Convert::Texinfo */
/* Return value to be freed by caller. */
char *
node_extra_to_texi (NODE_SPEC_EXTRA *nse)
@@ -59,110 +61,137 @@ static void
expand_cmd_args_to_texi (ELEMENT *e, TEXT *result)
{
enum command_id cmd = e->cmd;
- KEY_PAIR *k;
+ KEY_PAIR *k, *arg_line;
+ ELEMENT *elt, *spc_before_arg;
if (cmd)
{
ADD("@"); ADD(command_name(cmd));
+ elt = lookup_info_element (e, "spaces_after_cmd_before_arg");
+ if (elt)
+ ADD((char *)elt->text.text);
}
- // TODO extra spaces
- k = lookup_extra (e, "spaces_before_argument");
- if (k)
- ADD((char *)k->value);
+ spc_before_arg = lookup_info_element (e, "spaces_before_argument");
- // TODO multitable or block command
-
- if (cmd == CM_macro || cmd == CM_rmacro)
+ arg_line = lookup_info (e, "arg_line");
+ if (arg_line)
{
- KEY_PAIR *k;
char *s = 0;
- k = lookup_extra (e, "arg_line");
- if (k)
- s = (char *)k->value;
+
+ if (spc_before_arg)
+ ADD((char *)spc_before_arg->text.text);
+
+ s = (char *)arg_line->value;
if (s)
{
ADD(s);
- return;
}
}
-
- // TODO node
-
- if (e->args.number > 0)
+ else if (e->args.number > 0)
{
int braces, arg_nr, i;
+ int with_commas = 0;
+
braces = (e->args.list[0]->type == ET_brace_command_arg
- || e->args.list[0]->type == ET_brace_command_context);
+ || e->args.list[0]->type == ET_brace_command_context
+ || cmd == CM_value);
if (braces)
ADD("{");
if (e->cmd == CM_verb)
{
- k = lookup_extra (e, "delimiter");
+ k = lookup_info (e, "delimiter");
ADD((char *)k->value);
}
+ if (spc_before_arg)
+ ADD((char *)spc_before_arg->text.text);
+
+ if ((command_data(cmd).flags & CF_block
+ && ! (command_data(cmd).flags & CF_def
+ || cmd == CM_multitable))
+ || cmd == CM_node
+ || (command_data(cmd).flags & CF_brace)
+ || (command_data(cmd).flags & CF_INFOENCLOSE))
+ with_commas = 1;
+
arg_nr = 0;
for (i = 0; i < e->args.number; i++)
{
- if (command_data(cmd).flags & CF_brace)
+ ELEMENT *arg = e->args.list[i];
+ if (arg->type == ET_spaces_inserted
+ || arg->type == ET_bracketed_inserted
+ || arg->type == ET_command_as_argument_inserted)
+ continue;
+
+ if (with_commas)
{
if (arg_nr)
ADD(",");
arg_nr++;
}
- k = lookup_extra (e->args.list[i], "spaces_before_argument");
- if (k)
- ADD((char *)k->value);
- convert_to_texinfo_internal (e->args.list[i], result);
- k = lookup_extra (e->args.list[i], "spaces_after_argument");
- if (k)
- ADD((char *)k->value);
+ convert_to_texinfo_internal (arg, result);
}
if (e->cmd == CM_verb)
{
- k = lookup_extra (e, "delimiter");
+ k = lookup_info (e, "delimiter");
ADD((char *)k->value);
}
if (braces)
ADD("}");
}
+ else
+ {
+ if (spc_before_arg)
+ ADD((char *)spc_before_arg->text.text);
+ }
}
static void
convert_to_texinfo_internal (ELEMENT *e, TEXT *result)
{
- if (e->text.end > 0)
+ ELEMENT *elt;
+
+ if (e->type == ET_spaces_inserted
+ || e->type == ET_bracketed_inserted
+ || e->type == ET_command_as_argument_inserted)
+ {}
+ else if (e->text.end > 0)
ADD(e->text.text);
else
{
if (e->cmd
- || e->type == ET_def_line
- || e->type == ET_menu_entry
- || e->type == ET_menu_comment)
+ || e->type == ET_def_line)
{
expand_cmd_args_to_texi (e, result);
}
- if (e->type == ET_bracketed
- || e->type == ET_bracketed_def_content)
- {
- KEY_PAIR *k;
- ADD("{");
- k = lookup_extra (e, "spaces_before_argument");
- if (k)
- ADD((char *)k->value);
- }
+ if (e->type == ET_bracketed_arg || e->type == ET_bracketed_linemacro_arg)
+ ADD("{");
+ elt = lookup_info_element (e, "spaces_before_argument");
+ if (elt)
+ ADD((char *)elt->text.text);
if (e->contents.number > 0)
{
int i;
for (i = 0; i < e->contents.number; i++)
convert_to_texinfo_internal (e->contents.list[i], result);
}
- if (e->type == ET_bracketed)
+
+ elt = lookup_info_element (e, "spaces_after_argument");
+ if (elt)
+ {
+ ADD((char *)elt->text.text);
+ }
+
+ elt = lookup_info_element (e, "comment_at_end");
+ if (elt)
+ convert_to_texinfo_internal (elt, result);
+
+ if (e->type == ET_bracketed_arg || e->type == ET_bracketed_linemacro_arg)
ADD("}");
}
@@ -183,10 +212,25 @@ convert_to_texinfo (ELEMENT *e)
return result.text;
}
-/* Very stripped-down version of Texinfo::Convert::Text.
+char *
+convert_contents_to_texinfo (ELEMENT *e)
+{
+ ELEMENT *tmp = new_element (ET_NONE);
+ char *result;
+
+ tmp->contents = e->contents;
+ result = convert_to_texinfo (tmp);
+ tmp->contents.list = 0;
+ destroy_element (tmp);
+
+ return result;
+}
+
+/*
Convert the contents of E to plain text. Suitable for specifying a file
- name containing an at sign or braces. Set *SUPERFLUOUS_ARG if the contents
- of E are too complicated to convert properly. */
+ name containing an at sign or braces, but no other commands nor element
+ types. Set *SUPERFLUOUS_ARG if the E contains other commands or element
+ types. */
char *
convert_to_text (ELEMENT *e, int *superfluous_arg)
{
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.h
index a0a9650428..1b74c4175a 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/convert.h
@@ -5,6 +5,7 @@
#include "tree_types.h"
char *convert_to_texinfo (ELEMENT *e);
+char *convert_contents_to_texinfo (ELEMENT *e);
char *convert_to_text (ELEMENT *e, int *superfluous_arg);
char *node_extra_to_texi (NODE_SPEC_EXTRA *nse);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.c
index 79499e0eb5..de96c79728 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.c
@@ -1,4 +1,4 @@
-/* Copyright 2015-2021 Free Software Foundation, Inc.
+/* Copyright 2015-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.h
index 9e5ce2873c..79fe876722 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/counter.h
@@ -4,7 +4,7 @@
#include "tree_types.h"
-/* Copyright 2015-2021 Free Software Foundation, Inc.
+/* Copyright 2015-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.c
index 9f3577d520..f2a772c8b7 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.c
@@ -1,4 +1,4 @@
-/* Copyright 2014-2019 Free Software Foundation, Inc.
+/* Copyright 2014-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,8 +16,10 @@
#include <config.h>
#include <stdarg.h>
#include <stdio.h>
+#include <string.h>
-#include "parser.h"
+#include "debug.h"
+#include "commands.h"
/* Whether to dump debugging output on stderr. */
int debug_output = 0;
@@ -44,3 +46,100 @@ debug_nonl (char *s, ...)
va_start (v, s);
vfprintf (stderr, s, v);
}
+
+char *
+debug_command_name (enum command_id cmd)
+{
+ if (cmd == CM_TAB)
+ return "\\t";
+ else if (cmd == CM_NEWLINE)
+ return "\\n";
+ else
+ return command_name(cmd);
+}
+
+char *
+debug_protect_eol (char *input_string, int *allocated)
+{
+ char *end_of_line = strchr (input_string, '\n');
+ char *protected_string = input_string;
+ *allocated = 0;
+ if (end_of_line) {
+ char *p;
+ protected_string = malloc ((strlen(input_string) + 2) * sizeof(char));
+ *allocated = 1;
+ memcpy (protected_string, input_string, strlen(input_string));
+ p = protected_string + (end_of_line - input_string);
+ *p = '\\';
+ *(p+1) = 'n';
+ *(p+2) = '\0';
+ }
+ return protected_string;
+}
+
+char *
+print_element_debug (ELEMENT *e, int print_parent)
+{
+ TEXT text;
+ char *result;
+
+ text_init (&text);
+ text_append (&text, "");
+ if (e->cmd)
+ text_printf (&text, "@%s", debug_command_name(e->cmd));
+ if (e->type)
+ text_printf (&text, "(%s)", element_type_names[e->type]);
+ if (e->text.end > 0)
+ {
+ int allocated = 0;
+ char *element_text = debug_protect_eol (e->text.text, &allocated);
+ text_printf (&text, "[T: %s]", element_text);
+ if (allocated)
+ free (element_text);
+ }
+ if (e->args.number)
+ text_printf (&text, "[A%d]", e->args.number);
+ if (e->contents.number)
+ text_printf (&text, "[C%d]", e->contents.number);
+ if (print_parent && e->parent)
+ {
+ text_append (&text, " <- ");
+ if (e->parent->cmd)
+ text_printf (&text, "@%s", command_name(e->parent->cmd));
+ if (e->parent->type)
+ text_printf (&text, "(%s)", element_type_names[e->parent->type]);
+ }
+ result = strdup (text.text);
+ free (text.text);
+ return result;
+}
+
+void
+debug_print_element (ELEMENT *e, int print_parent)
+{
+ if (debug_output)
+ {
+ char *result;
+ result = print_element_debug (e, print_parent);
+ fputs (result, stderr);
+ free (result);
+ }
+}
+
+void
+debug_print_protected_string (char *input_string)
+{
+ if (debug_output)
+ {
+ int allocated = 0;
+ char *result;
+ if (!input_string)
+ result = "[NULL]";
+ else
+ result = debug_protect_eol (input_string, &allocated);
+ fputs (result, stderr);
+ if (allocated)
+ free (result);
+ }
+}
+
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.h
new file mode 100644
index 0000000000..42d5a87218
--- /dev/null
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/debug.h
@@ -0,0 +1,18 @@
+/* debug.h - declarations for debug.c */
+#ifndef TEXINFO_DEBUG_H
+#define TEXINFO_DEBUG_H
+
+/* We define TEXINFO_DEBUG_H instead of DEBUG_H to avoid a clash with Perl
+ header files in some versions of Perl. */
+
+#include "tree_types.h"
+
+void debug (char *s, ...);
+void debug_nonl (char *s, ...);
+extern int debug_output;
+void debug_print_element (ELEMENT *e, int print_parent);
+char *print_element_debug (ELEMENT *e, int print_parent);
+char *debug_command_name (enum command_id cmd);
+void debug_print_protected_string (char *input_string);
+
+#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.c
index bea4544d14..0dc8a4f21e 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,9 +15,14 @@
#include <config.h>
#include <string.h>
+#include <stdbool.h>
+#include "uniconv.h"
+#include "unistr.h"
#include "parser.h"
#include "text.h"
+#include "source_marks.h"
+#include "debug.h"
void
gather_def_item (ELEMENT *current, enum command_id next_command)
@@ -26,7 +31,8 @@ gather_def_item (ELEMENT *current, enum command_id next_command)
ELEMENT *def_item;
int contents_count, i;
- if (next_command)
+ if (next_command
+ && next_command != CM_defline && next_command != CM_deftypeline)
type = ET_inter_def_item; /* Between @def*x and @def*. */
else
type = ET_def_item;
@@ -41,11 +47,13 @@ gather_def_item (ELEMENT *current, enum command_id next_command)
if (command_data(current->cmd).flags & CF_line)
return;
- def_item = new_element (type);
+ contents_count = current->contents.number;
+ if (contents_count == 0)
+ return;
/* Starting from the end, collect everything that is not a ET_def_line and
put it into the ET_def_item. */
- contents_count = current->contents.number;
+ def_item = new_element (type);
for (i = 0; i < contents_count; i++)
{
ELEMENT *last_child, *item_content;
@@ -66,23 +74,6 @@ gather_def_item (ELEMENT *current, enum command_id next_command)
/* Starting at I in the contents, return the next non-whitespace element,
incrementing I. Return null if no more elements. */
ELEMENT *
-next_bracketed_or_word (ELEMENT *current, int *i)
-{
- while (1)
- {
- if (*i == current->contents.number)
- return 0;
- if (current->contents.list[*i]->type != ET_spaces
- && current->contents.list[*i]->type != ET_spaces_inserted
- && current->contents.list[*i]->type != ET_spaces_at_end
- && current->contents.list[*i]->type != ET_delimiter)
- break;
- (*i)++;
- }
- return current->contents.list[(*i)++];
-}
-
-ELEMENT *
next_bracketed_or_word_agg (ELEMENT *current, int *i)
{
int num = 0;
@@ -96,7 +87,6 @@ next_bracketed_or_word_agg (ELEMENT *current, int *i)
e = current->contents.list[*i];
if (e->type == ET_spaces
|| e->type == ET_spaces_inserted
- || e->type == ET_spaces_at_end
|| e->type == ET_delimiter)
{
if (num > 0)
@@ -104,26 +94,19 @@ next_bracketed_or_word_agg (ELEMENT *current, int *i)
else
{
(*i)++;
- continue;
}
}
- if (e->type == ET_bracketed_def_content
- || e->type == ET_bracketed_inserted)
+ else
{
- if (num > 0)
- break;
- else
- {
- (*i)++;
- return e;
- }
+ /* e is a text or command element or bracketed argument */
+ (*i)++;
+ num++;
}
- /* e is a text or command element */
- (*i)++;
- num++;
}
+
if (num == 0)
return 0;
+
if (num == 1)
return current->contents.list[*i - 1];
@@ -144,21 +127,60 @@ typedef struct {
enum command_id alias;
enum command_id command;
char *category;
+ char *translation_context;
} DEF_ALIAS;
DEF_ALIAS def_aliases[] = {
- CM_defun, CM_deffn, "Function",
- CM_defmac, CM_deffn, "Macro",
- CM_defspec, CM_deffn, "Special Form",
- CM_defvar, CM_defvr, "Variable",
- CM_defopt, CM_defvr, "User Option",
- CM_deftypefun, CM_deftypefn, "Function",
- CM_deftypevar, CM_deftypevr, "Variable",
- CM_defivar, CM_defcv, "Instance Variable",
- CM_deftypeivar, CM_deftypecv, "Instance Variable",
- CM_defmethod, CM_defop, "Method",
- CM_deftypemethod, CM_deftypeop, "Method",
- 0, 0, 0
+ CM_defun, CM_deffn, "Function", "category of functions for @defun",
+ CM_defmac, CM_deffn, "Macro", 0,
+ CM_defspec, CM_deffn, "Special Form", 0,
+ CM_defvar, CM_defvr, "Variable", "category of variables for @defvar",
+ CM_defopt, CM_defvr, "User Option", 0,
+ CM_deftypefun, CM_deftypefn, "Function", "category of functions for @deftypefun",
+ CM_deftypevar, CM_deftypevr, "Variable", "category of variables in typed languages for @deftypevar",
+ CM_defivar, CM_defcv, "Instance Variable", "category of instance variables in object-oriented programming for @defivar",
+ CM_deftypeivar, CM_deftypecv, "Instance Variable", "category of instance variables with data type in object-oriented programming for @deftypeivar",
+ CM_defmethod, CM_defop, "Method", "category of methods in object-oriented programming for @defmethod",
+ CM_deftypemethod, CM_deftypeop, "Method", "category of methods with data type in object-oriented programming for @deftypemethod",
+ 0, 0, 0, 0
+};
+
+typedef struct {
+ enum command_id command;
+ char **arguments;
+} DEF_MAP;
+
+ /*
+ Meaning of these:
+ CATEGORY - type of entity, e.g. "Function"
+ CLASS - class for object-oriented programming
+ TYPE - data type of a variable or function return value
+ NAME - name of entity being documented
+ ARGUMENTS - arguments to a function or macro */
+
+char *defline_arguments[] = {"category", "name", "arg", 0};
+char *deftypeline_arguments[] = {"category", "type", "name", "argtype", 0};
+char *defvr_arguments[] = {"category", "name", 0};
+char *deftypefn_arguments[] = {"category", "type", "name", "argtype", 0};
+char *deftypeop_arguments[] = {"category", "class" , "type", "name", "argtype", 0};
+char *deftypevr_arguments[] = {"category", "type", "name", 0};
+char *defcv_arguments[] = {"category", "class" , "name", 0};
+char *deftypecv_arguments[] = {"category", "class" , "type", "name", 0};
+char *defop_arguments[] = {"category", "class" , "name", "arg", 0};
+char *deftp_arguments[] = {"category", "name", "argtype", 0};
+
+DEF_MAP def_maps[] = {
+ CM_defline, defline_arguments,
+ CM_deftypeline, deftypeline_arguments,
+ CM_deffn, defline_arguments,
+ CM_defvr, defvr_arguments,
+ CM_deftypefn, deftypefn_arguments,
+ CM_deftypeop, deftypeop_arguments,
+ CM_deftypevr, deftypevr_arguments,
+ CM_defcv, defcv_arguments,
+ CM_deftypecv, deftypecv_arguments,
+ CM_defop, defop_arguments,
+ CM_deftp, deftp_arguments,
};
/* Split non-space text elements into strings without [ ] ( ) , and single
@@ -174,18 +196,37 @@ split_delimiters (ELEMENT *current, int starting_idx)
char *p;
ELEMENT *new;
int len;
+ /* count UTF-8 encoded Unicode characters for source marks locations */
+ size_t current_position = 0;
+ uint8_t *u8_text = 0;
+ uint8_t *u8_p;
if (e->type != ET_NONE
|| e->text.end == 0)
continue;
p = e->text.text;
+ if (e->source_mark_list.number)
+ u8_text = u8_strconv_from_encoding (p, "UTF-8",
+ iconveh_question_mark);
+ u8_p = u8_text;
+
while (1)
{
+ size_t u8_len = 0;
if (strchr (chars, *p))
{
new = new_element (ET_delimiter);
text_append_n (&new->text, p, 1);
+
+ if (u8_text)
+ {
+ u8_len = u8_mbsnlen (u8_p, 1);
+ u8_p += u8_len;
+ }
+ current_position = relocate_source_marks (&(e->source_mark_list), new,
+ current_position, u8_len);
+
insert_into_contents (current, new, i++);
add_extra_string_dup (new, "def_role", "delimiter");
if (!*++p)
@@ -196,18 +237,27 @@ split_delimiters (ELEMENT *current, int starting_idx)
len = strcspn (p, chars);
new = new_element (ET_NONE);
text_append_n (&new->text, p, len);
+
+ if (u8_text)
+ {
+ u8_len = u8_mbsnlen (u8_p, len);
+ u8_p += u8_len;
+ }
+ current_position = relocate_source_marks (&(e->source_mark_list), new,
+ current_position, u8_len);
+
insert_into_contents (current, new, i++);
if (!*(p += len))
break;
}
destroy_element (remove_from_contents (current, i--));
+ free (u8_text);
}
}
/* Divide any text elements into separate elements, separating whitespace
- and non-whitespace. Change ET_bracketed elements to
- ET_bracketed_def_content. */
+ and non-whitespace. */
static void
split_def_args (ELEMENT *current, int starting_idx)
{
@@ -218,57 +268,69 @@ split_def_args (ELEMENT *current, int starting_idx)
char *p;
ELEMENT *new;
int len;
- if (e->type == ET_bracketed)
+ /* count UTF-8 encoded Unicode characters for source marks locations */
+ size_t current_position = 0;
+ uint8_t *u8_text = 0;
+ uint8_t *u8_p;
+
+ if (e->type == ET_bracketed_arg)
{
isolate_last_space (e);
- e->type = ET_bracketed_def_content;
continue;
}
+
if (e->text.end == 0)
continue;
+
p = e->text.text;
+ if (e->source_mark_list.number)
+ u8_text = u8_strconv_from_encoding (p, "UTF-8",
+ iconveh_question_mark);
+ u8_p = u8_text;
+
while (1)
{
+ size_t u8_len = 0;
len = strspn (p, whitespace_chars);
if (len)
{
new = new_element (ET_spaces);
- text_append_n (&new->text, p, len);
- insert_into_contents (current, new, i++);
add_extra_string_dup (new, "def_role", "spaces");
- if (!*(p += len))
- {
- if (new->text.end > 0
- && new->text.text[new->text.end - 1] == '\n')
- new->type = ET_spaces_at_end;
- break;
- }
}
-
- len = strcspn (p, whitespace_chars);
- new = new_element (ET_NONE);
+ else
+ {
+ len = strcspn (p, whitespace_chars);
+ new = new_element (ET_NONE);
+ }
+ if (u8_text)
+ {
+ u8_len = u8_mbsnlen (u8_p, len);
+ u8_p += u8_len;
+ }
+
+ current_position = relocate_source_marks (&(e->source_mark_list), new,
+ current_position, u8_len);
text_append_n (&new->text, p, len);
insert_into_contents (current, new, i++);
if (!*(p += len))
break;
-
}
destroy_element (remove_from_contents (current, i--));
+ free (u8_text);
}
}
-DEF_INFO *
+DEF_ARG **
parse_def (enum command_id command, ELEMENT *current)
{
- DEF_INFO *ret;
int contents_idx = 0;
- int type, next_type;
- int i;
- ELEMENT *e, *e1;
-
- ret = malloc (sizeof (DEF_INFO));
- memset (ret, 0, sizeof (DEF_INFO));
+ int type, set_type_not_arg;
+ int i, i_def;
+ int arg_types_nr;
+ ELEMENT *e, *e1;
+ DEF_ARG **result;
+ char **arguments_list;
split_def_args (current, contents_idx);
@@ -283,7 +345,7 @@ parse_def (enum command_id command, ELEMENT *current)
goto found;
}
fatal ("no alias for CF_def_alias command");
-found:
+ found:
/* Prepended content is inserted into contents, so
@defun is converted into @deffn Function */
@@ -301,6 +363,9 @@ found:
e1->type = ET_untranslated;
add_extra_string_dup (e1, "documentlanguage",
global_documentlanguage);
+ if (def_aliases[i].translation_context)
+ add_extra_string_dup (e1, "translation_context",
+ def_aliases[i].translation_context);
}
e = new_element (ET_spaces_inserted);
@@ -309,54 +374,127 @@ found:
insert_into_contents (current, e, contents_idx + 1);
}
- /* Read arguments as CATEGORY [CLASS] [TYPE] NAME [ARGUMENTS].
-
- Meaning of these:
- CATEGORY - type of entity, e.g. "Function"
- CLASS - class for object-oriented programming
- TYPE - data type of a variable or function return value
- NAME - name of entity being documented
- ARGUMENTS - arguments to a function or macro */
-
- /* CATEGORY */
- ret->category = next_bracketed_or_word_agg (current, &contents_idx);
-
- /* CLASS */
- if (command == CM_deftypeop
- || command == CM_defcv
- || command == CM_deftypecv
- || command == CM_defop)
+ /* prepare the arguments numbers and list */
+ if (command_data(command).flags & CF_MACRO)
{
- ret->class = next_bracketed_or_word_agg (current, &contents_idx);
+ int args_number;
+ MACRO *macro_record = lookup_macro (command);
+ ELEMENT *macro;
+ if (!macro_record)
+ fatal ("no linemacro record for arguments parsing");
+ macro = macro_record->element;
+ args_number = macro->args.number - 1;
+ arguments_list = malloc ((args_number + 1) * sizeof (char *));
+ arguments_list[args_number] = 0;
+ arg_types_nr = args_number;
+ if (args_number > 0)
+ {
+ int arg_index;
+ ELEMENT **args = macro->args.list;
+ for (arg_index = 1; arg_index <= args_number; arg_index++)
+ {
+ if (args[arg_index]->type == ET_macro_arg)
+ arguments_list[arg_index -1] = args[arg_index]->text.text;
+ else
+ arguments_list[arg_index -1] = 0;
+ }
+ /* remove one for the rest of the line argument */
+ arg_types_nr--;
+ }
+ result = malloc ((args_number+1) * sizeof (DEF_ARG *));
}
-
- /* TYPE */
- if (command == CM_deftypefn
- || command == CM_deftypeop
- || command == CM_deftypevr
- || command == CM_deftypecv)
+ else
{
- ret->type = next_bracketed_or_word_agg (current, &contents_idx);
- }
+ /* Read arguments as CATEGORY [CLASS] [TYPE] NAME [ARGUMENTS]. */
+
+ for (i_def = 0; i_def < sizeof (def_maps) / sizeof (*def_maps); i_def++)
+ {
+ if (def_maps[i_def].command == command)
+ goto def_found;
+ }
+ fatal ("no arguments for def command");
+ def_found:
- /* NAME */
- ret->name = next_bracketed_or_word_agg (current, &contents_idx);
+ /* determine non arg/argtype number of arguments */
+ arg_types_nr = 0;
+ arguments_list = def_maps[i_def].arguments;
+ while (arguments_list[arg_types_nr])
+ {
+ char *arg_type_name = arguments_list[arg_types_nr];
- if (ret->category)
- {
- add_extra_string_dup (ret->category, "def_role", "category");
+ /* FIXME keep information about arg/argtype? */
+ if (!strcmp (arg_type_name, "arg")
+ || !strcmp (arg_type_name, "argtype"))
+ break;
+ arg_types_nr++;
+ }
+ result = malloc ((arg_types_nr+1) * sizeof (DEF_ARG *));
}
- if (ret->class)
+
+ for (i = 0; i < arg_types_nr; i++)
{
- add_extra_string_dup (ret->class, "def_role", "class");
+ ELEMENT *e = next_bracketed_or_word_agg (current, &contents_idx);
+
+ if (e)
+ {
+ char *arg_type_name = arguments_list[i];
+ DEF_ARG *def_arg = malloc (sizeof (DEF_ARG));
+
+ result[i] = def_arg;
+ def_arg->arg_type = strdup(arg_type_name);
+ def_arg->element = e;
+ }
+ else
+ break;
}
- if (ret->type)
+
+ result[i] = 0;
+ if (command_data(command).flags & CF_MACRO)
{
- add_extra_string_dup (ret->type, "def_role", "type");
+ while (contents_idx < current->contents.number
+ && current->contents.list[contents_idx]->type == ET_spaces)
+ contents_idx++;
+ /* note that element at contents_idx is not collected at that point */
+ /* arguments_list[i] NULL should only happen if there is no
+ argument at all for the linemacro */
+ if (contents_idx < current->contents.number && arguments_list[i])
+ {
+ DEF_ARG *def_arg = malloc (sizeof (DEF_ARG));
+ int contents_nr = current->contents.number - contents_idx;
+
+ result[i] = def_arg;
+ result[i+1] = 0;
+
+ def_arg->arg_type = strdup (arguments_list[i]);
+ if (contents_nr == 1)
+ def_arg->element = current->contents.list[contents_idx];
+ else
+ {
+ ELEMENT *new = new_element (ET_def_aggregate);
+ int j;
+ for (j = 0; j < contents_nr; j++)
+ {
+ add_to_element_contents (new,
+ remove_from_contents (current,
+ contents_idx));
+ }
+ add_to_element_contents (current, new);
+ def_arg->element = new;
+ }
+ }
+ return result;
}
- if (ret->name)
+
+ for (i = 0; i < arg_types_nr; i++)
{
- add_extra_string_dup (ret->name, "def_role", "name");
+ if (result[i])
+ {
+ DEF_ARG *def_arg = result[i];
+ if (def_arg->element)
+ add_extra_string_dup (def_arg->element, "def_role", def_arg->arg_type);
+ }
+ else
+ break;
}
/* Process args */
@@ -364,36 +502,37 @@ found:
/* For some commands, alternate between "arg" and "typearg". This matters for
the DocBook output. */
- if (command == CM_deftypefn || command == CM_deftypeop
- || command == CM_deftp)
- next_type = -1;
+ /* In that case set_type_not_arg is both used to set to argtype and
+ to switch sign to switch between arg and argtype */
+ if (command == CM_deftypeline || command == CM_deftypefn
+ || command == CM_deftypeop || command == CM_deftp)
+ set_type_not_arg = -1;
else
- next_type = 1;
+ set_type_not_arg = 1;
- type = next_type;
+ type = set_type_not_arg;
for (i = contents_idx; i < current->contents.number; i++)
{
e = contents_child_by_index (current, i);
if (e->type == ET_spaces
- || e->type == ET_spaces_inserted
- || e->type == ET_spaces_at_end)
+ || e->type == ET_spaces_inserted)
{
continue;
}
if (e->type == ET_delimiter)
{
- type = next_type;
+ type = set_type_not_arg;
continue;
}
if (e->cmd && e->cmd != CM_code)
{
add_extra_string_dup (e, "def_role", "arg");
- type = next_type;
+ type = set_type_not_arg;
continue;
}
add_extra_string_dup (e, "def_role",
(type == 1 ? "arg" : "typearg"));
- type *= next_type;
+ type *= set_type_not_arg;
}
- return ret;
+ return result;
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.h
index 074e5286e0..906b744038 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/def.h
@@ -5,5 +5,5 @@
#include "tree_types.h"
void gather_def_item (ELEMENT *current, enum command_id next_command);
-DEF_INFO *parse_def (enum command_id command, ELEMENT *current);
+DEF_ARG **parse_def (enum command_id command, ELEMENT *current);
#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.awk b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.awk
index 83618f9929..e744569cfe 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.awk
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.awk
@@ -1,4 +1,4 @@
-# Copyright 2014-2021 Free Software Foundation, Inc.
+# Copyright 2014-2023 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.c
index 99d8dab9c2..cb9fd8e798 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.c
@@ -12,14 +12,16 @@ char *element_type_names[] = {
"spaces_at_end",
"spaces_after_close_brace",
"spaces_before_paragraph",
+"text_after_end",
"text_before_beginning",
"space_at_end_menu_node",
"after_menu_description_line",
-"spaces",
+"spaces_after_cmd_before_arg",
"spaces_inserted",
"document_root",
"root_line",
"before_node_section",
+"postamble_after_end",
"preamble_before_beginning",
"preamble_before_setfilename",
"paragraph",
@@ -29,7 +31,7 @@ char *element_type_names[] = {
"brace_command_context",
"block_line_arg",
"line_arg",
-"misc_arg",
+"rawline_arg",
"menu_entry",
"menu_entry_leading_text",
"menu_entry_name",
@@ -41,12 +43,13 @@ char *element_type_names[] = {
"internal_spaces_after_command",
"internal_spaces_before_argument",
"internal_spaces_before_brace_in_index",
+"internal_spaces_after_cmd_before_arg",
"macro_name",
"macro_arg",
"before_item",
"table_entry",
"table_term",
-"table_item",
+"table_definition",
"inter_item",
"def_line",
"def_item",
@@ -54,15 +57,18 @@ char *element_type_names[] = {
"multitable_head",
"multitable_body",
"row",
-"bracketed",
-"bracketed_def_content",
+"balanced_braces",
+"bracketed_arg",
+"bracketed_linemacro_arg",
"def_aggregate",
"bracketed_inserted",
-"bracketed_multitable_prototype",
-"row_prototype",
-"elided",
-"elided_block",
+"elided_rawpreformatted",
+"elided_brace_command_arg",
"delimiter",
+"spaces",
"untranslated",
+"macro_call",
+"rmacro_call",
+"linemacro_call",
};
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.h
index c18e6c5a6e..9b3609a5cf 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.h
@@ -15,14 +15,16 @@ ET_ignorable_spaces_after_command,
ET_spaces_at_end,
ET_spaces_after_close_brace,
ET_spaces_before_paragraph,
+ET_text_after_end,
ET_text_before_beginning,
ET_space_at_end_menu_node,
ET_after_menu_description_line,
-ET_spaces,
+ET_spaces_after_cmd_before_arg,
ET_spaces_inserted,
ET_document_root,
ET_root_line,
ET_before_node_section,
+ET_postamble_after_end,
ET_preamble_before_beginning,
ET_preamble_before_setfilename,
ET_paragraph,
@@ -32,7 +34,7 @@ ET_brace_command_arg,
ET_brace_command_context,
ET_block_line_arg,
ET_line_arg,
-ET_misc_arg,
+ET_rawline_arg,
ET_menu_entry,
ET_menu_entry_leading_text,
ET_menu_entry_name,
@@ -44,12 +46,13 @@ ET_internal_menu_star,
ET_internal_spaces_after_command,
ET_internal_spaces_before_argument,
ET_internal_spaces_before_brace_in_index,
+ET_internal_spaces_after_cmd_before_arg,
ET_macro_name,
ET_macro_arg,
ET_before_item,
ET_table_entry,
ET_table_term,
-ET_table_item,
+ET_table_definition,
ET_inter_item,
ET_def_line,
ET_def_item,
@@ -57,16 +60,19 @@ ET_inter_def_item,
ET_multitable_head,
ET_multitable_body,
ET_row,
-ET_bracketed,
-ET_bracketed_def_content,
+ET_balanced_braces,
+ET_bracketed_arg,
+ET_bracketed_linemacro_arg,
ET_def_aggregate,
ET_bracketed_inserted,
-ET_bracketed_multitable_prototype,
-ET_row_prototype,
-ET_elided,
-ET_elided_block,
+ET_elided_rawpreformatted,
+ET_elided_brace_command_arg,
ET_delimiter,
+ET_spaces,
ET_untranslated,
+ET_macro_call,
+ET_rmacro_call,
+ET_linemacro_call,
};
extern char *element_type_names[];
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.txt b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.txt
index ee7034193a..1850fedf5d 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.txt
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/element_types.txt
@@ -1,4 +1,4 @@
-# Copyright 2010-2018 Free Software Foundation, Inc.
+# Copyright 2010-2023 Free Software Foundation, Inc.
#
# This file is part of GNU Texinfo.
#
@@ -30,16 +30,18 @@ ignorable_spaces_after_command
spaces_at_end
spaces_after_close_brace
spaces_before_paragraph
+text_after_end
text_before_beginning
space_at_end_menu_node
after_menu_description_line
-spaces
+spaces_after_cmd_before_arg
spaces_inserted
# Other special types
document_root
root_line
before_node_section
+postamble_after_end
preamble_before_beginning
preamble_before_setfilename
paragraph
@@ -49,7 +51,7 @@ brace_command_arg
brace_command_context
block_line_arg
line_arg
-misc_arg
+rawline_arg
menu_entry
menu_entry_leading_text
@@ -63,13 +65,14 @@ internal_menu_star
internal_spaces_after_command
internal_spaces_before_argument
internal_spaces_before_brace_in_index
+internal_spaces_after_cmd_before_arg
macro_name
macro_arg
before_item
table_entry
table_term
-table_item
+table_definition
inter_item
def_line
def_item
@@ -77,20 +80,25 @@ inter_def_item
multitable_head
multitable_body
row
-bracketed
-bracketed_def_content
+balanced_braces
+bracketed_arg
+bracketed_linemacro_arg
def_aggregate
bracketed_inserted
-bracketed_multitable_prototype
-row_prototype
# for unexpanded parts of conditionals
-elided
-elided_block
+elided_rawpreformatted
+elided_brace_command_arg
# for def commands
delimiter
+spaces
# for inserted text in def commands
untranslated
+# for macro expansion source marks
+macro_call
+rmacro_call
+linemacro_call
+
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/end_line.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/end_line.c
index 87ca036edd..1a5ff19bfb 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/end_line.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/end_line.c
@@ -1,5 +1,5 @@
/* end_line.c -- what to do at the end of a whole line of input */
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,45 +18,23 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <stdio.h>
#include "parser.h"
+#include "debug.h"
#include "text.h"
#include "input.h"
#include "convert.h"
#include "labels.h"
#include "indices.h"
+#include "def.h"
+#include "source_marks.h"
+#include "handle_commands.h"
-void
-check_internal_node (NODE_SPEC_EXTRA *nse)
-{
- if (nse && nse->manual_content
- && nse->manual_content->contents.number > 0)
- {
- char *texi = node_extra_to_texi (nse);
- line_error ("syntax for an external node used for `%s'", texi);
- free (texi);
- }
-}
-
-int
-check_empty_node (NODE_SPEC_EXTRA *nse,
- enum command_id cmd)
-{
- if (!nse || !nse->node_content || nse->node_content->contents.number == 0)
- {
- line_error ("empty argument in @%s", command_name(cmd));
- return 0;
- }
- else
- return 1;
-}
-
-int
-check_node_label (NODE_SPEC_EXTRA *nse,
- enum command_id cmd)
+static int
+isascii_alpha (int c)
{
- check_internal_node (nse);
- return check_empty_node (nse, cmd);
+ return (((c & ~0x7f) == 0) && isalpha(c));
}
static int
@@ -98,190 +76,6 @@ is_whole_number (char *string)
return 0;
}
-/* Return end of argument before comment and whitespace. */
-char *
-skip_comment (char *q, int *has_comment)
-{
- char *q1;
- while (1)
- {
- q1 = strstr (q, "@c");
- if (!q1)
- {
- q = q + strlen (q);
- break;
- }
- q = q1 + 2;
- if (!memcmp (q, "omment", 6))
- q += 6;
-
- /* TeX control sequence name ends at an escape character or
- whitespace. */
- if (*q == '@' || strchr (whitespace_chars, *q))
- {
- q = q1;
- *has_comment = 1;
- break;
- }
- }
-
- /* q is now either at the end of the string, or at the start of a comment.
- Find the start of any trailing whitespace. */
- while (strchr (whitespace_chars, q[-1]))
- q--;
-
- return q;
-}
-
-/* Process argument to special line command. */
-ELEMENT *
-parse_special_misc_command (char *line, enum command_id cmd, int *has_comment)
-{
-#define ADD_ARG(string, len) do { \
- ELEMENT *E = new_element (ET_NONE); \
- text_append_n (&E->text, string, len); \
- add_to_element_contents (args, E); \
-} while (0)
-
- ELEMENT *args = new_element (ET_NONE);
- char *p = 0, *q = 0, *r = 0;
- char *value = 0, *remaining = 0;;
-
- switch (cmd)
- {
- case CM_set:
- {
- p = line;
- p += strspn (p, whitespace_chars);
- if (!*p)
- goto set_no_name;
- if (!isalnum (*p) && *p != '-' && *p != '_')
- goto set_invalid;
- q = strpbrk (p,
- " \t\f\r\n" /* whitespace */
- "{\\}~^+\"<>|@"); /* other bytes that aren't allowed */
- /* see also read_flag_name function in end_line.c */
-
- r = skip_comment (p, has_comment);
-
- if (!strchr (whitespace_chars, *q) && *q != '@')
- goto set_invalid;
-
- if (*q == '@')
- {
- /* Check for a comment, e.g. "@set flag@c comment" */
- if (q != r)
- goto set_invalid;
- }
-
- ADD_ARG(p, q - p); /* name */
-
- p = q + strspn (q, whitespace_chars);
- /* Actually, whitespace characters except form feed. */
-
- if (r >= p)
- ADD_ARG(p, r - p); /* value */
- else
- ADD_ARG("", 0);
-
- store_value (args->contents.list[0]->text.text,
- args->contents.list[1]->text.text);
-
- break;
-set_no_name:
- line_error ("@set requires a name");
- break;
-set_invalid:
- line_error ("bad name for @set");
- break;
- }
- case CM_clear:
- {
- char *flag = 0;
- p = line;
- p += strspn (p, whitespace_chars);
- if (!*p)
- goto clear_no_name;
- q = p;
- flag = read_flag_name (&q);
- if (!flag)
- goto clear_invalid;
- r = q + strspn (q, whitespace_chars);
- if (*r)
- goto clear_invalid; /* Trailing argument. */
-
- ADD_ARG (p, q - p);
- clear_value (flag);
- free (flag);
-
- break;
-clear_no_name:
- line_error ("@clear requires a name");
- break;
-clear_invalid:
- free (flag);
- line_error ("bad name for @clear");
- break;
- }
- case CM_unmacro:
- p = line;
- p += strspn (p, whitespace_chars);
- if (!*p)
- goto unmacro_noname;
- q = p;
- value = read_command_name (&q);
- if (!value)
- goto unmacro_badname;
- /* FIXME: Check comment syntax is right */
- delete_macro (value);
- ADD_ARG(value, q - p);
- debug ("UNMACRO %s", value);
- free (value);
- break;
-unmacro_noname:
- line_error ("@unmacro requires a name");
- break;
-unmacro_badname:
- line_error ("bad name for @unmacro");
- break;
- case CM_clickstyle:
- p = line;
- p += strspn (p, whitespace_chars);
- if (*p++ != '@')
- goto clickstyle_invalid;
- q = p;
- value = read_command_name (&q);
- if (!value)
- goto clickstyle_invalid;
- ADD_ARG (p - 1, q - p + 1);
- free (global_clickstyle); global_clickstyle = value;
- if (!memcmp (q, "{}", 2))
- q += 2;
- remaining = q;
- /* FIXME: check comment */
- break;
-clickstyle_invalid:
- line_error ("@clickstyle should only accept an @-command as argument, "
- "not `%s'", line);
- free (value);
- break;
- default:
- fatal ("unknown special line command");
- }
-
- if (remaining)
- {
- remaining += strspn (remaining, whitespace_chars);
- if (*remaining)
- {
- line_warn ("remaining argument on @%s line: %s",
- command_name(cmd), remaining);
- }
- }
- return args;
-#undef ADD_ARG
-}
-
/* Parse the arguments to a line command. Return an element whose contents
is an array of the arguments. For some commands, there is further
processing of the arguments (for example, for an @alias, remember the
@@ -336,7 +130,7 @@ parse_line_command_args (ELEMENT *line_command)
line++;
line += strspn (line, whitespace_chars);
- if (!isalnum (*line))
+ if (!isascii_alnum (*line))
goto alias_invalid;
existing = read_command_name (&line);
if (!existing)
@@ -350,7 +144,13 @@ parse_line_command_args (ELEMENT *line_command)
existing_cmd = lookup_command (existing);
if (!existing_cmd)
- break; /* TODO: Error message */
+ {
+ /* supposedly existing command not defined. Pre-register a
+ user-defined command */
+ existing_cmd = add_texinfo_command (existing);
+ user_defined_command_data[existing_cmd & ~USER_COMMAND_BIT].flags
+ |= CF_UNKNOWN;
+ }
else
{
if (command_data(existing_cmd).flags & CF_block)
@@ -358,14 +158,27 @@ parse_line_command_args (ELEMENT *line_command)
command_name(existing_cmd));
}
+ if (command_data(existing_cmd).flags & CF_ALIAS)
+ {
+ enum command_id alias_exist_cmd = command_data(existing_cmd).data;
+ if (! strcmp(command_name(alias_exist_cmd), new))
+ line_warn ("recursive alias definition of %s through %s ignored",
+ new, command_name(existing_cmd));
+ else
+ existing_cmd = alias_exist_cmd;
+ }
+
/* Remember the alias. */
new_cmd = add_texinfo_command (new);
new_cmd &= ~USER_COMMAND_BIT;
user_defined_command_data[new_cmd].flags |= CF_ALIAS;
-
user_defined_command_data[new_cmd].data = existing_cmd;
- user_defined_command_data[new_cmd].args_number
- = command_data(existing_cmd).args_number;
+ if (existing_cmd & USER_COMMAND_BIT)
+ {
+ enum command_id user_data_cmd = existing_cmd & ~USER_COMMAND_BIT;
+ user_defined_command_data[user_data_cmd].flags |= CF_REGISTERED;
+ }
+
/* Note the data field is an int, existing_cmd is
enum command_id, so would have problems if enum command_id
were wider than an int. */
@@ -413,6 +226,7 @@ parse_line_command_args (ELEMENT *line_command)
/* Remember it. */
new_cmd = add_texinfo_command (new_command);
add_infoenclose (new_cmd, start, end);
+ debug ("DEFINFOENCLOSE @%s: %s, %s", new_command, start, end);
new_cmd &= ~USER_COMMAND_BIT;
user_defined_command_data[new_cmd].flags
@@ -509,14 +323,12 @@ parse_line_command_args (ELEMENT *line_command)
for (ptr = forbidden_index_names; *ptr; ptr++)
if (!strcmp (name, *ptr))
goto defindex_reserved;
-
- if (index_by_name (name))
- { free (name); break; }
}
add_index (name, cmd == CM_defcodeindex ? 1 : 0);
ADD_ARG(name);
+ free (name);
break;
defindex_invalid:
line_error ("bad argument to @%s: %s",
@@ -536,7 +348,7 @@ parse_line_command_args (ELEMENT *line_command)
INDEX *from_index, *to_index;
char *p = line;
- if (!isalnum (*p))
+ if (!isascii_alnum (*p))
goto synindex_invalid;
from = read_command_name (&p);
if (!from)
@@ -544,7 +356,7 @@ parse_line_command_args (ELEMENT *line_command)
p += strspn (p, whitespace_chars);
- if (!isalnum (*p))
+ if (!isascii_alnum (*p))
goto synindex_invalid;
to = read_command_name (&p);
if (!to)
@@ -615,7 +427,8 @@ parse_line_command_args (ELEMENT *line_command)
("printing an index `%s' merged in another one, `%s'",
arg, i2->name);
}
- if (!current_node && !current_section && !current_region ())
+ if (!current_node && !current_section
+ && nesting_context.regions_stack.top == 0)
{
line_warn ("printindex before document beginning: "
"@printindex %s", arg);
@@ -705,7 +518,7 @@ parse_line_command_args (ELEMENT *line_command)
ADD_ARG(line);
}
else
- line_error ("@firstparagraph arg must be "
+ line_error ("@firstparagraphindent arg must be "
"`none' or `insert', not `%s'", line);
break;
@@ -750,7 +563,7 @@ parse_line_command_args (ELEMENT *line_command)
if (0)
{
-kdbinputstyle_invalid:
+ kdbinputstyle_invalid:
line_error ("@kbdinputstyle arg must be "
"`code'/`example'/`distinct', not `%s'", line);
}
@@ -805,198 +618,135 @@ kdbinputstyle_invalid:
#undef ADD_ARG
}
-/* NODE->contents is the Texinfo for the specification of a node. This
- function sets two fields on the returned object:
-
- manual_content - Texinfo tree for a manual name extracted from the
- node specification.
- node_content - Texinfo tree for the node name on its own
-
- Objects returned from this function are used as an 'extra' key in a
- few places: the elements of a 'nodes_manuals' array (itself an extra key),
- the 'menu_entry_node' key on a 'menu_entry' element (not to be confused
- with an ET_menu_entry_node element, which occurs in the args of a
- 'menu_entry' element), and in the 'node_argument' key of a cross-reference
- command (like @xref). */
-NODE_SPEC_EXTRA *
-parse_node_manual (ELEMENT *node)
-{
- NODE_SPEC_EXTRA *result;
- ELEMENT *new;
- int idx = 0; /* index into node->contents */
+/* for now done in Texinfo::Convert::NodeNameNormalization, but could be
+ good to do in Parser/XS */
+/* Array of recorded @float's. */
- result = malloc (sizeof (NODE_SPEC_EXTRA));
- result->manual_content = result->node_content = 0;
+FLOAT_RECORD *floats_list = 0;
+size_t floats_number = 0;
+size_t floats_space = 0;
- /* If the content starts with a '(', try to get a manual name. */
- if (node->contents.number > 0 && node->contents.list[0]->text.end > 0
- && node->contents.list[0]->text.text[0] == '(')
- {
- ELEMENT *manual, *first;
- char *opening_bracket, *closing_bracket;
- /* Handle nested parentheses in the manual name, for whatever reason. */
- int bracket_count = 1; /* Number of ( seen minus number of ) seen. */
+char *
+parse_float_type (ELEMENT *current)
+{
+ char *normalized;
+ if (current->args.number > 0)
+ {
+ /* TODO convert_to_texinfo is incorrect here, conversion should follow
+ code of Texinfo::Convert::NodeNameNormalization::convert_to_normalized */
+ normalized = convert_to_texinfo (current->args.list[0]);
+ }
+ else
+ normalized = strdup ("");
+ add_extra_string (current, "float_type", normalized);
+ return normalized;
+}
- manual = new_element (ET_NONE);
+ELEMENT *
+end_line_def_line (ELEMENT *current)
+{
+ enum command_id def_command;
+ DEF_ARG **def_info = 0;
+ KEY_PAIR *k;
+ ELEMENT *index_entry = 0; /* Index entry text. */
+ ELEMENT *def_info_name = 0;
+ ELEMENT *def_info_class = 0;
+ ELEMENT *def_info_category = 0;
+ int i = 0;
+ enum context top_context = pop_context ();
- /* If the first contents element is "(" followed by more text, split
- the leading "(" into its own element. */
- first = node->contents.list[0];
- if (first->text.end > 1)
- {
- memmove (first->text.text, first->text.text + 1, first->text.end);
- first->text.end--;
- new = new_element (0);
- text_append_n (&new->text, "(", 1);
- insert_into_contents (node, new, 0);
- }
- idx++;
+ if (top_context != ct_def)
+ fatal ("def context expected");
- for (; idx < node->contents.number; idx++)
- {
- ELEMENT *e = node->contents.list[idx];
- char *p, *q;
+ k = lookup_extra (current->parent, "def_command");
+ def_command = lookup_command ((char *) k->value);
- if (e->text.end == 0)
- {
- /* Put this element in the manual contents. */
- add_to_contents_as_array (manual, e);
- continue;
- }
- p = e->text.text;
- while (p < e->text.text + e->text.end
- && bracket_count > 0)
- {
- opening_bracket = strchr (p, '(');
- closing_bracket = strchr (p, ')');
- if (!opening_bracket && !closing_bracket)
- {
- break;
- }
- else if (opening_bracket && !closing_bracket)
- {
- bracket_count++;
- p = opening_bracket + 1;
- }
- else if (!opening_bracket && closing_bracket)
- {
- bracket_count--;
- p = closing_bracket + 1;
- }
- else if (opening_bracket < closing_bracket)
- {
- bracket_count++;
- p = opening_bracket + 1;
- }
- else if (opening_bracket > closing_bracket)
- {
- bracket_count--;
- p = closing_bracket + 1;
- }
- }
+ debug_nonl ("END DEF LINE %s; current ",
+ command_name(def_command));
+ debug_print_element (current, 1); debug ("");
- if (bracket_count > 0)
- add_to_contents_as_array (manual, e);
- else /* end of filename component */
- {
- /* Split the element in two, putting the part before the ")"
- in the manual name, leaving the part afterwards for the
- node name. */
- remove_from_contents (node, idx); /* Remove 'e'. */
+ def_info = parse_def (def_command, current);
- p--; /* point at ) */
- if (p > e->text.text)
- {
- /* text before ), part of the manual name */
- new = new_element (ET_NONE);
- text_append_n (&new->text, e->text.text,
- p - e->text.text);
- insert_into_contents (node, new, idx++);
+ /* def_line */
+ current = current->parent;
- add_to_contents_as_array (manual, new);
- }
+ /* Record the index entry if def_info is not empty. */
- new = new_element (0);
- text_append_n (&new->text, ")", 1);
- insert_into_contents (node, new, idx++);
+ while (def_info[i] != 0 && def_info[i]->element != 0)
+ {
+ if (!strcmp(def_info[i]->arg_type, "name"))
+ def_info_name = def_info[i]->element;
+ else if (!strcmp(def_info[i]->arg_type, "class"))
+ def_info_class = def_info[i]->element;
+ else if (!strcmp(def_info[i]->arg_type, "category"))
+ def_info_category = def_info[i]->element;
+ free (def_info[i]->arg_type);
+ free (def_info[i]);
+ i++;
+ }
+ free (def_info);
- /* Skip ')' and any following whitespace.
- Note that we don't manage to skip any multibyte
- UTF-8 space characters here. */
- p++;
- q = p + strspn (p, whitespace_chars);
- if (q > p)
- {
- new = new_element (0);
- text_append_n (&new->text, p, q - p);
- insert_into_contents (node, new, idx++);
- }
+ if (def_info_category)
+ {
+ if (def_info_name)
+ {
+ char *t;
+ /* Set index_entry unless an empty ET_bracketed_arg. */
+ if (def_info_name->type == ET_bracketed_arg
+ && (def_info_name->contents.number == 0
+ || (def_info_name->contents.number == 1
+ && (t = def_info_name->contents.list[0]->text.text)
+ && t[strspn (t, whitespace_chars)] == '\0')))
+ {
+ }
+ else
+ index_entry = def_info_name;
+ }
- p = q;
- if (*p)
- {
- /* text after ), part of the node name. */
- new = new_element (ET_NONE);
- text_append_n (&new->text, p,
- e->text.text + e->text.end - p);
- insert_into_contents (node, new, idx);
- }
- destroy_element (e);
- break;
+ if (index_entry)
+ {
+ if (def_info_class &&
+ (def_command == CM_defop
+ || def_command == CM_deftypeop
+ || def_command == CM_defmethod
+ || def_command == CM_deftypemethod
+ || def_command == CM_defivar
+ || def_command == CM_deftypeivar
+ || def_command == CM_deftypecv))
+ {
+ /* def_index_element will be set in
+ Texinfo::Translations::complete_indices */
+ if (global_documentlanguage)
+ add_extra_string_dup (current, "documentlanguage",
+ global_documentlanguage);
+ }
+ else
+ {
+ add_extra_element (current, "def_index_element",
+ index_entry);
}
- } /* for */
- if (bracket_count == 0)
- result->manual_content = manual;
- else /* unbalanced */
+ if (def_command != CM_defline && def_command != CM_deftypeline)
+ enter_index_entry (def_command, current);
+ }
+ else
{
- destroy_element (manual);
- idx = 0; /* Back to the start, and consider the whole thing
- as a node name. */
+ k = lookup_extra (current, "original_def_cmdname");
+ command_warn (current, "missing name for @%s", (char *) k->value);
}
}
-
- /* If anything left, it is the node name. */
- if (idx < node->contents.number)
+ else
{
- new = new_element (0);
- insert_slice_into_contents (new, 0, node, idx, node->contents.number);
- result->node_content = new;
+ k = lookup_extra (current, "original_def_cmdname");
+ command_warn (current, "missing category for @%s", (char *) k->value);
}
- return result;
-}
-/* Array of recorded @float's. */
-FLOAT_RECORD *floats_list = 0;
-size_t floats_number = 0;
-size_t floats_space = 0;
-
-int
-parse_float_type (ELEMENT *current)
-{
- EXTRA_FLOAT_TYPE *eft;
- eft = malloc (sizeof (EXTRA_FLOAT_TYPE));
- eft->content = 0;
- eft->normalized = 0;
-
- if (current->args.number > 0)
- {
- if (current->args.list[0]->contents.number > 0)
- {
- char *normalized;
- normalized = convert_to_texinfo (current->args.list[0]);
- eft->content = current->args.list[0];
- eft->normalized = normalized;
+ current = current->parent;
+ current = begin_preformatted (current);
- add_extra_float_type (current, "type", eft);
- return 1;
- }
- }
- eft->normalized = strdup ("");
- add_extra_float_type (current, "type", eft);
- return 0;
+ return current;
}
/* Actions to be taken at the end of a line that started a block that
@@ -1004,49 +754,67 @@ parse_float_type (ELEMENT *current)
ELEMENT *
end_line_starting_block (ELEMENT *current)
{
+ KEY_PAIR *k;
+
+ enum command_id command;
+
+ if (current->parent->type == ET_def_line)
+ command = current->parent->parent->cmd;
+ else
+ command = current->parent->cmd;
+
+ if (command_data(command).flags & CF_contain_basic_inline)
+ (void) pop_command (&nesting_context.basic_inline_stack_block);
+ isolate_last_space (current);
+
+ if (current->parent->type == ET_def_line)
+ return end_line_def_line (current);
+
if (pop_context () != ct_line)
fatal ("line context expected");
- if (current->parent->cmd == CM_multitable)
+ debug_nonl ("END BLOCK LINE: ");
+ debug_print_element (current, 1); debug ("");
+
+ /* @multitable args */
+ if (command == CM_multitable
+ && (k = lookup_extra (current->parent, "columnfractions")))
{
- /* Parse prototype row for a @multitable. Handling
- of @columnfractions is done elsewhere. */
+ ELEMENT *misc_cmd = (ELEMENT *) k->value;
+ ELEMENT *misc_args;
+ if ((misc_args = lookup_extra_element (misc_cmd, "misc_args")))
+ {
+ add_extra_integer (current->parent, "max_columns",
+ misc_args->contents.number);
+ }
+ else
+ {
+ add_extra_integer (current->parent, "max_columns", 0);
+ k->key = "";
+ k->type = extra_deleted;
+ }
+ }
+ else if (command == CM_multitable)
+ {
int i;
- ELEMENT *prototypes = new_element (ET_NONE);
+ int max_columns = 0;
for (i = 0; i < current->contents.number; i++)
{
ELEMENT *e = contents_child_by_index(current, i);
- if (e->type == ET_bracketed)
+ if (e->type == ET_bracketed_arg)
{
- /* Copy and change the type of the element. */
-
- ELEMENT *new;
- new = malloc (sizeof (ELEMENT));
- memcpy (new, e, sizeof (ELEMENT));
- new->type = ET_bracketed_multitable_prototype;
- new->parent = 0;
- new->extra_number = 0;
- add_to_contents_as_array (prototypes, new);
+ max_columns++;
}
else if (e->text.end > 0)
{
- /* Split the text up by whitespace. */
- char *p, *p2;
- p = e->text.text;
- while (1)
- {
- ELEMENT *new;
- p2 = p + strspn (p, whitespace_chars);
- if (!*p2)
- break;
- p = p2 + strcspn (p2, whitespace_chars);
- new = new_element (ET_row_prototype);
- text_append_n (&new->text, p2, p - p2);
- add_to_contents_as_array (prototypes, new);
- }
+ /*
+ TODO: this should be a warning or an error - all prototypes
+ on a @multitable line should be in braces, as documented in the
+ Texinfo manual.
+ */
}
else
{
@@ -1064,59 +832,48 @@ end_line_starting_block (ELEMENT *current)
}
{
- int max_columns = prototypes->contents.number;
add_extra_integer (current->parent, "max_columns", max_columns);
if (max_columns == 0)
command_warn (current->parent, "empty multitable");
}
- add_extra_contents_oot (current->parent, "prototypes", prototypes);
- /* See code in destroy_element for how prototypes is deallocated. */
}
- isolate_last_space (current);
current = current->parent;
if (counter_value (&count_remaining_args, current) != -1)
counter_pop (&count_remaining_args);
- if (current->cmd == CM_float)
+ if (command == CM_float)
{
- char *type = "";
- KEY_PAIR *k;
- EXTRA_FLOAT_TYPE *eft;
+ /* char *float_type = ""; */
+ ELEMENT *float_label_element = 0;
current->source_info = current_source_info;
if (current->args.number >= 2)
{
- NODE_SPEC_EXTRA *float_label;
- float_label = parse_node_manual (args_child_by_index (current, 1));
- check_internal_node (float_label);
-
- register_label (current, float_label->node_content);
- if (float_label->manual_content)
- destroy_element (float_label->manual_content);
- free (float_label);
- }
- parse_float_type (current);
- k = lookup_extra (current, "type");
- if (k)
- {
- eft = (EXTRA_FLOAT_TYPE *) k->value;
- type = eft->normalized;
+ float_label_element = args_child_by_index (current, 1);
}
+ check_register_target_element_label (float_label_element, current);
+ /* for now done in Texinfo::Convert::NodeNameNormalization, but could be
+ good to do in Parser/XS */
+ /*
+ float_type = parse_float_type (current);
+ */
/* add to global 'floats' array */
+ /*
if (floats_number == floats_space)
{
floats_list = realloc (floats_list,
(floats_space += 5) * sizeof (FLOAT_RECORD));
}
- floats_list[floats_number].type = type;
+ floats_list[floats_number].type = float_type;
floats_list[floats_number++].element = current;
+ */
if (current_section)
add_extra_element (current, "float_section", current_section);
}
-
- if (command_flags(current) & CF_blockitem)
+ else if (command_data(command).flags & CF_blockitem)
{
- if (current->cmd == CM_enumerate)
+ KEY_PAIR *k;
+ if (command == CM_enumerate)
{
char *spec = "1";
@@ -1130,31 +887,46 @@ end_line_starting_block (ELEMENT *current)
g = current->args.list[0]->contents.list[0];
/* Check if @enumerate specification is either a single
letter or a string of digits. */
- if (g->text.end == 1
- && isalpha ((unsigned char) g->text.text[0])
+ if ((g->text.end == 1
+ && isascii_alpha (g->text.text[0]))
|| (g->text.end > 0
&& !*(g->text.text
- + strspn (g->text.text, "0123456789"))))
+ + strspn (g->text.text, digit_chars))))
{
spec = g->text.text;
}
else
command_error (current, "bad argument to @%s",
- command_name(current->cmd));
+ command_name(command));
}
add_extra_string_dup (current, "enumerate_specification", spec);
}
- else if (item_line_command (current->cmd))
+ else if (item_line_command (command))
{
KEY_PAIR *k;
k = lookup_extra (current, "command_as_argument");
if (!k)
- command_error (current,
- "%s requires an argument: the formatter for @item",
- command_name(current->cmd));
+ {
+ if (current->args.number > 0
+ && current->args.list[0]->contents.number > 0)
+ {
+ char *texi_arg;
+
+ /* expand the contents to avoid surrounding spaces */
+ texi_arg = convert_contents_to_texinfo (current->args.list[0]);
+ command_error (current, "bad argument to @%s: %s",
+ command_name(command), texi_arg);
+ free (texi_arg);
+ }
+ else
+ {
+ command_error (current, "missing @%s argument",
+ command_name(command));
+ }
+ }
else
{
- ELEMENT *e = k->value;
+ ELEMENT *e = (ELEMENT *) k->value;
if (!(command_flags(e) & CF_brace)
|| (command_data(e->cmd).data == BRACE_noarg))
{
@@ -1162,18 +934,16 @@ end_line_starting_block (ELEMENT *current)
"command @%s not accepting argument in brace "
"should not be on @%s line",
command_name(e->cmd),
- command_name(current->cmd));
+ command_name(command));
k->key = "";
k->type = extra_deleted;
- /* FIXME: Error message for accent commands is done
- elsewhere (3040). */
}
}
}
/* check that command_as_argument of the @itemize is alone on the line,
otherwise it is not a command_as_argument */
- if (current->cmd == CM_itemize)
+ else if (command == CM_itemize)
{
KEY_PAIR *k;
k = lookup_extra (current, "command_as_argument");
@@ -1184,7 +954,7 @@ end_line_starting_block (ELEMENT *current)
for (i = 0; i < e->contents.number; i++)
{
- if (contents_child_by_index (e, i) == k->value)
+ if (contents_child_by_index (e, i) == (ELEMENT *) k->value)
{
i++;
break;
@@ -1199,7 +969,7 @@ end_line_starting_block (ELEMENT *current)
&& !*(f->text.text
+ strspn (f->text.text, whitespace_chars))))
{
- k->value->type = ET_NONE;
+ ((ELEMENT *) k->value)->type = ET_NONE;
k->key = "";
k->type = extra_deleted;
break;
@@ -1208,29 +978,25 @@ end_line_starting_block (ELEMENT *current)
}
}
- // Check if command_as_argument isn't an accent command
- if (current->cmd == CM_itemize || item_line_command(current->cmd))
+ /* Check if command_as_argument isn't an accent command */
+ k = lookup_extra (current, "command_as_argument");
+ if (k && k->value)
{
- KEY_PAIR *k = lookup_extra (current, "command_as_argument");
- if (k && k->value)
+ enum command_id cmd = ((ELEMENT *) k->value)->cmd;
+ if (cmd && (command_data(cmd).flags & CF_accent))
{
- enum command_id cmd = k->value->cmd;
- if (cmd && (command_data(cmd).flags & CF_accent))
- {
- command_warn (current, "accent command `@%s' "
- "not allowed as @%s argument",
- command_name(cmd),
- command_name(current->cmd));
- k->key = "";
- k->value = 0;
- k->type = extra_deleted;
- }
+ command_warn (current, "accent command `@%s' "
+ "not allowed as @%s argument",
+ command_name(cmd),
+ command_name(command));
+ k->key = "";
+ k->value = 0;
+ k->type = extra_deleted;
}
}
-
/* if no command_as_argument given, default to @bullet for
@itemize, and @asis for @table. */
- if (current->cmd == CM_itemize
+ if (command == CM_itemize
&& (current->args.number == 0
|| current->args.list[0]->contents.number == 0))
{
@@ -1252,7 +1018,7 @@ end_line_starting_block (ELEMENT *current)
insert_into_contents (block_line_arg, e, 0);
add_extra_element (current, "command_as_argument", e);
}
- else if (item_line_command (current->cmd)
+ else if (item_line_command (command)
&& !lookup_extra (current, "command_as_argument"))
{
ELEMENT *e;
@@ -1269,25 +1035,140 @@ end_line_starting_block (ELEMENT *current)
current = bi;
}
} /* CF_blockitem */
+ else if (command_data (command).args_number == 0
+ && (! (command_data (command).flags & CF_variadic))
+ && current->args.number > 0
+ && current->args.list[0]->contents.number > 0)
+ {
+ char *texi_arg;
+
+ /* expand the contents to avoid surrounding spaces */
+ texi_arg = convert_contents_to_texinfo (current->args.list[0]);
+ command_warn (current, "unexpected argument on @%s line: %s",
+ command_name(command), texi_arg);
+ free (texi_arg);
+ }
+
+ if (command_data(command).data == BLOCK_conditional)
+ {
+ int iftrue = 0; /* Whether the conditional is true. */
+ int bad_line = 1;
+ if (command == CM_ifclear || command == CM_ifset
+ || command == CM_ifcommanddefined
+ || command == CM_ifcommandnotdefined)
+ {
+ if (current->args.number == 1
+ && current->args.list[0]->contents.number == 1)
+ {
+ ELEMENT *arg_elt = current->args.list[0]->contents.list[0];
+ if (arg_elt->text.end > 0)
+ {
+ char *name = arg_elt->text.text;
+ char *p = name + strspn (name, whitespace_chars);
+ if (!*p)
+ {
+ line_error ("@%s requires a name", command_name(command));
+ bad_line = 0;
+ }
+ else
+ {
+ char *p = name;
+ char *flag = read_flag_name (&p);
+ if (flag && !*p)
+ {
+ bad_line = 0;
+ if (command == CM_ifclear || command == CM_ifset)
+ {
+ char *val = fetch_value (flag);
+ if (val)
+ iftrue = 1;
+ if (command == CM_ifclear)
+ iftrue = !iftrue;
+ }
+ else /* command == CM_ifcommanddefined
+ || command == CM_ifcommandnotdefined */
+ {
+ enum command_id c = lookup_command (flag);
+ if (c)
+ iftrue = 1;
+ if (command == CM_ifcommandnotdefined)
+ iftrue = !iftrue;
+ }
+ debug ("CONDITIONAL @%s %s: %d",
+ command_name(command), flag, iftrue);
+ }
+ free (flag);
+ }
+ }
+ }
+ else
+ {
+ line_error ("@%s requires a name", command_name(command));
+ bad_line = 0;
+ }
+ if (bad_line)
+ line_error ("bad name for @%s", command_name(command));
+ }
+ else if (!memcmp (command_name(command), "if", 2)) /* e.g. @ifhtml */
+ {
+ int i; char *p;
+ /* Handle @if* and @ifnot* */
+
+ p = command_name(command) + 2; /* After "if". */
+ if (!memcmp (p, "not", 3))
+ p += 3; /* After "not". */
+ for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
+ i++)
+ {
+ if (!strcmp (p, expanded_formats[i].format))
+ {
+ iftrue = expanded_formats[i].expandedp;
+ break;
+ }
+ }
+ if (!memcmp (command_name(command), "ifnot", 5))
+ iftrue = !iftrue;
+ debug ("CONDITIONAL @%s format %s: %d", command_name(command),
+ p, iftrue);
+ }
+ else
+ bug_message ("unknown conditional command @%s", command_name(command));
+
+ if (iftrue)
+ {
+ ELEMENT *e;
+ SOURCE_MARK *source_mark;
+ current = current->parent;
+ e = pop_element_from_contents (current);
+ e->parent = 0;
+ source_mark = new_source_mark (SM_type_expanded_conditional_command);
+ source_mark->status = SM_status_start;
+ source_mark->element = e;
+ register_source_mark (current, source_mark);
+ debug ("PUSH BEGIN COND %s", command_name(command));
+ push_conditional_stack (command, source_mark);
+ }
+ }
- if (command_data(current->cmd).data == BLOCK_menu)
+ if (command_data(command).data == BLOCK_menu)
{
/* Start reading a menu. Processing will continue in
- handle_menu in menus.c. */
+ in menus.c. */
ELEMENT *menu_comment = new_element (ET_menu_comment);
add_to_element_contents (current, menu_comment);
current = menu_comment;
debug ("MENU_COMMENT OPEN");
}
- if (command_data(current->cmd).data == BLOCK_format_raw
- && format_expanded_p (command_name(current->cmd)))
+ if (command_data(command).data == BLOCK_format_raw
+ && format_expanded_p (command_name(command)))
{
ELEMENT *rawpreformatted = new_element (ET_rawpreformatted);
add_to_element_contents (current, rawpreformatted);
current = rawpreformatted;
}
- if (command_data(current->cmd).data != BLOCK_raw)
+ if (command_data(command).data != BLOCK_raw
+ && command_data(command).data != BLOCK_conditional)
current = begin_preformatted (current);
return current;
@@ -1295,38 +1176,48 @@ end_line_starting_block (ELEMENT *current)
/* Actions to be taken at the end of an argument to a line command
not starting a block. @end is processed in here. */
-static ELEMENT *
+ELEMENT *
end_line_misc_line (ELEMENT *current)
{
enum command_id cmd;
- int arg_type;
+ enum command_id data_cmd;
+ int arg_spec;
ELEMENT *misc_cmd;
char *end_command = 0;
enum command_id end_id = CM_NONE;
int included_file = 0;
+ SOURCE_MARK *include_source_mark = 0;
+ data_cmd = cmd = current->parent->cmd;
+ /* we are in a command line context, so the @item command information is
+ associated to CM_item_LINE */
+ if (cmd == CM_item)
+ data_cmd = CM_item_LINE;
+
+ if (command_data(data_cmd).flags & CF_contain_basic_inline)
+ (void) pop_command (&nesting_context.basic_inline_stack_on_line);
isolate_last_space (current);
+ if (current->parent->type == ET_def_line)
+ return end_line_def_line (current);
+
current = current->parent;
misc_cmd = current;
- cmd = current->cmd;
- if (!cmd)
- fatal ("command name unknown for @end");
- arg_type = command_data(cmd).data;
-
- if (pop_context () != ct_line)
- fatal ("line context expected");
+ arg_spec = command_data(data_cmd).data;
debug ("MISC END %s", command_name(cmd));
- if (arg_type == LINE_specific)
+ if (pop_context () != ct_line)
+ fatal ("line context expected");
+
+ if (arg_spec == LINE_specific)
{
ELEMENT *args = parse_line_command_args (current);
if (args)
add_extra_misc_args (current, "misc_args", args);
}
- else if (arg_type == LINE_text)
+ else if (arg_spec == LINE_text)
{
char *text = 0;
int superfluous_arg = 0;
@@ -1361,32 +1252,8 @@ end_line_misc_line (ELEMENT *current)
}
else
{
- debug ("END BLOCK %s", end_command);
- /* Handle conditional block commands (e.g. @ifinfo) */
-
- /* If we are in a non-ignored conditional, there is not
- an element for the block in the tree; it is recorded
- in the conditional stack. Pop it and check it is the
- same as the one given in the @end line. */
+ debug ("END BLOCK @end %s", end_command);
- if (command_data(end_id).data == BLOCK_conditional)
- {
- enum command_id popped;
- if (conditional_number == 0)
- goto conditional_stack_fail;
- popped = pop_conditional_stack ();
- if (popped != end_id)
- {
- push_conditional_stack (popped);
- goto conditional_stack_fail;
- }
- if (0)
- {
- conditional_stack_fail:
- command_error (current, "unmatched `@end'");
- free (end_command); end_command = 0;
- }
- }
/* If there is superfluous text after @end argument, set
superfluous_arg such that the error message triggered by an
unexpected @-command on the @end line is issued below. Note
@@ -1411,7 +1278,6 @@ end_line_misc_line (ELEMENT *current)
{
int status;
char *fullpath, *sys_filename;
- debug ("Include %s", text);
sys_filename = encode_file_name (text);
fullpath = locate_include_file (sys_filename);
@@ -1426,170 +1292,154 @@ end_line_misc_line (ELEMENT *current)
status = input_push_file (fullpath);
if (status)
{
+ char *decoded_file_path
+ = convert_to_utf8 (strdup(fullpath));
command_error (current,
- "@include: could not open %s:",
- text,
+ "@include: could not open %s: %s",
+ decoded_file_path,
strerror (status));
+ free (decoded_file_path);
}
else
- included_file = 1;
+ {
+ included_file = 1;
+ debug ("Included %s", fullpath);
+
+ include_source_mark = new_source_mark (SM_type_include);
+ include_source_mark->status = SM_status_start;
+ set_input_source_mark (include_source_mark);
+ }
+ free (fullpath);
}
}
else if (current->cmd == CM_verbatiminclude)
{
- if (global_info.input_perl_encoding)
- add_extra_string_dup (current, "input_perl_encoding",
- global_info.input_perl_encoding);
+ if (global_input_encoding_name)
+ add_extra_string_dup (current, "input_encoding_name",
+ global_input_encoding_name);
}
else if (current->cmd == CM_documentencoding)
{
- int i; char *p, *text2;
- char *texinfo_encoding, *perl_encoding, *input_encoding;
- /* See tp/Texinfo/Encoding.pm (whole file) */
-
- /* Three concepts of encoding:
- texinfo_encoding -- one of the encodings supported as an
- argument to @documentencoding, documented
- in Texinfo manual
- perl_encoding -- used for charset conversion within Perl
- input_encoding -- for output within an HTML file */
-
- text2 = strdup (text);
- for (p = text2; *p; p++)
- *p = tolower (*p);
-
- /* Get texinfo_encoding from what was in the document */
- {
- static char *canonical_encodings[] = {
- "us-ascii", "utf-8", "iso-8859-1",
- "iso-8859-15","iso-8859-2","koi8-r", "koi8-u",
- 0
- };
-
- texinfo_encoding = 0;
- for (i = 0; (canonical_encodings[i]); i++)
+ int i; char *p, *normalized_text, *q;
+ int encoding_set;
+ char *input_encoding = 0;
+ int possible_encoding = 0;
+
+ normalized_text = strdup (text);
+ q = normalized_text;
+ /* lower case, trim non-ascii characters and keep only alphanumeric
+ characters, - and _. iconv also seems to trim non alphanumeric
+ non - _ characters */
+ for (p = text; *p; p++)
{
- if (!strcmp (text2, canonical_encodings[i]))
+ /* check if ascii and alphanumeric */
+ if (isascii_alnum(*p))
{
- texinfo_encoding = canonical_encodings[i];
- break;
+ possible_encoding = 1;
+ *q = tolower (*p);
+ q++;
}
- }
- if (!texinfo_encoding)
- {
- command_warn (current, "encoding `%s' is not a "
- "canonical texinfo encoding", text);
- }
- }
-
- /* Get perl_encoding. */
- perl_encoding = 0;
- if (texinfo_encoding)
- perl_encoding = texinfo_encoding;
- else
- {
- int i;
- static char *known_encodings[] = {
- "shift_jis",
- "latin1",
- "latin-1",
- "utf8",
- 0
- };
- for (i = 0; (known_encodings[i]); i++)
+ else if (*p == '_' || *p == '-')
{
- if (!strcmp (text2, known_encodings[i]))
- {
- perl_encoding = known_encodings[i];
- break;
- }
+ *q = *p;
+ q++;
}
}
- free (text2);
+ *q = '\0';
- if (perl_encoding)
- {
- struct encoding_map {
- char *from; char *to;
- };
- /* The map mimics Encode::find_encoding()->name() result.
- Even when the alias is not good, such as 'utf-8-strict'
- for 'utf-8', use the same mapping for consistency with the
- perl Parser */
- static struct encoding_map map[] = {
- "utf-8", "utf-8-strict",
- "us-ascii", "ascii",
- "shift_jis", "shiftjis",
- "latin1", "iso-8859-1",
- "latin-1", "iso-8859-1"
- };
- for (i = 0; i < sizeof map / sizeof *map; i++)
- {
- if (!strcmp (perl_encoding, map[i].from))
- {
- perl_encoding = map[i].to;
- break;
- }
- }
- add_extra_string_dup (current, "input_perl_encoding",
- perl_encoding);
- free (global_info.input_perl_encoding);
- global_info.input_perl_encoding = strdup (perl_encoding);
- }
+ if (! possible_encoding)
+ command_warn (current, "bad encoding name `%s'",
+ text);
else
{
- command_warn (current, "unrecognized encoding name `%s'",
- text);
- /* the Perl Parser calls Encode::find_encoding, so knows
- about more encodings than what we know about here.
- TODO: Check when perl_encoding could be defined when
- texinfo_encoding isn't.
- Maybe we should check if an iconv conversion is possible
- from this encoding to UTF-8. */
- }
+ /* Warn if the encoding is not one of the encodings supported as an
+ argument to @documentencoding, documented in Texinfo manual */
+ {
+ char *texinfo_encoding = 0;
+ static char *canonical_encodings[] = {
+ "us-ascii", "utf-8", "iso-8859-1",
+ "iso-8859-15","iso-8859-2","koi8-r", "koi8-u",
+ 0
+ };
+ char *text_lc;
+
+ text_lc = strdup (text);
+ for (p = text_lc; *p; p++)
+ if (isascii_alpha (*p))
+ *p = tolower (*p);
+
+ for (i = 0; (canonical_encodings[i]); i++)
+ {
+ if (!strcmp (text_lc, canonical_encodings[i]))
+ {
+ texinfo_encoding = canonical_encodings[i];
+ break;
+ }
+ }
+ free (text_lc);
+ if (!texinfo_encoding)
+ {
+ command_warn (current, "encoding `%s' is not a "
+ "canonical texinfo encoding", text);
+ }
+ }
- /* Set input_encoding from perl_encoding. In the perl parser,
- lc(Encode::find_encoding()->mime_name()) is used */
- input_encoding = 0;
- if (perl_encoding)
- {
- struct encoding_map {
- char *from; char *to;
- };
- static struct encoding_map map[] = {
- "utf8", "utf-8",
- "utf-8-strict","utf-8",
- "ascii", "us-ascii",
- "shiftjis", "shift_jis",
- "iso-8859-1", "iso-8859-1",
- "iso-8859-2", "iso-8859-2",
- "iso-8859-15", "iso-8859-15",
- "koi8-r", "koi8-r",
- "koi8-u", "koi8-u",
- };
- input_encoding = perl_encoding;
- for (i = 0; i < sizeof map / sizeof *map; i++)
+ /* Set input_encoding -- for output within an HTML file, used
+ in most output formats */
+ {
+ struct encoding_map {
+ char *from; char *to;
+ };
+
+ /* In the perl parser,
+ lc(Encode::find_encoding()->mime_name()) is used */
+ /* the Perl Parser calls Encode::find_encoding, so knows
+ about more encodings than what we know about here.
+ */
+ static struct encoding_map map[] = {
+ "utf-8", "utf-8",
+ "utf8", "utf-8",
+ "ascii", "us-ascii",
+ "shiftjis", "shift_jis",
+ "latin1", "iso-8859-1",
+ "latin-1", "iso-8859-1",
+ "iso-8859-1", "iso-8859-1",
+ "iso-8859-2", "iso-8859-2",
+ "iso-8859-15", "iso-8859-15",
+ "koi8-r", "koi8-r",
+ "koi8-u", "koi8-u",
+ };
+ for (i = 0; i < sizeof map / sizeof *map; i++)
+ {
+ /* Elements in first column map to elements in
+ second column. Elements in second column map
+ to themselves. */
+ if (!strcasecmp (normalized_text, map[i].from)
+ || !strcasecmp (normalized_text, map[i].to))
+ {
+ input_encoding = map[i].to;
+ break;
+ }
+ }
+ }
+ if (!input_encoding)
{
- /* Elements in first column map to elements in
- second column. Elements in second column map
- to themselves. */
- if (!strcasecmp (input_encoding, map[i].from)
- || !strcasecmp (input_encoding, map[i].to))
- {
- input_encoding = map[i].to;
- break;
- }
+ input_encoding = normalized_text;
}
- }
- if (input_encoding)
- {
- add_extra_string_dup (current, "input_encoding_name",
- input_encoding);
- global_info.input_encoding_name = strdup (input_encoding);
- set_input_encoding (input_encoding);
+ /* set_input_encoding also sets global_input_encoding_name */
+ encoding_set = set_input_encoding (input_encoding);
+ if (encoding_set)
+ {
+ add_extra_string_dup (current, "input_encoding_name",
+ input_encoding);
+ }
+ else
+ command_warn (current, "unhandled encoding name `%s'",
+ text);
}
+ free (normalized_text);
}
else if (current->cmd == CM_documentlanguage)
{
@@ -1601,7 +1451,7 @@ end_line_misc_line (ELEMENT *current)
just check if the language code looks right. */
p = text;
- while (isalpha ((unsigned char) *p))
+ while (isascii_alpha (*p))
p++;
if (*p && *p != '_')
{
@@ -1614,11 +1464,11 @@ end_line_misc_line (ELEMENT *current)
if (p - text > 4)
{
/* looks too long */
- char c = *p;
+ char saved = *p;
*p = 0;
command_warn (current, "%s is not a valid language code",
text);
- *p = c;
+ *p = saved;
}
if (*p == '_')
{
@@ -1626,7 +1476,7 @@ end_line_misc_line (ELEMENT *current)
p = q;
/* Language code should be of the form LL_CC,
language code followed by country code. */
- while (isalpha ((unsigned char) *p))
+ while (isascii_alpha (*p))
p++;
if (*p || p - q > 4)
{
@@ -1646,14 +1496,14 @@ end_line_misc_line (ELEMENT *current)
p = convert_to_texinfo (args_child_by_index(current, 0));
texi_line = p;
- while (isspace ((unsigned char) *texi_line))
- texi_line++;
+
+ texi_line += strspn (texi_line, whitespace_chars);
/* Trim leading and trailing whitespace. */
p1 = strchr (texi_line, '\0');
if (p1 > texi_line)
{
- while (p1 > texi_line && isspace ((unsigned char) p1[-1]))
+ while (p1 > texi_line && strchr (whitespace_chars, p1[-1]))
p1--;
*p1 = '\0';
}
@@ -1665,46 +1515,23 @@ end_line_misc_line (ELEMENT *current)
else if (current->cmd == CM_node)
{
int i;
- ELEMENT *arg;
- NODE_SPEC_EXTRA **nodes_manuals;
-
- /* Construct 'nodes_manuals' array. Maximum of four elements
- (node name, up, prev, next). */
- nodes_manuals = malloc (sizeof (NODE_SPEC_EXTRA *) * 5);
-
- for (i = 0; i < current->args.number && i < 4; i++)
+ for (i = 1; i < current->args.number && i < 4; i++)
{
- arg = current->args.list[i];
- nodes_manuals[i] = parse_node_manual (arg);
+ ELEMENT * arg = current->args.list[i];
+ NODE_SPEC_EXTRA *direction_label_info = parse_node_manual (arg, 1);
+ if (direction_label_info->node_content)
+ add_extra_contents (arg, "node_content",
+ direction_label_info->node_content);
+ if (direction_label_info->manual_content)
+ add_extra_contents (arg, "manual_content",
+ direction_label_info->manual_content);
+ free (direction_label_info);
}
- nodes_manuals[i] = 0;
-
- add_extra_node_spec_array (current, "nodes_manuals", nodes_manuals);
-
- check_internal_node (nodes_manuals[0]);
- if (nodes_manuals[0])
- {
- ELEMENT *label = 0;
- if (nodes_manuals[0]->node_content)
- {
- /* Copy the first 'node_content' array, to avoid the complication
- of it being referenced in two different places.
- This might be better with a separate function. */
- int i;
+ /* Now take care of the node itself */
+ check_register_target_element_label (current->args.list[0], current);
- label = new_element (0);
-
- for (i = 0; i<nodes_manuals[0]->node_content->contents.number;
- i++)
- {
- add_to_contents_as_array (label,
- contents_child_by_index(nodes_manuals[0]->node_content, i));
- }
- }
- register_label (current, label);
- }
if (current_part
&& !lookup_extra (current_part, "part_associated_section"))
{
@@ -1720,7 +1547,9 @@ end_line_misc_line (ELEMENT *current)
}
else if (current->cmd == CM_listoffloats)
{
- parse_float_type (current);
+ /* for now done in Texinfo::Convert::NodeNameNormalization, but could be
+ good to do in Parser/XS */
+ /* parse_float_type (current); */
}
else
{
@@ -1740,21 +1569,12 @@ end_line_misc_line (ELEMENT *current)
&& (current->cmd == CM_item || current->cmd == CM_itemx))
{
enter_index_entry (current->parent->cmd,
- current->cmd,
- current,
- current->args.list[0]);
- }
- else
- {
- // 3273 FIXME possibly check for @def... command
+ current);
}
-
-
+ else if (command_flags(current) & CF_index_entry_command)
/* Index commands */
- if (command_flags(current) & CF_index_entry_command)
{
- enter_index_entry (current->cmd, current->cmd, current,
- current->args.list[0]);
+ enter_index_entry (current->cmd, current);
current->type = ET_index_entry_command;
}
/* if there is a brace command interrupting an index or subentry
@@ -1779,25 +1599,20 @@ end_line_misc_line (ELEMENT *current)
ELEMENT *end_elt;
debug ("END COMMAND %s", end_command);
+ free (end_command);
/* Reparent the "@end" element to be a child of the block element. */
end_elt = pop_element_from_contents (current);
/* If not a conditional */
- if (command_data(end_id).data != BLOCK_conditional)
+ if (command_data(end_id).data != BLOCK_conditional
+ /* ignored conditional */
+ || current->cmd == end_id
+ /* not a non-ignored conditional */
+ || (conditional_number == 0
+ || top_conditional_stack ()->command != end_id))
{
ELEMENT *closed_command;
- /* here close some empty types. Typically empty preformatted
- that would have been closed anyway in _close_commands, but
- also other types (rawpreformatted, before_item), some which
- may also have been closed anyway. */
- if (!current->cmd && current->type != ET_NONE
- && (current->contents.number == 0) && current->parent)
- {
- current = current->parent;
- destroy_element (pop_element_from_contents (current));
- debug ("popping at end command");
- }
/* This closes tree elements (e.g. paragraphs) until we reach
end_command. It can print an error if another block command
is found first. */
@@ -1825,28 +1640,56 @@ end_line_misc_line (ELEMENT *current)
}
else
{
- /* The "@end" line does not appear in the final tree for a
+ /* If we are in a non-ignored conditional, there is not
+ an element for the block in the tree; it is recorded
+ in the conditional stack. Pop it, such that
+ the "@end" line does not appear in the final tree for a
conditional block. */
- destroy_element_and_children (end_elt);
+ CONDITIONAL_STACK_ITEM *cond_info = pop_conditional_stack ();
+ SOURCE_MARK *end_source_mark;
+ SOURCE_MARK *cond_source_mark = cond_info->source_mark;
+
+ debug ("POP END COND %s %s", command_name(end_id),
+ command_name(cond_info->command));
+
+ end_source_mark = new_source_mark (cond_source_mark->type);
+ end_source_mark->counter = cond_source_mark->counter;
+ end_source_mark->status = SM_status_end;
+ end_elt->parent = 0;
+ end_source_mark->element = end_elt;
+ register_source_mark (current, end_source_mark);
}
}
else
{
+ /* If a file was included, remove the include command completely.
+ Also ignore @setfilename in included file, as said in the manual. */
+ if (included_file || (cmd == CM_setfilename && top_file_index () > 0))
+ {
+ SOURCE_MARK *source_mark = 0;
+ if (included_file && include_source_mark)
+ source_mark = include_source_mark;
+ else
+ source_mark = new_source_mark (SM_type_setfilename);
+
+ if (source_mark)
+ {
+ /* this is in order to keep source marks that are within a
+ removed element. For the XS parser it is also easier to
+ manage the source mark memory which can stay associated
+ to the element. */
+ source_mark->element = pop_element_from_contents (current);
+ register_source_mark (current, source_mark);
+ }
+ }
if (close_preformatted_command (cmd))
current = begin_preformatted (current);
}
- /* If a file was included, remove the include command completely.
- Also ignore @setfilename in included file, as said in the manual. */
- if (included_file || (cmd == CM_setfilename && top_file_index () > 0))
- destroy_element_and_children (pop_element_from_contents (current));
- else if (cmd == CM_setfilename && (current_node || current_section))
+ if (cmd == CM_setfilename && (current_node || current_section))
command_warn (misc_cmd, "@setfilename after the first element");
else if (cmd == CM_columnfractions)
{
- ELEMENT *before_item;
- KEY_PAIR *misc_args;
-
/* Check if in multitable. */
if (!current->parent || current->parent->cmd != CM_multitable)
{
@@ -1855,35 +1698,15 @@ end_line_misc_line (ELEMENT *current)
}
else
{
- if (pop_context () != ct_line)
- fatal ("line context expected");
-
- current = current->parent;
-
- if ((misc_args = lookup_extra (misc_cmd, "misc_args")))
- {
- add_extra_element (current, "columnfractions", misc_cmd);
- add_extra_integer (current, "max_columns",
- misc_args->value->contents.number);
- }
- else
- add_extra_integer (current, "max_columns", 0);
-
- before_item = new_element (ET_before_item);
- add_to_element_contents (current, before_item);
- current = before_item;
+ add_extra_element (current->parent, "columnfractions", misc_cmd);
}
}
- else if (command_data(cmd).flags & CF_root)
+ else if (command_data(data_cmd).flags & CF_root)
{
current = last_contents_child (current);
if (cmd == CM_node)
counter_pop (&count_remaining_args);
- /* Destroy all contents (TODO: check why do we do this?) */
- while (last_contents_child (current))
- destroy_element (pop_element_from_contents (current));
-
/* Set 'associated_section' extra key for a node. */
if (cmd != CM_node && cmd != CM_part)
{
@@ -1938,7 +1761,8 @@ end_line (ELEMENT *current)
if (last_contents_child (current)
&& last_contents_child (current)->type == ET_empty_line)
{
- debug ("END EMPTY LINE");
+ debug_nonl ("END EMPTY LINE in ");
+ debug_print_element (current, 0); debug ("");
if (current->type == ET_paragraph)
{
ELEMENT *e;
@@ -1953,10 +1777,13 @@ end_line (ELEMENT *current)
else if (current->type == ET_preformatted
&& current->parent->type == ET_menu_entry_description)
{
+ /* happens for an empty line following a menu_description */
ELEMENT *empty_line, *e;
empty_line = pop_element_from_contents (current);
if (current->contents.number == 0)
{
+ /* it should not be possible to have source marks associated
+ to that container */
current = current->parent;
destroy_element (pop_element_from_contents (current));
}
@@ -1974,6 +1801,7 @@ end_line (ELEMENT *current)
current = e;
e = new_element (ET_after_menu_description_line);
text_append (&e->text, empty_line->text.text);
+ transfer_source_marks (empty_line, e);
destroy_element (empty_line);
add_to_element_contents (current, e);
@@ -1984,240 +1812,11 @@ end_line (ELEMENT *current)
current = end_paragraph (current, 0, 0);
}
}
- /* The end of the line of a menu. */
+ /* The end of the line of a menu entry, without description. */
else if (current->type == ET_menu_entry_name
|| current->type == ET_menu_entry_node)
{
- ELEMENT *end_comment = 0;
- int empty_menu_entry_node = 0;
-
- if (current->type == ET_menu_entry_node)
- {
- ELEMENT *last = last_contents_child (current);
-
- if (current->contents.number > 0
- && (last->cmd == CM_c || last->cmd == CM_comment))
- {
- end_comment = pop_element_from_contents (current);
- }
-
- /* If contents empty or is all whitespace. */
- if (current->contents.number == 0
- || (current->contents.number == 1
- && last->text.end > 0
- && !last->text.text[strspn (last->text.text,
- whitespace_chars)]))
- {
- empty_menu_entry_node = 1;
- if (end_comment)
- add_to_element_contents (current, end_comment);
- }
- }
-
- /* Abort the menu entry if there is no destination node given. */
- if (empty_menu_entry_node || current->type == ET_menu_entry_name)
- {
- ELEMENT *menu, *menu_entry, *description_or_menu_comment = 0;
- debug ("FINALLY NOT MENU ENTRY");
- menu = current->parent->parent;
- menu_entry = pop_element_from_contents (menu);
- if (menu->contents.number > 0
- && last_contents_child(menu)->type == ET_menu_entry)
- {
- ELEMENT *entry, *description = 0;
- int j;
-
- entry = last_contents_child(menu);
- for (j = entry->args.number - 1; j >= 0; j--)
- {
- ELEMENT *e = args_child_by_index (entry, j);
- if (e->type == ET_menu_entry_description)
- {
- description = e;
- break;
- }
- }
- if (description)
- description_or_menu_comment = description;
- else
- {
- ELEMENT *e;
- /* "Normally this cannot happen." */
- bug ("no description in menu entry");
- e = new_element (ET_menu_entry_description);
- add_to_element_args (entry, e);
- description_or_menu_comment = e;
- }
- }
- else if (menu->contents.number > 0
- && last_contents_child(menu)->type == ET_menu_comment)
- {
- description_or_menu_comment = last_contents_child(menu);
- }
- if (description_or_menu_comment)
- {
- current = description_or_menu_comment;
- if (current->contents.number > 0
- && last_contents_child(current)->type == ET_preformatted)
- current = last_contents_child(current);
- else
- {
- ELEMENT *e;
- /* This should not happen */
- bug ("description or menu comment not in preformatted");
- e = new_element (ET_preformatted);
- add_to_element_contents (current, e);
- current = e;
- }
- }
- else
- {
- ELEMENT *e;
- e = new_element (ET_menu_comment);
- add_to_element_contents (menu, e);
- current = e;
- e = new_element (ET_preformatted);
- add_to_element_contents (current, e);
- current = e;
- debug ("THEN MENU_COMMENT OPEN");
- }
- {
- int i, j;
- for (i = 0; i < menu_entry->args.number; i++)
- {
- ELEMENT *arg = args_child_by_index(menu_entry, i);
- if (arg->text.end > 0)
- current = merge_text (current, arg->text.text);
- else
- {
- ELEMENT *e;
- for (j = 0; j < arg->contents.number; j++)
- {
- e = contents_child_by_index (arg, j);
- if (e->text.end > 0)
- {
- current = merge_text (current, e->text.text);
- destroy_element (e);
- }
- else
- {
- add_to_element_contents (current, e);
- }
- }
- }
- destroy_element (arg);
- }
- destroy_element (menu_entry);
- }
- }
- else
- {
- debug ("MENU ENTRY END LINE");
- current = current->parent;
- current = enter_menu_entry_node (current);
- if (end_comment)
- add_to_element_contents (current, end_comment);
- }
- }
-
- /* End of a definition line, like @deffn */
- else if (current->parent && current->parent->type == ET_def_line)
- {
- enum command_id def_command, original_def_command;
- DEF_INFO *def_info = 0;
- static DEF_INFO zero_def_info; /* always stays zeroed */
- KEY_PAIR *k;
-
- if (pop_context () != ct_def)
- fatal ("def context expected");
-
- k = lookup_extra (current->parent, "original_def_cmdname");
- if (k)
- original_def_command = lookup_command ((char *) k->value);
- else
- original_def_command = current->parent->parent->cmd;
-
- def_command = original_def_command;
- /* Strip an trailing x from the command, e.g. @deffnx -> @deffn */
- if (command_data(def_command).flags & CF_line)
- {
- char *stripped = strdup (command_name(def_command));
- stripped[strlen (stripped) - 1] = '\0';
- def_command = lookup_command (stripped);
- free (stripped);
- }
-
- /* in case there are no arguments at all, it needs to be called here. */
- abort_empty_line (&current, NULL);
-
- def_info = parse_def (def_command, current);
-
- /* Record the index entry if def_info is not empty. */
- if (!memcmp(def_info, &zero_def_info, sizeof (DEF_INFO)))
- {
- free (def_info);
- command_warn (current->parent, "missing category for @%s",
- command_name (original_def_command));
- }
- else
- {
- ELEMENT *index_entry = 0; /* Index entry text. */
-
- add_extra_def_info (current->parent, "def_parsed_hash", def_info);
-
- if (def_info->name)
- {
- char *t;
- /* Set index_entry unless an empty ET_bracketed_def_content. */
- if (def_info->name->type == ET_bracketed_def_content
- && (def_info->name->contents.number == 0
- || (def_info->name->contents.number == 1
- && (t = def_info->name->contents.list[0]->text.text)
- && t[strspn (t, whitespace_chars)] == '\0')))
- {
- }
- else
- index_entry = def_info->name;
- }
-
- if (index_entry)
- {
- ELEMENT *index_contents = 0;
-
- if (def_info->class &&
- (def_command == CM_defop
- || def_command == CM_deftypeop
- || def_command == CM_defmethod
- || def_command == CM_deftypemethod
- || def_command == CM_defivar
- || def_command == CM_deftypeivar
- || def_command == CM_deftypecv))
- {
- if (global_documentlanguage)
- add_extra_string_dup (current->parent, "documentlanguage",
- global_documentlanguage);
- }
- else
- {
- index_contents = new_element (ET_NONE);
- if (index_contents->contents.number == 0)
- add_to_contents_as_array (index_contents, index_entry);
- }
-
- enter_index_entry (def_command,
- original_def_command,
- current->parent,
- index_contents);
- }
- else
- {
- command_warn (current->parent, "missing name for @%s",
- command_name (original_def_command));
- }
- }
-
- current = current->parent->parent;
- current = begin_preformatted (current);
+ current = end_line_menu_entry (current);
}
/* End of a line starting a block. */
else if (current->type == ET_block_line_arg)
@@ -2234,7 +1833,9 @@ end_line (ELEMENT *current)
line commands are nested (always incorrectly?) */
if (current_context () == ct_line || current_context () == ct_def)
{
- debug ("Still opened line command");
+ debug_nonl ("Still opened line/block command %s: ",
+ context_name (current_context ()));
+ debug_print_element (current, 1); debug("");
if (current_context () == ct_def)
{
while (current->parent
@@ -2253,7 +1854,8 @@ end_line (ELEMENT *current)
}
}
- if (current == current_old)
+ /* Check is disabled as new_element can reuse storage. */
+ if (0 && current == current_old)
fatal ("infinite loop when closing commands");
current = end_line (current);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/errors.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/errors.c
index fafaf9c9d4..d333ce1292 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/errors.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/errors.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "errors.h"
#include "input.h"
#include "text.h"
+#include "debug.h"
/* wrappers for asprintf and vasprintf */
int
@@ -59,6 +60,22 @@ void fatal (char *message)
abort ();
}
+/* these are not full line messages, but the part that are output along
+ with debug messages, as is done in Texinfo::Register::line_warn/line_error
+ called by the perl parser. Here without using the gettext framework
+ for the translation of 'warning'*/
+void
+debug_error_warning_message (ERROR_MESSAGE *error_message)
+{
+ if (error_message->type == warning)
+ fprintf (stderr, "warning: ");
+
+ if (error_message->source_info.macro)
+ fprintf (stderr, "%s (possibly involving @%s)\n",
+ error_message->message, error_message->source_info.macro);
+ else
+ fprintf (stderr, "%s\n", error_message->message);
+}
ERROR_MESSAGE *error_list = 0;
size_t error_number = 0;
@@ -93,6 +110,9 @@ line_error_internal (enum error_type type, SOURCE_INFO *cmd_source_info,
}
else
error_list[error_number++].source_info = current_source_info;
+
+ if (debug_output)
+ debug_error_warning_message (&error_list[error_number -1]);
}
void
@@ -176,3 +196,4 @@ bug_message (char *format, ...)
va_start (v, format);
bug_message_internal (format, v);
}
+
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/extra.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/extra.c
index ccdb7fe5c0..9e37e5346c 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/extra.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/extra.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,30 +19,30 @@
#include "parser.h"
static void
-add_extra_key (ELEMENT *e, char *key, ELEMENT *value,
- enum extra_type type)
+add_associated_info_key (ASSOCIATED_INFO *a, char *key, intptr_t value,
+ enum extra_type type)
{
int i;
- for (i = 0; i < e->extra_number; i++)
+ for (i = 0; i < a->info_number; i++)
{
- if (!strcmp (e->extra[i].key, key))
+ if (!strcmp (a->info[i].key, key))
break;
}
- if (i == e->extra_number)
+ if (i == a->info_number)
{
- if (e->extra_number == e->extra_space)
+ if (a->info_number == a->info_space)
{
- e->extra = realloc (e->extra,
- (e->extra_space += 5) * sizeof (KEY_PAIR));
- if (!e->extra)
+ a->info = realloc (a->info,
+ (a->info_space += 5) * sizeof (KEY_PAIR));
+ if (!a->info)
fatal ("realloc failed");
}
- e->extra_number++;
+ a->info_number++;
}
- e->extra[i].key = key;
- e->extra[i].value = value;
- e->extra[i].type = type;
+ a->info[i].key = key;
+ a->info[i].value = value;
+ a->info[i].type = type;
}
/* Add an extra key that is a reference to another element (for example,
@@ -50,37 +50,35 @@ add_extra_key (ELEMENT *e, char *key, ELEMENT *value,
void
add_extra_element (ELEMENT *e, char *key, ELEMENT *value)
{
- add_extra_key (e, key, value, extra_element);
+ add_associated_info_key (&e->extra_info, key,
+ (intptr_t) value, extra_element);
}
/* Add an extra key that is a reference to another element that is
- out-of-tree, i.e., not referenced anywhere in the tree. */
+ out-of-tree, i.e., not referenced anywhere in the tree.
+ Unused in 2023.
+*/
void
add_extra_element_oot (ELEMENT *e, char *key, ELEMENT *value)
{
- add_extra_key (e, key, value, extra_element_oot);
+ add_associated_info_key (&e->extra_info,
+ key, (intptr_t) value, extra_element_oot);
}
-/* Add an extra key that is a reference to the contents array of another
- element (for example, 'node_content' on a node command element). */
-void
-add_extra_contents (ELEMENT *e, char *key, ELEMENT *value)
-{
- add_extra_key (e, key, value, extra_contents);
-}
-
-/* Like add_extra_contents but all of the contents are out-of-tree. */
void
-add_extra_contents_oot (ELEMENT *e, char *key, ELEMENT *value)
+add_info_element_oot (ELEMENT *e, char *key, ELEMENT *value)
{
- add_extra_key (e, key, value, extra_contents_oot);
+ add_associated_info_key (&e->info_info,
+ key, (intptr_t) value, extra_element_oot);
}
-/* An array of content arrays. */
+/* Add an extra key that is a reference to the contents array of another
+ element (for example, 'node_content' on a node command element). */
void
-add_extra_contents_array (ELEMENT *e, char *key, ELEMENT *value)
+add_extra_contents (ELEMENT *e, char *key, ELEMENT *value)
{
- add_extra_key (e, key, value, extra_contents_array);
+ add_associated_info_key (&e->extra_info,
+ key, (intptr_t) value, extra_contents);
}
/* Add an extra key that is a reference to the text field of another
@@ -88,77 +86,93 @@ add_extra_contents_array (ELEMENT *e, char *key, ELEMENT *value)
void
add_extra_text (ELEMENT *e, char *key, ELEMENT *value)
{
- add_extra_key (e, key, value, extra_text);
+ add_associated_info_key (&e->extra_info, key, (intptr_t) value, extra_text);
}
-#if 0
-/* Function not used */
-void
-add_extra_index_entry (ELEMENT *e, char *key, INDEX_ENTRY_REF *value)
-{
- add_extra_key (e, key, (ELEMENT *) value, extra_index_entry);
-}
-#endif
-
void
add_extra_misc_args (ELEMENT *e, char *key, ELEMENT *value)
{
if (!value) return;
- add_extra_key (e, key, value, extra_misc_args);
+ add_associated_info_key (&e->extra_info,
+ key, (intptr_t) value, extra_misc_args);
}
void
-add_extra_node_spec (ELEMENT *e, char *key, NODE_SPEC_EXTRA *value)
+add_extra_string (ELEMENT *e, char *key, char *value)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_node_spec);
+ add_associated_info_key (&e->extra_info, key,
+ (intptr_t) value, extra_string);
}
-/* Used for 'node_manuals' array for the arguments given on a
- @node line. Argument is a null-terminated array of pointers. */
void
-add_extra_node_spec_array (ELEMENT *e, char *key, NODE_SPEC_EXTRA **value)
+add_info_string (ELEMENT *e, char *key, char *value)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_node_spec_array);
+ add_associated_info_key (&e->info_info, key, (intptr_t) value, extra_string);
}
void
-add_extra_def_info (ELEMENT *e, char *key, DEF_INFO *value)
+add_extra_string_dup (ELEMENT *e, char *key, char *value)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_def_info);
+ add_associated_info_key (&e->extra_info,
+ key, (intptr_t) strdup (value), extra_string);
}
void
-add_extra_float_type (ELEMENT *e, char *key, EXTRA_FLOAT_TYPE *value)
+add_info_string_dup (ELEMENT *e, char *key, char *value)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_float_type);
+ add_associated_info_key (&e->info_info,
+ key, (intptr_t) strdup (value), extra_string);
}
void
-add_extra_string (ELEMENT *e, char *key, char *value)
+add_extra_integer (ELEMENT *e, char *key, long value)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_string);
+ add_associated_info_key (&e->extra_info,
+ key, (intptr_t) value, extra_integer);
}
-void
-add_extra_string_dup (ELEMENT *e, char *key, char *value)
+KEY_PAIR *
+lookup_associated_info (ASSOCIATED_INFO *a, char *key)
{
- add_extra_key (e, key, (ELEMENT *) strdup (value), extra_string);
+ int i;
+ for (i = 0; i < a->info_number; i++)
+ {
+ if (!strcmp (a->info[i].key, key))
+ return &a->info[i];
+ }
+ return 0;
}
-void
-add_extra_integer (ELEMENT *e, char *key, long value)
+ELEMENT *
+lookup_extra_element (ELEMENT *e, char *key)
{
- add_extra_key (e, key, (ELEMENT *) value, extra_integer);
+ KEY_PAIR *k;
+ k = lookup_associated_info (&e->extra_info, key);
+ if (!k)
+ return 0;
+ return (ELEMENT *) k->value;
}
KEY_PAIR *
lookup_extra (ELEMENT *e, char *key)
{
- int i;
- for (i = 0; i < e->extra_number; i++)
- {
- if (!strcmp (e->extra[i].key, key))
- return &e->extra[i];
- }
- return 0;
+ return lookup_associated_info (&e->extra_info, key);
+}
+
+ELEMENT *
+lookup_info_element (ELEMENT *e, char *key)
+{
+ KEY_PAIR *k;
+ k = lookup_associated_info (&e->info_info, key);
+ if (!k)
+ return 0;
+ return (ELEMENT *) k->value;
+}
+
+
+KEY_PAIR *
+lookup_info (ELEMENT *e, char *key)
+{
+ return lookup_associated_info (&e->info_info, key);
}
+
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.c
index 94c95eb69f..880870ba70 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.c
@@ -1,5 +1,5 @@
/* handle_commands.c -- what to do when a command name is first read */
-/* Copyright 2010-2020 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,8 +17,12 @@
#include <config.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include "parser.h"
+#include "def.h"
+#include "debug.h"
+#include "tree.h"
#include "input.h"
#include "text.h"
@@ -77,12 +81,244 @@ check_no_text (ELEMENT *current)
return after_paragraph;
}
+int
+in_paragraph (ELEMENT *current)
+{
+ while (current->parent
+ && (command_flags(current->parent) & CF_brace)
+ && !(command_data(current->parent->cmd).data == BRACE_context))
+ {
+ current = current->parent->parent;
+ }
+ if (current->type == ET_paragraph)
+ return 1;
+ else
+ return 0;
+}
+
+/* Return end of argument before comment and whitespace. */
+char *
+skip_to_comment (char *q, int *has_comment)
+{
+ char *q1;
+
+ while (1)
+ {
+ q1 = strstr (q, "@c");
+ if (!q1)
+ {
+ q = q + strlen (q);
+ break;
+ }
+
+ /* q is advanced to after @c/@comment, whether there is indeed
+ a comment or not. In case there is no @c/@comment, this allows
+ to advance on the line and loop to search again for @c/@comment */
+ q = read_comment (q1, has_comment);
+ if (*has_comment)
+ {
+ /* replace q at the start of the comment */
+ q = q1;
+ break;
+ }
+ }
+
+ /* q is now either at the end of the string, or at the start of a comment.
+ Find the start of any trailing whitespace. */
+ while (strchr (whitespace_chars, q[-1]))
+ q--;
+
+ return q;
+}
+
+/* Return end of argument before comment and whitespace if the
+ line is followed either by whitespaces or a comment. */
+char *
+skip_to_comment_if_comment_or_spaces (char *after_argument,
+ int *has_comment)
+{
+ char *r = skip_to_comment (after_argument, has_comment);
+
+ if (!strchr (whitespace_chars, *after_argument)
+ && *after_argument != '@')
+ return 0;
+
+ if (*after_argument == '@')
+ {
+ /* Check for a comment, e.g. "@set flag@c comment" */
+ if (after_argument != r)
+ return 0;
+ }
+ return r;
+}
+
+/* Process argument to raw line command. */
+ELEMENT *
+parse_rawline_command (char *line, enum command_id cmd,
+ int *has_comment, int *special_arg)
+{
+#define ADD_ARG(string, len) do { \
+ ELEMENT *E = new_element (ET_NONE); \
+ text_append_n (&E->text, string, len); \
+ add_to_element_contents (args, E); \
+} while (0)
+
+ ELEMENT *args = new_element (ET_NONE);
+ char *p = 0, *q = 0, *r = 0;
+ char *value = 0;
+
+ *special_arg = 1;
+
+ switch (cmd)
+ {
+ case CM_set:
+ {
+ p = line;
+ p += strspn (p, whitespace_chars);
+ if (!*p)
+ goto set_no_name;
+ if (!isascii_alnum (*p) && *p != '-' && *p != '_')
+ goto set_invalid;
+ q = strpbrk (p,
+ " \t\f\r\n" /* whitespace */
+ "{\\}~^+\"<>|@"); /* other bytes that aren't allowed */
+ if (q)
+ {
+ /* see also read_flag_name function in end_line.c */
+ r = skip_to_comment_if_comment_or_spaces (q, has_comment);
+ if (!r)
+ goto set_invalid;
+ }
+ else /* very specific case of end of text fragment after name
+ without anything following the name, in particular
+ without new line */
+ q = p + strlen(p);
+
+ ADD_ARG(p, q - p); /* name */
+
+ p = q + strspn (q, whitespace_chars);
+ /* Actually, whitespace characters except form feed. */
+
+ if (r >= p)
+ ADD_ARG(p, r - p); /* value */
+ else
+ ADD_ARG("", 0);
+
+ store_value (args->contents.list[0]->text.text,
+ args->contents.list[1]->text.text);
+
+ break;
+ set_no_name:
+ line_error ("@set requires a name");
+ break;
+ set_invalid:
+ line_error ("bad name for @set");
+ break;
+ }
+ case CM_clear:
+ {
+ char *flag = 0;
+ p = line;
+ p += strspn (p, whitespace_chars);
+ if (!*p)
+ goto clear_no_name;
+ q = p;
+ flag = read_flag_name (&q);
+ if (!flag)
+ goto clear_invalid;
+ r = skip_to_comment_if_comment_or_spaces (q, has_comment);
+ if (!r || r != q)
+ goto clear_invalid; /* Trailing argument. */
+
+ ADD_ARG (p, q - p);
+ clear_value (flag);
+ free (flag);
+
+ break;
+ clear_no_name:
+ line_error ("@clear requires a name");
+ break;
+ clear_invalid:
+ free (flag);
+ line_error ("bad name for @clear");
+ break;
+ }
+ case CM_unmacro:
+ p = line;
+ p += strspn (p, whitespace_chars);
+ if (!*p)
+ goto unmacro_noname;
+ q = p;
+ value = read_command_name (&q);
+ if (!value)
+ goto unmacro_badname;
+ r = skip_to_comment_if_comment_or_spaces (q, has_comment);
+ if (!r || r != q)
+ goto clear_invalid; /* Trailing argument. */
+ delete_macro (value);
+ ADD_ARG(value, q - p);
+ debug ("UNMACRO %s", value);
+ free (value);
+ break;
+ unmacro_noname:
+ line_error ("@unmacro requires a name");
+ break;
+ unmacro_badname:
+ line_error ("bad name for @unmacro");
+ break;
+ case CM_clickstyle:
+ p = line;
+ p += strspn (p, whitespace_chars);
+ if (*p++ != '@')
+ goto clickstyle_invalid;
+ q = p;
+ value = read_command_name (&q);
+ if (!value)
+ goto clickstyle_invalid;
+ ADD_ARG (p - 1, q - p + 1);
+ free (global_clickstyle); global_clickstyle = value;
+ /* if strlen is not used to guard against checking after the end of q,
+ for some reason, valgrind does not find that the *(q+1) could be
+ unallocated */
+ if (strlen (q) >= 2 && !memcmp (q, "{}", 2))
+ q += 2;
+ r = skip_to_comment_if_comment_or_spaces (q, has_comment);
+ if (!r || r != q)
+ {
+ char *end_line;
+ char *line_nonl;
+ q += strspn (q, whitespace_chars);
+ /* remove new line for the message */
+ line_nonl = strdup (q);
+ end_line = strchr (line_nonl, '\n');
+ if (end_line)
+ *end_line = '\0';
+ line_warn ("remaining argument on @%s line: %s",
+ command_name(cmd), line_nonl);
+ free (line_nonl);
+ }
+ break;
+ clickstyle_invalid:
+ line_error ("@clickstyle should only accept an @-command as argument, "
+ "not `%s'", line);
+ free (value);
+ break;
+ default:
+ *special_arg = 0;
+ ADD_ARG (line, strlen(line));
+ }
+
+ return args;
+#undef ADD_ARG
+}
+
/* symbol skipspace other */
ELEMENT *
handle_other_command (ELEMENT *current, char **line_inout,
- enum command_id cmd, int *status)
+ enum command_id cmd, int *status,
+ ELEMENT **command_element)
{
- ELEMENT *misc = 0;
+ ELEMENT *command_e = 0;
char *line = *line_inout;
int arg_spec;
@@ -91,9 +327,9 @@ handle_other_command (ELEMENT *current, char **line_inout,
arg_spec = command_data(cmd).data;
if (arg_spec != NOBRACE_skipspace)
{
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
- add_to_element_contents (current, misc);
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ add_to_element_contents (current, command_e);
if (command_data(cmd).flags & CF_in_heading_spec
&& !(command_data(current_context_command()).flags & CF_heading_spec))
{
@@ -115,7 +351,7 @@ handle_other_command (ELEMENT *current, char **line_inout,
}
else /* NOBRACE_other */
{
- register_global_command (misc);
+ register_global_command (command_e);
if (close_preformatted_command(cmd))
current = begin_preformatted (current);
}
@@ -135,14 +371,14 @@ handle_other_command (ELEMENT *current, char **line_inout,
{
debug ("ITEM CONTAINER");
counter_inc (&count_items);
- misc = new_element (ET_NONE);
- misc->cmd = CM_item;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = CM_item;
- add_extra_integer (misc, "item_number",
+ add_extra_integer (command_e, "item_number",
counter_value (&count_items, parent));
- add_to_element_contents (parent, misc);
- current = misc;
+ add_to_element_contents (parent, command_e);
+ current = command_e;
}
else
{
@@ -163,23 +399,12 @@ handle_other_command (ELEMENT *current, char **line_inout,
/* In a @multitable */
else if ((parent = item_multitable_parent (current)))
{
- int max_columns = 0;
- KEY_PAIR *prototypes;
+ long max_columns = 0;
+ KEY_PAIR *k;
- prototypes = lookup_extra (parent, "prototypes");
- if (prototypes)
- max_columns = prototypes->value->contents.number;
- else
- {
- prototypes = lookup_extra(parent, "columnfractions");
- if (prototypes)
- {
- prototypes = lookup_extra((ELEMENT *) prototypes->value,
- "misc_args");
- if (prototypes)
- max_columns = prototypes->value->contents.number;
- }
- }
+ k = lookup_extra (parent, "max_columns");
+ if (k)
+ max_columns = (long) k->value;
if (max_columns == 0)
{
@@ -201,10 +426,10 @@ handle_other_command (ELEMENT *current, char **line_inout,
else
{
counter_inc (&count_cells);
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
- add_to_element_contents (row, misc);
- current = misc;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ add_to_element_contents (row, command_e);
+ current = command_e;
debug ("TAB");
add_extra_integer (current, "cell_number",
@@ -224,10 +449,10 @@ handle_other_command (ELEMENT *current, char **line_inout,
add_extra_integer (row, "row_number",
parent->contents.number - 1);
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
- add_to_element_contents (row, misc);
- current = misc;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ add_to_element_contents (row, command_e);
+ current = command_e;
if (counter_value (&count_cells, parent) != -1)
counter_pop (&count_cells);
@@ -248,37 +473,47 @@ handle_other_command (ELEMENT *current, char **line_inout,
command_name(cmd));
current = begin_preformatted (current);
}
- if (misc)
- misc->source_info = current_source_info;
+ if (command_e)
+ command_e->source_info = current_source_info;
}
else
{
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
- misc->source_info = current_source_info;
- add_to_element_contents (current, misc);
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ command_e->source_info = current_source_info;
+ add_to_element_contents (current, command_e);
+ if ((cmd == CM_indent || cmd == CM_noindent)
+ && in_paragraph (current))
+ {
+ line_warn ("@%s is useless inside of a paragraph",
+ command_name(cmd));
+ }
}
start_empty_line_after_command (current, &line, 0);
}
*line_inout = line;
+ *command_element = command_e;
return current;
}
/* STATUS is set to GET_A_NEW_LINE if we should get a new line after this,
to FINISHED_TOTALLY if we should stop processing completely. */
+/* data_cmd (used for the information on the command) and cmd (for the
+ command name) is different for the only multicategory command, @item */
ELEMENT *
handle_line_command (ELEMENT *current, char **line_inout,
- enum command_id cmd, int *status)
+ enum command_id cmd, enum command_id data_cmd,
+ int *status, ELEMENT **command_element)
{
- ELEMENT *misc = 0;
+ ELEMENT *command_e = 0;
char *line = *line_inout;
int arg_spec;
*status = STILL_MORE_TO_PROCESS;
/* Root commands (like @node) and @bye */
- if (command_data(cmd).flags & CF_root || cmd == CM_bye)
+ if (command_data(data_cmd).flags & CF_root || cmd == CM_bye)
{
ELEMENT *closed_elt; /* Not used */
current = close_commands (current, 0, &closed_elt, cmd);
@@ -293,19 +528,21 @@ handle_line_command (ELEMENT *current, char **line_inout,
}
}
- /* Look up information about this command ( skipline text
- line lineraw specific ). */
- arg_spec = command_data(cmd).data;
+ /* Look up information about this command
+ ( text line lineraw specific special ). */
+ arg_spec = command_data(data_cmd).data;
/* All the cases using the raw line.
- TODO: I don't understand what the difference is between these.
- LINE_skipline is used where the command takes no argument at all. */
- if (arg_spec == LINE_skipline || arg_spec == LINE_lineraw
- || arg_spec == LINE_special)
+ For some commands, the arguments are determined especially from the
+ raw line, for other the line is taken as is as argument, and possibly
+ later ignored for commands without arg.
+ */
+ if (arg_spec == LINE_lineraw)
{
ELEMENT *args = 0;
enum command_id equivalent_cmd = 0;
int has_comment = 0;
+ int special_arg = 0;
int ignored = 0;
if (cmd == CM_insertcopying)
@@ -330,12 +567,20 @@ handle_line_command (ELEMENT *current, char **line_inout,
if (!strchr (line, '\n'))
{
char *line2;
- SOURCE_INFO save_src_info;
+ SOURCE_INFO save_src_info;
- input_push_text (strdup (line), 0);
+ input_push_text (strdup (line), current_source_info.line_nr, 0, 0);
save_src_info = current_source_info;
- line2 = new_line ();
+ /* REMARK the source marks (mostly end of macro/value expansion) will
+ be associated to the previous element in current, as the command being
+ considered has not been added already, although the end of macro
+ expansion is located after the command opening. Wrongly placed
+ mark sources are unavoidable, as the line is not parsed as usual
+ and macro/value expansion happen here in advance and not while
+ the remaining of the line is parsed. */
+
+ line2 = new_line (current);
if (line2)
{
line = line2;
@@ -343,22 +588,13 @@ handle_line_command (ELEMENT *current, char **line_inout,
}
}
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
- if (arg_spec == LINE_skipline || arg_spec == LINE_lineraw)
- {
- ELEMENT *arg;
- args = new_element (ET_NONE);
- arg = new_element (ET_NONE);
- add_to_element_contents (args, arg);
- text_append (&arg->text, line);
- }
- else /* arg_spec == LINE_special */
- {
- args = parse_special_misc_command (line, cmd, &has_comment);
- add_extra_string (misc, "arg_line", strdup (line));
- }
+ args = parse_rawline_command (line, cmd,
+ &has_comment, &special_arg);
+ if (special_arg)
+ add_info_string_dup (command_e, "arg_line", line);
/* Handle @set txicodequoteundirected as an
alternative to @codequoteundirected. */
@@ -380,6 +616,8 @@ handle_line_command (ELEMENT *current, char **line_inout,
char *arg = 0;
ELEMENT *line_args;
ELEMENT *e;
+ ELEMENT *spaces_before = new_element (ET_NONE);
+ ELEMENT *spaces_after = new_element (ET_NONE);
if (cmd == CM_set)
arg = "on";
@@ -395,51 +633,49 @@ handle_line_command (ELEMENT *current, char **line_inout,
text_append (&e->text, arg);
add_to_element_contents (args, e);
- destroy_element_and_children (misc);
- misc = new_element (ET_NONE);
- misc->cmd = equivalent_cmd;
- misc->source_info = current_source_info;
+ destroy_element_and_children (command_e);
+ command_e = new_element (ET_NONE);
+ command_e->cmd = equivalent_cmd;
+ command_e->source_info = current_source_info;
line_args = new_element (ET_line_arg);
- add_to_element_args (misc, line_args);
- add_extra_misc_args (misc, "misc_args", args);
- add_extra_string_dup (misc, "spaces_before_argument", " ");
+ add_to_element_args (command_e, line_args);
+ add_extra_misc_args (command_e, "misc_args", args);
+ text_append (&spaces_before->text, " ");
+ add_info_element_oot (command_e, "spaces_before_argument", spaces_before);
- add_extra_string_dup (line_args, "spaces_after_argument", "\n");
+ text_append (&spaces_after->text, "\n");
+ add_info_element_oot (line_args, "spaces_after_argument",
+ spaces_after);
e = new_element (ET_NONE);
text_append (&e->text, arg);
add_to_element_contents (line_args, e);
- add_to_element_contents (current, misc);
+ add_to_element_contents (current, command_e);
}
else
{
int i;
if (!ignored)
{
- add_to_element_contents (current, misc);
+ add_to_element_contents (current, command_e);
for (i = 0; i < args->contents.number; i++)
{
- ELEMENT *misc_arg = new_element (ET_misc_arg);
- text_append_n (&misc_arg->text,
+ ELEMENT *rawline_arg = new_element (ET_rawline_arg);
+ text_append_n (&rawline_arg->text,
args->contents.list[i]->text.text,
args->contents.list[i]->text.end);
- add_to_element_args (misc, misc_arg);
+ add_to_element_args (command_e, rawline_arg);
}
- /* TODO: Could we have just set misc->args directly as args? */
- if (args->contents.number > 0 && arg_spec != LINE_skipline)
- add_extra_misc_args (misc, "misc_args", args);
- else
- destroy_element_and_children (args);
}
else
{
- destroy_element_and_children (misc);
- destroy_element_and_children (args);
- misc = 0;
+ destroy_element_and_children (command_e);
+ command_e = 0;
}
+ destroy_element_and_children (args);
}
if (cmd == CM_raisesections)
@@ -451,11 +687,16 @@ handle_line_command (ELEMENT *current, char **line_inout,
global_info.sections_level--;
}
- if (misc)
- register_global_command (misc);
+ if (command_e)
+ register_global_command (command_e);
- if (arg_spec != LINE_special || !has_comment)
- current = end_line (current);
+ /* This does nothing for the command being processed, as there is
+ no line context setup nor line_args, but it closes a line or block
+ line @-commands the raw line command is on. For c/comment
+ this corresponds to legitimate constructs, not for other raw line
+ commands.
+ */
+ current = end_line (current);
if (cmd == CM_bye)
{
@@ -473,36 +714,59 @@ handle_line_command (ELEMENT *current, char **line_inout,
{
ELEMENT *arg;
- /* text, line, or a number.
+ /* text, line, or specific.
(This includes handling of "@end", which is LINE_text.) */
- if (cmd == CM_item_LINE || cmd == CM_itemx)
+ if (cmd == CM_item || cmd == CM_itemx)
{
ELEMENT *parent;
if ((parent = item_line_parent (current)))
{
- debug ("ITEM_LINE");
+ debug ("ITEM LINE %s", command_name(cmd));
current = parent;
gather_previous_item (current, cmd);
}
else
{
line_error ("@%s outside of table or list",
- cmd == CM_item_LINE ? "item" : "itemx");
+ command_name(cmd));
current = begin_preformatted (current);
}
- misc = new_element (ET_NONE);
- misc->cmd = (cmd == CM_item_LINE) ? CM_item : CM_itemx;
- misc->source_info = current_source_info;
- add_to_element_contents (current, misc);
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ command_e->source_info = current_source_info;
+ add_to_element_contents (current, command_e);
}
else
{
/* Add to contents */
- misc = new_element (ET_NONE);
- misc->cmd = cmd;
- misc->source_info = current_source_info;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
+ command_e->source_info = current_source_info;
- if (cmd == CM_subentry)
+ if (cmd == CM_nodedescription)
+ {
+ if (current_node)
+ {
+ KEY_PAIR *k = lookup_extra (current_node, "node_description");
+ if (k && k->value)
+ {
+ ELEMENT *e_description = (ELEMENT *) k->value;
+ if (e_description->cmd == cmd)
+ line_warn ("multiple node @nodedescription");
+ else
+ /* silently replace nodedescriptionblock */
+ add_extra_element (current_node, "node_description",
+ command_e);
+ }
+ else
+ add_extra_element (current_node, "node_description",
+ command_e);
+ add_extra_element (command_e, "element_node", current_node);
+ }
+ else
+ line_warn ("@nodedescription outside of any node");
+ }
+ else if (cmd == CM_subentry)
{
long level = 1;
ELEMENT *parent = current->parent;
@@ -513,7 +777,7 @@ handle_line_command (ELEMENT *current, char **line_inout,
line_warn ("@subentry should only occur in an index entry");
}
- add_extra_element (parent, "subentry", misc);
+ add_extra_element (parent, "subentry", command_e);
if (parent->cmd == CM_subentry)
{
@@ -521,7 +785,7 @@ handle_line_command (ELEMENT *current, char **line_inout,
if (k && k->value)
level = (long) k->value + 1;
}
- add_extra_integer (misc, "level", level);
+ add_extra_integer (command_e, "level", level);
if (level > 2)
{
line_error
@@ -534,83 +798,110 @@ handle_line_command (ELEMENT *current, char **line_inout,
current = end_line (current);
}
- add_to_element_contents (current, misc);
+ add_to_element_contents (current, command_e);
- if (command_data(cmd).flags & CF_sectioning_heading)
+ if (command_data(data_cmd).flags & CF_sectioning_heading)
{
if (global_info.sections_level)
{
- add_extra_integer (misc, "sections_level",
+ add_extra_integer (command_e, "sections_level",
global_info.sections_level);
}
}
/* @def*x */
- if (command_data(cmd).flags & CF_def)
+ if (command_data(data_cmd).flags & CF_def)
{
enum command_id base_command;
- char *base_name;
- int base_len;
int after_paragraph;
+ int appropriate_command;
+ enum command_id cmdname;
char *val;
- /* Find the command with "x" stripped from the end, e.g.
- deffnx -> deffn. */
- base_name = command_name(cmd);
- add_extra_string_dup (misc, "original_def_cmdname", base_name);
-
- base_name = strdup (base_name);
- base_len = strlen (base_name);
- if (base_name[base_len - 1] != 'x')
- fatal ("no x at end of def command name");
- base_name[base_len - 1] = '\0';
- base_command = lookup_command (base_name);
- if (base_command == CM_NONE)
- fatal ("no def base command");
- add_extra_string (misc, "def_command", base_name);
-
- after_paragraph = check_no_text (current);
+ if (cmd == CM_defline || cmd == CM_deftypeline)
+ {
+ base_command = cmd;
+ add_extra_string_dup (command_e, "original_def_cmdname",
+ command_name(cmd));
+ add_extra_string_dup (command_e, "def_command",
+ command_name(cmd));
+ }
+ else
+ {
+ /* Find the command with "x" stripped from the end, e.g.
+ deffnx -> deffn. */
+
+ char *base_name;
+ int base_len;
+
+ base_name = command_name(cmd);
+ add_extra_string_dup (command_e, "original_def_cmdname",
+ base_name);
+ base_name = strdup (base_name);
+ base_len = strlen (base_name);
+ if (base_name[base_len - 1] != 'x')
+ fatal ("no x at end of def command name");
+ base_name[base_len - 1] = '\0';
+ base_command = lookup_command (base_name);
+ if (base_command == CM_NONE)
+ fatal ("no def base command");
+ add_extra_string (command_e, "def_command", base_name);
+ }
+
+ cmdname = current->cmd;
+ if (cmdname != CM_defblock)
+ after_paragraph = check_no_text (current);
+ else
+ after_paragraph = 0;
push_context (ct_def, cmd);
- misc->type = ET_def_line;
+ command_e->type = ET_def_line;
/* Check txidefnamenospace flag */
val = fetch_value ("txidefnamenospace");
if (val)
- add_extra_integer (misc, "omit_def_name_space", 1);
+ add_extra_integer (command_e, "omit_def_name_space", 1);
+
+ if (cmdname == base_command || cmdname == CM_defblock)
+ appropriate_command = 1;
+ else
+ appropriate_command = 0;
- if (current->cmd == base_command)
+ if (appropriate_command)
{
ELEMENT *e = pop_element_from_contents (current);
- /* e should be the same as misc */
+ /* e should be the same as command_e */
/* Gather an "inter_def_item" element. */
gather_def_item (current, cmd);
add_to_element_contents (current, e);
}
- if (current->cmd != base_command || after_paragraph)
+ if (!appropriate_command || after_paragraph)
{
- // error - deffnx not after deffn
+ /* error - deffnx not after deffn */
line_error ("must be after `@%s' to use `@%s'",
command_name(base_command),
command_name(cmd));
- add_extra_integer (misc, "not_after_command", 1);
+ add_extra_integer (command_e, "not_after_command", 1);
}
}
}
- /* change 'current' to its last child. This is ELEMENT *misc above. */
+ /* change 'current' to its last child. This is command_e. */
current = last_contents_child (current);
arg = new_element (ET_line_arg);
add_to_element_args (current, arg);
+ if (command_data(data_cmd).flags & CF_contain_basic_inline)
+ push_command (&nesting_context.basic_inline_stack_on_line, cmd);
+
/* LINE_specific commands arguments are handled in a specific way.
The only other line commands that have more than one argument is
node, so the following condition only applies to node */
- if (command_data (current->cmd).data != LINE_specific
- && command_data (current->cmd).args_number > 1)
+ if (arg_spec != LINE_specific
+ && command_data (data_cmd).args_number > 1)
{
counter_push (&count_remaining_args,
current,
- command_data (current->cmd).args_number - 1);
+ command_data (data_cmd).args_number - 1);
}
if (cmd == CM_author)
{
@@ -632,7 +923,7 @@ handle_line_command (ELEMENT *current, char **line_inout,
KEY_PAIR *k; ELEMENT *e;
k = lookup_extra (parent, "authors");
if (k)
- e = k->value;
+ e = (ELEMENT *) k->value;
else
{
e = new_element (ET_NONE);
@@ -656,27 +947,23 @@ handle_line_command (ELEMENT *current, char **line_inout,
/* add 'line' to context_stack. This will be the
case while we read the argument on this line. */
- if (!(command_data(cmd).flags & CF_def))
+ if (!(command_data(data_cmd).flags & CF_def))
push_context (ct_line, cmd);
- start_empty_line_after_command (current, &line, misc);
+ start_empty_line_after_command (current, &line, command_e);
}
- if (misc)
- register_global_command (misc);
+ if (command_e)
+ register_global_command (command_e);
if (cmd == CM_dircategory)
- add_to_contents_as_array (&global_info.dircategory_direntry, misc);
+ add_to_contents_as_array (&global_info.dircategory_direntry, command_e);
funexit:
*line_inout = line;
+ *command_element = command_e;
return current;
}
-
-struct expanded_format {
- char *format;
- int expandedp;
-};
-static struct expanded_format expanded_formats[] = {
+struct expanded_format expanded_formats[] = {
"html", 0,
"docbook", 0,
"plaintext", 1,
@@ -728,154 +1015,57 @@ format_expanded_p (char *format)
}
/* A command name has been read that starts a multiline block, which should
- end in @end <command name>. The block will be processed until
+ end in @end <command name>. The block will be processed until
"end_line_misc_line" in end_line.c processes the @end command. */
ELEMENT *
handle_block_command (ELEMENT *current, char **line_inout,
- enum command_id cmd, int *get_new_line)
+ enum command_id cmd, int *get_new_line,
+ ELEMENT **command_element)
{
char *line = *line_inout;
unsigned long flags = command_data(cmd).flags;
+ ELEMENT *block = 0;
/* New macro being defined. */
- if (cmd == CM_macro || cmd == CM_rmacro)
+ if (cmd == CM_macro || cmd == CM_rmacro || cmd == CM_linemacro)
{
- ELEMENT *macro;
- macro = parse_macro_command_line (cmd, &line, current);
- add_to_element_contents (current, macro);
- current = macro;
+ block = parse_macro_command_line (cmd, &line, current);
+ add_to_element_contents (current, block);
+ current = block;
/* A new line should be read immediately after this. */
line = strchr (line, '\0');
*get_new_line = 1;
goto funexit;
}
- else if (command_data(cmd).data == BLOCK_conditional)
- {
- int iftrue = 0; /* Whether the conditional is true. */
- if (cmd == CM_ifclear || cmd == CM_ifset
- || cmd == CM_ifcommanddefined || cmd == CM_ifcommandnotdefined)
- {
- char *p = line;
- p = line + strspn (line, whitespace_chars);
- if (!*p)
- line_error ("@%s requires a name", command_name(cmd));
- else
- {
- char *flag = read_flag_name (&p);
- if (!flag)
- goto bad_value;
- else
- {
- p += strspn (p, whitespace_chars);
- /* Check for a comment at the end of the line. */
- if (*p)
- {
- if (memcmp (p, "@c", 2) == 0)
- {
- p += 2;
- if (memcmp (p, "omment", 6) == 0)
- p += 7;
- if (*p && *p != '@' && !strchr (whitespace_chars, *p))
- goto bad_value; /* @c or @comment not terminated. */
- }
- else
- goto bad_value; /* Trailing characters on line. */
- }
- }
- if (1)
- {
- if (cmd == CM_ifclear || cmd == CM_ifset)
- {
- char *val = fetch_value (flag);
- if (val)
- iftrue = 1;
- if (cmd == CM_ifclear)
- iftrue = !iftrue;
- }
- else /* cmd == CM_ifcommanddefined
- || cmd == CM_ifcommandnotdefined */
- {
- enum command_id c = lookup_command (flag);
- if (c)
- iftrue = 1;
- if (cmd == CM_ifcommandnotdefined)
- iftrue = !iftrue;
- }
- }
- else if (0)
- {
- bad_value:
- line_error ("bad name for @%s", command_name(cmd));
- }
- free (flag);
- }
- }
- else if (!memcmp (command_name(cmd), "if", 2)) /* e.g. @ifhtml */
- {
- int i; char *p;
- /* Handle @if* and @ifnot* */
-
- p = command_name(cmd) + 2; /* After "if". */
- if (!memcmp (p, "not", 3))
- p += 3; /* After "not". */
- for (i = 0; i < sizeof (expanded_formats)/sizeof (*expanded_formats);
- i++)
- {
- if (!strcmp (p, expanded_formats[i].format))
- {
- iftrue = expanded_formats[i].expandedp;
- break;
- }
- }
- if (!memcmp (command_name(cmd), "ifnot", 5))
- iftrue = !iftrue;
- }
- else
- bug_message ("unknown conditional command @%s", command_name(cmd));
-
-
- /* If conditional true, push onto conditional stack. Otherwise
- open a new element (which we shall later remove, in
- process_remaining_on_line ("CLOSED conditional")). */
-
- debug ("CONDITIONAL %s %d", command_name(cmd), iftrue);
- if (iftrue)
- push_conditional_stack (cmd);
- else
- {
- /* Ignored. */
- ELEMENT *e;
- e = new_element (ET_NONE);
- e->cmd = cmd;
- add_to_element_contents (current, e);
- current = e;
- }
- line = strchr (line, '\0');
- *get_new_line = 1;
- goto funexit;
- }
else
{
- ELEMENT *block = 0;
ELEMENT *bla; /* block line arg element */
if (command_data(cmd).data == BLOCK_menu
&& (current->type == ET_menu_comment
|| current->type == ET_menu_entry_description))
{
- /* This is for @detailmenu within @menu */
- ELEMENT *menu = current->parent;
- if (current->contents.number == 0)
- destroy_element (pop_element_from_contents (menu));
-
- if (menu->type == ET_menu_entry)
- menu = menu->parent;
- current = menu;
+ /* This is, in general, caused by @detailmenu within @menu */
+ if (current->type == ET_menu_comment)
+ current = close_container(current);
+ else /* menu_entry_description */
+ {
+ current = close_container(current);
+ if (current->type == ET_menu_entry)
+ current = current->parent;
+ else
+ {
+ bug_message ("menu description parent not a menu_entry: %s",
+ element_type_name (current));
+ abort ();
+ }
+ }
}
if (flags & CF_def)
{
ELEMENT *def_line;
+ char *val;
push_context (ct_def, cmd);
block = new_element (ET_NONE);
block->cmd = cmd;
@@ -891,7 +1081,7 @@ handle_block_command (ELEMENT *current, char **line_inout,
add_extra_string_dup (current, "original_def_cmdname",
command_name(cmd));
/* Check txidefnamenospace flag */
- char *val = fetch_value ("txidefnamenospace");
+ val = fetch_value ("txidefnamenospace");
if (val)
add_extra_integer (current, "omit_def_name_space", 1);
}
@@ -915,13 +1105,7 @@ handle_block_command (ELEMENT *current, char **line_inout,
}
else if (command_data(cmd).data == BLOCK_region)
{
- if (current_region_cmd ())
- {
- line_error ("region %s inside region %s is not allowed",
- command_name(cmd),
- command_name(current_region_cmd ()));
- }
- push_region (block);
+ push_command (&nesting_context.regions_stack, cmd);
}
if (command_data(cmd).data == BLOCK_menu)
@@ -948,6 +1132,31 @@ handle_block_command (ELEMENT *current, char **line_inout,
}
}
+ if (cmd == CM_nodedescriptionblock)
+ {
+ if (current_node)
+ {
+ KEY_PAIR *k = lookup_extra (current_node, "node_long_description");
+ if (k && k->value)
+ line_warn ("multiple node @nodedescriptionblock");
+ else
+ {
+ KEY_PAIR *kn = lookup_extra (current_node, "node_description");
+
+ if (!kn || !kn->value)
+ add_extra_element (current_node, "node_description",
+ block);
+
+ add_extra_element (current_node, "node_long_description",
+ block);
+ }
+ add_extra_element (block, "element_node", current_node);
+ }
+ else
+ line_warn ("@nodedescriptionblock outside of any node");
+
+ }
+
if (cmd == CM_itemize || cmd == CM_enumerate)
counter_push (&count_items, current, 0);
@@ -970,6 +1179,8 @@ handle_block_command (ELEMENT *current, char **line_inout,
current = bla;
if (!(command_data(cmd).flags & CF_def))
push_context (ct_line, cmd);
+ if (command_data(cmd).flags & CF_contain_basic_inline)
+ push_command (&nesting_context.basic_inline_stack_block, cmd);
block->source_info = current_source_info;
register_global_command (block);
@@ -978,24 +1189,28 @@ handle_block_command (ELEMENT *current, char **line_inout,
funexit:
*line_inout = line;
+ *command_element = block;
return current;
}
ELEMENT *
-handle_brace_command (ELEMENT *current, char **line_inout, enum command_id cmd)
+handle_brace_command (ELEMENT *current, char **line_inout, enum command_id cmd,
+ ELEMENT **command_element)
{
char *line = *line_inout;
- ELEMENT *e;
+ ELEMENT *command_e;
+
+ debug ("OPEN BRACE @%s", command_name(cmd));
- e = new_element (ET_NONE);
- e->cmd = cmd;
+ command_e = new_element (ET_NONE);
+ command_e->cmd = cmd;
/* The line number information is only ever used for brace commands
if the command is given with braces, but it's easier just to always
store the information. */
- e->source_info = current_source_info;
+ command_e->source_info = current_source_info;
- add_to_element_contents (current, e);
+ add_to_element_contents (current, command_e);
if (cmd == CM_sortas)
{
@@ -1007,17 +1222,17 @@ handle_brace_command (ELEMENT *current, char **line_inout, enum command_id cmd)
}
}
- current = e;
+ current = command_e;
if (cmd == CM_click)
{
- add_extra_string_dup (e, "clickstyle", global_clickstyle);
+ add_extra_string_dup (command_e, "clickstyle", global_clickstyle);
}
else if (cmd == CM_kbd)
{
if (kbd_formatted_as_code(current))
{
- add_extra_integer (e, "code", 1);
+ add_extra_integer (command_e, "code", 1);
}
}
else if (command_data(cmd).flags & CF_INFOENCLOSE)
@@ -1025,12 +1240,13 @@ handle_brace_command (ELEMENT *current, char **line_inout, enum command_id cmd)
INFO_ENCLOSE *ie = lookup_infoenclose (cmd);
if (ie)
{
- add_extra_string_dup (e, "begin", ie->begin);
- add_extra_string_dup (e, "end", ie->end);
+ add_extra_string_dup (command_e, "begin", ie->begin);
+ add_extra_string_dup (command_e, "end", ie->end);
}
- e->type = ET_definfoenclose_command;
+ command_e->type = ET_definfoenclose_command;
}
*line_inout = line;
+ *command_element = command_e;
return current;
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.h
index 08673a2d5c..6dcc8254f9 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/handle_commands.h
@@ -5,15 +5,26 @@
#include "tree_types.h"
ELEMENT *handle_other_command (ELEMENT *current, char **line_inout,
- enum command_id cmd_id, int *status);
+ enum command_id cmd_id, int *status,
+ ELEMENT **command_element);
ELEMENT *handle_line_command (ELEMENT *current, char **line_inout,
- enum command_id cmd_id, int *status);
+ enum command_id cmd_id, enum command_id data_cmd,
+ int *status, ELEMENT **command_element);
ELEMENT *handle_block_command (ELEMENT *current, char **line_inout,
- enum command_id cmd_id, int *new_line);
+ enum command_id cmd_id, int *new_line,
+ ELEMENT **command_element);
ELEMENT *handle_brace_command (ELEMENT *current, char **line_inout,
- enum command_id cmd_id);
+ enum command_id cmd_id, ELEMENT **command_element);
int check_no_text (ELEMENT *current);
void clear_expanded_formats (void);
void add_expanded_format (char *format);
+
+struct expanded_format {
+ char *format;
+ int expandedp;
+};
+
+extern struct expanded_format expanded_formats[7];
+
#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.c
index 537bb833b8..706ae30616 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -71,7 +71,9 @@ add_index_command (char *cmdname, INDEX *idx)
{
enum command_id new = add_texinfo_command (cmdname);
user_defined_command_data[new & ~USER_COMMAND_BIT].flags
- = CF_line | CF_index_entry_command;
+ |= CF_line | CF_index_entry_command | CF_contain_basic_inline
+ /* | CF_close_paragraph */
+ | CF_no_paragraph;
user_defined_command_data[new & ~USER_COMMAND_BIT].data = LINE_line;
associate_command_to_index (new, idx);
}
@@ -115,10 +117,11 @@ index_by_name (char *name)
void
add_index (char *name, int in_code)
{
- INDEX *idx;
+ INDEX *idx = index_by_name (name);
char *cmdname;
- idx = add_index_internal (name, in_code);
+ if (!idx)
+ idx = add_index_internal (strdup (name), in_code);
/* For example, "rq" -> "rqindex". */
xasprintf (&cmdname, "%s%s", name, "index");
@@ -129,15 +132,6 @@ add_index (char *name, int in_code)
static void
wipe_index (INDEX *idx)
{
- int i;
- INDEX_ENTRY *ie;
- for (i = 0; i < idx->index_number; i++)
- {
- ie = &idx->index_entries[i];
- /* Destroy element if it is not in the main tree */
- if (ie->content && !ie->content->parent)
- destroy_element (ie->content);
- }
free (idx->name);
free (idx->index_entries);
}
@@ -261,24 +255,19 @@ typedef struct {
} INDEX_ENTRY_REF;
-/* INDEX_TYPE_COMMAND is used to determine which index to enter the entry in.
- INDEX_AT_COMMAND is the Texinfo @-command defining the index entry.
- CONTENT is an element whose contents represent the text of the
- index entry. CURRENT is the element in the main body of the manual that
- the index entry refers to.
-
- CONTENT_NORMALIZED would be "the index entry content, independent
- of the current language." */
+/* INDEX_TYPE_CMD is used to determine which index to enter the entry in.
+ index entry. ELEMENT is the element in the main body of the manual that
+ the index entry refers/belongs to.
+*/
void
-enter_index_entry (enum command_id index_type_command,
- enum command_id index_at_command,
- ELEMENT *current, ELEMENT *content)
+enter_index_entry (enum command_id index_type_cmd,
+ ELEMENT *element)
{
INDEX *idx;
INDEX_ENTRY *entry;
- KEY_PAIR *k;
+ TEXT ignored_chars;
- idx = index_of_command (index_type_command);
+ idx = index_of_command (index_type_cmd);
if (idx->index_number == idx->index_space)
{
idx->index_entries = realloc (idx->index_entries,
@@ -290,38 +279,50 @@ enter_index_entry (enum command_id index_type_command,
memset (entry, 0, sizeof (INDEX_ENTRY));
entry->index_name = idx->name;
- entry->index_at_command = index_at_command;
- entry->index_type_command = index_type_command;
- entry->index_prefix = idx->prefix;
- entry->content = content;
- entry->command = current;
- entry->number = idx->index_number;
- entry->ignored_chars = global_info.ignored_chars;
-
- k = lookup_extra (current, "sortas");
- if (k)
- entry->sortas = (char *) k->value;
-
- if (current_region ())
- entry->region = current_region ();
- else
- entry->node = current_node;
-
+ /* not needed, the position in the index is directly used
entry->number = idx->index_number;
+ */
+ entry->command = element;
+
+ /* Create ignored_chars string. */
+ text_init (&ignored_chars);
+ if (global_info.ignored_chars.backslash)
+ text_append (&ignored_chars, "\\");
+ if (global_info.ignored_chars.hyphen)
+ text_append (&ignored_chars, "-");
+ if (global_info.ignored_chars.lessthan)
+ text_append (&ignored_chars, "<");
+ if (global_info.ignored_chars.atsign)
+ text_append (&ignored_chars, "@");
+ if (ignored_chars.end > 0)
+ {
+ add_extra_string_dup (element, "index_ignore_chars", ignored_chars.text);
+ free (ignored_chars.text);
+ }
-#if 0
- /* This reference is not used in api.c when the Perl tree is output. */
+ /* index_entry is an array with two elements. Use
+ extra_misc_args to pass that information as an array */
{
- INDEX_ENTRY_REF *ier;
- ier = malloc (sizeof (INDEX_ENTRY_REF));
- ier->index = idx;
- ier->entry = idx->index_number - 1;
-
- add_extra_index_entry (current, "index_entry", ier);
+ ELEMENT *index_entry = new_element (ET_NONE);
+ ELEMENT *e = new_element (ET_NONE);
+ text_append (&e->text, idx->name);
+ add_to_element_contents (index_entry, e);
+ e = new_element (ET_NONE);
+ add_extra_integer (e, "integer", idx->index_number);
+ add_to_element_contents (index_entry, e);
+ add_extra_misc_args (element, "index_entry", index_entry);
}
-#endif
- if (!current_region () && !current_node && !current_section)
+ if (nesting_context.regions_stack.top > 0)
+ {
+ enum command_id region = top_command (&nesting_context.regions_stack);
+ add_extra_string_dup (element, "element_region", command_name (region));
+ }
+ else if (current_node)
+ add_extra_element (element, "element_node", current_node);
+
+ if (nesting_context.regions_stack.top == 0
+ && !current_node && !current_section)
line_warn ("entry for index `%s' outside of any node", idx->name);
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.h
index dc17890f39..1770f259e3 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/indices.h
@@ -11,9 +11,8 @@ void init_index_commands (void);
INDEX *index_by_name (char *name);
void add_index (char *name, int in_code);
INDEX *index_of_command (enum command_id cmd);
-void enter_index_entry (enum command_id index_type_command,
- enum command_id index_at_command, ELEMENT *current,
- ELEMENT *content);
+void enter_index_entry (enum command_id index_type_cmd,
+ ELEMENT *current);
INDEX *ultimate_index (INDEX *index);
void wipe_indices (void);
void set_non_ignored_space_in_index_before_command (ELEMENT *content);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.c
index c8730b4d6a..e4a4577b86 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,73 +23,126 @@
#include <sys/stat.h>
#include "errors.h"
+#include "debug.h"
#include "input.h"
#include "text.h"
#include "commands.h"
+#include "source_marks.h"
enum input_type { IN_file, IN_text };
-enum character_encoding {
- ce_latin1,
- ce_latin2,
- ce_latin15,
- ce_utf8,
- ce_shiftjis,
- ce_koi8r,
- ce_koi8u
-};
-
typedef struct {
enum input_type type;
FILE *file;
SOURCE_INFO source_info;
+ char *input_file_path; /* for IN_file type, the full input file path */
char *text; /* Input text to be parsed as Texinfo. */
char *ptext; /* How far we are through 'text'. Used to split 'text'
into lines. */
+ char *value_flag; /* value flag if the input text is a @value
+ expansion */
+ char *macro_name; /* macro name if the input text is a user-defined
+ macro expansion */
+ SOURCE_MARK *input_source_mark;
} INPUT;
static char *input_pushback_string;
-enum character_encoding input_encoding;
-
-static char *input_encoding_name;
static iconv_t reverse_iconv; /* used in encode_file_name */
-void
+typedef struct {
+ char *encoding_name;
+ iconv_t iconv;
+} ENCODING_CONVERSION;
+
+static ENCODING_CONVERSION *encodings_list = 0;
+int encoding_number = 0;
+int encoding_space = 0;
+char *global_input_encoding_name = 0;
+
+static ENCODING_CONVERSION *current_encoding_conversion = 0;
+
+/* ENCODING should always be lower cased */
+/* WARNING: it is very important for the first call to
+ set_input_encoding to be for "utf-8" as the codes assume
+ a conversion to UTF-8 in encodings_list[0]. */
+int
set_input_encoding (char *encoding)
{
- free (input_encoding_name); input_encoding_name = strdup (encoding);
+ int encoding_index = -1;
+ int encoding_set = 0;
+ char *conversion_encoding = encoding;
+
+ /* should correspond to
+ Texinfo::Common::encoding_name_conversion_map.
+ Thoughts on this mapping are available near
+ Texinfo::Common::encoding_name_conversion_map definition
+ */
+ if (!strcmp (encoding, "us-ascii"))
+ conversion_encoding = "iso-8859-1";
+
if (reverse_iconv)
{
iconv_close (reverse_iconv);
reverse_iconv = (iconv_t) 0;
}
- if (!strcasecmp (encoding, "utf-8"))
- input_encoding = ce_utf8;
- else if (!strcmp (encoding, "iso-8859-1")
- || !strcmp (encoding, "us-ascii"))
- input_encoding = ce_latin1;
- else if (!strcmp (encoding, "iso-8859-2"))
- input_encoding = ce_latin2;
- else if (!strcmp (encoding, "iso-8859-15"))
- input_encoding = ce_latin15;
- else if (!strcmp (encoding, "shift_jis"))
- input_encoding = ce_shiftjis;
- else if (!strcmp (encoding, "koi8-r"))
- input_encoding = ce_koi8r;
- else if (!strcmp (encoding, "koi8-u"))
- input_encoding = ce_koi8u;
+ if (!strcmp (encoding, "utf-8"))
+ {
+ if (encoding_number > 0)
+ encoding_index = 0;
+ }
+ else if (encoding_number > 1)
+ {
+ int i;
+ for (i = 1; i < encoding_number; i++)
+ {
+ if (!strcmp (encoding, encodings_list[i].encoding_name))
+ {
+ encoding_index = i;
+ break;
+ }
+ }
+ }
+
+ if (encoding_index == -1)
+ {
+ if (encoding_number >= encoding_space)
+ {
+ encodings_list = realloc (encodings_list,
+ (encoding_space += 3) * sizeof (ENCODING_CONVERSION));
+ }
+ encodings_list[encoding_number].encoding_name
+ = strdup (conversion_encoding);
+ /* Initialize conversions for the first time. iconv_open returns
+ (iconv_t) -1 on failure so these should only be called once. */
+ encodings_list[encoding_number].iconv
+ = iconv_open ("UTF-8", conversion_encoding);
+ encoding_index = encoding_number;
+ encoding_number++;
+ }
+
+ if (encodings_list[encoding_index].iconv == (iconv_t) -1)
+ current_encoding_conversion = 0;
else
- fprintf (stderr, "warning: unhandled encoding %s\n", encoding);
+ {
+ current_encoding_conversion = &encodings_list[encoding_index];
+ encoding_set = 1;
+ free (global_input_encoding_name);
+ global_input_encoding_name = strdup (encoding);
+ }
+
+ return encoding_set;
}
static INPUT *input_stack = 0;
int input_number = 0;
int input_space = 0;
+int macro_expansion_nr = 0;
+int value_expansion_nr = 0;
/* Current filename and line number. Used for reporting. */
SOURCE_INFO current_source_info;
@@ -101,8 +154,9 @@ SOURCE_INFO current_source_info;
Return value should not be freed by caller, and becomes invalid after
a subsequent call. */
+/* CURRENT is the current container that can be used for source marks. */
char *
-new_line (void)
+new_line (ELEMENT *current)
{
static TEXT t;
char *new = 0;
@@ -111,7 +165,7 @@ new_line (void)
while (1)
{
- new = next_text ();
+ new = next_text (current);
if (!new)
break;
text_append (&t, new);
@@ -128,14 +182,6 @@ new_line (void)
}
-static iconv_t iconv_from_latin1;
-static iconv_t iconv_from_latin2;
-static iconv_t iconv_from_latin15;
-static iconv_t iconv_from_shiftjis;
-static iconv_t iconv_from_koi8u;
-static iconv_t iconv_from_koi8r;
-static iconv_t iconv_validate_utf8;
-
/* Run iconv using text buffer as output buffer. */
size_t
text_buffer_iconv (TEXT *buf, iconv_t iconv_state,
@@ -168,7 +214,7 @@ encode_with_iconv (iconv_t our_iconv, char *s)
ICONV_CONST char *inptr; size_t bytes_left;
size_t iconv_ret;
- t.end = 0;
+ t.end = 0; /* reset internal TEXT buffer */
inptr = s;
bytes_left = strlen (s);
text_alloc (&t, 10);
@@ -211,10 +257,9 @@ encode_with_iconv (iconv_t our_iconv, char *s)
/* Return conversion of S according to input_encoding. This function
frees S. */
-static char *
+char *
convert_to_utf8 (char *s)
{
- iconv_t our_iconv = (iconv_t) -1;
char *ret;
/* Convert from @documentencoding to UTF-8.
@@ -224,49 +269,7 @@ convert_to_utf8 (char *s)
file, then we'd have to keep track of which strings needed the UTF-8 flag
and which didn't. */
- /* Initialize conversions for the first time. iconv_open returns
- (iconv_t) -1 on failure so these should only be called once. */
- if (iconv_validate_utf8 == (iconv_t) 0)
- iconv_validate_utf8 = iconv_open ("UTF-8", "UTF-8");
- if (iconv_from_latin1 == (iconv_t) 0)
- iconv_from_latin1 = iconv_open ("UTF-8", "ISO-8859-1");
- if (iconv_from_latin2 == (iconv_t) 0)
- iconv_from_latin2 = iconv_open ("UTF-8", "ISO-8859-2");
- if (iconv_from_latin15 == (iconv_t) 0)
- iconv_from_latin15 = iconv_open ("UTF-8", "ISO-8859-15");
- if (iconv_from_shiftjis == (iconv_t) 0)
- iconv_from_shiftjis = iconv_open ("UTF-8", "SHIFT-JIS");
- if (iconv_from_koi8r == (iconv_t) 0)
- iconv_from_koi8r = iconv_open ("UTF-8", "KOI8-R");
- if (iconv_from_koi8u == (iconv_t) 0)
- iconv_from_koi8u = iconv_open ("UTF-8", "KOI8-U");
-
- switch (input_encoding)
- {
- case ce_utf8:
- our_iconv = iconv_validate_utf8;
- break;
- case ce_latin1:
- our_iconv = iconv_from_latin1;
- break;
- case ce_latin2:
- our_iconv = iconv_from_latin2;
- break;
- case ce_latin15:
- our_iconv = iconv_from_latin15;
- break;
- case ce_shiftjis:
- our_iconv = iconv_from_shiftjis;
- break;
- case ce_koi8r:
- our_iconv = iconv_from_koi8r;
- break;
- case ce_koi8u:
- our_iconv = iconv_from_koi8u;
- break;
- }
-
- if (our_iconv == (iconv_t) -1)
+ if (current_encoding_conversion == 0)
{
/* In case the converter couldn't be initialised.
Danger: this will cause problems if the input is not in UTF-8 as
@@ -274,7 +277,7 @@ convert_to_utf8 (char *s)
return s;
}
- ret = encode_with_iconv (our_iconv, s);
+ ret = encode_with_iconv (current_encoding_conversion->iconv, s);
free (s);
return ret;
}
@@ -312,9 +315,12 @@ encode_file_name (char *filename)
}
else if (doc_encoding_for_input_file_name)
{
- if (input_encoding != ce_utf8 && input_encoding_name)
+ if (current_encoding_conversion
+ && strcmp (global_input_encoding_name, "utf-8"))
{
- reverse_iconv = iconv_open (input_encoding_name, "UTF-8");
+ char *conversion_encoding
+ = current_encoding_conversion->encoding_name;
+ reverse_iconv = iconv_open (conversion_encoding, "UTF-8");
}
}
else if (locale_encoding)
@@ -383,12 +389,15 @@ input_pushback (char *string)
}
/* Return value to be freed by caller. Return null if we are out of input. */
+/* CURRENT is the current container that can be used for source marks. */
char *
-next_text (void)
+next_text (ELEMENT *current)
{
ssize_t status;
char *line = 0;
- size_t n;
+ size_t n = 1;
+ /* Note: n needs to be a positive value, rather than 0, to work around
+ a bug in getline on MinGW. This appears to be allowed by POSIX. */
FILE *input_file;
if (input_pushback_string)
@@ -402,36 +411,40 @@ next_text (void)
while (input_number > 0)
{
/* Check for pending input. */
- INPUT *i = &input_stack[input_number - 1];
+ INPUT *input = &input_stack[input_number - 1];
- switch (i->type)
+ switch (input->type)
{
char *p, *new;
case IN_text:
- if (!*i->ptext)
- {
- /* End of text reached. */
- free (i->text);
- break;
- }
+ /*
+ debug_nonl ("IN_TEXT '"); debug_print_protected_string (input->ptext);
+ debug ("'");
+ */
+ if (!*input->ptext)
+ break;
/* Split off a line of input. */
- p = strchrnul (i->ptext, '\n');
- new = strndup (i->ptext, p - i->ptext + 1);
+ p = strchrnul (input->ptext, '\n');
+ new = strndup (input->ptext, p - input->ptext + 1);
if (*p)
- i->ptext = p + 1;
+ input->ptext = p + 1;
else
- i->ptext = p; /* The next time, we will pop the input source. */
+ input->ptext = p; /* The next time, we will pop the input source. */
+ /*
+ debug_nonl ("NEW IN_TEXT '"); debug_print_protected_string (new);
+ debug_nonl ("' next: '");
+ debug_print_protected_string (input->ptext); debug ("'");
+ */
+ if (!input->source_info.macro && !input->value_flag)
+ input->source_info.line_nr++;
- if (!i->source_info.macro)
- i->source_info.line_nr++;
-
- current_source_info = i->source_info;
+ current_source_info = input->source_info;
return new;
break;
case IN_file:
- input_file = input_stack[input_number - 1].file;
+ input_file = input->file;
status = getline (&line, &n, input_file);
if (status != -1)
{
@@ -448,10 +461,27 @@ next_text (void)
/* Strip off a comment. */
comment = strchr (line, '\x7F');
if (comment)
- *comment = '\0';
+ {
+ SOURCE_MARK *source_mark
+ = new_source_mark (SM_type_delcomment);
+ *comment = '\0';
+ if (*(comment+1) != '\0')
+ source_mark->line = convert_to_utf8 (strdup (comment+1));
+ else
+ source_mark->line = 0;
+ input_push_text(strdup (""),
+ input->source_info.line_nr, 0, 0);
+ /* if the input_stack was reallocated in input_push_text,
+ the input pointer for the file may have been freed and
+ re-created at another address. Therefore we reset it.
+ input_number has been increased too, so the input file
+ being processed is now at input_number - 2 */
+ input = &input_stack[input_number - 2];
+ set_input_source_mark (source_mark);
+ }
- i->source_info.line_nr++;
- current_source_info = i->source_info;
+ input->source_info.line_nr++;
+ current_source_info = input->source_info;
return convert_to_utf8 (line);
}
@@ -461,29 +491,93 @@ next_text (void)
fatal ("unknown input source type");
}
- /* Top input source failed. Pop it and try the next one. */
-
- if (input_stack[input_number - 1].type == IN_file)
+ /* Top input source failed. Close, pop, and try the next one. */
+ if (input->type == IN_file)
{
- FILE *file = input_stack[input_number - 1].file;
+ FILE *file = input->file;
if (file != stdin)
{
- if (fclose (input_stack[input_number - 1].file) == EOF)
- fprintf (stderr, "error on closing %s: %s",
- input_stack[input_number - 1].source_info.file_name,
- strerror (errno));
+ if (fclose (input->file) == EOF)
+ {
+ /* convert to UTF-8 for the messages, to have character strings in perl
+ that will be encoded on output to the locale encoding.
+ Done differently for the file names in source_info
+ which are byte strings and end up unmodified in output error
+ messages.
+ */
+ char *decoded_file_name
+ = convert_to_utf8 (strdup(input->input_file_path));
+ line_warn ("error on closing %s: %s",
+ decoded_file_name,
+ strerror (errno));
+ free (decoded_file_name);
+ }
+ }
+ }
+ else
+ {
+ /* End of text reached. */
+ free (input->text);
+ if (input->value_flag)
+ {
+ value_expansion_nr--;
+ free (input->value_flag);
+ }
+ else if (input->macro_name)
+ {
+ macro_expansion_nr--;
}
}
+ if (input->input_source_mark)
+ {
+ if (current)
+ {
+ SOURCE_MARK *input_source_mark = input->input_source_mark;
+ SOURCE_MARK *end_include_source_mark;
+ if (input_source_mark->type == SM_type_delcomment)
+ end_include_source_mark = input_source_mark;
+ else
+ {
+ end_include_source_mark
+ = new_source_mark (input_source_mark->type);
+ end_include_source_mark->counter = input_source_mark->counter;
+ end_include_source_mark->status = SM_status_end;
+ }
+ register_source_mark (current, end_include_source_mark);
+ }
+ else
+ debug ("INPUT MARK MISSED");
+
+ input->input_source_mark = 0;
+ }
input_number--;
}
+ debug ("INPUT FINISHED");
return 0;
}
+/* Store TEXT as a source for Texinfo content. TEXT should be a UTF-8
+ string. TEXT will be later free'd and must be allocated on the heap.
+ MACRO_NAME is the name of the macro expanded as text. It should only be
+ given if this is the text corresponds to a new macro expansion.
+ If already within a macro expansion, but not from a macro expansion
+ (from a value expansion, for instance), the macro name will be taken
+ from the input stack.
+ VALUE_FLAG is the name of the value flag expanded as text.
+ VALUE_FLAG will be later free'd, but not MACRO_NAME.
+ */
void
-input_push (char *text, char *macro, char *filename, int line_number)
+input_push_text (char *text, int line_number, char *macro_name,
+ char *value_flag)
{
+ char *filename = 0;
+ char *in_macro = 0;
+
+ if (!text)
+ return;
+
if (input_number == input_space)
{
input_space++; input_space *= 1.5;
@@ -494,17 +588,37 @@ input_push (char *text, char *macro, char *filename, int line_number)
input_stack[input_number].type = IN_text;
input_stack[input_number].file = 0;
+ input_stack[input_number].input_file_path = 0;
input_stack[input_number].text = text;
input_stack[input_number].ptext = text;
- if (!macro)
+ if (input_number > 0)
+ {
+ filename = input_stack[input_number - 1].source_info.file_name;
+ /* context macro expansion */
+ in_macro = input_stack[input_number - 1].source_info.macro;
+ }
+ if (macro_name) {
+ /* new macro expansion */
+ in_macro = macro_name;
+ }
+ if (!in_macro && !value_flag)
line_number--;
input_stack[input_number].source_info.line_nr = line_number;
input_stack[input_number].source_info.file_name = save_string (filename);
- input_stack[input_number].source_info.macro = save_string (macro);
+ input_stack[input_number].source_info.macro = save_string (in_macro);
+ input_stack[input_number].macro_name = save_string (macro_name);
+ input_stack[input_number].value_flag = value_flag;
+ input_stack[input_number].input_source_mark = 0;
input_number++;
}
+void
+set_input_source_mark (SOURCE_MARK *source_mark)
+{
+ input_stack[input_number - 1].input_source_mark = source_mark;
+}
+
/* For filenames and macro names, it is possible that they won't be referenced
in the line number of any element. It would be too much work to keep track,
so just keep them all here, and free them all together at the end. */
@@ -544,33 +658,6 @@ free_small_strings (void)
small_strings_num = 0;
}
-
-/* Store TEXT as a source for Texinfo content. TEXT should be a UTF-8
- string. TEXT will be later free'd and must be allocated on the heap.
- MACRO is the name of a macro that the text came from. */
-void
-input_push_text (char *text, char *macro)
-{
- if (text)
- {
- char *filename = 0;
- if (input_number > 0)
- {
- filename = input_stack[input_number - 1].source_info.file_name;
- }
- input_push (text, macro, filename, current_source_info.line_nr);
- }
-}
-
-/* Used in tests - like input_push_text, but the lines from the text have
- line numbers. */
-void
-input_push_text_with_line_nos (char *text, int starting)
-{
- input_push (text, 0, 0, starting);
- input_stack[input_number - 1].type = IN_text;
-}
-
void
input_reset_input_stack (void)
{
@@ -589,6 +676,29 @@ input_reset_input_stack (void)
}
}
input_number = 0;
+ macro_expansion_nr = 0;
+ value_expansion_nr = 0;
+}
+
+void
+reset_encoding_list (void)
+{
+ int i;
+ /* never reset the utf-8 encoding in position 0 */
+ if (encoding_number > 1)
+ {
+ for (i = 1; i < encoding_number; i++)
+ {
+ free (encodings_list[i].encoding_name);
+ if (encodings_list[i].iconv != (iconv_t) -1)
+ iconv_close (encodings_list[i].iconv);
+ }
+ encoding_number = 1;
+ }
+ /* could be named global_encoding_conversion and reset in wipe_global_info,
+ but we prefer to keep it static as long as it is only used in one
+ file */
+ current_encoding_conversion = 0;
}
int
@@ -672,6 +782,7 @@ input_push_file (char *filename)
{
FILE *stream = 0;
char *p, *q;
+ char *base_filename;
if (!strcmp (filename, "-"))
stream = stdin;
@@ -698,15 +809,17 @@ input_push_file (char *filename)
q = strchr (q + 1, '/');
}
if (p)
- filename = save_string (p+1);
+ base_filename = save_string (p+1);
else
- filename = save_string (filename);
+ base_filename = save_string (filename);
input_stack[input_number].type = IN_file;
input_stack[input_number].file = stream;
- input_stack[input_number].source_info.file_name = filename;
+ input_stack[input_number].input_file_path = filename;
+ input_stack[input_number].source_info.file_name = base_filename;
input_stack[input_number].source_info.line_nr = 0;
input_stack[input_number].source_info.macro = 0;
+ input_stack[input_number].input_source_mark = 0;
input_stack[input_number].text = 0;
input_stack[input_number].ptext = 0;
input_number++;
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.h
index 9cf758e030..e6738ed661 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/input.h
@@ -4,23 +4,25 @@
#include "tree_types.h"
-char *new_line (void);
-char *next_text (void);
+char *new_line (ELEMENT *current);
+char *next_text (ELEMENT *current);
void save_line_directive (int line_nr, char *filename);
-void input_push (char *text, char *macro, char *filename, int line_number);
-void input_push_text (char *line, char *macro);
-void input_push_text_with_line_nos (char *text, int starting);
+void input_push_text (char *text, int line_number, char *macro_name,
+ char *value_flag);
int input_push_file (char *filename);
void input_pushback (char *line);
+void set_input_source_mark (SOURCE_MARK *source_mark);
void input_reset_input_stack (void);
+void reset_encoding_list (void);
int expanding_macro (char *macro);
int top_file_index (void);
char *locate_include_file (char *filename);
char *encode_file_name (char *filename);
-void set_input_encoding (char *encoding);
+char *convert_to_utf8 (char *s);
+int set_input_encoding (char *encoding);
void add_include_directory (char *filename);
void clear_include_directories (void);
@@ -30,9 +32,12 @@ void free_small_strings (void);
extern SOURCE_INFO current_source_info;
extern int input_number;
+extern int macro_expansion_nr;
+extern int value_expansion_nr;
extern int doc_encoding_for_input_file_name;
extern char *input_file_name_encoding;
+extern char *global_input_encoding_name;
extern char *locale_encoding;
void set_input_file_name_encoding (char *value);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.c
index 8d3090f1a6..17b469959d 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,35 +14,35 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
+#include <string.h>
+
#include "parser.h"
#include "convert.h"
+#include "source_marks.h"
#include "labels.h"
-/* Array of recorded labels. */
-/* If looking through this array turns out to be slow, we might have to replace
- it with some kind of hash table implementation. */
-LABEL *labels_list = 0;
+/* Array of recorded elements with labels. */
+ELEMENT **target_elements_list = 0;
size_t labels_number = 0;
size_t labels_space = 0;
-/* Register a label, that is something that may be the target of a reference
- and must be unique in the document. Corresponds to @node, @anchor, and
- second arg of @float. */
+/* Register a target element associated to a label that may be the target of
+ a reference and must be unique in the document. Corresponds to @node,
+ @anchor, and @float (float label corresponds to the second argument). */
void
-register_label (ELEMENT *current, ELEMENT *label)
+register_label (ELEMENT *target_element)
{
+ /* register the element in the list. */
if (labels_number == labels_space)
{
labels_space += 1;
labels_space *= 1.5;
- labels_list = realloc (labels_list, labels_space * sizeof (LABEL));
- if (!labels_list)
+ target_elements_list = realloc (target_elements_list,
+ labels_space * sizeof (ELEMENT *));
+ if (!target_elements_list)
fatal ("realloc failed");
}
- labels_list[labels_number++].target = current;
-
- if (label)
- add_extra_contents (current, "node_content", label);
+ target_elements_list[labels_number++] = target_element;
}
void
@@ -50,8 +50,306 @@ reset_labels (void)
{
labels_number = 0;
}
+
+void
+check_register_target_element_label (ELEMENT *label_element,
+ ELEMENT *target_element)
+{
+ if (label_element)
+ {
+ /* check that the label used as an anchor for link target has no
+ external manual part */
+ NODE_SPEC_EXTRA *label_info = parse_node_manual (label_element, 0);
+ if (label_info && label_info->manual_content)
+ {
+ /* show contents only to avoid leading/trailing spaces */
+ char *texi = convert_contents_to_texinfo (label_element);
+ line_error ("syntax for an external node used for `%s'", texi);
+ free (texi);
+ }
+ destroy_node_spec (label_info);
+ }
+ register_label (target_element);
+}
+
+/* NODE->contents is the Texinfo for the specification of a node. This
+ function sets two fields on the returned object:
+
+ manual_content - Texinfo tree for a manual name extracted from the
+ node specification.
+ node_content - Texinfo tree for the node name on its own
+
+ Objects returned from this function are used as an 'extra' key in
+ the element for elements linking to nodes (such as @*ref,
+ menu_entry_node or node direction arguments). In that case
+ modify_node is set to 1 and the node contents are modified in-place to
+ hold the same elements as the returned objects.
+
+ This function is also used for elements that are targets of links (@node and
+ @anchor first argument, float second argument) mainly to check that
+ the syntax for an external node is not used. In that case modify_node
+ is set to 0 and the node is not modified, and added elements are
+ collected in a third field of the returned object,
+ out_of_tree_elements - elements collected in manual_content or
+ node_content and not in the node
+ */
+
+NODE_SPEC_EXTRA *
+parse_node_manual (ELEMENT *node, int modify_node)
+{
+ NODE_SPEC_EXTRA *result;
+ ELEMENT *node_content = 0;
+ int idx = 0; /* index into node->contents */
+
+ result = malloc (sizeof (NODE_SPEC_EXTRA));
+ result->manual_content = result->node_content = 0;
+ /* if not modifying the tree, and there is a manual name, the elements
+ added for the manual name and for the node content that are based
+ on texts from tree elements are not anywhere in the tree.
+ They are collected in result->out_of_tree_element to be freed later.
+ These elements correspond to the text after the first manual name
+ opening brace and text before and after the closing manual name brace */
+ result->out_of_tree_elements = 0;
+
+ /* If the content starts with a '(', try to get a manual name. */
+ if (node->contents.number > 0 && node->contents.list[0]->text.end > 0
+ && node->contents.list[0]->text.text[0] == '(')
+ {
+ ELEMENT *manual, *first;
+ ELEMENT *new_first = 0;
+ ELEMENT *opening_brace = 0;
+ char *opening_bracket, *closing_bracket;
+
+ /* Handle nested parentheses in the manual name, for whatever reason. */
+ int bracket_count = 1; /* Number of ( seen minus number of ) seen. */
+
+ manual = new_element (ET_NONE);
+
+ /* If the first contents element is "(" followed by more text, split
+ the leading "(" into its own element. */
+ first = node->contents.list[0];
+ if (first->text.end > 1)
+ {
+ if (modify_node)
+ {
+ opening_brace = new_element (0);
+ text_append_n (&opening_brace->text, "(", 1);
+ }
+ new_first = new_element (0);
+ text_append_n (&new_first->text, first->text.text +1, first->text.end -1);
+ }
+ else
+ {
+ /* first element is "(", keep it */
+ idx++;
+ }
+
+ for (; idx < node->contents.number; idx++)
+ {
+ ELEMENT *e;
+ char *p, *q;
+
+ if (idx == 0)
+ e = new_first;
+ else
+ e = node->contents.list[idx];
+
+ if (e->text.end == 0)
+ {
+ /* Put this element in the manual contents. */
+ add_to_contents_as_array (manual, e);
+ continue;
+ }
+ p = e->text.text;
+ while (p < e->text.text + e->text.end
+ && bracket_count > 0)
+ {
+ opening_bracket = strchr (p, '(');
+ closing_bracket = strchr (p, ')');
+ if (!opening_bracket && !closing_bracket)
+ {
+ break;
+ }
+ else if (opening_bracket && !closing_bracket)
+ {
+ bracket_count++;
+ p = opening_bracket + 1;
+ }
+ else if (!opening_bracket && closing_bracket)
+ {
+ bracket_count--;
+ p = closing_bracket + 1;
+ }
+ else if (opening_bracket < closing_bracket)
+ {
+ bracket_count++;
+ p = opening_bracket + 1;
+ }
+ else if (opening_bracket > closing_bracket)
+ {
+ bracket_count--;
+ p = closing_bracket + 1;
+ }
+ }
+
+ if (bracket_count > 0)
+ add_to_contents_as_array (manual, e);
+ else /* end of filename component */
+ {
+ size_t current_position = 0;
+ /* At this point, we are sure that there is a manual part,
+ so the pending removal/addition of elements at the beginning
+ of the manual can proceed (if modify_node). */
+ /* Also, split the element in two, putting the part before the ")"
+ in the manual name, leaving the part afterwards for the
+ node name. */
+ if (modify_node)
+ {
+ if (opening_brace)
+ {
+ /* remove the original first element and prepend the
+ split "(" and text elements */
+ remove_from_contents (node, 0); /* remove first element */
+ insert_into_contents (node, new_first, 0);
+ insert_into_contents (node, opening_brace, 0);
+ idx++;
+ if (first->source_mark_list.number > 0)
+ {
+ size_t current_position
+ = relocate_source_marks (&(first->source_mark_list),
+ opening_brace, 0,
+ count_convert_u8 (opening_brace->text.text));
+ relocate_source_marks (&(first->source_mark_list),
+ new_first, current_position,
+ count_convert_u8 (new_first->text.text));
+ }
+ destroy_element (first);
+ }
+ remove_from_contents (node, idx); /* Remove current element e
+ with closing brace from the tree. */
+ }
+ else
+ {
+ /* collect elements out of tree */
+ result->out_of_tree_elements = calloc (3, sizeof (ELEMENT *));
+ if (new_first)
+ result->out_of_tree_elements[0] = new_first;
+ }
+ p--; /* point at ) */
+ if (p > e->text.text)
+ {
+ /* text before ), part of the manual name */
+ ELEMENT *last_manual_element = new_element (ET_NONE);
+ text_append_n (&last_manual_element->text, e->text.text,
+ p - e->text.text);
+ add_to_contents_as_array (manual, last_manual_element);
+ if (modify_node)
+ {
+ insert_into_contents (node, last_manual_element, idx++);
+ current_position
+ = relocate_source_marks (&(e->source_mark_list),
+ last_manual_element,
+ current_position,
+ count_convert_u8 (last_manual_element->text.text));
+ }
+ else
+ result->out_of_tree_elements[1] = last_manual_element;
+ }
+
+ if (modify_node)
+ {
+ ELEMENT *closing_brace = new_element (0);
+ text_append_n (&closing_brace->text, ")", 1);
+ insert_into_contents (node, closing_brace, idx++);
+ current_position
+ = relocate_source_marks (&(e->source_mark_list),
+ closing_brace,
+ current_position,
+ count_convert_u8 (closing_brace->text.text));
+ }
+
+ /* Skip ')' and any following whitespace.
+ Note that we don't manage to skip any multibyte
+ UTF-8 space characters here. */
+ p++;
+ q = p + strspn (p, whitespace_chars);
+ if (q > p && modify_node)
+ {
+ ELEMENT *spaces_element = new_element (0);
+ text_append_n (&spaces_element->text, p, q - p);
+ insert_into_contents (node, spaces_element, idx++);
+ current_position
+ = relocate_source_marks (&(e->source_mark_list),
+ spaces_element,
+ current_position,
+ count_convert_u8 (spaces_element->text.text));
+ }
+
+ p = q;
+ if (*p)
+ {
+ /* text after ), part of the node name. */
+ ELEMENT *leading_node_content = new_element (ET_NONE);
+ text_append_n (&leading_node_content->text, p,
+ e->text.text + e->text.end - p);
+ /* start node_content */
+ node_content = new_element (0);
+ add_to_contents_as_array (node_content, leading_node_content);
+ if (modify_node)
+ {
+ insert_into_contents (node, leading_node_content, idx);
+ current_position
+ = relocate_source_marks (&(e->source_mark_list),
+ leading_node_content,
+ current_position,
+ count_convert_u8 (leading_node_content->text.text));
+ }
+ else
+ result->out_of_tree_elements[2] = leading_node_content;
+ idx++;
+ }
+ if (modify_node)
+ destroy_element (e);
+ break;
+ }
+ } /* for */
+
+ if (bracket_count == 0)
+ result->manual_content = manual;
+ else /* Unbalanced parentheses, consider that there is no manual
+ afterall. So far the node has not been modified, so the
+ only thing that needs to be done is to remove the manual
+ element and the elements allocated for the beginning of
+ the manual, and start over */
+ {
+ destroy_element (manual);
+ if (new_first)
+ destroy_element (new_first);
+ if (opening_brace)
+ destroy_element (opening_brace);
+ idx = 0; /* Back to the start, and consider the whole thing
+ as a node name. */
+ }
+ }
+
+ /* If anything left, it is part of the node name. */
+ if (idx < node->contents.number)
+ {
+ if (!node_content)
+ node_content = new_element (0);
+ insert_slice_into_contents (node_content, node_content->contents.number,
+ node, idx, node->contents.number);
+ }
+
+ if (node_content)
+ result->node_content = node_content;
+
+ return result;
+}
+
+
ELEMENT **internal_xref_list = 0;
size_t internal_xref_number = 0;
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.h
index 66624c56b0..7528192cd2 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/labels.h
@@ -1,7 +1,7 @@
/* labels.h - declarations for labels.c */
#ifndef LABELS_H
#define LABELS_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,24 +18,19 @@
#include "tree_types.h"
-/* Information about a possible target of a cross-reference, often a node. */
-typedef struct {
- /* Pointer to the element for the command defining this label, usually a
- node element. FIXME: I'm not sure if we actualy need to get to the
- target - much of the use of the labels_information is to check that
- references are to real places. */
- ELEMENT *target;
-} LABEL;
-
-extern LABEL *labels_list;
+extern ELEMENT **target_elements_list;
extern size_t labels_number;
-void register_label (ELEMENT *current, ELEMENT *label);
void reset_labels (void);
+void check_register_target_element_label (ELEMENT *label_element,
+ ELEMENT *target_element);
+
+
+
+NODE_SPEC_EXTRA *parse_node_manual (ELEMENT *node, int modify_node);
extern ELEMENT **internal_xref_list;
extern size_t internal_xref_number;
-extern size_t internal_xref_space;
void remember_internal_xref (ELEMENT *element);
void reset_internal_xrefs (void);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.c
index e2b65432b1..44596cbd18 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,12 +17,18 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <stdio.h>
#include "parser.h"
+#include "debug.h"
#include "tree.h"
#include "text.h"
#include "input.h"
#include "convert.h"
+#include "source_marks.h"
+#include "macro.h"
+
+COUNTER count_toplevel_braces;
static MACRO *macro_list;
static size_t macro_number;
@@ -31,30 +37,54 @@ static size_t macro_space;
/* Macro definition. */
+MACRO *
+lookup_macro_and_slot (enum command_id cmd, size_t *free_slot)
+{
+ int i;
+ if (free_slot)
+ *free_slot = 0;
+
+ for (i = 0; i < macro_number; i++)
+ {
+ if (macro_list[i].cmd == cmd)
+ return &macro_list[i];
+ if (free_slot && !*free_slot && macro_list[i].cmd == 0)
+ *free_slot = i;
+ }
+ return 0;
+}
+
void
new_macro (char *name, ELEMENT *macro)
{
enum command_id new;
MACRO *m = 0;
- ELEMENT tmp;
+ size_t free_slot = 0;
/* Check for an existing definition first for us to overwrite. */
new = lookup_command (name);
if (new)
- m = lookup_macro (new);
+ m = lookup_macro_and_slot (new, &free_slot);
if (!m)
{
- if (macro_number == macro_space)
+ size_t macro_index;
+ if (free_slot)
+ macro_index = free_slot;
+ else
{
- macro_list = realloc (macro_list,
- (macro_space += 5) * sizeof (MACRO));
- if (!macro_list)
- fatal ("realloc failed");
+ if (macro_number == macro_space)
+ {
+ macro_list = realloc (macro_list,
+ (macro_space += 5) * sizeof (MACRO));
+ if (!macro_list)
+ fatal ("realloc failed");
+ }
+ macro_index = macro_number;
+ macro_number++;
}
new = add_texinfo_command (name);
- m = &macro_list[macro_number];
+ m = &macro_list[macro_index];
m->cmd = new;
- macro_number++;
new &= ~USER_COMMAND_BIT;
user_defined_command_data[new].flags |= CF_MACRO;
}
@@ -66,9 +96,7 @@ new_macro (char *name, ELEMENT *macro)
m->macro_name = strdup (name);
m->element = macro;
- memset (&tmp, 0, sizeof (ELEMENT));
- tmp.contents = macro->contents;
- m->macrobody = convert_to_texinfo (&tmp);
+ m->macrobody = convert_contents_to_texinfo (macro);
}
/* CMD will be either CM_macro or CM_rmacro. Read the line defining a macro's
@@ -87,26 +115,29 @@ parse_macro_command_line (enum command_id cmd, char **line_inout,
macro->cmd = cmd;
macro->source_info = current_source_info;
- add_extra_string (macro, "arg_line", strdup (line));
- /* Note this extra value isn't used much, so it might be possible
- to get rid of it. */
+ add_info_string_dup (macro, "arg_line", line);
line += strspn (line, whitespace_chars);
name = read_command_name (&line);
- if (*line && *line != '{' && !strchr (whitespace_chars, *line))
+ if (!name)
{
- line_error ("bad name for @%s", command_name (cmd));
+ line_error ("@%s requires a name", command_name (cmd));
add_extra_integer (macro, "invalid_syntax", 1);
return macro;
}
- else if (!name)
+
+ if (*line && *line != '{' && *line != '@'
+ && !strchr (whitespace_chars, *line))
{
- line_error ("@%s requires a name", command_name (cmd));
+ line_error ("bad name for @%s", command_name (cmd));
add_extra_integer (macro, "invalid_syntax", 1);
+ free (name);
return macro;
}
+ debug ("MACRO @%s %s", command_name (cmd), name);
+
macro_name = new_element (ET_macro_name);
text_append (&macro_name->text, name);
free (name);
@@ -173,12 +204,12 @@ parse_macro_command_line (enum command_id cmd, char **line_inout,
char *p;
for (p = args_ptr; p < q2; p++)
{
- if (!isalnum (*p) && *p != '_' && *p != '-')
+ if (!isascii_alnum (*p) && *p != '_' && *p != '-')
{
- char c = *q2; *q2 = 0;
+ char saved = *q2; *q2 = 0;
line_error ("bad or empty @%s formal argument: %s",
command_name(cmd), args_ptr);
- *q2 = c;
+ *q2 = saved;
add_extra_integer (macro, "invalid_syntax", 1);
break;
}
@@ -194,13 +225,20 @@ parse_macro_command_line (enum command_id cmd, char **line_inout,
index++;
}
-check_trailing:
+ check_trailing:
line = args_ptr;
line += strspn (line, whitespace_chars);
if (*line && *line != '@')
{
+ char *argument_str = strdup (line);
+ /* remove new line for the message */
+ char *end_line = strchr (argument_str, '\n');
+
+ if (end_line)
+ *end_line = '\0';
line_error ("bad syntax for @%s argument: %s",
- command_name(cmd), line);
+ command_name(cmd), argument_str);
+ free (argument_str);
add_extra_integer (macro, "invalid_syntax", 1);
}
//line += strlen (line); /* Discard rest of line. */
@@ -236,26 +274,57 @@ lookup_macro_parameter (char *name, ELEMENT *macro)
return -1;
}
-/* LINE points the first non-whitespace character after the opening brace in a
- macro invocation. CMD is the command identifier of the macro command.
- Return array of the arguments. Return value to be freed by caller. */
-char **
-expand_macro_arguments (ELEMENT *macro, char **line_inout, enum command_id cmd)
+/* not done by _close_container as argument is in args and not in
+ contents. */
+/* Currently unused */
+ELEMENT *
+remove_empty_arg (ELEMENT *argument)
+{
+ ELEMENT *current = close_container (argument);
+ if (is_container_empty (argument)
+ && argument->source_mark_list.number == 0)
+ {
+ ELEMENT *last_child = last_args_child (current);
+ if (last_child == argument)
+ destroy_element (pop_element_from_args (current));
+ }
+ return current;
+}
+
+/* LINE points the opening brace in a macro invocation. CMD is the command
+ identifier of the macro command. Return array of the arguments. Return
+ value to be freed by caller. */
+void
+expand_macro_arguments (ELEMENT *macro, char **line_inout, enum command_id cmd,
+ ELEMENT *current)
{
char *line = *line_inout;
char *pline = line;
- TEXT arg;
+ TEXT *arg;
int braces_level = 1;
int args_total;
+ int whitespaces_len;
+ ELEMENT *argument = new_element (ET_brace_command_arg);
+ ELEMENT *argument_content = new_element (ET_NONE);
- char **arg_list = 0;
- size_t arg_number = 0;
- size_t arg_space = 0;
+ add_to_element_args (current, argument);
+ text_append_n (&argument_content->text, "", 0);
+ add_to_element_contents (argument, argument_content);
+ arg = &(argument_content->text);
- arg_list = malloc (sizeof (char *));
args_total = macro->args.number - 1;
- text_init (&arg);
+ /* *pline is '{', advance past the open brace, start at braces_level = 1 */
+ pline++;
+ whitespaces_len = strspn (pline, whitespace_chars);
+ if (whitespaces_len > 0)
+ {
+ ELEMENT *spaces_element = new_element (ET_NONE);
+ text_append_n (&spaces_element->text, pline, whitespaces_len);
+ add_info_element_oot (current, "spaces_before_argument",
+ spaces_element);
+ pline += whitespaces_len;
+ }
while (braces_level > 0)
{
@@ -267,114 +336,327 @@ expand_macro_arguments (ELEMENT *macro, char **line_inout, enum command_id cmd)
if (!*sep)
{
debug ("MACRO ARG end of line");
- text_append (&arg, pline);
- line = new_line ();
+ text_append (arg, pline);
+ line = new_line (argument);
if (!line)
{
- line_error ("@%s missing closing brace", command_name(cmd));
+ line_error ("@%s missing closing brace", command_name (cmd));
+ remove_empty_content (argument);
line = "\n";
- free (arg.text);
goto funexit;
}
pline = line;
continue;
}
- text_append_n (&arg, pline, sep - pline);
+ text_append_n (arg, pline, sep - pline);
switch (*sep)
{
case '\\':
if (!strchr ("\\{},", sep[1]))
- text_append_n (&arg, sep, 1);
+ text_append_n (arg, sep, 1);
if (sep[1])
{
- text_append_n (&arg, &sep[1], 1);
+ text_append_n (arg, &sep[1], 1);
pline = sep + 2;
+ if (sep[1] == ',')
+ line_warn ("use %s instead of %s in macro arg",
+ "@comma{}", "\\,");
}
else
pline = sep + 1;
break;
case '{':
braces_level++;
- text_append_n (&arg, sep, 1);
+ text_append_n (arg, sep, 1);
pline = sep + 1;
break;
case '}':
braces_level--;
if (braces_level > 0)
- {
- text_append_n (&arg, sep, 1);
- pline = sep + 1;
- break;
- }
-
- /* Fall through to add argument. */
+ text_append_n (arg, sep, 1);
+ else
+ /* end of arguments */
+ remove_empty_content (argument);
+ pline = sep + 1;
+ break;
case ',':
+ pline = sep + 1;
if (braces_level > 1)
+ text_append_n (arg, sep, 1);
+ else
{
- text_append_n (&arg, sep, 1);
- pline = sep + 1;
- break;
+ if (current->args.number < args_total)
+ {
+ char *p = pline;
+
+ remove_empty_content (argument);
+
+ /* new argument */
+ argument = new_element (ET_brace_command_arg);
+ argument_content = new_element (ET_NONE);
+ add_to_element_args (current, argument);
+ text_append_n (&argument_content->text, "", 0);
+ add_to_element_contents (argument, argument_content);
+ arg = &(argument_content->text);
+ pline += strspn (pline, whitespace_chars);
+ if (pline - p)
+ {
+ ELEMENT *spaces_element = new_element (ET_NONE);
+ text_append_n (&spaces_element->text, p, pline - p);
+ add_info_element_oot (argument, "spaces_before_argument",
+ spaces_element);
+ }
+ debug ("MACRO NEW ARG");
+ }
+ else
+ /* too many args */
+ {
+ if (args_total != 1)
+ line_error ("macro `%s' called with too many args",
+ command_name(cmd));
+ text_append_n (arg, sep, 1);
+ }
}
+ break;
+ }
+ }
+
+ line = pline;
+
+ if (args_total == 0
+ && (current->args.number > 1
+ || current->args.list[0]->contents.number > 0))
+ {
+ line_error
+ ("macro `%s' declared without argument called with an argument",
+ command_name(cmd));
+ }
+ debug ("END MACRO ARGS EXPANSION");
+
+funexit:
+ *line_inout = line;
+}
+
+void
+set_toplevel_braces_nr (COUNTER *counter, ELEMENT* element)
+{
+ int toplevel_braces_nr = counter_value (counter,
+ element);
+ if (toplevel_braces_nr)
+ add_extra_integer (element,
+ "toplevel_braces_nr",
+ toplevel_braces_nr);
+ counter_pop (counter);
+}
+
+void
+expand_linemacro_arguments (ELEMENT *macro, char **line_inout,
+ enum command_id cmd, ELEMENT *current)
+{
+ char *line = *line_inout;
+ char *pline = line;
+ TEXT *arg;
+ int braces_level = 0;
+ int args_total;
+ int spaces_nr;
+ int i;
+ ELEMENT *argument = new_element (ET_NONE);
+ ELEMENT *argument_content = new_element (ET_NONE);
+ counter_push (&count_toplevel_braces, argument_content, 0);
+
+ add_to_element_args (current, argument);
+ text_append_n (&argument_content->text, "", 0);
+ add_to_element_contents (argument, argument_content);
+ arg = &(argument_content->text);
+
+ spaces_nr = strspn (pline, whitespace_chars_except_newline);
+ if (spaces_nr)
+ {
+ ELEMENT *spaces_element = new_element (ET_NONE);
+ text_append_n (&spaces_element->text, line, spaces_nr);
+ add_info_element_oot (argument, "spaces_before_argument",
+ spaces_element);
+
+ pline += spaces_nr;
+ }
+
+ args_total = macro->args.number - 1;
+
+ while (1)
+ {
+ char *sep;
+
+ sep = pline + strcspn (pline, linecommand_expansion_delimiters);
+ if (!*sep)
+ {
+ debug_nonl ("LINEMACRO ARGS no separator %d '", braces_level);
+ debug_print_protected_string (pline); debug ("'");
+ if (braces_level > 0)
+ {
+ text_append (arg, pline);
- // check for too many args
- if (*sep == '}' || arg_number < args_total - 1)
+ line = new_line (argument);
+ if (!line)
+ {
+ line_error ("@%s missing closing brace", command_name (cmd));
+ line = "";
+ goto funexit;
+ }
+ }
+ else
{
- /* Add the last argument read to the list. */
- if (arg_number == arg_space)
+ int text_len = strcspn (pline, "\n");
+ line = pline + text_len;
+ text_append_n (arg, pline, text_len);
+ if (! *line)
{
- arg_list = realloc (arg_list,
- (1+(arg_space += 5)) * sizeof (char *));
- /* Include space for terminating null element. */
- if (!arg_list)
- fatal ("realloc failed");
+ /* happens when @ protects the end of line, at the very end
+ of a text fragment and with macro expansion */
+ line = new_line (argument);
+ if (!line)
+ {
+ debug ("LINEMACRO ARGS end no EOL");
+ line = "";
+ goto funexit;
+ }
}
- if (arg.space > 0)
- arg_list[arg_number++] = arg.text;
else
- arg_list[arg_number++] = strdup ("");
- text_init (&arg);
+ {
+ /* end of macro call with an end of line */
+ goto funexit;
+ }
+ }
+ pline = line;
+ continue;
+ }
+
+ text_append_n (arg, pline, sep - pline);
- debug ("MACRO NEW ARG");
- pline = sep + 1;
+ switch (*sep)
+ {
+ int single_char;
+ char *command;
+ int whitespaces_len;
+ case '@':
+ pline = sep + 1;
+ command = parse_command_name (&pline, &single_char);
+ if (command)
+ {
+ enum command_id cmd = lookup_command (command);
+ if (braces_level <= 0 && cmd
+ && (cmd == CM_comment || cmd == CM_c))
+ {
+ line = sep;
+ goto funexit;
+ }
+ text_append_n (arg, sep, 1);
+ text_append (arg, command);
+ if (cmd && (command_data(cmd).flags & CF_brace)
+ && strchr (whitespace_chars, *pline)
+ && ((command_flags(current) & CF_accent)
+ || conf.ignore_space_after_braced_command_name))
+ {
+ int whitespaces_len = strspn (pline, whitespace_chars);
+ text_append_n (arg, pline, whitespaces_len);
+ pline += whitespaces_len;
+ }
+ free (command);
+ }
+ else
+ {
+ text_append_n (arg, sep, 1);
+ }
+ break;
+ case '{':
+ braces_level++;
+ text_append_n (arg, sep, 1);
+ pline = sep + 1;
+ break;
+ case '}':
+ braces_level--;
+ text_append_n (arg, sep, 1);
+ pline = sep + 1;
+ if (braces_level == 0)
+ counter_inc (&count_toplevel_braces);
+ break;
+ /* spaces */
+ default:
+ pline = sep;
+ whitespaces_len = strspn (pline, whitespace_chars_except_newline);
- if (*sep == ',')
- pline += strspn (pline, whitespace_chars);
+ if (braces_level > 0
+ || current->args.number >= args_total)
+ {
+ text_append_n (arg, pline, whitespaces_len);
}
else
{
- if (args_total != 1)
- line_error ("macro `%s' called with too many args",
- command_name(cmd));
- text_append_n (&arg, ",", 1);
- pline = sep + 1;
+ ELEMENT *spaces_element = new_element (ET_NONE);
+
+ set_toplevel_braces_nr (&count_toplevel_braces,
+ argument_content);
+
+ argument = new_element (ET_NONE);
+ argument_content = new_element (ET_NONE);
+ counter_push (&count_toplevel_braces, argument_content, 0);
+
+ add_to_element_args (current, argument);
+ text_append_n (&argument_content->text, "", 0);
+ add_to_element_contents (argument, argument_content);
+ arg = &(argument_content->text);
+
+ text_append_n (&spaces_element->text, pline,
+ whitespaces_len);
+ add_info_element_oot (argument, "spaces_before_argument",
+ spaces_element);
+ debug ("LINEMACRO NEW ARG");
}
+ pline += whitespaces_len;
break;
}
}
- debug ("END MACRO ARGS EXPANSION");
- line = pline;
-
- if (args_total == 0 && arg_number > 0
- && arg_list[0] && *arg_list[0])
+ funexit:
+ set_toplevel_braces_nr (&count_toplevel_braces,
+ argument_content);
+ for (i = 0; i < current->args.number; i++)
{
- line_error
- ("macro `%s' declared without argument called with an argument",
- command_name(cmd));
+ ELEMENT *argument_content = current->args.list[i]->contents.list[0];
+ KEY_PAIR *k = lookup_extra (argument_content, "toplevel_braces_nr");
+ if (k)
+ {
+ if ((intptr_t) k->value == 1)
+ {
+ int text_len = strlen(argument_content->text.text);
+ if (argument_content->text.text[0] == '{'
+ && argument_content->text.text[text_len -1] == '}')
+ {
+ char *braced_text = strdup (argument_content->text.text);
+ debug_nonl ("TURN to bracketed %d ", i);
+ debug_print_element (argument_content, 0); debug ("");
+
+ text_reset (&argument_content->text);
+ text_append_n (&argument_content->text,
+ braced_text+1, text_len -2);
+ free(braced_text);
+ argument_content->type = ET_bracketed_linemacro_arg;
+ }
+ }
+
+ k->key = "";
+ k->type = extra_deleted;
+ }
}
+ debug ("END LINEMACRO ARGS EXPANSION");
-funexit:
*line_inout = line;
- arg_list[arg_number] = 0;
- return arg_list;
}
-
-/* ARGUMENTS are the arguments used in the macro invocation. EXPANDED gets the
- result of the expansion. */
-static void
-expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
+/* ARGUMENTS element holds the arguments used in the macro invocation.
+ EXPANDED gets the result of the expansion. */
+void
+expand_macro_body (MACRO *macro_record, ELEMENT *arguments, TEXT *expanded)
{
int pos; /* Index into arguments. */
ELEMENT *macro;
@@ -384,7 +666,7 @@ expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
macro = macro_record->element;
macrobody = macro_record->macrobody;
-
+
/* Initialize TEXT object. */
expanded->end = 0;
@@ -402,7 +684,7 @@ expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
bs = strchrnul (ptext, '\\');
text_append_n (expanded, ptext, bs - ptext);
if (!*bs)
- break; /* End of line. */
+ break; /* End of body. */
ptext = bs + 1;
if (*ptext == '\\')
@@ -415,7 +697,8 @@ expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
bs = strchr (ptext, '\\');
if (!bs)
{
- /* malformed input - unpaired backslash */
+ /* unpaired backslash */
+ text_append (expanded, ptext);
return;
}
@@ -432,8 +715,14 @@ expand_macro_body (MACRO *macro_record, char *arguments[], TEXT *expanded)
}
else
{
- if (arguments && arguments[pos])
- text_append (expanded, arguments[pos]);
+ if (arguments && pos < arguments->args.number)
+ {
+ ELEMENT *argument = args_child_by_index (arguments, pos);
+ if (argument->contents.number > 0)
+ text_append (expanded,
+ last_contents_child (
+ args_child_by_index (arguments, pos))->text.text);
+ }
}
*bs = '\\';
ptext = bs + 1;
@@ -455,22 +744,29 @@ lookup_macro (enum command_id cmd)
}
void
-delete_macro (char *name)
+unset_macro_record (MACRO *m)
{
- enum command_id cmd;
- MACRO *m;
- cmd = lookup_command (name);
- if (!cmd)
- return;
- m = lookup_macro (cmd);
if (!m)
return;
+
m->cmd = 0;
free (m->macro_name);
- m->macro_name = strdup ("");
+ m->macro_name = 0;
free (m->macrobody);
m->macrobody = 0;
m->element = 0;
+}
+
+void
+delete_macro (char *name)
+{
+ enum command_id cmd;
+ MACRO *m;
+ cmd = lookup_command (name);
+ if (!cmd)
+ return;
+ m = lookup_macro (cmd);
+ unset_macro_record (m);
remove_texinfo_command (cmd);
}
@@ -487,7 +783,9 @@ wipe_macros (void)
macro_number = 0;
}
-/* Handle macro expansion. CMD is the macro command. */
+/* Handle macro expansion. CMD is the macro command.
+ The returned element is an out of tree element holding the call
+ arguments also associated to the macro expansion source mark */
ELEMENT *
handle_macro (ELEMENT *current, char **line_inout, enum command_id cmd)
{
@@ -495,8 +793,11 @@ handle_macro (ELEMENT *current, char **line_inout, enum command_id cmd)
MACRO *macro_record;
ELEMENT *macro;
TEXT expanded;
- char **arguments = 0;
+ char *expanded_macro_text;
int args_number;
+ SOURCE_MARK *macro_source_mark;
+ ELEMENT *macro_call_element = new_element (ET_NONE);
+ int error = 0;
line = *line_inout;
text_init (&expanded);
@@ -506,100 +807,186 @@ handle_macro (ELEMENT *current, char **line_inout, enum command_id cmd)
fatal ("no macro record");
macro = macro_record->element;
- /* Get number of args. - 1 for the macro name. */
- args_number = macro->args.number - 1;
+ if (macro->cmd == CM_macro)
+ macro_call_element->type = ET_macro_call;
+ else if (macro->cmd == CM_rmacro)
+ macro_call_element->type = ET_rmacro_call;
+ else if (macro->cmd == CM_linemacro)
+ macro_call_element->type = ET_linemacro_call;
+
+ add_info_string_dup (macro_call_element, "command_name", command_name(cmd));
+
+ /* It is important to check for expansion before the expansion and
+ not after, as during the expansion, the text may go past the
+ call. In particular for user defined linemacro which generally
+ get the final new line from following text.
+ */
+
+ macro_expansion_nr++;
+ debug ("MACRO EXPANSION NUMBER %d %s", macro_expansion_nr, command_name(cmd));
- p = line + strspn (line, whitespace_chars);
- if (*p == '{')
+ if (macro->cmd != CM_rmacro)
{
- line = p;
- line++;
- line += strspn (line, whitespace_chars);
- arguments = expand_macro_arguments (macro, &line, cmd);
+ if (expanding_macro (command_name(cmd)))
+ {
+ line_error ("recursive call of macro %s is not allowed; "
+ "use @rmacro if needed", command_name(cmd));
+ error = 1;
+ }
}
- /* Warning depending on the number of arguments this macro
- is supposed to take. */
- else if (args_number != 1)
+
+ if (conf.max_macro_call_nesting
+ && macro_expansion_nr > conf.max_macro_call_nesting)
{
- if (args_number > 1)
- line_warn ("@%s defined with zero or more than one argument should "
- "be invoked with {}", command_name(cmd));
- /* As agreed on the bug-texinfo mailing list, no warn when zero
- arg and not called with {}. */
+ line_warn (
+ "macro call nested too deeply "
+ "(set MAX_MACRO_CALL_NESTING to override; current value %d)",
+ conf.max_macro_call_nesting);
+ error = 1;
+ }
+
+ if (macro->cmd == CM_linemacro)
+ {
+ expand_linemacro_arguments (macro, &line, cmd, macro_call_element);
}
else
{
- char *p;
- /* If it takes a single line of input, and we don't have a full line of
- input already, call new_line. */
- if (!strchr (line, '\n'))
- {
- line = new_line ();
- if (!line)
- line = "";
- }
- line += strspn (line, whitespace_chars_except_newline);
+ /* Get number of args. - 1 for the macro name. */
+ args_number = macro->args.number - 1;
- arguments = malloc (sizeof (char *) * 2);
- arguments[0] = strdup (line);
- arguments[1] = 0;
+ p = line + strspn (line, whitespace_chars);
+ if (*p == '{')
+ {
+ if (p - line > 0)
+ {
+ ELEMENT *spaces_element = new_element (ET_NONE);
+ text_append_n (&spaces_element->text, line, p - line);
+ add_info_element_oot (macro_call_element, "spaces_after_cmd_before_arg",
+ spaces_element);
- p = strchr (arguments[0], '\n');
- if (p)
+ }
+ line = p;
+ expand_macro_arguments (macro, &line, cmd, macro_call_element);
+ }
+ /* Warning depending on the number of arguments this macro
+ is supposed to take. */
+ else if (args_number != 1)
{
- *p = '\0';
- line = "\n";
+ if (args_number > 1)
+ line_warn ("@%s defined with zero or more than one argument should "
+ "be invoked with {}", command_name(cmd));
+ /* As agreed on the bug-texinfo mailing list, no warn when zero
+ arg and not called with {}. */
}
- }
-
- expand_macro_body (macro_record, arguments, &expanded);
- debug ("MACROBODY: %s||||||", expanded.text);
+ else
+ {
+ ELEMENT *arg_elt = new_element (ET_line_arg);
+ add_to_element_args (macro_call_element, arg_elt);
- if (expanded.end > 0 && expanded.text[expanded.end - 1] == '\n')
- expanded.text[--expanded.end] = '\0';
+ while (1)
+ {
+ if (*line == '\0')
+ {
+ /* If it takes a single line of input, and we don't have a
+ full line of input already, call new_line. */
+ line = new_line (arg_elt);
+ if (!line)
+ {
+ line = "";
+ break;
+ }
+ }
+ else
+ {
+ int leading_spaces_added = 0;
+ if (arg_elt->contents.number == 0)
+ {
+ int leading_spaces_nr = strspn (line,
+ whitespace_chars_except_newline);
+ if (leading_spaces_nr)
+ {
+ ELEMENT *internal_space
+ = new_element (ET_internal_spaces_before_argument);
+ text_append_n (&internal_space->text, line,
+ leading_spaces_nr);
+ add_extra_element (internal_space,
+ "spaces_associated_command",
+ macro_call_element);
+ add_to_element_contents (arg_elt, internal_space);
+
+ line += leading_spaces_nr;
+
+ leading_spaces_added = 1;
+ }
+ }
+ if (! leading_spaces_added)
+ {
+ char *p = strchr (line, '\n');
+ if (!p)
+ {
+ arg_elt = merge_text (arg_elt, line, 0);
+ line += strlen(line);
+ }
+ else
+ {
+ *p = '\0';
+ arg_elt = merge_text (arg_elt, line, 0);
+ line = "\n";
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
- if (input_number >= 1000)
+ if (error)
{
- line_warn (
- "macro call nested too deeply "
- "(set MAX_NESTED_MACROS to override; current value %d)", 1000);
+ macro_expansion_nr--;
+ destroy_element_and_children (macro_call_element);
+ macro_call_element = 0;
goto funexit;
- /* TODO: actually check MAX_NESTED_MACROS? */
}
- if (macro->cmd == CM_macro)
- {
- if (expanding_macro (command_name(cmd)))
- {
- line_error ("recursive call of macro %s is not allowed; "
- "use @rmacro if needed", command_name(cmd));
- expanded.text[0] = '\0';
- expanded.end = 0;
- }
- }
+ expand_macro_body (macro_record, macro_call_element, &expanded);
- /* Free arguments. */
- if (arguments)
+ if (expanded.text)
{
- char **s = arguments;
- while (*s)
- {
- free (*s);
- s++;
- }
- free (arguments);
+ if (expanded.text[expanded.end - 1] == '\n')
+ expanded.text[--expanded.end] = '\0';
+ expanded_macro_text = expanded.text;
}
+ else
+ /* we want to always have a text for the source mark */
+ expanded_macro_text = strdup ("");
- // 3958 Pop macro stack
+ debug ("MACROBODY: %s||||||", expanded_macro_text);
+
+ if (macro->cmd == CM_linemacro)
+ macro_source_mark = new_source_mark (SM_type_linemacro_expansion);
+ else
+ macro_source_mark = new_source_mark (SM_type_macro_expansion);
+ macro_source_mark->status = SM_status_start;
+ macro_source_mark->element = macro_call_element;
+ register_source_mark (current, macro_source_mark);
+
+ /* first put the line that was interrupted by the macro call
+ on the input pending text stack */
+ input_push_text (strdup (line), current_source_info.line_nr, 0, 0);
/* Put expansion in front of the current line. */
- input_push_text (strdup (line), 0);
+ input_push_text (expanded_macro_text, current_source_info.line_nr,
+ command_name(cmd), 0);
+
+ set_input_source_mark (macro_source_mark);
+
+ /* not really important as line is ignored by the caller if there
+ was no macro expansion error */
line = strchr (line, '\0');
- input_push_text (expanded.text, command_name(cmd));
-funexit:
+ funexit:
*line_inout = line;
- return current;
+ return macro_call_element;
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.h
index 784a3ca497..b9607f7329 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/macro.h
@@ -1,7 +1,7 @@
/* macro.h - declarations for macro.c */
#ifndef MACRO_H
#define MACRO_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,6 +37,9 @@ ELEMENT *parse_macro_command_line (enum command_id, char **line_inout,
ELEMENT *handle_macro (ELEMENT *current, char **line_inout,
enum command_id cmd_id);
void delete_macro (char *name);
+void unset_macro_record (MACRO *m);
+void expand_macro_body (MACRO *macro_record, ELEMENT *arguments,
+ TEXT *expanded);
MACRO *lookup_macro (enum command_id cmd);
void wipe_macros (void);
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/menus.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/menus.c
index 394f2edf5b..8b142d14c1 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/menus.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/menus.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,25 +18,26 @@
#include <string.h>
#include "parser.h"
+#include "debug.h"
#include "input.h"
#include "text.h"
#include "convert.h"
#include "labels.h"
+#include "source_marks.h"
-/* Save 'menu_entry_name' 'menu_entry_node', and 'menu_entry_description'
- extra keys on the top-level @menu element. */
-void
+/* Save 'menu_entry_node' extra keys. */
+ELEMENT *
register_extra_menu_entry_information (ELEMENT *current)
{
int i;
+ ELEMENT *menu_entry_node = 0;
- for (i = 0; i < current->args.number; i++)
+ for (i = 0; i < current->contents.number; i++)
{
- ELEMENT *arg = current->args.list[i];
+ ELEMENT *arg = current->contents.list[i];
if (arg->type == ET_menu_entry_name)
{
- add_extra_element (current, "menu_entry_name", arg);
if (arg->contents.number == 0)
{
char *texi = convert_to_texinfo (current);
@@ -50,7 +51,7 @@ register_extra_menu_entry_information (ELEMENT *current)
isolate_last_space (arg);
- parsed_entry_node = parse_node_manual (arg);
+ parsed_entry_node = parse_node_manual (arg, 1);
if (!parsed_entry_node->manual_content
&& !parsed_entry_node->node_content)
{
@@ -58,28 +59,37 @@ register_extra_menu_entry_information (ELEMENT *current)
line_error ("empty node name in menu entry");
}
else
- add_extra_node_spec (current, "menu_entry_node",
- parsed_entry_node);
- }
- else if (arg->type == ET_menu_entry_description)
- {
- add_extra_element (current, "menu_entry_description", arg);
+ {
+ menu_entry_node = arg;
+ if (parsed_entry_node->node_content)
+ add_extra_contents (arg, "node_content",
+ parsed_entry_node->node_content);
+ if (parsed_entry_node->manual_content)
+ add_extra_contents (arg, "manual_content",
+ parsed_entry_node->manual_content);
+ }
+ free (parsed_entry_node);
}
}
+ return menu_entry_node;
}
-/* Process the destination of the menu entry, and start a menu entry
+/* Process the destination of the menu entry, and start a menu entry
description. */
ELEMENT *
enter_menu_entry_node (ELEMENT *current)
{
ELEMENT *description, *preformatted;
+ ELEMENT *menu_entry_node;
- description = new_element (ET_menu_entry_description);
- add_to_element_args (current, description);
- register_extra_menu_entry_information (current);
current->source_info = current_source_info;
- remember_internal_xref (current);
+
+ menu_entry_node = register_extra_menu_entry_information (current);
+ if (menu_entry_node)
+ remember_internal_xref (menu_entry_node);
+
+ description = new_element (ET_menu_entry_description);
+ add_to_element_contents (current, description);
current = description;
preformatted = new_element (ET_preformatted);
@@ -88,10 +98,10 @@ enter_menu_entry_node (ELEMENT *current)
return current;
}
-/* Called from 'process_remaining_on_line' in parser.c. Return 1 if we find
+/* Called from 'process_remaining_on_line' in parser.c. Return 1 if we find
menu syntax to process, otherwise return 0. */
int
-handle_menu (ELEMENT **current_inout, char **line_inout)
+handle_menu_entry_separators (ELEMENT **current_inout, char **line_inout)
{
ELEMENT *current = *current_inout;
char *line = *line_inout;
@@ -103,7 +113,8 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
&& (current->parent->type == ET_menu_comment
|| current->parent->type == ET_menu_entry_description)
&& current->contents.number > 0
- && last_contents_child(current)->type == ET_empty_line)
+ && last_contents_child(current)->type == ET_empty_line
+ && last_contents_child(current)->text.end == 0)
{
ELEMENT *star;
@@ -123,47 +134,44 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
&& last_contents_child(current)->type == ET_internal_menu_star)
{
ELEMENT *menu_entry, *leading_text, *entry_name;
+ ELEMENT *menu_star_element;
int leading_spaces;
debug ("MENU ENTRY (certainly)");
- leading_spaces = strspn (line, whitespace_chars);
- destroy_element (pop_element_from_contents (current));
+ /* this is the menu star collected previously */
+ menu_star_element = pop_element_from_contents (current);
+
+ leading_spaces = strspn (line, whitespace_chars);
if (current->type == ET_preformatted
&& current->parent->type == ET_menu_comment)
{
- ELEMENT *menu = current->parent->parent;
-
- /* Remove an empty ET_preformatted, and an empty ET_menu_comment. */
- if (current->contents.number == 0)
- {
- pop_element_from_contents (current->parent);
- if (current->parent->contents.number == 0)
- {
- pop_element_from_contents (menu);
- destroy_element (current->parent);
- }
- destroy_element (current);
- }
-
- current = menu;
+ /* Close ET_preformatted, and ET_menu_comment. */
+ current = close_container (current);
+ current = close_container (current);
}
else
{
/* current should be ET_preformatted,
1st parent ET_menu_entry_description,
2nd parent ET_menu_entry,
- 3rd parent @menu. */
- current = current->parent->parent->parent;
+ 3rd parent @menu.
+ Close current, 1st and 2nd parent (which cannot be empty) */
+ current = close_container (current);
+ current = close_container (current);
+ current = close_container (current);
}
menu_entry = new_element (ET_menu_entry);
leading_text = new_element (ET_menu_entry_leading_text);
+ /* transfer source marks from removed menu star to leading text */
+ transfer_source_marks (menu_star_element, leading_text);
+ destroy_element (menu_star_element);
entry_name = new_element (ET_menu_entry_name);
add_to_element_contents (current, menu_entry);
- add_to_element_args (menu_entry, leading_text);
- add_to_element_args (menu_entry, entry_name);
+ add_to_element_contents (menu_entry, leading_text);
+ add_to_element_contents (menu_entry, entry_name);
current = entry_name;
text_append (&leading_text->text, "*");
@@ -174,20 +182,42 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
else if (current->contents.number > 0
&& last_contents_child(current)->type == ET_internal_menu_star)
{
- debug ("ABORT MENU STAR");
+ debug_nonl ("ABORT MENU STAR before: ");
+ debug_print_protected_string (line); debug ("");
+
last_contents_child(current)->type = ET_NONE;
}
- /* After a separator in a menu (which would have been added in
- handle_separator in separator.c). */
- else if (current->args.number > 0
- && last_args_child (current)->type == ET_menu_entry_separator)
+ /* After a separator in a menu, end of menu entry node or menu entry name
+ (. must be followed by a space to stop the node). */
+ else if (*line != '\0'
+ && ((*line == ':' && current->type == ET_menu_entry_name)
+ || (strchr (",\t.", *line)
+ && current->type == ET_menu_entry_node)))
+ {
+ ELEMENT *e;
+ char menu_separator = *line;
+ line++;
+
+ current = current->parent;
+ e = new_element (ET_menu_entry_separator);
+ text_append_n (&e->text, &menu_separator, 1);
+ add_to_element_contents (current, e);
+
+ /* Note, if a '.' is not followed by whitespace, we revert was was
+ done here below. */
+ }
+ /* After a separator in a menu */
+ else if (current->contents.number > 0
+ && last_contents_child (current)->type == ET_menu_entry_separator)
{
ELEMENT *last_child;
char *separator;
- last_child = last_args_child (current);
+ last_child = last_contents_child (current);
separator = last_child->text.text;
+ debug ("AFTER menu_entry_separator %s", separator);
+
/* Separator is "::". */
if (!strcmp (separator, ":") && *line == ':')
{
@@ -199,11 +229,12 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
/* A "." not followed by a space. Not a separator. */
else if (!strcmp (separator, ".") && !strchr (whitespace_chars, *line))
{
- pop_element_from_args (current);
- current = last_args_child (current);
- merge_text (current, last_child->text.text);
+ pop_element_from_contents (current);
+ current = last_contents_child (current);
+ merge_text (current, last_child->text.text, last_child);
destroy_element (last_child);
}
+ /* here we collect spaces following separators. */
else if (strchr (whitespace_chars_except_newline, *line))
{
int n;
@@ -212,30 +243,34 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
text_append_n (&last_child->text, line, n);
line += n;
}
+ /* :: after a menu entry name => change to a menu entry node */
else if (!strncmp (separator, "::", 2))
{
ELEMENT *entry_name;
- debug ("MENU NODE no entry %s", separator);
- entry_name = args_child_by_index (current, -2);
+ debug ("MENU NODE done (change from menu entry name) %s", separator);
+ entry_name = contents_child_by_index (current, -2);
- /* Change it from ET_menu_entry_name (i.e. the label). */
+ /* Change from menu_entry_name (i.e. a label)
+ to a menu entry node */
entry_name->type = ET_menu_entry_node;
current = enter_menu_entry_node (current);
}
- /* End of the label. Begin the element for the destination. */
+ /* a :, but not ::, after a menu entry name => end of menu entry name */
else if (*separator == ':')
{
ELEMENT *entry_node;
- debug ("MENU ENTRY %s", separator);
+ debug ("MENU ENTRY done %s", separator);
entry_node = new_element (ET_menu_entry_node);
- add_to_element_args (current, entry_node);
+ add_to_element_contents (current, entry_node);
current = entry_node;
}
else
+ /* anything else corresponds to a separator that does not contain
+ : and is after a menu node (itself following a menu_entry_name) */
{
- debug ("MENU NODE");
+ debug ("MENU NODE done %s", separator);
current = enter_menu_entry_node (current);
}
}
@@ -247,3 +282,139 @@ handle_menu (ELEMENT **current_inout, char **line_inout)
return retval;
}
+
+ELEMENT *
+end_line_menu_entry (ELEMENT *current)
+{
+ ELEMENT *end_comment = 0;
+ int empty_menu_entry_node = 0;
+
+ if (current->type == ET_menu_entry_node)
+ {
+ ELEMENT *last = last_contents_child (current);
+
+ if (current->contents.number > 0
+ && (last->cmd == CM_c || last->cmd == CM_comment))
+ {
+ end_comment = pop_element_from_contents (current);
+ }
+
+ /* If contents empty or is all whitespace. */
+ if (current->contents.number == 0
+ || (current->contents.number == 1
+ && last->text.end > 0
+ && !last->text.text[strspn (last->text.text,
+ whitespace_chars)]))
+ {
+ empty_menu_entry_node = 1;
+ if (end_comment)
+ add_to_element_contents (current, end_comment);
+ }
+ }
+ /* Abort the menu entry if there is no destination node given. */
+ if (empty_menu_entry_node || current->type == ET_menu_entry_name)
+ {
+ ELEMENT *menu, *menu_entry, *description_or_menu_comment = 0;
+ debug ("FINALLY NOT MENU ENTRY");
+ menu = current->parent->parent;
+ menu_entry = pop_element_from_contents (menu);
+ if (menu->contents.number > 0
+ && last_contents_child(menu)->type == ET_menu_entry)
+ {
+ ELEMENT *entry, *description = 0;
+ int j;
+
+ entry = last_contents_child(menu);
+ for (j = entry->contents.number - 1; j >= 0; j--)
+ {
+ ELEMENT *e = contents_child_by_index (entry, j);
+ if (e->type == ET_menu_entry_description)
+ {
+ description = e;
+ break;
+ }
+ }
+ if (description)
+ description_or_menu_comment = description;
+ else
+ {
+ ELEMENT *e;
+ /* "Normally this cannot happen." */
+ bug ("no description in menu entry");
+ e = new_element (ET_menu_entry_description);
+ add_to_element_contents (entry, e);
+ description_or_menu_comment = e;
+ }
+ }
+ else if (menu->contents.number > 0
+ && last_contents_child(menu)->type == ET_menu_comment)
+ {
+ description_or_menu_comment = last_contents_child(menu);
+ }
+ if (description_or_menu_comment)
+ {
+ current = description_or_menu_comment;
+ if (current->contents.number > 0
+ && last_contents_child(current)->type == ET_preformatted)
+ current = last_contents_child(current);
+ else
+ {
+ ELEMENT *e;
+ /* This should not happen */
+ bug ("description or menu comment not in preformatted");
+ e = new_element (ET_preformatted);
+ add_to_element_contents (current, e);
+ current = e;
+ }
+ }
+ else
+ {
+ ELEMENT *e;
+ e = new_element (ET_menu_comment);
+ add_to_element_contents (menu, e);
+ current = e;
+ e = new_element (ET_preformatted);
+ add_to_element_contents (current, e);
+ current = e;
+ debug ("THEN MENU_COMMENT OPEN");
+ }
+ {
+ int i, j;
+ for (i = 0; i < menu_entry->contents.number; i++)
+ {
+ ELEMENT *arg = contents_child_by_index(menu_entry, i);
+ if (arg->text.end > 0)
+ current = merge_text (current, arg->text.text, arg);
+ else
+ {
+ ELEMENT *e;
+ for (j = 0; j < arg->contents.number; j++)
+ {
+ e = contents_child_by_index (arg, j);
+ if (e->text.end > 0)
+ {
+ current = merge_text (current, e->text.text, e);
+ destroy_element (e);
+ }
+ else
+ {
+ add_to_element_contents (current, e);
+ }
+ }
+ }
+ destroy_element (arg);
+ }
+ destroy_element (menu_entry);
+ }
+ }
+ else
+ {
+ debug ("MENU ENTRY END LINE");
+ current = current->parent;
+ current = enter_menu_entry_node (current);
+ if (end_comment)
+ add_to_element_contents (current, end_comment);
+ }
+
+ return current;
+}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/multitable.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/multitable.c
index 7f98377f15..b8b68374ee 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/multitable.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/multitable.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -52,85 +52,134 @@ item_multitable_parent (ELEMENT *current)
}
/* Put the contents of a @table row in a ET_table_entry container, containing
- a ET_table_term element and a ET_table_item element. The elements of
+ a ET_table_term element and a ET_table_definition element. The elements of
this row currently occur the end of the contents of CURRENT as immediate
children.
- NEXT_COMMAND is the command that ends this row, usually CM_item. It is null
- at the end of a @table. If NEXT_COMMAND is given as CM_itemx, gather a
- ET_inter_item container instead. */
+ NEXT_COMMAND is the command that ends this row, usually CM_item. It is
+ null at the end of a @table. If NEXT_COMMAND is given as CM_itemx, gather
+ an ET_inter_item container instead. */
void
gather_previous_item (ELEMENT *current, enum command_id next_command)
{
- ELEMENT *gathered;
+ ELEMENT *table_after_terms, *e;
enum element_type type;
int i, contents_count;
+ int begin = -1, end = -1, term_begin = -1;
if (last_contents_child(current)
&& last_contents_child(current)->type == ET_before_item)
{
if (next_command == CM_itemx)
- line_warn ("@itemx should not begin @%s", command_name(current->cmd));
+ line_error ("@itemx should not begin @%s", command_name(current->cmd));
return;
}
- type = next_command != CM_itemx ? ET_table_item : ET_inter_item;
- gathered = new_element (type);
+ type = next_command != CM_itemx ? ET_table_definition : ET_inter_item;
/* Starting from the end, collect everything that is not a ET_item
- or ET_itemx and put it into the ET_table_item. */
+ or ET_itemx and put it into the ET_table_definition/ET_inter_item. */
contents_count = current->contents.number;
- for (i = 0; i < contents_count; i++)
+ for (i = contents_count - 1; i >= 0; i--)
{
- ELEMENT *e;
- if (last_contents_child(current)->cmd == CM_item
- || last_contents_child(current)->cmd == CM_itemx)
- break;
+ e = contents_child_by_index (current, i);
+ if (e->cmd == CM_item || e->cmd == CM_itemx)
+ {
+ begin = i + 1;
+ break;
+ }
+ }
+ if (begin == -1)
+ begin = 0;
- e = pop_element_from_contents (current);
- insert_into_contents (gathered, e, 0);
+ if (next_command)
+ {
+ /* Don't absorb trailing index entries as they are included with a
+ following @item. */
+ for (i = contents_count - 1; i >= begin; i--)
+ {
+ e = contents_child_by_index (current, i);
+ if (e->type != ET_index_entry_command)
+ {
+ end = i + 1;
+ break;
+ }
+ }
}
- /* TODO: A similar algorithm is is in gather_def_item in def.c. If
- speed is an issue then we could move all the elements at once instead
- of calling insert_into_contents multiple times. */
+ if (end == -1)
+ end = contents_count;
+
+ table_after_terms = new_element (type);
+
+ /* Move everything from 'begin' onwards to be children of
+ table_after_terms. */
+ insert_slice_into_contents (table_after_terms, 0, current, begin, end);
+ for (i = 0; i < table_after_terms->contents.number; i++)
+ contents_child_by_index(table_after_terms, i)->parent = table_after_terms;
+ remove_slice_from_contents (current, begin, end);
- if (type == ET_table_item)
+ if (type == ET_table_definition)
{
+ ELEMENT *before_item = 0;
ELEMENT *table_entry = new_element (ET_table_entry);
ELEMENT *table_term = new_element (ET_table_term);
add_to_element_contents (table_entry, table_term);
- /* We previously collected elements into a ET_table_item. Now
+ /* We previously collected elements into a ET_table_definition. Now
do the same for ET_table_term. */
- contents_count = current->contents.number;
- for (i = 0; i < contents_count; i++)
+ for (i = begin - 1; i >= 0; i--)
{
- ELEMENT *e;
- if (last_contents_child(current)->type == ET_before_item
- || last_contents_child(current)->type == ET_table_entry)
- break;
-
- e = pop_element_from_contents (current);
- insert_into_contents (table_term, e, 0);
+ e = contents_child_by_index (current, i);
+ if (e->type == ET_before_item
+ || e->type == ET_table_entry)
+ {
+ if (e->type == ET_before_item)
+ before_item = e;
+ term_begin = i + 1;
+ break;
+ }
}
-
- add_to_element_contents (current, table_entry);
-
- if (gathered->contents.number > 0)
- add_to_element_contents (table_entry, gathered);
+ if (term_begin == -1)
+ term_begin = 0;
+
+ insert_slice_into_contents (table_term, 0, current,
+ term_begin, begin);
+ for (i = 0; i < table_term->contents.number; i++)
+ contents_child_by_index(table_term, i)->parent = table_term;
+ remove_slice_from_contents (current, term_begin, begin);
+ if (before_item)
+ {
+ /* Reparent any trailing index entries in the before_item to the
+ beginning of table term. */
+ while (before_item->contents.number > 0
+ && (last_contents_child(before_item)->type
+ == ET_index_entry_command
+ || last_contents_child(before_item)->cmd == CM_c
+ || last_contents_child(before_item)->cmd
+ == CM_comment))
+ {
+ ELEMENT *e = pop_element_from_contents (before_item);
+ insert_into_contents (table_term, e, 0);
+ }
+ }
+
+ if (table_after_terms->contents.number > 0)
+ add_to_element_contents (table_entry, table_after_terms);
else
- destroy_element (gathered);
+ destroy_element (table_after_terms);
+
+ insert_into_contents (current, table_entry, term_begin);
}
else /* Gathering ET_inter_item between @item and @itemx */
{
/* Text between @item and @itemx is only allowed in a few cases:
comments, empty lines, or index entries. */
- if (check_no_text (gathered))
+ if (check_no_text (table_after_terms))
line_error ("@itemx must follow @item");
- if (gathered->contents.number > 0)
- add_to_element_contents (current, gathered);
+ if (table_after_terms->contents.number > 0)
+ insert_into_contents (current, table_after_terms, begin);
else
- destroy_element (gathered);
+ destroy_element (table_after_terms);
}
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.c
index 8a85a14c2e..ced78cd376 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2022 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,17 +18,42 @@
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
+#include <stdbool.h>
+#include "uniconv.h"
+#include "unistr.h"
#include "parser.h"
+#include "debug.h"
#include "text.h"
#include "input.h"
+#include "source_marks.h"
const char *whitespace_chars = " \t\v\f\r\n";
const char *digit_chars = "0123456789";
-// [^\S\r\n] in Perl
-const char *whitespace_chars_except_newline = " \t\v\f";
+/* in the perl parser, comments including whitespace_chars_except_newline
+ show where code should be changed if the list of characters changes here */
+#define WHITESPACE_CHARS_EXCEPT_NEWLINE " \t\v\f"
+const char *whitespace_chars_except_newline = WHITESPACE_CHARS_EXCEPT_NEWLINE;
+
+const char *linecommand_expansion_delimiters = WHITESPACE_CHARS_EXCEPT_NEWLINE
+ "{}@";
+#undef WHITESPACE_CHARS_EXCEPT_NEWLINE
+
+/* count characters, not bytes. */
+size_t
+count_convert_u8 (char *text)
+{
+ /* FIXME error checking? */
+ uint8_t *resultbuf = u8_strconv_from_encoding (text, "UTF-8",
+ iconveh_question_mark);
+ size_t result = u8_mbsnlen (resultbuf, u8_strlen (resultbuf));
+
+ free (resultbuf);
+
+ return result;
+}
/* Check if the contents of S2 appear at S1). */
int
@@ -37,6 +62,12 @@ looking_at (char *s1, char *s2)
return !strncmp (s1, s2, strlen (s2));
}
+int
+isascii_alnum (int c)
+{
+ return (((c & ~0x7f) == 0) && isalnum(c));
+}
+
/* Look for a sequence of alphanumeric characters or hyphens, where the
first isn't a hyphen. This is the format of (non-single-character) Texinfo
commands, but is also used elsewhere. Return value to be freed by caller.
@@ -48,10 +79,10 @@ read_command_name (char **ptr)
char *ret = 0;
q = p;
- if (!isalnum ((unsigned char) *q))
+ if (!isascii_alnum (*q))
return 0; /* Invalid. */
- while (isalnum ((unsigned char) *q) || *q == '-' || *q == '_')
+ while (isascii_alnum (*q) || *q == '-' || *q == '_')
q++;
ret = strndup (p, q - p);
p = q;
@@ -60,6 +91,38 @@ read_command_name (char **ptr)
return ret;
}
+/* look for a command name. Return value to be freed by caller.
+ *PTR is advanced past the read name. *SINGLE_CHAR is set to 1
+ if the command is a single character command.
+ Return 0 if name is invalid or the empty string */
+char *
+parse_command_name (char **ptr, int *single_char)
+{
+ char *p = *ptr;
+ char *ret = 0;
+ *single_char = 0;
+
+ if (*p
+ /* List of single character Texinfo commands. */
+ && strchr ("([\"'~@&}{,.!?"
+ " \f\n\r\t"
+ "*-^`=:|/\\",
+ *p))
+ {
+ char single_char_str[2];
+ single_char_str[0] = *p++;
+ single_char_str[1] = '\0';
+ ret = strdup (single_char_str);
+ *single_char = 1;
+ *ptr = p;
+ }
+ else
+ {
+ ret = read_command_name (ptr);
+ }
+ return ret;
+}
+
/* Read a name used for @set and @value. */
char *
read_flag_name (char **ptr)
@@ -68,7 +131,7 @@ read_flag_name (char **ptr)
char *ret = 0;
q = p;
- if (!isalnum ((unsigned char) *q) && *q != '-' && *q != '_')
+ if (!isascii_alnum (*q) && *q != '-' && *q != '_')
return 0; /* Invalid. */
while (!strchr (whitespace_chars, *q)
@@ -87,6 +150,33 @@ element_type_name (ELEMENT *e)
return element_type_names[(e)->type];
}
+/* the pointer returned is past @c/@comment, whether there is indeed
+ a comment or not. If there is a comment, *has_comment is set to 1 */
+char *
+read_comment (char *line, int *has_comment)
+{
+ char *p = line;
+ int len = strlen (line);
+
+ *has_comment = 0;
+
+ if (len >= 2 && memcmp (p, "@c", 2) == 0)
+ {
+ p += 2;
+ if (len >= 8 && memcmp (p, "omment", 6) == 0)
+ p += 6;
+
+ /* TeX control sequence name ends at an escape character or
+ whitespace. */
+ if (*p && *p != '@' && !strchr (whitespace_chars, *p))
+ return p; /* @c or @comment not terminated. */
+ }
+ else
+ return p; /* Trailing characters on line. */
+ *has_comment = 1;
+ return p;
+}
+
/* Return 1 if the element expansion is all whitespace */
int
check_space_element (ELEMENT *e)
@@ -108,7 +198,6 @@ check_space_element (ELEMENT *e)
return 1;
}
-
/* Current node, section and part. */
@@ -119,30 +208,77 @@ ELEMENT *current_part = 0;
/* Conditional stack. */
-enum command_id *conditional_stack;
+CONDITIONAL_STACK_ITEM *conditional_stack;
size_t conditional_number;
size_t conditional_space;
void
-push_conditional_stack (enum command_id cond)
+push_conditional_stack (enum command_id cond, SOURCE_MARK *source_mark)
{
if (conditional_number == conditional_space)
{
conditional_stack = realloc (conditional_stack,
(conditional_space += 5)
- * sizeof (enum command_id));
+ * sizeof (CONDITIONAL_STACK_ITEM));
if (!conditional_stack)
fatal ("realloc failed");
}
- conditional_stack[conditional_number++] = cond;
+ conditional_stack[conditional_number].command = cond;
+ conditional_stack[conditional_number].source_mark = source_mark;
+ conditional_number++;
}
-enum command_id
+CONDITIONAL_STACK_ITEM *
pop_conditional_stack (void)
{
if (conditional_number == 0)
+ return 0;
+ return &(conditional_stack[--conditional_number]);
+}
+
+CONDITIONAL_STACK_ITEM *
+top_conditional_stack (void)
+{
+ if (conditional_number == 0)
+ return 0;
+ return &(conditional_stack[conditional_number - 1]);
+}
+
+
+/* Raw block commands stack. */
+
+enum command_id *raw_block_stack;
+size_t raw_block_number;
+size_t raw_block_space;
+
+void
+push_raw_block_stack (enum command_id raw_block)
+{
+ if (raw_block_number == raw_block_space)
+ {
+ raw_block_stack = realloc (raw_block_stack,
+ (raw_block_space += 5)
+ * sizeof (enum command_id));
+ if (!raw_block_stack)
+ fatal ("realloc failed");
+ }
+ raw_block_stack[raw_block_number++] = raw_block;
+}
+
+enum command_id
+pop_raw_block_stack (void)
+{
+ if (raw_block_number == 0)
return CM_NONE;
- return conditional_stack[--conditional_number];
+ return raw_block_stack[--raw_block_number];
+}
+
+enum command_id
+raw_block_stack_top (void)
+{
+ if (raw_block_number == 0)
+ return CM_NONE;
+ return raw_block_stack[raw_block_number-1];
}
@@ -211,14 +347,20 @@ register_global_command (ELEMENT *current)
add_to_contents_as_array (&global_info.footnotes, current);
break;
+ case CM_float:
+ add_to_contents_as_array (&global_info.floats, current);
+ break;
+
+ /* global in command_data.txt */
+ GLOBAL_CASE(author);
+ GLOBAL_CASE(detailmenu);
GLOBAL_CASE(hyphenation);
GLOBAL_CASE(insertcopying);
+ GLOBAL_CASE(listoffloats);
+ GLOBAL_CASE(part);
GLOBAL_CASE(printindex);
GLOBAL_CASE(subtitle);
GLOBAL_CASE(titlefont);
- GLOBAL_CASE(listoffloats);
- GLOBAL_CASE(detailmenu);
- GLOBAL_CASE(part);
/* from Common.pm %document_settable_multiple_at_commands */
GLOBAL_CASE(allowcodebreaks);
@@ -244,7 +386,6 @@ register_global_command (ELEMENT *current)
/* do nothing; just silence -Wswitch about lots of un-covered cases */
break;
}
- /* TODO: Check if all of these are necessary. */
return 1;
}
else if ((command_data(cmd).flags & CF_global_unique))
@@ -329,23 +470,26 @@ wipe_global_info (void)
}
global_kbdinputstyle = kbd_distinct;
- free (global_info.input_perl_encoding);
- free (global_info.input_encoding_name);
-
free (global_info.dircategory_direntry.contents.list);
free (global_info.footnotes.contents.list);
+ free (global_input_encoding_name);
+ /* set by set_input_encoding */
+ global_input_encoding_name = 0;
+
#define GLOBAL_CASE(cmx) \
free (global_info.cmx.contents.list)
+ GLOBAL_CASE(author);
+ GLOBAL_CASE(detailmenu);
GLOBAL_CASE(hyphenation);
GLOBAL_CASE(insertcopying);
GLOBAL_CASE(printindex);
GLOBAL_CASE(subtitle);
GLOBAL_CASE(titlefont);
GLOBAL_CASE(listoffloats);
- GLOBAL_CASE(detailmenu);
GLOBAL_CASE(part);
+ GLOBAL_CASE(floats);
GLOBAL_CASE(allowcodebreaks);
GLOBAL_CASE(clickstyle);
GLOBAL_CASE(codequotebacktick);
@@ -369,9 +513,6 @@ wipe_global_info (void)
/* clear the rest of the fields */
memset (&global_info, 0, sizeof (global_info));
-
- global_info.input_perl_encoding = strdup ("utf-8");
- global_info.input_encoding_name = strdup ("utf-8");
}
ELEMENT *
@@ -399,7 +540,7 @@ parse_texi_document (void)
ELEMENT *l;
free (line);
- line = next_text ();
+ line = next_text (0);
if (!line)
break;
@@ -509,7 +650,7 @@ end_paragraph (ELEMENT *current,
if (current->type == ET_paragraph)
{
debug ("CLOSE PARA");
- current = current->parent;
+ current = close_container(current);
}
return current;
@@ -525,21 +666,17 @@ end_preformatted (ELEMENT *current,
if (current->type == ET_preformatted)
{
debug ("CLOSE PREFORMATTED");
- if (current->contents.number == 0)
- {
- current = current->parent;
- destroy_element (pop_element_from_contents (current));
- debug ("popping");
- }
- else
- current = current->parent;
+ current = close_container(current);
}
return current;
}
-/* Add TEXT to the contents of CURRENT, maybe starting a new paragraph. */
+/* Add TEXT to the contents of CURRENT, maybe starting a new paragraph.
+ If TRANSFER_MARKS_ELEMENT is given, also transfer mark sources
+ from that element.
+ */
ELEMENT *
-merge_text (ELEMENT *current, char *text)
+merge_text (ELEMENT *current, char *text, ELEMENT *transfer_marks_element)
{
int no_merge_with_following_text = 0;
int leading_spaces = strspn (text, whitespace_chars);
@@ -587,16 +724,40 @@ merge_text (ELEMENT *current, char *text)
&& !strchr (last_child->text.text, '\n'))
&& !no_merge_with_following_text)
{
- /* Append text to contents */
+ /* Transfer source marks */
+ if (transfer_marks_element
+ && transfer_marks_element->source_mark_list.number > 0)
+ {
+ size_t additional_length = count_convert_u8 (last_child->text.text);
+ SOURCE_MARK_LIST *s_mark_list
+ = &(transfer_marks_element->source_mark_list);
+ int i;
+ for (i = 0; i < s_mark_list->number; i++)
+ {
+ SOURCE_MARK *source_mark = s_mark_list->list[i];
+ if (additional_length > 0)
+ source_mark->position += additional_length;
+ add_source_mark (source_mark, last_child);
+ }
+ transfer_marks_element->source_mark_list.number = 0;
+ }
+
+ debug_nonl ("MERGED TEXT: %s||| in ", text);
+ debug_print_element (last_child, 0);
+ debug_nonl (" last of ");
+ debug_print_element (current, 0); debug ("");
+
+ /* Append text */
text_append (&last_child->text, text);
- debug ("MERGED TEXT: %s|||", text);
}
else
{
ELEMENT *e = new_element (ET_NONE);
+ if (transfer_marks_element)
+ transfer_source_marks (transfer_marks_element, e);
text_append (&e->text, text);
add_to_element_contents (current, e);
- debug ("NEW TEXT: %s|||", text);
+ debug ("NEW TEXT (merge): %s|||", text);
}
return current;
@@ -624,17 +785,30 @@ abort_empty_line (ELEMENT **current_inout, char *additional_spaces)
{
retval = 1;
- debug ("ABORT EMPTY %s additional text |%s| "
- "current |%s|",
- element_type_name(last_child),
- additional_spaces,
- last_child->text.text);
+ debug_nonl ("ABORT EMPTY in ");
+ debug_print_element (current, 0);
+ debug_nonl ("(p:%d): %s; add |%s| to |%s|",
+ in_paragraph_context (current_context ()),
+ element_type_name (last_child), additional_spaces,
+ last_child->text.end > 0 ? last_child->text.text : "");
+ debug ("");
+
text_append (&last_child->text, additional_spaces);
/* Remove element altogether if it's empty. */
if (last_child->text.end == 0)
{
ELEMENT *e = pop_element_from_contents (current);
+ if (e->source_mark_list.number)
+ {
+ SOURCE_MARK_LIST *source_mark_list = &e->source_mark_list;
+
+ int i;
+ for (i = 0; i < source_mark_list->number; i++)
+ place_source_mark (current, source_mark_list->list[i]);
+ source_mark_list->number = 0;
+ }
+
destroy_element (e);
}
else if (last_child->type == ET_empty_line)
@@ -646,15 +820,18 @@ abort_empty_line (ELEMENT **current_inout, char *additional_spaces)
|| last_child->type == ET_internal_spaces_before_argument)
{
/* Remove element from main tree. It will still be referenced in
- the 'extra' hash as 'spaces_before_argument'. */
+ the 'info' hash as 'spaces_before_argument'. */
ELEMENT *owning_element;
KEY_PAIR *k;
ELEMENT *e = pop_element_from_contents (current);
+ ELEMENT *spaces_element = new_element (ET_NONE);
k = lookup_extra (last_child, "spaces_associated_command");
owning_element = (ELEMENT *) k->value;
- add_extra_string_dup (owning_element, "spaces_before_argument",
- e->text.text);
+ text_append (&spaces_element->text, e->text.text);
+ transfer_source_marks (e, spaces_element);
+ add_info_element_oot (owning_element, "spaces_before_argument",
+ spaces_element);
destroy_element (e);
}
}
@@ -671,6 +848,7 @@ isolate_last_space_internal (ELEMENT *current)
ELEMENT *last_elt;
char *text;
int text_len;
+ ELEMENT *spaces_element = new_element (ET_NONE);
last_elt = last_contents_child (current);
text = element_text (last_elt);
@@ -680,8 +858,10 @@ isolate_last_space_internal (ELEMENT *current)
/* If text all whitespace */
if (text[strspn (text, whitespace_chars)] == '\0')
{
- add_extra_string_dup (current, "spaces_after_argument",
- last_elt->text.text);
+ text_append (&spaces_element->text, last_elt->text.text);
+ transfer_source_marks (last_elt, spaces_element);
+ add_info_element_oot (current, "spaces_after_argument",
+ spaces_element);
destroy_element (pop_element_from_contents (current));
}
else
@@ -702,10 +882,17 @@ isolate_last_space_internal (ELEMENT *current)
trailing_spaces);
text[text_len - trailing_spaces] = '\0';
+ if (last_elt->source_mark_list.number > 0)
+ {
+ size_t begin_position = count_convert_u8 (text);
+ relocate_source_marks (&(last_elt->source_mark_list), spaces_element,
+ begin_position, count_convert_u8 (t.text));
+ }
last_elt->text.end -= trailing_spaces;
- add_extra_string_dup (current, "spaces_after_argument",
- t.text);
+ text_append (&spaces_element->text, t.text);
+ add_info_element_oot (current, "spaces_after_argument",
+ spaces_element);
}
}
@@ -755,21 +942,24 @@ void
isolate_last_space (ELEMENT *current)
{
char *text;
- ELEMENT *last_elt;
+ ELEMENT *last_elt = 0;
int text_len;
if (current->contents.number == 0)
return;
- if (last_contents_child(current)->cmd == CM_c
- || last_contents_child(current)->cmd == CM_comment)
+ /* Store a final comment command in the 'info' hash, except for brace
+ commands */
+ if (current->type != ET_brace_command_arg
+ && (last_contents_child(current)->cmd == CM_c
+ || last_contents_child(current)->cmd == CM_comment))
{
- add_extra_element_oot (current, "comment_at_end",
- pop_element_from_contents (current));
+ add_info_element_oot (current, "comment_at_end",
+ pop_element_from_contents (current));
}
if (current->contents.number == 0)
- return;
+ goto no_isolate_space;
last_elt = last_contents_child (current);
text = element_text (last_elt);
@@ -777,17 +967,34 @@ isolate_last_space (ELEMENT *current)
|| (last_elt->type && (!current->type
|| (current->type != ET_line_arg
&& current->type != ET_block_line_arg))))
- return;
+ goto no_isolate_space;
text_len = last_elt->text.end;
/* Does the text end in whitespace? */
if (!strchr (whitespace_chars, text[text_len - 1]))
- return;
+ goto no_isolate_space;
+
+ debug_nonl ("ISOLATE SPACE p ");
+ debug_print_element (current, 0);
+ debug_nonl ("; c ");
+ debug_print_element (last_elt, 0); debug ("");
if (current->type == ET_menu_entry_node)
isolate_trailing_space (current, ET_space_at_end_menu_node);
else
isolate_last_space_internal (current);
+
+ return;
+
+ no_isolate_space:
+ debug_nonl ("NOT ISOLATING p ");
+ debug_print_element (current, 0);
+ debug_nonl ("; c ");
+ if (last_elt)
+ debug_print_element (last_elt, 0);
+ debug ("");
+
+ return;
}
@@ -856,7 +1063,7 @@ parent_of_command_as_argument (ELEMENT *current)
void
register_command_as_argument (ELEMENT *cmd_as_arg)
{
- debug ("FOR PARENT @%s command_as_argument @%s",
+ debug ("FOR PARENT @%s command_as_argument %s",
command_name(cmd_as_arg->parent->parent->cmd),
command_name(cmd_as_arg->cmd));
if (!cmd_as_arg->type)
@@ -870,6 +1077,31 @@ register_command_as_argument (ELEMENT *cmd_as_arg)
}
}
+void
+gather_spaces_after_cmd_before_arg(ELEMENT *current)
+{
+ ELEMENT *spaces_element = pop_element_from_contents (current);
+ spaces_element->type = ET_NONE;
+ add_info_element_oot (current, "spaces_after_cmd_before_arg",
+ spaces_element);
+}
+
+ELEMENT *
+new_value_element (enum command_id cmd, char *flag, ELEMENT *spaces_element)
+{
+ ELEMENT *value_elt = new_element (ET_NONE);
+ ELEMENT *value_arg = new_element (ET_NONE);
+
+ value_elt->cmd = cmd;
+
+ text_append (&value_arg->text, flag);
+ add_to_element_args (value_elt, value_arg);
+ if (spaces_element)
+ add_info_element_oot (value_elt, "spaces_after_cmd_before_arg",
+ spaces_element);
+ return value_elt;
+}
+
/* Check if line is "@end ..." for current command. If so, advance LINE. */
int
is_end_current_command (ELEMENT *current, char **line,
@@ -915,31 +1147,15 @@ check_valid_nesting (ELEMENT *current, enum command_id cmd)
plain text
full text
- simple text
- full line
- full line no refs
*/
int ok = 0; /* Whether nesting is allowed. */
- /* Whether command is a "simple text" command */
- int simple_text_command = 0;
-
enum command_id outer = current->parent->cmd;
unsigned long outer_flags = command_data(outer).flags;
unsigned long cmd_flags = command_data(cmd).flags;
- // much TODO here.
-
- if (outer_flags & CF_contain_simple_text
- /* not in CF_contain_simple_text since index entry flags are not set
- in command_data.txt, and also index commands are dynamically added */
- || outer_flags & CF_index_entry_command)
- {
- simple_text_command = 1;
- }
-
/* first three conditions check if in the main contents of the commands
or in the arguments where there is checking of nesting */
if (outer_flags & CF_root && current->type != ET_line_arg)
@@ -963,28 +1179,20 @@ check_valid_nesting (ELEMENT *current, enum command_id cmd)
if (cmd == CM_c || cmd == CM_comment)
ok = 1;
}
- else if (simple_text_command
- /* "full text commands" */
- || (outer_flags & CF_brace)
- && (command_data(outer).data == BRACE_style_other
- || command_data(outer).data == BRACE_style_code
- || command_data(outer).data == BRACE_style_no_code)
- /* "full line commands" */
+ else if (((outer_flags & CF_brace) /* "full text commands" */
+ && (command_data(outer).data == BRACE_style_other
+ || command_data(outer).data == BRACE_style_code
+ || command_data(outer).data == BRACE_style_no_code))
|| outer == CM_center
|| outer == CM_exdent
|| outer == CM_item
|| outer == CM_itemx
-
- || (!current->parent->cmd && current_context () == ct_def)
-
- /* "full line no refs commands" */
- || (outer_flags & (CF_sectioning_heading | CF_def))
- || (!current->parent->cmd && current_context () == ct_def))
+ || outer == CM_nodedescription)
{
/* Start by checking if the command is allowed inside a "full text
command" - this is the most permissive. */
/* in the perl parser the checks are not dynamic as in this function,
- a hash is used and modified when defining the definfoencose command */
+ a hash is used and modified when defining the definfoenclose command */
/* all the brace commands, not the definfoenclose commands, which
should be consistent with the perl parser */
if (cmd_flags & CF_brace && !(cmd_flags & CF_INFOENCLOSE))
@@ -1021,30 +1229,6 @@ check_valid_nesting (ELEMENT *current, enum command_id cmd)
|| command_data(outer).data == BRACE_style_no_code)))
ok = 1;
}
-
- /* Now add more restrictions for "full line no refs" commands and "simple
- text" commands on valid brace commands. */
- if (outer_flags & (CF_sectioning_heading | CF_def)
- || (!current->parent->cmd && current_context () == ct_def)
- || simple_text_command)
- {
- if (cmd == CM_titlefont
- || cmd == CM_anchor
- || cmd == CM_footnote
- || cmd == CM_verb
- || cmd == CM_indent || cmd == CM_noindent)
- ok = 0;
- }
-
- /* Exceptions for "simple text commands" only for brace commands. */
- if (simple_text_command)
- {
- if (cmd == CM_xref
- || cmd == CM_ref
- || cmd == CM_pxref
- || cmd == CM_inforef)
- ok = 0;
- }
}
else
{
@@ -1074,6 +1258,102 @@ check_valid_nesting (ELEMENT *current, enum command_id cmd)
}
}
+void
+check_valid_nesting_context (enum command_id cmd)
+{
+ enum command_id invalid_context = 0, invalid_line = 0;
+
+ if (nesting_context.caption > 0
+ && (cmd == CM_caption || cmd == CM_shortcaption))
+ {
+ line_warn ("@%s should not appear anywhere inside caption",
+ command_name(cmd));
+ return;
+ }
+
+ if (nesting_context.footnote > 0
+ && cmd == CM_footnote)
+ {
+ invalid_context = CM_footnote;
+ }
+ else if (nesting_context.basic_inline_stack.top > 0
+ || nesting_context.basic_inline_stack_on_line.top > 0
+ || nesting_context.basic_inline_stack_block.top > 0)
+ {
+ unsigned long flags = command_data(cmd).flags;
+ int data = command_data(cmd).data;
+
+ if (!( /* inclusions */
+ (flags & (CF_accent | CF_brace | CF_in_heading_spec))
+ || ((flags & CF_nobrace) && data == NOBRACE_symbol)
+ || cmd == CM_c
+ || cmd == CM_comment
+ || cmd == CM_refill
+ || cmd == CM_subentry
+ || cmd == CM_columnfractions
+ || cmd == CM_set
+ || cmd == CM_clear
+ || cmd == CM_end
+ || ((flags & CF_block)
+ && (data == BLOCK_format_raw || data == BLOCK_conditional))
+ )
+ || (flags & (CF_ref | CF_INFOENCLOSE)) /* exclusions */
+ || cmd == CM_caption
+ || cmd == CM_shortcaption
+ || cmd == CM_titlefont
+ || cmd == CM_anchor
+ || cmd == CM_footnote
+ || cmd == CM_verb)
+ {
+ if (nesting_context.basic_inline_stack.top > 0)
+ invalid_context = top_command
+ (&nesting_context.basic_inline_stack);
+ else if (nesting_context.basic_inline_stack_on_line.top > 0)
+ invalid_line = top_command
+ (&nesting_context.basic_inline_stack_on_line);
+ else if (nesting_context.basic_inline_stack_block.top > 0)
+ invalid_line = top_command
+ (&nesting_context.basic_inline_stack_block);
+ }
+ }
+
+ if (invalid_context)
+ {
+ line_warn ("@%s should not appear anywhere inside @%s",
+ command_name(cmd),
+ command_name(invalid_context));
+ return;
+ }
+
+ /* Inclusions for "basic inline with refs" commands. */
+ if (command_data(invalid_line).flags & (CF_sectioning_heading | CF_def))
+ {
+ if (command_data(cmd).flags & CF_ref)
+ invalid_line = 0;
+ }
+
+ if (invalid_line)
+ {
+ line_warn ("@%s should not appear on @%s line",
+ command_name(cmd),
+ command_name(invalid_line));
+ }
+
+ if (nesting_context.regions_stack.top > 0)
+ {
+ if ((command_data(cmd).flags & CF_block)
+ && (command_data(cmd).data == BLOCK_region))
+ invalid_context = top_command (&nesting_context.regions_stack);
+ }
+
+ if (invalid_context)
+ {
+ line_warn ("@%s should not appear in @%s block",
+ command_name(cmd),
+ command_name(invalid_context));
+ }
+}
+
/* *LINEP is a pointer into the line being processed. It is advanced past any
bytes processed.
Return STILL_MORE_TO_PROCESS when there is more to process on the line
@@ -1083,24 +1363,32 @@ int
process_remaining_on_line (ELEMENT **current_inout, char **line_inout)
{
ELEMENT *current = *current_inout;
+ ELEMENT *macro_call_element = 0;
char *line = *line_inout;
char *line_after_command;
int retval = STILL_MORE_TO_PROCESS;
enum command_id end_cmd;
+ enum command_id from_alias = CM_NONE;
enum command_id cmd = CM_NONE;
/* remains set only if command is unknown, otherwise cmd is used */
char *command = 0;
+ /*
+ debug_nonl("PROCESS "); debug_print_protected_string (line); debug ("");
+ */
+
/********* BLOCK_raw ******************/
if (command_flags(current) & CF_block
&& (command_data(current->cmd).data == BLOCK_raw))
{
char *p = line;
+ enum command_id cmd = 0;
+ int closed_nested_raw = 0;
/* Check if we are using a macro within a macro. */
- if (current->cmd == CM_macro || current->cmd == CM_rmacro)
+ if (current->cmd == CM_macro || current->cmd == CM_rmacro
+ || current->cmd == CM_linemacro)
{
- enum command_id cmd = 0;
p += strspn (p, whitespace_chars);
if (!strncmp (p, "@macro", strlen ("@macro")))
{
@@ -1112,87 +1400,117 @@ process_remaining_on_line (ELEMENT **current_inout, char **line_inout)
p += strlen ("@rmacro");
cmd = CM_rmacro;
}
- if (cmd)
+ else if (!strncmp (p, "@linemacro", strlen ("@linemacro")))
{
- ELEMENT *e = new_element (ET_NONE);
- e->cmd = cmd;
- line = p;
- add_to_element_contents (current, e);
- add_extra_string (e, "arg_line", strdup (line));
- current = e;
- retval = GET_A_NEW_LINE;
- goto funexit;
+ p += strlen ("@linemacro");
+ cmd = CM_linemacro;
}
+ if (*p && !strchr (whitespace_chars, *p))
+ cmd = 0;
+ }
+ else if (current->cmd == CM_ignore)
+ {
+ p += strspn (p, whitespace_chars);
+ if (!strncmp (p, "@ignore", strlen ("@ignore")))
+ {
+ p += strlen ("@ignore");
+ if (!(*p && *p != '@' && !strchr (whitespace_chars, *p)))
+ cmd = CM_ignore;
+ }
+ }
+ if (cmd)
+ {
+ debug ("RAW SECOND LEVEL %s in @%s", command_name(cmd),
+ command_name(current->cmd));
+ push_raw_block_stack (cmd);
}
/* Else check if line is "@end ..." for current command. */
- if (is_end_current_command (current, &p, &end_cmd))
+ else
{
- ELEMENT *e;
-
- if (strchr (whitespace_chars, *line))
+ ELEMENT *top_stack_raw_element;
+ enum command_id top_stack_cmd = raw_block_stack_top ();
+ if (top_stack_cmd == CM_NONE)
{
- ELEMENT *e;
- int n = strspn (line, whitespace_chars);
- e = new_element (ET_raw);
- text_append_n (&e->text, line, n);
- add_to_element_contents (current, e);
- line += n;
- line_warn ("@end %s should only appear at the "
- "beginning of a line", command_name(end_cmd));
+ top_stack_raw_element = current;
}
-
- /* For macros, define a new macro (unless we are in a nested
- macro definition). */
- if ((end_cmd == CM_macro || end_cmd == CM_rmacro)
- && (!current->parent
- || (current->parent->cmd != CM_macro
- && current->parent->cmd != CM_rmacro)))
+ else
+ {
+ top_stack_raw_element = new_element (ET_NONE);
+ top_stack_raw_element->cmd = top_stack_cmd;
+ }
+ if (is_end_current_command (top_stack_raw_element, &p, &end_cmd))
{
- char *name;
- enum command_id existing;
- if (current->args.number > 0)
+ if (raw_block_number == 0)
{
- name = element_text (args_child_by_index (current, 0));
+ ELEMENT *e;
- existing = lookup_command (name);
- if (existing)
+ if (strchr (whitespace_chars, *line))
{
- MACRO *macro;
- macro = lookup_macro (existing);
- if (macro)
- {
- line_error_ext (1, &current->source_info,
- "macro `%s' previously defined", name);
- line_error_ext (1, &macro->element->source_info,
- "here is the previous definition of `%s'", name);
- }
- else if (!(existing & USER_COMMAND_BIT))
- {
- line_error_ext (1, &current->source_info,
- "redefining Texinfo language command: @%s",
- name);
- }
+ ELEMENT *e;
+ int n = strspn (line, whitespace_chars);
+ e = new_element (ET_raw);
+ text_append_n (&e->text, line, n);
+ add_to_element_contents (current, e);
+ line += n;
+ line_warn ("@end %s should only appear at the "
+ "beginning of a line", command_name(end_cmd));
}
- if (!lookup_extra (current, "invalid_syntax"))
+ /* For macros, define a new macro. */
+ if (end_cmd == CM_macro || end_cmd == CM_rmacro
+ || end_cmd == CM_linemacro)
{
- new_macro (name, current);
+ char *name;
+ enum command_id existing;
+ if (current->args.number > 0)
+ {
+ name = element_text (args_child_by_index (current, 0));
+
+ existing = lookup_command (name);
+ if (existing)
+ {
+ MACRO *macro;
+ macro = lookup_macro (existing);
+ if (macro)
+ {
+ line_error_ext (1, &current->source_info,
+ "macro `%s' previously defined", name);
+ line_error_ext (1, &macro->element->source_info,
+ "here is the previous definition of `%s'", name);
+ }
+ else if (!(existing & USER_COMMAND_BIT))
+ {
+ line_error_ext (1, &current->source_info,
+ "redefining Texinfo language command: @%s",
+ name);
+ }
+ }
+ if (!lookup_extra (current, "invalid_syntax"))
+ {
+ new_macro (name, current);
+ }
+ }
}
+ debug ("CLOSED raw %s", command_name(end_cmd));
+ /* 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 */
+ e = new_element (ET_empty_line);
+ add_to_element_contents (current, e);
+
+ closed_nested_raw = 1;
}
+ else
+ pop_raw_block_stack();
}
-
-
- debug ("CLOSED raw %s", command_name(end_cmd));
- /* 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 */
- e = new_element (ET_empty_line);
- add_to_element_contents (current, e);
+ if (top_stack_cmd != CM_NONE)
+ destroy_element (top_stack_raw_element);
}
- else /* save the line verbatim */
+ /* save the line verbatim */
+ if (! closed_nested_raw)
{
ELEMENT *e;
e = new_element (ET_raw);
@@ -1210,103 +1528,90 @@ process_remaining_on_line (ELEMENT **current_inout, char **line_inout)
char *p = line;
/* check for nested @ifset (so that @end ifset doesn't end the
- the outermost @ifset). It is discarded when the outermost is.*/
+ the outermost @ifset). */
if (current->cmd == CM_ifclear || current->cmd == CM_ifset
|| current->cmd == CM_ifcommanddefined
|| current->cmd == CM_ifcommandnotdefined)
{
ELEMENT *e;
p += strspn (p, whitespace_chars);
- if (*p == '@'
- && !strncmp (p + 1, command_name(current->cmd),
- strlen (command_name(current->cmd))))
+ if (*p == '@')
{
- e = new_element (ET_NONE);
- e->cmd = current->cmd;
- add_to_element_contents (current, e);
- current = e;
- retval = GET_A_NEW_LINE;
- goto funexit;
+ char *command;
+ p++;
+ command = read_command_name (&p);
+ if (command)
+ {
+ cmd = lookup_command (command);
+ free (command);
+ if (cmd == current->cmd)
+ {
+ e = new_element (ET_NONE);
+ e->cmd = current->cmd;
+ add_to_element_contents (current, e);
+ current = e;
+ retval = GET_A_NEW_LINE;
+ goto funexit;
+ }
+ }
}
}
+ p = line;
/* Else check if line is "@end ..." for current command. */
- if (is_end_current_command (current, &line, &end_cmd))
+ if (is_end_current_command (current, &p, &end_cmd))
{
- char *tmp = 0;
- ELEMENT *popped;
+ ELEMENT *e;
- /* check whitespaces at the beginning of the line */
- if (strchr (whitespace_chars, *p))
+ if (strchr (whitespace_chars, *line))
{
+ ELEMENT *e;
+ int n = strspn (line, whitespace_chars);
+ e = new_element (ET_raw);
+ text_append_n (&e->text, line, n);
+ add_to_element_contents (current, e);
+ line += n;
line_warn ("@end %s should only appear at the "
"beginning of a line", command_name(end_cmd));
}
- current = current->parent;
-
- /* Remove an ignored block. */
- popped = pop_element_from_contents (current);
- if (popped->cmd != end_cmd)
- fatal ("command mismatch for ignored block");
-
- /* 'line' is now advanced past the "@end ...". Check if
- there's anything after it. */
- p = line + strspn (line, whitespace_chars);
- if (*p && *p != '@')
- goto superfluous_arg;
- if (*p)
- {
- p++;
- tmp = read_command_name (&p);
- if (tmp && (!strcmp (tmp, "c") || !strcmp (tmp, "comment")))
- {
- }
- else if (*p && p[strspn (p, whitespace_chars)])
- {
-superfluous_arg:
- line_warn ("superfluous argument to @end %s: %s",
- command_name(end_cmd), line);
- }
- free (tmp);
- }
+ debug ("CLOSED conditional %s", command_name(end_cmd));
- /* Ignore until end of line */
- if (!strchr (line, '\n'))
- {
- line = new_line ();
- debug ("IGNORE CLOSE LINE");
- }
- destroy_element_and_children (popped);
+ e = new_element (ET_empty_line);
+ add_to_element_contents (current, e);
- debug ("CLOSED conditional %s", command_name(end_cmd));
}
- /* anything remaining on the line and any other line is ignored here */
- retval = GET_A_NEW_LINE;
- goto funexit;
+ else
+ {
+ ELEMENT *e = new_element (ET_raw);
+ text_append (&(e->text), line);
+ add_to_element_contents (current, e);
+ retval = GET_A_NEW_LINE;
+ goto funexit;
+ }
} /********* (ignored) BLOCK_conditional *************/
/* Check if parent element is 'verb' */
else if (current->parent && current->parent->cmd == CM_verb)
{
- char c;
+ char *delimiter;
char *q;
KEY_PAIR *k;
- k = lookup_extra (current->parent, "delimiter");
+ k = lookup_info (current->parent, "delimiter");
- c = *(char *)k->value;
- if (c)
+ delimiter = (char *)k->value;
+ if (strcmp (delimiter, ""))
{
/* Look forward for the delimiter character followed by a close
brace. */
q = line;
while (1)
{
- q = strchr (q, c);
- if (!q || q[1] == '}')
+ q = strstr (q, delimiter);
+ if (!q || q[strlen(delimiter)] == '}')
break;
- q++;
+ q += strlen(delimiter);
}
}
else
@@ -1325,8 +1630,8 @@ superfluous_arg:
add_to_element_contents (current, e);
}
debug ("END VERB");
- if (c)
- line = q + 1;
+ if (strcmp (delimiter, ""))
+ line = q + strlen (delimiter);
else
line = q;
/* The '}' will close the @verb command in handle_separator below. */
@@ -1347,34 +1652,50 @@ superfluous_arg:
&& command_data(current->cmd).data == BLOCK_format_raw
&& !format_expanded_p (command_name(current->cmd)))
{
- ELEMENT *e;
+ ELEMENT *e_elided_rawpreformatted;
+ ELEMENT *e_empty_line;
enum command_id dummy;
char *line_dummy;
int n;
- e = new_element (ET_elided_block);
- add_to_element_contents (current, e);
+ e_elided_rawpreformatted = new_element (ET_elided_rawpreformatted);
+ add_to_element_contents (current, e_elided_rawpreformatted);
line_dummy = line;
- while (!is_end_current_command (current, &line_dummy,
- &dummy))
+ while (1)
{
- line = new_line ();
if (!line)
{
- line = "";
- break;
+ /* unclosed block */
+ goto funexit;
+ }
+ else
+ {
+ line_dummy = line;
+ if (is_end_current_command (current, &line_dummy,
+ &dummy))
+ {
+ debug ("CLOSED ignored raw preformated %s",
+ command_name(current->cmd));
+ break;
+ }
+ else
+ {
+ ELEMENT *raw_text = new_element (ET_raw);
+ text_append (&(raw_text->text), line);
+ add_to_element_contents (e_elided_rawpreformatted, raw_text);
+ }
}
- line_dummy = line;
+ line = new_line (e_elided_rawpreformatted);
}
/* 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. */
- e = new_element (ET_empty_line);
- add_to_element_contents (current, e);
+ e_empty_line = new_element (ET_empty_line);
+ add_to_element_contents (current, e_empty_line);
n = strspn (line, whitespace_chars_except_newline);
- text_append_n (&e->text, line, n);
+ text_append_n (&e_empty_line->text, line, n);
line += n;
/* 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 */
@@ -1386,65 +1707,56 @@ superfluous_arg:
/* There are cases when we need more input, but we don't want to
get it in the top-level loop in parse_texi - this is mostly
(always?) when we don't want to start a new, empty line, and
- need to get more from the current, incomplete line of input. */
+ need to get more from the current, incomplete line of input.
+ Also, this ensures that the line cannot be empty in parsing below
+ */
while (*line == '\0')
{
static char *allocated_text;
- debug ("EMPTY TEXT");
+ debug_nonl ("EMPTY TEXT in: ");
+ debug_print_element (current, 0); debug ("");
/* Each place we supply Texinfo input we store the supplied
input in a static variable like allocated_text, to prevent
memory leaks. */
free (allocated_text);
- line = allocated_text = next_text ();
+ line = allocated_text = next_text (current);
if (!line)
{
- /* TODO: Can this only happen at end of file? */
- current = end_line (current);
- retval = GET_A_NEW_LINE;
+ /* End of the file or of a text fragment. */
+ debug ("NO MORE LINE for empty text");
goto funexit;
}
}
if (*line == '@')
{
+ int single_char;
line_after_command = line + 1;
- /* List of single character Texinfo commands. */
- if (strchr ("([\"'~@&}{,.!?"
- " \f\n\r\t"
- "*-^`=:|/\\",
- *line_after_command))
+ command = parse_command_name (&line_after_command, &single_char);
+ if (command)
{
- char single_char[2];
- single_char[0] = *line_after_command++;
- single_char[1] = '\0';
- cmd = lookup_command (single_char);
+ cmd = lookup_command (command);
+ /* known command */
+ if (cmd)
+ free (command);
+ /* command holds the unknown command name if !cmd && command */
}
else
{
- command = read_command_name (&line_after_command);
-
- cmd = 0;
- if (command)
- {
- cmd = lookup_command (command);
- /* known command */
- if (cmd)
- {
- free (command);
- }
- /* command holds the unknown command name if !cmd && command */
- }
- else
- {
- /* @ was followed by gibberish. "unexpected @" is printed
- below. */
- }
+ /* @ was followed by gibberish or by nothing, for instance at the
+ very end of a string/file. */
+ line_error ("unexpected @");
+ line = line_after_command;
+ goto funexit;
}
if (cmd && (command_data(cmd).flags & CF_ALIAS))
- cmd = command_data(cmd).data;
+ {
+ from_alias = cmd;
+ cmd = command_data(cmd).data;
+ }
}
/* Handle user-defined macros before anything else because their expansion
@@ -1452,13 +1764,28 @@ superfluous_arg:
if (cmd && (command_data(cmd).flags & CF_MACRO))
{
static char *allocated_line;
+
line = line_after_command;
- current = handle_macro (current, &line, cmd);
- free (allocated_line);
- allocated_line = next_text ();
- line = allocated_line;
- retval = STILL_MORE_TO_PROCESS;
- goto funexit;
+ macro_call_element = handle_macro (current, &line, cmd);
+ if (macro_call_element)
+ {
+ if (from_alias != CM_NONE)
+ add_info_string_dup (macro_call_element, "alias_of",
+ command_name (from_alias));
+
+ /* directly get the following input (macro expansion text) instead
+ of going through the next call of process_remaining_on_line and
+ the processing of empty text. No difference in output, more
+ efficient.
+ */
+
+ free (allocated_line);
+ allocated_line = next_text (current);
+ line = allocated_line;
+ goto funexit;
+ }
+ else
+ goto funexit;
}
/* expand value if it actually expands and changes the line. It is
considered again together with other commands below for all the other cases
@@ -1466,39 +1793,85 @@ superfluous_arg:
and early value expansion may be needed to provide with an argument. */
else if (cmd == CM_value)
{
- char *expanded_line = line_after_command;
+ char *remaining_line = line_after_command;
+ ELEMENT *spaces_element = 0;
if (conf.ignore_space_after_braced_command_name)
- expanded_line += strspn (expanded_line, whitespace_chars);
- if (*expanded_line == '{')
+ {
+ int whitespaces_len = strspn (remaining_line, whitespace_chars);
+ if (whitespaces_len > 0)
+ {
+ spaces_element = new_element (ET_NONE);
+ text_append_n (&(spaces_element->text),
+ remaining_line, whitespaces_len);
+ remaining_line += whitespaces_len;
+ }
+ }
+ if (*remaining_line == '{')
{
char *flag;
- expanded_line++;
- flag = read_flag_name (&expanded_line);
+ remaining_line++;
+ flag = read_flag_name (&remaining_line);
if (flag)
{
- if (*expanded_line == '}')
+ if (*remaining_line == '}')
{
char *value;
value = fetch_value (flag);
if (value)
{
- expanded_line++; /* past '}' */
- input_push_text (strdup (expanded_line), current_source_info.macro);
- input_push_text (strdup (value), current_source_info.macro);
+ SOURCE_MARK *value_source_mark;
+ ELEMENT *sm_value_element;
+
+ remaining_line++; /* past '}' */
+ if (conf.max_macro_call_nesting
+ && value_expansion_nr >= conf.max_macro_call_nesting)
+ {
+ line_warn (
+ "value call nested too deeply "
+ "(set MAX_MACRO_CALL_NESTING to override; current value %d)",
+ conf.max_macro_call_nesting);
+ free (flag);
+ if (spaces_element)
+ destroy_element (spaces_element);
+ line = remaining_line;
+ goto funexit;
+ }
+
+ input_push_text (strdup (remaining_line),
+ current_source_info.line_nr, 0, 0);
+ input_push_text (strdup (value),
+ current_source_info.line_nr, 0,
+ strdup (flag));
+
+ value_source_mark
+ = new_source_mark (SM_type_value_expansion);
+ value_source_mark->status = SM_status_start;
+ value_source_mark->line = strdup(value);
+ sm_value_element = new_value_element (cmd, flag, spaces_element);
+ value_source_mark->element = sm_value_element;
+
+ register_source_mark (current, value_source_mark);
+ set_input_source_mark (value_source_mark);
+
+ value_expansion_nr++;
/* Move 'line' to end of string so next input to
be processed is taken from input stack. */
- line = expanded_line + strlen (expanded_line);
- retval = STILL_MORE_TO_PROCESS;
+ line = remaining_line + strlen (remaining_line);
}
- free (flag);
if (value)
- goto funexit;
+ {
+ free (flag);
+ goto funexit;
+ }
}
+ free (flag);
}
}
+ if (spaces_element)
+ destroy_element (spaces_element);
}
/* special case for @-command as argument of @itemize or @*table.
@@ -1509,6 +1882,7 @@ superfluous_arg:
Need to be done as early as possible such that no other condition
prevail and lead to a missed command */
if (command_flags(current) & CF_brace && *line != '{'
+ && command_data(current->cmd).data != BRACE_accent
&& parent_of_command_as_argument (current->parent))
{
register_command_as_argument (current);
@@ -1521,35 +1895,62 @@ superfluous_arg:
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. */
+ NOTE the last element in the current command contents is an element that
+ is transiently in the tree, and is put in the info hash by
+ gather_spaces_after_cmd_before_arg. It could therefore be possible
+ to accept an @comment here and put it in this element. It would not
+ necessarily be a good idea, as it would mean having an element
+ in the info hash that holds something more complex than text and source
+ marks.
+ */
if (command_flags(current) & CF_brace && (cmd || command))
{
line_error ("@%s expected braces",
command_name(current->cmd));
+ if (current->contents.number > 0)
+ gather_spaces_after_cmd_before_arg (current);
current = current->parent;
}
/* Handle unknown command. */
- if (!cmd && command)
+ if ((!cmd && command)
+ /* command marked as unknown, normally a registered user-defined command
+ that was set as @alias-ed but has not been defined since, or
+ that has been removed (with @unmacro) */
+ || (command_data(cmd).flags & CF_UNKNOWN)
+ /* Alias command that did not resolve to a non alias command.
+ This is possible only if the command read was already an alias
+ resolving to cmd and not to a non alias command. In turn,
+ this is possible if there was an error at the time of alias
+ definition (because the alias was defined recursively).
+ */
+ || (command_data(cmd).flags & CF_ALIAS))
{
- ELEMENT *paragraph;
+ char *unknown_cmd;
- line_error ("unknown command `%s'", command);
- debug ("COMMAND (UNKNOWN) %s", command);
- free (command);
- abort_empty_line (&current, 0);
- paragraph = begin_paragraph (current);
- if (paragraph)
- current = paragraph;
+ if (cmd)
+ {
+ unknown_cmd = command_name (cmd);
+ /* Would there be something similar in the perl parser?
+ debug ("COMMAND (REGISTERED UNKNOWN) %d %s", cmd, unknown_cmd);
+ */
+ }
+ else
+ {
+ unknown_cmd = command;
+ /* Would there be something similar in the perl parser?
+ debug ("COMMAND (UNKNOWN) %s", command);
+ */
+ }
+ line_error ("unknown command `%s'", unknown_cmd);
+ if (!cmd)
+ free (command);
line = line_after_command;
- retval = STILL_MORE_TO_PROCESS;
goto funexit;
}
-
+
/* 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
@@ -1559,14 +1960,16 @@ superfluous_arg:
command container. */
if (command_flags(current) & CF_brace && *line != '{')
{
+ debug_nonl ("BRACE CMD: no brace after @%s||| ",
+ command_name (current->cmd));
+ debug_print_protected_string (line); debug ("");
+
if (strchr (whitespace_chars, *line)
&& ((command_flags(current) & CF_accent)
|| conf.ignore_space_after_braced_command_name))
{
- char *p; char *s;
int whitespaces_len;
int additional_newline = 0;
- KEY_PAIR *k;
whitespaces_len = strspn (line, whitespace_chars);
for (int i = 0; i < whitespaces_len; i++)
@@ -1575,92 +1978,158 @@ superfluous_arg:
{
line_warn ("command `@%s' must not be followed by new line",
command_name(current->cmd));
+ if (current_context() == ct_def
+ || current_context() == ct_line)
+ {
+ /* do not consider the end of line to be possibly between
+ the @-command and the argument if at the end of a
+ line or block @-command. */
+ char saved; /* TODO: Have a length argument to merge_text? */
+ if (current->contents.number > 0)
+ gather_spaces_after_cmd_before_arg (current);
+ current = current->parent;
+ saved = line[whitespaces_len];
+ line[whitespaces_len] = '\0';
+ current = merge_text (current, line, 0);
+ line += whitespaces_len;
+ *line = saved;
+ isolate_last_space (current);
+ current = end_line (current);
+ retval = GET_A_NEW_LINE;
+ goto funexit;
+ }
additional_newline = 1;
break;
}
}
- k = lookup_extra (current, "spaces");
- if (!k)
+ /* The added element is only transiently present, it is removed
+ by calls of gather_spaces_after_cmd_before_arg, which transfer
+ the element to the info hash. The contents allow to have source
+ marks easily associated.
+ The type name is not used anywhere but can be usefull for
+ debugging, in particular to check that the element does not
+ appear anywhere in the tree.
+ Note that contents is transiently set for brace commands, which in
+ general only have args. */
+
+ if (current->contents.number == 0)
{
- p = line + whitespaces_len;
- xasprintf (&s, "%.*s", (int) (p - line), line);
- add_extra_string (current, "spaces", s);
- line = p;
+ ELEMENT *e_spaces_after_cmd_before_arg
+ = new_element (ET_internal_spaces_after_cmd_before_arg);
+ text_append_n (&(e_spaces_after_cmd_before_arg->text),
+ line, whitespaces_len);
+ add_to_element_contents (current, e_spaces_after_cmd_before_arg);
+
+ debug_nonl ("BRACE CMD before brace init spaces '");
+ debug_print_protected_string
+ (e_spaces_after_cmd_before_arg->text.text);
+ debug ("'");
+
+ line += whitespaces_len;
}
else
{
+ /* contents, at this point can only be for spaces_after_cmd_before_arg */
/* only ignore spaces and one newline, two newlines lead to
an empty line before the brace or argument which is incorrect. */
- char *previous_value = (char *) k->value;
+ char *previous_value = current->contents.list[0]->text.text;
if (additional_newline && strchr ("\n", *previous_value))
{
+ debug ("BRACE CMD before brace second newline stops spaces");
line_error ("@%s expected braces",
command_name(current->cmd));
+ gather_spaces_after_cmd_before_arg (current);
current = current->parent;
}
else
{
- p = line + whitespaces_len;
- xasprintf (&s, "%s%.*s",
- previous_value,
- (int) (p - line), line);
- free (k->value);
- k->value = (ELEMENT *) s;
- line = p;
+ text_append_n (&(current->contents.list[0]->text),
+ line, whitespaces_len);
+ debug ("BRACE CMD before brace add spaces '%s'",
+ current->contents.list[0]->text.text
+ + strlen(current->contents.list[0]->text.text)
+ - whitespaces_len);
+ line += whitespaces_len;
}
}
}
/* special case for accent commands, use following character except @
* as argument */
else if ((command_flags(current) & CF_accent)
- && *line != '\0' && *line != '@')
+ && *line != '@')
{
ELEMENT *e, *e2;
- debug ("ACCENT");
+ int char_len;
+
+ if (current->contents.number > 0)
+ gather_spaces_after_cmd_before_arg (current);
e = new_element (ET_following_arg);
add_to_element_args (current, e);
+
+ /* Count any UTF-8 continuation bytes. */
+ char_len = 1;
+ while ((line[char_len] & 0xC0) == 0x80)
+ char_len++;
+
e2 = new_element (ET_NONE);
- text_append_n (&e2->text, line, 1);
+ text_append_n (&e2->text, line, char_len);
+ debug ("ACCENT @%s following_arg: %s", command_name(current->cmd),
+ e2->text.text);
add_to_element_contents (e, e2);
if (current->cmd == CM_dotless
&& *line != 'i' && *line != 'j')
{
line_error ("@dotless expects `i' or `j' as argument, "
- "not `%c'", *line);
+ "not `%s'", e2->text.text);
}
- while (current->contents.number > 0)
- destroy_element (pop_element_from_contents (current));
- line++;
+ line += char_len;
current = current->parent;
}
else
{
line_error ("@%s expected braces",
command_name(current->cmd));
+ if (current->contents.number > 0)
+ gather_spaces_after_cmd_before_arg (current);
current = current->parent;
}
}
- else if (handle_menu (&current, &line))
+ else if (handle_menu_entry_separators (&current, &line))
{
- ; /* Nothing - everything was done in handle_menu. */
+ ; /* Nothing - everything was done in handle_menu_entry_separators. */
}
/* Any other @-command. */
else if (cmd)
{
int def_line_continuation;
+ /* command used to get command data. Needed for the multicategory
+ @item command. */
+ enum command_id data_cmd = cmd;
+ ELEMENT *command_element;
+
+ debug ("COMMAND @%s", debug_command_name(cmd));
line = line_after_command;
- debug ("COMMAND %s", command_name(cmd));
/* @value not expanded (expansion is done above), and @txiinternalvalue */
if ((cmd == CM_value) || (cmd == CM_txiinternalvalue))
{
char *arg_start;
char *flag;
+ ELEMENT *spaces_element = 0;
if (conf.ignore_space_after_braced_command_name)
- line += strspn (line, whitespace_chars);
+ {
+ int whitespaces_len = strspn (line, whitespace_chars);
+ if (whitespaces_len > 0)
+ {
+ spaces_element = new_element (ET_NONE);
+ text_append_n (&(spaces_element->text),
+ line, whitespaces_len);
+ line += whitespaces_len;
+ }
+ }
if (*line != '{')
goto value_invalid;
@@ -1673,62 +2142,56 @@ superfluous_arg:
if (*line != '}')
{
line = arg_start - 1;
+ free (flag);
goto value_invalid;
}
if (1) /* @value syntax is valid */
{
char *value;
-value_valid:
+ value_valid:
if (cmd == CM_value)
{
value = fetch_value (flag);
if (!value)
{
/* Add element for unexpanded @value.
- This should be an error, but still leave a tree element
+ This should be an error, but still leave a tree element
for the converters to handle */
ELEMENT *value_elt;
- line_warn ("undefined flag: %s", flag);
-
abort_empty_line (&current, NULL);
- value_elt = new_element (ET_NONE);
- value_elt->cmd = CM_value;
- add_extra_string_dup (value_elt, "flag", flag);
+ line_warn ("undefined flag: %s", flag);
+
+ value_elt = new_value_element (cmd, flag, spaces_element);
add_to_element_contents (current, value_elt);
line++; /* past '}' */
- retval = STILL_MORE_TO_PROCESS;
}
- /* expansion of value already done above
else
{
- value is set
- }
+ if (spaces_element)
+ destroy_element (spaces_element);
+ /* expansion of value already done above
+ value is set
*/
+ }
free (flag);
goto funexit;
}
else
{ /* CM_txiinternalvalue */
- ELEMENT *txiinternalvalue_elt, *txiinternalvalue_arg;
+ ELEMENT *txiinternalvalue_elt;
abort_empty_line (&current, NULL);
- txiinternalvalue_elt = new_element (ET_NONE);
- txiinternalvalue_elt->cmd = CM_txiinternalvalue;
-
- /* FIXME or ET_misc_arg? */
- txiinternalvalue_arg = new_element (ET_NONE);
- text_append (&txiinternalvalue_arg->text, flag);
- add_to_element_args (txiinternalvalue_elt, txiinternalvalue_arg);
+ txiinternalvalue_elt = new_value_element (cmd, flag,
+ spaces_element);
add_to_element_contents (current, txiinternalvalue_elt);
line++; /* past '}' */
- retval = STILL_MORE_TO_PROCESS;
free (flag);
goto funexit;
@@ -1736,9 +2199,10 @@ value_valid:
}
else
{
-value_invalid:
+ value_invalid:
line_error ("bad syntax for @%s", command_name(cmd));
- retval = STILL_MORE_TO_PROCESS;
+ if (spaces_element)
+ destroy_element (spaces_element);
goto funexit;
}
}
@@ -1761,10 +2225,13 @@ value_invalid:
gettext is implemented */
}
+ /* special case with @ followed by a newline protecting end of lines
+ in @def* */
def_line_continuation = (current_context() == ct_def
&& cmd == CM_NEWLINE);
- /* warn on not appearing at line beginning */
- /* TODO maybe have a command flag for "begin line commands" */
+
+ /* warn on not appearing at line beginning. Need to do before closing
+ paragraph as it also closes the empty line */
if (!def_line_continuation
&& !abort_empty_line (&current, NULL)
&& ((cmd == CM_node || cmd == CM_bye)
@@ -1772,58 +2239,42 @@ value_invalid:
|| ((command_data(cmd).flags & CF_line)
&& cmd != CM_comment
&& cmd != CM_c
- && cmd != CM_sp
&& cmd != CM_columnfractions
&& cmd != CM_item
- && cmd != CM_verbatiminclude
- && cmd != CM_set
- && cmd != CM_clear
- && cmd != CM_vskip)
- && cmd != CM_subentry))
+ && cmd != CM_subentry)))
{
- line_warn ("@%s should only appear at the beginning of a line",
+ line_warn ("@%s should only appear at the beginning of a line",
command_name(cmd));
}
- if (current->parent)
- check_valid_nesting (current, cmd);
-
- if (def_line_continuation)
+ if (cmd)
{
- retval = GET_A_NEW_LINE;
- goto funexit;
+ if (command_data(cmd).flags & CF_close_paragraph)
+ current = end_paragraph (current, 0, 0);
+ if (close_preformatted_command (cmd))
+ current = end_preformatted (current, 0, 0);
}
- /* check command doesn't start a paragraph */
- /* TODO store this in cmd->flags. */
- if (!((command_data(cmd).flags & (CF_line | CF_block))
- || (command_data(cmd).flags & CF_nobrace
- && (command_data(cmd).data == NOBRACE_skipspace
- /* FIXME NOBRACE_other should probably start a paragraph
- except for refill */
- || command_data(cmd).data == NOBRACE_other))
- || cmd == CM_titlefont
- || cmd == CM_caption
- || cmd == CM_shortcaption
- || cmd == CM_image
- || cmd == CM_ASTERISK /* @* */
- || cmd == CM_hyphenation
- || cmd == CM_anchor
- || cmd == CM_errormsg
- || (command_data(cmd).flags & CF_index_entry_command)))
+ /* cannot check parent before closing paragraph/preformatted */
+ if (cmd == CM_item && item_line_parent (current))
+ data_cmd = CM_item_LINE;
+
+ if (current->parent)
{
- ELEMENT *paragraph;
- paragraph = begin_paragraph (current);
- if (paragraph)
- current = paragraph;
+ /* NOTE the command name appears in the functions, so it is
+ better to use cmd and not data_cmd. This means that all
+ the checks are done with @item as NOBRACE_skipspace */
+ check_valid_nesting (current, cmd);
+ check_valid_nesting_context (cmd);
}
- if (cmd)
+ if (def_line_continuation)
{
- if (command_data(cmd).flags & CF_close_paragraph)
- current = end_paragraph (current, 0, 0);
- if (close_preformatted_command (cmd))
- current = end_preformatted (current, 0, 0);
+ SOURCE_MARK *line_continuation_source_mark
+ = new_source_mark (SM_type_defline_continuation);
+ register_source_mark (current, line_continuation_source_mark);
+ retval = GET_A_NEW_LINE;
+ goto funexit;
}
if ((cmd == CM_sortas
@@ -1852,99 +2303,134 @@ value_invalid:
}
}
- if (cmd == CM_item && item_line_parent (current))
- cmd = CM_item_LINE;
- /* We could possibly have done this before check_valid_nesting. */
+ /* check command doesn't start a paragraph */
+ if (!(command_data(data_cmd).flags & CF_no_paragraph))
+ {
+ ELEMENT *paragraph;
+ paragraph = begin_paragraph (current);
+ if (paragraph)
+ current = paragraph;
+ }
/* No-brace command */
- if (command_data(cmd).flags & CF_nobrace)
+ if (command_data(data_cmd).flags & CF_nobrace)
{
int status;
- current = handle_other_command (current, &line, cmd, &status);
+ current = handle_other_command (current, &line, cmd, &status,
+ &command_element);
if (status == GET_A_NEW_LINE || status == FINISHED_TOTALLY)
{
retval = status;
- goto funexit;
}
}
- else if (command_data(cmd).flags & CF_line)
+ else if (command_data(data_cmd).flags & CF_line)
{
int status;
- current = handle_line_command (current, &line, cmd, &status);
+ current = handle_line_command (current, &line, cmd, data_cmd, &status,
+ &command_element);
if (status == GET_A_NEW_LINE || status == FINISHED_TOTALLY)
{
retval = status;
- goto funexit;
}
}
- else if (command_data(cmd).flags & CF_block)
+ else if (command_data(data_cmd).flags & CF_block)
{
int new_line = 0;
- current = handle_block_command (current, &line, cmd, &new_line);
+ current = handle_block_command (current, &line, cmd, &new_line,
+ &command_element);
if (new_line)
{
/* For @macro, to get a new line. This is done instead of
doing the EMPTY TEXT code on the next time round. */
retval = GET_A_NEW_LINE;
- goto funexit;
}
}
- else if (command_data(cmd).flags & (CF_brace | CF_accent))
+ else if (command_data(data_cmd).flags & (CF_brace | CF_accent))
{
- current = handle_brace_command (current, &line, cmd);
+ current = handle_brace_command (current, &line, cmd, &command_element);
}
+ if (from_alias != CM_NONE && command_element)
+ {
+ add_info_string_dup (command_element, "alias_of",
+ command_name (from_alias));
+ }
+ }
+ /* "Separator" characters */
+ else if (*line == '{')
+ {
+ line++;
+ current = handle_open_brace (current, &line);
}
- /* "Separator" character */
- else if (*line != '\0' && strchr ("{}@,:\t.\f", *line))
+ else if (*line == '}')
{
+ line++;
+ current = handle_close_brace (current, &line);
+ }
+ else if (*line == ',')
+ {
+ line++;
+ /* comma as a command argument separator */
+ if (counter_value (&count_remaining_args, current->parent) > 0)
+ current = handle_comma (current, &line);
+ else if (current->type == ET_line_arg && current->parent->cmd == CM_node)
+ line_warn ("superfluous arguments for node");
+ else
+ current = merge_text (current, ",", 0);
+ }
+ else if (strchr (":\t.", *line))
+ {
+ /* merge menu separator (other than comma) */
char separator = *line++;
- debug ("SEPARATOR: %c", separator);
- if (separator == '@')
- line_error ("unexpected @");
+ char t[2];
+ t[0] = separator;
+ t[1] = '\0';
+ current = merge_text (current, t, 0);
+ }
+ else if (*line == '\f')
+ {
+ line++;
+ debug_nonl ("FORM FEED in "); debug_print_element (current, 1);
+ debug_nonl (": "); debug_print_protected_string (line); debug ("");
+ if (current->type == ET_paragraph)
+ {
+ ELEMENT *e;
+
+ /* A form feed stops and restarts a paragraph. */
+ current = end_paragraph (current, 0, 0);
+ e = new_element (ET_empty_line);
+ text_append_n (&e->text, "\f", 1);
+ add_to_element_contents (current, e);
+ e = new_element (ET_empty_line);
+ add_to_element_contents (current, e);
+ }
else
- current = handle_separator (current, separator, &line);
+ current = merge_text (current, "\f", 0);
}
- /* "Misc text except end of line." */
- else if (*line && *line != '\n')
+ /* Misc text except end of line. */
+ else if (*line != '\n')
{
size_t len;
-
+
/* Output until next command, separator or newline. */
{
char saved; /* TODO: Have a length argument to merge_text? */
len = strcspn (line, "{}@,:\t.\n\f");
saved = line[len];
line[len] = '\0';
- current = merge_text (current, line);
+ current = merge_text (current, line, 0);
line += len;
*line = saved;
}
-
- retval = STILL_MORE_TO_PROCESS;
- goto funexit;
}
else /* End of line */
{
- if (current->type)
- debug ("END LINE (%s)", element_type_names[current->type]);
- else if (current->cmd)
- debug ("END LINE (@%s)", command_name(current->cmd));
- else
- debug ("END LINE");
- if (current->parent)
- {
- debug_nonl (" <- ");
- if (current->parent->cmd)
- debug_nonl("@%s", command_name(current->parent->cmd));
- if (current->parent->type)
- debug_nonl("(%s)", element_type_names[current->parent->type]);
- debug ("");
- debug ("");
- }
+ debug_nonl ("END LINE ");
+ debug_print_element (current, 1);
+ debug ("");
if (*line == '\n')
{
- current = merge_text (current, "\n");
+ current = merge_text (current, "\n", 0);
line++;
}
else
@@ -1994,26 +2480,26 @@ check_line_directive (char *line)
p += strspn (p, " \t");
/* p should now be at the line number */
- if (!strchr ("0123456789", *p))
+ if (!strchr (digit_chars, *p))
return 0;
line_no = strtoul (p, &p, 10);
p += strspn (p, " \t");
if (*p == '"')
{
- char c;
+ char saved;
p++;
q = strchr (p, '"');
if (!q)
return 0;
- c = *q;
+ saved = *q;
*q = 0;
filename = save_string (p);
- *q = c;
+ *q = saved;
p = q + 1;
p += strspn (p, " \t");
- p += strspn (p, "0123456789");
+ p += strspn (p, digit_chars);
p += strspn (p, " \t");
}
if (*p && *p != '\n')
@@ -2032,14 +2518,18 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
ELEMENT *current = current_elt;
static char *allocated_line;
char *line;
+ int status;
/* Read input file line-by-line. */
while (1)
{
free (allocated_line);
- line = allocated_line = next_text ();
+ line = allocated_line = next_text (current);
if (!allocated_line)
- break; /* Out of input. */
+ {
+ debug ("NEXT_LINE NO MORE");
+ break; /* Out of input. */
+ }
debug_nonl ("NEW LINE %s", line);
@@ -2053,7 +2543,7 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
|| command_data(current->cmd).data == BLOCK_conditional)
|| (command_data(current->cmd).data == BLOCK_format_raw
&& !format_expanded_p (command_name(current->cmd)))))
- || current->parent && current->parent->cmd == CM_verb)
+ || (current->parent && current->parent->cmd == CM_verb))
&& current_context () != ct_def)
{
ELEMENT *e;
@@ -2068,7 +2558,7 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
&& last_contents_child(current)->type
== ET_internal_spaces_before_argument)
{
- /* Remove this element and update 'extra' values. */
+ /* Remove this element and update 'info' values. */
abort_empty_line (&current, 0);
}
@@ -2084,28 +2574,44 @@ parse_texi (ELEMENT *root_elt, ELEMENT *current_elt)
of line. */
while (1)
{
- int status = process_remaining_on_line (&current, &line);
+ status = process_remaining_on_line (&current, &line);
if (status == GET_A_NEW_LINE)
- break;
+ {
+ debug ("GET_A_NEW_LINE");
+ break;
+ }
if (status == FINISHED_TOTALLY)
- goto finished_totally;
+ {
+ debug ("FINISHED_TOTALLY");
+ goto finished_totally;
+ }
if (!line)
{
+ debug ("END LINE in line loop STILL_MORE_TO_PROCESS");
+ abort_empty_line (&current, NULL);
current = end_line (current);
break;
}
}
}
-finished_totally:
+ finished_totally:
/* Check for unclosed conditionals */
while (conditional_number > 0)
{
line_error ("expected @end %s",
- command_name(conditional_stack[conditional_number - 1]));
+ command_name(conditional_stack[conditional_number - 1].command));
conditional_number--;
}
+ /* Check for unclosed raw block commands */
+ while (raw_block_number > 0)
+ {
+ line_error ("expected @end %s",
+ command_name(raw_block_stack[raw_block_number - 1]));
+ raw_block_number--;
+ }
+
{
ELEMENT *dummy;
current = close_commands (current, CM_NONE, &dummy, CM_NONE);
@@ -2117,9 +2623,42 @@ finished_totally:
current = current->parent;
}
- input_reset_input_stack (); /* to avoid a memory leak if @bye is given */
+ if (current_context () != ct_NONE)
+ fatal ("context_stack not empty at the end");
+
+ /* Gather text after @bye */
+ if (line && status == FINISHED_TOTALLY) {
+ ELEMENT *element_after_bye;
+ element_after_bye = new_element (ET_postamble_after_end);
+
+ debug ("GATHER AFTER BYE");
+
+ while (1)
+ {
+ ELEMENT *e;
+ free (allocated_line);
+ line = allocated_line = next_text (element_after_bye);
+ if (!allocated_line)
+ break; /* Out of input. */
+
+ e = new_element (ET_text_after_end);
+ text_append (&e->text, line);
+ add_to_element_contents (element_after_bye, e);
+ }
+ if (element_after_bye->contents.number == 0)
+ destroy_element (element_after_bye);
+ else
+ add_to_element_contents (current, element_after_bye);
+ }
- /* TODO: Check for "unclosed stacks". */
+ if (macro_expansion_nr > 0)
+ fprintf (stderr, "BUG: at end, macro_expansion_nr > 0: %d\n",
+ macro_expansion_nr);
+ if (value_expansion_nr > 0)
+ fprintf (stderr, "BUG: at end, value_expansion_nr > 0: %d\n",
+ value_expansion_nr);
+ if (input_number > 0)
+ fprintf (stderr, "BUG: at end, input_number > 0: %d\n", input_number);
return current;
}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.h
index 7303a53357..4df58346b0 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/parser.h
@@ -1,10 +1,10 @@
-/* parser.h - include many other header files. type declarations.
- declarations for close.c, end_line.c, debug.c, separator.c, parser.c,
+/* parser.h - include many other header files. type declarations.
+ declarations for close.c, end_line.c, separator.c, parser.c,
multitable.c, extra.c and menu.c. */
#ifndef PARSER_H
#define PARSER_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,6 @@
#include "context_stack.h"
#include "commands.h"
#include "handle_commands.h"
-#include "def.h"
#include "errors.h"
#include "counter.h"
#include "macro.h"
@@ -32,8 +31,6 @@
typedef struct GLOBAL_INFO {
char *input_file_name;
- char *input_encoding_name;
- char *input_perl_encoding;
int sections_level;
ELEMENT dircategory_direntry; /* an array of elements */
@@ -71,15 +68,17 @@ typedef struct GLOBAL_INFO {
ELEMENT *smallbook;
/* Arrays of elements */
+ ELEMENT author;
+ ELEMENT detailmenu;
+ ELEMENT floats;
ELEMENT footnotes;
ELEMENT hyphenation;
ELEMENT insertcopying;
+ ELEMENT listoffloats;
+ ELEMENT part;
ELEMENT printindex;
ELEMENT subtitle;
ELEMENT titlefont;
- ELEMENT listoffloats;
- ELEMENT detailmenu;
- ELEMENT part;
ELEMENT allowcodebreaks;
ELEMENT clickstyle;
@@ -106,6 +105,9 @@ typedef struct GLOBAL_INFO {
/* In close.c */
+int is_container_empty (ELEMENT *current);
+void remove_empty_content (ELEMENT *current);
+ELEMENT *close_container (ELEMENT *current);
void close_command_cleanup (ELEMENT *current);
ELEMENT *close_commands (ELEMENT *current, enum command_id closed_block_command,
ELEMENT **closed_element, enum command_id);
@@ -115,13 +117,16 @@ ELEMENT *close_all_style_commands (ELEMENT *current,
ELEMENT *close_current (ELEMENT *current,
enum command_id closed_block_command,
enum command_id interrupting_command);
+ELEMENT *close_brace_command (ELEMENT *current,
+ enum command_id closed_block_command,
+ enum command_id interrupting_command,
+ int missing_brace);
+void close_ignored_block_conditional (ELEMENT *current);
/* In end_line.c */
-NODE_SPEC_EXTRA *parse_node_manual (ELEMENT *node);
ELEMENT *end_line (ELEMENT *current);
-ELEMENT *parse_special_misc_command (char *line, enum command_id cmd,
- int *has_commment);
-int check_node_label (NODE_SPEC_EXTRA *nse, enum command_id cmd);
+ELEMENT *end_line_misc_line (ELEMENT *current);
+ELEMENT *end_line_starting_block (ELEMENT *current);
typedef struct {
char *type;
@@ -132,19 +137,24 @@ extern FLOAT_RECORD *floats_list;
extern size_t floats_number;
extern size_t floats_space;
-/* In debug.c */
-void debug (char *s, ...);
-void debug_nonl (char *s, ...);
-extern int debug_output;
/* In separator.c */
-ELEMENT *handle_separator (ELEMENT *current, char separator,
- char **line_inout);
+ELEMENT * handle_open_brace (ELEMENT *current, char **line_inout);
+ELEMENT * handle_close_brace (ELEMENT *current, char **line_inout);
+ELEMENT * handle_comma (ELEMENT *current, char **line_inout);
/* In parser.c */
+typedef struct {
+ enum command_id command;
+ SOURCE_MARK *source_mark;
+} CONDITIONAL_STACK_ITEM;
+
+size_t count_convert_u8 (char *text);
+int isascii_alnum (int c);
ELEMENT *parse_texi (ELEMENT *root_elt, ELEMENT *current_elt);
-void push_conditional_stack (enum command_id cond);
-enum command_id pop_conditional_stack (void);
+void push_conditional_stack (enum command_id cond, SOURCE_MARK *source_mark);
+CONDITIONAL_STACK_ITEM *pop_conditional_stack (void);
+CONDITIONAL_STACK_ITEM *top_conditional_stack (void);
extern size_t conditional_number;
ELEMENT *parse_texi_document (void);
int abort_empty_line (ELEMENT **current_inout, char *additional);
@@ -160,8 +170,10 @@ ELEMENT *end_preformatted (ELEMENT *current,
enum command_id closed_block_command,
enum command_id interrupting_command);
char *read_command_name (char **ptr);
+char *read_comment (char *line, int *has_comment);
char *read_flag_name (char **ptr);
-ELEMENT *merge_text (ELEMENT *current, char *text);
+ELEMENT *merge_text (ELEMENT *current, char *text,
+ ELEMENT *transfer_marks_element);
void start_empty_line_after_command (ELEMENT *current, char **line_inout,
ELEMENT *command);
ELEMENT *begin_paragraph (ELEMENT *current);
@@ -173,14 +185,16 @@ void set_documentlanguage_override (char *value);
void set_accept_internalvalue (void);
char *element_type_name (ELEMENT *e);
int check_space_element (ELEMENT *e);
+void gather_spaces_after_cmd_before_arg (ELEMENT *current);
+char *parse_command_name (char **ptr, int *single_char);
/* Return values */
#define GET_A_NEW_LINE 0
#define STILL_MORE_TO_PROCESS 1
#define FINISHED_TOTALLY 2
-
extern const char *whitespace_chars, *whitespace_chars_except_newline;
+extern const char *linecommand_expansion_delimiters;
extern const char *digit_chars;
extern ELEMENT *current_node;
@@ -212,20 +226,20 @@ void gather_previous_item (ELEMENT *current, enum command_id next_command);
void add_extra_element (ELEMENT *e, char *key, ELEMENT *value);
void add_extra_element_oot (ELEMENT *e, char *key, ELEMENT *value);
void add_extra_contents (ELEMENT *e, char *key, ELEMENT *value);
-void add_extra_contents_oot (ELEMENT *e, char *key, ELEMENT *value);
-void add_extra_contents_array (ELEMENT *e, char *key, ELEMENT *value);
void add_extra_text (ELEMENT *e, char *key, ELEMENT *value);
void add_extra_misc_args (ELEMENT *e, char *key, ELEMENT *value);
-void add_extra_node_spec (ELEMENT *e, char *key, NODE_SPEC_EXTRA *value);
-void add_extra_node_spec_array (ELEMENT *, char *, NODE_SPEC_EXTRA **value);
-void add_extra_def_info (ELEMENT *e, char *key, DEF_INFO *value);
-void add_extra_float_type (ELEMENT *e, char *key, EXTRA_FLOAT_TYPE *value);
void add_extra_string (ELEMENT *e, char *key, char *value);
void add_extra_string_dup (ELEMENT *e, char *key, char *value);
void add_extra_integer (ELEMENT *e, char *key, long value);
+void add_info_string (ELEMENT *e, char *key, char *value);
+void add_info_string_dup (ELEMENT *e, char *key, char *value);
+void add_info_element_oot (ELEMENT *e, char *key, ELEMENT *value);
KEY_PAIR *lookup_extra (ELEMENT *e, char *key);
+KEY_PAIR *lookup_info (ELEMENT *e, char *key);
+ELEMENT *lookup_extra_element (ELEMENT *e, char *key);
+ELEMENT *lookup_info_element (ELEMENT *e, char *key);
/* In menus.c */
-int handle_menu (ELEMENT **current_inout, char **line_inout);
-ELEMENT *enter_menu_entry_node (ELEMENT *current);
+int handle_menu_entry_separators (ELEMENT **current_inout, char **line_inout);
+ELEMENT *end_line_menu_entry (ELEMENT *current);
#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/separator.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/separator.c
index dd1c49b60a..64b80bc0a2 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/separator.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/separator.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
#include <stdio.h>
#include "parser.h"
+#include "debug.h"
#include "text.h"
#include "convert.h"
#include "input.h"
@@ -29,13 +30,17 @@ handle_open_brace (ELEMENT *current, char **line_inout)
{
char *line = *line_inout;
- abort_empty_line (&current, NULL);
if (command_flags(current) & CF_brace)
{
enum command_id command;
ELEMENT *arg;
command = current->cmd;
+
+ /* if there is already content it is for spaces_after_cmd_before_arg */
+ if (current->contents.number > 0)
+ gather_spaces_after_cmd_before_arg (current);
+
counter_push (&count_remaining_args, current,
command_data(current->cmd).args_number);
counter_dec (&count_remaining_args);
@@ -43,22 +48,33 @@ handle_open_brace (ELEMENT *current, char **line_inout)
arg = new_element (ET_NONE);
add_to_element_args (current, arg);
current = arg;
+ if (command_data(command).flags & CF_contain_basic_inline)
+ push_command (&nesting_context.basic_inline_stack, command);
if (command == CM_verb)
{
current->type = ET_brace_command_arg;
+ /* the delimiter may be in macro expansion */
+ if (!*line)
+ line = new_line (current);
/* Save the deliminating character in 'type'. */
if (!*line || *line == '\n')
{
line_error ("@verb without associated character");
- add_extra_string_dup (current->parent, "delimiter", "");
+ add_info_string_dup (current->parent, "delimiter", "");
current->parent->type = 0;
}
else
{
- static char c[2];
- c[0] = *line++;
- add_extra_string_dup (current->parent, "delimiter", c);
+ /* Count any UTF-8 continuation bytes. */
+ int char_len = 1;
+ char *delimiter_character;
+ while ((line[char_len] & 0xC0) == 0x80)
+ char_len++;
+ delimiter_character = strndup (line, char_len);
+ add_info_string (current->parent, "delimiter",
+ delimiter_character);
+ line += char_len;
}
}
else if (command_data(command).data == BRACE_context)
@@ -67,6 +83,7 @@ handle_open_brace (ELEMENT *current, char **line_inout)
{
#define float floatxx
ELEMENT *float;
+ nesting_context.caption++;
if (!current->parent->parent
|| current->parent->parent->cmd != CM_float)
{
@@ -99,7 +116,11 @@ handle_open_brace (ELEMENT *current, char **line_inout)
}
}
#undef float
- }
+ }
+ else if (command == CM_footnote)
+ {
+ nesting_context.footnote++;
+ }
/* Add to context stack. */
switch (command)
@@ -151,13 +172,19 @@ handle_open_brace (ELEMENT *current, char **line_inout)
push_context (ct_inlineraw, command);
}
}
- debug ("OPENED");
+ debug_nonl ("OPENED @%s, remaining: %d ",
+ command_name (current->parent->cmd),
+ counter_value (&count_remaining_args, current->parent) > 0 ?
+ counter_value (&count_remaining_args, current->parent) : 0);
+ debug_print_element (current, 0); debug ("");
}
else if (current->parent && (current->parent->cmd == CM_multitable
- || current->parent->type == ET_def_line))
+ || current->parent->type == ET_def_line
+ || current->parent->type == ET_linemacro_call))
{
ELEMENT *b, *e;
- b = new_element (ET_bracketed);
+ abort_empty_line (&current, NULL);
+ b = new_element (ET_bracketed_arg);
add_to_element_contents (current, b);
current = b;
@@ -174,30 +201,30 @@ handle_open_brace (ELEMENT *current, char **line_inout)
}
else if (current->type == ET_rawpreformatted)
{
- ELEMENT *e = new_element (ET_NONE);
- text_append (&e->text, "{");
- add_to_element_contents (current, e);
+ debug ("LONE OPEN BRACE in rawpreformatted");
+ current = merge_text (current, "{", 0);
}
+ /* matching braces accepted in a rawpreformatted, inline raw or
+ math. Note that for rawpreformatted, it can only happen
+ within an @-command as { is simply added as seen just above.
+ */
else if (current_context() == ct_math
|| current_context() == ct_rawpreformatted
|| current_context() == ct_inlineraw)
{
- ELEMENT *b = new_element (ET_bracketed);
+ ELEMENT *b = new_element (ET_balanced_braces);
+ ELEMENT *open_brace = new_element (ET_NONE);
+ abort_empty_line (&current, NULL);
b->source_info = current_source_info;
add_to_element_contents (current, b);
current = b;
- debug ("BRACKETED in math");
+ text_append (&open_brace->text, "{");
+ add_to_element_contents (current, open_brace);
+ debug ("BALANCED BRACES in math/rawpreformatted/inlineraw");
}
else
{
line_error ("misplaced {");
- if (current->contents.number > 0
- && last_contents_child(current)->type
- == ET_internal_spaces_before_argument)
- {
- /* FIXME: Is this right? */
- remove_from_contents (current, 0);
- }
}
*line_inout = line;
@@ -228,35 +255,40 @@ handle_close_brace (ELEMENT *current, char **line_inout)
{
char *line = *line_inout;
- abort_empty_line (&current, NULL);
+ debug ("CLOSE BRACE");
- if (current->type == ET_bracketed)
+ /* For footnote and caption closing, when there is a paragraph inside.
+ This makes the brace command the parent element. */
+ if (current->parent && current->parent->type == ET_brace_command_context
+ && current->type == ET_paragraph)
{
- /* Used in @math */
+ abort_empty_line (&current, NULL);
+ debug ("IN BRACE_COMMAND_CONTEXT end paragraph");
+ current = end_paragraph (current, 0, 0);
+ }
+
+ if (current->type == ET_balanced_braces)
+ {
+ current = merge_text (current, "}", 0);
+ current = current->parent;
+ }
+ else if (current->type == ET_bracketed_arg)
+ {
+ abort_empty_line (&current, NULL);
current = current->parent;
- goto funexit;
}
else if (command_flags(current->parent) & CF_brace)
{
enum command_id closed_command;
- if (command_data(current->parent->cmd).data == BRACE_context)
- {
- if (current->parent->cmd == CM_math)
- {
- if (pop_context () != ct_math)
- fatal ("math context expected");
- }
- else if (pop_context () != ct_brace_command)
- fatal ("context brace command context expected");
- }
+
+ abort_empty_line (&current, NULL);
+
/* determine if trailing spaces are ignored */
- else if (command_data(current->parent->cmd).data == BRACE_arguments)
- {
- isolate_last_space (current);
- }
+ if (command_data(current->parent->cmd).data == BRACE_arguments)
+ isolate_last_space (current);
closed_command = current->parent->cmd;
- debug ("CLOSING(brace) %s", command_data(closed_command).cmdname);
+ debug ("CLOSING(brace) @%s", command_data(closed_command).cmdname);
counter_pop (&count_remaining_args);
if (current->contents.number > 0
@@ -266,30 +298,33 @@ handle_close_brace (ELEMENT *current, char **line_inout)
if (closed_command == CM_anchor)
{
- NODE_SPEC_EXTRA *parsed_anchor;
current->parent->source_info = current_source_info;
- parsed_anchor = parse_node_manual (current);
- if (check_node_label (parsed_anchor, CM_anchor))
+ if (current->contents.number == 0)
+ line_error ("empty argument in @%s",
+ command_name(current->parent->cmd));
+ else
{
- register_label (current->parent, parsed_anchor->node_content);
- if (current_region ())
- add_extra_element (current, "region", current_region ());
- if (parsed_anchor->manual_content)
- destroy_element (parsed_anchor->manual_content);
+ check_register_target_element_label (current, current->parent);
+ if (nesting_context.regions_stack.top > 0)
+ {
+ add_extra_string_dup (current, "element_region",
+ command_name(top_command(&nesting_context.regions_stack)));
+ }
}
- free (parsed_anchor);
}
else if (command_data(closed_command).flags & CF_ref)
{
ELEMENT *ref = current->parent;
if (ref->args.number > 0)
{
- if ((closed_command == CM_inforef
+ int link_or_inforef = (closed_command == CM_link
+ || closed_command == CM_inforef);
+ if ((link_or_inforef
&& (ref->args.number <= 0
|| ref->args.list[0]->contents.number == 0)
&& (ref->args.number <= 2
|| ref->args.list[2]->contents.number == 0))
- || (closed_command != CM_inforef
+ || (!link_or_inforef
&& (ref->args.number <= 0
|| ref->args.list[0]->contents.number == 0)
&& (ref->args.number <= 3
@@ -302,28 +337,42 @@ handle_close_brace (ELEMENT *current, char **line_inout)
}
else
{
- NODE_SPEC_EXTRA *nse;
- nse = parse_node_manual (args_child_by_index (ref, 0));
- if (nse && (nse->manual_content || nse->node_content))
- add_extra_node_spec (ref, "node_argument", nse);
+ ELEMENT *arg_label = args_child_by_index (ref, 0);
+ NODE_SPEC_EXTRA *ref_label_info = parse_node_manual (arg_label, 1);
+
+ if (ref_label_info && (ref_label_info->manual_content
+ || ref_label_info->node_content))
+ {
+ if (ref_label_info->node_content)
+ add_extra_contents (arg_label, "node_content",
+ ref_label_info->node_content);
+ if (ref_label_info->manual_content)
+ add_extra_contents (arg_label, "manual_content",
+ ref_label_info->manual_content);
+ }
else
{
- if (nse->manual_content)
- destroy_element (nse->manual_content);
- if (nse->node_content)
- destroy_element (nse->node_content);
- free (nse);
+ if (ref_label_info->manual_content)
+ destroy_element (ref_label_info->manual_content);
+ if (ref_label_info->node_content)
+ destroy_element (ref_label_info->node_content);
}
- if (closed_command != CM_inforef
- && (ref->args.number <= 3
- || ref->args.number <= 4
- && ref->args.list[3]->contents.number == 0
- || (ref->args.list[3]->contents.number == 0
- && ref->args.list[4]->contents.number == 0))
- && !nse->manual_content)
+ if ((!link_or_inforef
+ && (ref->args.number <= 3
+ || (ref->args.number <= 4
+ && ref->args.list[3]->contents.number == 0)
+ || (ref->args.list[3]->contents.number == 0
+ && ref->args.list[4]->contents.number == 0))
+ && !ref_label_info->manual_content)
+ || (link_or_inforef
+ && (ref->args.number <= 2
+ || ref->args.list[2]->contents.number == 0)))
{
+ /* we use the @*ref command here and not the label
+ command to have more information for messages */
remember_internal_xref (ref);
}
+ free (ref_label_info);
}
if (ref->args.number > 1
@@ -333,7 +382,7 @@ handle_close_brace (ELEMENT *current, char **line_inout)
{
char *texi = 0;
if (ref->args.list[1])
- texi = convert_to_texinfo (ref->args.list[1]);
+ texi = convert_contents_to_texinfo (ref->args.list[1]);
line_warn ("in @%s empty cross reference name "
"after expansion `%s'",
@@ -343,7 +392,7 @@ handle_close_brace (ELEMENT *current, char **line_inout)
}
}
- if (closed_command != CM_inforef
+ if (!link_or_inforef
&& ref->args.number > 2
&& ref->args.list[2]->contents.number > 0)
{
@@ -351,7 +400,7 @@ handle_close_brace (ELEMENT *current, char **line_inout)
{
char *texi = 0;
if (ref->args.list[2])
- texi = convert_to_texinfo (ref->args.list[2]);
+ texi = convert_contents_to_texinfo (ref->args.list[2]);
line_warn ("in @%s empty cross reference title "
"after expansion `%s'",
@@ -370,9 +419,9 @@ handle_close_brace (ELEMENT *current, char **line_inout)
{
line_error ("@image missing filename argument");
}
- if (global_info.input_perl_encoding)
- add_extra_string_dup (image, "input_perl_encoding",
- global_info.input_perl_encoding);
+ if (global_input_encoding_name)
+ add_extra_string_dup (image, "input_encoding_name",
+ global_input_encoding_name);
}
else if (closed_command == CM_dotless)
{
@@ -499,46 +548,21 @@ handle_close_brace (ELEMENT *current, char **line_inout)
add_to_element_contents (current->parent->parent, e);
}
- current = current->parent->parent;
+ current = close_brace_command (current->parent, 0, 0, 0);
+
if (close_preformatted_command(closed_command))
current = begin_preformatted (current);
} /* CF_brace */
else if (current->type == ET_rawpreformatted)
{
/* lone right braces are accepted in a rawpreformatted */
- ELEMENT *e = new_element (ET_NONE);
- text_append_n (&e->text, "}", 1);
- add_to_element_contents (current, e);
- goto funexit;
- }
- /* context brace command (e.g. @footnote) when there is a paragraph inside */
- else if (current_context() == ct_brace_command)
- {
- current = end_paragraph (current, 0, 0);
- if (current->parent
- && (command_flags(current->parent) & CF_brace)
- && (command_data(current->parent->cmd).data == BRACE_context))
- {
- enum command_id closed_command;
- if (pop_context () != ct_brace_command)
- fatal ("context brace command context expected");
- debug ("CLOSING(context command)");
- closed_command = current->parent->cmd;
- counter_pop (&count_remaining_args);
-
- register_global_command (current->parent);
- current = current->parent->parent;
- if (close_preformatted_command(closed_command))
- current = begin_preformatted (current);
- }
+ current = merge_text (current, "}", 0);
}
else
{
line_error ("misplaced }");
- goto funexit;
}
-
-funexit:
+
*line_inout = line;
return current;
}
@@ -562,7 +586,6 @@ handle_comma (ELEMENT *current, char **line_inout)
{
KEY_PAIR *k;
int expandp = 0;
- debug ("THE INLINE PART");
k = lookup_extra (current, "format");
if (!k)
{
@@ -576,59 +599,67 @@ handle_comma (ELEMENT *current, char **line_inout)
inline_type = arg->text.text;
}
- debug ("INLINE <%s>", inline_type);
if (!inline_type)
{
/* Condition is missing */
debug ("INLINE COND MISSING");
+ add_extra_string (current, "format", 0);
}
- else if (current->cmd == CM_inlineraw
- || current->cmd == CM_inlinefmt
- || current->cmd == CM_inlinefmtifelse)
+ else
{
- if (format_expanded_p (inline_type))
+ debug ("INLINE: %s", inline_type);
+ if (current->cmd == CM_inlineraw
+ || current->cmd == CM_inlinefmt
+ || current->cmd == CM_inlinefmtifelse)
+ {
+ if (format_expanded_p (inline_type))
+ {
+ expandp = 1;
+ add_extra_integer (current, "expand_index", 1);
+ }
+ else
+ expandp = 0;
+ }
+ else if (current->cmd == CM_inlineifset
+ || current->cmd == CM_inlineifclear)
{
- expandp = 1;
- add_extra_integer (current, "expand_index", 1);
+ expandp = 0;
+ if (fetch_value (inline_type))
+ expandp = 1;
+ if (current->cmd == CM_inlineifclear)
+ expandp = !expandp;
+ if (expandp)
+ add_extra_integer (current, "expand_index", 1);
}
else
expandp = 0;
- }
- else if (current->cmd == CM_inlineifset
- || current->cmd == CM_inlineifclear)
- {
- expandp = 0;
- if (fetch_value (inline_type))
- expandp = 1;
- if (current->cmd == CM_inlineifclear)
- expandp = !expandp;
- if (expandp)
- add_extra_integer (current, "expand_index", 1);
- }
- else
- expandp = 0;
- if (inline_type)
- add_extra_string_dup (current, "format", inline_type);
- else
- add_extra_string (current, "format", 0);
+ add_extra_string_dup (current, "format", inline_type);
+ }
/* Skip first argument for a false @inlinefmtifelse */
if (!expandp && current->cmd == CM_inlinefmtifelse)
{
ELEMENT *e;
+ ELEMENT *arg;
int brace_count = 1;
add_extra_integer (current, "expand_index", 2);
- /* Add a dummy argument for the first argument. */
- e = new_element (ET_elided);
+ e = new_element (ET_elided_brace_command_arg);
add_to_element_args (current, e);
+ arg = new_element (ET_raw);
+ text_append (&arg->text, "");
+ add_to_element_contents (e, arg);
/* Scan forward to get the next argument. */
while (brace_count > 0)
{
- line += strcspn (line, "{},");
+ static char *alloc_line;
+ size_t non_separator_len = strcspn (line, "{},");
+ if (non_separator_len > 0)
+ text_append_n (&arg->text, line, non_separator_len);
+ line += non_separator_len;
switch (*line)
{
case ',':
@@ -637,69 +668,90 @@ handle_comma (ELEMENT *current, char **line_inout)
line++;
goto inlinefmtifelse_done;
}
+ text_append_n (&arg->text, line, 1);
break;
case '{':
brace_count++;
+ text_append_n (&arg->text, line, 1);
break;
case '}':
brace_count--;
+ if (brace_count > 0)
+ text_append_n (&arg->text, line, 1);
break;
default:
- line = next_text ();
+ /* at the end of line */
+ free (alloc_line);
+ line = alloc_line = next_text (e);
if (!line)
goto funexit;
continue;
}
line++;
}
-inlinefmtifelse_done:
- /* Check if the second argument is missing. */
+ inlinefmtifelse_done:
+ /* Second argument is missing. */
if (brace_count == 0)
{
+ current = last_args_child (current);
line--; /* on '}' */
+ goto funexit;
}
-
- counter_dec (&count_remaining_args);
+ else
+ counter_dec (&count_remaining_args);
expandp = 1;
}
}
else if (current->cmd == CM_inlinefmtifelse)
{
- /* Second art of @inlinefmtifelse when condition is true. Discard
+ /* Second part of @inlinefmtifelse when condition is true. Discard
second argument. */
expandp = 0;
}
- /* If this command is not being expanded, add a dummy argument, and
+ /* If this command is not being expanded, add an elided argument, and
scan forward to the closing brace. */
if (!expandp)
{
static char *alloc_line;
ELEMENT *e;
+ ELEMENT *arg;
int brace_count = 1;
- e = new_element (ET_elided);
+
+ e = new_element (ET_elided_brace_command_arg);
add_to_element_args (current, e);
+ arg = new_element (ET_raw);
+ text_append (&arg->text, "");
+ add_to_element_contents (e, arg);
+
while (brace_count > 0)
{
- line += strcspn (line, "{}");
+ size_t non_separator_len = strcspn (line, "{}");
+ if (non_separator_len > 0)
+ text_append_n (&arg->text, line, non_separator_len);
+ line += non_separator_len;
switch (*line)
{
case '{':
brace_count++;
+ text_append_n (&arg->text, line, 1);
break;
case '}':
brace_count--;
+ if (brace_count > 0)
+ text_append_n (&arg->text, line, 1);
break;
default:
+ /* at the end of line */
free (alloc_line);
- alloc_line = next_text ();
+ line = alloc_line = next_text (e);
if (!alloc_line)
goto funexit;
- line = alloc_line;
continue;
}
line++;
}
+ counter_dec (&count_remaining_args);
current = last_args_child (current);
line--; /* on '}' */
goto funexit;
@@ -721,70 +773,3 @@ funexit:
return current;
}
-/* Actions to be taken when a special character appears in the input. */
-ELEMENT *
-handle_separator (ELEMENT *current, char separator, char **line_inout)
-{
- char *line = *line_inout;
-
- if (separator == '{')
- {
- current = handle_open_brace (current, &line);
- }
- else if (separator == '}')
- {
- current = handle_close_brace (current, &line);
- }
- /* If a comma is seen after all the arguments for the command have been
- read, it is included in the last argument. */
- else if (separator == ','
- && counter_value (&count_remaining_args, current->parent) > 0)
- {
- current = handle_comma (current, &line);
- }
- else if (separator == ',' && current->type == ET_line_arg
- && current->parent->cmd == CM_node)
- {
- line_warn ("superfluous arguments for node");
- }
- /* After a separator in a menu. */
- else if ((separator == ','
- || separator == '\t'
- || separator == '.')
- && current->type == ET_menu_entry_node
- || separator == ':' && current->type == ET_menu_entry_name)
- {
- ELEMENT *e;
-
- current = current->parent;
- e = new_element (ET_menu_entry_separator);
- text_append_n (&e->text, &separator, 1);
- add_to_element_args (current, e);
-
- /* Note in 'handle_menu' in menus.c, if a '.' is not followed by
- whitespace, we revert was was done here. */
- }
- else if (separator == '\f' && current->type == ET_paragraph)
- {
- ELEMENT *e;
-
- /* A form feed stops and restarts a paragraph. */
- current = end_paragraph (current, 0, 0);
- e = new_element (ET_empty_line);
- text_append_n (&e->text, "\f", 1);
- add_to_element_contents (current, e);
- e = new_element (ET_empty_line);
- add_to_element_contents (current, e);
- }
- else
- {
- /* Default - merge the character as usual. */
- char t[2];
- t[0] = separator;
- t[1] = '\0';
- current = merge_text (current, t);
- }
-
- *line_inout = line;
- return current;
-}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.c
new file mode 100644
index 0000000000..ce3aab5fce
--- /dev/null
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.c
@@ -0,0 +1,272 @@
+/* Copyright 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <string.h>
+
+#include "parser.h"
+#include "debug.h"
+#include "source_marks.h"
+#include "tree.h"
+#include "errors.h"
+
+int include_counter = 0;
+int setfilename_counter = 0;
+int delcomment_counter = 0;
+int defline_continuation_counter = 0;
+int macro_expansion_counter = 0;
+int linemacro_expansion_counter = 0;
+int value_expansion_counter = 0;
+int ignored_conditional_block_counter = 0;
+int expanded_conditional_command_counter = 0;
+
+/* it isn't much readable to use here the SM_TYPES_LIST macro defined
+ in a header file, but the table should be allocated in files using
+ it only if static (or in only one file if extern) */
+static char *source_marks_names[SM_type_expanded_conditional_command + 1] =
+{
+ #define sm_type(name) [SM_type_ ## name] = #name,
+ SM_TYPES_LIST
+ #undef sm_type
+};
+
+char *
+source_mark_name(enum source_mark_type type)
+{
+ return source_marks_names[type];
+}
+
+SOURCE_MARK *
+new_source_mark (enum source_mark_type type)
+{
+ SOURCE_MARK *source_mark = malloc (sizeof (SOURCE_MARK));
+
+ /* Zero all elements */
+ memset (source_mark, 0, sizeof (*source_mark));
+
+ source_mark->type = type;
+ source_mark->counter = -1;
+ source_mark->status = SM_status_none;
+ return source_mark;
+}
+
+void
+add_source_mark (SOURCE_MARK *source_mark, ELEMENT *e)
+{
+ SOURCE_MARK_LIST *s_mark_list = &(e->source_mark_list);
+ if (s_mark_list->number == s_mark_list->space)
+ {
+ s_mark_list->space++; s_mark_list->space *= 1.5;
+ s_mark_list->list = realloc (s_mark_list->list,
+ s_mark_list->space * sizeof (SOURCE_MARK));
+ if (!s_mark_list->list)
+ fatal ("realloc failed");
+ }
+ s_mark_list->list[s_mark_list->number] = source_mark;
+ s_mark_list->number++;
+}
+
+void
+transfer_source_marks (ELEMENT *from_e, ELEMENT *e)
+{
+ SOURCE_MARK_LIST *source_mark_list = &(from_e->source_mark_list);
+ if (source_mark_list->number)
+ {
+ int i;
+ for (i = 0; i < source_mark_list->number; i++)
+ {
+ add_source_mark (source_mark_list->list[i], e);
+ }
+ source_mark_list->number = 0;
+ }
+}
+
+/* ELEMENT should be the parent container. */
+void
+place_source_mark (ELEMENT *e, SOURCE_MARK *source_mark)
+{
+ ELEMENT *mark_element;
+ /* for debug string */
+ char *add_element_string = "no-add";
+
+ source_mark->position = 0;
+ if (e->contents.number > 0)
+ {
+ ELEMENT *last_child = last_contents_child (e);
+ mark_element = last_child;
+ if (last_child->text.end > 0)
+ source_mark->position = count_convert_u8 (last_child->text.text);
+ }
+ else
+ {
+ /* add an empty element only used for source marks */
+ mark_element = new_element (ET_NONE);
+ /* set empty text to have merge_text work as expected */
+ text_append (&mark_element->text, "");
+ add_to_element_contents (e, mark_element);
+ add_element_string = "add";
+ }
+
+ debug_nonl ("MARK %s c: %d p: %d %s %s ", source_mark_name(source_mark->type),
+ source_mark->counter, source_mark->position,
+ source_mark->status == SM_status_start ? "start"
+ : source_mark->status == SM_status_end ? "end"
+ : "UNDEF", add_element_string);
+ debug_print_element(mark_element, 0); debug_nonl (" ");
+ debug_print_element(e, 0); debug ("");
+
+ add_source_mark (source_mark, mark_element);
+}
+
+/* ELEMENT should be the parent container. */
+void
+register_source_mark (ELEMENT *e, SOURCE_MARK *source_mark)
+{
+ if (source_mark->counter == -1)
+ {
+ if (source_mark->type == SM_type_include)
+ {
+ include_counter++;
+ source_mark->counter = include_counter;
+ }
+ else if (source_mark->type == SM_type_setfilename)
+ {
+ setfilename_counter++;
+ source_mark->counter = setfilename_counter;
+ }
+ else if (source_mark->type == SM_type_delcomment)
+ {
+ delcomment_counter++;
+ source_mark->counter = delcomment_counter;
+ }
+ else if (source_mark->type == SM_type_defline_continuation)
+ {
+ defline_continuation_counter++;
+ source_mark->counter = defline_continuation_counter;
+ }
+ else if (source_mark->type == SM_type_macro_expansion)
+ {
+ macro_expansion_counter++;
+ source_mark->counter = macro_expansion_counter;
+ }
+ else if (source_mark->type == SM_type_linemacro_expansion)
+ {
+ linemacro_expansion_counter++;
+ source_mark->counter = linemacro_expansion_counter;
+ }
+ else if (source_mark->type == SM_type_value_expansion)
+ {
+ value_expansion_counter++;
+ source_mark->counter = value_expansion_counter;
+ }
+ else if (source_mark->type == SM_type_ignored_conditional_block)
+ {
+ ignored_conditional_block_counter++;
+ source_mark->counter = ignored_conditional_block_counter;
+ }
+ else if (source_mark->type == SM_type_expanded_conditional_command)
+ {
+ expanded_conditional_command_counter++;
+ source_mark->counter = expanded_conditional_command_counter;
+ }
+ }
+
+ place_source_mark (e, source_mark);
+}
+
+void
+source_marks_reset_counters (void)
+{
+ include_counter = 0;
+ setfilename_counter = 0;
+ delcomment_counter = 0;
+ defline_continuation_counter = 0;
+ macro_expansion_counter = 0;
+ linemacro_expansion_counter = 0;
+ value_expansion_counter = 0;
+ ignored_conditional_block_counter = 0;
+ expanded_conditional_command_counter = 0;
+}
+
+SOURCE_MARK *
+remove_from_source_mark_list (SOURCE_MARK_LIST *list, int where)
+{
+ SOURCE_MARK *removed;
+
+ if (where < 0)
+ where = list->number + where;
+
+ if (where < 0 || where > list->number)
+ fatal ("source marks list index out of bounds");
+
+ removed = list->list[where];
+ memmove (&list->list[where], &list->list[where + 1],
+ (list->number - (where+1)) * sizeof (SOURCE_MARK *));
+ list->number--;
+ return removed;
+}
+
+/* relocate SOURCE_MARKS source marks with position between
+ BEGIN_POSITION and BEGIN_POSITION + LEN to be relative to BEGIN_POSITION,
+ and move to element E.
+ Returns BEGIN_POSITION + LEN if there were source marks.
+*/
+size_t
+relocate_source_marks (SOURCE_MARK_LIST *source_mark_list, ELEMENT *new_e,
+ size_t begin_position, size_t len)
+{
+ int i = 0;
+ int j;
+ int list_number = source_mark_list->number;
+ int *indices_to_remove;
+ size_t end_position;
+
+ if (list_number == 0)
+ return 0;
+
+ end_position = begin_position + len;
+
+ indices_to_remove = malloc (sizeof(int) * list_number);
+ memset (indices_to_remove, 0, sizeof(int) * list_number);
+
+ while (i < list_number)
+ {
+ SOURCE_MARK *source_mark
+ = source_mark_list->list[i];
+ if ((begin_position == 0 && source_mark->position == 0)
+ || (source_mark->position > begin_position
+ && source_mark->position <= end_position))
+ {
+ indices_to_remove[i] = 1;
+ source_mark->position
+ = source_mark->position - begin_position;
+ add_source_mark (source_mark, new_e);
+ }
+ i++;
+ if (source_mark->position > end_position)
+ break;
+ }
+ /* i is past the last index with a potential source mark to remove
+ (to be ready for the next pass in the loop above). So remove one */
+ for (j = i - 1; j >= 0; j--)
+ {
+ if (indices_to_remove[j] == 1)
+ remove_from_source_mark_list (source_mark_list, j);
+ }
+
+ free (indices_to_remove);
+ return end_position;
+}
+
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.h
new file mode 100644
index 0000000000..a1a0cbd020
--- /dev/null
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/source_marks.h
@@ -0,0 +1,31 @@
+/* source_marks.h - declarations for source_marks.c */
+#ifndef SOURCE_MARKS_H
+#define SOURCE_MARKS_H
+/* Copyright 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "tree_types.h"
+
+SOURCE_MARK *new_source_mark (enum source_mark_type type);
+void register_source_mark (ELEMENT *e, SOURCE_MARK *source_mark);
+void source_marks_reset_counters (void);
+void transfer_source_marks (ELEMENT *from_e, ELEMENT *e);
+void add_source_mark (SOURCE_MARK *source_mark, ELEMENT *e);
+void place_source_mark (ELEMENT *e, SOURCE_MARK *source_mark);
+size_t relocate_source_marks (SOURCE_MARK_LIST *source_mark_list, ELEMENT *new_e,
+ size_t previous_position, size_t current_position);
+
+
+#endif
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.c
index 7427560c5f..43310b0130 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.c
@@ -1,4 +1,4 @@
-/* Copyright 2014-2022 Free Software Foundation, Inc.
+/* Copyright 2014-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.h
index 11ea682aea..402181f64e 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/text.h
@@ -1,7 +1,7 @@
/* text.h - declarations for text.c */
#ifndef TEXT_H
#define TEXT_H
-/* Copyright 2014-2021 Free Software Foundation, Inc.
+/* Copyright 2014-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.c b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.c
index f1b64742d9..f2d69e0454 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.c
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.c
@@ -1,4 +1,4 @@
-/* Copyright 2010-2019 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,140 +16,139 @@
#include <config.h>
#include <stdlib.h>
#include <string.h>
+#include "obstack.h"
#include "errors.h"
#include "tree.h"
+#include "source_marks.h"
+/* for debug */
+#include "parser.h"
-//int element_counter;
+static struct obstack obs_element;
+static int *obs_element_first = 0;
+
+/* Used with destroy_element to reuse storage, e.g. from
+ abort_empty_line. Reduces memory use slightly (about 5% from testing)
+ for large manuals. */
+static ELEMENT *spare_element;
+
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+
+void
+reset_obstacks (void)
+{
+ spare_element = 0;
+
+ if (obs_element_first)
+ obstack_free (&obs_element, obs_element_first);
+ else
+ obstack_init (&obs_element);
+
+ obs_element_first = obstack_alloc (&obs_element, sizeof (int));
+}
+
+static ELEMENT *alloc_element (void)
+{
+ ELEMENT *e;
+ e = (ELEMENT *) obstack_alloc (&obs_element, sizeof (ELEMENT));
+ memset (e, 0, sizeof (ELEMENT));
+ return e;
+}
ELEMENT *
new_element (enum element_type type)
{
- ELEMENT *e = malloc (sizeof (ELEMENT));
+ ELEMENT *e;
- //element_counter++;
-
- /* Zero all elements */
- memset (e, 0, sizeof (*e));
+ if (spare_element)
+ {
+ e = spare_element;
+ spare_element = 0;
+ memset (e, 0, sizeof (ELEMENT));
+ }
+ else
+ {
+ e = alloc_element ();
+ /* alloc_element zeroes *e. We assume null pointers have bit
+ representation of all zeroes. */
+ }
e->type = type;
- e->cmd = CM_NONE;
- e->args.list = 0;
- e->args.space = 0;
- e->args.number = 0;
- e->contents.list = 0;
- e->contents.space = 0;
- e->contents.number = 0;
- e->parent = 0;
- e->extra = 0;
return e;
}
void
-destroy_element (ELEMENT *e)
+destroy_associated_info (ASSOCIATED_INFO *a)
{
int i;
- free (e->text.text);
-
- /* Note the pointers in these lists are not themselves freed. */
- free (e->contents.list);
- free (e->args.list);
- for (i = 0; i < e->extra_number; i++)
+ for (i = 0; i < a->info_number; i++)
{
- switch (e->extra[i].type)
+ switch (a->info[i].type)
{
case extra_string:
- case extra_index_entry:
- free (e->extra[i].value);
+ free ((char *) a->info[i].value);
break;
case extra_element_oot:
- destroy_element_and_children (e->extra[i].value);
+ destroy_element_and_children ((ELEMENT *) a->info[i].value);
break;
case extra_contents:
- if (e->extra[i].value)
- destroy_element ((ELEMENT *) e->extra[i].value);
- break;
- case extra_contents_oot:
- {
- /* Only used for 'prototypes' */
- /* Free each element in the array, but not any children
- of each element. */
- int j;
- ELEMENT *array = e->extra[i].value;
- for (j = 0 ; j < array->contents.number; j++)
- {
- if (array->contents.list[j])
- {
- free (array->contents.list[j]->text.text);
- free (array->contents.list[j]);
- }
- }
- destroy_element (array);
- break;
- }
- case extra_contents_array:
- {
- int j;
- ELEMENT *array = e->extra[i].value;
- for (j = 0 ; j < array->contents.number; j++)
- {
- if (array->contents.list[j])
- destroy_element (array->contents.list[j]);
- }
- destroy_element (array);
+ if (a->info[i].value)
+ destroy_element ((ELEMENT *) a->info[i].value);
break;
- }
- case extra_node_spec:
- {
- NODE_SPEC_EXTRA *nse = (NODE_SPEC_EXTRA *) e->extra[i].value;
-
- if (nse->manual_content)
- destroy_element (nse->manual_content);
- if (nse->node_content)
- destroy_element (nse->node_content);
- free (nse);
- break;
- }
- case extra_node_spec_array:
- {
- NODE_SPEC_EXTRA **array = (NODE_SPEC_EXTRA **) e->extra[i].value;
- NODE_SPEC_EXTRA **nse;
-
- for (nse = array; (*nse); nse++)
- {
- if ((*nse)->manual_content)
- destroy_element ((*nse)->manual_content);
- if ((*nse)->node_content)
- destroy_element ((*nse)->node_content);
- free (*nse);
- }
- free (array);
- break;
- }
- case extra_float_type:
- {
- EXTRA_FLOAT_TYPE *eft = (EXTRA_FLOAT_TYPE *) e->extra[i].value;
- free (eft->normalized);
-
- free (eft);
- break;
- }
case extra_misc_args:
- destroy_element_and_children (e->extra[i].value);
- break;
- case extra_def_info:
- free (e->extra[i].value);
+ destroy_element_and_children ((ELEMENT *) a->info[i].value);
break;
default:
break;
}
}
- free (e->extra);
+ free (a->info);
+}
+
+void
+destroy_source_mark (SOURCE_MARK *source_mark)
+{
+ if (source_mark->element)
+ destroy_element_and_children (source_mark->element);
+ if (source_mark->line)
+ free (source_mark->line);
+ free (source_mark);
+}
+
+void
+destroy_source_mark_list (SOURCE_MARK_LIST *source_mark_list)
+{
+ int i;
+ for (i = 0; i < source_mark_list->number; i++)
+ destroy_source_mark (source_mark_list->list[i]);
- free (e);
+ source_mark_list->number = 0;
+ free (source_mark_list->list);
+ source_mark_list->space = 0;
+}
+
+void
+destroy_element (ELEMENT *e)
+{
+ free (e->text.text);
+
+ /* Note the pointers in these lists are not themselves freed. */
+ free (e->contents.list);
+ free (e->args.list);
+
+ destroy_source_mark_list (&(e->source_mark_list));
+
+ destroy_associated_info (&e->extra_info);
+ destroy_associated_info (&e->info_info);
+
+ spare_element = e;
+
+ /* freed in reset_obstacks */
+ /* free (e); */
}
/* Recursively destroy this element and all data in its descendants. */
@@ -301,6 +300,18 @@ remove_from_contents (ELEMENT *parent, int where)
return removed;
}
+/* Remove elements from START inclusive to END exclusive. Do not
+ free any of them. */
+void
+remove_slice_from_contents (ELEMENT *parent, int start, int end)
+{
+ memmove (&parent->contents.list[start],
+ &parent->contents.list[end],
+ (parent->contents.number - end) * sizeof (ELEMENT *));
+
+ parent->contents.number -= (end - start);
+}
+
ELEMENT *
pop_element_from_args (ELEMENT *parent)
@@ -314,8 +325,11 @@ ELEMENT *
pop_element_from_contents (ELEMENT *parent)
{
ELEMENT_LIST *list = &parent->contents;
+ ELEMENT *popped_element = list->list[list->number -1];
- return list->list[--list->number];
+ list->number--;
+
+ return popped_element;
}
ELEMENT *
@@ -359,3 +373,25 @@ args_child_by_index (ELEMENT *e, int index)
return e->args.list[index];
}
+
+/* should only be used if the nse->manual_content
+ and nse->node_content are not already in the tree,
+ in practice when the node spec was created by
+ parse_node_manual (., 0); */
+void
+destroy_node_spec (NODE_SPEC_EXTRA *nse)
+{
+ if (nse->out_of_tree_elements)
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ if (nse->out_of_tree_elements[i])
+ destroy_element (nse->out_of_tree_elements[i]);
+ free (nse->out_of_tree_elements);
+ }
+ if (nse->manual_content)
+ destroy_element (nse->manual_content);
+ if (nse->node_content)
+ destroy_element (nse->node_content);
+ free (nse);
+}
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.h
index acb224abec..6ca91789f0 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree.h
@@ -4,6 +4,9 @@
#include "tree_types.h"
+void reset_obstacks (void);
+
+ASSOCIATED_INFO *new_associated_info (void);
ELEMENT *new_element (enum element_type type);
void add_to_element_contents (ELEMENT *parent, ELEMENT *e);
void add_to_contents_as_array (ELEMENT *parent, ELEMENT *e);
@@ -13,6 +16,7 @@ void insert_into_args (ELEMENT *parent, ELEMENT *e, int where);
void insert_slice_into_contents (ELEMENT *to, int idx, ELEMENT *from,
int start, int end);
ELEMENT *remove_from_contents (ELEMENT *parent, int where);
+void remove_slice_from_contents (ELEMENT *parent, int start, int end);
ELEMENT *last_args_child (ELEMENT *current);
ELEMENT *last_contents_child (ELEMENT *current);
ELEMENT *pop_element_from_args (ELEMENT *parent);
@@ -21,6 +25,7 @@ ELEMENT *contents_child_by_index (ELEMENT *e, int index);
ELEMENT *args_child_by_index (ELEMENT *e, int index);
void destroy_element (ELEMENT *e);
void destroy_element_and_children (ELEMENT *e);
+void destroy_node_spec (NODE_SPEC_EXTRA *nse);
#define element_contents_number(e) ((e)->contents.number)
#define element_args_number(e) ((e)->args.number)
diff --git a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree_types.h b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree_types.h
index 66e84cf956..b6536e8b45 100644
--- a/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree_types.h
+++ b/macros/texinfo/texinfo/tp/Texinfo/XS/parsetexi/tree_types.h
@@ -1,7 +1,7 @@
/* tree_types.h - types for the parse tree that are used in many places */
#ifndef TREE_TYPES_H
#define TREE_TYPES_H
-/* Copyright 2010-2021 Free Software Foundation, Inc.
+/* Copyright 2010-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stdlib.h>
+#include <stdint.h>
#include "command_ids.h"
#include "element_types.h"
@@ -26,24 +27,44 @@ enum extra_type {
extra_element,
extra_element_oot,
extra_contents,
- extra_contents_oot,
- extra_contents_array,
extra_text,
- extra_index_entry,
extra_misc_args,
- extra_node_spec,
- extra_node_spec_array,
extra_string,
extra_integer,
- extra_def_info,
- extra_float_type,
extra_deleted
};
+/* the *_none enums are not necessarily used, they may also
+ be there to avoid using 0, for a code easier to debug */
+
+#define SM_TYPES_LIST \
+ sm_type(none) \
+ sm_type(include) \
+ sm_type(setfilename) \
+ sm_type(delcomment) \
+ sm_type(defline_continuation) \
+ sm_type(macro_expansion) \
+ sm_type(linemacro_expansion) \
+ sm_type(value_expansion) \
+ sm_type(ignored_conditional_block) \
+ sm_type(expanded_conditional_command) \
+
+enum source_mark_type {
+ #define sm_type(name) SM_type_ ## name,
+ SM_TYPES_LIST
+ #undef sm_type
+};
+
+enum source_mark_status {
+ SM_status_none,
+ SM_status_start,
+ SM_status_end,
+};
+
typedef struct KEY_PAIR {
char *key;
enum extra_type type;
- struct ELEMENT *value;
+ intptr_t value;
} KEY_PAIR;
typedef struct ELEMENT_LIST {
@@ -58,23 +79,46 @@ typedef struct SOURCE_INFO {
char *macro;
} SOURCE_INFO;
+typedef struct ASSOCIATED_INFO {
+ KEY_PAIR *info;
+ size_t info_number;
+ size_t info_space;
+} ASSOCIATED_INFO;
+
+typedef struct SOURCE_MARK {
+ enum source_mark_type type;
+ enum source_mark_status status;
+ size_t position;
+ int counter;
+ struct ELEMENT *element; /* needed for elements removed
+ from the tree */
+ char *line; /* used when the information is not available as
+ an element, for DEL comments, for instance */
+} SOURCE_MARK;
+
+typedef struct SOURCE_MARK_LIST {
+ struct SOURCE_MARK **list;
+ size_t number;
+ size_t space;
+} SOURCE_MARK_LIST;
+
typedef struct ELEMENT {
+ /* Used when building Perl tree only. This should be HV *hv,
+ but we don't want to include the Perl headers everywhere; */
+ void *hv;
+
+ enum element_type type;
enum command_id cmd;
TEXT text;
- enum element_type type;
ELEMENT_LIST args;
ELEMENT_LIST contents;
struct ELEMENT *parent;
SOURCE_INFO source_info;
- KEY_PAIR *extra;
- size_t extra_number;
- size_t extra_space;
+ ASSOCIATED_INFO extra_info;
+ ASSOCIATED_INFO info_info;
- /********* Used when building Perl tree only ********************/
- void *hv;
- /* This should be HV *hv, but we don't want to include the Perl headers
- everywhere; */
+ SOURCE_MARK_LIST source_mark_list;
} ELEMENT;
typedef struct IGNORED_CHARS {
@@ -85,19 +129,8 @@ typedef struct IGNORED_CHARS {
} IGNORED_CHARS;
typedef struct {
- char *index_name;
- char *index_prefix;
- enum command_id index_at_command;
- enum command_id index_type_command;
-
- /* content->contents is the index entry text */
- ELEMENT *content;
+ char *index_name; /* kept with the entry as the indices may be merged */
ELEMENT *command;
- ELEMENT *node;
- int number; /* Index of entry in containing index, 1-based. */
- ELEMENT *region;
- char *sortas; /* the sort key for the index */
- IGNORED_CHARS ignored_chars;
} INDEX_ENTRY;
typedef struct INDEX {
@@ -120,20 +153,12 @@ typedef struct INDEX {
typedef struct {
ELEMENT *manual_content;
ELEMENT *node_content;
+ ELEMENT **out_of_tree_elements;
} NODE_SPEC_EXTRA;
-/* For 'def_parsed_hash'. */
-typedef struct {
- ELEMENT *category;
- ELEMENT *class;
- ELEMENT *type;
- ELEMENT *name;
-} DEF_INFO;
-
typedef struct {
- ELEMENT *content;
- char *normalized;
-} EXTRA_FLOAT_TYPE;
-
+ char *arg_type;
+ ELEMENT *element;
+} DEF_ARG;
#endif