texinfo-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Patrice Dumas
Date: Sat, 25 Nov 2023 18:22:02 -0500 (EST)

branch: master
commit d3ad6d6ca523ab44d1d69b0da5e728e4494adcf0
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sun Nov 26 00:20:47 2023 +0100

    * tp/Texinfo/XS/main/tree.c (remove_from_element_list): do not accept
    a where index equal to list->number.  Do not call memmove if it is not
    needed.
    
    * tp/Texinfo/XS/convert/convert_html.c (count_elements_in_filename):
    fix result with CEFT_current.
    
    * tp/Texinfo/XS/convert/get_html_perl_info.c
    (html_converter_initialize_sv): use simplified_special_unit_info
    instead of special_unit_info to get all the information.
    
    * tp/Texinfo/XS/convert/build_html_perl_state.c
    (build_html_formatting_state), tp/Texinfo/XS/convert/convert_html.c
    (html_free_converter), tp/Texinfo/XS/main/converter_types.h
    (CONVERTER): add referred_command_stack, add code to free and pass to
    perl.
    
    * tp/Texinfo/XS/convert/convert_html.c (new_tree_added_elements)
    (clear_tree_added_elements, free_tree_added_elements)
    (destroy_tree_added_elements, new_element_added),
    tp/Texinfo/XS/main/tree_types.h (enum tree_added_elements_status)
    (TREE_ADDED_ELEMENTS): add functions and structure to handle trees
    with added elements and Texinfo tree elements, or new tree obtained
    from gdt, in order to manage memory correctly, and unregister elements
    that were scheduled to be built for perl but are destroyed.
    
    * tp/Texinfo/XS/convert/call_html_perl_function.c
    (build_tree_to_build, call_*), tp/Texinfo/XS/convert/convert_html.c
    (special_unit_info_tree, html_finalize_output_state)
    (html_check_transfer_state_finalization)
    (reset_unset_no_arg_commands_formatting_context),
    tp/Texinfo/XS/main/converter_types.h (CONVERTER),
    tp/Texinfo/XS/main/tree.c (add_element_if_not_in_list): change
    tree_to_build to be a list.  Add and remove from the list, and add
    build_tree_to_build to build all the elements to perl in call_*
    functions.
    
    * tp/Texinfo/XS/main/build_perl_info.c (element_to_perl_hash)
    (build_perl_array, build_perl_container, build_perl_directions)
    (store_additional_info, build_texinfo_tree): add an argument,
    avoid_recursion, to recurse into children or out of tree elements only
    if hv is not already set.  Update callers.
    
    * tp/Texinfo/XS/convert/converter.c (float_type_number): add.
    
    * tp/Texinfo/XS/convert/call_html_perl_function.c
    (call_formatting_function_format_heading_text)
    (call_formatting_function_format_element_footer): add.
    
    * tp/Texinfo/XS/convert/convert_html.c (html_command_tree)
    (html_command_text, reset_html_targets, html_translate_names)
    tp/Texinfo/XS/main/converter_types.h (enum html_command_text_type)
    (HTML_TARGET): add. Update HTML_TARGET. Set and free html_target tree,
    tree_nonumber and command_text.
    
    * tp/Texinfo/XS/convert/convert_html.c (convert_special_unit_type)
    (output_units_internal_conversion_table): finish implementation of
    convert_special_unit_type.
    
    * tp/Texinfo/XS/main/translations.c (replace_substrings)
    (add_element_to_named_string_element_list)
    (add_string_to_named_string_element_list),
    tp/Texinfo/XS/main/translations.h (NAMED_STRING_ELEMENT): add some
    const.
    
    * tp/Texinfo/XS/main/output_unit.c (output_unit_texi),
    tp/Texinfo/Structuring.pm (output_unit_texi): better debug
    message.
---
 ChangeLog                                          |  71 ++
 tp/Texinfo/Structuring.pm                          |   2 +
 tp/Texinfo/XS/convert/build_html_perl_state.c      |  29 +-
 tp/Texinfo/XS/convert/call_html_perl_function.c    | 213 ++++-
 tp/Texinfo/XS/convert/call_html_perl_function.h    |  12 +-
 tp/Texinfo/XS/convert/convert_html.c               | 861 +++++++++++++++------
 tp/Texinfo/XS/convert/converter.c                  |  46 ++
 tp/Texinfo/XS/convert/converter.h                  |   1 +
 tp/Texinfo/XS/convert/get_html_perl_info.c         |  10 +-
 tp/Texinfo/XS/main/build_perl_info.c               |  57 +-
 tp/Texinfo/XS/main/build_perl_info.h               |   4 +-
 tp/Texinfo/XS/main/call_perl_function.c            |   4 +-
 tp/Texinfo/XS/main/converter_types.h               |  29 +-
 tp/Texinfo/XS/main/output_unit.c                   |   7 +
 tp/Texinfo/XS/main/translations.c                  |  12 +-
 tp/Texinfo/XS/main/translations.h                  |  15 +-
 tp/Texinfo/XS/main/tree.c                          |  21 +-
 tp/Texinfo/XS/main/tree.h                          |   3 +-
 tp/Texinfo/XS/main/tree_types.h                    |  16 +
 tp/Texinfo/XS/main/utils.h                         |   3 +-
 .../XS/structuring_transfo/StructuringTransfo.xs   |   2 +-
 21 files changed, 1088 insertions(+), 330 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 98aa88cb94..f77bb426d4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,74 @@
+2023-11-25  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/XS/main/tree.c (remove_from_element_list): do not accept
+       a where index equal to list->number.  Do not call memmove if it is not
+       needed.
+
+       * tp/Texinfo/XS/convert/convert_html.c (count_elements_in_filename):
+       fix result with CEFT_current.
+
+       * tp/Texinfo/XS/convert/get_html_perl_info.c
+       (html_converter_initialize_sv): use simplified_special_unit_info
+       instead of special_unit_info to get all the information.
+
+       * tp/Texinfo/XS/convert/build_html_perl_state.c
+       (build_html_formatting_state), tp/Texinfo/XS/convert/convert_html.c
+       (html_free_converter), tp/Texinfo/XS/main/converter_types.h
+       (CONVERTER): add referred_command_stack, add code to free and pass to
+       perl.
+
+       * tp/Texinfo/XS/convert/convert_html.c (new_tree_added_elements)
+       (clear_tree_added_elements, free_tree_added_elements)
+       (destroy_tree_added_elements, new_element_added),
+       tp/Texinfo/XS/main/tree_types.h (enum tree_added_elements_status)
+       (TREE_ADDED_ELEMENTS): add functions and structure to handle trees
+       with added elements and Texinfo tree elements, or new tree obtained
+       from gdt, in order to manage memory correctly, and unregister elements
+       that were scheduled to be built for perl but are destroyed.
+
+       * tp/Texinfo/XS/convert/call_html_perl_function.c
+       (build_tree_to_build, call_*), tp/Texinfo/XS/convert/convert_html.c
+       (special_unit_info_tree, html_finalize_output_state)
+       (html_check_transfer_state_finalization)
+       (reset_unset_no_arg_commands_formatting_context),
+       tp/Texinfo/XS/main/converter_types.h (CONVERTER),
+       tp/Texinfo/XS/main/tree.c (add_element_if_not_in_list): change
+       tree_to_build to be a list.  Add and remove from the list, and add
+       build_tree_to_build to build all the elements to perl in call_*
+       functions.
+
+       * tp/Texinfo/XS/main/build_perl_info.c (element_to_perl_hash)
+       (build_perl_array, build_perl_container, build_perl_directions)
+       (store_additional_info, build_texinfo_tree): add an argument,
+       avoid_recursion, to recurse into children or out of tree elements only
+       if hv is not already set.  Update callers.
+
+       * tp/Texinfo/XS/convert/converter.c (float_type_number): add.
+
+       * tp/Texinfo/XS/convert/call_html_perl_function.c
+       (call_formatting_function_format_heading_text)
+       (call_formatting_function_format_element_footer): add.
+
+       * tp/Texinfo/XS/convert/convert_html.c (html_command_tree)
+       (html_command_text, reset_html_targets, html_translate_names)
+       tp/Texinfo/XS/main/converter_types.h (enum html_command_text_type)
+       (HTML_TARGET): add. Update HTML_TARGET. Set and free html_target tree,
+       tree_nonumber and command_text.
+
+       * tp/Texinfo/XS/convert/convert_html.c (convert_special_unit_type)
+       (output_units_internal_conversion_table): finish implementation of
+       convert_special_unit_type.
+
+       * tp/Texinfo/XS/main/translations.c (replace_substrings)
+       (add_element_to_named_string_element_list)
+       (add_string_to_named_string_element_list),
+       tp/Texinfo/XS/main/translations.h (NAMED_STRING_ELEMENT): add some
+       const.
+
+       * tp/Texinfo/XS/main/output_unit.c (output_unit_texi),
+       tp/Texinfo/Structuring.pm (output_unit_texi): better debug
+       message.
+
 2023-11-25  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/Convert/HTML.pm (count_elements_in_filename)
diff --git a/tp/Texinfo/Structuring.pm b/tp/Texinfo/Structuring.pm
index 7a8b38d999..c2262b617d 100644
--- a/tp/Texinfo/Structuring.pm
+++ b/tp/Texinfo/Structuring.pm
@@ -2130,6 +2130,8 @@ sub output_unit_texi($)
   if ($output_unit->{'unit_type'} eq 'external_node_unit') {
     return Texinfo::Convert::Texinfo::convert_to_texinfo(
                             {'contents' => $unit_command->{'contents'}});
+  } elsif ($output_unit->{'unit_type'} eq 'special_unit') {
+    return "_SPECIAL_UNIT: $output_unit->{'special_unit_variety'}";
   }
 
   if (!$unit_command) {
diff --git a/tp/Texinfo/XS/convert/build_html_perl_state.c 
b/tp/Texinfo/XS/convert/build_html_perl_state.c
index 9497c135ee..d1077a29e2 100644
--- a/tp/Texinfo/XS/convert/build_html_perl_state.c
+++ b/tp/Texinfo/XS/convert/build_html_perl_state.c
@@ -517,7 +517,7 @@ build_html_translated_names (HV *hv, CONVERTER *converter)
               if (no_arg_cmd_context->tree)
                 {
                   if (!no_arg_cmd_context->tree->hv)
-                    element_to_perl_hash (no_arg_cmd_context->tree);
+                    element_to_perl_hash (no_arg_cmd_context->tree, 1);
                   hv_store (context_hv, "tree", strlen ("tree"),
                           newRV_inc ((SV *) no_arg_cmd_context->tree->hv), 0);
                 }
@@ -978,6 +978,33 @@ build_html_formatting_state (CONVERTER *converter, 
unsigned long flags)
         }
     }
 
