texinfo-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

branch master updated: * tp/Texinfo/XS/main/utils.c, tp/Texinfo/XS/main/


From: Patrice Dumas
Subject: branch master updated: * tp/Texinfo/XS/main/utils.c, tp/Texinfo/XS/main/converter_types.h: remove HTML_CSS_FORMATTING_REFERENCES_LIST.
Date: Sat, 04 Nov 2023 19:14:25 -0400

This is an automated email from the git hooks/post-receive script.

pertusus pushed a commit to branch master
in repository texinfo.

The following commit(s) were added to refs/heads/master by this push:
     new a389a0e0d7 * tp/Texinfo/XS/main/utils.c, 
tp/Texinfo/XS/main/converter_types.h: remove 
HTML_CSS_FORMATTING_REFERENCES_LIST.
a389a0e0d7 is described below

commit a389a0e0d76b7ad2ab07df270a0c2081c66d3e76
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sun Nov 5 00:13:11 2023 +0100

    * tp/Texinfo/XS/main/utils.c, tp/Texinfo/XS/main/converter_types.h:
    remove HTML_CSS_FORMATTING_REFERENCES_LIST.
    
    * tp/Texinfo/Convert/HTML.pm (command_text): handle 'cmdname' not set
    to set context string by using the type.
    
    * tp/Texinfo/Convert/HTML.pm (_convert, _convert_style_command)
    (_convert_w_command, _convert_email_command)
    (_convert_explained_command, _convert_uref_command)
    (_convert_image_command, _convert_math_command)
    (_convert_indicateurl_command, _convert_titlefont_command)
    (_convert_U_command), tp/init/html32.pm,
    tp/init/documentation_examples.pm: if there are no arguments for a
    command, pass undef as args.  Update converting functions to account
    for that change.
    
    * tp/Texinfo/Convert/Text.pm (encode_text_options),
    tp/Texinfo/XS/main/get_perl_info.c (get_expanded_formats): pass
    expanded_formats as a hash, never as an array.
    
    * tp/Texinfo/Convert/HTML.pm (_convert_before_item_type): handle undef
    $contents.
    
    * tp/Texinfo/Convert/HTML.pm (_new_document_context)
    (_reset_unset_no_arg_commands_formatting_context),
    tp/Texinfo/XS/convert/convert_html.c (html_new_document_context)
    (reset_unset_no_arg_commands_formatting_context): change in contexts
    names.
    
    * tp/Texinfo/Convert/HTML.pm (convert): set 'current_filename' earlier
    such that it is available in perl codes called by XS.
    
    * tp/Texinfo/Convert/HTML.pm (import, converter_initialize, convert)
    (_finalize_output_state, output), tp/Texinfo/XS/convert/ConvertXS.xs
    (html_initialize_output_state, html_finalize_output_state)
    (html_new_document_context, html_pop_document_context),
    tp/Texinfo/XS/convert/convert_html.c (html_new_document_context)
    (html_pop_document_context, html_converter_initialize)
    (html_finalize_output_state), tp/Texinfo/XS/main/build_perl_info.c
    (build_html_formatting_state), tp/Texinfo/XS/main/command_stack.c
    (html_top_document_context, html_top_formatting_context): add XS
    overrides for _new_document_context.  push the first document context
    in _initialize_output_state, not in converter_initialize, add an
    argument for _initialize_output_state for the context name.  Add
    _finalize_output_state to be called at the end of output, and add an
    XS override to pop the last document context.  Add
    document_contexts_to_pop and document_context_change states to change
    only the document contexts that need to be when passing to perl.
    rename top_document_context as html_top_document_context and
    top_html_formatting_context as html_top_formatting_context.
    
    * tp/Texinfo/XS/convert/convert_html.c (html_gdt_string, html_gdt_tree)
    (html_pgdt_tree): prepend html_ to the function names.
    
    * tp/Texinfo/XS/convert/convert_html.c (html_gdt_string)
    tp/Texinfo/XS/main/build_perl_info.c (build_replaced_substrings),
    tp/Texinfo/XS/main/call_perl_function.c
    (call_formatting_function_format_translate_message_string): add
    strings customization support.
    
    * tp/Texinfo/XS/main/translations.c (translate_string): free langs
    pointers.
    
    * tp/Texinfo/XS/main/translations.c: use const for messages, contexts
    and language aruments.
    
    * tp/Texinfo/Convert/Converter.pm (%common_converters_defaults),
    tp/t/accents.t (test_enable_encoding): add document_descriptor as
    an option in Texinfo::Convert::Converter to retrieve a document even
    if only the descriptor is known, for instance if only the tree is
    available.  Setup state and an XS converter by passing
    tree_document_descriptor as document_descriptor in option in
    accents.t, and by calling _initialize_output_state.
    
    * tp/Texinfo/Convert/HTML.pm (register_file_information)
    (get_file_information, _initialize_output_state): rename
    files_information state as html_files_information.
---
 ChangeLog                               |  81 ++++++++++++
 tp/Texinfo/Convert/Converter.pm         |   3 +
 tp/Texinfo/Convert/HTML.pm              | 218 +++++++++++++++++++++-----------
 tp/Texinfo/Convert/Text.pm              |   6 +-
 tp/Texinfo/Translations.pm              |   8 +-
 tp/Texinfo/XS/convert/ConvertXS.xs      | 106 +++++++++++++++-
 tp/Texinfo/XS/convert/convert_html.c    | 210 +++++++++++++++++++-----------
 tp/Texinfo/XS/convert/convert_html.h    |   8 +-
 tp/Texinfo/XS/main/build_perl_info.c    |  85 ++++++++++++-
 tp/Texinfo/XS/main/build_perl_info.h    |   5 +
 tp/Texinfo/XS/main/call_perl_function.c |  74 +++++++++++
 tp/Texinfo/XS/main/call_perl_function.h |   5 +
 tp/Texinfo/XS/main/command_stack.c      |   4 +-
 tp/Texinfo/XS/main/command_stack.h      |   4 +-
 tp/Texinfo/XS/main/converter_types.h    |  16 +--
 tp/Texinfo/XS/main/get_perl_info.c      |  18 +--
 tp/Texinfo/XS/main/translations.c       |  30 +++--
 tp/Texinfo/XS/main/translations.h       |  16 +--
 tp/Texinfo/XS/main/utils.c              |   6 -
 tp/Texinfo/XS/main/utils.h              |   1 -
 tp/init/documentation_examples.pm       |   5 +-
 tp/init/html32.pm                       |   9 +-
 tp/t/accents.t                          |   8 +-
 23 files changed, 706 insertions(+), 220 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index a07c0769f4..1c7d076cc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,83 @@
+2023-11-04  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/XS/main/utils.c, tp/Texinfo/XS/main/converter_types.h:
+       remove HTML_CSS_FORMATTING_REFERENCES_LIST.
+
+       * tp/Texinfo/Convert/HTML.pm (command_text): handle 'cmdname' not set
+       to set context string by using the type.
+
+       * tp/Texinfo/Convert/HTML.pm (_convert, _convert_style_command)
+       (_convert_w_command, _convert_email_command)
+       (_convert_explained_command, _convert_uref_command)
+       (_convert_image_command, _convert_math_command)
+       (_convert_indicateurl_command, _convert_titlefont_command)
+       (_convert_U_command), tp/init/html32.pm,
+       tp/init/documentation_examples.pm: if there are no arguments for a
+       command, pass undef as args.  Update converting functions to account
+       for that change.
+
+       * tp/Texinfo/Convert/Text.pm (encode_text_options),
+       tp/Texinfo/XS/main/get_perl_info.c (get_expanded_formats): pass
+       expanded_formats as a hash, never as an array.
+
+       * tp/Texinfo/Convert/HTML.pm (_convert_before_item_type): handle undef
+       $contents.
+
+       * tp/Texinfo/Convert/HTML.pm (_new_document_context)
+       (_reset_unset_no_arg_commands_formatting_context),
+       tp/Texinfo/XS/convert/convert_html.c (html_new_document_context)
+       (reset_unset_no_arg_commands_formatting_context): change in contexts
+       names.
+
+       * tp/Texinfo/Convert/HTML.pm (convert): set 'current_filename' earlier
+       such that it is available in perl codes called by XS.
+
+       * tp/Texinfo/Convert/HTML.pm (import, converter_initialize, convert)
+       (_finalize_output_state, output), tp/Texinfo/XS/convert/ConvertXS.xs
+       (html_initialize_output_state, html_finalize_output_state)
+       (html_new_document_context, html_pop_document_context),
+       tp/Texinfo/XS/convert/convert_html.c (html_new_document_context)
+       (html_pop_document_context, html_converter_initialize)
+       (html_finalize_output_state), tp/Texinfo/XS/main/build_perl_info.c
+       (build_html_formatting_state), tp/Texinfo/XS/main/command_stack.c
+       (html_top_document_context, html_top_formatting_context): add XS
+       overrides for _new_document_context.  push the first document context
+       in _initialize_output_state, not in converter_initialize, add an
+       argument for _initialize_output_state for the context name.  Add
+       _finalize_output_state to be called at the end of output, and add an
+       XS override to pop the last document context.  Add
+       document_contexts_to_pop and document_context_change states to change
+       only the document contexts that need to be when passing to perl.
+       rename top_document_context as html_top_document_context and 
+       top_html_formatting_context as html_top_formatting_context.
+
+       * tp/Texinfo/XS/convert/convert_html.c (html_gdt_string, html_gdt_tree)
+       (html_pgdt_tree): prepend html_ to the function names.
+
+       * tp/Texinfo/XS/convert/convert_html.c (html_gdt_string)
+       tp/Texinfo/XS/main/build_perl_info.c (build_replaced_substrings),
+       tp/Texinfo/XS/main/call_perl_function.c
+       (call_formatting_function_format_translate_message_string): add
+       strings customization support.
+
+       * tp/Texinfo/XS/main/translations.c (translate_string): free langs
+       pointers.
+
+       * tp/Texinfo/XS/main/translations.c: use const for messages, contexts
+       and language aruments.
+
+       * tp/Texinfo/Convert/Converter.pm (%common_converters_defaults),
+       tp/t/accents.t (test_enable_encoding): add document_descriptor as
+       an option in Texinfo::Convert::Converter to retrieve a document even
+       if only the descriptor is known, for instance if only the tree is
+       available.  Setup state and an XS converter by passing
+       tree_document_descriptor as document_descriptor in option in
+       accents.t, and by calling _initialize_output_state.
+
+       * tp/Texinfo/Convert/HTML.pm (register_file_information)
+       (get_file_information, _initialize_output_state): rename
+       files_information state as html_files_information.
+
 2023-11-04  Gavin Smith <gavinsmith0123@gmail.com>
 
        * tp/Texinfo/Structuring.pm (import),
