texinfo-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Patrice Dumas
Date: Fri, 27 Oct 2023 12:57:49 -0400 (EDT)

branch: master
commit f275f01a7514cda32c804108a7b851997ec478cf
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Fri Oct 27 18:57:48 2023 +0200

    * tp/Texinfo/XS/Makefile.am (libtexinfo_la_SOURCES),
    tp/Texinfo/XS/main/command_stack.c (COMMAND_STACK)
    (reset_command_stack, push_command, pop_command, top_command)
    (enum command_type_variety, enum monospace_context, COMMAND_OR_TYPE)
    (COMMAND_OR_TYPE_STACK, push_command_or_type, pop_command_or_type)
    (top_command_or_type, STRING_STACK, push_string_stack_string)
    (pop_string_stack, top_string_stack, MONOSPACE_CONTEXT_STACK)
    (push_monospace, push_style_no_code, pop_monospace_context)
    (top_monospace_context), parsetexi/context_stack.c: move code related
    to command stack out of to main/command_stack.c and add code there
    related to other stacks.
    
    * tp/Texinfo/Convert/Converter.pm (encode_converter_document),
    tp/Texinfo/XS/main/get_perl_info.c (html_converter_initialize_sv):
    pass code_types and pre_class_types to XS.
    
    * tp/Texinfo/XS/convert/convert_html.c (HTML_COMMAND_STRUCT)
    (additional_format_context_cmd, HTML_align_cmd, html_commands_data)
    (register_format_context_command, register_pre_class_command)
    (html_converter_initialize), tp/Texinfo/XS/main/utils.c
    (small_block_associated_command), tp/Texinfo/XS/main/utils.h
    (SMALL_BLOC_COMMANDS_LIST): setup informations on commands, flags,
    preformatted class and format context strings.
    
    * tp/Texinfo/XS/convert/convert_html.c (type_conversion, type_open),
    tp/Texinfo/XS/main/call_perl_function.c (call_types_conversion)
    (call_types_open): call of perl conversion type and open type
    functions.
    
    * tp/Texinfo/XS/convert/convert_html.c (push_html_formatting_context)
    (top_html_formatting_context, pop_html_formatting_context)
    (html_new_document_context, html_pop_document_context)
    (top_document_context), tp/Texinfo/XS/main/utils.h
    (HTML_FORMATTING_CONTEXT, HTML_FORMATTING_CONTEXT_STACK)
    (HTML_DOCUMENT_CONTEXT, HTML_DOCUMENT_CONTEXT_STACK): functions to
    manipulate document context and formatting context.
    
    * tp/Texinfo/XS/convert/convert_html.c (convert_to_html_internal),
    tp/Texinfo/XS/main/build_perl_info.c (build_html_formatting_context)
    (build_html_document_context, build_html_formatting_state),
    tp/Texinfo/XS/main/call_perl_function.c (call_types_conversion),
    tp/Texinfo/XS/main/element_types.txt, tp/Texinfo/XS/main/utils.h
    (CONVERTER): add setting of document and formatting context, call
    types formatting functions, more types of args formatted.  Set
    modified_state if the state has been changed and needs to be
    reexported before calling a perl function.  Pass document and
    formatting context to perl before calling perl functions.
---
 ChangeLog                                 |  50 +++
 tp/Texinfo/Convert/Converter.pm           |   3 +-
 tp/Texinfo/XS/Makefile.am                 |   2 +
 tp/Texinfo/XS/convert/convert_html.c      | 646 ++++++++++++++++++++++++++++--
 tp/Texinfo/XS/main/build_perl_info.c      | 204 +++++++++-
 tp/Texinfo/XS/main/build_perl_info.h      |   1 +
 tp/Texinfo/XS/main/call_perl_function.c   | 119 ++++++
 tp/Texinfo/XS/main/command_stack.c        | 134 ++++++-
 tp/Texinfo/XS/main/command_stack.h        |  58 ++-
 tp/Texinfo/XS/main/element_types.c        |   3 +
 tp/Texinfo/XS/main/element_types.h        |   3 +
 tp/Texinfo/XS/main/element_types.txt      |   8 +
 tp/Texinfo/XS/main/get_perl_info.c        |  95 ++++-
 tp/Texinfo/XS/main/translations.h         |   8 +-
 tp/Texinfo/XS/main/tree_perl_api.h        |   5 +
 tp/Texinfo/XS/main/utils.c                |   7 +
 tp/Texinfo/XS/main/utils.h                |  60 ++-
 tp/Texinfo/XS/parsetexi/api.c             |   1 +
 tp/Texinfo/XS/parsetexi/close.c           |   1 +
 tp/Texinfo/XS/parsetexi/context_stack.c   |  51 +--
 tp/Texinfo/XS/parsetexi/context_stack.h   |  16 +-
 tp/Texinfo/XS/parsetexi/end_line.c        |   1 +
 tp/Texinfo/XS/parsetexi/handle_commands.c |   1 +
 tp/Texinfo/XS/parsetexi/indices.c         |   1 +
 tp/Texinfo/XS/parsetexi/parser.c          |   1 +
 tp/Texinfo/XS/parsetexi/separator.c       |   1 +
 26 files changed, 1378 insertions(+), 102 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7afe0d0c36..cc3788a3d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2023-10-27  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/XS/Makefile.am (libtexinfo_la_SOURCES),
+       tp/Texinfo/XS/main/command_stack.c (COMMAND_STACK)
+       (reset_command_stack, push_command, pop_command, top_command)
+       (enum command_type_variety, enum monospace_context, COMMAND_OR_TYPE)
+       (COMMAND_OR_TYPE_STACK, push_command_or_type, pop_command_or_type)
+       (top_command_or_type, STRING_STACK, push_string_stack_string)
+       (pop_string_stack, top_string_stack, MONOSPACE_CONTEXT_STACK)
+       (push_monospace, push_style_no_code, pop_monospace_context)
+       (top_monospace_context), parsetexi/context_stack.c: move code related
+       to command stack out of to main/command_stack.c and add code there
+       related to other stacks.
+
+       * tp/Texinfo/Convert/Converter.pm (encode_converter_document),
+       tp/Texinfo/XS/main/get_perl_info.c (html_converter_initialize_sv):
+       pass code_types and pre_class_types to XS.
+
+       * tp/Texinfo/XS/convert/convert_html.c (HTML_COMMAND_STRUCT)
+       (additional_format_context_cmd, HTML_align_cmd, html_commands_data)
+       (register_format_context_command, register_pre_class_command)
+       (html_converter_initialize), tp/Texinfo/XS/main/utils.c
+       (small_block_associated_command), tp/Texinfo/XS/main/utils.h
+       (SMALL_BLOC_COMMANDS_LIST): setup informations on commands, flags,
+       preformatted class and format context strings.
+
+       * tp/Texinfo/XS/convert/convert_html.c (type_conversion, type_open),
+       tp/Texinfo/XS/main/call_perl_function.c (call_types_conversion)
+       (call_types_open): call of perl conversion type and open type
+       functions.
+
+       * tp/Texinfo/XS/convert/convert_html.c (push_html_formatting_context)
+       (top_html_formatting_context, pop_html_formatting_context)
+       (html_new_document_context, html_pop_document_context)
+       (top_document_context), tp/Texinfo/XS/main/utils.h
+       (HTML_FORMATTING_CONTEXT, HTML_FORMATTING_CONTEXT_STACK)
+       (HTML_DOCUMENT_CONTEXT, HTML_DOCUMENT_CONTEXT_STACK): functions to
+       manipulate document context and formatting context.
+
+       * tp/Texinfo/XS/convert/convert_html.c (convert_to_html_internal),
+       tp/Texinfo/XS/main/build_perl_info.c (build_html_formatting_context)
+       (build_html_document_context, build_html_formatting_state),
+       tp/Texinfo/XS/main/call_perl_function.c (call_types_conversion),
+       tp/Texinfo/XS/main/element_types.txt, tp/Texinfo/XS/main/utils.h
+       (CONVERTER): add setting of document and formatting context, call
+       types formatting functions, more types of args formatted.  Set
+       modified_state if the state has been changed and needs to be
+       reexported before calling a perl function.  Pass document and
+       formatting context to perl before calling perl functions.
+
 2023-10-27  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/Convert/HTML.pm (import): load conversion overrides only
