texinfo-commits
[Top][All Lists]
Advanced

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

branch master updated: * tp/Texinfo/Convert/HTML.pm, tp/Texinfo/XS/conve


From: Patrice Dumas
Subject: branch master updated: * tp/Texinfo/Convert/HTML.pm, tp/Texinfo/XS/convert/convert_html.c: move functions around, to group better commands formatting and types formatting.
Date: Thu, 04 Jan 2024 08:56:04 -0500

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

pertusus pushed a commit to branch master
in repository texinfo.

The following commit(s) were added to refs/heads/master by this push:
     new 8f550d8c38 * tp/Texinfo/Convert/HTML.pm, 
tp/Texinfo/XS/convert/convert_html.c: move functions around, to group better 
commands formatting and types formatting.
8f550d8c38 is described below

commit 8f550d8c38a4b378d81302ae0d80414e98eadc24
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Thu Jan 4 14:56:00 2024 +0100

    * tp/Texinfo/Convert/HTML.pm, tp/Texinfo/XS/convert/convert_html.c:
    move functions around, to group better commands formatting and types
    formatting.
---
 ChangeLog                            |    6 +
 tp/Texinfo/Convert/HTML.pm           |  153 +--
 tp/Texinfo/XS/convert/convert_html.c | 2092 +++++++++++++++++-----------------
 3 files changed, 1130 insertions(+), 1121 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 26fdf0ea2d..632b041490 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-01-04  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/Convert/HTML.pm, tp/Texinfo/XS/convert/convert_html.c:
+       move functions around, to group better commands formatting and types
+       formatting.
+
 2024-01-04  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/Convert/HTML.pm (_default_format_button)
diff --git a/tp/Texinfo/Convert/HTML.pm b/tp/Texinfo/Convert/HTML.pm
index db74d2e5d5..376f5bf61f 100644
--- a/tp/Texinfo/Convert/HTML.pm
+++ b/tp/Texinfo/Convert/HTML.pm
@@ -2112,6 +2112,7 @@ sub _XS_set_shared_conversion_state($$$;@)
                                $state_name, @args);
 }
 
+# XS is only used for default conversion states.
 sub set_shared_conversion_state($$$;@)
 {
   my $self = shift;
@@ -7702,82 +7703,6 @@ $default_types_conversion{'table_definition'}
 $default_types_conversion{'inter_item'}
                                   = \&_convert_table_definition_type;
 
-sub _contents_shortcontents_in_title($)
-{
-  my $self = shift;
-
-  my $result = '';
-
-  my $sections_list = $self->get_info('sections_list');
-  if ($sections_list
-      and scalar(@{$sections_list}) > 1
-      and $self->get_conf('CONTENTS_OUTPUT_LOCATION') eq 'after_title') {
-    foreach my $cmdname ('shortcontents', 'contents') {
-      if ($self->get_conf($cmdname)) {
-        my $contents_text = $self->_contents_inline_element($cmdname, undef);
-        if ($contents_text ne '') {
-          $result .= $contents_text . $self->get_conf('DEFAULT_RULE')."\n";
-        }
-      }
-    }
-  }
-  return $result;
-}
-
-# Convert @titlepage.  Falls back to simpletitle.
-sub _default_format_titlepage($)
-{
-  my $self = shift;
-
-  my $titlepage_text;
-  my $global_commands = $self->get_info('global_commands');
-  if ($global_commands->{'titlepage'}) {
-    $titlepage_text = $self->convert_tree({'contents'
-               => $global_commands->{'titlepage'}->{'contents'}},
-                                          'convert titlepage');
-  } else {
-    my $simpletitle_tree = $self->get_info('simpletitle_tree');
-    if ($simpletitle_tree) {
-      my $simpletitle_command_name = 
$self->get_info('simpletitle_command_name');
-      my $title_text = $self->convert_tree_new_formatting_context(
-        $simpletitle_tree, "$simpletitle_command_name simpletitle");
-      $titlepage_text = 
&{$self->formatting_function('format_heading_text')}($self,
-                                  $simpletitle_command_name,
-                          [$simpletitle_command_name], $title_text, 0);
-    }
-  }
-  my $result = '';
-  $result .= $titlepage_text.$self->get_conf('DEFAULT_RULE')."\n"
-    if (defined($titlepage_text));
-  $result .= $self->_contents_shortcontents_in_title();
-  return $result;
-}
-
-sub _default_format_title_titlepage($)
-{
-  my $self = shift;
-
-  if ($self->get_conf('SHOW_TITLE')) {
-    if ($self->get_conf('USE_TITLEPAGE_FOR_TITLE')) {
-      return &{$self->formatting_function('format_titlepage')}($self);
-    } else {
-      my $result = '';
-      my $simpletitle_tree = $self->get_info('simpletitle_tree');
-      if ($simpletitle_tree) {
-        my $simpletitle_command_name = 
$self->get_info('simpletitle_command_name');
-        my $title_text = $self->convert_tree_new_formatting_context(
-         $simpletitle_tree, "$simpletitle_command_name simpletitle");
-        $result .= &{$self->formatting_function('format_heading_text')}($self,
-                       $simpletitle_command_name,
-                       [$simpletitle_command_name], $title_text, 0);
-      }
-      $result .= $self->_contents_shortcontents_in_title();
-      return $result;
-    }
-  }
-  return '';
-}
-
 # Function for converting special output units
 sub _convert_special_unit_type($$$$)
 {
@@ -7896,6 +7821,82 @@ sub _convert_unit_type($$$$)
 
 $default_output_units_conversion{'unit'} = \&_convert_unit_type;
 
+sub _contents_shortcontents_in_title($)
+{
+  my $self = shift;
+
+  my $result = '';
+
+  my $sections_list = $self->get_info('sections_list');
+  if ($sections_list
+      and scalar(@{$sections_list}) > 1
+      and $self->get_conf('CONTENTS_OUTPUT_LOCATION') eq 'after_title') {
+    foreach my $cmdname ('shortcontents', 'contents') {
+      if ($self->get_conf($cmdname)) {
+        my $contents_text = $self->_contents_inline_element($cmdname, undef);
+        if ($contents_text ne '') {
+          $result .= $contents_text . $self->get_conf('DEFAULT_RULE')."\n";
+        }
+      }
+    }
+  }
+  return $result;
+}
+
+# Convert @titlepage.  Falls back to simpletitle.
+sub _default_format_titlepage($)
+{
+  my $self = shift;
+
+  my $titlepage_text;
+  my $global_commands = $self->get_info('global_commands');
+  if ($global_commands->{'titlepage'}) {
+    $titlepage_text = $self->convert_tree({'contents'
+               => $global_commands->{'titlepage'}->{'contents'}},
+                                          'convert titlepage');
+  } else {
+    my $simpletitle_tree = $self->get_info('simpletitle_tree');
+    if ($simpletitle_tree) {
+      my $simpletitle_command_name = 
$self->get_info('simpletitle_command_name');
+      my $title_text = $self->convert_tree_new_formatting_context(
+        $simpletitle_tree, "$simpletitle_command_name simpletitle");
+      $titlepage_text = 
&{$self->formatting_function('format_heading_text')}($self,
+                                  $simpletitle_command_name,
+                          [$simpletitle_command_name], $title_text, 0);
+    }
+  }
+  my $result = '';
+  $result .= $titlepage_text.$self->get_conf('DEFAULT_RULE')."\n"
+    if (defined($titlepage_text));
+  $result .= $self->_contents_shortcontents_in_title();
+  return $result;
+}
+
+sub _default_format_title_titlepage($)
+{
+  my $self = shift;
+
+  if ($self->get_conf('SHOW_TITLE')) {
+    if ($self->get_conf('USE_TITLEPAGE_FOR_TITLE')) {
+      return &{$self->formatting_function('format_titlepage')}($self);
+    } else {
+      my $result = '';
+      my $simpletitle_tree = $self->get_info('simpletitle_tree');
+      if ($simpletitle_tree) {
+        my $simpletitle_command_name = 
$self->get_info('simpletitle_command_name');
+        my $title_text = $self->convert_tree_new_formatting_context(
+         $simpletitle_tree, "$simpletitle_command_name simpletitle");
+        $result .= &{$self->formatting_function('format_heading_text')}($self,
+                       $simpletitle_command_name,
+                       [$simpletitle_command_name], $title_text, 0);
+      }
+      $result .= $self->_contents_shortcontents_in_title();
+      return $result;
+    }
+  }
+  return '';
+}
+
 # for output units, both normal and special
 sub _default_format_element_footer($$$$;$)
 {
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index 1b02a1eb7a..cbc1b6c0e6 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -7677,1004 +7677,596 @@ format_footnotes_segment (CONVERTER *self, TEXT 
*result)
     }
 }
 
-#define static_class(name, class) \
-static char * name ##_array[] = {#class}; \
-static const STRING_LIST name ##_classes = {name ##_array, 1, 1};
-
-static_class(def_type, def-type)
-static_class(def_name, def-name)
-static_class(def_code_arguments, def-code-arguments)
-static_class(def_var_arguments, def-var-arguments)
-static_class(call_def, call-def)
-static_class(category_def, category-def)
-
-void
-convert_def_line_type (CONVERTER *self, const enum element_type type,
-                       const ELEMENT *element, const char *content,
-                       TEXT *result)
+static void
+text_element_conversion (CONVERTER *self,
+                         const HTML_COMMAND_CONVERSION *specification,
+                         const enum command_id cmd,
+                         TEXT *result)
 {
-  char *index_id;
-  PARSED_DEF *parsed_def;
-  STRING_LIST *classes;
-  char *attribute_class;
-  char *alias_class = 0;
-  enum command_id original_def_cmd;
-  enum command_id def_cmd;
-  enum command_id original_cmd = 0;
-  enum command_id base_cmd = 0;
-  TEXT def_call;
-  char *anchor;
-
-  if (html_in_string (self))
+  if (specification->element)
     {
-      /* should probably never happen */
-      char *text;
-      TEXT_OPTIONS *text_conv_options
-         = copy_options_for_convert_text (self, 0);
-      text = convert_to_text (element, text_conv_options);
-      free (text_conv_options);
-      format_protect_text (self, text, result);
-    }
+      STRING_LIST *classes;
+      char *attribute_class;
+      classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+      memset (classes, 0, sizeof (STRING_LIST));
+      add_string (builtin_command_name (cmd), classes);
 
-  index_id = html_command_id (self, element);
+      attribute_class
+       = html_attribute_class (self, specification->element, classes);
+      destroy_strings_list (classes);
+      text_append (result, attribute_class);
+      free (attribute_class);
 
-  parsed_def = definition_arguments_content (element);
+      text_append_n (result, ">", 1);
+      if (specification->text)
+        text_append (result, specification->text);
+      text_append_n (result, "</", 2);
+      text_append (result, specification->element);
+      text_append_n (result, ">", 1);
+    }
+  else if (specification->text)
+    text_append (result, specification->text);
+}
 