@@ -21,6 +101,7 @@
        * tp/Texinfo/XS/Makefile.am: Make files depend on
        maintain/regenerate_C_options_info.pl if built by that script.
 
+
 2023-11-03  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/XS/main/build_perl_info.c (build_html_formatting_state):
diff --git a/tp/Texinfo/Convert/Converter.pm b/tp/Texinfo/Convert/Converter.pm
index 5da319169c..b916f5fa0f 100644
--- a/tp/Texinfo/Convert/Converter.pm
+++ b/tp/Texinfo/Convert/Converter.pm
@@ -111,6 +111,9 @@ my %common_converters_defaults = (
   # Not set in the main program
   'translated_commands'  => {'error' => 'error@arrow{}',},
 
+  # used in tests to have XS data passed to converter
+  'document_descriptor' => undef,
+
 # This is the default, mainly for tests; the caller should set them.  These
 # values are what is used in tests of the Converters.  These variables are
 # customization options, set in the main program when a converter is
diff --git a/tp/Texinfo/Convert/HTML.pm b/tp/Texinfo/Convert/HTML.pm
index 947ec95e2b..68859caf6f 100644
--- a/tp/Texinfo/Convert/HTML.pm
+++ b/tp/Texinfo/Convert/HTML.pm
@@ -49,6 +49,8 @@ use strict;
 #no autovivification qw(fetch delete exists store strict);
 
 use Carp qw(cluck confess);
+# for abort
+#use POSIX;
 
 use File::Copy qw(copy);
 
@@ -107,6 +109,15 @@ sub import {
       "Texinfo::Convert::HTML::_XS_initialize_output_state",
       "Texinfo::Convert::ConvertXS::html_initialize_output_state");
       Texinfo::XSLoader::override(
+      "Texinfo::Convert::HTML::_finalize_output_state",
+      "Texinfo::Convert::ConvertXS::html_finalize_output_state");
+      Texinfo::XSLoader::override(
+      "Texinfo::Convert::HTML::_new_document_context",
+      "Texinfo::Convert::ConvertXS::html_new_document_context");
+      Texinfo::XSLoader::override(
+      "Texinfo::Convert::HTML::_pop_document_context",
+      "Texinfo::Convert::ConvertXS::html_pop_document_context");
+      Texinfo::XSLoader::override(
       "Texinfo::Convert::HTML::_XS_sort_sortable_index_entries_by_letter",
       "Texinfo::Convert::ConvertXS::sort_sortable_index_entries_by_letter");
       Texinfo::XSLoader::override(
@@ -1161,7 +1172,9 @@ sub command_text($$;$)
                                           and $target->{'tree_nonumber'});
     return $tree if ($type eq 'tree' or $type eq 'tree_nonumber');
 
-    $self->_new_document_context($command->{'cmdname'}, $explanation);
+    my $context_name = $command->{'cmdname'};
+    $context_name = $command->{'type'} if (!defined($context_name));
+    $self->_new_document_context($context_name, $explanation);
 
     if ($type eq 'string') {
       $tree = {'type' => '_string',
@@ -1533,11 +1546,13 @@ sub direction_string($$$;$)
       } else {
         $converted_tree = $translated_tree;
       }
+      my $context_str = "DIRECTION $direction ($string_type/$context)";
       # FIXME calling convert_tree_new_formatting_context may remove
       # $self->{'directions_strings'}->{$string_type}->{$direction}, that was
       # set above if not already existing.
-      my $result_string = 
$self->convert_tree_new_formatting_context($converted_tree,
-                             "direction $direction", undef, "direction 
$direction");
+      my $result_string
+         = $self->convert_tree_new_formatting_context($converted_tree,
+                 $context_str, undef, $context_str);
       $self->{'directions_strings'}->{$string_type}->{$direction} = {}
           if (not $self->{'directions_strings'}->{$string_type}->{$direction});
       $self->{'directions_strings'}->{$string_type}->{$direction}->{$context}
@@ -1835,9 +1850,14 @@ sub register_file_information($$;$)
   my $key = shift;
   my $value = shift;
 
-  $self->{'files_information'}->{$self->{'current_filename'}} = {}
-    if (!$self->{'files_information'}->{$self->{'current_filename'}});
-  $self->{'files_information'}->{$self->{'current_filename'}}->{$key} = $value;
+  if (!defined ($self->{'current_filename'})) {
+    cluck();
+  }
+
+  $self->{'html_files_information'}->{$self->{'current_filename'}} = {}
+    if (!$self->{'html_files_information'}->{$self->{'current_filename'}});
+  $self->{'html_files_information'}->{$self->{'current_filename'}}->{$key}
+    = $value;
 }
 
 sub get_file_information($$;$)
@@ -1850,12 +1870,12 @@ sub get_file_information($$;$)
     $filename = $self->{'current_filename'};
   }
   if (not defined($filename)
-      or not $self->{'files_information'}
-      or not $self->{'files_information'}->{$filename}
-      or not exists($self->{'files_information'}->{$filename}->{$key})) {
+      or not $self->{'html_files_information'}
+      or not $self->{'html_files_information'}->{$filename}
+      or not exists($self->{'html_files_information'}->{$filename}->{$key})) {
     return (0, undef);
   }
-  return (1, $self->{'files_information'}->{$filename}->{$key})
+  return (1, $self->{'html_files_information'}->{$filename}->{$key})
 }
 
 # information from converter available 'read-only', in general set up before
@@ -2999,10 +3019,10 @@ sub _convert_style_command($$$$)
   my $args = shift;
 
   my $text;