diff --git a/tp/Texinfo/Convert/Converter.pm b/tp/Texinfo/Convert/Converter.pm
index c518b37ffb..7991632f4f 100644
--- a/tp/Texinfo/Convert/Converter.pm
+++ b/tp/Texinfo/Convert/Converter.pm
@@ -443,7 +443,8 @@ sub encode_converter_document($)
                 'document_descriptor' => $self->{'document_descriptor'}};
 
   foreach my $variable ('style_commands_formatting', 'formatting_function',
-     'types_open', 'types_conversion', 'commands_open', 'commands_conversion') 
{
+     'types_open', 'types_conversion', 'commands_open', 'commands_conversion',
+     'code_types', 'pre_class_types') {
     if ($self->{$variable}) {
       $result->{$variable} = $self->{$variable};
     }
diff --git a/tp/Texinfo/XS/Makefile.am b/tp/Texinfo/XS/Makefile.am
index d2f9e90a54..2dc36990ed 100644
--- a/tp/Texinfo/XS/Makefile.am
+++ b/tp/Texinfo/XS/Makefile.am
@@ -143,6 +143,8 @@ libtexinfo_la_SOURCES= \
                      main/manipulate_tree.h \
                      main/node_name_normalization.c \
                      main/node_name_normalization.h \
+                     main/command_stack.c \
+                     main/command_stack.h \
                      main/targets.c \
                      main/targets.h \
                      main/utils.c \
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index 225ef383a0..b2d0e4876f 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -77,6 +77,21 @@ typedef struct ARGS_FORMATTED {
 #define F_AFT_url               0x0080
 #define F_AFT_raw               0x0100
 
+#define HF_composition_context  0x0001
+#define HF_format_context       0x0002
+#define HF_format_raw           0x0004
+#define HF_pre_class            0x0008
+#define HF_upper_case           0x0010
+#define HF_HTML_align           0x0020
+
+typedef struct HTML_COMMAND_STRUCT {
+    unsigned long flags;
+    char *pre_class;
+    char *format_context;
+} HTML_COMMAND_STRUCT;
+
+static HTML_COMMAND_STRUCT html_commands_data[BUILTIN_CMD_NUMBER];
+
 /* in specification of args.  Number max +1 for a trailing 0 */
 #define MAX_COMMAND_ARGS_NR 6
 
@@ -118,6 +133,8 @@ typedef struct COMMAND_ARGS_SPECIFICATION {
 
 static COMMAND_ARGS_SPECIFICATION command_args_flags[BUILTIN_CMD_NUMBER];
 
+
+
 static void convert_to_html_internal (CONVERTER *self, ELEMENT *e,
                                       TEXT *result, char *explanation);
 
@@ -803,6 +820,39 @@ prepare_special_units (CONVERTER *self, int 
output_units_descriptor,
   destroy_strings_list (do_special);
 }
 
+static enum command_id additional_format_context_cmd[] = {
+   CM_tab, CM_item, CM_itemx, CM_headitem, 0
+ };
+
+static enum command_id HTML_align_cmd[] = {
+   CM_raggedright, CM_flushleft, CM_flushright, CM_center, 0
+};
+
+/* TODO free? It should be freed at exit? */
+void
+register_format_context_command (enum command_id cmd)
+{
+  char *context_str;
+
+  xasprintf (&context_str, "@%s", builtin_command_data[cmd].cmdname);
+
+  html_commands_data[cmd].format_context = context_str;
+  html_commands_data[cmd].flags |= HF_format_context;
+}
+
+void register_pre_class_command (enum command_id cmd, enum command_id main_cmd)
+{
+  char *pre_class_str;
+
+  if (main_cmd)
+    pre_class_str = builtin_command_data[main_cmd].cmdname;
+  else
+    pre_class_str = builtin_command_data[cmd].cmdname;
+
+  html_commands_data[cmd].pre_class = pre_class_str;
+  html_commands_data[cmd].flags |= HF_pre_class;
+}
+
 /* most of the initialization is done by html_converter_initialize_sv
    in get_perl_info, the initialization that sdo not require information
    from perl is done here */
@@ -823,6 +873,49 @@ html_converter_initialize (CONVERTER *self)
       memcpy (&command_args_flags[cmd].flags, &default_commands_args[i].flags,
               max_args);
     }
+
+  for (i = 0; small_block_associated_command[i][0]; i++)
+    {
+      enum command_id small_cmd = small_block_associated_command[i][0];
+      enum command_id cmd = small_block_associated_command[i][1];
+      register_pre_class_command (small_cmd, cmd);
+    }
+
+  for (i = 1; i < BUILTIN_CMD_NUMBER; i++)
+    {
+      if (builtin_command_data[i].flags & CF_block
+          || builtin_command_data[i].flags & CF_root)
+        register_format_context_command (i);
+
+      if (builtin_command_data[i].flags & CF_preformatted
+          || builtin_command_data[i].flags & CF_root)
+        html_commands_data[i].flags |= HF_composition_context;
+
+      if (builtin_command_data[i].flags & CF_block)
+        {
+          if (builtin_command_data[i].data == BLOCK_menu)
+            html_commands_data[i].flags |= HF_composition_context;
+          else if (builtin_command_data[i].data == BLOCK_format_raw)
+            html_commands_data[i].flags |= HF_format_raw;
+        }
+
+      if (builtin_command_data[i].flags & CF_preformatted)
+        {
+          if (!(html_commands_data[i].flags & HF_pre_class))
+            register_pre_class_command (i, 0);
+        }
+    }
+  register_pre_class_command (CM_verbatim, 0);
+  register_pre_class_command (CM_menu, 0);
+  for (i = 0; additional_format_context_cmd[i]; i++)
+    register_format_context_command (additional_format_context_cmd[i]);
+
+  for (i = 0; HTML_align_cmd[i]; i++)
+    html_commands_data[i].flags |= HF_HTML_align | HF_composition_context;
+
+  html_commands_data[CM_float].flags |= HF_composition_context;
+
+  html_commands_data[CM_sc].flags |= HF_upper_case;
 }
 
 void
@@ -843,6 +936,7 @@ html_initialize_output_state (CONVERTER *self)
         = (HTML_TARGET_LIST *) malloc (sizeof (HTML_TARGET_LIST));
       memset (self->html_special_targets[i], 0, sizeof (HTML_TARGET_LIST));
     }
+
 }
 
 static HTML_TARGET *
@@ -2278,6 +2372,141 @@ html_convert_init (CONVERTER *self)
   self->title_titlepage = title_titlepage;
 }
 