-  if (element->cmd)
-    original_def_cmd = element->cmd;
+void
+convert_no_arg_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
+{
+  enum command_id formatted_cmd = cmd;
+  enum conversion_context context;
+  HTML_COMMAND_CONVERSION *specification;
+
+  if (html_in_preformatted_context (self) || html_in_math (self))
+    context = HCC_type_preformatted;
+  else if (html_in_string (self))
+    context = HCC_type_string;
   else
-    original_def_cmd = element->parent->cmd;
+    context = HCC_type_normal;
 
-  if (builtin_command_data[original_def_cmd].flags & CF_def_alias)
+  if (cmd == CM_click)
     {
-      int i;
-      for (i = 0; def_aliases[i].alias ; i++)
+      enum command_id click_cmd = 0;
+      char *click_cmdname = lookup_extra_string (element, "clickstyle");
+      if (click_cmdname)
         {
-          if (def_aliases[i].alias == original_def_cmd)
+          click_cmd = lookup_builtin_command (click_cmdname);
+        }
+      if (click_cmd)
+        {
+          HTML_COMMAND_CONVERSION *conv_context
+            = self->html_command_conversion[click_cmd];
+          if (conv_context[context].text || conv_context[context].element)
             {
-              original_cmd = def_aliases[i].command;
-              break;
+              formatted_cmd = click_cmd;
             }
         }
-
-      xasprintf (&alias_class, "%s-alias-%s",
-                    builtin_command_name(original_def_cmd),
-                    builtin_command_name(original_cmd));
     }
-  else
-    original_cmd = original_def_cmd;
-
-  /* parent is defblock, we do not put it in class */
-  if (element->cmd == CM_defline || element->cmd == CM_deftypeline)
-    def_cmd = element->cmd;
-  else
-  /* the parent is the def both for def* def_line and def*x */
-    def_cmd = element->parent->cmd;
 
-  if (builtin_command_data[def_cmd].flags & CF_def_alias)
+  if (html_in_upper_case (self)
+      && (builtin_command_data[formatted_cmd].other_flags & CF_letter_no_arg))
     {
-      int i;
-      for (i = 0; def_aliases[i].alias ; i++)
+      const char *command = builtin_command_name (formatted_cmd);
+      char *upper_case_command = strdup (command);
+      char *p;
+      enum command_id upper_case_cmd;
+      for (p = upper_case_command; *p; p++)
         {
-          if (def_aliases[i].alias == def_cmd)
-            {
-              base_cmd = def_aliases[i].command;
-              break;
-            }
+          *p = toupper (*p);
+        }
+      /* TODO the mapping could be done once for all */
+      upper_case_cmd = lookup_builtin_command (upper_case_command);
+      if (upper_case_cmd)
+        {
+          HTML_COMMAND_CONVERSION *conv_context
+            = self->html_command_conversion[upper_case_cmd];
+          if (conv_context[context].text || conv_context[context].element)
+            formatted_cmd = upper_case_cmd;
         }
+      free (upper_case_command);
     }
-  else
-    base_cmd = def_cmd;
 
-  classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
-  memset (classes, 0, sizeof (STRING_LIST));
+  specification
+    = &self->html_command_conversion[formatted_cmd][context];
 
-  add_string (builtin_command_name(original_cmd), classes);
-  if (alias_class)
-    {
-      add_string (alias_class, classes);
-      free (alias_class);
-    }
-  if (base_cmd != original_cmd)
+  text_element_conversion (self, specification, formatted_cmd, result);
+}
+
+void
+css_string_convert_no_arg_command (CONVERTER *self,
+                    const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
+{
+  enum command_id formatted_cmd = cmd;
+  if (cmd == CM_click)
     {
-      char *class;
-      xasprintf (&class, "def-cmd-%s", builtin_command_name(base_cmd));
-      add_string (class, classes);
-      free (class);
+      enum command_id click_cmd = 0;
+      char *click_cmdname = lookup_extra_string (element, "clickstyle");
+      if (click_cmdname)
+        {
+          click_cmd = lookup_builtin_command (click_cmdname);
+        }
+      if (click_cmd)
+        {
+          formatted_cmd = click_cmd;
+        }
     }
 
-  text_init (&def_call);
-  text_append (&def_call, "");
-  if (parsed_def->type)
+  if (html_in_upper_case (self)
+      && (builtin_command_data[formatted_cmd].other_flags & CF_letter_no_arg))
     {
-      char *type_text;
-      size_t type_text_len;
-      ELEMENT *root_code = new_element (ET__code);
-
-      add_to_contents_as_array (root_code, parsed_def->type);
-
-      add_to_element_list (&self->tree_to_build, root_code);
-
-      type_text = html_convert_tree (self, root_code, 0);
-
-      remove_element_from_list (&self->tree_to_build, root_code);
-
-      destroy_element (root_code);
-      type_text_len = strlen (type_text);
-
-      if (type_text_len > 0)
+      const char *command = builtin_command_name (formatted_cmd);
+      char *upper_case_command = strdup (command);
+      char *p;
+      enum command_id upper_case_cmd;
+      for (p = upper_case_command; *p; p++)
         {
-          char *attribute_class = html_attribute_class (self, "code",
-                                                        &def_type_classes);
-          text_append (&def_call, attribute_class);
-          free (attribute_class);
-          text_append_n (&def_call, ">", 1);
-          text_append_n (&def_call, type_text, type_text_len);
-          text_append_n (&def_call, "</code>", 7);
+          *p = toupper (*p);
         }
-      if ((base_cmd == CM_deftypefn || base_cmd == CM_deftypeop)
-          && !strcmp (self->conf->deftypefnnewline.string, "on"))
+      /* TODO the mapping could be done once for all */
+      upper_case_cmd = lookup_builtin_command (upper_case_command);
+      free (upper_case_command);
+      if (upper_case_cmd)
         {
-          text_append_n (&def_call, self->line_break_element.string,
-                                    self->line_break_element.len);
-          text_append_n (&def_call, " ", 1);
+          HTML_COMMAND_CONVERSION *conv_context
+            = self->html_command_conversion[upper_case_cmd];
+          if (conv_context[HCC_type_css_string].text)
+            formatted_cmd = upper_case_cmd;
         }
-      else if (type_text_len > 0)
-        text_append_n (&def_call, " ", 1);
-      free (type_text);
     }
 
-  if (parsed_def->name)
-    {
-      char *attribute_class = html_attribute_class (self, "strong",
-                                                    &def_name_classes);
-      ELEMENT *root_code = new_element (ET__code);
+  text_append (result,
+    self->html_command_conversion[formatted_cmd][HCC_type_css_string].text);
+}
 
-      add_to_contents_as_array (root_code, parsed_def->name);
+void
+convert_today_command (CONVERTER *self, const enum command_id cmd,
+                       const ELEMENT *element,
+                       const HTML_ARGS_FORMATTED *args_formatted,
+                       const char *content, TEXT *result)
+{
+  ELEMENT *today_element = expand_today (self->conf);
 
-      add_to_element_list (&self->tree_to_build, root_code);
+  add_to_element_list (&self->tree_to_build, today_element);
 
-      text_append (&def_call, attribute_class);
-      free (attribute_class);
-      text_append_n (&def_call, ">", 1);
+  convert_to_html_internal (self, today_element, result, "convert today");
 
-      convert_to_html_internal (self, root_code, &def_call, 0);
+  remove_element_from_list (&self->tree_to_build, today_element);
+  destroy_element_and_children (today_element);
+}
 
-      remove_element_from_list (&self->tree_to_build, root_code);
-      destroy_element (root_code);
+void
+convert_style_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
+{
+  enum command_id style_cmd = cmd;
+  HTML_COMMAND_CONVERSION *formatting_spec;
 
-      text_append_n (&def_call, "</strong>", 9);
-    }
+  /* happens with bogus @-commands without argument, like @strong something */
+  if (!args_formatted || args_formatted->number <= 0
+      || !args_formatted->args[0].formatted[AFT_type_normal])
+    return;
 
-  if (parsed_def->args)
+  if (html_in_string (self))
     {
-      char *args_formatted;
-   /* arguments not only metasyntactic variables
-      (deftypefn, deftypevr, deftypeop, deftypecv) */
-      /* Texinfo::Common::def_no_var_arg_commands{$base_command_name} */
-      if (strlen (builtin_command_name(base_cmd)) >= 7
-          && !memcmp (builtin_command_name(base_cmd), "deftype", 7))
-        {
-          ELEMENT *root_code = new_element (ET__code);
-
-          add_to_contents_as_array (root_code, parsed_def->args);
+      text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
+      return;
+    }
 
-          add_to_element_list (&self->tree_to_build, root_code);
+  if (cmd == CM_kbd)
+    {
+      int status;
+      int code = lookup_extra_integer (element, "code", &status);
+      if (code > 0)
+        style_cmd = CM_code;
+    }
 
-          args_formatted = html_convert_tree (self, root_code, 0);
+  if (html_in_preformatted_context (self))
+    formatting_spec
+      = &self->html_command_conversion[style_cmd][HCC_type_preformatted];
+  else
+    formatting_spec
+      = &self->html_command_conversion[style_cmd][HCC_type_normal];
 
-          remove_element_from_list (&self->tree_to_build, root_code);
-          destroy_element (root_code);
+  if (formatting_spec->element)
+    {
+      STRING_LIST *classes;
+      char *open;
+      size_t open_len;
+      classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+      memset (classes, 0, sizeof (STRING_LIST));
+      add_string (builtin_command_name (style_cmd), classes);
 
-          if (args_formatted[strspn (args_formatted, whitespace_chars)] != 
'\0')
-            {
-              char *attribute_class = html_attribute_class (self, "code",
-                                              &def_code_arguments_classes);
-              int status;
-              int omit_def_name_space = lookup_extra_integer (element,
-                                              "omit_def_name_space", &status);
-              if (omit_def_name_space <= 0)
-                text_append_n (&def_call, " ", 1);
-              text_append (&def_call, attribute_class);
-              free (attribute_class);
-              text_append_n (&def_call, ">", 1);
-              text_append (&def_call, args_formatted);
-              text_append_n (&def_call, "</code>", 7);
-            }
-        }
-      else
+      if (style_cmd != cmd)
         {
-          html_set_code_context (self, 0);
-          args_formatted = html_convert_tree (self, parsed_def->args, 0);
-          html_pop_code_context (self);
-          if (args_formatted[strspn (args_formatted, whitespace_chars)] != 
'\0')
-            {
-              char *attribute_class = html_attribute_class (self, "var",
-                                              &def_var_arguments_classes);
-              int status;
-              int omit_def_name_space = lookup_extra_integer (element,
-                                              "omit_def_name_space", &status);
-              if (omit_def_name_space <= 0)
-                text_append_n (&def_call, " ", 1);
-              text_append (&def_call, attribute_class);
-              free (attribute_class);
-              text_append_n (&def_call, ">", 1);
-              text_append (&def_call, args_formatted);
-              text_append_n (&def_call, "</var>", 6);
-            }
+          char *style_as_cmd;
+          xasprintf (&style_as_cmd, "as-%s-%s",
+                     builtin_command_name (style_cmd),
+                     builtin_command_name (cmd));
+          add_string (style_as_cmd, classes);
+          free (style_as_cmd);
         }
-      free (args_formatted);
-    }
 
-  if (self->conf->DEF_TABLE.integer > 0)
-    {
-      ELEMENT *category_tree
-         = definition_category_tree (self->conf, element);
+      if (formatting_spec->quote)
+        text_append (result, self->conf->OPEN_QUOTE_SYMBOL.string);
 
-      attribute_class = html_attribute_class (self, "tr", classes);
+      open
+        = html_attribute_class (self, formatting_spec->element, classes);
+      open_len = strlen (open);
       destroy_strings_list (classes);
-      text_append (result, attribute_class);
-      free (attribute_class);
-      if (index_id && strlen (index_id) && !html_in_multi_expanded (self))
-        text_printf (result, " id=\"%s\"", index_id);
-      text_append_n (result, ">", 1);
-
-      attribute_class = html_attribute_class (self, "td",
-                                               &call_def_classes);
-      text_append (result, attribute_class);
-      free (attribute_class);
-      text_append_n (result, ">", 1);
-      text_append_n (result, def_call.text, def_call.end);
-      free (def_call.text);
-      text_append_n (result, "</td>", 5);
-
-      attribute_class = html_attribute_class (self, "td",
-                                              &category_def_classes);
-      text_append (result, attribute_class);
-      free (attribute_class);
-      text_append_n (result, ">[", 2);
 
-      if (category_tree)
+      if (open_len > 0)
         {
-          add_to_element_list (&self->tree_to_build, category_tree);
-          convert_to_html_internal (self, category_tree, result, 0);
-          remove_element_from_list (&self->tree_to_build, category_tree);
-          destroy_element_and_children (category_tree);
+          text_append (result, open);
+          text_append_n (result, ">", 1);
+          free (open);
         }
-      text_append_n (result, "]</td></tr>\n", 12);
-      return;
-    }
-
-  attribute_class = html_attribute_class (self, "dt", classes);
-  destroy_strings_list (classes);
-  text_append (result, attribute_class);
-  free (attribute_class);
-  if (index_id && strlen (index_id) && !html_in_multi_expanded (self))
-    text_printf (result, " id=\"%s\"", index_id);
-  text_append_n (result, ">", 1);
-
-  if (parsed_def->category)
-    {
-      ELEMENT *category_tree = 0;
-      NAMED_STRING_ELEMENT_LIST *substrings
-                                   = new_named_string_element_list ();
-      ELEMENT *category_copy = copy_tree (parsed_def->category);
 
-      add_element_to_named_string_element_list (substrings,
-                                            "category", category_copy);
-      if (parsed_def->class)
-        {
-          ELEMENT *class_copy = copy_tree (parsed_def->class);
-          add_element_to_named_string_element_list (substrings,
-                                            "class", class_copy);
+      text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
 
-          if (base_cmd == CM_deftypeop && parsed_def->type
-              && !strcmp (self->conf->deftypefnnewline.string, "on"))
-            {
-               category_tree
-                  = html_gdt_tree ("{category} on @code{{class}}:@* ",
-                                   self->document, self, substrings, 0, 0);
-            }
-          else if (base_cmd == CM_defop || base_cmd == CM_deftypeop)
-            {
-               category_tree
-                  = html_gdt_tree ("{category} on @code{{class}}: ",
-                                   self->document, self, substrings, 0, 0);
-            }
-          else if (base_cmd == CM_defcv || base_cmd == CM_deftypecv)
-            {
-               category_tree
-                  = html_gdt_tree ("{category} of @code{{class}}: ",
-                                   self->document, self, substrings, 0, 0);
-            }
-        }
-      else
+      if (open_len > 0)
         {
-          if ((base_cmd == CM_deftypefn || base_cmd == CM_deftypeop)
-              && parsed_def->type
-              && !strcmp (self->conf->deftypefnnewline.string, "on"))
-            {
-              category_tree
-                  = html_gdt_tree ("{category}:@* ",
-                                   self->document, self, substrings, 0, 0);
-            }
-          else
-            {
-              category_tree
-                  = html_gdt_tree ("{category}: ",
-                                   self->document, self, substrings, 0, 0);
-            }
+          text_append_n (result, "</", 2);
+          text_append (result, formatting_spec->element);
+          text_append_n (result, ">", 1);
         }
-      destroy_named_string_element_list (substrings);
 
-      if (category_tree)
-        {
-          char *attribute_open = html_attribute_class (self, "span",
-                                             &category_def_classes);
-          size_t open_len = strlen (attribute_open);
-          if (open_len)
-            {
-              text_append_n (result, attribute_open, open_len);
-              text_append_n (result, ">", 1);
-            }
-          free (attribute_open);
-          add_to_element_list (&self->tree_to_build, category_tree);
-          convert_to_html_internal (self, category_tree, result, 0);
-          remove_element_from_list (&self->tree_to_build, category_tree);
-          destroy_element_and_children (category_tree);
-          if (open_len)
-            text_append_n (result, "</span>", 7);
-        }
+      if (formatting_spec->quote)
+        text_append (result, self->conf->CLOSE_QUOTE_SYMBOL.string);
     }
+  else
+    text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
+}
 
-  destroy_parsed_def (parsed_def);
-
-  anchor = get_copiable_anchor (self, index_id);
-
-  if (anchor)
-    text_append_n (result, "<span>", 6);
-
-  text_append_n (result, def_call.text, def_call.end);
-  free (def_call.text);
-  if (anchor)
+void
+convert_w_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
+{
+  if (args_formatted && args_formatted->number > 0)
     {
-      text_append (result, anchor);
-      text_append_n (result, "</span>", 7);
+      if (args_formatted->args[0].formatted[AFT_type_normal])
+        text_append (result,
+                     args_formatted->args[0].formatted[AFT_type_normal]);
+    }
+  if (!html_in_string (self))
+    {
+      text_append (result, "<!-- /@w -->");
     }
-
-  text_append_n (result, "</dt>\n", 6);
-
-  free (anchor);
 }
 
 void
-convert_table_term_type (CONVERTER *self, const enum element_type type,
-                        const ELEMENT *element, const char *content,
-                        TEXT *result)
+convert_value_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
 {
-  if (content)
-    {
-      text_append (result, "<dt>");
-      text_append (result, content);
-    }
+  ELEMENT *tree;
+  ELEMENT *value_text = new_element (ET_NONE);
+  NAMED_STRING_ELEMENT_LIST *substrings = new_named_string_element_list ();
+
+  text_append (&value_text->text,
+               args_formatted->args[0].formatted[AFT_type_monospacestring]);
+  add_element_to_named_string_element_list (substrings,
+                                            "value", value_text);
+
+  tree = html_gdt_tree ("@{No value for `{value}'@}", self->document,
+                        self, substrings, 0, 0);
+
+  add_to_element_list (&self->tree_to_build, tree);
+  convert_to_html_internal (self, tree, result, 0);
+  remove_element_from_list (&self->tree_to_build, tree);
+
+  destroy_element_and_children (tree);
+
+  destroy_named_string_element_list (substrings);
 }
 
 void
-convert_row_type (CONVERTER *self, const enum element_type type,
-                  const ELEMENT *element, const char *content,
-                  TEXT *result)
+convert_email_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
 {
-  if (html_in_string (self))
+  char *mail = 0;
+  char *mail_string = 0;
+  char *text = 0;
+
+  if (args_formatted->number > 0)
     {
-      if (content)
-        text_append (result, content);
+      mail = args_formatted->args[0].formatted[AFT_type_url];
+      mail_string
+       = args_formatted->args[0].formatted[AFT_type_monospacestring];
     }
 
-  if (!content || content[strspn (content, whitespace_chars)] == '\0')
-    return;
-  else
+  if (args_formatted->number > 1
+      && args_formatted->args[1].formatted[AFT_type_normal])
     {
-      text_append (result, "<tr>");
-      text_append (result, content);
-      text_append (result, "</tr>");
+      text = args_formatted->args[1].formatted[AFT_type_normal];
+    }
 
-      if (element->contents.number > 0
-          && element->contents.list[0]->cmd != CM_headitem)
-      /* if headitem, end of line added in _convert_multitable_head_type */
-        text_append (result, "\n");
+  if (!text || !strlen (text))
+    {
+      text = mail_string;
     }
-}
 
-static void
-text_element_conversion (CONVERTER *self,
-                         const HTML_COMMAND_CONVERSION *specification,
-                         const enum command_id cmd,
-                         TEXT *result)
-{
-  if (specification->element)
+  /* FIXME match unicode spaces in perl */
+  if (!mail || mail[strspn (mail, whitespace_chars)] == '\0')
+    {
+      if (text)
+        text_append (result, text);
+      return;
+    }
+
+  if (html_in_string (self))
+    {
+      text_printf (result, "%s (%s)", mail_string, text);
+    }
+  else
     {
-      STRING_LIST *classes;
       char *attribute_class;
+      char *protected_mailto;
+      char *mailto;
+      STRING_LIST *classes;
       classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
       memset (classes, 0, sizeof (STRING_LIST));
       add_string (builtin_command_name (cmd), classes);
 
-      attribute_class
-       = html_attribute_class (self, specification->element, classes);
+      attribute_class = html_attribute_class (self, "a", classes);
       destroy_strings_list (classes);
       text_append (result, attribute_class);
       free (attribute_class);
 
-      text_append_n (result, ">", 1);
-      if (specification->text)
-        text_append (result, specification->text);
-      text_append_n (result, "</", 2);
-      text_append (result, specification->element);
-      text_append_n (result, ">", 1);
+      xasprintf (&mailto, "mailto:%s";, mail);
+      protected_mailto = url_protect_url_text (self, mailto);
+      free (mailto);
+
+      text_printf (result, " href=\"%s\">%s</a>", protected_mailto, text);
+      free (protected_mailto);
     }
-  else if (specification->text)
-    text_append (result, specification->text);
 }
 
-void
-convert_no_arg_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
+EXPLAINED_COMMAND_TYPE *
+find_explained_command_string (EXPLAINED_COMMAND_TYPE_LIST *type_explanations,
+                               const enum command_id cmd, const char *type)
 {
-  enum command_id formatted_cmd = cmd;
-  enum conversion_context context;
-  HTML_COMMAND_CONVERSION *specification;
-
-  if (html_in_preformatted_context (self) || html_in_math (self))
-    context = HCC_type_preformatted;
-  else if (html_in_string (self))
-    context = HCC_type_string;
-  else
-    context = HCC_type_normal;
-
-  if (cmd == CM_click)
+  size_t i;
+  for (i = 0; i < type_explanations->number; i++)
     {
-      enum command_id click_cmd = 0;
-      char *click_cmdname = lookup_extra_string (element, "clickstyle");
-      if (click_cmdname)
-        {
-          click_cmd = lookup_builtin_command (click_cmdname);
-        }
-      if (click_cmd)
-        {
-          HTML_COMMAND_CONVERSION *conv_context
-            = self->html_command_conversion[click_cmd];
-          if (conv_context[context].text || conv_context[context].element)
-            {
-              formatted_cmd = click_cmd;
-            }
-        }
+      EXPLAINED_COMMAND_TYPE *type_explanation = &type_explanations->list[i];
+      if (type_explanation->cmd == cmd
+          && !strcmp (type_explanation->type, type))
+        return type_explanation;
     }
+  return 0;
+}
 
-  if (html_in_upper_case (self)
-      && (builtin_command_data[formatted_cmd].other_flags & CF_letter_no_arg))
+void
+register_explained_command_string (
+               EXPLAINED_COMMAND_TYPE_LIST *type_explanations,
+                    const enum command_id cmd,
+                    const char *type, const char *explanation)
+{
+  EXPLAINED_COMMAND_TYPE *type_explanation
+    = find_explained_command_string (type_explanations, cmd, type);
+  if (!type_explanation)
     {
-      const char *command = builtin_command_name (formatted_cmd);
-      char *upper_case_command = strdup (command);
-      char *p;
-      enum command_id upper_case_cmd;
-      for (p = upper_case_command; *p; p++)
-        {
-          *p = toupper (*p);
-        }
-      /* TODO the mapping could be done once for all */
-      upper_case_cmd = lookup_builtin_command (upper_case_command);
-      if (upper_case_cmd)
+      if (type_explanations->number == type_explanations->space)
         {
-          HTML_COMMAND_CONVERSION *conv_context
-            = self->html_command_conversion[upper_case_cmd];
-          if (conv_context[context].text || conv_context[context].element)
-            formatted_cmd = upper_case_cmd;
+          type_explanations->list
+           = realloc (type_explanations->list,
+            sizeof (EXPLAINED_COMMAND_TYPE) * (type_explanations->space += 5));
         }
-      free (upper_case_command);
-    }
+      type_explanation = &type_explanations->list[type_explanations->number];
+      type_explanation->cmd = cmd;
+      type_explanation->type = strdup (type);
 
-  specification
-    = &self->html_command_conversion[formatted_cmd][context];
+      type_explanations->number++;
+    }
+  else
+    free (type_explanation->explanation);
 
-  text_element_conversion (self, specification, formatted_cmd, result);
+  type_explanation->explanation = strdup (explanation);
 }
 
 void