-  $text = $args->[0]->{'normal'} if ($args->[0]);
-  if (!defined($text)) {
+  if ($args and $args->[0]) {
+    $text = $args->[0]->{'normal'};
+  } else {
     # happens with bogus @-commands without argument, like @strong something
-    #cluck "text not defined in _convert_style_command";
     return '';
   }
 
@@ -3057,9 +3077,9 @@ sub _convert_w_command($$$$)
   my $args = shift;
 
   my $text;
-  $text = $args->[0]->{'normal'} if ($args->[0]);
-
-  if (!defined($text)) {
+  if ($args and $args->[0]) {
+    $text = $args->[0]->{'normal'};
+  } else {
     $text = '';
   }
   if ($self->in_string()) {
@@ -3090,7 +3110,10 @@ sub _convert_email_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  my $args_nr = scalar(@$args);
+  my $args_nr = 0;
+  if ($args) {
+    $args_nr = scalar(@$args);
+  }
 
   my $mail = '';
   my $mail_string = '';
@@ -3142,7 +3165,7 @@ sub _convert_explained_command($$$$)
   $explained_commands->{$cmdname} = {} if (!$explained_commands->{$cmdname});
   my $element_explanation_contents
     = $self->shared_conversion_state('element_explanation_contents', {});
-  if ($args->[1] and defined($args->[1]->{'string'})
+  if ($args and $args->[1] and defined($args->[1]->{'string'})
                  and $args->[1]->{'string'} =~ /\S/) {
     $with_explanation = 1;
     $explanation_string = $args->[1]->{'string'};
@@ -3188,7 +3211,7 @@ sub _convert_explained_command($$$$)
     $element_explanation_contents->{$command} = [];
   }
   my $result = '';
-  if (defined($args->[0])) {
+  if ($args and defined($args->[0])) {
     $result = $args->[0]->{'normal'};
   }
   if (!$self->in_string()) {
@@ -3321,7 +3344,11 @@ sub _convert_uref_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  my $args_nr = scalar(@$args);
+  my $args_nr = 0;
+
+  if ($args) {
+    $args_nr = scalar(@$args);
+  }
 
   my $text = '';
   my $url = '';
@@ -3360,7 +3387,7 @@ sub _convert_image_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  if (defined($args->[0])
+  if ($args and defined($args->[0])
       and defined($args->[0]->{'filenametext'})
       and $args->[0]->{'filenametext'} ne '') {
     my $basefile_string = '';
@@ -3401,7 +3428,12 @@ sub _convert_math_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  my $arg = $args->[0]->{'normal'};
+  my $arg;
+  if ($args and $args->[0]) {
+    $arg = $args->[0]->{'normal'};
+  } else {
+    return '';
+  }
 
   my $math_type = $self->get_conf('HTML_MATH');
   if ($math_type and $math_type eq 'mathjax') {
@@ -3565,7 +3597,13 @@ sub _convert_indicateurl_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  my $text = $args->[0]->{'normal'};
+  my $text;
+  if ($args and $args->[0]) {
+    $text = $args->[0]->{'normal'};
+  } else {
+    return '';
+  }
+
   if (!defined($text)) {
     # happens with bogus @-commands without argument, like @strong something
     return '';
@@ -3590,14 +3628,14 @@ sub _convert_titlefont_command($$$$)
   my $command = shift;
   my $args = shift;
 
+  my $text;
+  if ($args and $args->[0]) {
+    $text = $args->[0]->{'normal'};
+  } else {
   # happens with empty command
-  return '' if (!$args->[0]);
-
-  my $text = $args->[0]->{'normal'};
-  if (!defined($text)) {
-    # happens with bogus @-commands without argument, like @strong something
     return '';
   }
+
   return &{$self->formatting_function('format_heading_text')}($self, $cmdname,
                                                          [$cmdname], $text, 0);
 }
@@ -3610,16 +3648,14 @@ sub _convert_U_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  my $arg;
-  $arg = $args->[0]->{'normal'} if ($args->[0]);
-  my $res;
-  if (defined($arg) and $arg ne '') {
-    # checks on the value already done in Parser, just output it here.
-    $res = "&#x$arg;";
-  } else {
-    $res = '';
+  if ($args and $args->[0]) {
+    my $arg = $args->[0]->{'normal'};
+    if ($arg ne '') {
+      # checks on the value already done in Parser, just output it here.
+      return "&#x$arg;";
+    }
   }
-  return $res;
+  return '';
 }
 $default_commands_conversion{'U'} = \&_convert_U_command;
 
@@ -6951,7 +6987,7 @@ sub _convert_before_item_type($$$$)
   my $element = shift;
   my $content = shift;
 
-  return '' if ($content !~ /\S/);
+  return '' if (!defined ($content) or $content !~ /\S/);
   return $content if ($self->in_string());
   my $top_block_command = $self->top_block_command();
   if ($top_block_command eq 'itemize' or $top_block_command eq 'enumerate') {
@@ -7538,7 +7574,7 @@ sub _default_format_element_footer($$$$;$)
 # is not done within the document formatting flow, but the formatted
 # output may still end up in the document.  In particular for
 # command_text() which caches its computations.
-sub _new_document_context($;$$$)
+sub _new_document_context($$;$$)
 {
   my $self = shift;
   my $context = shift;
@@ -7547,7 +7583,7 @@ sub _new_document_context($;$$$)
 
   push @{$self->{'document_context'}},
           {'context' => $context,
-           'formatting_context' => [{'context_name' => $context}],
+           'formatting_context' => [{'context_name' => '_format'}],
            'composition_context' => [''],
            'monospace' => [0],
            'document_global_context' => $document_global_context,
@@ -7652,30 +7688,29 @@ sub 
_reset_unset_no_arg_commands_formatting_context($$$$;$)
     my $translated_tree
       = $no_arg_command_context->{'tree'};
     my $translation_result;
+    my $explanation
+       = "Translated NO ARG \@$cmdname ctx $reset_context";
+    my $context_str = "Tr $cmdname ctx $reset_context";
     if ($reset_context eq 'normal') {
       $translation_result
-        = $self->convert_tree($translated_tree,
-               "no arg $cmdname translated for $reset_context");
+        = $self->convert_tree($translated_tree, $explanation);
     } elsif ($reset_context eq 'preformatted') {
       # there does not seems to be anything simpler...
       my $preformatted_command_name = 'example';
-      $self->_new_document_context("Translate $cmdname for $reset_context");
+      $self->_new_document_context($context_str);
       push @{$self->{'document_context'}->[-1]->{'composition_context'}},
           $preformatted_command_name;
       # should not be needed for at commands no brace translation strings
       push @{$self->{'document_context'}->[-1]->{'preformatted_classes'}},
           $pre_class_commands{$preformatted_command_name};
       $translation_result
-        = $self->convert_tree($translated_tree,
-                              "no arg $cmdname translated for $reset_context");
-      # only pop the main context
+        = $self->convert_tree($translated_tree, $explanation);
       $self->_pop_document_context();
     } elsif ($reset_context eq 'string') {
       $translation_result
         = $self->convert_tree_new_formatting_context({'type' => '_string',
                                           'contents' => [$translated_tree]},
-                                         'translated_string',
-                    "string no arg $cmdname translated for $reset_context");
+                                              $context_str);
     } elsif ($reset_context eq 'css_string') {
       $translation_result = $self->html_convert_css_string($translated_tree);
     }
@@ -8419,7 +8454,6 @@ sub converter_initialize($)
   $self->{'document_context'} = [];
   $self->{'multiple_pass'} = [];
   $self->{'pending_closes'} = [];
-  $self->_new_document_context('_toplevel_context');
 
   # TODO warn if the split specification is not one known?  The main
   # program warns if the specific command line option value is not known.
@@ -10996,7 +11030,7 @@ sub _has_contents_or_shortcontents($)
   return 0;
 }
 
-sub _XS_initialize_output_state($)
+sub _XS_initialize_output_state($$)
 {
 }
 
@@ -11004,11 +11038,14 @@ sub _XS_initialize_output_state($)
 # NOTE not called directly by convert_tree, which means that convert_tree
 # needs to be called from a converter which would have had this function
 # called already.
-sub _initialize_output_state($)
+sub _initialize_output_state($$)
 {
   my $self = shift;
+  my $context = shift;
 
-  _XS_initialize_output_state($self);
+  # TODO override the whole function and add a C build_ function to setup
+  # the perl state similarly with what is done in that function.
+  _XS_initialize_output_state($self, $context.'C');
 
   # for diverse API used in conversion
   $self->{'shared_conversion_state'} = {};
@@ -11016,7 +11053,7 @@ sub _initialize_output_state($)
   $self->{'associated_inline_content'} = {};
 
   # even if there is no actual file, this is needed if the API is used.
-  $self->{'files_information'} = {};
+  $self->{'html_files_information'} = {};
 
   # Needed for CSS gathering, even if nothing related to CSS is output
   $self->{'document_global_context_css'} = {};
@@ -11035,10 +11072,6 @@ sub _initialize_output_state($)
   $self->{'targets'} = {};
   $self->{'seen_ids'} = {};
 
-  # to avoid infinite recursions when a section refers to itself, possibly
-  # indirectly
-  $self->{'referred_command_stack'} = [];
-
   # for global directions always set, and for directions to special elements,
   # only filled if special elements are actually used.
   $self->{'global_units_directions'} = {};
@@ -11049,8 +11082,20 @@ sub _initialize_output_state($)
   # other
   $self->{'pending_footnotes'} = [];
 
+  # to avoid infinite recursions when a section refers to itself, possibly
+  # indirectly
+  $self->{'referred_command_stack'} = [];
+
   $self->{'check_htmlxref_already_warned'} = {}
     if ($self->get_conf('CHECK_HTMLXREF'));
+
+  $self->_new_document_context($context);
+}
+
+sub _finalize_output_state($)
+{
+  my $self = shift;
+  $self->_pop_document_context();
 }
 
 
@@ -11107,7 +11152,7 @@ sub convert($$)
 
   my $result = '';
 
-  $self->_initialize_output_state();
+  $self->_initialize_output_state('_convert');
 
   # the presence of contents elements in the document is used in diverse
   # places, set it once for all here
@@ -11168,14 +11213,15 @@ sub convert($$)
   # complete information should be available.
   $self->_reset_info();
 
+  $self->{'current_filename'} = '';
+
   if ($self->{'converter_descriptor'} and $XS_convert) {
     my $XS_result = _XS_html_convert_convert ($encoded_converter, $root,
                                               $output_units, $special_units);
+    $self->_finalize_output_state();
     return $XS_result;
   }
 
-  $self->{'current_filename'} = '';
-
   if (!defined($output_units)) {
     print STDERR "\nC NO UNIT\n" if ($self->get_conf('DEBUG'));
     $result = $self->_convert($root, 'convert no unit');
@@ -11195,6 +11241,7 @@ sub convert($$)
   }
   $self->{'current_filename'} = undef;
 
+  $self->_finalize_output_state();
   return $result;
 }
 
@@ -11613,7 +11660,7 @@ sub output($$)
   # therefore set in converter_info early too (using the reference).
   $self->{'current_filename'} = undef;
 
-  $self->_initialize_output_state();
+  $self->_initialize_output_state('_output');
 
   # no splitting when writing to the null device or to stdout or returning
   # a string
@@ -11676,8 +11723,11 @@ sub output($$)
   $self->_reset_info();
 
   my $setup_status = $self->run_stage_handlers($root, 'setup');
-  return undef unless ($setup_status < $handler_fatal_error_level
-                       and $setup_status > -$handler_fatal_error_level);
+  unless ($setup_status < $handler_fatal_error_level
+          and $setup_status > -$handler_fatal_error_level) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
   # the configuration has potentially been modified for
   # this output file especially.  Set a corresponding initial
@@ -11735,7 +11785,10 @@ sub output($$)
   my $succeeded
     = $self->create_destination_directory($encoded_destination_directory,
                                           $destination_directory);
-  return undef unless $succeeded;
+  unless ($succeeded) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
   # set for init files
   $self->{'document_name'} = $document_name;
@@ -11767,8 +11820,11 @@ sub output($$)
   $self->_reset_info();
 
   my $structure_status = $self->run_stage_handlers($root, 'structure');
-  return undef unless ($structure_status < $handler_fatal_error_level
-                       and $structure_status > -$handler_fatal_error_level);
+  unless ($structure_status < $handler_fatal_error_level
+          and $structure_status > -$handler_fatal_error_level) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
   my $default_document_language = $self->get_conf('documentlanguage');
 
@@ -11874,8 +11930,11 @@ sub output($$)
 
 
   my $init_status = $self->run_stage_handlers($root, 'init');
-  return undef unless ($init_status < $handler_fatal_error_level
-                       and $init_status > -$handler_fatal_error_level);
+  unless ($init_status < $handler_fatal_error_level
+          and $init_status > -$handler_fatal_error_level) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
 
   $self->_prepare_title_titlepage($output_units, $output_file,
@@ -11889,7 +11948,10 @@ sub output($$)
                        $special_units, $output_file, $destination_directory,
                        $output_filename, $document_name);
 
-  return undef if (!defined($text_output));
+  if (!defined($text_output)) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
   if ($text_output ne '' and $output_file eq '') {
     # $output_file eq '' should always be true, see comment above.
@@ -11898,14 +11960,18 @@ sub output($$)
       # only if formatting is called as convert, which only happens in tests.
       $self->_do_js_files($destination_directory);
     }
+    $self->_finalize_output_state();
     return $text_output;
   }
 
   $self->_do_js_files($destination_directory);
 
   my $finish_status = $self->run_stage_handlers($root, 'finish');
-  return undef unless ($finish_status < $handler_fatal_error_level
-                       and $finish_status > -$handler_fatal_error_level);
+  unless ($finish_status < $handler_fatal_error_level
+          and $finish_status > -$handler_fatal_error_level) {
+    $self->_finalize_output_state();
+    return undef;
+  }
 
   my $extension = '';
   $extension = '.'.$self->get_conf('EXTENSION')
@@ -12052,12 +12118,14 @@ sub output($$)
             $self->document_error($self, sprintf(__(
                              "error on closing redirection node file %s: %s"),
                                     $out_filename, $!));
+            $self->_finalize_output_state();
             return undef;
           }
         }
       }
     }
   }
+  $self->_finalize_output_state();
   return undef;
 }
 
@@ -12103,10 +12171,14 @@ sub _convert($$;$)
 
   if ($debug) {
     $explanation = 'NO EXPLANATION' if (!defined($explanation));
+    my @document_contexts = map {defined($_->{'context'})
+                                       ? $_->{'context'}: 'UNDEF'}
+                                  @{$self->{'document_context'}};
     my @contexts_names = map {defined($_->{'context_name'})
                                  ? $_->{'context_name'}: 'UNDEF'}
          @{$self->{'document_context'}->[-1]->{'formatting_context'}};
-    print STDERR "ELEMENT($explanation) (".join('|',@contexts_names)."), ->";
+    print STDERR "ELEMENT($explanation) [".join('|',@document_contexts)
+                                   ."](".join('|',@contexts_names)."), ->";
     print STDERR " cmd: $element->{'cmdname'}," if ($element->{'cmdname'});
     print STDERR " type: $element->{'type'}" if ($element->{'type'});
     my $text = $element->{'text'};
@@ -12254,8 +12326,8 @@ sub _convert($$;$)
               or $command_name eq 'smallquotation')
           or $command_name eq 'float'
           or $command_name eq 'cartouche') {
-        $args_formatted = [];
         if ($element->{'args'}) {
+          $args_formatted = [];
           my @args_specification;
           @args_specification = @{$default_commands_args{$command_name}}
             if (defined($default_commands_args{$command_name}));
diff --git a/tp/Texinfo/Convert/Text.pm b/tp/Texinfo/Convert/Text.pm
index 81b826c46c..526641dcc3 100644
--- a/tp/Texinfo/Convert/Text.pm
+++ b/tp/Texinfo/Convert/Text.pm
@@ -432,9 +432,11 @@ sub encode_text_options($)
   }
 
   if (defined($options->{'expanded_formats'})) {
-    my $expanded_formats = [];
+    # FIXME may not need to encode, as the formats are ascii strings
+    my $expanded_formats = {};
     foreach my $format (keys(%{$options->{'expanded_formats'}})) {
-      push @$expanded_formats, Encode::encode("UTF-8", $format);
+      my $encoded_format = Encode::encode("UTF-8", $format);
+      $expanded_formats->{$encoded_format} = 1;
     }
     $encoded_options->{'expanded_formats'} = $expanded_formats;
   }
diff --git a/tp/Texinfo/Translations.pm b/tp/Texinfo/Translations.pm
index cba465f966..0d4840261f 100644
--- a/tp/Texinfo/Translations.pm
+++ b/tp/Texinfo/Translations.pm
@@ -322,8 +322,8 @@ sub replace_substrings($$;$)
   my $translation_result = $translated_string;
 
   if (defined($replaced_substrings) and ref($replaced_substrings)) {
-      my $re = join '|', map { quotemeta $_ } keys %$replaced_substrings;
-      # next line taken from libintl perl, copyright Guido. sub __expand
+    my $re = join '|', map { quotemeta $_ } keys %$replaced_substrings;
+    # next line taken from libintl perl, copyright Guido. sub __expand
     $translation_result
   =~ s/\{($re)\}/defined $replaced_substrings->{$1} ? 
$replaced_substrings->{$1} : "{$1}"/ge;
   }
@@ -391,6 +391,10 @@ sub replace_convert_substrings($$;$)
     }
   }
   $tree = _substitute($tree, $replaced_substrings);
+  if ($customization_information->get_conf('DEBUG')) {
+    print STDERR "RESULT GDT: '".
+       Texinfo::Convert::Texinfo::convert_to_texinfo($tree)."'\n";
+  }
   return $tree;
 }
 