+static char *
+type_conversion (CONVERTER *self, enum element_type type,
+                 ELEMENT *element, char *content)
+{
+  /* TODO call a C function if status is FRS_status_default_set
+     maybe putting function references in an array */
+  if (self->types_conversion[type].status > 0)
+    return call_types_conversion (self, type, element, content);
+  return 0;
+}
+
+static char *
+type_open (CONVERTER *self, enum element_type type, ELEMENT *element)
+{
+  /* TODO call a C function if status is FRS_status_default_set
+     maybe putting function references in an array */
+  if (self->types_open[type].status > 0)
+    return call_types_open (self, type, element);
+  return 0;
+}
+
+
+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 HTML_FORMATTING_CONTEXT *
+top_html_formatting_context (HTML_FORMATTING_CONTEXT_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("HTML formatting context stack empty for top");
+
+  return &stack->stack[stack->top - 1];
+}
+
+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--;
+}
+
+static void
+html_new_document_context (CONVERTER *self,
+        char *context_name, int document_global_context,
+        enum command_id block_command)
+{
+  HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
+  if (stack->top >= stack->space)
+    {
+      stack->stack
+        = realloc (stack->stack,
+                   (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;
+
+  push_style_no_code (&stack->stack[stack->top].monospace_context);
+  push_command_or_type (&stack->stack[stack->top].composition_context,
+                        0, 0);
+  if (block_command)
+    push_command (&stack->stack[stack->top].block_commands, block_command);
+
+  if (document_global_context)
+    {
+      self->document_global_context++;
+      self->modified_state++;
+    }
+
+  push_html_formatting_context (&stack->stack[stack->top].formatting_context,
+                                context_name);
+
+  stack->top++;
+}
+
+static 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");
+
+  document_ctx = &stack->stack[stack->top -1];
+
+  free (document_ctx->context);
+  free (document_ctx->monospace_context.stack);
+  free (document_ctx->composition_context.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++;
+    }
+
+  stack->top--;
+}
+
+static HTML_DOCUMENT_CONTEXT *
+top_document_context (CONVERTER *self)
+{
+  HTML_DOCUMENT_CONTEXT_STACK *stack = &self->html_document_context;
+
+  if (stack->top == 0)
+    fatal ("HTML document context stack empty for top");
+
+  return &stack->stack[stack->top - 1];
+}
+
+
 #define ADD(x) text_append (result, x)
 
 /* EXPLANATION is used for debugging */
@@ -2336,19 +2565,47 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
         {
           fprintf (stderr, "IGNORED %s\n", command_type.text);
         }
+      return;
     }
 
   /* Process text */
 
   if (element->text.space > 0)
     {
-      char *result = "";
+      TEXT text_result;
+      text_init (&text_result);
+      text_append (&text_result, "");
+      /* already converted to html, keep it as is, assume it cannot be NULL */
+      if (element->type == ET__converted)
+        text_append (&text_result, element->text.text);
+      else if (element->type == ET_untranslated)
+        {
+          char *translation_context
+            = lookup_extra_string (element, "translation_context");
+          ELEMENT *translated = gdt_tree (element->text.text, self->document,
+                                    self->conf, 0, translation_context, 0);
+
+          convert_to_html_internal (self, translated, &text_result,
+                                    "translated TEXT");
+        }
+      else
+        {
+          char *result = type_conversion (self, element->type, element,
+                                          element->text.text);
+          if (result)
+            {
+              text_append (&text_result, result);
+              free (result);
+            }
+        }
 
       if (self->conf->DEBUG > 0)
         {
-          fprintf (stderr, "DO TEXT => `%s'\n", result);
+          fprintf (stderr, "DO TEXT => `%s'\n", text_result.text);
         }
 
+      ADD(text_result.text);
+      free (text_result.text);
       return;
     }
 
@@ -2360,7 +2617,10 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
       enum command_id data_cmd = element_builtin_data_cmd (element);
 
       if (builtin_command_data[data_cmd].flags & CF_root)
-        self->current_root_command = element;
+        {
+          self->current_root_command = element;
+          self->modified_state++;
+        }
 
       if (self->commands_conversion[cmd].status)
         {
@@ -2368,7 +2628,104 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
           ARGS_FORMATTED *args_formatted = 0;
           TEXT content_formatted;
 
-          /* */
+          HTML_DOCUMENT_CONTEXT *top_document_ctx;
+          HTML_FORMATTING_CONTEXT *top_formating_ctx;
+
+          if (builtin_command_data[data_cmd].flags & CF_brace
+              && builtin_command_data[data_cmd].data == BRACE_context)
+            {
+              html_new_document_context (self,
+                               builtin_command_data[data_cmd].cmdname, 0, 0);
+              self->modified_state++;
+
+            }
+          top_document_ctx = top_document_context (self);
+
+          if (html_commands_data[data_cmd].flags & HF_format_context)
+            {
+              push_html_formatting_context (
+                         &top_document_ctx->formatting_context,
+                         html_commands_data[cmd].format_context);
+              self->modified_state++;
+            }
+
+          top_formating_ctx
+            = top_html_formatting_context 
(&top_document_ctx->formatting_context);
+
+          if (builtin_command_data[data_cmd].flags & CF_block)
+            {
+              push_command (&top_document_ctx->block_commands, data_cmd);
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_composition_context)
+            {
+              push_command_or_type (&top_document_ctx->composition_context,
+                                    cmd, 0);
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_pre_class)
+            {
+              push_string_stack_string 
(&top_document_ctx->preformatted_classes,
+                                        
html_commands_data[data_cmd].pre_class);
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_format_raw)
+            {
+              top_document_ctx->raw_ctx++;
+              self->modified_state++;
+            }
+          else if (data_cmd == CM_verbatim)
+            {
+              top_document_ctx->verbatim_ctx++;
+              self->modified_state++;
+            }
+
+          if (builtin_command_data[data_cmd].other_flags & CF_brace_code
+              || builtin_command_data[data_cmd].flags & CF_preformatted_code)
+            {
+              push_monospace (&top_document_ctx->monospace_context);
+              self->modified_state++;
+            }
+          else if (builtin_command_data[data_cmd].flags & CF_brace
+                   && builtin_command_data[data_cmd].data == 
BRACE_style_no_code)
+            {
+              push_style_no_code (&top_document_ctx->monospace_context);
+              self->modified_state++;
+            }
+          else if (html_commands_data[data_cmd].flags & HF_upper_case)
+            {
+              top_formating_ctx->upper_case_ctx++;
+              self->modified_state++;
+            }
+          else if (builtin_command_data[data_cmd].flags & CF_math)
+            {
+              top_document_ctx->math_ctx++;
+              self->modified_state++;
+             /*
+        $convert_to_latex = 1 if ($self->get_conf('CONVERT_TO_LATEX_IN_MATH'));
+              */
+            }
+          if (cmd == CM_verb)
+            {
+              top_formating_ctx->space_protected++;
+              self->modified_state++;
+            }
+          else if (cmd == CM_w)
+            {
+              top_formating_ctx->no_break++;
+              self->modified_state++;
+            }
+
+          /*
+      my $result = '';
+      if (defined($self->{'commands_open'}->{$command_name})) {
+        $result .= &{$self->{'commands_open'}->{$command_name}}($self,
+                                                 $command_name, $element);
+      }
+           */
 
           if (element->contents.number > 0)
             {
@@ -2376,7 +2733,13 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
 
               if (convert_to_latex)
                 {
-                  /* */
+                  /*
+          $content_formatted
+           = Texinfo::Convert::LaTeX::convert_to_latex_math(undef,
+                                {'contents' => $element->{'contents'}},
+                                         $self->{'options_latex_math'});
+
+                  */
                 }
               else
                 {
@@ -2471,23 +2834,193 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
                           text_reset (&formatted_arg);
                           xasprintf (&explanation, "%s A[%d]monospace",
                                                    command_type.text, arg_idx);
-                /*
-                 push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
-                 convert_to_html_internal ...
-                pop @{$self->{'document_context'}->[-1]->{'monospace'}};
-                 */
+                          push_monospace 
(&top_document_ctx->monospace_context);
+                          self->modified_state++;
+
                           convert_to_html_internal (self, arg, &formatted_arg,
                                                     explanation);
+                          pop_monospace_context
+                              (&top_document_ctx->monospace_context);
+                          self->modified_state++;
 
                           free (explanation);
                           arg_formatted->formatted[AFT_type_monospace]
                            = strdup (formatted_arg.text);
                         }
+                      if (arg_flags & F_AFT_string)
+                        {
+                          HTML_DOCUMENT_CONTEXT *string_document_ctx;
+                          text_reset (&formatted_arg);
+                          html_new_document_context (self, command_type.text,
+                                                     0, 0);
+                          string_document_ctx = top_document_context (self);
+                          string_document_ctx->string_ctx++;
+                          self->modified_state++;
+                          xasprintf (&explanation, "%s A[%d]string",
+                                                   command_type.text, arg_idx);
+                          convert_to_html_internal (self, arg, &formatted_arg,
+                                                    explanation);
+
+                          free (explanation);
+                          html_pop_document_context (self);
+                          self->modified_state++;
+                          arg_formatted->formatted[AFT_type_string]
+                           = strdup (formatted_arg.text);
+                        }
+                      if (arg_flags & F_AFT_monospacestring)
+                        {
+                          HTML_DOCUMENT_CONTEXT *string_document_ctx;
+                          text_reset (&formatted_arg);
+                          html_new_document_context (self, command_type.text,
+                                                     0, 0);
+                          string_document_ctx = top_document_context (self);
+                          string_document_ctx->string_ctx++;
+                          push_monospace 
(&string_document_ctx->monospace_context);
+                          self->modified_state++;
+                          xasprintf (&explanation, "%s A[%d]monospacestring",
+                                                   command_type.text, arg_idx);
+                          convert_to_html_internal (self, arg, &formatted_arg,
+                                                    explanation);
+
+                          free (explanation);
+                          pop_monospace_context
+                              (&string_document_ctx->monospace_context);
+                          html_pop_document_context (self);
+                          self->modified_state++;
+                          arg_formatted->formatted[AFT_type_monospacestring]
+                           = strdup (formatted_arg.text);
+                        }
+                      if (arg_flags & F_AFT_monospacetext)
+                        {
+                        /*
+                $arg_formatted->{$arg_type}
+                  = Texinfo::Convert::Text::convert_to_text($arg,
+                         {'code' => 1,
+                 
Texinfo::Convert::Text::copy_options_for_convert_text($self)});
+                        */
+                        }
+                      if (arg_flags & F_AFT_filenametext)
+                        {
+                        /*
+                # Always use encoded characters for file names
+                $arg_formatted->{$arg_type}
+                  = Texinfo::Convert::Text::convert_to_text($arg,
+                         {'code' => 1,
+               Texinfo::Convert::Text::copy_options_for_convert_text($self, 
1)});
+                        */
+                        }
+                      if (arg_flags & F_AFT_filenametext)
+                        {
+                         /*
+                # set the encoding to UTF-8 to always have a string that is 
suitable
+                # for percent encoding.
+                my $text_conversion_options = {'code' => 1,
+                  Texinfo::Convert::Text::copy_options_for_convert_text($self, 
1)};
+                $text_conversion_options->{'enabled_encoding'} = 'utf-8';
+                $arg_formatted->{$arg_type}
+                   = Texinfo::Convert::Text::convert_to_text($arg,
+                                                   $text_conversion_options);
+                         */
+                        }
+                      if (arg_flags & F_AFT_raw)
+                        {
+                          top_document_ctx->raw_ctx++;
+                          self->modified_state++;
+                          xasprintf (&explanation, "%s A[%d]raw",
+                                                   command_type.text, arg_idx);
+                          convert_to_html_internal (self, arg, &formatted_arg,
+                                                    explanation);
+
+                          free (explanation);
+                          top_document_ctx->raw_ctx--;
+                          self->modified_state++;
+                          arg_formatted->formatted[AFT_type_raw]
+                           = strdup (formatted_arg.text);
+                        }
                     }
                   free (formatted_arg.text);
                 }
             }