+  if (flags & HMSF_referred_command_stack)
+    {
+      SV **referred_command_stack_sv;
+      AV *referred_command_stack_av;
+
+      FETCH(referred_command_stack);
+
+      if (!referred_command_stack_sv)
+        {
+          referred_command_stack_av = newAV ();
+          STORE("referred_command_stack",
+                newRV_noinc ((SV *) referred_command_stack_av));
+        }
+      else
+        {
+          referred_command_stack_av = (AV *) SvRV (*referred_command_stack_sv);
+          av_clear (referred_command_stack_av);
+        }
+
+      for (i = 0; i < converter->referred_command_stack.number; i++)
+        {
+          ELEMENT *referred_e = converter->referred_command_stack.list[i];
+          av_push (referred_command_stack_av,
+                   newRV_inc ((SV *) referred_e->hv));
+        }
+    }
+
   if (converter->file_changed_counter.number)
     {
       SV **file_counters_sv;
diff --git a/tp/Texinfo/XS/convert/call_html_perl_function.c 
b/tp/Texinfo/XS/convert/call_html_perl_function.c
index 6c281c97aa..a1f8d1d6f1 100644
--- a/tp/Texinfo/XS/convert/call_html_perl_function.c
+++ b/tp/Texinfo/XS/convert/call_html_perl_function.c
@@ -38,6 +38,20 @@
 #include "build_html_perl_state.h"
 #include "call_html_perl_function.h"
 
+static void
+build_tree_to_build (ELEMENT_LIST *tree_to_build)
+{
+  if (tree_to_build->number > 0)
+    {
+      int i;
+      for (i = 0; i < tree_to_build->number; i++)
+        {
+          build_texinfo_tree (tree_to_build->list[i], 1);
+        }
+      tree_to_build->number = 0;
+    }
+}
+
 TARGET_FILENAME *
 call_file_id_setting_special_unit_target_file_name (CONVERTER *self,
                                       OUTPUT_UNIT *special_unit, char *target,
@@ -751,7 +765,7 @@ char *
 call_formatting_function_format_navigation_header (CONVERTER *self,
                                   const BUTTON_SPECIFICATION_LIST *buttons,
                                   const char *cmdname,
-                                  const ELEMENT *element)
+                                  ELEMENT *element)
 {
   int count;
   char *result = 0;
@@ -775,6 +789,8 @@ call_formatting_function_format_navigation_header 
(CONVERTER *self,
       self->modified_state = 0;
     }
 
+  build_tree_to_build (&self->tree_to_build);
+
   dSP;
 
   ENTER;
@@ -809,6 +825,165 @@ call_formatting_function_format_navigation_header 
(CONVERTER *self,
   return result;
 }
 
+char *
+call_formatting_function_format_heading_text (CONVERTER *self,
+                                  const char *cmdname,
+                                  const STRING_LIST *classes,
+                                  const char *text,
+                                  int level, const char *id,
+                                  ELEMENT *element, const char *target)
+{
+  int count;
+  char *result = 0;
+  char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  SV *formatting_reference_sv;
+  SV *classes_sv;
+  SV *element_sv;
+
+  dTHX;
+
+  if (!self->hv)
+    return 0;
+
+  formatting_reference_sv
+    = self->formatting_references[
+         FR_format_heading_text].sv_reference;
+
+  if (self->modified_state)
+    {
+      build_html_formatting_state (self, self->modified_state);
+      self->modified_state = 0;
+    }
+
+  build_tree_to_build (&self->tree_to_build);
+
+  if (classes && classes->number)
+    {
+      size_t i;
+      AV *classes_av = newAV ();
+      for (i = 0; i < classes->number; i++)
+        {
+          char *class = classes->list[i];
+          SV *class_sv = newSVpv_utf8 (class, 0);
+          av_push (classes_av, class_sv);
+        }
+      classes_sv = newRV_noinc ((SV *) classes_av);
+    }
+  else
+    classes_sv = newSV (0);
+
+  if (element)
+    element_sv = newRV_inc (element->hv);
+  else
+    element_sv = newSV (0);
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 7);
+
+  PUSHs(sv_2mortal (newRV_inc (self->hv)));
+  PUSHs(sv_2mortal (newSVpv (cmdname, 0)));
+  PUSHs(sv_2mortal (classes_sv));
+  PUSHs(sv_2mortal (newSVpv_utf8 (text, 0)));
+  PUSHs(sv_2mortal (newSViv ((IV) level)));
+  PUSHs(sv_2mortal (newSVpv_utf8 (id, 0)));
+  PUSHs(sv_2mortal (element_sv));
+  PUSHs(sv_2mortal (newSVpv_utf8 (target, 0)));
+  PUTBACK;
+
+  count = call_sv (formatting_reference_sv,
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("format_heading_text should return 1 item\n");
+
+  result_sv = POPs;
+  result_ret = SvPVutf8 (result_sv, len);
+  result = strdup (result_ret);
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
+char *
+call_formatting_function_format_element_footer (CONVERTER *self,
+                              const enum output_unit_type unit_type,
+                              const OUTPUT_UNIT *output_unit,
+                              const char *content, ELEMENT *command)
+{
+  int count;
+  char *result = 0;
+  char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  SV *formatting_reference_sv;
+
+  dTHX;
+
+  if (!self->hv)
+    return 0;
+
+  formatting_reference_sv
+    = self->formatting_references[
+         FR_format_element_footer].sv_reference;
+
+  if (self->modified_state)
+    {
+      build_html_formatting_state (self, self->modified_state);
+      self->modified_state = 0;
+    }
+
+  build_tree_to_build (&self->tree_to_build);
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 5);
+
+  PUSHs(sv_2mortal (newRV_inc (self->hv)));
+  PUSHs(sv_2mortal (newSVpv (output_unit_type_names[unit_type], 0)));
+  PUSHs(sv_2mortal (newRV_inc (output_unit->hv)));
+  /* content == 0 is possible, hope that newSVpv result corresponds to
+     undef in that case, but could also need to explicitely use newSV(0) */
+  PUSHs(sv_2mortal (newSVpv_utf8 (content, 0)));
+  PUSHs(sv_2mortal (newRV_inc (command->hv)));
+  PUTBACK;
+
+  count = call_sv (formatting_reference_sv,
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("format_element_footer should return 1 item\n");
+
+  result_sv = POPs;
+  result_ret = SvPVutf8 (result_sv, len);
+  result = strdup (result_ret);
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
 
 
 
@@ -830,11 +1005,7 @@ call_types_conversion (CONVERTER *self, const enum 
element_type type,
   if (!self->hv)
     return;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   formatting_reference_sv = formatting_reference->sv_reference;
 
@@ -893,11 +1064,7 @@ call_types_open (CONVERTER *self, const enum element_type 
type,
 
   dTHX;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   if (!self->hv)
     return;
@@ -964,11 +1131,7 @@ call_commands_conversion (CONVERTER *self, const enum 
command_id cmd,
   if (!self->hv)
     return;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   /* could also be builtin_command_data[cmd].cmdname) */
   command_name = element_command_name (element);
@@ -1037,11 +1200,7 @@ call_commands_open (CONVERTER *self, const enum 
command_id cmd,
   if (!self->hv)
     return;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   formatting_reference_sv = self->commands_open[cmd].sv_reference;
 
@@ -1105,11 +1264,7 @@ call_output_units_conversion (CONVERTER *self,
   if (!self->hv)
     return;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   formatting_reference_sv
      = self->output_units_conversion[unit_type].sv_reference;
@@ -1176,11 +1331,7 @@ call_special_unit_body_formatting (CONVERTER *self,
   if (!self->hv)
     return;
 
-  if (self->tree_to_build)
-    {
-      build_texinfo_tree (self->tree_to_build);
-      self->tree_to_build = 0;
-    }
+  build_tree_to_build (&self->tree_to_build);
 
   formatting_reference_sv
      = self->special_unit_body[special_unit_number -1].sv_reference;
diff --git a/tp/Texinfo/XS/convert/call_html_perl_function.h 
b/tp/Texinfo/XS/convert/call_html_perl_function.h
index b1a82a437c..5f41bb3535 100644
--- a/tp/Texinfo/XS/convert/call_html_perl_function.h
+++ b/tp/Texinfo/XS/convert/call_html_perl_function.h
@@ -49,7 +49,17 @@ char *call_formatting_function_format_begin_file (CONVERTER 
*self,
 char *call_formatting_function_format_navigation_header (CONVERTER *self,
                                   const BUTTON_SPECIFICATION_LIST *buttons,
                                   const char *cmdname,
-                                  const ELEMENT *element);
+                                  ELEMENT *element);
+char *call_formatting_function_format_heading_text (CONVERTER *self,
+                                  const char *cmdname,
+                                  const STRING_LIST *classes,
+                                  const char *text,
+                                  int level, const char *id,
+                                  ELEMENT *element, const char *target);
+char *call_formatting_function_format_element_footer (CONVERTER *self,
+                              const enum output_unit_type unit_type,
+                              const OUTPUT_UNIT *output_unit,
+                              const char *content, ELEMENT *command);
 
 void call_types_conversion (CONVERTER *self, const enum element_type type,
                        const FORMATTING_REFERENCE *formatting_reference,
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index c4cacfca22..de71c82a0c 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -45,6 +45,7 @@
 #include "document.h"
 /* for OTXI_UNICODE_TEXT_CASES */
 #include "unicode.h"
+#include "manipulate_tree.h"
 #include "convert_html.h"
 
 enum count_elements_in_filename_type {
@@ -584,12 +585,12 @@ count_elements_in_filename (CONVERTER *self,
   else if (type == CEFT_remaining)
     return file_counter->counter;
   else /* if (type == CEFT_current) */
-    return file_counter->elements_in_file_count - file_counter->counter;
+    return file_counter->elements_in_file_count - file_counter->counter +1;
 }
 
 ELEMENT *
-special_unit_info_tree (CONVERTER *self, enum special_unit_info_tree type,
-                        char *special_unit_variety)
+special_unit_info_tree (CONVERTER *self, const enum special_unit_info_tree 
type,
+                        const char *special_unit_variety)
 {
   /* number is index +1 */
   size_t number = find_string (&self->special_unit_varieties,
@@ -608,6 +609,9 @@ special_unit_info_tree (CONVERTER *self, enum 
special_unit_info_tree type,
             = translated_special_unit_info[j].string_type;
           char *special_unit_info_string
             = self->special_unit_info[string_type][i];
+          /* if set to undef in user customization. To be forbidden? */
+          if (!special_unit_info_string)
+            return 0;
           char *translation_context;
           xasprintf (&translation_context, "%s section heading",
                      special_unit_variety);
@@ -615,6 +619,8 @@ special_unit_info_tree (CONVERTER *self, enum 
special_unit_info_tree type,
             = html_pgdt_tree (translation_context, special_unit_info_string,
                               self->document, self, 0, 0);
           free (translation_context);
+          add_to_element_list (&self->tree_to_build,
+                               self->special_unit_info_tree[type][i]);
           return self->special_unit_info_tree[type][i];
         }
     }
@@ -1428,37 +1434,6 @@ set_root_commands_targets_node_files (CONVERTER *self)
     }
 }
 
-static void
-register_added_target (HTML_ADDED_TARGET_LIST *added_targets,
-                       HTML_TARGET *target)
-{
-  if (added_targets->number == added_targets->space)
-    {
-      added_targets->list = realloc (added_targets->list,
-                   sizeof (HTML_TARGET *) * (added_targets->space += 5));
-    }
-  added_targets->list[added_targets->number] = target;
-  added_targets->number++;
-}
-
-static HTML_TARGET *
-get_target (CONVERTER *self, const ELEMENT *element)
-{
-  HTML_TARGET *result
-   = find_element_target (&self->html_targets, element);
-  if (!result && element->cmd
-      && builtin_command_flags(element) & CF_sectioning_heading
-      && !(builtin_command_flags(element) & CF_root)) {
-    new_sectioning_command_target (self, element);
-
-    result = find_element_target (&self->html_targets, element);
-
-    register_added_target (&self->added_targets, result);
-    self->modified_state |= HMSF_added_target;
-  }
-  return result;
-}
-
 /* to be inlined in text parsing codes */
 #define OTXI_PROTECT_XML_FORM_FEED_CASES(var) \
         OTXI_PROTECT_XML_CASES(var) \
@@ -1655,16 +1630,544 @@ html_default_format_protect_text (const char *text, 
TEXT *result)
 {
   const char *p = text;
 
-  OTXI_CONVERT_TEXT ( , )
+  OTXI_CONVERT_TEXT ( , )
+}
+
+static TREE_ADDED_ELEMENTS *
+new_tree_added_elements ()
+{
+  TREE_ADDED_ELEMENTS *new
+    = (TREE_ADDED_ELEMENTS *) malloc (sizeof (TREE_ADDED_ELEMENTS));
+  memset (new, 0, sizeof (TREE_ADDED_ELEMENTS));
+  return new;
+}
+
+static void
+clear_tree_added_elements (CONVERTER *self, TREE_ADDED_ELEMENTS *tree_elements)
+{
+  if (tree_elements->status != tree_added_status_reused_tree)
+    remove_element_from_list (&self->tree_to_build, tree_elements->tree);
+
+  if (tree_elements->status == tree_added_status_new_tree)
+    destroy_element_and_children (tree_elements->tree);
+  else if (tree_elements->status == tree_added_status_normal)
+    {
+      int i;
+      for (i = 0; i < tree_elements->added.number; i++)
+        {
+          ELEMENT *added_e = tree_elements->added.list[i];
+          destroy_element (added_e);
+        }
+      tree_elements->added.number = 0;
+    }
+  tree_elements->tree = 0;
+  tree_elements->status = 0;
+}
+
+static void
+free_tree_added_elements (CONVERTER *self, TREE_ADDED_ELEMENTS *tree_elements)
+{
+  clear_tree_added_elements (self, tree_elements);
+  free (tree_elements->added.list);
+}
+
+static void
+destroy_tree_added_elements (CONVERTER *self, TREE_ADDED_ELEMENTS 
*tree_elements)
+{
+  free_tree_added_elements (self, tree_elements);
+  free (tree_elements);
+}
+
+static void
+push_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack,
+                              char *context_name)
+{
+  if (stack->top >= stack->space)
+    {
+      stack->stack
+        = realloc (stack->stack,
+                   (stack->space += 5) * sizeof (HTML_FORMATTING_CONTEXT));
+    }
+
+  memset (&stack->stack[stack->top], 0, sizeof (HTML_FORMATTING_CONTEXT));
+
+  stack->stack[stack->top].context_name = strdup (context_name);
+
+  stack->top++;
+}
+
+static void
+pop_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("HTML formatting context stack empty");
+
+  free (stack->stack[stack->top - 1].context_name);
+  stack->top--;
+}
+
+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
+        = realloc (stack->stack,
+                   (stack->space += 5) * sizeof (HTML_DOCUMENT_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_integer_stack_integer (&doc_context->monospace, 0);
+  push_integer_stack_integer (&doc_context->preformatted_context, 0);
+  push_command_or_type (&doc_context->composition_context, 0, 0);
+  if (block_command)
+    push_command (&doc_context->block_commands, block_command);
+
+  if (document_global_context)
+    {
+      self->document_global_context++;
+      self->modified_state |= HMSF_converter_state;
+    }
+
+  push_html_formatting_context (&doc_context->formatting_context,
+                                "_format");
+
+  stack->top++;
+}
+
+void
+html_pop_document_context (CONVERTER *self)
+{
+  HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
+  HTML_DOCUMENT_CONTEXT *document_ctx;
+
+  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);
+  free (document_ctx->monospace.stack);
+  free (document_ctx->preformatted_context.stack);
+  free (document_ctx->composition_context.stack);
+  free (document_ctx->preformatted_classes.stack);
+  if (document_ctx->block_commands.top > 0)
+    pop_command (&document_ctx->block_commands);
+  free (document_ctx->block_commands.stack);
+  pop_html_formatting_context (&document_ctx->formatting_context);
+  free (document_ctx->formatting_context.stack);
+
+  if (document_ctx->document_global_context)
+    {
+      self->document_global_context--;
+      self->modified_state |= HMSF_converter_state;
+    }
+
+  stack->top--;
+}
+
+char *
+html_convert_tree (CONVERTER *self, const ELEMENT *tree, char *explanation)
+{
+  TEXT result;
+  text_init (&result);
+
+  convert_to_html_internal (self, tree, &result, explanation);
+
+  return result.text;
+}
+
+/* This function should be used in formatting functions when some
+   Texinfo tree need to be converted. */
+char *
+convert_tree_new_formatting_context (CONVERTER *self, const ELEMENT *tree,
+                              char *context_string, char *multiple_pass,
+                              char *document_global_context,
+                              enum command_id block_cmd)
+{
+  char *result;
+  char *multiple_pass_str = "";
+  char *explanation;
+  TEXT context_string_str;
+  text_init (&context_string_str);
+  text_append (&context_string_str, "");
+
+  if (context_string)
+    {
+      html_new_document_context (self, context_string,
+                                 document_global_context, block_cmd);
+      text_printf (&context_string_str, "C(%s)", context_string);
+    }
+
+  if (multiple_pass)
+    {
+      self->ignore_notice++;
+      push_string_stack_string (&self->multiple_pass, multiple_pass);
+      self->modified_state |= HMSF_multiple_pass | HMSF_converter_state;
+      multiple_pass_str = "|M";
+    }
+
+  if (self->conf->DEBUG > 0)
+    fprintf (stderr, "new_fmt_ctx %s%s\n", context_string_str.text,
+                                           multiple_pass_str);
+
+  xasprintf (&explanation, "new_fmt_ctx %s", context_string_str.text);
+  result = html_convert_tree (self, tree, explanation);
+
+  free (explanation);
+  free (context_string_str.text);
+
+  if (context_string)
+    {
+      html_pop_document_context (self);
+    }
+
+  if (multiple_pass)
+    {
+      self->ignore_notice--;
+      pop_string_stack (&self->multiple_pass);
+      self->modified_state |= HMSF_multiple_pass | HMSF_converter_state;
+    }
+
+  return result;
+}
+
+static void
+register_added_target (HTML_ADDED_TARGET_LIST *added_targets,
+                       HTML_TARGET *target)
+{
+  if (added_targets->number == added_targets->space)
+    {
+      added_targets->list = realloc (added_targets->list,
+                   sizeof (HTML_TARGET *) * (added_targets->space += 5));
+    }
+  added_targets->list[added_targets->number] = target;
+  added_targets->number++;
+}
+
+static HTML_TARGET *
+get_target (CONVERTER *self, const ELEMENT *element)
+{
+  HTML_TARGET *result
+   = find_element_target (&self->html_targets, element);
+  if (!result && element->cmd
+      && builtin_command_flags(element) & CF_sectioning_heading
+      && !(builtin_command_flags(element) & CF_root))
+    {
+      new_sectioning_command_target (self, element);
+
+      result = find_element_target (&self->html_targets, element);
+
+      register_added_target (&self->added_targets, result);
+      self->modified_state |= HMSF_added_target;
+    }
+  return result;
+}
+
+char *html_command_id (CONVERTER *self, ELEMENT *command)
+{
+  HTML_TARGET *target = get_target (self, command);
+  if (target)
+    return target->target;
+  else
+    return 0;
+}
+
+ELEMENT *
+new_element_added (TREE_ADDED_ELEMENTS *added_elements, enum element_type type)
+{
+  ELEMENT *new = new_element (type);
+  add_to_element_list (&added_elements->added, new);
+  return new;
+}
+
+TREE_ADDED_ELEMENTS *
+html_command_tree (CONVERTER *self, ELEMENT *command, int no_number)
+{
+  TREE_ADDED_ELEMENTS *tree;
+  HTML_TARGET *target;
+
+  ELEMENT *manual_content = lookup_extra_element (command,
+                                                  "manual_content");
+  if (manual_content)
+    {
+      ELEMENT *root_code;
+      ELEMENT *open_p;
+      ELEMENT *close_p;
+
+      ELEMENT *node_content = lookup_extra_element (command,
+                                                    "node_content");
+
+      tree = new_tree_added_elements ();
+
+      root_code = new_element_added (tree, ET__code);
+      open_p = new_element_added (tree, ET_NONE);
+      close_p = new_element_added (tree, ET_NONE);
+
+      text_append_n (&open_p->text, "(", 1);
+      text_append_n (&close_p->text, ")", 1);
+
+      add_to_element_contents (root_code, open_p);
+      add_to_contents_as_array (root_code, manual_content);
+      add_to_element_contents (root_code, close_p);
+      if (node_content)
+        add_to_contents_as_array (root_code, node_content);
+
+      tree->tree = root_code;
+      add_to_element_list (&self->tree_to_build, root_code);
+      return tree;
+    }
+
+  target = get_target (self, command);
+  if (target)
+    {
+      if (!target->tree.status)
+        {
+          tree = &target->tree;
+          tree->status = tree_added_status_normal;
+          if (command->type == ET_special_unit_element)
+            {
+              const char *special_unit_variety
+                = command->associated_unit->special_unit_variety;
+              ELEMENT *heading_tree = special_unit_info_tree (self,
+                                   SUIT_type_heading, special_unit_variety);
+              tree->tree = heading_tree;
+            }
+          else if (command->cmd == CM_node || command->cmd == CM_anchor)
+            {
+              ELEMENT *root_code = new_element_added (tree, ET__code);
+              add_to_contents_as_array (root_code, command->args.list[0]);
+              tree->tree = root_code;
+              add_to_element_list (&self->tree_to_build, tree->tree);
+            }
+          else if (command->cmd == CM_float)
+            {
+              tree->tree = float_type_number (self, command);
+              tree->status = tree_added_status_new_tree;
+              add_to_element_list (&self->tree_to_build, tree->tree);
+            }
+          else if (command->args.number <= 0
+                   || command->args.list[0]->contents.number <= 0)
+            { /* no argument, nothing to do */
+              /* TODO check if possible */
+              tree->status = tree_added_status_no_tree;
+            }
+          else
+            {
+              char *section_number
+                = lookup_extra_string (command, "section_number");
+              if (section_number && !self->conf->NUMBER_SECTIONS == 0)
+                {
+                  NAMED_STRING_ELEMENT_LIST *replaced_substrings
+                    = new_named_string_element_list ();
+                  ELEMENT *e_number = new_element (ET_NONE);
+                  ELEMENT *section_title_copy
+                     = copy_tree (command->args.list[0]);
+
+                  add_element_to_named_string_element_list (
+                              replaced_substrings, "section_title",
+                              section_title_copy);
+                  text_append (&e_number->text, section_number);
+                  add_element_to_named_string_element_list (
+                              replaced_substrings, "number", e_number);
+
+                  if (command->cmd == CM_appendix)
+                    {
+                      int status;
+                      int section_level = lookup_extra_integer (command,
+                                               "section_level", &status);
+                      if (section_level == 1)
+                        {
+                          tree->tree
+                            = gdt_tree ("Appendix {number} {section_title}",
+                                        self->document, self->conf,
+                                        replaced_substrings, 0, 0);
+                        }
+                    }
+                  if (!tree->tree)
+                    /* TRANSLATORS: numbered section title */
+                    tree->tree = gdt_tree ("{number} {section_title}",
+                                            self->document, self->conf,
+                                            replaced_substrings, 0, 0);
+
+                  destroy_named_string_element_list (replaced_substrings);
+                  tree->status = tree_added_status_new_tree;
+                  add_to_element_list (&self->tree_to_build, tree->tree);
+                }
+              else
+                {
+                  tree->status = tree_added_status_reused_tree;
+                  tree->tree = command->args.list[0];
+                }
+
+              target->tree_nonumber.tree = command->args.list[0];
+              target->tree_nonumber.status = tree_added_status_reused_tree;
+            }
+        }
+
+      if (no_number && target->tree_nonumber.tree)
+        return &target->tree_nonumber;
+      else
+        return &target->tree;
+    }
+
+  return 0;
 }
 
-char *html_command_id (CONVERTER *self, ELEMENT *command)
+/* keep in sync with enum html_command_text_type */
+static char *html_command_text_type_name[] = {
+  "text", "text_nonumber", "string", "string_nonumber"
+};
+
+char *
+html_command_text (CONVERTER *self, ELEMENT *command,
+                   const enum html_command_text_type type)
 {
-  HTML_TARGET *target = get_target (self, command);
+  char *result;
+  HTML_TARGET *target;
+  ELEMENT *tree_root;
+  ELEMENT *manual_content = lookup_extra_element (command,
+                                                  "manual_content");
+  if (manual_content)
+    {
+      TREE_ADDED_ELEMENTS *command_tree = html_command_tree (self, command, 0);
+      TREE_ADDED_ELEMENTS *string_tree = 0;
+      if (type == HCTT_string)
+        {
+          ELEMENT *tree_root_string;
+
+          string_tree = new_tree_added_elements ();
+
+          tree_root_string = new_element_added (string_tree, ET__string);
+
+          add_to_element_contents (tree_root_string, command_tree->tree);
+          tree_root = tree_root_string;
+          add_to_element_list (&self->tree_to_build, tree_root);
+        }
+      else
+        tree_root = command_tree->tree;
+
+      result = convert_tree_new_formatting_context (self, tree_root,
+                                     element_command_name(command), 0,
+                                     "command_text-manual_content", 0);
+
+      if (type == HCTT_string)
+        destroy_tree_added_elements (self, string_tree);
+      return result;
+    }
+
+  target = get_target (self, command);
   if (target)
-    return target->target;
-  else
-    return 0;
+    {
+      if (target->command_text[type])
+        return target->command_text[type];
+      else
+        {
+          TREE_ADDED_ELEMENTS *string_tree = 0;
+          char *explanation = 0;
+          char *context_name;
+          ELEMENT *selected_tree;
+          TREE_ADDED_ELEMENTS *command_tree
+            = html_command_tree (self, command, 0);
+
+          if (!command_tree->tree)
+            return 0;
+
+          if (command->cmd)
+            {
+              char *command_name = element_command_name(command);
+              context_name = command_name;
+              xasprintf (&explanation, "command_text:%s @%s",
+                         html_command_text_type_name[type],
+                         command_name);
+            }
+          else
+            {
+              context_name = element_type_names[command->type];
+              if (command->type == ET_special_unit_element)
+                {
+                  char *special_unit_variety
+                    = command->associated_unit->special_unit_variety;
+                  xasprintf (&explanation, "command_text %s",
+                             special_unit_variety);
+                }
+            }
+          html_new_document_context (self, context_name, explanation, 0);
+
+          if ((type == HCTT_text_nonumber || type == HCTT_string_nonumber)
+              && target->tree_nonumber.tree)
+            selected_tree = target->tree_nonumber.tree;
+          else
+            selected_tree = command_tree->tree;
+
+          if (type == HCTT_string)
+            {
+              ELEMENT *tree_root_string;
+
+              string_tree = new_tree_added_elements ();
+
+              tree_root_string = new_element_added (string_tree, ET__string);
+
+              add_to_element_contents (tree_root_string, selected_tree);
+              tree_root = tree_root_string;
+              add_to_element_list (&self->tree_to_build, tree_root);
+            }
+          else
+            tree_root = selected_tree;
+
+          self->ignore_notice++;
+          add_to_element_list (&self->referred_command_stack, command);
+          self->modified_state |= HMSF_referred_command_stack
+                                   | HMSF_converter_state;
+          target->command_text[type]
+            = html_convert_tree (self, tree_root, explanation);
+          free (explanation);
+          remove_from_element_list (&self->referred_command_stack, -1);
+          self->ignore_notice--;
+          self->modified_state |= HMSF_referred_command_stack
+                                   | HMSF_converter_state;
+
+          html_pop_document_context (self);
+
+          if (type == HCTT_string)
+            {
+              destroy_tree_added_elements (self, string_tree);
+            }
+          return target->command_text[type];
+        }
+    }
+
+ /*
+    Can happen
+    * if USE_NODES is 0 and there are no sectioning commands.
+    * if a special element target was set to undef in user defined code.
+    * for @*ref with missing targets (maybe @novalidate needed in that case).
+    * for @node header if the node consist only in spaces (example in 
sectioning
+      in_menu_only_special_ascii_spaces_node).
+    * for multiple targets with the same name, eg both @node and @anchor
+    * with @inforef with node argument only, without manual argument.
+  */
+
+  return 0;
 }
 
 static int
@@ -3092,6 +3595,7 @@ convert_special_unit_type (CONVERTER *self,
                         const OUTPUT_UNIT *output_unit, const char *content,
                         TEXT *result)
 {
+  const char *heading;
   size_t number;
   TEXT special_unit_body;
   ELEMENT *unit_command;
@@ -3103,7 +3607,10 @@ convert_special_unit_type (CONVERTER *self,
 
   char *special_unit_variety;
   STRING_LIST *closed_strings;
-  size_t file_index;
+  size_t count_in_file = 0;
+  int level;
+  char *formatted_footer;
+  char *formatted_heading;
 
   if (in_string (self))
     return;
@@ -3121,7 +3628,10 @@ convert_special_unit_type (CONVERTER *self,
         {
           text_append (result, closed_strings->list[i]);
         }
+      free (closed_strings->list);
     }
+  free (closed_strings);
+
   text_init (&special_unit_body);
   text_append (&special_unit_body, "");
 
@@ -3131,7 +3641,10 @@ convert_special_unit_type (CONVERTER *self,
   /* This may happen with footnotes in regions that are not expanded,
      like @copying or @titlepage */
   if (special_unit_body.end == 0)
-    return;
+    {
+      free (special_unit_body.text);
+      return;
+    }
 
   classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
   memset (classes, 0, sizeof (STRING_LIST));
@@ -3145,7 +3658,7 @@ convert_special_unit_type (CONVERTER *self,
   add_string (class, classes);
   free (class);
   attribute_class = html_attribute_class (self, "div", classes);
-  destroy_strings_list (classes);
+  clear_strings_list (classes);
 
   text_append (result, attribute_class);
   free (attribute_class);
@@ -3154,10 +3667,16 @@ convert_special_unit_type (CONVERTER *self,
     text_printf (result, " id=\"%s\"", id);
   text_append (result, ">\n");
 
-  file_index = self->special_unit_file_indices[output_unit->index];
+  if (output_unit->unit_filename)
+    {
+      size_t file_index = self->special_unit_file_indices[output_unit->index];
+      count_in_file
+        = count_elements_in_filename (self, CEFT_current, file_index +1);
+    }
+
   if (self->conf->HEADERS > 0
       /* first in page */
- || (count_elements_in_filename (self, CEFT_current, file_index +1) == 1))
+      || count_in_file == 1)
     {
       char *navigation_header =
         call_formatting_function_format_navigation_header (self,
@@ -3165,13 +3684,40 @@ convert_special_unit_type (CONVERTER *self,
       text_append (result, navigation_header);
       free (navigation_header);
     }
-  /* TODO */
+
+  heading = html_command_text (self, unit_command, 0);
+  level = self->conf->CHAPTER_HEADER_LEVEL;
+  if (!strcmp (special_unit_variety, "footnotes"))
+    level = self->conf->FOOTNOTE_SEPARATE_HEADER_LEVEL;
+
+  xasprintf (&class, "%s-heading", class_base);
+
+  add_string (class, classes);
+  free (class);
+
+  formatted_heading
+    = call_formatting_function_format_heading_text (self, 0, classes, heading,
+                                                    level, 0, 0, 0);
+  destroy_strings_list (classes);
+  text_append (result, formatted_heading);
+  text_append_n (result, "\n", 1);
+
+  free (formatted_heading);
+
+  text_append (result, special_unit_body.text);
+  free (special_unit_body.text);
+  text_append (result, "</div>");
+
+  formatted_footer
+    = call_formatting_function_format_element_footer (self, unit_type,
+                                         output_unit, content, unit_command);
+  text_append (result, formatted_footer);
+
+  free (formatted_footer);
 }
 
 static OUTPUT_UNIT_INTERNAL_CONVERSION 
output_units_internal_conversion_table[] = {
-   /*
   {OU_special_unit, &convert_special_unit_type},
-    */
   {0, 0},
 };
 
@@ -3256,113 +3802,6 @@ special_unit_body_formatting_external (CONVERTER *self,
                                        output_unit, result);
 }
 
-static void
-push_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack,
-                              char *context_name)
-{
-  if (stack->top >= stack->space)
-    {
-      stack->stack
-        = realloc (stack->stack,
-                   (stack->space += 5) * sizeof (HTML_FORMATTING_CONTEXT));
-    }
-
-  memset (&stack->stack[stack->top], 0, sizeof (HTML_FORMATTING_CONTEXT));
-
-  stack->stack[stack->top].context_name = strdup (context_name);
-
-  stack->top++;
-}
-
-static void
-pop_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack)
-{
-  if (stack->top == 0)
-    fatal ("HTML formatting context stack empty");
-
-  free (stack->stack[stack->top - 1].context_name);
-  stack->top--;
-}
-
-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
-        = realloc (stack->stack,
-                   (stack->space += 5) * sizeof (HTML_DOCUMENT_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_integer_stack_integer (&doc_context->monospace, 0);
-  push_integer_stack_integer (&doc_context->preformatted_context, 0);
-  push_command_or_type (&doc_context->composition_context, 0, 0);
-  if (block_command)
-    push_command (&doc_context->block_commands, block_command);
-
-  if (document_global_context)
-    {
-      self->document_global_context++;
-      self->modified_state |= HMSF_converter_state;
-    }
-
-  push_html_formatting_context (&doc_context->formatting_context,
-                                "_format");
-
-  stack->top++;
-}
-
-void
-html_pop_document_context (CONVERTER *self)
-{
-  HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
-  HTML_DOCUMENT_CONTEXT *document_ctx;
-
-  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);
-  free (document_ctx->monospace.stack);
-  free (document_ctx->preformatted_context.stack);
-  free (document_ctx->composition_context.stack);
-  free (document_ctx->preformatted_classes.stack);
-  if (document_ctx->block_commands.top > 0)
-    pop_command (&document_ctx->block_commands);
-  free (document_ctx->block_commands.stack);
-  pop_html_formatting_context (&document_ctx->formatting_context);
-  free (document_ctx->formatting_context.stack);
-
-  if (document_ctx->document_global_context)
-    {
-      self->document_global_context--;
-      self->modified_state |= HMSF_converter_state;
-    }
-
-  stack->top--;
-}
-
 void
 reset_translated_special_unit_info_tree (CONVERTER *self)
 {
@@ -3679,7 +4118,7 @@ html_converter_prepare_output (CONVERTER* self)
 }
 
 void
-reset_html_targets (HTML_TARGET_LIST *targets)
+reset_html_targets (CONVERTER *self, HTML_TARGET_LIST *targets)
 {
   size_t i;
 
@@ -3687,6 +4126,7 @@ reset_html_targets (HTML_TARGET_LIST *targets)
     {
       for (i = 0; i < targets->number; i++)
         {
+          int j;
           HTML_TARGET *html_target = &targets->list[i];
           /* setup before conversion */
           free (html_target->target);
@@ -3696,7 +4136,11 @@ reset_html_targets (HTML_TARGET_LIST *targets)
           free (html_target->contents_target);
           free (html_target->shortcontents_target);
 
-          /* TODO free fields changed during conversion */
+          for (j = 0; j < HCTT_string_nonumber+1; j++)
+            free (html_target->command_text[j]);
+
+          free_tree_added_elements (self, &html_target->tree);
+          free_tree_added_elements (self, &html_target->tree_nonumber);
         }
       memset (targets->list, 0,
               sizeof (HTML_TARGET) * targets->number);
@@ -3729,13 +4173,15 @@ html_finalize_output_state (CONVERTER *self)
   int i;
   reset_translated_special_unit_info_tree (self);
   /* targets */
-  reset_html_targets (&self->html_targets);
+  reset_html_targets (self, &self->html_targets);
   clear_strings_list (&self->seen_ids);
   for (i = 0; i < ST_footnote_location+1; i++)
     {
-      reset_html_targets (&self->html_special_targets[i]);
+      reset_html_targets (self, &self->html_special_targets[i]);
     }
 
+  free (self->tree_to_build.list);
+
   free (self->special_units_direction_name);
   self->special_units_direction_name = 0;
   free (self->output_unit_file_indices);
@@ -3792,6 +4238,9 @@ html_finalize_output_state (CONVERTER *self)
   /* could change to 0 in releases? */
   if (1)
     {
+      if (self->tree_to_build.number > 0)
+        fprintf (stderr, "BUG: tree_to_build: %zu\n",
+                         self->tree_to_build.number);
       if (self->html_document_context.top > 0)
         fprintf (stderr, "BUG: document context top > 0: %zu\n",
                          self->html_document_context.top);
@@ -3811,8 +4260,11 @@ html_check_transfer_state_finalization (CONVERTER *self)
   if (1)
     {
       /* check that all the state change have been transmitted */
-      if (self->tree_to_build)
-        fprintf (stderr, "BUG: tree_to_build set\n");
+      /*
+      if (self->tree_to_build.number > 0)
+        fprintf (stderr, "BUG: tree_to_build: %zu\n",
+                         self->tree_to_build.number);
+       */
       if (self->document_context_change)
         fprintf (stderr, "BUG: document_context_change: %d\n",
                          self->document_context_change);
@@ -3909,76 +4361,13 @@ html_free_converter (CONVERTER *self)
   free (self->reset_target_commands.list);
   free (self->file_changed_counter.list);
 
+  free (self->referred_command_stack.list);
+
   free (self->html_document_context.stack);
 
   free_strings_list (&self->special_unit_varieties);
 }
 
-char *
-html_convert_tree (CONVERTER *self, const ELEMENT *tree, char *explanation)
-{
-  TEXT result;
-  text_init (&result);
-
-  convert_to_html_internal (self, tree, &result, explanation);
-
-  return result.text;
-}
-
-/* This function should be used in formatting functions when some
-   Texinfo tree need to be converted. */
-char *
-convert_tree_new_formatting_context (CONVERTER *self, const ELEMENT *tree,
-                              char *context_string, char *multiple_pass,
-                              char *document_global_context,
-                              enum command_id block_cmd)
-{
-  char *result;
-  char *multiple_pass_str = "";
-  char *explanation;
-  TEXT context_string_str;
-  text_init (&context_string_str);
-  text_append (&context_string_str, "");
-
-  if (context_string)
-    {
-      html_new_document_context (self, context_string,
-                                 document_global_context, block_cmd);
-      text_printf (&context_string_str, "C(%s)", context_string);
-    }
-
-  if (multiple_pass)
-    {
-      self->ignore_notice++;
-      push_string_stack_string (&self->multiple_pass, multiple_pass);
-      self->modified_state |= HMSF_multiple_pass | HMSF_converter_state;
-      multiple_pass_str = "|M";
-    }
-
-  if (self->conf->DEBUG > 0)
-    fprintf (stderr, "new_fmt_ctx %s%s\n", context_string_str.text,
-                                           multiple_pass_str);
-
-  xasprintf (&explanation, "new_fmt_ctx %s", context_string_str.text);
-  result = html_convert_tree (self, tree, explanation);
-
-  free (explanation);
-  free (context_string_str.text);
-
-  if (context_string)
-    {
-      html_pop_document_context (self);
-    }
-
-  if (multiple_pass)
-    {
-      self->ignore_notice--;
-      pop_string_stack (&self->multiple_pass);
-      self->modified_state |= HMSF_multiple_pass | HMSF_converter_state;
-    }
-
-  return result;
-}
 
 char *
 html_convert_css_string (CONVERTER *self, const ELEMENT *element, char 
*explanation)
@@ -4061,11 +4450,12 @@ reset_unset_no_arg_commands_formatting_context 
(CONVERTER *self,
       char *translation_result = 0;
       char *explanation;
       char *context;
+      ELEMENT *tree_built = 0;
       ELEMENT *translated_tree = no_arg_command_context->tree;
       if (!translated_tree->hv)
-        {/* FIXME Would need to be done differently if it is possible
-                  to recursively call html_translate_names. */
-          self->tree_to_build = translated_tree;
+        {
+          add_element_if_not_in_list (&self->tree_to_build, translated_tree);
+          tree_built = translated_tree;
         }
       xasprintf (&explanation, "Translated NO ARG @%s ctx %s",
                  builtin_command_data[cmd].cmdname,
@@ -4127,7 +4517,8 @@ reset_unset_no_arg_commands_formatting_context (CONVERTER 
*self,
       if (no_arg_command_context->text)
         free (no_arg_command_context->text);
       no_arg_command_context->text = translation_result;
-      self->tree_to_build = 0;
+      if (tree_built)
+        remove_element_from_list (&self->tree_to_build, tree_built);
     }
 }
 
@@ -4195,11 +4586,11 @@ html_translate_names (CONVERTER *self)
        /* the tree is a reference to special_unit_info_tree, so it should
           not be freed, but need to be reset to trigger the creation of the
           special_unit_info_tree tree when needed */
-                       target->tree = 0;
-       /* TODO check if there is a need to free when the code setting
-               those fields is done */
-                       target->string = 0;
-                       target->text = 0;
+                       clear_tree_added_elements (self, &target->tree);
+                       free (target->command_text[HCTT_string]);
+                       target->command_text[HCTT_string] = 0;
+                       free (target->command_text[HCTT_text]);
+                       target->command_text[HCTT_text] = 0;
                        /* gather elements to pass information to perl */
                        add_to_element_list (&self->reset_target_commands,
                                             command);
diff --git a/tp/Texinfo/XS/convert/converter.c 
b/tp/Texinfo/XS/convert/converter.c
index 2dbe1836e8..1c9c7fb4e1 100644
--- a/tp/Texinfo/XS/convert/converter.c
+++ b/tp/Texinfo/XS/convert/converter.c
@@ -29,6 +29,8 @@
 #include "builtin_commands.h"
 #include "node_name_normalization.h"
 #include "convert_utils.h"
+#include "translations.h"
+#include "manipulate_tree.h"
 #include "converter.h"
 
 static CONVERTER **converter_list;
@@ -645,3 +647,47 @@ xml_protect_text (const char *text, TEXT *result)
         }
     }
 }
+
+ELEMENT *
+float_type_number (CONVERTER *self, ELEMENT *float_e)
+{
+  int have_float_number;
+  ELEMENT *tree = 0;
+  ELEMENT *type_element = 0;
+  NAMED_STRING_ELEMENT_LIST *replaced_substrings
+     = new_named_string_element_list ();
+  char *float_type = lookup_extra_string (float_e, "float_type");
+  int float_number
+     = lookup_extra_integer (float_e, "float_number", &have_float_number);
+
+  if (float_type && strlen (float_type))
+    type_element = float_e->args.list[0];
+
+  if (have_float_number)
+    {
+      ELEMENT *e_number = new_element (ET_NONE);
+      text_printf (&e_number->text, "%d", float_number);
+      add_element_to_named_string_element_list (replaced_substrings,
+                                     "float_number", e_number);
+    }
+
+  if (type_element)
+    {
+      ELEMENT *type_element_copy = copy_tree (type_element);
+      add_element_to_named_string_element_list (replaced_substrings,
+                                     "float_type", type_element_copy);
+      if (have_float_number)
+        tree = gdt_tree ("{float_type} {float_number}", self->document,
+                         self->conf, replaced_substrings, 0, 0);
+      else
+        tree = gdt_tree ("{float_type}", self->document, self->conf,
+                         replaced_substrings, 0, 0);
+    }
+  else if (have_float_number)
+    tree = gdt_tree ("{float_number}", self->document, self->conf,
+                     replaced_substrings, 0, 0);
+
+  destroy_named_string_element_list (replaced_substrings);
+
+  return tree;
+}
diff --git a/tp/Texinfo/XS/convert/converter.h 
b/tp/Texinfo/XS/convert/converter.h
index 8d0e405ab7..eef23706ad 100644
--- a/tp/Texinfo/XS/convert/converter.h
+++ b/tp/Texinfo/XS/convert/converter.h
@@ -89,6 +89,7 @@ void free_comma_index_subentries_tree (ELEMENT_LIST *element);
 
 char *top_node_filename (CONVERTER *self, char *document_name);
 
+ELEMENT *float_type_number (CONVERTER *self, ELEMENT *float_e);
 
 void initialize_output_units_files (CONVERTER *self);
 size_t set_output_unit_file (CONVERTER *self, OUTPUT_UNIT *output_unit,
diff --git a/tp/Texinfo/XS/convert/get_html_perl_info.c 
b/tp/Texinfo/XS/convert/get_html_perl_info.c
index 61e41e4411..398ef5ced7 100644
--- a/tp/Texinfo/XS/convert/get_html_perl_info.c
+++ b/tp/Texinfo/XS/convert/get_html_perl_info.c
@@ -366,7 +366,7 @@ html_converter_initialize_sv (SV *converter_sv,
     {
       int i;
       enum special_unit_info_type j;
-      SV **special_unit_info_sv;
+      SV **simplified_special_unit_info_sv;
       HV *special_unit_info_hv;
       SV **special_unit_body_sv;
       HV *special_unit_body_hv;
@@ -377,9 +377,9 @@ html_converter_initialize_sv (SV *converter_sv,
         add_svav_to_string_list (*sorted_special_unit_varieties_sv,
                                  special_unit_varieties, svt_char);
 
-      FETCH(special_unit_info);
+      FETCH(simplified_special_unit_info);
 
-      special_unit_info_hv = (HV *) SvRV(*special_unit_info_sv);
+      special_unit_info_hv = (HV *) SvRV(*simplified_special_unit_info_sv);
 
       for (j = 0; j < SUI_type_heading+1; j++)
         {
@@ -425,6 +425,10 @@ html_converter_initialize_sv (SV *converter_sv,
                       else
                         converter->special_unit_info[j][k] = 0;
                     }
+                    /*
+                  else
+                    fprintf (stderr, "Missing %d:%s %d:%s\n", j, sui_type, k, 
variety_name);
+                     */
                 }
             }
         }
diff --git a/tp/Texinfo/XS/main/build_perl_info.c 
b/tp/Texinfo/XS/main/build_perl_info.c
index a220ccb826..02191f0b45 100644
--- a/tp/Texinfo/XS/main/build_perl_info.c
+++ b/tp/Texinfo/XS/main/build_perl_info.c
@@ -97,7 +97,7 @@ init (int texinfo_uninstalled, char *builddir)
 }
 
 
-void element_to_perl_hash (ELEMENT *e);
+void element_to_perl_hash (ELEMENT *e, int avoid_recursion);
 
 /* 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
@@ -108,7 +108,7 @@ void element_to_perl_hash (ELEMENT *e);
    information where build_perl_array is called.
  */
 static SV *
-build_perl_array (ELEMENT_LIST *e)
+build_perl_array (ELEMENT_LIST *e, int avoid_recursion)
 {
   SV *sv;
   AV *av;
@@ -140,7 +140,7 @@ build_perl_array (ELEMENT_LIST *e)
               free (message.text);
               /* Out-of-tree element */
               /* WARNING: This is possibly recursive. */
-              element_to_perl_hash (e->list[i]);
+              element_to_perl_hash (e->list[i], avoid_recursion);
             }
         }
       av_store (av, i, newRV_inc ((SV *) e->list[i]->hv));
@@ -150,7 +150,7 @@ build_perl_array (ELEMENT_LIST *e)
 
 /* contents appears in other parts of the tree */
 void
-build_perl_container (ELEMENT *e)
+build_perl_container (ELEMENT *e, int avoid_recursion)
 {
   SV *sv;
 
@@ -161,13 +161,13 @@ build_perl_container (ELEMENT *e)
   else
     hv_clear (e->hv);
 
-  sv = build_perl_array (&e->contents);
+  sv = build_perl_array (&e->contents, avoid_recursion);
 
   hv_store (e->hv, "contents", strlen ("contents"), sv, 0);
 }
 
 static SV *
-build_perl_directions (ELEMENT_LIST *e)
+build_perl_directions (ELEMENT_LIST *e, int avoid_recursion)
 {
   SV *sv;
   HV *hv;
@@ -201,7 +201,7 @@ build_perl_directions (ELEMENT_LIST *e)
                   free (message.text);
                   /* Out-of-tree element */
                   /* WARNING: This is possibly recursive. */
-                  element_to_perl_hash (e->list[d]);
+                  element_to_perl_hash (e->list[d], avoid_recursion);
                 }
             }
           hv_store (hv, key, strlen (key),
@@ -238,7 +238,8 @@ newSVpv_byte (const char *str, STRLEN len)
 }
 
 static void
-store_additional_info (const ELEMENT *e, ASSOCIATED_INFO* a, char *key)
+store_additional_info (const ELEMENT *e, ASSOCIATED_INFO* a, char *key,
+                       int avoid_recursion)
 {
   dTHX;
 
@@ -302,24 +303,25 @@ store_additional_info (const ELEMENT *e, ASSOCIATED_INFO* 
a, char *key)
                   fprintf (stderr, message.text);
                 }
                    */
-              element_to_perl_hash (f);
+              if (!f->hv || !avoid_recursion)
+                element_to_perl_hash (f, avoid_recursion);
               STORE(newRV_inc ((SV *)f->hv));
               break;
             case extra_container:
-              build_perl_container (f);
+              build_perl_container (f, avoid_recursion);
               STORE(newRV_inc ((SV *)f->hv));
               break;
             case extra_contents:
               {
               ELEMENT_LIST *l = k->list;
               if (l && l->number)
-                STORE(build_perl_array (l));
+                STORE(build_perl_array (l, avoid_recursion));
               break;
               }
             case extra_directions:
               {
               if (f)
-                STORE(build_perl_directions (&f->contents));
+                STORE(build_perl_directions (&f->contents, avoid_recursion));
               break;
               }
             case extra_string:
@@ -422,7 +424,7 @@ store_source_mark_list (ELEMENT *e)
               if (e->hv)
                 fatal ("element_to_perl_hash source mark elt twice");
                */
-              element_to_perl_hash (e);
+              element_to_perl_hash (e, 0);
               STORE("element", newRV_inc ((SV *)e->hv));
             }
           if (s_mark->line)
@@ -485,8 +487,10 @@ static U32 HSH_macro = 0;
 
 /* Set E->hv and 'hv' on E's descendants.  e->parent->hv is assumed
    to already exist. */
+/* If AVOID_RECURSION is set, recurse in children elements only if
+   hv is not set */
 void
-element_to_perl_hash (ELEMENT *e)
+element_to_perl_hash (ELEMENT *e, int avoid_recursion)
 {
   SV *sv;
 
@@ -569,12 +573,14 @@ element_to_perl_hash (ELEMENT *e)
       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]);
+          ELEMENT *child = e->contents.list[i];
+          if (!child->hv || !avoid_recursion)
+            element_to_perl_hash (child, avoid_recursion);
       /* we do not transfer the hv ref to the perl av because we consider
          that contents.list[i]->hv still own a reference, which should only be
          released when the element is destroyed, by calling
          unregister_perl_tree_element */
-          sv = newRV_inc ((SV *) e->contents.list[i]->hv);
+          sv = newRV_inc ((SV *) child->hv);
           av_store (av, i, sv);
         }
     }
@@ -591,8 +597,10 @@ element_to_perl_hash (ELEMENT *e)
       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);
+          ELEMENT *child = e->args.list[i];
+          if (!child->hv || !avoid_recursion)
+            element_to_perl_hash (child, avoid_recursion);
+          sv = newRV_inc ((SV *) child->hv);
           av_store (av, i, sv);
         }
     }
@@ -603,8 +611,8 @@ element_to_perl_hash (ELEMENT *e)
       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_additional_info (e, &e->extra_info, "extra", avoid_recursion);
+  store_additional_info (e, &e->info_info, "info", avoid_recursion);
 
   store_source_mark_list (e);
 
@@ -640,7 +648,7 @@ element_to_perl_hash (ELEMENT *e)
 }
 
 HV *
-build_texinfo_tree (ELEMENT *root)
+build_texinfo_tree (ELEMENT *root, int avoid_recursion)
 {
   if (! root)
       /* use an empty element with contents if there is nothing.
@@ -652,7 +660,8 @@ build_texinfo_tree (ELEMENT *root)
   /*
   fprintf (stderr, "BTT ------------------------------------------------\n");
    */
-  element_to_perl_hash (root);
+  if (!root->hv || !avoid_recursion)
+    element_to_perl_hash (root, avoid_recursion);
   return root->hv;
 }
 
@@ -1184,7 +1193,7 @@ build_document (size_t document_descriptor, int no_store)
 
   document = retrieve_document (document_descriptor);
 
-  hv_tree = build_texinfo_tree (document->tree);
+  hv_tree = build_texinfo_tree (document->tree, 0);
 
   hv_info = build_global_info (document->global_info,
                                document->global_commands);
@@ -1328,7 +1337,7 @@ output_unit_to_perl_hash (OUTPUT_UNIT *output_unit)
               SV *unit_sv;
               unit_sv = newRV_inc ((SV *) output_unit->hv);
               /* a virtual out of tree element, add it to perl */
-              element_to_perl_hash (command);
+              element_to_perl_hash (command, 0);
               hv_store (command->hv, "associated_unit",
                         strlen ("associated_unit"), unit_sv, 0);
             }
diff --git a/tp/Texinfo/XS/main/build_perl_info.h 
b/tp/Texinfo/XS/main/build_perl_info.h
index 81b27b9af7..e08bc83c4e 100644
--- a/tp/Texinfo/XS/main/build_perl_info.h
+++ b/tp/Texinfo/XS/main/build_perl_info.h
@@ -17,12 +17,12 @@ int init (int texinfo_uninstalled, char *srcdir_in);
 /* does not exist as perl macro */
 SV *newSVpv_utf8 (const char *str, STRLEN len);
 
-void element_to_perl_hash (ELEMENT *e);
+void element_to_perl_hash (ELEMENT *e, int avoid_recursion);
 
 SV *build_document (size_t document_descriptor, int no_store);
 SV *get_document (size_t document_descriptor);
 
-HV *build_texinfo_tree (ELEMENT *root);
+HV *build_texinfo_tree (ELEMENT *root, int avoid_recursion);
 AV *get_errors (ERROR_MESSAGE* error_list, size_t error_number);
 AV *build_target_elements_list (LABEL *labels_list,
                                 size_t labels_number);
diff --git a/tp/Texinfo/XS/main/call_perl_function.c 
b/tp/Texinfo/XS/main/call_perl_function.c
index 9638e6046a..fb13e69d27 100644
--- a/tp/Texinfo/XS/main/call_perl_function.c
+++ b/tp/Texinfo/XS/main/call_perl_function.c
@@ -97,11 +97,11 @@ call_latex_convert_to_latex_math (CONVERTER *self, ELEMENT 
*element)
   if (!self->hv)
     return 0;
 
-  /* in case of @displaymath a element containing the contents
+  /* in case of @displaymath an element containing the contents
      of the displaymath element is passed, it is not registered in perl */
   if (!element->hv)
     {
-      element_to_perl_hash (element);
+      element_to_perl_hash (element, 1);
     }
 
   dSP;
diff --git a/tp/Texinfo/XS/main/converter_types.h 
b/tp/Texinfo/XS/main/converter_types.h
index fc3029f6ff..b07e6d1fe3 100644
--- a/tp/Texinfo/XS/main/converter_types.h
+++ b/tp/Texinfo/XS/main/converter_types.h
@@ -154,11 +154,18 @@ enum html_argument_formatting_type {
 };
 
 enum html_special_character {
-  SC_paragraph_symbol,
-  SC_left_quote,
-  SC_right_quote,
-  SC_bullet,
-  SC_non_breaking_space,
+   SC_paragraph_symbol,
+   SC_left_quote,
+   SC_right_quote,
+   SC_bullet,
+   SC_non_breaking_space,
+};
+
+enum html_command_text_type {
+   HCTT_text,
+   HCTT_text_nonumber,
+   HCTT_string,
+   HCTT_string_nonumber, /* not sure that it is set/used */
 };
 
 typedef struct {
@@ -208,12 +215,9 @@ typedef struct HTML_TARGET {
     char *contents_target;
     char *shortcontents_target;
 
-    char *text;
-    char *text_nonumber;
-    ELEMENT *tree;
-    ELEMENT *tree_nonumber;
-    char *string;
-    char *string_nonumber;
+    char *command_text[HCTT_string_nonumber+1];
+    TREE_ADDED_ELEMENTS tree;
+    TREE_ADDED_ELEMENTS tree_nonumber;
     char *filename;
     /*
     ELEMENT *node_command;
@@ -556,7 +560,7 @@ typedef struct CONVERTER {
 
     /* state only in C converter */
     unsigned long modified_state; /* specifies which perl state to rebuild */
-    ELEMENT *tree_to_build; /* C tree that needs to be built to perl
+    ELEMENT_LIST tree_to_build; /* C trees that needs to be built to perl
                                before calling perl functions on it */
     COMMAND_ID_LIST no_arg_formatted_cmd_translated; /* list of commands that
                          were translated and need to be passed back to perl */
@@ -586,6 +590,7 @@ typedef struct CONVERTER {
     STRING_STACK multiple_pass;
     STRING_STACK pending_closes;
     CURRENT_FILE_INFO current_filename;
+    ELEMENT_LIST referred_command_stack;
     /* state common with perl converter, not transmitted to perl */
     int use_unicode_text;
 } CONVERTER;
diff --git a/tp/Texinfo/XS/main/output_unit.c b/tp/Texinfo/XS/main/output_unit.c
index 9be9d75c21..30d048817a 100644
--- a/tp/Texinfo/XS/main/output_unit.c
+++ b/tp/Texinfo/XS/main/output_unit.c
@@ -408,6 +408,13 @@ output_unit_texi (const OUTPUT_UNIT *output_unit)
 
   if (output_unit->unit_type == OU_external_node_unit)
     return convert_contents_to_texinfo (unit_command);
+  else if (output_unit->unit_type == OU_special_unit)
+    {
+      char *result;
+      xasprintf (&result, "_SPECIAL_UNIT: %s",
+                          output_unit->special_unit_variety);
+      return result;
+    }
 
   if (!unit_command)
     {
diff --git a/tp/Texinfo/XS/main/translations.c 
b/tp/Texinfo/XS/main/translations.c
index 3d68ec9864..0bd9e7c3d9 100644
--- a/tp/Texinfo/XS/main/translations.c
+++ b/tp/Texinfo/XS/main/translations.c
@@ -339,10 +339,10 @@ translate_string (OPTIONS *options, const char * string,
 }
 
 char *
-replace_substrings (char *string,
-                    NAMED_STRING_ELEMENT_LIST *replaced_substrings)
+replace_substrings (const char *string,
+                    const NAMED_STRING_ELEMENT_LIST *replaced_substrings)
 {
-  char *p = string;
+  const char *p = string;
   TEXT substituted;
 
   if (!replaced_substrings)
@@ -529,7 +529,6 @@ replace_convert_substrings (char *translated_string,
       free (texinfo_line);
     }
 
-
 /*
   {
     char *result_texi = convert_to_texinfo (document->tree);
@@ -648,7 +647,7 @@ reallocate_named_string_element_list 
(NAMED_STRING_ELEMENT_LIST *nsel)
    string in general */
 void
 add_string_to_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel,
-                                         char *name, char *string)
+                                         const char *name, char *string)
 {
   NAMED_STRING_ELEMENT *new_string;
 
@@ -664,7 +663,8 @@ add_string_to_named_string_element_list 
(NAMED_STRING_ELEMENT_LIST *nsel,
    string in general */
 void
 add_element_to_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel,
-                                          char *name, ELEMENT *element)
+                                          const char *name,
+                                          ELEMENT *element)
 {
   NAMED_STRING_ELEMENT *new_element;
 
diff --git a/tp/Texinfo/XS/main/translations.h 
b/tp/Texinfo/XS/main/translations.h
index 9dc0d150e0..b1b50e7a3a 100644
--- a/tp/Texinfo/XS/main/translations.h
+++ b/tp/Texinfo/XS/main/translations.h
@@ -10,9 +10,9 @@
 
 /* element or string may not always be present */
 typedef struct NAMED_STRING_ELEMENT {
-    char *name;
-    ELEMENT *element;
-    char *string;
+    const char *name;
+    ELEMENT *element; /* actually const until added to tree */
+    char *string; /* const in gdt_string, but used temporarily in gdt_tree */
 } NAMED_STRING_ELEMENT;
 
 typedef struct NAMED_STRING_ELEMENT_LIST {
@@ -27,8 +27,8 @@ char *translate_string (OPTIONS *options, const char * string,
                   const char *translation_context, const char *in_lang);
 int replace_convert_substrings (char *translated_string,
                            NAMED_STRING_ELEMENT_LIST *replaced_substrings);
-char *replace_substrings (char *string,
-                    NAMED_STRING_ELEMENT_LIST *replaced_substrings);
+char *replace_substrings (const char *string,
+                    const NAMED_STRING_ELEMENT_LIST *replaced_substrings);
 
 int gdt (const char * string, OPTIONS *options,
          NAMED_STRING_ELEMENT_LIST *replaced_substrings,
@@ -51,9 +51,10 @@ ELEMENT *pgdt_tree (const char *translation_context, const 
char *string,
 
 NAMED_STRING_ELEMENT_LIST * new_named_string_element_list (void);
 void add_string_to_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel,
-                                              char *name, char *string);
+                                              const char *name, char *string);
 void add_element_to_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel,
-                                               char *name, ELEMENT *element);
+                                               const char *name,
+                                               ELEMENT *element);
 void destroy_named_string_element_list (NAMED_STRING_ELEMENT_LIST *nsel);
 
 #endif
diff --git a/tp/Texinfo/XS/main/tree.c b/tp/Texinfo/XS/main/tree.c
index 799be9bd68..50d5399bbc 100644
--- a/tp/Texinfo/XS/main/tree.c
+++ b/tp/Texinfo/XS/main/tree.c
@@ -398,12 +398,13 @@ remove_from_element_list (ELEMENT_LIST *list, int where)
   if (where < 0)
     where = list->number + where;
 
-  if (where < 0 || where > list->number)
+  if (where < 0 || where > list->number -1)
     fatal ("element list index out of bounds");
 
   removed = list->list[where];
-  memmove (&list->list[where], &list->list[where + 1],
-           (list->number - (where+1)) * sizeof (ELEMENT *));
+  if (where < list->number - 1)
+    memmove (&list->list[where], &list->list[where + 1],
+             (list->number - (where+1)) * sizeof (ELEMENT *));
   list->number--;
   return removed;
 }
@@ -441,6 +442,20 @@ remove_element_from_list (ELEMENT_LIST *list, ELEMENT *e)
   return 0;
 }
 
+void
+add_element_if_not_in_list (ELEMENT_LIST *list, ELEMENT *e)
+{
+  int i;
+  for (i = 0; i < list->number; i++)
+    {
+      if (list->list[i] == e)
+        {
+          return;
+        }
+    }
+  add_to_element_list (list, e);
+}
+
 /* Remove elements from START inclusive to END exclusive.  Do not
    free any of them. */
 void
diff --git a/tp/Texinfo/XS/main/tree.h b/tp/Texinfo/XS/main/tree.h
index 8db37d8308..dc44adc631 100644
--- a/tp/Texinfo/XS/main/tree.h
+++ b/tp/Texinfo/XS/main/tree.h
@@ -17,6 +17,7 @@ void insert_into_element_list (ELEMENT_LIST *list, ELEMENT 
*e, int where);
 void insert_into_contents (ELEMENT *parent, ELEMENT *e, int where);
 void insert_into_args (ELEMENT *parent, ELEMENT *e, int where);
 ELEMENT *remove_element_from_list (ELEMENT_LIST *list, ELEMENT *e);
+void add_element_if_not_in_list (ELEMENT_LIST *list, ELEMENT *e);
 void insert_list_slice_into_list (ELEMENT_LIST *to, int where,
                                   const ELEMENT_LIST *from, int start, int 
end);
 void insert_slice_into_contents (ELEMENT *to, int idx, const ELEMENT *from,
@@ -36,7 +37,7 @@ ELEMENT *pop_element_from_args (ELEMENT *parent);
 ELEMENT *pop_element_from_contents (ELEMENT *parent);
 ELEMENT *contents_child_by_index (ELEMENT *e, int index);
 ELEMENT *args_child_by_index (ELEMENT *e, int index);
-void destroy_list (ELEMENT_LIST * list);
+void destroy_list (ELEMENT_LIST *list);
 void destroy_element (ELEMENT *e);
 void destroy_element_and_children (ELEMENT *e);
 int replace_element_in_contents (ELEMENT *parent, ELEMENT *removed,
diff --git a/tp/Texinfo/XS/main/tree_types.h b/tp/Texinfo/XS/main/tree_types.h
index 973f3b2e30..ccd8e517b2 100644
--- a/tp/Texinfo/XS/main/tree_types.h
+++ b/tp/Texinfo/XS/main/tree_types.h
@@ -294,4 +294,20 @@ typedef struct STRING_LIST {
     size_t space;
 } STRING_LIST;
 
+enum tree_added_elements_status {
+  tree_added_status_none,
+  tree_added_status_normal,
+  tree_added_status_new_tree,
+  tree_added_status_reused_tree,
+  tree_added_status_no_tree,
+};
+
+/* not used in parser */
+typedef struct TREE_ADDED_ELEMENTS {
+    ELEMENT *tree;
+    ELEMENT_LIST added; /* list of added elements in tree that are not in the
+                           document Texinfo tree */
+    enum tree_added_elements_status status;
+} TREE_ADDED_ELEMENTS;
+
 #endif
diff --git a/tp/Texinfo/XS/main/utils.h b/tp/Texinfo/XS/main/utils.h
index 2b3815138a..9fd8f61f7c 100644
--- a/tp/Texinfo/XS/main/utils.h
+++ b/tp/Texinfo/XS/main/utils.h
@@ -148,6 +148,7 @@ enum command_location {
 #define HMSF_translations            0x4000
 #define HMSF_file_counter            0x8000
 #define HMSF_added_target            0x00010000
+#define HMSF_referred_command_stack  0x00020000
 
 typedef struct TARGET_FILENAME {
     char *target;
@@ -210,7 +211,7 @@ char *collapse_spaces (char *text);
 char *parse_line_directive (char *line, int *retval, int *out_line_no);
 int is_content_empty (ELEMENT *tree, int do_not_ignore_index_entries);
 
-void clear_strings_list (STRING_LIST *include_dirs_list);
+void clear_strings_list (STRING_LIST *strings);
 void free_strings_list (STRING_LIST *strings);
 void destroy_strings_list (STRING_LIST *strings);
 void add_string (const char *string, STRING_LIST *strings_list);
diff --git a/tp/Texinfo/XS/structuring_transfo/StructuringTransfo.xs 
b/tp/Texinfo/XS/structuring_transfo/StructuringTransfo.xs
index 99dcffa2e7..4373ce6dba 100644
--- a/tp/Texinfo/XS/structuring_transfo/StructuringTransfo.xs
+++ b/tp/Texinfo/XS/structuring_transfo/StructuringTransfo.xs
@@ -74,7 +74,7 @@ copy_tree (SV *tree_in)
             /* FIXME have a similar system but for trees only? */
             int copy_document_descriptor = register_document (result, 0, 0, 0,
                                                       0, 0, 0, 0, 0, 0);
-            HV *hv = build_texinfo_tree (result);
+            HV *hv = build_texinfo_tree (result, 0);
             hv_store (hv, "tree_document_descriptor",
                       strlen ("tree_document_descriptor"),
                       newSViv ((IV) copy_document_descriptor), 0);



reply via email to

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