diff --git a/tp/Texinfo/XS/convert/ConvertXS.xs 
b/tp/Texinfo/XS/convert/ConvertXS.xs
index f1953fc38f..17b4f17914 100644
--- a/tp/Texinfo/XS/convert/ConvertXS.xs
+++ b/tp/Texinfo/XS/convert/ConvertXS.xs
@@ -35,7 +35,9 @@
 #include "convert_plain_texinfo.h"
 #include "convert_text.h"
 #include "convert_to_text.h"
+#include "builtin_commands.h"
 #include "indices_in_conversion.h"
+#include "command_stack.h"
 #include "convert_html.h"
 #include "document.h"
 
@@ -105,13 +107,108 @@ void set_conf(SV *converter_in, conf, SV *value)
            set_conf (self, conf, value);
 
 void
-html_initialize_output_state (SV *converter_in)
+html_initialize_output_state (SV *converter_in, char *context)
       PREINIT:
          CONVERTER *self;
       CODE:
          self = get_sv_converter (converter_in, 
"html_initialize_output_state");
          if (self)
-           html_initialize_output_state (self);
+           html_initialize_output_state (self, context);
+
+void
+html_finalize_output_state (SV *converter_in)
+      PREINIT:
+         CONVERTER *self;
+      CODE:
+         self = get_sv_converter (converter_in, "html_finalize_output_state");
+         if (self)
+           {
+             html_finalize_output_state (self);
+
+             if (self->modified_state)
+               {
+                 build_html_formatting_state (self, self->modified_state);
+                 self->modified_state = 0;
+               }
+           }
+
+void
+html_new_document_context (SV *converter_in, char *context_name, ...)
+      PROTOTYPE: $$;$$
+      PREINIT:
+         CONVERTER *self;
+         char *document_global_context = 0;
+         char *block_command_name = 0;
+         enum command_id block_command = 0;
+      CODE:
+         self = get_sv_converter (converter_in, "html_new_document_context");
+         if (items > 2 && SvOK(ST(2)))
+           document_global_context = SvPVutf8_nolen (ST(2));
+         if (items > 3 && SvOK(ST(3)))
+           block_command_name = SvPVutf8_nolen (ST(3));
+         if (block_command_name)
+           block_command = lookup_builtin_command (block_command_name);
+
+         if (self)
+           {
+             HV *document_context_hv;
+             HTML_DOCUMENT_CONTEXT *document_context;
+             HV *converter_hv = (HV *) SvRV (converter_in); 
+             SV **document_context_sv = hv_fetch (converter_hv,
+                   "document_context", strlen("document_context"), 0);
+             AV *document_context_av = (AV *) SvRV (*document_context_sv);
+             /* should not be needed as we are calling from perl 
+             if (self->modified_state)
+               {
+                 build_html_formatting_state (self, self->modified_state);
+                 self->modified_state = 0;
+               }
+              */
+             html_new_document_context (self, context_name,
+                                        document_global_context, 
block_command);
+             /* reset to ignore the HMSF_formatting_context flag just set */
+             self->modified_state = 0;
+             document_context = html_top_document_context (self);
+             document_context_hv = build_html_document_context
+                                                      (document_context);
+             av_push (document_context_av,
+                      newRV_noinc ((SV *) document_context_hv));
+             self->document_context_change--;
+             hv_store (converter_hv, "document_global_context",
+                       strlen ("document_global_context"),
+                       newSViv (self->document_global_context), 0);
+           }
+
+
+void
+html_pop_document_context (SV *converter_in)
+      PREINIT:
+         CONVERTER *self;
+      CODE:
+         self = get_sv_converter (converter_in, "html_new_document_context");
+         if (self)
+           {
+             HV *converter_hv = (HV *) SvRV (converter_in); 
+             SV **document_context_sv = hv_fetch (converter_hv,
+                   "document_context", strlen("document_context"), 0);
+             AV *document_context_av = (AV *) SvRV (*document_context_sv);
+             /* should not be needed as we are calling from perl 
+             if (self->modified_state)
+               {
+                 build_html_formatting_state (self, self->modified_state);
+                 self->modified_state = 0;
+               }
+              */
+             html_pop_document_context (self);
+             av_pop (document_context_av);
+             hv_store (converter_hv, "document_global_context",
+                       strlen ("document_global_context"),
+                       newSViv (self->document_global_context), 0);
+             /* reset to ignore the HMSF_formatting_context flag just set */
+             self->modified_state = 0;
+             self->document_context_change++;
+           }
+
 
 # unfinished, see sort_indices_by_letter comment
 void
@@ -156,9 +253,8 @@ html_prepare_conversion_units (SV *converter_in, ...)
          SV *special_targets_sv;
          SV *seen_ids_sv;
       PPCODE:
-         if (items > 1)
-           if (SvOK(ST(1)))
-             document_name = SvPVbyte_nolen (ST(1));
+         if (items > 1 && SvOK(ST(1)))
+           document_name = SvPVbyte_nolen (ST(1));
 
          /* add warn string? */
          self = set_output_converter_sv (converter_in, 0);
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index dfd64f7ee0..4d94cc6a4e 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -72,6 +72,7 @@ CMD_VARIETY command_special_unit_variety[] = {
 #define F_AFT_url               0x0080
 #define F_AFT_raw               0x0100
 
+/* HTML command data flags */
 #define HF_composition_context  0x0001
 #define HF_format_context       0x0002
 #define HF_format_raw           0x0004
@@ -306,6 +307,58 @@ find_element_target (HTML_TARGET_LIST *targets, ELEMENT 
*element)
   return 0;
 }
 
+ELEMENT *
+html_gdt_tree (const char *string, DOCUMENT *document, OPTIONS *options,
+               NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+               const char *translation_context,
+               const char *in_lang)
+{
+  return gdt_tree (string, document, options, replaced_substrings,
+                   translation_context, in_lang);
+}
+
+
+char *
+html_gdt_string (const char *string, CONVERTER *self,
+                 NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                 const char *translation_context, const char *in_lang)
+{
+  FORMATTING_REFERENCE *formatting_reference
+    = &self->formatting_references[FR_format_translate_message_string];
+
+  /* there is no place where FRS_status_ignore could be set, but
+     it does not hurt to consider it possible */
+  if (formatting_reference->status
+      && formatting_reference->status != FRS_status_ignored
+      && formatting_reference->sv_reference)
+    {
+      const char *lang = in_lang;
+      char *translated_string;
+
+      if (!lang && self->conf->documentlanguage)
+        lang = self->conf->documentlanguage;
+
+      translated_string
+       = call_formatting_function_format_translate_message_string(
+          self, string, lang, replaced_substrings, translation_context);
+
+      if (translated_string)
+        return translated_string;
+    }
+
+  return gdt_string (string, self->conf, replaced_substrings,
+                     translation_context, in_lang);
+}
+
+ELEMENT *
+html_pgdt_tree (const char *translation_context, const char *string,
+                DOCUMENT *document, OPTIONS *options,
+                NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                const char *in_lang)
+{
+  return html_gdt_tree (string, document, options, replaced_substrings,
+                        translation_context, in_lang);
+}
 
 
 ELEMENT *
@@ -332,8 +385,8 @@ special_unit_info_tree (CONVERTER *self, enum 
special_unit_info_tree type,
           xasprintf (&translation_context, "%s section heading",
                      special_unit_variety);
           self->special_unit_info_tree[type][i]
-            = pgdt_tree (translation_context, special_unit_info_string,
-                         self->document, self->conf, 0, 0);
+            = html_pgdt_tree (translation_context, special_unit_info_string,
+                              self->document, self->conf, 0, 0);
           free (translation_context);
           return self->special_unit_info_tree[type][i];
         }