-          /* */
+
+          if (html_commands_data[data_cmd].flags & HF_composition_context)
+            {
+              pop_command_or_type (&top_document_ctx->composition_context);
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_pre_class)
+            {
+              pop_string_stack (&top_document_ctx->preformatted_classes);
+              self->modified_state++;
+            }
+
+          if (cmd == CM_verb)
+            {
+              top_formating_ctx->space_protected--;
+              self->modified_state++;
+            }
+          else if (cmd == CM_w)
+            {
+              top_formating_ctx->no_break--;
+              self->modified_state++;
+            }
+
+          if (builtin_command_data[data_cmd].flags & CF_preformatted_code
+              || (builtin_command_data[data_cmd].flags & CF_brace
+                  && builtin_command_data[data_cmd].data == 
BRACE_style_no_code)
+              || builtin_command_data[data_cmd].other_flags & CF_brace_code)
+            {
+              pop_monospace_context (&top_document_ctx->monospace_context);
+              self->modified_state++;
+            }
+          else if (html_commands_data[data_cmd].flags & HF_upper_case)
+            {
+              top_formating_ctx->upper_case_ctx--;
+              self->modified_state++;
+            }
+
+          else if (builtin_command_data[data_cmd].flags & CF_math)
+            {
+              top_document_ctx->math_ctx--;
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_format_raw)
+            {
+              top_document_ctx->raw_ctx--;
+              self->modified_state++;
+            }
+          else if (data_cmd == CM_verbatim)
+            {
+              top_document_ctx->verbatim_ctx--;
+              self->modified_state++;
+            }
+
+          if (builtin_command_data[data_cmd].flags & CF_block)
+            {
+              pop_command (&top_document_ctx->block_commands);
+              self->modified_state++;
+            }
+
+          if (html_commands_data[data_cmd].flags & HF_format_context)
+            {
+              pop_html_formatting_context (
+                         &top_document_ctx->formatting_context);
+              self->modified_state++;
+            }
+
+          if (builtin_command_data[data_cmd].flags & CF_brace
+              && builtin_command_data[data_cmd].data == BRACE_context)
+            {
+              html_pop_document_context (self);
+              self->modified_state++;
+            }
+
+          if (element->cmd == CM_node)
+            {
+              self->current_node = element;
+              self->modified_state++;
+            }
 
           /* args are formatted, now format the command itself */
           if (self->commands_conversion[cmd].status)
@@ -2514,22 +3047,66 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
         }
 
       if (builtin_command_data[data_cmd].flags & CF_root)
-        self->current_root_command = 0;
+        {
+          self->current_root_command = 0;
+          self->modified_state++;
+        }
     }
   else if (element->type)
     {
-      char *type_name = element_type_names[element->type];
+      char *open_result;
+      enum element_type type = element->type;
+      char *type_name = element_type_names[type];
       TEXT type_result;
       TEXT content_formatted;
+      HTML_DOCUMENT_CONTEXT *top_document_ctx = top_document_context (self);
+      HTML_FORMATTING_CONTEXT *top_formating_ctx
+        = top_html_formatting_context (&top_document_ctx->formatting_context);
 
       text_init (&type_result);
       text_append (&type_result, "");
 
-      /* */
+      open_result = type_open (self, type, element);
+      if (open_result)
+        {
+          text_append (&type_result, open_result);
+          free (open_result);
+        }
+
+      if (type == ET_paragraph)
+        {
+          top_formating_ctx->paragraph_number++;
+          self->modified_state++;
+        }
+      else if (type == ET_preformatted || type == ET_rawpreformatted)
+        {
+          top_formating_ctx->preformatted_number++;
+          self->modified_state++;
+        }
+      else if (self->pre_class_types[type])
+        {
+          push_string_stack_string (&top_document_ctx->preformatted_classes,
+                                    self->pre_class_types[type]);
+          push_command_or_type (&top_document_ctx->composition_context,
+                                0, type);
+          self->modified_state++;
+        }
+
+      if (self->code_types[type])
+        {
+          push_monospace (&top_document_ctx->monospace_context);
+          self->modified_state++;
+        }
+
+      if (type == ET__string)
+        {
+          top_document_ctx->string_ctx++;
+          self->modified_state++;
+        }
 
       text_init (&content_formatted);
 
-      if (element->type == ET_definfoenclose_command)
+      if (type == ET_definfoenclose_command)
         {
           if (element->args.number > 0)
             {
@@ -2554,21 +3131,40 @@ convert_to_html_internal (CONVERTER *self, ELEMENT 
*element,
             }
         }
 
-      if (self->types_conversion[element->type].status)
+      if (self->types_conversion[type].status)
         {
-        /*
-      $result .= &{$self->{'types_conversion'}->{$type_name}} ($self,
-                                                 $type_name,
-                                                 $element,
-                                                 $content_formatted);
-         */
+          char *result = type_conversion (self, type, element,
+                                          content_formatted.text);
+          if (result)
+            {
+              text_append (&type_result, result);
+              free (result);
+            }
         }
       else if (content_formatted.end > 0)
         {
           text_append (&type_result, content_formatted.text);
         }
       free (content_formatted.text);
-      /* */
+
+      if (self->code_types[type])
+        {
+          pop_monospace_context (&top_document_ctx->monospace_context);
+          self->modified_state++;
+        }
+
+      if (type == ET__string)
+        {
+          top_document_ctx->string_ctx--;
+          self->modified_state++;
+        }
+
+      if (self->pre_class_types[type])
+        {
+          pop_string_stack (&top_document_ctx->preformatted_classes);
+          pop_command_or_type (&top_document_ctx->composition_context);
+          self->modified_state++;
+        }
 
       if (self->conf->DEBUG > 0)
         {
@@ -2647,6 +3243,7 @@ convert_output_unit (CONVERTER *self, OUTPUT_UNIT 
*output_unit,
  */
 
   self->current_output_unit = output_unit;
+  self->modified_state++;
 
   text_init (&content_formatted);
   text_append (&content_formatted, "");
@@ -2684,6 +3281,7 @@ convert_output_unit (CONVERTER *self, OUTPUT_UNIT 
*output_unit,
     }
 
   self->current_output_unit = 0;
+  self->modified_state++;
 
   if (self->conf->DEBUG > 0)
     fprintf (stderr, "UNIT (%s) => `%s'\n", output_unit_type_names[unit_type],
@@ -2723,6 +3321,7 @@ html_convert_convert (CONVERTER *self, ELEMENT *root,
   OUTPUT_UNIT_LIST *special_units
     = retrieve_output_units (special_units_descriptor);
 
+  html_new_document_context (self, "_toplevel_context", 0, 0);
   text_init (&result);
 
   if (!output_units || !output_units->number)
@@ -2759,6 +3358,7 @@ html_convert_convert (CONVERTER *self, ELEMENT *root,
             }
         }
     }
+  html_pop_document_context (self);
   return result.text;
 }
 
diff --git a/tp/Texinfo/XS/main/build_perl_info.c 
b/tp/Texinfo/XS/main/build_perl_info.c
index d5a1efa5f3..8da67d8b9a 100644
--- a/tp/Texinfo/XS/main/build_perl_info.c
+++ b/tp/Texinfo/XS/main/build_perl_info.c
@@ -38,7 +38,7 @@
 #include "tree_types.h"
 #include "tree.h"
 #include "element_types.h"
-/* for GLOBAL_INFO ERROR_MESSAGE fatal output_unit_type_names */
+/* for GLOBAL_INFO ERROR_MESSAGE fatal output_unit_type_names CONVERTER */
 #include "utils.h"
 /* for debugging */
 #include "debug.h"
@@ -51,6 +51,7 @@
 /* for wipe_error_message_list */
 #include "errors.h"
 #include "tree_perl_api.h"
+#include "command_stack.h"
 #include "build_perl_info.h"
 
 #define LOCALEDIR DATADIR "/locale"
@@ -1776,3 +1777,204 @@ build_out_filepaths (FILE_NAME_PATH_COUNTER_LIST 
*output_unit_files)
   return newRV_noinc ((SV *) hv);
 }
 
+HV *
+build_html_formatting_context (HTML_FORMATTING_CONTEXT *formatting_context)
+{
+  HV *hv;
+
+  dTHX;
+
+  hv = newHV ();
+
+#define STORE(key, value) hv_store (hv, key, strlen (key), value, 0)
+
+  STORE("context_name", newSVpv (formatting_context->context_name, 0));
+#define STORE_INT(name) STORE(#name, newSViv (formatting_context->name))
+  STORE_INT(preformatted_number);
+  STORE_INT(paragraph_number);
+  STORE_INT(space_protected);
+  STORE_INT(no_break);
+#undef STORE_INT
+
+#define STORE_CTX(name) STORE(#name, newSViv (formatting_context->name##_ctx))
+  STORE_CTX(upper_case);
+#undef STORE_CTX
+
+#undef STORE
+  return hv;
+}
+
+HV *
+build_html_document_context (HTML_DOCUMENT_CONTEXT *document_context)
+{
+  int i;
+  HV *hv;
+  AV *monospace_context_av;
+  AV *composition_context_av;
+  AV *block_commands_av;
+  AV *formatting_context_av;
+  AV *preformatted_classes_av;
+
+  dTHX;
+
+  hv = newHV ();
+  monospace_context_av = newAV ();
+  composition_context_av = newAV ();
+  block_commands_av = newAV ();
+  formatting_context_av = newAV ();
+  preformatted_classes_av = newAV ();
+
+
+#define STORE(key, value) hv_store (hv, key, strlen (key), value, 0)
+
+  STORE ("context", newSVpv_utf8 (document_context->context, 0));
+
+#define STORE_CTX(name) STORE(#name, newSViv (document_context->name##_ctx))
+  STORE_CTX(string);
+  STORE_CTX(raw);
+  STORE_CTX(verbatim);
+  STORE_CTX(math);
+#undef STORE_CTX
+  STORE ("document_global_context",
+         newSViv (document_context->document_global_context));
+
+  for (i = 0; i < document_context->monospace_context.top; i++)
+    {
+      enum monospace_context context
+        = document_context->monospace_context.stack[i];
+      av_push (monospace_context_av, newSViv (context));
+    }
+
+  STORE ("monospace_context", newRV_noinc ((SV *) monospace_context_av));
+
+  for (i = 0; i < document_context->composition_context.top; i++)
+    {
+      char *context_str = 0;
+      COMMAND_OR_TYPE *context
+        = &document_context->composition_context.stack[i];
+      if (context->variety == CTV_type_type)
+        context_str = element_type_names[context->type];
+      else if (context->variety == CTV_type_command)
+        context_str = builtin_command_data[context->cmd].cmdname;
+      else
+        context_str = "";
+      av_push (composition_context_av, newSVpv (context_str, 0));
+    }
+  STORE ("composition_context", newRV_noinc ((SV *) composition_context_av));
+
+  for (i = 0; i < document_context->block_commands.top; i++)
+    {
+      enum command_id cmd = document_context->block_commands.stack[i];
+      char *context_str = builtin_command_data[cmd].cmdname;
+      av_push (block_commands_av, newSVpv (context_str, 0));
+    }
+  STORE ("block_commands", newRV_noinc ((SV *) block_commands_av));
+
+  for (i = 0; i < document_context->preformatted_classes.top; i++)
+    {
+      char *context_str = document_context->preformatted_classes.stack[i];
+      av_push (preformatted_classes_av, newSVpv (context_str, 0));
+    }
+  STORE ("preformatted_classes", newRV_noinc ((SV *) preformatted_classes_av));
+
+  for (i = 0; i < document_context->formatting_context.top; i++)
+    {
+      HTML_FORMATTING_CONTEXT *formatting_context
+        = &document_context->formatting_context.stack[i];
+      HV *context_hv = build_html_formatting_context (formatting_context);
+      av_push (formatting_context_av, newRV_noinc ((SV *) context_hv));
+    }
+  STORE ("formatting_context", newRV_noinc ((SV *) formatting_context_av));
+
+#undef STORE
+  return hv;
+}
+
+/* there is no need to return anything. */
+SV *
+build_html_formatting_state (CONVERTER *converter)
+{
+  HV *hv;
+  SV **document_context_sv;
+  AV *document_context_av;
+  SV **files_information_sv;
+  HV *files_information_hv;
+  int i;
+
+  dTHX;
+
+  if (!converter->hv)
+    return newSV (0);
+
+  hv = converter->hv;
+
+#define STORE(key, value) hv_store (hv, key, strlen (key), value, 0)
+  STORE("document_global_context",
+        newSViv (converter->document_global_context));
+
+  if (!converter->current_root_command)
+    STORE("current_root_command", newSV (0));
+  else
+    STORE("current_root_command",
+       newRV_inc ((SV *) converter->current_root_command->hv));
+
+  if (!converter->current_node)
+    STORE("current_node", newSV (0));
+  else
+    STORE("current_node",
+       newRV_inc ((SV *) converter->current_node->hv));
+
+  if (!converter->current_output_unit)
+    STORE("current_output_unit", newSV (0));
+  else
+    STORE("current_output_unit",
+       newRV_inc ((SV *) converter->current_output_unit->hv));
+
+  if (!converter->current_filename)
+    STORE("current_filename", newSV (0));
+  else
+    STORE("current_filename", newSVpv_utf8 (converter->current_filename, 0));
+
+  document_context_sv = hv_fetch (hv, "document_context",
+                                  strlen ("document_context"), 0);
+
+  if (!document_context_sv)
+    {
+      document_context_av = newAV ();
+      STORE("document_context", newRV_noinc ((SV *) document_context_av));
+    }
+  else
+    {
+      document_context_av = (AV *) SvRV (*document_context_sv);
+      av_clear (document_context_av);
+    }
+
+  for (i = 0; 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));
+    }
+
+  files_information_sv = hv_fetch (hv, "files_information",
+                                  strlen ("files_information"), 0);
+
+  if (!files_information_sv)
+    {
+      files_information_hv = newHV ();
+      STORE("files_information", newRV_noinc ((SV *) files_information_hv));
+    }
+  else
+    {
+      /* TODO
+      files_information_hv = (HV *) SvRV (*files_information_sv);
+      hv_clear (files_information_av);
+       */
+    }
+
+
+#undef STORE
+
+  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 4aab36f540..421aa65d40 100644
--- a/tp/Texinfo/XS/main/build_perl_info.h
+++ b/tp/Texinfo/XS/main/build_perl_info.h
@@ -48,4 +48,5 @@ 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);
 