-css_string_convert_no_arg_command (CONVERTER *self,
-                    const enum command_id cmd,
+convert_explained_command (CONVERTER *self, const enum command_id cmd,
                     const ELEMENT *element,
                     const HTML_ARGS_FORMATTED *args_formatted,
                     const char *content, TEXT *result)
 {
-  enum command_id formatted_cmd = cmd;
-  if (cmd == CM_click)
+  TEXT explained_string;
+  TEXT *text_result;
+  char *explained_arg = 0;
+  char *normalized_type = 0;
+  char *explanation_string = 0;
+  char *explanation_result = 0;
+  EXPLAINED_COMMAND_TYPE_LIST *type_explanations
+    = &self->shared_conversion_state.explained_commands;
+
+  if (element->args.number > 0
+      && element->args.list[0]->contents.number > 0)
     {
-      enum command_id click_cmd = 0;
-      char *click_cmdname = lookup_extra_string (element, "clickstyle");
-      if (click_cmdname)
-        {
-          click_cmd = lookup_builtin_command (click_cmdname);
-        }
-      if (click_cmd)
-        {
-          formatted_cmd = click_cmd;
-        }
+      normalized_type = convert_to_identifier (element->args.list[0]);
     }
+  else
+    normalized_type = strdup ("");
 
-  if (html_in_upper_case (self)
-      && (builtin_command_data[formatted_cmd].other_flags & CF_letter_no_arg))
+  if (args_formatted && args_formatted->number > 1)
     {
-      const char *command = builtin_command_name (formatted_cmd);
-      char *upper_case_command = strdup (command);
-      char *p;
-      enum command_id upper_case_cmd;
-      for (p = upper_case_command; *p; p++)
-        {
-          *p = toupper (*p);
-        }
-      /* TODO the mapping could be done once for all */
-      upper_case_cmd = lookup_builtin_command (upper_case_command);
-      free (upper_case_command);
-      if (upper_case_cmd)
+      if (args_formatted->args[1].formatted[AFT_type_string])
         {
-          HTML_COMMAND_CONVERSION *conv_context
-            = self->html_command_conversion[upper_case_cmd];
-          if (conv_context[HCC_type_css_string].text)
-            formatted_cmd = upper_case_cmd;
-        }
-    }
-
-  text_append (result,
-    self->html_command_conversion[formatted_cmd][HCC_type_css_string].text);
-}
+          explanation_string
+            = args_formatted->args[1].formatted[AFT_type_string];
 
-void
-convert_today_command (CONVERTER *self, const enum command_id cmd,
-                       const ELEMENT *element,
-                       const HTML_ARGS_FORMATTED *args_formatted,
-                       const char *content, TEXT *result)
-{
-  ELEMENT *today_element = expand_today (self->conf);
-
-  add_to_element_list (&self->tree_to_build, today_element);
-
-  convert_to_html_internal (self, today_element, result, "convert today");
-
-  remove_element_from_list (&self->tree_to_build, today_element);
-  destroy_element_and_children (today_element);
-}
-
-void
-convert_style_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
-{
-  enum command_id style_cmd = cmd;
-  HTML_COMMAND_CONVERSION *formatting_spec;
-
-  /* happens with bogus @-commands without argument, like @strong something */
-  if (!args_formatted || args_formatted->number <= 0
-      || !args_formatted->args[0].formatted[AFT_type_normal])
-    return;
+          if (explanation_string[strspn
+                     (explanation_string, whitespace_chars)] != '\0')
+            {
+              register_explained_command_string (type_explanations,
+                           cmd, normalized_type, explanation_string);
+            }
+          else
+            explanation_string = 0;
+       }
+     if (args_formatted->args[1].formatted[AFT_type_normal])
+       explanation_result = args_formatted->args[1].formatted[AFT_type_normal];
+    }
 