@@ -2130,12 +2183,17 @@ pop_html_formatting_context 
(HTML_FORMATTING_CONTEXT_STACK *stack)
   stack->top--;
 }
 
-static void
+void
 html_new_document_context (CONVERTER *self,
         char *context_name, char *document_global_context,
         enum command_id block_command)
 {
   HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
+  HTML_DOCUMENT_CONTEXT *doc_context;
+
+  self->modified_state |= HMSF_document_context;
+  self->document_context_change++;
+
   if (stack->top >= stack->space)
     {
       stack->stack
@@ -2143,15 +2201,15 @@ html_new_document_context (CONVERTER *self,
                    (stack->space += 5) * sizeof (HTML_DOCUMENT_CONTEXT));
     }
 
-  memset (&stack->stack[stack->top], 0, sizeof (HTML_DOCUMENT_CONTEXT));
-  stack->stack[stack->top].context = strdup (context_name);
-  stack->stack[stack->top].document_global_context = document_global_context;
+  doc_context = &stack->stack[stack->top];
+  memset (doc_context, 0, sizeof (HTML_DOCUMENT_CONTEXT));
+  doc_context->context = strdup (context_name);
+  doc_context->document_global_context = document_global_context;
 
-  push_style_no_code (&stack->stack[stack->top].monospace);
-  push_command_or_type (&stack->stack[stack->top].composition_context,
-                        0, 0);
+  push_style_no_code (&doc_context->monospace);
+  push_command_or_type (&doc_context->composition_context, 0, 0);
   if (block_command)
-    push_command (&stack->stack[stack->top].block_commands, block_command);
+    push_command (&doc_context->block_commands, block_command);
 
   if (document_global_context)
     {
@@ -2159,13 +2217,13 @@ html_new_document_context (CONVERTER *self,
       self->modified_state |= HMSF_converter_state;
     }
 
-  push_html_formatting_context (&stack->stack[stack->top].formatting_context,
-                                context_name);
+  push_html_formatting_context (&doc_context->formatting_context,
+                                "_format");
 
   stack->top++;
 }
 
-static void
+void
 html_pop_document_context (CONVERTER *self)
 {
   HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
@@ -2174,6 +2232,13 @@ html_pop_document_context (CONVERTER *self)
   if (stack->top == 0)
     fatal ("HTML document context stack empty for pop");
 
+  self->modified_state |= HMSF_document_context;
+  self->document_context_change--;
+  /* set document_contexts_to_pop to the lowest level below last sync with
+     perl reached */
+  if (-self->document_context_change > self->document_contexts_to_pop)
+    self->document_contexts_to_pop = -self->document_context_change;
+
   document_ctx = &stack->stack[stack->top -1];
 
   free (document_ctx->context);
@@ -2269,9 +2334,6 @@ html_converter_initialize (CONVERTER *self)
 
   html_commands_data[CM_sc].flags |= HF_upper_case;
 
-  /* FIXME need to call html_pop_document_context to free memory */
-  html_new_document_context (self, "_toplevel_context", 0, 0);
-
   /* initialization needing some information from perl */
 
   nr_special_units = self->special_unit_varieties->number;
@@ -2306,7 +2368,7 @@ html_converter_initialize (CONVERTER *self)
 }
 
 void
-html_initialize_output_state (CONVERTER *self)
+html_initialize_output_state (CONVERTER *self, char *context)
 {
   int i;
   /* targets and directions */
@@ -2327,6 +2389,17 @@ html_initialize_output_state (CONVERTER *self)
   self->current_formatting_references = &self->formatting_references[0];
   self->current_commands_conversion = &self->commands_conversion[0];
   self->current_types_conversion = &self->types_conversion[0];
+
+  /* FIXME now done through HTML _initialize_output_state, would need
+     to readd when the HTML function is overriden
+  html_new_document_context (self, context, 0, 0);
+   */
+}
+
+void
+html_finalize_output_state (CONVERTER *self)
+{
+  html_pop_document_context (self);
 }
 
 char *
@@ -2360,7 +2433,6 @@ convert_tree_new_formatting_context (CONVERTER *self, 
ELEMENT *tree,
       html_new_document_context (self, context_string,
                                  document_global_context, block_cmd);
       text_printf (&context_string_str, "C(%s)", context_string);
-      self->modified_state |= HMSF_document_context;
     }
 
   if (multiple_pass)
@@ -2384,7 +2456,6 @@ convert_tree_new_formatting_context (CONVERTER *self, 
ELEMENT *tree,
   if (context_string)
     {
       html_pop_document_context (self);
-      self->modified_state |= HMSF_document_context;
     }
 
   if (multiple_pass)
@@ -2418,14 +2489,12 @@ html_convert_css_string (CONVERTER *self, ELEMENT 
*element, char *explanation)
     = &self->css_string_types_conversion[0];
 
   html_new_document_context (self, "css_string", 0, 0);
-  top_document_ctx = top_document_context (self);
-  self->modified_state |= HMSF_document_context;
+  top_document_ctx = html_top_document_context (self);
   top_document_ctx->string_ctx++;
 
   result = html_convert_tree (self, element, explanation);
 
   html_pop_document_context (self);
-  self->modified_state |= HMSF_document_context;
 
   self->current_formatting_references = saved_formatting_references;
   self->current_commands_conversion = saved_commands_conversion;
@@ -2476,8 +2545,10 @@ reset_unset_no_arg_commands_formatting_context 
(CONVERTER *self,
                 = strdup (no_arg_ref->translated_converted);
             }
           if (no_arg_ref->translated_to_convert)
-            no_arg_command_context->translated_to_convert
-              = no_arg_ref->translated_to_convert;
+            {
+              no_arg_command_context->translated_to_convert
+                = no_arg_ref->translated_to_convert;
+            }
         }
     }
 