+SV *build_html_formatting_state (CONVERTER *converter);
 #endif
diff --git a/tp/Texinfo/XS/main/call_perl_function.c 
b/tp/Texinfo/XS/main/call_perl_function.c
index ac763204ae..9c661a4422 100644
--- a/tp/Texinfo/XS/main/call_perl_function.c
+++ b/tp/Texinfo/XS/main/call_perl_function.c
@@ -527,3 +527,122 @@ call_formatting_function_format_title_titlepage 
(CONVERTER *self)
 
   return result;
 }
+
+char *
+call_types_conversion (CONVERTER *self, enum element_type type,
+                       ELEMENT *element, char *content)
+{
+  int count;
+  char *result;
+  char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  SV *formatting_reference = self->types_conversion[type].sv_reference;
+
+  dTHX;
+
+  if (!self->hv)
+    return 0;
+
+  if (self->modified_state)
+    {
+      build_html_formatting_state (self);
+      self->modified_state = 0;
+    }
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 4);
+
+  PUSHs(sv_2mortal (newRV_inc (self->hv)));
+  PUSHs(sv_2mortal (newSVpv (element_type_names[type], 0)));
+  PUSHs(sv_2mortal (newRV_inc (element->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)));
+  PUTBACK;
+
+  count = call_sv (formatting_reference,
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("types_conversion should return 1 item\n");
+
+  result_sv = POPs;
+  /* it is encoded using non strict encoding, so the UTF-8 could be invalid.
+     It could be possible to add a wrapper in perl that encode to UTF-8,
+     but probably not worth it */
+  result_ret = SvPVutf8 (result_sv, len);
+  result = strdup (result_ret);
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
+
+char *
+call_types_open (CONVERTER *self, enum element_type type,
+                 ELEMENT *element)
+{
+  int count;
+  char *result;
+  char *result_ret;
+  STRLEN len;
+  SV *result_sv;
+  SV *formatting_reference = self->types_open[type].sv_reference;
+
+  dTHX;
+
+  if (!self->hv)
+    return 0;
+
+  if (self->modified_state)
+    {
+      build_html_formatting_state (self);
+      self->modified_state = 0;
+    }
+
+  dSP;
+
+  ENTER;
+  SAVETMPS;
+
+  PUSHMARK(SP);
+  EXTEND(SP, 3);
+
+  PUSHs(sv_2mortal (newRV_inc (self->hv)));
+  PUSHs(sv_2mortal (newSVpv (element_type_names[type], 0)));
+  PUSHs(sv_2mortal (newRV_inc (element->hv)));
+  PUTBACK;
+
+  count = call_sv (formatting_reference,
+                   G_SCALAR);
+
+  SPAGAIN;
+
+  if (count != 1)
+    croak("types_open should return 1 item\n");
+
+  result_sv = POPs;
+  /* it is encoded using non strict encoding, so the UTF-8 could be invalid.
+     It could be possible to add a wrapper in perl that encode to UTF-8,
+     but probably not worth it */
+  result_ret = SvPVutf8 (result_sv, len);
+  result = strdup (result_ret);
+
+  PUTBACK;
+
+  FREETMPS;
+  LEAVE;
+
+  return result;
+}
diff --git a/tp/Texinfo/XS/main/command_stack.c 
b/tp/Texinfo/XS/main/command_stack.c
index 478167aa66..eb1b873a95 100644
--- a/tp/Texinfo/XS/main/command_stack.c
+++ b/tp/Texinfo/XS/main/command_stack.c
@@ -15,6 +15,7 @@
 
 #include <config.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "tree_types.h"
 #include "command_ids.h"
@@ -64,17 +65,132 @@ top_command (COMMAND_STACK *stack)
   return stack->stack[stack->top - 1];
 }
 