-  if (html_in_string (self))
+  if (!explanation_string)
     {
-      text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
-      return;
+      EXPLAINED_COMMAND_TYPE *type_explanation
+          = find_explained_command_string (type_explanations,
+                                                     cmd, normalized_type);
+      if (type_explanation)
+        explanation_string = type_explanation->explanation;
     }
 
-  if (cmd == CM_kbd)
+  free (normalized_type);
+
+  if (explanation_result)
     {
-      int status;
-      int code = lookup_extra_integer (element, "code", &status);
-      if (code > 0)
-        style_cmd = CM_code;
+      text_init (&explained_string);
+      text_result = &explained_string;
     }
+  else
+    text_result = result;
 
-  if (html_in_preformatted_context (self))
-    formatting_spec
-      = &self->html_command_conversion[style_cmd][HCC_type_preformatted];
+  if (args_formatted->number > 0 &&
+      args_formatted->args[0].formatted[AFT_type_normal])
+    explained_arg = args_formatted->args[0].formatted[AFT_type_normal];
   else
-    formatting_spec
-      = &self->html_command_conversion[style_cmd][HCC_type_normal];
+    explained_arg = "";
 
-  if (formatting_spec->element)
+  if (!html_in_string (self))
     {
+      char *attribute_class;
       STRING_LIST *classes;
-      char *open;
-      size_t open_len;
       classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
       memset (classes, 0, sizeof (STRING_LIST));
-      add_string (builtin_command_name (style_cmd), classes);
-
-      if (style_cmd != cmd)
-        {
-          char *style_as_cmd;
-          xasprintf (&style_as_cmd, "as-%s-%s",
-                     builtin_command_name (style_cmd),
-                     builtin_command_name (cmd));
-          add_string (style_as_cmd, classes);
-          free (style_as_cmd);
-        }
-
-      if (formatting_spec->quote)
-        text_append (result, self->conf->OPEN_QUOTE_SYMBOL.string);
+      add_string (builtin_command_name (cmd), classes);
 
-      open
-        = html_attribute_class (self, formatting_spec->element, classes);
-      open_len = strlen (open);
+      attribute_class = html_attribute_class (self, "abbr", classes);
       destroy_strings_list (classes);
+      text_append (text_result, attribute_class);
+      free (attribute_class);
 
-      if (open_len > 0)
-        {
-          text_append (result, open);
-          text_append_n (result, ">", 1);
-          free (open);
-        }
+      if (explanation_string)
+        text_printf (text_result, " title=\"%s\"", explanation_string);
+      text_append_n (text_result, ">", 1);
+      text_append (text_result, explained_arg);
+      text_append_n (text_result, "</abbr>", 7);
+    }
+  else
+    text_append (text_result, explained_arg);
 