@@ -2486,35 +2557,32 @@ reset_unset_no_arg_commands_formatting_context 
(CONVERTER *self,
       && !no_arg_command_context->translated_converted)
     {
       char *translation_result = 0;
+      char *explanation;
+      char *context;
       ELEMENT *translated_tree = no_arg_command_context->tree;
       if (!translated_tree->hv)
         {/* FIXME Should be done differently if it is possible
            it be possible to recursively call html_translate_names. */
           self->tree_to_build = translated_tree;
         }
+      xasprintf (&explanation, "Translated NO ARG @%s ctx %s",
+                 builtin_command_data[cmd].cmdname,
+                 html_conversion_context_type_names[reset_context]);
+      xasprintf (&context, "Tr %s ctx %s",
+                 builtin_command_data[cmd].cmdname,
+                 html_conversion_context_type_names[reset_context]);
       if (reset_context == HCC_type_normal)
         {
-          char *explanation;
-          xasprintf (&explanation, "no arg %s translated for",
-                     builtin_command_data[cmd].cmdname,
-                     html_conversion_context_type_names[reset_context]);
           translation_result = html_convert_tree (self, translated_tree,
                                                   explanation);
-          free (explanation);
         }
       else if (reset_context == HCC_type_preformatted)
         {
-          char *context_name;
           enum command_id preformated_cmd = CM_example;
           HTML_DOCUMENT_CONTEXT *top_document_ctx;
-          char *explanation;
-          xasprintf (&context_name, "Translate %s for %s",
-                     builtin_command_data[cmd].cmdname,
-                     html_conversion_context_type_names[reset_context]);
-          html_new_document_context (self, context_name, 0, 0);
-          free (context_name);
+          html_new_document_context (self, context, 0, 0);
 
-          top_document_ctx = top_document_context (self);
+          top_document_ctx = html_top_document_context (self);
 
           /* there does not seems to be anything simpler... */
           push_command_or_type (&top_document_ctx->composition_context,
@@ -2522,44 +2590,33 @@ reset_unset_no_arg_commands_formatting_context 
(CONVERTER *self,
       /* should not be needed for at commands no brace translation strings */
           push_string_stack_string (&top_document_ctx->preformatted_classes,
                               html_commands_data[preformated_cmd].pre_class);
-          self->modified_state |= HMSF_document_context;
 
-          xasprintf (&explanation, "no arg %s translated for %s",
-                     builtin_command_data[cmd].cmdname,
-                     html_conversion_context_type_names[reset_context]);
           translation_result = html_convert_tree (self, translated_tree,
                                                   explanation);
-          free (explanation);
           pop_command_or_type (&top_document_ctx->composition_context);
           pop_string_stack (&top_document_ctx->preformatted_classes);
           html_pop_document_context (self);
-          self->modified_state |= HMSF_document_context;
         }
       else if (reset_context == HCC_type_string)
         {
-          char *context_name;
           HTML_DOCUMENT_CONTEXT *top_document_ctx;
 
-          xasprintf (&context_name, "string no arg %s translated for %s",
-                     html_conversion_context_type_names[reset_context],
-                     builtin_command_data[cmd].cmdname);
-          html_new_document_context (self, context_name, 0, 0);
+          html_new_document_context (self, context, 0, 0);
 
-          top_document_ctx = top_document_context (self);
+          top_document_ctx = html_top_document_context (self);
           top_document_ctx->string_ctx++;
 
-          self->modified_state |= HMSF_document_context;
           translation_result = html_convert_tree (self, translated_tree,
-                                                  context_name);
-          free (context_name);
+                                                  explanation);
           html_pop_document_context (self);
-          self->modified_state |= HMSF_document_context;
         }
       else if (reset_context == HCC_type_css_string)
         {
           translation_result = html_convert_css_string (self, translated_tree,
                                                         0);
         }
+      free (explanation);
+      free (context);
       if (no_arg_command_context->text)
         free (no_arg_command_context->text);
       no_arg_command_context->text = translation_result;
@@ -2666,7 +2723,7 @@ html_translate_names (CONVERTER *self)
                 {
                   add_cmd = 1;
                   format_spec->text
-                   = gdt_string (format_spec->translated_converted, self->conf,
+                   = html_gdt_string (format_spec->translated_converted, self,
                                  0, 0, 0);
                 }
               else if (i == HCC_type_normal)
@@ -2675,7 +2732,7 @@ html_translate_names (CONVERTER *self)
                   if (format_spec->translated_to_convert)
                     {/* FIXME use document associated to converter? */
                       translated_tree =
-                         gdt_tree (format_spec->translated_to_convert,
+                        html_gdt_tree (format_spec->translated_to_convert,
                                    0, self->conf, 0, 0, 0);
                     }
                   else
@@ -2759,10 +2816,27 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
       TEXT contexts_str;
       text_init (&debug_str);
       text_init (&contexts_str);
-      HTML_DOCUMENT_CONTEXT *top_document_ctx = top_document_context (self);
+      text_append (&contexts_str, "[");
+      HTML_DOCUMENT_CONTEXT_STACK *document_context_stack
+        = &self->html_document_context;
+      HTML_DOCUMENT_CONTEXT *top_document_ctx
+        = html_top_document_context (self);
       HTML_FORMATTING_CONTEXT_STACK *formatting_context_stack
         = &top_document_ctx->formatting_context;
 
+      for (i = 0; i < document_context_stack->top; i++)
+        {
+          HTML_DOCUMENT_CONTEXT *document_context
+            = &document_context_stack->stack[i];
+          if (i != 0)
+            text_append (&contexts_str, "|");
+          if (document_context->context)
+            text_append (&contexts_str, document_context->context);
+          else
+            text_append (&contexts_str, "UNDEF");
+        }
+      text_append (&contexts_str, "](");
+
       for (i = 0; i < formatting_context_stack->top; i++)
         {
           HTML_FORMATTING_CONTEXT *formatting_context
@@ -2775,7 +2849,8 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
             text_append (&contexts_str, "UNDEF");
 
         }
-      text_printf (&debug_str, "XS|ELEMENT(%s) (%s), ->", explanation,
+      text_append (&contexts_str, ")");
+      text_printf (&debug_str, "XS|ELEMENT(%s) %s, ->", explanation,
                                                        contexts_str.text);
       free (contexts_str.text);
       if (command_name)
@@ -2823,7 +2898,7 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
         {
           char *translation_context
             = lookup_extra_string (element, "translation_context");
-          ELEMENT *translated = gdt_tree (element->text.text, self->document,
+          ELEMENT *translated = html_gdt_tree (element->text.text, 
self->document,
                                     self->conf, 0, translation_context, 0);
 
           convert_to_html_internal (self, translated, &text_result,
@@ -2884,10 +2959,9 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
             {
               html_new_document_context (self,
                                builtin_command_data[data_cmd].cmdname, 0, 0);
-              self->modified_state |= HMSF_document_context;
 
             }
-          top_document_ctx = top_document_context (self);
+          top_document_ctx = html_top_document_context (self);
 
           if (html_commands_data[data_cmd].flags & HF_format_context)
             {
@@ -2898,7 +2972,7 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
             }
 
           top_formating_ctx
-            = top_html_formatting_context 
(&top_document_ctx->formatting_context);
+            = html_top_formatting_context 
(&top_document_ctx->formatting_context);
 
           if (builtin_command_data[data_cmd].flags & CF_block)
             {
@@ -3100,11 +3174,9 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
                           text_reset (&formatted_arg);
                           html_new_document_context (self, command_type.text,
                                                      0, 0);
-                          string_document_ctx = top_document_context (self);
+                          string_document_ctx = html_top_document_context 
(self);
                           string_document_ctx->string_ctx++;
 
-                          self->modified_state |= HMSF_document_context;
-
                           xasprintf (&explanation, "%s A[%d]string",
                                                    command_type.text, arg_idx);
                           convert_to_html_internal (self, arg, &formatted_arg,
@@ -3113,7 +3185,6 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
                           free (explanation);
 
                           html_pop_document_context (self);
-                          self->modified_state |= HMSF_document_context;
 
                           arg_formatted->formatted[AFT_type_string]
                            = strdup (formatted_arg.text);
@@ -3124,10 +3195,9 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
                           text_reset (&formatted_arg);
                           html_new_document_context (self, command_type.text,
                                                      0, 0);
-                          string_document_ctx = top_document_context (self);
+                          string_document_ctx = html_top_document_context 
(self);
                           string_document_ctx->string_ctx++;
                           push_monospace (&string_document_ctx->monospace);
-                          self->modified_state |= HMSF_document_context;
                           xasprintf (&explanation, "%s A[%d]monospacestring",
                                                    command_type.text, arg_idx);
                           convert_to_html_internal (self, arg, &formatted_arg,
@@ -3137,7 +3207,6 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
                           pop_monospace_context
                               (&string_document_ctx->monospace);
                           html_pop_document_context (self);
-                          self->modified_state |= HMSF_document_context;
                           arg_formatted->formatted[AFT_type_monospacestring]
                            = strdup (formatted_arg.text);
                         }
@@ -3277,7 +3346,6 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
               && builtin_command_data[data_cmd].data == BRACE_context)
             {
               html_pop_document_context (self);
-              self->modified_state |= HMSF_document_context;
             }
 
           if (element->cmd == CM_node)
@@ -3338,9 +3406,9 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
       char *type_name = element_type_names[type];
       TEXT type_result;
       TEXT content_formatted;
-      HTML_DOCUMENT_CONTEXT *top_document_ctx = top_document_context (self);
+      HTML_DOCUMENT_CONTEXT *top_document_ctx = html_top_document_context 
(self);
       HTML_FORMATTING_CONTEXT *top_formating_ctx
-        = top_html_formatting_context (&top_document_ctx->formatting_context);
+        = html_top_formatting_context (&top_document_ctx->formatting_context);
 
       text_init (&type_result);
       text_append (&type_result, "");
diff --git a/tp/Texinfo/XS/convert/convert_html.h 
b/tp/Texinfo/XS/convert/convert_html.h
index 978b3c68b3..a3b36ea1cd 100644
--- a/tp/Texinfo/XS/convert/convert_html.h
+++ b/tp/Texinfo/XS/convert/convert_html.h
@@ -8,7 +8,13 @@
 
 void html_converter_initialize (CONVERTER *self);
 
-void html_initialize_output_state (CONVERTER *self);
+void html_initialize_output_state (CONVERTER *self, char *context);
+void html_finalize_output_state (CONVERTER *self);
+
+void html_new_document_context (CONVERTER *self,
+        char *context_name, char *document_global_context,
+        enum command_id block_command);
+void html_pop_document_context (CONVERTER *self);
 
 void html_prepare_conversion_units (CONVERTER *self,
                                     int *output_units_descriptor_ref,
diff --git a/tp/Texinfo/XS/main/build_perl_info.c 
b/tp/Texinfo/XS/main/build_perl_info.c
index 351408c716..87fb6193dc 100644
--- a/tp/Texinfo/XS/main/build_perl_info.c
+++ b/tp/Texinfo/XS/main/build_perl_info.c
@@ -55,6 +55,7 @@
 /* for wipe_error_message_list */
 #include "errors.h"
 #include "command_stack.h"
+#include "translations.h"
 #include "build_perl_info.h"
 
 #define LOCALEDIR DATADIR "/locale"
@@ -2271,36 +2272,64 @@ build_html_formatting_state (CONVERTER *converter, 
unsigned long flags)
         SvUTF8_on (*current_filename_sv);
     }
 
-  if (flags & HMSF_document_context)
+  if (flags & HMSF_document_context
+      && (converter->document_context_change
+          || converter->document_contexts_to_pop))
     {
+      SSize_t top_document_context_idx;
       FETCH(document_context);
 
       if (!document_context_sv)
         {
           document_context_av = newAV ();
+          fprintf (stderr, "BUG: no document context\n");
           STORE("document_context", newRV_noinc ((SV *) document_context_av));
+          top_document_context_idx = -1;
         }
-       else
+      else
         {
+          int doc_top_target;
           document_context_av = (AV *) SvRV (*document_context_sv);
-          av_clear (document_context_av);
+          /* check consistentcy of C and perl document context stack levels */
+          top_document_context_idx = av_top_index (document_context_av);
+          doc_top_target = top_document_context_idx+1
+                               + converter->document_context_change;
+          if (doc_top_target != converter->html_document_context.top)
+            {
+              fprintf (stderr,
+          "BUG: top and document context level change mismatch %zu %d (%zu)\n",
+                  converter->html_document_context.top, doc_top_target,
+                  top_document_context_idx+1);
+            }
+
+          /* remove obsolete document contexts in perl */
+          while (converter->document_contexts_to_pop)
+            {
+              converter->document_contexts_to_pop--;
+              top_document_context_idx--;
+              av_pop (document_context_av);
+            }
         }
 
-      for (i = 0; i < converter->html_document_context.top; i++)
+      /* add the modified contexts */
+      for (i = top_document_context_idx +1;
+           i < converter->html_document_context.top; i++)
         {
           HTML_DOCUMENT_CONTEXT *document_context
             = &converter->html_document_context.stack[i];
           HV *document_context_hv = build_html_document_context 
(document_context);
           av_push (document_context_av, newRV_noinc ((SV *) 
document_context_hv));
         }
+      converter->document_context_change = 0;
     }
-  else if (flags & (HMSF_formatting_context | HMSF_composition_context
+
+  if (flags & (HMSF_formatting_context | HMSF_composition_context
                     | HMSF_preformatted_classes | HMSF_block_commands
                     | HMSF_monospace | HMSF_top_document_ctx
                     | HMSF_top_formatting_context))
     {
       HTML_DOCUMENT_CONTEXT *top_document_ctx
-         = top_document_context (converter);
+         = html_top_document_context (converter);
       SSize_t top_document_context_idx;
       SV **top_document_context_sv;
       HV *top_document_context_hv;
@@ -2312,8 +2341,19 @@ build_html_formatting_state (CONVERTER *converter, 
unsigned long flags)
 
       document_context_sv = hv_fetch (hv, "document_context",
                                       strlen ("document_context"), 0);
+      if (!document_context_sv)
+        {
+          fprintf (stderr,
+                   "BUG: no document context but formatting F: %#8lx\n", 
flags);
+          abort();
+        }
       document_context_av = (AV *) SvRV (*document_context_sv);
       top_document_context_idx = av_top_index (document_context_av);
+      if (top_document_context_idx < 0)
+        {
+          fprintf (stderr,
+               "BUG: empty document_context but formatting F: %#8lx\n", flags);
+        }
       top_document_context_sv = av_fetch (document_context_av,
                                           top_document_context_idx, 0);
 
@@ -2342,7 +2382,7 @@ build_html_formatting_state (CONVERTER *converter, 
unsigned long flags)
           && flags & HMSF_top_formatting_context)
         {
           HTML_FORMATTING_CONTEXT *top_formatting_ctx
-         = top_html_formatting_context (&top_document_ctx->formatting_context);
+         = html_top_formatting_context (&top_document_ctx->formatting_context);
           SSize_t top_formatting_context_idx;
           SV **top_formatting_context_sv;
           HV *top_formatting_context_hv;
@@ -2594,3 +2634,34 @@ build_html_command_formatted_args (HTML_ARGS_FORMATTED 
*args_formatted)
 
   return newRV_noinc ((SV *) av);
 }
+
+SV *
+build_replaced_substrings (NAMED_STRING_ELEMENT_LIST *replaced_substrings)
+{
+  HV *hv;
+  int i;
+
+  dTHX;
+
+  if (!replaced_substrings)
+    return newSV (0);
+
+  hv = newHV ();
+
+  for (i = 0; i < replaced_substrings->number; i++)
+    {
+      NAMED_STRING_ELEMENT *named_string_elt = &replaced_substrings->list[i];
+      SV *name_sv = newSVpv_utf8 (named_string_elt->name, 0);
+      SV *value_sv = 0;
+
+      if (named_string_elt->element)
+        value_sv = newRV_inc ((SV *) named_string_elt->element->hv);
+      else if (named_string_elt->string)
+        value_sv = newSVpv_utf8 (named_string_elt->string, 0);
+
+      if (value_sv)
+        hv_store_ent (hv, name_sv, value_sv, 0);
+    }
+
+  return newRV_noinc ((SV *) hv);
+}
diff --git a/tp/Texinfo/XS/main/build_perl_info.h 
b/tp/Texinfo/XS/main/build_perl_info.h
index 3638e76962..2218f0dc81 100644
--- a/tp/Texinfo/XS/main/build_perl_info.h
+++ b/tp/Texinfo/XS/main/build_perl_info.h
@@ -9,6 +9,8 @@
 #include "converter_types.h"
 /* for FILE_SOURCE_INFO_LIST and HTML_ARGS_FORMATTED */
 #include "utils.h"
+/* for NAMED_STRING_ELEMENT_LIST */
+#include "translations.h"
 
 int init (int texinfo_uninstalled, char *srcdir_in);
 
@@ -52,9 +54,12 @@ SV *build_filenames (FILE_NAME_PATH_COUNTER_LIST 
*output_unit_files);
 SV *build_file_counters (FILE_NAME_PATH_COUNTER_LIST *output_unit_files);
 SV *build_out_filepaths (FILE_NAME_PATH_COUNTER_LIST *output_unit_files);
 
+HV *build_html_document_context (HTML_DOCUMENT_CONTEXT *document_context);
+
 SV *build_html_formatting_state (CONVERTER *converter, unsigned long flags);
 
 void build_output_files_information (CONVERTER *converter);
 
 SV *build_html_command_formatted_args (HTML_ARGS_FORMATTED *args_formatted);
+SV *build_replaced_substrings (NAMED_STRING_ELEMENT_LIST *replaced_substrings);
 #endif
diff --git a/tp/Texinfo/XS/main/call_perl_function.c 
b/tp/Texinfo/XS/main/call_perl_function.c
index 4c95c6b1c0..6fb59090bd 100644
--- a/tp/Texinfo/XS/main/call_perl_function.c
+++ b/tp/Texinfo/XS/main/call_perl_function.c
@@ -722,6 +722,80 @@ call_formatting_function_format_begin_file (CONVERTER 
*self, char *filename,
   return result;
 }
 
+char *
+call_formatting_function_format_translate_message_string (CONVERTER *self,
+                                  const char *message, const char *lang,
+                         NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                                  const char *message_context)
+{
+  int count;
+  char *result = 0;
+  char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  SV *formatting_reference_sv;
+  SV *replaced_substrings_sv;
+
+  dTHX;
+
+  if (!self->hv)
+    return 0;
+
+  formatting_reference_sv
+    = self->formatting_references[
+         FR_format_translate_message_string].sv_reference;
+
+  if (self->modified_state)
+    {
+      build_html_formatting_state (self, self->modified_state);
+      self->modified_state = 0;
+    }
+
+  if (replaced_substrings)
+    replaced_substrings_sv = build_replaced_substrings (replaced_substrings);
+  else
+    replaced_substrings_sv = newSV (0);
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 5);
+
+  PUSHs(sv_2mortal (newRV_inc (self->hv)));
+  PUSHs(sv_2mortal (newSVpv_utf8 (message, 0)));
+  PUSHs(sv_2mortal (newSVpv (lang, 0)));
+  PUSHs(sv_2mortal (replaced_substrings_sv));
+  PUSHs(sv_2mortal (newSVpv_utf8 (message_context, 0)));
+  PUTBACK;
+
+  count = call_sv (formatting_reference_sv,
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("format_translate_message_string should return 1 item\n");
+
+  result_sv = POPs;
+  if (SvOK (result_sv))
+    {
+      result_ret = SvPVutf8 (result_sv, len);
+      result = strdup (result_ret);
+    }
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
+
+
 char *
 call_types_conversion (CONVERTER *self, enum element_type type,
                        FORMATTING_REFERENCE *formatting_reference,
diff --git a/tp/Texinfo/XS/main/call_perl_function.h 
b/tp/Texinfo/XS/main/call_perl_function.h
index 5b2cea12bc..d340134933 100644
--- a/tp/Texinfo/XS/main/call_perl_function.h
+++ b/tp/Texinfo/XS/main/call_perl_function.h
@@ -4,6 +4,7 @@
 
 #include "tree_types.h"
 #include "converter_types.h"
+#include "translations.h"
 
 typedef struct FILE_NAME_PATH {
     char *filename;
@@ -59,5 +60,9 @@ char *call_commands_open (CONVERTER *self, enum command_id 
cmd,
 char *call_output_units_conversion (CONVERTER *self,
                                     enum output_unit_type unit_type,
                                 OUTPUT_UNIT *output_unit, const char *content);
+char *call_formatting_function_format_translate_message_string (CONVERTER 
*self,
+                                  const char *message, const char *lang,
+                         NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                                  const char *message_context);
 
 #endif
diff --git a/tp/Texinfo/XS/main/command_stack.c 
b/tp/Texinfo/XS/main/command_stack.c
index bca18ef1f9..2ae66f1c3c 100644
--- a/tp/Texinfo/XS/main/command_stack.c
+++ b/tp/Texinfo/XS/main/command_stack.c
@@ -200,7 +200,7 @@ top_monospace_context (MONOSPACE_CONTEXT_STACK *stack)
 
 /* HTML specific but also used to build perl */
 HTML_DOCUMENT_CONTEXT *
-top_document_context (CONVERTER *self)
+html_top_document_context (CONVERTER *self)
 {
   HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
 
@@ -211,7 +211,7 @@ top_document_context (CONVERTER *self)
 }
 
 HTML_FORMATTING_CONTEXT *
-top_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack)
+html_top_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack)
 {
   if (stack->top == 0)
     fatal ("HTML formatting context stack empty for top");
diff --git a/tp/Texinfo/XS/main/command_stack.h 
b/tp/Texinfo/XS/main/command_stack.h
index cae30f6202..f689f07a67 100644
--- a/tp/Texinfo/XS/main/command_stack.h
+++ b/tp/Texinfo/XS/main/command_stack.h
@@ -41,8 +41,8 @@ void push_style_no_code (MONOSPACE_CONTEXT_STACK *stack);
 enum monospace_context pop_monospace_context (MONOSPACE_CONTEXT_STACK *stack);
 enum monospace_context top_monospace_context (MONOSPACE_CONTEXT_STACK *stack);
 
-HTML_DOCUMENT_CONTEXT *top_document_context (CONVERTER *self);
+HTML_DOCUMENT_CONTEXT *html_top_document_context (CONVERTER *self);
 
-HTML_FORMATTING_CONTEXT *top_html_formatting_context
+HTML_FORMATTING_CONTEXT *html_top_formatting_context
                          (HTML_FORMATTING_CONTEXT_STACK *stack);
 #endif
diff --git a/tp/Texinfo/XS/main/converter_types.h 
b/tp/Texinfo/XS/main/converter_types.h
index 281200a46f..40b7d4ced7 100644
--- a/tp/Texinfo/XS/main/converter_types.h
+++ b/tp/Texinfo/XS/main/converter_types.h
@@ -90,8 +90,7 @@ enum direction_string {
   #undef tds_type
 };
 
-/* %default_formatting_references + %default_css_string_formatting_references
-   in Texinfo::HTML */
+/* %default_formatting_references in Texinfo::HTML */
 #define HTML_FORMATTING_REFERENCES_LIST \
   html_fr_reference(format_begin_file) \
   html_fr_reference(format_button) \
@@ -116,21 +115,12 @@ enum direction_string {
   html_fr_reference(format_translate_message_tree) \
   html_fr_reference(format_translate_message_string) \
 
-#define HTML_CSS_FORMATTING_REFERENCES_LIST \
-  html_fr_reference(format_protect_text)
-
 enum html_formatting_reference {
   #define html_fr_reference(name) FR_## name,
    HTML_FORMATTING_REFERENCES_LIST
   #undef html_fr_reference
 };
 
-enum html_css_string_formatting_reference {
-  #define html_fr_reference(name) CSSFR_## name,
-   HTML_CSS_FORMATTING_REFERENCES_LIST
-  #undef html_fr_reference
-};
-
 typedef struct {
     enum command_id *stack;
     size_t top;   /* One above last pushed command. */
@@ -448,6 +438,10 @@ typedef struct CONVERTER {
                                            change */
     ARRAY_INDEX_LIST file_changed_counter;  /* index of files in
                                  output_unit_files with changed counter */
+    int document_context_change; /* change of document context top that may 
need
+                                    to be brought to perl */
+    int document_contexts_to_pop;  /* number of contexts to pop in perl before
+                                      readding the new contexts */
     size_t *output_unit_file_indices;   /* array of indices in 
output_unit_files
               each position corresponding to an output unit. */
     size_t *special_unit_file_indices;  /* same for special output units */
diff --git a/tp/Texinfo/XS/main/get_perl_info.c 
b/tp/Texinfo/XS/main/get_perl_info.c
index b742c2fb2f..a996c22ae2 100644
--- a/tp/Texinfo/XS/main/get_perl_info.c
+++ b/tp/Texinfo/XS/main/get_perl_info.c
@@ -234,22 +234,24 @@ get_expanded_formats (HV *hv, EXPANDED_FORMAT 
**expanded_formats)
                                   strlen ("expanded_formats"), 0);
   if (expanded_formats_sv)
     {
-      int i;
-      SSize_t formats_nr;
+      I32 i;
+      I32 formats_nr;
 
       if (!*expanded_formats)
         *expanded_formats = new_expanded_formats (0);
 
-      AV *av = (AV *)SvRV (*expanded_formats_sv);
+      HV *expanded_formats_hv = (HV *)SvRV (*expanded_formats_sv);
+
+      formats_nr = hv_iterinit (expanded_formats_hv);
 
-      formats_nr = av_top_index (av) +1;
       for (i = 0; i < formats_nr; i++)
         {
-          SV** string_sv = av_fetch (av, i, 0);
-          if (string_sv)
+          char *format;
+          I32 retlen;
+          SV *value_sv = hv_iternextsv (expanded_formats_hv, &format, &retlen);
+          if (SvTRUE (value_sv))
             {
-              char *string = SvPVbyte_nolen (*string_sv);
-              add_expanded_format (*expanded_formats, string);
+              add_expanded_format (*expanded_formats, format);
             }
         }
     }
diff --git a/tp/Texinfo/XS/main/translations.c 
b/tp/Texinfo/XS/main/translations.c
index 4a0b65dd35..b820299160 100644
--- a/tp/Texinfo/XS/main/translations.c
+++ b/tp/Texinfo/XS/main/translations.c
@@ -147,10 +147,10 @@ switch_messages_locale (void)
 }
 
 char *
-translate_string (OPTIONS *options, char * string,
-                  const char *translation_context, char *in_lang)
+translate_string (OPTIONS *options, const char * string,
+                  const char *translation_context, const char *in_lang)
 {
-  char *lang = in_lang;
+  const char *lang = in_lang;
   char *saved_LANGUAGE;
   char *saved_LANG;
   char *saved_LC_MESSAGES;
@@ -262,7 +262,7 @@ translate_string (OPTIONS *options, char * string,
     #$perl_encoding = $DEFAULT_PERL_ENCODING;
   }
  */
-  langs[0] = lang;
+  langs[0] = strdup (lang);
   p = strchr (lang, '_');
   if (p && p - lang > 0)
     {
@@ -315,6 +315,7 @@ translate_string (OPTIONS *options, char * string,
           text_append_n (&language_locales, ".", 1);
           text_append (&language_locales, "us-ascii");
         }
+      free (langs[i]);
     }
   if (setenv ("LANGUAGE", language_locales.text, 1) != 0)
     {
@@ -562,9 +563,10 @@ replace_convert_substrings (char *translated_string,
       free (texinfo_line);
     }
 
-/*
-  fprintf (stderr, "RESULT GDT %d: %s\n", document_descriptor,
+
+  debug("XS|RESULT GDT %d: '%s'\n", document_descriptor,
                                           convert_to_texinfo (document->tree));
+/*
 */
 
   return document_descriptor;
@@ -572,9 +574,9 @@ replace_convert_substrings (char *translated_string,
 
 /* returns a document descriptor. */
 int
-gdt (char *string, OPTIONS *options,
+gdt (const char *string, OPTIONS *options,
      NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-     const char *translation_context, char *in_lang)
+     const char *translation_context, const char *in_lang)
 {
   char *translated_string = translate_string (options, string,
                                               translation_context,
@@ -591,10 +593,10 @@ gdt (char *string, OPTIONS *options,
    DOCUMENT small strings.  It is possible to pass 0 for the DOCUMENT
    if one knows that there won't be small strings (the general case) */
 ELEMENT *
-gdt_tree (char *string, DOCUMENT *document, OPTIONS *options,
+gdt_tree (const char *string, DOCUMENT *document, OPTIONS *options,
           NAMED_STRING_ELEMENT_LIST *replaced_substrings,
           const char *translation_context,
-          char *in_lang)
+          const char *in_lang)
 {
   ELEMENT *tree;
   int gdt_document_descriptor = gdt (string, options, replaced_substrings,
@@ -625,9 +627,9 @@ gdt_tree (char *string, DOCUMENT *document, OPTIONS 
*options,
 }
 
 char *
-gdt_string (char *string, OPTIONS *options,
+gdt_string (const char *string, OPTIONS *options,
             NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-            const char *translation_context, char *in_lang)
+            const char *translation_context, const char *in_lang)
 {
   char *translated_string = translate_string (options, string,
                                               translation_context,
@@ -639,10 +641,10 @@ gdt_string (char *string, OPTIONS *options,
 }
 
 ELEMENT *
-pgdt_tree (const char *translation_context, char *string,
+pgdt_tree (const char *translation_context, const char *string,
            DOCUMENT *document, OPTIONS *options,
            NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-           char *in_lang)
+           const char *in_lang)
 {
   return gdt_tree (string, document, options, replaced_substrings,
                    translation_context, in_lang);
diff --git a/tp/Texinfo/XS/main/translations.h 
b/tp/Texinfo/XS/main/translations.h
index 290739a81e..f38f7d1f3e 100644
--- a/tp/Texinfo/XS/main/translations.h
+++ b/tp/Texinfo/XS/main/translations.h
@@ -21,24 +21,24 @@ typedef struct NAMED_STRING_ELEMENT_LIST {
     NAMED_STRING_ELEMENT *list;
 } NAMED_STRING_ELEMENT_LIST;
 
-int gdt (char * string, OPTIONS *options,
+int gdt (const char * string, OPTIONS *options,
          NAMED_STRING_ELEMENT_LIST *replaced_substrings,
          const char *translation_context,
-         char *in_lang);
+         const char *in_lang);
 
-ELEMENT *gdt_tree (char * string, DOCUMENT *document, OPTIONS *options,
+ELEMENT *gdt_tree (const char * string, DOCUMENT *document, OPTIONS *options,
                    NAMED_STRING_ELEMENT_LIST *replaced_substrings,
                    const char *translation_context,
-                   char *in_lang);
+                   const char *in_lang);
 
-char *gdt_string (char *string, OPTIONS *options,
+char *gdt_string (const char *string, OPTIONS *options,
                   NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                  const char *translation_context, char *in_lang);
+                  const char *translation_context, const char *in_lang);
 
-ELEMENT *pgdt_tree (const char *translation_context, char *string,
+ELEMENT *pgdt_tree (const char *translation_context, const char *string,
                     DOCUMENT *document, OPTIONS *options,
                     NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                    char *in_lang);
+                    const char *in_lang);
 
 NAMED_STRING_ELEMENT_LIST * new_named_string_element_list (void);
 void add_string_to_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel,
diff --git a/tp/Texinfo/XS/main/utils.c b/tp/Texinfo/XS/main/utils.c
index 99c4f045d2..3aec357159 100644
--- a/tp/Texinfo/XS/main/utils.c
+++ b/tp/Texinfo/XS/main/utils.c
@@ -86,12 +86,6 @@ char *html_formatting_reference_names[] = {
   #undef html_fr_reference
 };
 
-char *html_css_string_formatting_reference_names[] = {
-  #define html_fr_reference(name) #name,
-   HTML_CSS_FORMATTING_REFERENCES_LIST
-  #undef html_fr_reference
-};
-
 const char *html_argument_formatting_type_names[] = {
    #define html_aft_type(name) #name,
     HTML_ARGUMENTS_FORMATTED_FORMAT_TYPE
diff --git a/tp/Texinfo/XS/main/utils.h b/tp/Texinfo/XS/main/utils.h
index 52a5e183dd..8167d06c98 100644
--- a/tp/Texinfo/XS/main/utils.h
+++ b/tp/Texinfo/XS/main/utils.h
@@ -44,7 +44,6 @@ extern char *html_conversion_context_type_names[];
 extern char *html_global_unit_direction_names[];
 
 extern char *html_formatting_reference_names[];
-extern char *html_css_string_formatting_reference_names[];
 
 typedef struct {
     char *encoding_name;
diff --git a/tp/init/documentation_examples.pm 
b/tp/init/documentation_examples.pm
index 1a02fa7850..4bb590d37c 100644
--- a/tp/init/documentation_examples.pm
+++ b/tp/init/documentation_examples.pm
@@ -82,7 +82,10 @@ sub my_email_formatting_function {
   my $command = shift;
   my $args = shift;
 
-  my $args_nr = scalar(@$args);
+  my $args_nr = 0;
+  if ($args) {
+    $args_nr = scalar(@$args);
+  }
 
   my $mail = '';
   my $mail_string = '';
diff --git a/tp/init/html32.pm b/tp/init/html32.pm
index 86bcf5a43a..c345f4bc80 100644
--- a/tp/init/html32.pm
+++ b/tp/init/html32.pm
@@ -181,11 +181,10 @@ sub html32_convert_explained_command($$$$)
 
   my $with_explanation;
 
-  return '' if (!defined($args->[0]) or !defined($args->[0]->{'normal'})
+  return '' if (!$args or !$args->[0]
                 or $args->[0]->{'normal'} !~ /\S/);
 
-  if (defined($args->[1]) and defined($args->[1]->{'string'})
-                 and $args->[1]->{'string'} =~ /\S/) {
+  if ($args->[1] and $args->[1]->{'string'} =~ /\S/) {
     $with_explanation = 1;
   }
 
@@ -332,7 +331,7 @@ sub html32_convert_center_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  if (!defined($args->[0])) {
+  if (!$args or !$args->[0]) {
     return '';
   }
 
@@ -399,7 +398,7 @@ sub html32_convert_subtitle_command($$$$)
   my $command = shift;
   my $args = shift;
 
-  return '' if (! defined($args->[0]));
+  return '' if (!$args or !$args->[0]);
 
   if (!$self->in_string()) {
     return "<h3 align=\"right\">$args->[0]->{'normal'}</h3>\n";
diff --git a/tp/t/accents.t b/tp/t/accents.t
index 6184865ae1..98f5103733 100644
--- a/tp/t/accents.t
+++ b/tp/t/accents.t
@@ -102,7 +102,13 @@ sub test_enable_encoding ($)
                                                  $commands_stack, 'iso-8859-1',
                                 
\&Texinfo::Convert::Text::ascii_accent_fallback);
 
-  my $html_converter = Texinfo::Convert::HTML->converter();
+  my $options = {};
+  if ($root->{'tree_document_descriptor'}) {
+    $options->{'document_descriptor'} = $root->{'tree_document_descriptor'};
+  }
+  my $html_converter = Texinfo::Convert::HTML->converter($options);
+  # NOTE we use a converter outside of output/convert
+  $html_converter->_initialize_output_state('_test_accents');
   my $result_xml = Texinfo::Convert::Converter::xml_accents($html_converter,
                                                             $accent_tree);
   $html_converter->{'conf'}->{'USE_NUMERIC_ENTITY'} = 1;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]