-enum command_id
-current_context_command (void)
+void
+push_command_or_type (COMMAND_OR_TYPE_STACK *stack, enum command_id cmd,
+                      enum element_type type)
 {
-  int i;
+  if (stack->top >= stack->space)
+    {
+      stack->stack
+        = realloc (stack->stack,
+                   (stack->space += 5) * sizeof (COMMAND_OR_TYPE));
+    }
 
-  if (top == 0)
-    return CM_NONE;
-  for (i = top -1; i >= 0; i--)
+  if (type)
+    {
+      stack->stack[stack->top].type = type;
+      stack->stack[stack->top].variety = CTV_type_type;
+    }
+  else if (cmd)
+    {
+      stack->stack[stack->top].cmd = cmd;
+      stack->stack[stack->top].variety = CTV_type_command;
+    }
+  else
     {
-      if (command_stack.stack[i] != CM_NONE)
-        return command_stack.stack[i];
+      stack->stack[stack->top].cmd = 0;
+      stack->stack[stack->top].variety = CTV_type_none;
     }
-  return CM_NONE;
+
+  stack->top++;
+}
+
+void
+pop_command_or_type (COMMAND_OR_TYPE_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("command or type stack empty");
+
+  stack->top--;
 }
+
+COMMAND_OR_TYPE *
+top_command_or_type (COMMAND_OR_TYPE_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("command or type stack empty for top");
+
+  return &stack->stack[stack->top - 1];
+}
+
+
+void
+push_string_stack_string (STRING_STACK *stack, char *string)
+{
+  if (stack->top >= stack->space)
+    {
+      stack->stack
+        = realloc (stack->stack,
+                   (stack->space += 5) * sizeof (char *));
+    }
+
+  stack->stack[stack->top] = strdup (string);
+
+  stack->top++;
+}
+
+void
+pop_string_stack (STRING_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("string stack empty");
+
+  free (stack->stack[stack->top - 1]);
+  stack->top--;
+}
+
+char *
+top_string_stack (STRING_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("string stack empty for top");
+
+  return stack->stack[stack->top - 1];
+}
+
+
+static void
+push_monospace_context (MONOSPACE_CONTEXT_STACK *stack,
+                        enum monospace_context mono_ctx)
+{
+  if (stack->top >= stack->space)
+    {
+      stack->stack
+        = realloc (stack->stack,
+                   (stack->space += 5) * sizeof (enum monospace_context));
+    }
+
+  stack->stack[stack->top] = mono_ctx;
+  stack->top++;
+}
+
+void
+push_monospace (MONOSPACE_CONTEXT_STACK *stack)
+{
+  push_monospace_context (stack, MONO_ctx_on);
+}
+
+void
+push_style_no_code (MONOSPACE_CONTEXT_STACK *stack)
+{
+  push_monospace_context (stack, MONO_ctx_off);
+}
+
+enum monospace_context
+pop_monospace_context (MONOSPACE_CONTEXT_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("monospace stack empty for top");
+
+  return stack->stack[--stack->top];
+}
+
+enum monospace_context
+top_monospace_context (MONOSPACE_CONTEXT_STACK *stack)
+{
+  if (stack->top == 0)
+    fatal ("monospace stack empty for top");
+
+  return stack->stack[stack->top - 1];
+}
+
diff --git a/tp/Texinfo/XS/main/command_stack.h 
b/tp/Texinfo/XS/main/command_stack.h
index f9e5287c57..0a5b3bf20d 100644
--- a/tp/Texinfo/XS/main/command_stack.h
+++ b/tp/Texinfo/XS/main/command_stack.h
@@ -19,10 +19,22 @@
 #include <stddef.h>
 
 #include "tree_types.h"
+#include "element_types.h"
+
+enum command_type_variety {
+   CTV_type_none,
+   CTV_type_command,
+   CTV_type_type,
+};
+
+enum monospace_context {
+   MONO_ctx_off,
+   MONO_ctx_on,
+};
 
 typedef struct {
     enum command_id *stack;
-    size_t top;   /* One above last pushed context. */
+    size_t top;   /* One above last pushed command. */
     size_t space;
 } COMMAND_STACK;
 
@@ -30,6 +42,48 @@ void reset_command_stack (COMMAND_STACK *stack);
 void push_command (COMMAND_STACK *stack, enum command_id cmd);
 enum command_id pop_command (COMMAND_STACK *stack);
 enum command_id top_command (COMMAND_STACK *stack);
-enum command_id current_context_command (void);
+
+/* either a type or a command id */
+typedef struct {
+    enum command_type_variety variety;
+    union {
+      enum command_id cmd;
+      enum element_type type;
+    };
+} COMMAND_OR_TYPE;
+
+typedef struct {
+    COMMAND_OR_TYPE *stack;
+    size_t top;   /* One above last pushed command. */
+    size_t space;
+} COMMAND_OR_TYPE_STACK;
+
+void push_command_or_type (COMMAND_OR_TYPE_STACK *stack, enum command_id cmd,
+                           enum element_type type);
+void pop_command_or_type (COMMAND_OR_TYPE_STACK *stack);
+COMMAND_OR_TYPE *top_command_or_type (COMMAND_OR_TYPE_STACK *stack);
+
+
+typedef struct {
+    char **stack;
+    size_t top;   /* One above last pushed command. */
+    size_t space;
+} STRING_STACK;
+
+void push_string_stack_string (STRING_STACK *stack, char *string);
+void pop_string_stack (STRING_STACK *stack);
+char *top_string_stack (STRING_STACK *stack);
+
+
+typedef struct {
+    enum monospace_context *stack;
+    size_t top;   /* One above last pushed. */
+    size_t space;
+} MONOSPACE_CONTEXT_STACK;
+
+void push_monospace (MONOSPACE_CONTEXT_STACK *stack);
+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);
 
 #endif
diff --git a/tp/Texinfo/XS/main/element_types.c 
b/tp/Texinfo/XS/main/element_types.c
index 8a47d991ad..410cd47d49 100644
--- a/tp/Texinfo/XS/main/element_types.c
+++ b/tp/Texinfo/XS/main/element_types.c
@@ -71,6 +71,9 @@ char *element_type_names[] = {
 "macro_call",
 "rmacro_call",
 "linemacro_call",
+"_code",
+"_converted",
+"_string",
 "special_unit_element",
 
 };
diff --git a/tp/Texinfo/XS/main/element_types.h 
b/tp/Texinfo/XS/main/element_types.h
index aa0ec079a5..c3e7a74fb2 100644
--- a/tp/Texinfo/XS/main/element_types.h
+++ b/tp/Texinfo/XS/main/element_types.h
@@ -74,6 +74,9 @@ ET_untranslated,
 ET_macro_call,
 ET_rmacro_call,
 ET_linemacro_call,
+ET__code,
+ET__converted,
+ET__string,
 ET_special_unit_element,
 };
 
diff --git a/tp/Texinfo/XS/main/element_types.txt 
b/tp/Texinfo/XS/main/element_types.txt
index 778f15e5f8..8769b50fe9 100644
--- a/tp/Texinfo/XS/main/element_types.txt
+++ b/tp/Texinfo/XS/main/element_types.txt
@@ -103,6 +103,14 @@ macro_call
 rmacro_call
 linemacro_call
 
+# for HTML converter
+_code
+_converted
+_string
+
 # not in parser, for virtual element associated to special output units
+# the corresponding type is often used in code to determine the number of
+# element types, so it would be a good idea to keep special_unit_element
+# last.
 special_unit_element
 
diff --git a/tp/Texinfo/XS/main/get_perl_info.c 
b/tp/Texinfo/XS/main/get_perl_info.c
index 7bf4a994d7..bdcbf18dcc 100644
--- a/tp/Texinfo/XS/main/get_perl_info.c
+++ b/tp/Texinfo/XS/main/get_perl_info.c
@@ -454,6 +454,8 @@ html_converter_initialize_sv (SV *sv_in, SV 
*default_formatting_references,
   SV **types_conversion_sv;
   SV **commands_open_sv;
   SV **commands_conversion_sv;
+  SV **code_types_sv;
+  SV **pre_class_types_sv;
   HV *formatting_function_hv;
   HV *commands_open_hv;
   HV *commands_conversion_hv;
@@ -612,7 +614,6 @@ html_converter_initialize_sv (SV *sv_in, SV 
*default_formatting_references,
         types_conversion_hv);
     }
 
-
   FETCH(sorted_special_unit_varieties)
 
   if (sorted_special_unit_varieties_sv)