-      text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
+  if (explanation_result)
+    {
+      char *context_str;
+      NAMED_STRING_ELEMENT_LIST *substrings
+                                       = new_named_string_element_list ();
+      ELEMENT *explained_string_element = new_element (ET__converted);
+      ELEMENT *explanation_result_element = new_element (ET__converted);
+      ELEMENT *tree;
 
-      if (open_len > 0)
-        {
-          text_append_n (result, "</", 2);
-          text_append (result, formatting_spec->element);
-          text_append_n (result, ">", 1);
-        }
+      text_append (&explained_string_element->text, text_result->text);
+      free (text_result->text);
+      text_append (&explanation_result_element->text, explanation_result);
 
-      if (formatting_spec->quote)
-        text_append (result, self->conf->CLOSE_QUOTE_SYMBOL.string);
+      add_element_to_named_string_element_list (substrings,
+                          "explained_string", explained_string_element);
+      add_element_to_named_string_element_list (substrings,
+                          "explanation", explanation_result_element);
+      tree = html_gdt_tree ("{explained_string} ({explanation})",
+                             self->document, self, substrings, 0, 0);
+      destroy_named_string_element_list (substrings);
+
+      xasprintf (&context_str, "convert explained  %s",
+                 builtin_command_name (cmd));
+      add_to_element_list (&self->tree_to_build, tree);
+      convert_to_html_internal (self, tree, result, context_str);
+      remove_element_from_list (&self->tree_to_build, tree);
+      free (context_str);
+      /* should destroy explained_*_element */
+      destroy_element_and_children (tree);
     }
-  else
-    text_append (result, args_formatted->args[0].formatted[AFT_type_normal]);
 }
 
 void
-convert_w_command (CONVERTER *self, const enum command_id cmd,
+convert_anchor_command (CONVERTER *self, const enum command_id cmd,
                     const ELEMENT *element,
                     const HTML_ARGS_FORMATTED *args_formatted,
                     const char *content, TEXT *result)
 {
-  if (args_formatted && args_formatted->number > 0)
-    {
-      if (args_formatted->args[0].formatted[AFT_type_normal])
-        text_append (result,
-                     args_formatted->args[0].formatted[AFT_type_normal]);
-    }
-  if (!html_in_string (self))
+  if (!html_in_multi_expanded (self) && !html_in_string (self))
     {
-      text_append (result, "<!-- /@w -->");
+      char *id = html_command_id (self, element);
+      if (id && strlen (id))
+        {
+          format_separate_anchor (self, id, "anchor", result);
+        }
     }
 }
 
 void
-convert_value_command (CONVERTER *self, const enum command_id cmd,
+convert_footnote_command (CONVERTER *self, const enum command_id cmd,
                     const ELEMENT *element,
                     const HTML_ARGS_FORMATTED *args_formatted,
                     const char *content, TEXT *result)
 {
-  ELEMENT *tree;
-  ELEMENT *value_text = new_element (ET_NONE);
-  NAMED_STRING_ELEMENT_LIST *substrings = new_named_string_element_list ();
-
-  text_append (&value_text->text,
-               args_formatted->args[0].formatted[AFT_type_monospacestring]);
-  add_element_to_named_string_element_list (substrings,
-                                            "value", value_text);
-
-  tree = html_gdt_tree ("@{No value for `{value}'@}", self->document,
-                        self, substrings, 0, 0);
-
-  add_to_element_list (&self->tree_to_build, tree);
-  convert_to_html_internal (self, tree, result, 0);
-  remove_element_from_list (&self->tree_to_build, tree);
-
-  destroy_element_and_children (tree);
-
-  destroy_named_string_element_list (substrings);
-}
+  const static char *target_prefix = "t_f";
+  char *footnote_mark;
+  const char *footnote_id;
+  const char *footnote_docid;
+  char *footid;
+  char *docid;
+  int multiple_expanded_footnote = 0;
+  const char *multi_expanded_region;
+  int foot_num;
+  char *footnote_href;
+  char *attribute_class;
+  STRING_LIST *classes;
 
-void
-convert_email_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
-{
-  char *mail = 0;
-  char *mail_string = 0;
-  char *text = 0;
+  self->shared_conversion_state.footnote_number++;
+  foot_num = self->shared_conversion_state.footnote_number;
 
-  if (args_formatted->number > 0)
-    {
-      mail = args_formatted->args[0].formatted[AFT_type_url];
-      mail_string
-       = args_formatted->args[0].formatted[AFT_type_monospacestring];
-    }
+  if (self->conf->NUMBER_FOOTNOTES.integer > 0)
+    xasprintf (&footnote_mark, "%d", foot_num);
+  else
+    footnote_mark = strdup (self->conf->NO_NUMBER_FOOTNOTE_SYMBOL.string);
 
-  if (args_formatted->number > 1
-      && args_formatted->args[1].formatted[AFT_type_normal])
+  if (html_in_string (self))
     {
-      text = args_formatted->args[1].formatted[AFT_type_normal];
+      text_printf (result, "(%s)", footnote_mark);
+      free (footnote_mark);
+      return;
     }
 
-  if (!text || !strlen (text))
-    {
-      text = mail_string;
-    }
+  footnote_id = html_command_id (self, element);
 
-  /* FIXME match unicode spaces in perl */
-  if (!mail || mail[strspn (mail, whitespace_chars)] == '\0')
+  /* happens for bogus footnotes */
+  if (!footnote_id)
     {
-      if (text)
-        text_append (result, text);
+      free (footnote_mark);
       return;
     }
 
-  if (html_in_string (self))
+  /* ID for linking back to the main text from the footnote. */
+  footnote_docid = html_footnote_location_target (self, element);
+
+  multi_expanded_region = html_in_multi_expanded (self);
+  if (multi_expanded_region)
     {
-      text_printf (result, "%s (%s)", mail_string, text);
-    }
-  else
-    {
-      char *attribute_class;
-      char *protected_mailto;
-      char *mailto;
-      STRING_LIST *classes;
-      classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
-      memset (classes, 0, sizeof (STRING_LIST));
-      add_string (builtin_command_name (cmd), classes);
-
-      attribute_class = html_attribute_class (self, "a", classes);
-      destroy_strings_list (classes);
-      text_append (result, attribute_class);
-      free (attribute_class);
-
-      xasprintf (&mailto, "mailto:%s";, mail);
-      protected_mailto = url_protect_url_text (self, mailto);
-      free (mailto);
-
-      text_printf (result, " href=\"%s\">%s</a>", protected_mailto, text);
-      free (protected_mailto);
-    }
-}
-
-EXPLAINED_COMMAND_TYPE *
-find_explained_command_string (EXPLAINED_COMMAND_TYPE_LIST *type_explanations,
-                               const enum command_id cmd, const char *type)
-{
-  size_t i;
-  for (i = 0; i < type_explanations->number; i++)
-    {
-      EXPLAINED_COMMAND_TYPE *type_explanation = &type_explanations->list[i];
-      if (type_explanation->cmd == cmd
-          && !strcmp (type_explanation->type, type))
-        return type_explanation;
-    }
-  return 0;
-}
-
-void
-register_explained_command_string (
-               EXPLAINED_COMMAND_TYPE_LIST *type_explanations,
-                    const enum command_id cmd,
-                    const char *type, const char *explanation)
-{
-  EXPLAINED_COMMAND_TYPE *type_explanation
-    = find_explained_command_string (type_explanations, cmd, type);
-  if (!type_explanation)
-    {
-      if (type_explanations->number == type_explanations->space)
-        {
-          type_explanations->list
-           = realloc (type_explanations->list,
-            sizeof (EXPLAINED_COMMAND_TYPE) * (type_explanations->space += 5));
-        }
-      type_explanation = &type_explanations->list[type_explanations->number];
-      type_explanation->cmd = cmd;
-      type_explanation->type = strdup (type);
-
-      type_explanations->number++;
-    }
-  else
-    free (type_explanation->explanation);
-
-  type_explanation->explanation = strdup (explanation);
-}
-
-void
-convert_explained_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
-{
-  TEXT explained_string;
-  TEXT *text_result;
-  char *explained_arg = 0;
-  char *normalized_type = 0;
-  char *explanation_string = 0;
-  char *explanation_result = 0;
-  EXPLAINED_COMMAND_TYPE_LIST *type_explanations
-    = &self->shared_conversion_state.explained_commands;
-
-  if (element->args.number > 0
-      && element->args.list[0]->contents.number > 0)
-    {
-      normalized_type = convert_to_identifier (element->args.list[0]);
-    }
-  else
-    normalized_type = strdup ("");
-
-  if (args_formatted && args_formatted->number > 1)
-    {
-      if (args_formatted->args[1].formatted[AFT_type_string])
-        {
-          explanation_string
-            = args_formatted->args[1].formatted[AFT_type_string];
-
-          if (explanation_string[strspn
-                     (explanation_string, whitespace_chars)] != '\0')
-            {
-              register_explained_command_string (type_explanations,
-                           cmd, normalized_type, explanation_string);
-            }
-          else
-            explanation_string = 0;
-       }
-     if (args_formatted->args[1].formatted[AFT_type_normal])
-       explanation_result = args_formatted->args[1].formatted[AFT_type_normal];
-    }
-
-  if (!explanation_string)
-    {
-      EXPLAINED_COMMAND_TYPE *type_explanation
-          = find_explained_command_string (type_explanations,
-                                                     cmd, normalized_type);
-      if (type_explanation)
-        explanation_string = type_explanation->explanation;
-    }
-
-  free (normalized_type);
-
-  if (explanation_result)
-    {
-      text_init (&explained_string);
-      text_result = &explained_string;
-    }
-  else
-    text_result = result;
-
-  if (args_formatted->number > 0 &&
-      args_formatted->args[0].formatted[AFT_type_normal])
-    explained_arg = args_formatted->args[0].formatted[AFT_type_normal];
-  else
-    explained_arg = "";
-
-  if (!html_in_string (self))
-    {
-      char *attribute_class;
-      STRING_LIST *classes;
-      classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
-      memset (classes, 0, sizeof (STRING_LIST));
-      add_string (builtin_command_name (cmd), classes);
-
-      attribute_class = html_attribute_class (self, "abbr", classes);
-      destroy_strings_list (classes);
-      text_append (text_result, attribute_class);
-      free (attribute_class);
-
-      if (explanation_string)
-        text_printf (text_result, " title=\"%s\"", explanation_string);
-      text_append_n (text_result, ">", 1);
-      text_append (text_result, explained_arg);
-      text_append_n (text_result, "</abbr>", 7);
-    }
-  else
-    text_append (text_result, explained_arg);
-
-  if (explanation_result)
-    {
-      char *context_str;
-      NAMED_STRING_ELEMENT_LIST *substrings
-                                       = new_named_string_element_list ();
-      ELEMENT *explained_string_element = new_element (ET__converted);
-      ELEMENT *explanation_result_element = new_element (ET__converted);
-      ELEMENT *tree;
-
-      text_append (&explained_string_element->text, text_result->text);
-      free (text_result->text);
-      text_append (&explanation_result_element->text, explanation_result);
-
-      add_element_to_named_string_element_list (substrings,
-                          "explained_string", explained_string_element);
-      add_element_to_named_string_element_list (substrings,
-                          "explanation", explanation_result_element);
-      tree = html_gdt_tree ("{explained_string} ({explanation})",
-                             self->document, self, substrings, 0, 0);
-      destroy_named_string_element_list (substrings);
-
-      xasprintf (&context_str, "convert explained  %s",
-                 builtin_command_name (cmd));
-      add_to_element_list (&self->tree_to_build, tree);
-      convert_to_html_internal (self, tree, result, context_str);
-      remove_element_from_list (&self->tree_to_build, tree);
-      free (context_str);
-      /* should destroy explained_*_element */
-      destroy_element_and_children (tree);
-    }
-}
-
-void
-convert_anchor_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
-{
-  if (!html_in_multi_expanded (self) && !html_in_string (self))
-    {
-      char *id = html_command_id (self, element);
-      if (id && strlen (id))
-        {
-          format_separate_anchor (self, id, "anchor", result);
-        }
-    }
-}
-
-void
-convert_footnote_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
-{
-  const static char *target_prefix = "t_f";
-  char *footnote_mark;
-  const char *footnote_id;
-  const char *footnote_docid;
-  char *footid;
-  char *docid;
-  int multiple_expanded_footnote = 0;
-  const char *multi_expanded_region;
-  int foot_num;
-  char *footnote_href;
-  char *attribute_class;
-  STRING_LIST *classes;
-
-  self->shared_conversion_state.footnote_number++;
-  foot_num = self->shared_conversion_state.footnote_number;
-
-  if (self->conf->NUMBER_FOOTNOTES.integer > 0)
-    xasprintf (&footnote_mark, "%d", foot_num);
-  else
-    footnote_mark = strdup (self->conf->NO_NUMBER_FOOTNOTE_SYMBOL.string);
-
-  if (html_in_string (self))
-    {
-      text_printf (result, "(%s)", footnote_mark);
-      free (footnote_mark);
-      return;
-    }
-
-  footnote_id = html_command_id (self, element);
-
-  /* happens for bogus footnotes */
-  if (!footnote_id)
-    {
-      free (footnote_mark);
-      return;
-    }
-
-  /* ID for linking back to the main text from the footnote. */
-  footnote_docid = html_footnote_location_target (self, element);
-
-  multi_expanded_region = html_in_multi_expanded (self);
-  if (multi_expanded_region)
-    {
-    /* to avoid duplicate names, use a prefix that cannot happen in anchors */
-      xasprintf (&footid, "%s%s_%s_%d", target_prefix, multi_expanded_region,
-                 footnote_id, foot_num);
-      xasprintf (&docid, "%s%s_%s_%d", target_prefix, multi_expanded_region,
-                 footnote_docid, foot_num);
+    /* to avoid duplicate names, use a prefix that cannot happen in anchors */
+      xasprintf (&footid, "%s%s_%s_%d", target_prefix, multi_expanded_region,
+                 footnote_id, foot_num);
+      xasprintf (&docid, "%s%s_%s_%d", target_prefix, multi_expanded_region,
+                 footnote_docid, foot_num);
     }
   else
     {
@@ -12920,152 +12512,10 @@ convert_informative_command (CONVERTER *self, const 
enum command_id cmd,
 }
 
 void
-contents_shortcontents_in_title (CONVERTER *self, TEXT *result)
-{
-  if (self->document->sections_list
-      && self->document->sections_list->number > 0
-      && !strcmp (self->conf->CONTENTS_OUTPUT_LOCATION.string, "after_title"))
-    {
-      enum command_id contents_cmds[2] = {CM_shortcontents, CM_contents};
-      int i;
-      for (i = 0; i < 2; i++)
-        {
-          int contents_set = 0;
-          enum command_id cmd = contents_cmds[i];
-          OPTION *contents_option_ref = get_command_option (self->conf, cmd);
-          if (contents_option_ref->integer > 0)
-            contents_set = 1;
-          if (contents_set)
-            {
-              char *contents_text
-                = contents_inline_element (self, cmd, 0);
-              if (contents_text)
-                {
-                  text_append (result, contents_text);
-                  text_append (result, self->conf->DEFAULT_RULE.string);
-                  text_append_n (result, "\n", 1);
-                  free (contents_text);
-                }
-            }
-        }
-    }
-}
-
-static void
-format_simpletitle (CONVERTER *self, TEXT *result)
-{
-  char *title_text;
-  char *context_str;
-  STRING_LIST *classes;
-  enum command_id cmd = self->simpletitle_cmd;
-  classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
-  memset (classes, 0, sizeof (STRING_LIST));
-  add_string (builtin_command_name (cmd), classes);
-  xasprintf (&context_str, "%s simpletitle",
-             builtin_command_name (cmd));
-  title_text
-    = convert_tree_new_formatting_context (self,
-        self->simpletitle_tree, context_str, 0, 0, 0);
-  free (context_str);
-  format_heading_text (self, cmd, classes, title_text,
-                                    0, 0, 0, 0, result);
-  destroy_strings_list (classes);
-  free (title_text);
-}
-
-/* Convert @titlepage.  Falls back to simpletitle. */
-char *
-html_default_format_titlepage (CONVERTER *self)
-{
-  int titlepage_text = 0;
-  TEXT result;
-  text_init (&result);
-  text_append (&result, "");
-  if (self->document->global_commands->titlepage)
-    {
-      ELEMENT *tmp = new_element (ET_NONE);
-      tmp->contents = self->document->global_commands->titlepage->contents;
-      convert_to_html_internal (self, tmp, &result, "convert titlepage");
-      tmp->contents.list = 0;
-      destroy_element (tmp);
-      titlepage_text = 1;
-    }
-  else if (self->simpletitle_tree)
-    {
-      format_simpletitle (self, &result);
-      titlepage_text = 1;
-    }
-  if (titlepage_text)
-    {
-      text_append (&result, self->conf->DEFAULT_RULE.string);
-      text_append_n (&result, "\n", 1);
-    }
-  contents_shortcontents_in_title (self, &result);
-  return result.text;
-}
-
-char *
-format_titlepage (CONVERTER *self)
-{
-  FORMATTING_REFERENCE *formatting_reference
-   = &self->current_formatting_references[FR_format_titlepage];
-  if (formatting_reference->status == FRS_status_default_set)
-    {
-      return html_default_format_titlepage (self);
-    }
-  else
-    {
-      return call_formatting_function_format_titlepage (self,
-                                               formatting_reference);
-    }
-}
-
-char *
-html_default_format_title_titlepage (CONVERTER *self)
-{
-  if (self->conf->SHOW_TITLE.integer > 0)
-    {
-      if (self->conf->USE_TITLEPAGE_FOR_TITLE.integer)
-        {
-          return format_titlepage (self);
-        }
-      else
-        {
-          TEXT result;
-          text_init (&result);
-          text_append (&result, "");
-
-          if (self->simpletitle_tree)
-            format_simpletitle (self, &result);
-
-          contents_shortcontents_in_title (self, &result);
-          return result.text;
-        }
-    }
-  return strdup ("");
-}
-
-char *
-format_title_titlepage (CONVERTER *self)
-{
-  FORMATTING_REFERENCE *formatting_reference
-   = &self->current_formatting_references[FR_format_title_titlepage];
-  if (formatting_reference->status == FRS_status_default_set)
-    {
-      return html_default_format_title_titlepage (self);
-    }
-  else
-    {
-      return call_formatting_function_format_title_titlepage (self,
-                                                      formatting_reference);
-    }
-}
-
-void
-convert_contents_command (CONVERTER *self, const enum command_id cmd,
-                    const ELEMENT *element,
-                    const HTML_ARGS_FORMATTED *args_formatted,
-                    const char *content, TEXT *result)
+convert_contents_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
 {
   if (html_in_string (self))
     return;
@@ -13192,71 +12642,488 @@ static COMMAND_INTERNAL_CONVERSION 
commands_internal_conversion_table[] = {
   {CM_majorheading, &convert_heading_command},
   {CM_centerchap, &convert_heading_command},
 
-  {CM_html, &convert_raw_command},
-  {CM_tex, &convert_raw_command},
-  {CM_xml, &convert_raw_command},
-  {CM_docbook, &convert_raw_command},
-  {CM_latex, &convert_raw_command},
+  {CM_html, &convert_raw_command},
+  {CM_tex, &convert_raw_command},
+  {CM_xml, &convert_raw_command},
+  {CM_docbook, &convert_raw_command},
+  {CM_latex, &convert_raw_command},
+
+  {CM_inforef, &convert_xref_commands},
+  {CM_link, &convert_xref_commands},
+  {CM_xref, &convert_xref_commands},
+  {CM_ref, &convert_xref_commands},
+  {CM_pxref, &convert_xref_commands},
+
+  {0, 0},
+};
+
+void
+open_quotation_command (CONVERTER *self, const enum command_id cmd,
+                        const ELEMENT *element, TEXT *result)
+{
+  const char *cmdname = element_command_name (element);
+  char *formatted_quotation_arg_to_prepend = 0;
+  if (element->args.number > 0 && element->args.list[0]->contents.number > 0)
+    {
+      ELEMENT *tree;
+      char *explanation;
+      NAMED_STRING_ELEMENT_LIST *substrings
+                                       = new_named_string_element_list ();
+      ELEMENT *quotation_arg_copy = copy_tree (element->args.list[0]);
+      add_element_to_named_string_element_list (substrings,
+                          "quotation_arg", quotation_arg_copy);
+      tree = html_gdt_tree ("@b{{quotation_arg}:} ", self->document,
+                           self, substrings, 0, 0);
+      destroy_named_string_element_list (substrings);
+      xasprintf (&explanation, "open %s prepended arg", cmdname);
+      add_to_element_list (&self->tree_to_build, tree);
+      formatted_quotation_arg_to_prepend
+        = html_convert_tree (self, tree, explanation);
+      remove_element_from_list (&self->tree_to_build, tree);
+      destroy_element_and_children (tree);
+      free (explanation);
+    }
+  html_register_pending_formatted_inline_content (self, cmdname,
+                                  formatted_quotation_arg_to_prepend);
+  free (formatted_quotation_arg_to_prepend);
+}
+
+void
+open_inline_container_type (CONVERTER *self, const enum element_type type,
+                            const ELEMENT *element, TEXT *result)
+{
+  char *pending_formatted = html_get_pending_formatted_inline_content (self);
+  if (pending_formatted)
+    {
+      html_associate_pending_formatted_inline_content (self, element, 0,
+                                                       pending_formatted);
+      free (pending_formatted);
+    }
+}
+
+/* associate command to the C function implementing the opening */
+static COMMAND_INTERNAL_OPEN commands_internal_open_table[] = {
+  {CM_quotation, &open_quotation_command},
+  {CM_smallquotation, &open_quotation_command},
+  {0, 0},
+};
+
+/* associate type to the C function implementing the opening */
+static TYPE_INTERNAL_OPEN types_internal_open_table[] = {
+  {ET_paragraph, &open_inline_container_type},
+  {ET_preformatted, &open_inline_container_type},
+  {0, 0},
+};
+
+#define static_class(name, class) \
+static char * name ##_array[] = {#class}; \
+static const STRING_LIST name ##_classes = {name ##_array, 1, 1};
+
+static_class(def_type, def-type)
+static_class(def_name, def-name)
+static_class(def_code_arguments, def-code-arguments)
+static_class(def_var_arguments, def-var-arguments)
+static_class(call_def, call-def)
+static_class(category_def, category-def)
+
+#undef static_class
+
+void
+convert_def_line_type (CONVERTER *self, const enum element_type type,
+                       const ELEMENT *element, const char *content,
+                       TEXT *result)
+{
+  char *index_id;
+  PARSED_DEF *parsed_def;
+  STRING_LIST *classes;
+  char *attribute_class;
+  char *alias_class = 0;
+  enum command_id original_def_cmd;
+  enum command_id def_cmd;
+  enum command_id original_cmd = 0;
+  enum command_id base_cmd = 0;
+  TEXT def_call;
+  char *anchor;
+
+  if (html_in_string (self))
+    {
+      /* should probably never happen */
+      char *text;
+      TEXT_OPTIONS *text_conv_options
+         = copy_options_for_convert_text (self, 0);
+      text = convert_to_text (element, text_conv_options);
+      free (text_conv_options);
+      format_protect_text (self, text, result);
+    }
+
+  index_id = html_command_id (self, element);
+
+  parsed_def = definition_arguments_content (element);
+
+  if (element->cmd)
+    original_def_cmd = element->cmd;
+  else
+    original_def_cmd = element->parent->cmd;
+
+  if (builtin_command_data[original_def_cmd].flags & CF_def_alias)
+    {
+      int i;
+      for (i = 0; def_aliases[i].alias ; i++)
+        {
+          if (def_aliases[i].alias == original_def_cmd)
+            {
+              original_cmd = def_aliases[i].command;
+              break;
+            }
+        }
+
+      xasprintf (&alias_class, "%s-alias-%s",
+                    builtin_command_name(original_def_cmd),
+                    builtin_command_name(original_cmd));
+    }
+  else
+    original_cmd = original_def_cmd;
+
+  /* parent is defblock, we do not put it in class */
+  if (element->cmd == CM_defline || element->cmd == CM_deftypeline)
+    def_cmd = element->cmd;
+  else
+  /* the parent is the def both for def* def_line and def*x */
+    def_cmd = element->parent->cmd;
+
+  if (builtin_command_data[def_cmd].flags & CF_def_alias)
+    {
+      int i;
+      for (i = 0; def_aliases[i].alias ; i++)
+        {
+          if (def_aliases[i].alias == def_cmd)
+            {
+              base_cmd = def_aliases[i].command;
+              break;
+            }
+        }
+    }
+  else
+    base_cmd = def_cmd;
+
+  classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+  memset (classes, 0, sizeof (STRING_LIST));
+
+  add_string (builtin_command_name(original_cmd), classes);
+  if (alias_class)
+    {
+      add_string (alias_class, classes);
+      free (alias_class);
+    }
+  if (base_cmd != original_cmd)
+    {
+      char *class;
+      xasprintf (&class, "def-cmd-%s", builtin_command_name(base_cmd));
+      add_string (class, classes);
+      free (class);
+    }
+
+  text_init (&def_call);
+  text_append (&def_call, "");
+  if (parsed_def->type)
+    {
+      char *type_text;
+      size_t type_text_len;
+      ELEMENT *root_code = new_element (ET__code);
+
+      add_to_contents_as_array (root_code, parsed_def->type);
+
+      add_to_element_list (&self->tree_to_build, root_code);
+
+      type_text = html_convert_tree (self, root_code, 0);
+
+      remove_element_from_list (&self->tree_to_build, root_code);
+
+      destroy_element (root_code);
+      type_text_len = strlen (type_text);
+
+      if (type_text_len > 0)
+        {
+          char *attribute_class = html_attribute_class (self, "code",
+                                                        &def_type_classes);
+          text_append (&def_call, attribute_class);
+          free (attribute_class);
+          text_append_n (&def_call, ">", 1);
+          text_append_n (&def_call, type_text, type_text_len);
+          text_append_n (&def_call, "</code>", 7);
+        }
+      if ((base_cmd == CM_deftypefn || base_cmd == CM_deftypeop)
+          && !strcmp (self->conf->deftypefnnewline.string, "on"))
+        {
+          text_append_n (&def_call, self->line_break_element.string,
+                                    self->line_break_element.len);
+          text_append_n (&def_call, " ", 1);
+        }
+      else if (type_text_len > 0)
+        text_append_n (&def_call, " ", 1);
+      free (type_text);
+    }
+
+  if (parsed_def->name)
+    {
+      char *attribute_class = html_attribute_class (self, "strong",
+                                                    &def_name_classes);
+      ELEMENT *root_code = new_element (ET__code);
+
+      add_to_contents_as_array (root_code, parsed_def->name);
+
+      add_to_element_list (&self->tree_to_build, root_code);
+
+      text_append (&def_call, attribute_class);
+      free (attribute_class);
+      text_append_n (&def_call, ">", 1);
+
+      convert_to_html_internal (self, root_code, &def_call, 0);
+
+      remove_element_from_list (&self->tree_to_build, root_code);
+      destroy_element (root_code);
+
+      text_append_n (&def_call, "</strong>", 9);
+    }
+
+  if (parsed_def->args)
+    {
+      char *args_formatted;
+   /* arguments not only metasyntactic variables
+      (deftypefn, deftypevr, deftypeop, deftypecv) */
+      /* Texinfo::Common::def_no_var_arg_commands{$base_command_name} */
+      if (strlen (builtin_command_name(base_cmd)) >= 7
+          && !memcmp (builtin_command_name(base_cmd), "deftype", 7))
+        {
+          ELEMENT *root_code = new_element (ET__code);
+
+          add_to_contents_as_array (root_code, parsed_def->args);
+
+          add_to_element_list (&self->tree_to_build, root_code);
+
+          args_formatted = html_convert_tree (self, root_code, 0);
+
+          remove_element_from_list (&self->tree_to_build, root_code);
+          destroy_element (root_code);
+
+          if (args_formatted[strspn (args_formatted, whitespace_chars)] != 
'\0')
+            {
+              char *attribute_class = html_attribute_class (self, "code",
+                                              &def_code_arguments_classes);
+              int status;
+              int omit_def_name_space = lookup_extra_integer (element,
+                                              "omit_def_name_space", &status);
+              if (omit_def_name_space <= 0)
+                text_append_n (&def_call, " ", 1);
+              text_append (&def_call, attribute_class);
+              free (attribute_class);
+              text_append_n (&def_call, ">", 1);
+              text_append (&def_call, args_formatted);
+              text_append_n (&def_call, "</code>", 7);
+            }
+        }
+      else
+        {
+          html_set_code_context (self, 0);
+          args_formatted = html_convert_tree (self, parsed_def->args, 0);
+          html_pop_code_context (self);
+          if (args_formatted[strspn (args_formatted, whitespace_chars)] != 
'\0')
+            {
+              char *attribute_class = html_attribute_class (self, "var",
+                                              &def_var_arguments_classes);
+              int status;
+              int omit_def_name_space = lookup_extra_integer (element,
+                                              "omit_def_name_space", &status);
+              if (omit_def_name_space <= 0)
+                text_append_n (&def_call, " ", 1);
+              text_append (&def_call, attribute_class);
+              free (attribute_class);
+              text_append_n (&def_call, ">", 1);
+              text_append (&def_call, args_formatted);
+              text_append_n (&def_call, "</var>", 6);
+            }
+        }
+      free (args_formatted);
+    }
+
+  if (self->conf->DEF_TABLE.integer > 0)
+    {
+      ELEMENT *category_tree
+         = definition_category_tree (self->conf, element);
+
+      attribute_class = html_attribute_class (self, "tr", classes);
+      destroy_strings_list (classes);
+      text_append (result, attribute_class);
+      free (attribute_class);
+      if (index_id && strlen (index_id) && !html_in_multi_expanded (self))
+        text_printf (result, " id=\"%s\"", index_id);
+      text_append_n (result, ">", 1);
+
+      attribute_class = html_attribute_class (self, "td",
+                                               &call_def_classes);
+      text_append (result, attribute_class);
+      free (attribute_class);
+      text_append_n (result, ">", 1);
+      text_append_n (result, def_call.text, def_call.end);
+      free (def_call.text);
+      text_append_n (result, "</td>", 5);
+
+      attribute_class = html_attribute_class (self, "td",
+                                              &category_def_classes);
+      text_append (result, attribute_class);
+      free (attribute_class);
+      text_append_n (result, ">[", 2);
+
+      if (category_tree)
+        {
+          add_to_element_list (&self->tree_to_build, category_tree);
+          convert_to_html_internal (self, category_tree, result, 0);
+          remove_element_from_list (&self->tree_to_build, category_tree);
+          destroy_element_and_children (category_tree);
+        }
+      text_append_n (result, "]</td></tr>\n", 12);
+      return;
+    }
+
+  attribute_class = html_attribute_class (self, "dt", classes);
+  destroy_strings_list (classes);
+  text_append (result, attribute_class);
+  free (attribute_class);
+  if (index_id && strlen (index_id) && !html_in_multi_expanded (self))
+    text_printf (result, " id=\"%s\"", index_id);
+  text_append_n (result, ">", 1);
+
+  if (parsed_def->category)
+    {
+      ELEMENT *category_tree = 0;
+      NAMED_STRING_ELEMENT_LIST *substrings
+                                   = new_named_string_element_list ();
+      ELEMENT *category_copy = copy_tree (parsed_def->category);
+
+      add_element_to_named_string_element_list (substrings,
+                                            "category", category_copy);
+      if (parsed_def->class)
+        {
+          ELEMENT *class_copy = copy_tree (parsed_def->class);
+          add_element_to_named_string_element_list (substrings,
+                                            "class", class_copy);
+
+          if (base_cmd == CM_deftypeop && parsed_def->type
+              && !strcmp (self->conf->deftypefnnewline.string, "on"))
+            {
+               category_tree
+                  = html_gdt_tree ("{category} on @code{{class}}:@* ",
+                                   self->document, self, substrings, 0, 0);
+            }
+          else if (base_cmd == CM_defop || base_cmd == CM_deftypeop)
+            {
+               category_tree
+                  = html_gdt_tree ("{category} on @code{{class}}: ",
+                                   self->document, self, substrings, 0, 0);
+            }
+          else if (base_cmd == CM_defcv || base_cmd == CM_deftypecv)
+            {
+               category_tree
+                  = html_gdt_tree ("{category} of @code{{class}}: ",
+                                   self->document, self, substrings, 0, 0);
+            }
+        }
+      else
+        {
+          if ((base_cmd == CM_deftypefn || base_cmd == CM_deftypeop)
+              && parsed_def->type
+              && !strcmp (self->conf->deftypefnnewline.string, "on"))
+            {
+              category_tree
+                  = html_gdt_tree ("{category}:@* ",
+                                   self->document, self, substrings, 0, 0);
+            }
+          else
+            {
+              category_tree
+                  = html_gdt_tree ("{category}: ",
+                                   self->document, self, substrings, 0, 0);
+            }
+        }
+      destroy_named_string_element_list (substrings);
+
+      if (category_tree)
+        {
+          char *attribute_open = html_attribute_class (self, "span",
+                                             &category_def_classes);
+          size_t open_len = strlen (attribute_open);
+          if (open_len)
+            {
+              text_append_n (result, attribute_open, open_len);
+              text_append_n (result, ">", 1);
+            }
+          free (attribute_open);
+          add_to_element_list (&self->tree_to_build, category_tree);
+          convert_to_html_internal (self, category_tree, result, 0);
+          remove_element_from_list (&self->tree_to_build, category_tree);
+          destroy_element_and_children (category_tree);
+          if (open_len)
+            text_append_n (result, "</span>", 7);
+        }
+    }
+
+  destroy_parsed_def (parsed_def);
 
-  {CM_inforef, &convert_xref_commands},
-  {CM_link, &convert_xref_commands},
-  {CM_xref, &convert_xref_commands},
-  {CM_ref, &convert_xref_commands},
-  {CM_pxref, &convert_xref_commands},
+  anchor = get_copiable_anchor (self, index_id);
 
-  {0, 0},
-};
+  if (anchor)
+    text_append_n (result, "<span>", 6);
+
+  text_append_n (result, def_call.text, def_call.end);
+  free (def_call.text);
+  if (anchor)
+    {
+      text_append (result, anchor);
+      text_append_n (result, "</span>", 7);
+    }
+
+  text_append_n (result, "</dt>\n", 6);
+
+  free (anchor);
+}
 
 void
-open_quotation_command (CONVERTER *self, const enum command_id cmd,
-                        const ELEMENT *element, TEXT *result)
+convert_table_term_type (CONVERTER *self, const enum element_type type,
+                        const ELEMENT *element, const char *content,
+                        TEXT *result)
 {
-  const char *cmdname = element_command_name (element);
-  char *formatted_quotation_arg_to_prepend = 0;
-  if (element->args.number > 0 && element->args.list[0]->contents.number > 0)
+  if (content)
     {
-      ELEMENT *tree;
-      char *explanation;
-      NAMED_STRING_ELEMENT_LIST *substrings
-                                       = new_named_string_element_list ();
-      ELEMENT *quotation_arg_copy = copy_tree (element->args.list[0]);
-      add_element_to_named_string_element_list (substrings,
-                          "quotation_arg", quotation_arg_copy);
-      tree = html_gdt_tree ("@b{{quotation_arg}:} ", self->document,
-                           self, substrings, 0, 0);
-      destroy_named_string_element_list (substrings);
-      xasprintf (&explanation, "open %s prepended arg", cmdname);
-      add_to_element_list (&self->tree_to_build, tree);
-      formatted_quotation_arg_to_prepend
-        = html_convert_tree (self, tree, explanation);
-      remove_element_from_list (&self->tree_to_build, tree);
-      destroy_element_and_children (tree);
-      free (explanation);
+      text_append (result, "<dt>");
+      text_append (result, content);
     }
-  html_register_pending_formatted_inline_content (self, cmdname,
-                                  formatted_quotation_arg_to_prepend);
-  free (formatted_quotation_arg_to_prepend);
 }
 
 void
-open_inline_container_type (CONVERTER *self, const enum element_type type,
-                            const ELEMENT *element, TEXT *result)
+convert_row_type (CONVERTER *self, const enum element_type type,
+                  const ELEMENT *element, const char *content,
+                  TEXT *result)
 {
-  char *pending_formatted = html_get_pending_formatted_inline_content (self);
-  if (pending_formatted)
+  if (html_in_string (self))
     {
-      html_associate_pending_formatted_inline_content (self, element, 0,
-                                                       pending_formatted);
-      free (pending_formatted);
+      if (content)
+        text_append (result, content);
     }
-}
 
-/* associate command to the C function implementing the opening */
-static COMMAND_INTERNAL_OPEN commands_internal_open_table[] = {
-  {CM_quotation, &open_quotation_command},
-  {CM_smallquotation, &open_quotation_command},
-  {0, 0},
-};
+  if (!content || content[strspn (content, whitespace_chars)] == '\0')
+    return;
+  else
+    {
+      text_append (result, "<tr>");
+      text_append (result, content);
+      text_append (result, "</tr>");
+
+      if (element->contents.number > 0
+          && element->contents.list[0]->cmd != CM_headitem)
+      /* if headitem, end of line added in _convert_multitable_head_type */
+        text_append (result, "\n");
+    }
+}
 
 /* associate type to the C function implementing the conversion */
 static TYPE_INTERNAL_CONVERSION types_internal_conversion_table[] = {
@@ -13267,13 +13134,6 @@ static TYPE_INTERNAL_CONVERSION 
types_internal_conversion_table[] = {
   {0, 0},
 };
 
-/* associate type to the C function implementing the opening */
-static TYPE_INTERNAL_OPEN types_internal_open_table[] = {
-  {ET_paragraph, &open_inline_container_type},
-  {ET_preformatted, &open_inline_container_type},
-  {0, 0},
-};
-
 void
 convert_unit_type (CONVERTER *self, const enum output_unit_type unit_type,
                    const OUTPUT_UNIT *output_unit, const char *content,
@@ -13453,6 +13313,148 @@ static OUTPUT_UNIT_INTERNAL_CONVERSION 
output_units_internal_conversion_table[]
   {0, 0},
 };
 
+void
+contents_shortcontents_in_title (CONVERTER *self, TEXT *result)
+{
+  if (self->document->sections_list
+      && self->document->sections_list->number > 0
+      && !strcmp (self->conf->CONTENTS_OUTPUT_LOCATION.string, "after_title"))
+    {
+      enum command_id contents_cmds[2] = {CM_shortcontents, CM_contents};
+      int i;
+      for (i = 0; i < 2; i++)
+        {
+          int contents_set = 0;
+          enum command_id cmd = contents_cmds[i];
+          OPTION *contents_option_ref = get_command_option (self->conf, cmd);
+          if (contents_option_ref->integer > 0)
+            contents_set = 1;
+          if (contents_set)
+            {
+              char *contents_text
+                = contents_inline_element (self, cmd, 0);
+              if (contents_text)
+                {
+                  text_append (result, contents_text);
+                  text_append (result, self->conf->DEFAULT_RULE.string);
+                  text_append_n (result, "\n", 1);
+                  free (contents_text);
+                }
+            }
+        }
+    }
+}
+
+static void
+format_simpletitle (CONVERTER *self, TEXT *result)
+{
+  char *title_text;
+  char *context_str;
+  STRING_LIST *classes;
+  enum command_id cmd = self->simpletitle_cmd;
+  classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+  memset (classes, 0, sizeof (STRING_LIST));
+  add_string (builtin_command_name (cmd), classes);
+  xasprintf (&context_str, "%s simpletitle",
+             builtin_command_name (cmd));
+  title_text
+    = convert_tree_new_formatting_context (self,
+        self->simpletitle_tree, context_str, 0, 0, 0);
+  free (context_str);
+  format_heading_text (self, cmd, classes, title_text,
+                                    0, 0, 0, 0, result);
+  destroy_strings_list (classes);
+  free (title_text);
+}
+
+/* Convert @titlepage.  Falls back to simpletitle. */
+char *
+html_default_format_titlepage (CONVERTER *self)
+{
+  int titlepage_text = 0;
+  TEXT result;
+  text_init (&result);
+  text_append (&result, "");
+  if (self->document->global_commands->titlepage)
+    {
+      ELEMENT *tmp = new_element (ET_NONE);
+      tmp->contents = self->document->global_commands->titlepage->contents;
+      convert_to_html_internal (self, tmp, &result, "convert titlepage");
+      tmp->contents.list = 0;
+      destroy_element (tmp);
+      titlepage_text = 1;
+    }
+  else if (self->simpletitle_tree)
+    {
+      format_simpletitle (self, &result);
+      titlepage_text = 1;
+    }
+  if (titlepage_text)
+    {
+      text_append (&result, self->conf->DEFAULT_RULE.string);
+      text_append_n (&result, "\n", 1);
+    }
+  contents_shortcontents_in_title (self, &result);
+  return result.text;
+}
+
+char *
+format_titlepage (CONVERTER *self)
+{
+  FORMATTING_REFERENCE *formatting_reference
+   = &self->current_formatting_references[FR_format_titlepage];
+  if (formatting_reference->status == FRS_status_default_set)
+    {
+      return html_default_format_titlepage (self);
+    }
+  else
+    {
+      return call_formatting_function_format_titlepage (self,
+                                               formatting_reference);
+    }
+}
+
+char *
+html_default_format_title_titlepage (CONVERTER *self)
+{
+  if (self->conf->SHOW_TITLE.integer > 0)
+    {
+      if (self->conf->USE_TITLEPAGE_FOR_TITLE.integer)
+        {
+          return format_titlepage (self);
+        }
+      else
+        {
+          TEXT result;
+          text_init (&result);
+          text_append (&result, "");
+
+          if (self->simpletitle_tree)
+            format_simpletitle (self, &result);
+
+          contents_shortcontents_in_title (self, &result);
+          return result.text;
+        }
+    }
+  return strdup ("");
+}
+
+char *
+format_title_titlepage (CONVERTER *self)
+{
+  FORMATTING_REFERENCE *formatting_reference
+   = &self->current_formatting_references[FR_format_title_titlepage];
+  if (formatting_reference->status == FRS_status_default_set)
+    {
+      return html_default_format_title_titlepage (self);
+    }
+  else
+    {
+      return call_formatting_function_format_title_titlepage (self,
+                                                      formatting_reference);
+    }
+}
+
 void
 default_format_special_body_contents (CONVERTER *self,
                                const size_t special_unit_number,



reply via email to

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