@@ -716,6 +717,98 @@ html_converter_initialize_sv (SV *sv_in, SV 
*default_formatting_references,
   memset (converter->global_units_directions, 0,
     (D_Last + nr_special_units+1) * sizeof (OUTPUT_UNIT));
 
+  FETCH(code_types)
+
+  if (code_types_sv)
+    {
+      I32 hv_number;
+      I32 i;
+
+      HV *code_types_hv = (HV *)SvRV (*code_types_sv);
+
+      hv_number = hv_iterinit (code_types_hv);
+
+      for (i = 0; i < hv_number; i++)
+        {
+          int j;
+          enum element_type type = ET_NONE;
+          I32 retlen;
+          char *type_name;
+          SV *code_sv = hv_iternextsv (code_types_hv,
+                                       &type_name, &retlen);
+          if (SvOK (code_sv))
+            {
+              int code_value = SvIV (code_sv);
+          /* this is not very efficient, but should be done only once
+             in the default case.  If this is needed more, a qsort/bfind
+             could be used, but the overhead could probably only be
+             justified if finding the type index happens more often */
+              for (j = 1; j < ET_special_unit_element+1; j++)
+                {
+                  if (!strcmp (element_type_names[j], type_name))
+                    {
+                      type = j;
+                      break;
+                    }
+                }
+              if (type == ET_NONE)
+                {
+                  fprintf (stderr, "ERROR: %s: code type not found\n",
+                                   type_name);
+                }
+              else
+                converter->code_types[type] = code_value;
+           }
+       }
+   }
+
+  FETCH(pre_class_types)
+
+  if (pre_class_types_sv)
+    {
+      I32 hv_number;
+      I32 i;
+
+      HV *pre_class_types_hv = (HV *)SvRV (*pre_class_types_sv);
+
+      hv_number = hv_iterinit (pre_class_types_hv);
+
+      for (i = 0; i < hv_number; i++)
+        {
+          int j;
+          I32 retlen;
+          char *type_name;
+          SV *pre_class_sv = hv_iternextsv (pre_class_types_hv,
+                                            &type_name, &retlen);
+          if (SvOK (pre_class_sv))
+            {
+              enum element_type type = ET_NONE;
+              char *pre_class = SvPV_nolen (pre_class_sv);
+          /* this is not very efficient, but should be done only once
+             in the default case.  If this is needed more, a qsort/bfind
+             could be used, but the overhead could probably only be
+             justified if finding the type index happens more often */
+              for (j = 1; j < ET_special_unit_element+1; j++)
+                {
+                  if (!strcmp (element_type_names[j], type_name))
+                    {
+                      type = j;
+                      break;
+                    }
+                }
+              if (type == ET_NONE)
+                {
+                  fprintf (stderr, "ERROR: %s: pre class type not found\n",
+                           type_name);
+                }
+              else
+                converter->pre_class_types[type] = strdup (pre_class);
+            }
+        }
+    }
+
+
+
   FETCH(no_arg_commands_formatting)
 
   if (no_arg_commands_formatting_sv)
diff --git a/tp/Texinfo/XS/main/translations.h 
b/tp/Texinfo/XS/main/translations.h
index 8d0d445477..bbb45f1dab 100644
--- a/tp/Texinfo/XS/main/translations.h
+++ b/tp/Texinfo/XS/main/translations.h
@@ -35,10 +35,10 @@ char *gdt_string (char *string, OPTIONS *options,
                   NAMED_STRING_ELEMENT_LIST *replaced_substrings,
                   const char *translation_context, char *in_lang);
 
-ELEMENT * pgdt_tree (const char *translation_context, char *string,
-                     DOCUMENT *document, OPTIONS *options,
-                     NAMED_STRING_ELEMENT_LIST *replaced_substrings,
-                     char *in_lang);
+ELEMENT *pgdt_tree (const char *translation_context, char *string,
+                    DOCUMENT *document, OPTIONS *options,
+                    NAMED_STRING_ELEMENT_LIST *replaced_substrings,
+                    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/tree_perl_api.h 
b/tp/Texinfo/XS/main/tree_perl_api.h
index 1c1bb0ed70..4e6bf3e878 100644
--- a/tp/Texinfo/XS/main/tree_perl_api.h
+++ b/tp/Texinfo/XS/main/tree_perl_api.h
@@ -29,4 +29,9 @@ FILE_NAME_PATH *call_file_id_setting_unit_file_name 
(CONVERTER *self,
                                                char *filename, char *filepath);
 char *call_formatting_function_format_title_titlepage (CONVERTER *self);
 
+char *call_types_conversion (CONVERTER *self, enum element_type type,
+                             ELEMENT *element, char *content);
+char *call_types_open (CONVERTER *self, enum element_type type,
+                       ELEMENT *element);
+
 #endif
diff --git a/tp/Texinfo/XS/main/utils.c b/tp/Texinfo/XS/main/utils.c
index b91c156386..e50c5cf498 100644
--- a/tp/Texinfo/XS/main/utils.c
+++ b/tp/Texinfo/XS/main/utils.c
@@ -56,6 +56,13 @@ const char *direction_names[] = {"next", "prev", "up"};
 const char *direction_texts[] = {"Next", "Prev", "Up"};
 const size_t directions_length = sizeof (direction_names) / sizeof 
(direction_names[0]);
 
+const enum command_id small_block_associated_command[][2] = {
+  #define smbc_command_name(name) {CM_small##name, CM_##name},
+   SMALL_BLOC_COMMANDS_LIST
+  #undef smbc_command_name
+   {0, 0},
+};
+
 /* to keep synchronized with enum output_unit_type in tree_types.h */
 const char *output_unit_type_names[] = {"unit",
                                         "external_node_unit",
diff --git a/tp/Texinfo/XS/main/utils.h b/tp/Texinfo/XS/main/utils.h
index d0510e48e8..730598f22e 100644
--- a/tp/Texinfo/XS/main/utils.h
+++ b/tp/Texinfo/XS/main/utils.h
@@ -24,6 +24,7 @@
 #include "global_commands_types.h"
 #include "tree_types.h"
 #include "command_ids.h"
+#include "command_stack.h"
 #include "builtin_commands.h"
 
 extern const char *whitespace_chars;
@@ -125,6 +126,16 @@ typedef struct COMMAND_OPTION_VALUE {
     };
 } COMMAND_OPTION_VALUE;
 
+#define SMALL_BLOC_COMMANDS_LIST \
+    smbc_command_name(example)\
+    smbc_command_name(display) \
+    smbc_command_name(format) \
+    smbc_command_name(lisp) \
+    smbc_command_name(quotation) \
+    smbc_command_name(indentedblock)
+
+extern const enum command_id small_block_associated_command[][2];
+
 /* CONVERTER and associated types needed for set_global_document_command */
 /* see Texinfo::HTML _prepare_output_units_global_targets
 
@@ -363,6 +374,41 @@ typedef struct FORMATTING_REFERENCE {
     enum formatting_reference_status status;
 } FORMATTING_REFERENCE;
 
+typedef struct HTML_FORMATTING_CONTEXT {
+    char *context_name;
+    int preformatted_number;
+    int paragraph_number;
+    int upper_case_ctx;
+    int space_protected;
+    int no_break;
+} HTML_FORMATTING_CONTEXT;
+
+typedef struct HTML_FORMATTING_CONTEXT_STACK {
+    HTML_FORMATTING_CONTEXT *stack;
+    size_t top;   /* One above last pushed context. */
+    size_t space;
+} HTML_FORMATTING_CONTEXT_STACK;
+
+typedef struct HTML_DOCUMENT_CONTEXT {
+    char *context;
+    int string_ctx;
+    int raw_ctx;
+    int verbatim_ctx;
+    int math_ctx;
+    int document_global_context;
+    MONOSPACE_CONTEXT_STACK monospace_context;
+    COMMAND_OR_TYPE_STACK composition_context;
+    COMMAND_STACK block_commands;
+    HTML_FORMATTING_CONTEXT_STACK formatting_context;
+    STRING_STACK preformatted_classes;
+} HTML_DOCUMENT_CONTEXT;
+
+typedef struct HTML_DOCUMENT_CONTEXT_STACK {
+    HTML_DOCUMENT_CONTEXT *stack;
+    size_t top;   /* One above last pushed context. */
+    size_t space;
+} HTML_DOCUMENT_CONTEXT_STACK;
+
 typedef struct CONVERTER {
     int converter_descriptor;
     OPTIONS *conf;
@@ -378,6 +424,8 @@ typedef struct CONVERTER {
   /* output unit files API */
     FILE_NAME_PATH_COUNTER_LIST *output_unit_files;
 
+    int modified_state; /* to determine if perl data should be rebuilt */
+
   /* perl converter. This should be HV *hv,
      but we don't want to include the Perl headers everywhere; */
     void *hv;
@@ -386,8 +434,6 @@ typedef struct CONVERTER {
     char *title_titlepage;
 
   /* HTML specific */
-    ELEMENT *current_root_command;
-    OUTPUT_UNIT *current_output_unit;
     OUTPUT_UNIT **global_units_directions;
     SPECIAL_UNIT_DIRECTION **special_units_direction_name;
     char **special_unit_info[SUI_type_heading+1];
@@ -400,6 +446,8 @@ typedef struct CONVERTER {
     char **directions_strings[TDS_type_rel+1];
     HTML_COMMAND_CONVERSION **html_command_conversion[BUILTIN_CMD_NUMBER];
     COMMAND_ID_LIST *no_arg_formatted_cmd;
+    int code_types[ET_special_unit_element+1];
+    char *pre_class_types[ET_special_unit_element+1];
     FORMATTING_REFERENCE
            formatting_references[FR_format_translate_message_string+1];
     FORMATTING_REFERENCE
@@ -408,6 +456,14 @@ typedef struct CONVERTER {
     FORMATTING_REFERENCE commands_conversion[BUILTIN_CMD_NUMBER];
     FORMATTING_REFERENCE types_open[ET_special_unit_element+1];
     FORMATTING_REFERENCE types_conversion[ET_special_unit_element+1];
+
+    /* state */
+    int document_global_context;
+    ELEMENT *current_root_command;
+    ELEMENT *current_node;
+    OUTPUT_UNIT *current_output_unit;
+    HTML_DOCUMENT_CONTEXT_STACK html_document_context;
+    char *current_filename;
 } CONVERTER;
 
 typedef struct TARGET_FILENAME {
diff --git a/tp/Texinfo/XS/parsetexi/api.c b/tp/Texinfo/XS/parsetexi/api.c
index dddb2aeb4e..6e62d5fef4 100644
--- a/tp/Texinfo/XS/parsetexi/api.c
+++ b/tp/Texinfo/XS/parsetexi/api.c
@@ -43,6 +43,7 @@
 #include "document.h"
 /* for wipe_user_commands */
 #include "commands.h"
+#include "command_stack.h"
 #include "context_stack.h"
 /* for clear_parser_expanded_formats and add_parser_expanded_format */
 #include "handle_commands.h"
diff --git a/tp/Texinfo/XS/parsetexi/close.c b/tp/Texinfo/XS/parsetexi/close.c
index cfad12ec18..35d660117b 100644
--- a/tp/Texinfo/XS/parsetexi/close.c
+++ b/tp/Texinfo/XS/parsetexi/close.c
@@ -30,6 +30,7 @@
 #include "counter.h"
 #include "builtin_commands.h"
 #include "source_marks.h"
+#include "command_stack.h"
 #include "context_stack.h"
 #include "extra.h"
 
diff --git a/tp/Texinfo/XS/parsetexi/context_stack.c 
b/tp/Texinfo/XS/parsetexi/context_stack.c
index a47131a63c..47c617aba2 100644
--- a/tp/Texinfo/XS/parsetexi/context_stack.c
+++ b/tp/Texinfo/XS/parsetexi/context_stack.c
@@ -16,10 +16,13 @@
 #include <config.h>
 #include <stdlib.h>
 
+#include "tree_types.h"
+#include "command_ids.h"
+#include "utils.h"
+#include "commands.h"
 #include "debug.h"
+#include "command_stack.h"
 #include "context_stack.h"
-#include "commands.h"
-#include "utils.h"
 
 static enum context *context_stack;
 static size_t top; /* One above last pushed context. */
@@ -28,49 +31,6 @@ static size_t space;
 /* Kept in sync with context_stack. */
 static COMMAND_STACK command_stack;
 
-/* Generic command stack functions */
-
-void
-reset_command_stack (COMMAND_STACK *stack)
-{
-  stack->top = 0;
-  stack->space = 0;
-  free (stack->stack);
-  stack->stack = 0;
-}
-
-void
-push_command (COMMAND_STACK *stack, enum command_id cmd)
-{
-  if (stack->top >= stack->space)
-    {
-      stack->stack
-        = realloc (stack->stack,
-                   (stack->space += 5) * sizeof (enum command_id));
-    }
-
-  stack->stack[stack->top] = cmd;
-  stack->top++;
-}
-
-enum command_id
-pop_command (COMMAND_STACK *stack)
-{
-  if (stack->top == 0)
-    fatal ("command stack empty");
-
-  return stack->stack[--stack->top];
-}
-
-enum command_id
-top_command (COMMAND_STACK *stack)
-{
-  if (stack->top == 0)
-    fatal ("command stack empty for top");
-
-  return stack->stack[stack->top - 1];
-}
-
 enum command_id
 current_context_command (void)
 {
@@ -85,7 +45,6 @@ current_context_command (void)
     }
   return CM_NONE;
 }
-
 /* Context stacks */
 
 void
diff --git a/tp/Texinfo/XS/parsetexi/context_stack.h 
b/tp/Texinfo/XS/parsetexi/context_stack.h
index 09fcde5ff5..ab8c29b020 100644
--- a/tp/Texinfo/XS/parsetexi/context_stack.h
+++ b/tp/Texinfo/XS/parsetexi/context_stack.h
@@ -19,6 +19,7 @@
 #include <stddef.h>
 
 #include "tree_types.h"
+#include "command_stack.h"
 
 enum context {
    ct_NONE,
@@ -39,6 +40,8 @@ enum context {
    || (c) == ct_rawpreformatted \
    || (c) == ct_inlineraw)
 
+enum command_id current_context_command (void);
+
 void push_context (enum context c, enum command_id cmd);
 enum context pop_context (void);
 enum context current_context (void);
@@ -49,19 +52,6 @@ char *context_name (enum context c);
 
 
 
-typedef struct {
-    enum command_id *stack;
-    size_t top;   /* One above last pushed context. */
-    size_t space;
-} COMMAND_STACK;
-
-void reset_command_stack (COMMAND_STACK *stack);
-void push_command (COMMAND_STACK *stack, enum command_id cmd);
-enum command_id pop_command (COMMAND_STACK *stack);
-enum command_id top_command (COMMAND_STACK *stack);
-enum command_id current_context_command (void);
-
-
 /* Used to check indirect nesting, e.g. @footnote{@emph{@footnote{...}}} */
 typedef struct {
     int footnote;
diff --git a/tp/Texinfo/XS/parsetexi/end_line.c 
b/tp/Texinfo/XS/parsetexi/end_line.c
index 54f5880625..e16a1ebbd5 100644
--- a/tp/Texinfo/XS/parsetexi/end_line.c
+++ b/tp/Texinfo/XS/parsetexi/end_line.c
@@ -41,6 +41,7 @@
 /* add_infoenclose */
 #include "macro.h"
 #include "indices.h"
+#include "command_stack.h"
 #include "context_stack.h"
 #include "builtin_commands.h"
 #include "commands.h"
diff --git a/tp/Texinfo/XS/parsetexi/handle_commands.c 
b/tp/Texinfo/XS/parsetexi/handle_commands.c
index 6c93460087..69f26c6b24 100644
--- a/tp/Texinfo/XS/parsetexi/handle_commands.c
+++ b/tp/Texinfo/XS/parsetexi/handle_commands.c
@@ -28,6 +28,7 @@
 /* for isascii_alnum whitespace_chars read_flag_name item_line_parent */
 #include "utils.h"
 #include "counter.h"
+#include "command_stack.h"
 #include "context_stack.h"
 /* for conf */
 #include "conf.h"
diff --git a/tp/Texinfo/XS/parsetexi/indices.c 
b/tp/Texinfo/XS/parsetexi/indices.c
index 113b69221b..a2478e7f48 100644
--- a/tp/Texinfo/XS/parsetexi/indices.c
+++ b/tp/Texinfo/XS/parsetexi/indices.c
@@ -26,6 +26,7 @@
 /* for xasprintf and other */
 #include "errors.h"
 #include "debug.h"
+#include "command_stack.h"
 #include "context_stack.h"
 #include "builtin_commands.h"
 #include "extra.h"
diff --git a/tp/Texinfo/XS/parsetexi/parser.c b/tp/Texinfo/XS/parsetexi/parser.c
index 46ceec0a9f..ea542f0107 100644
--- a/tp/Texinfo/XS/parsetexi/parser.c
+++ b/tp/Texinfo/XS/parsetexi/parser.c
@@ -42,6 +42,7 @@
 #include "extra.h"
 /* for conf */
 #include "conf.h"
+#include "command_stack.h"
 /* for nesting_context */
 #include "context_stack.h"
 #include "commands.h"
diff --git a/tp/Texinfo/XS/parsetexi/separator.c 
b/tp/Texinfo/XS/parsetexi/separator.c
index 38a554b903..c0f2720991 100644
--- a/tp/Texinfo/XS/parsetexi/separator.c
+++ b/tp/Texinfo/XS/parsetexi/separator.c
@@ -28,6 +28,7 @@
 #include "debug.h"
 #include "debug_parser.h"
 #include "errors.h"
+#include "command_stack.h"
 #include "context_stack.h"
 /* for parse_node_manual */
 #include "manipulate_tree.h"



reply via email to

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