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, 4 Oct 2024 11:31:26 -0400 (EDT)

branch: master
commit 80415312e3031fc651b9dcc394ad5eb626087ca4
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Wed Aug 14 16:11:10 2024 +0200

    * tp/Texinfo/XS/convert/convert_html.c (html_normalized_to_id)
    (html_normalized_label_id_file): prepend normalized_to_id and
    normalized_label_id_file with html_ and declare in header file.
    Update callers.
    
    * tp/Texinfo/XS/convert/convert_html.c,
    tp/Texinfo/XS/convert/html_prepare_converter.c
    (add_element_target_to_list, add_element_target, add_special_target)
    (set_special_units_targets_files, unique_target)
    (prepare_associated_special_units_targets)
    (new_sectioning_command_target, set_root_commands_targets_node_files)
    (prepare_index_entries_targets, compare_footnote_id)
    (find_footnote_id_number, footid_base, docid_base)
    (prepare_footnotes_targets, heading_commands_list)
    (set_heading_commands_targets, check_targets_order, sort_cmd_targets)
    (html_prepare_conversion_units_targets): move
    add_element_target_to_list, add_element_target, add_special_target,
    unique_target, set_special_units_targets_files,
    prepare_associated_special_units_targets,
    new_sectioning_command_target, set_root_commands_targets_node_files,
    prepare_index_entries_targets, prepare_footnotes_targets,
    heading_commands_list, set_heading_commands_targets,
    check_targets_order, sort_cmd_targets and
    html_prepare_conversion_units_targets to html_prepare_converter.c.
    duplicate compare_footnote_id and compare_element_target.
---
 ChangeLog                                      |   28 +
 tp/Texinfo/XS/convert/convert_html.c           | 1189 +++++-------------------
 tp/Texinfo/XS/convert/convert_html.h           |    8 +-
 tp/Texinfo/XS/convert/html_prepare_converter.c |  775 +++++++++++++++
 tp/Texinfo/XS/convert/html_prepare_converter.h |    3 +
 5 files changed, 1034 insertions(+), 969 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d09ccaaeac..b9ae151345 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,34 @@
        * tp/Texinfo/XS/convert/convert_html.h: declare node_part_command
        open function.
 
+2024-08-14  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/XS/convert/convert_html.c (html_normalized_to_id)
+       (html_normalized_label_id_file): prepend normalized_to_id and
+       normalized_label_id_file with html_ and declare in header file.
+       Update callers.
+
+       * tp/Texinfo/XS/convert/convert_html.c,
+       tp/Texinfo/XS/convert/html_prepare_converter.c
+       (add_element_target_to_list, add_element_target, add_special_target)
+       (set_special_units_targets_files, unique_target)
+       (prepare_associated_special_units_targets)
+       (new_sectioning_command_target, set_root_commands_targets_node_files)
+       (prepare_index_entries_targets, compare_footnote_id)
+       (find_footnote_id_number, footid_base, docid_base)
+       (prepare_footnotes_targets, heading_commands_list)
+       (set_heading_commands_targets, check_targets_order, sort_cmd_targets)
+       (html_prepare_conversion_units_targets): move
+       add_element_target_to_list, add_element_target, add_special_target,
+       unique_target, set_special_units_targets_files,
+       prepare_associated_special_units_targets,
+       new_sectioning_command_target, set_root_commands_targets_node_files,
+       prepare_index_entries_targets, prepare_footnotes_targets,
+       heading_commands_list, set_heading_commands_targets,
+       check_targets_order, sort_cmd_targets and
+       html_prepare_conversion_units_targets to html_prepare_converter.c.
+       duplicate compare_footnote_id and compare_element_target.
+
 2024-08-14  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/XS/convert/convert_html.c (html_run_stage_handlers):
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index b13ba13a17..9670d4e42d 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -689,217 +689,13 @@ html_special_unit_info (const CONVERTER *self,
   return self->special_unit_info[type][i];
 }
 
-/* used for diverse elements: tree units, indices, footnotes, special
-  elements, contents elements... */
-static HTML_TARGET *
-add_element_target_to_list (HTML_TARGET_LIST *targets,
-                            const ELEMENT *element, const char *target)
-{
-  HTML_TARGET *element_target;
-
-  if (targets->number == targets->space)
-    {
-      targets->list = realloc (targets->list,
-                   sizeof (HTML_TARGET) * (targets->space += 5));
-    }
-  element_target = &targets->list[targets->number];
-  memset (element_target, 0, sizeof (HTML_TARGET));
-  element_target->element = element;
-  if (target)
-    element_target->target = strdup (target);
-
-  targets->number++;
-  return element_target;
-}
-
-/* setup a list per command id.  Note that elements associated to targets
-   without cmd are all associated to 0.  This is the case for the special
-   units associated elements with type ET_special_unit_element and cmd 0 */
-static HTML_TARGET *
-add_element_target (CONVERTER *self, const ELEMENT *element,
-                    const char *target)
-{
-  enum command_id cmd = element_builtin_cmd (element);
-  HTML_TARGET_LIST *targets = &self->html_targets[cmd];
-  return add_element_target_to_list (targets, element, target);
-}
-
-static HTML_TARGET *
-add_special_target (CONVERTER *self, enum special_target_type type,
-                    const ELEMENT *element, const char *target)
-{
-  HTML_TARGET_LIST *targets = &self->html_special_targets[type];
-  return add_element_target_to_list (targets, element, target);
-}
-
 
 static const enum command_id conf_for_documentlanguage[]
                           = {CM_documentlanguage, 0};
 
 
-/* calls customization function requiring output units */
-void
-set_special_units_targets_files (CONVERTER *self, const char *document_name)
-{
-  size_t i;
-  TEXT text_name;
-  OUTPUT_UNIT_LIST *special_units = retrieve_output_units
-    (self->document, self->output_units_descriptors[OUDT_special_units]);
-
-  char *extension = "";
-  if (self->conf->EXTENSION.o.string)
-    extension = self->conf->EXTENSION.o.string;
-
-  text_init (&text_name);
-
-  for (i = 0; i < special_units->number; i++)
-    {
-      TARGET_FILENAME *target_filename;
-      char *default_filename = 0;
-      char *filename = 0;
-      OUTPUT_UNIT *special_unit = special_units->list[i];
-      const char *special_unit_variety = special_unit->special_unit_variety;
-
-      /* refers to self->special_unit_info */
-      const char *target = html_special_unit_info (self, SUI_type_target,
-                                                   special_unit_variety);
-
-      if (!target)
-        continue;
-
-      if (((self->conf->SPLIT.o.string && strlen (self->conf->SPLIT.o.string))
-           || self->conf->MONOLITHIC.o.integer <= 0)
-    /* in general document_name not defined means called through convert */
-          && document_name)
-        {
-          const char *special_unit_file_string
-            = html_special_unit_info (self, SUI_type_file_string,
-                                      special_unit_variety);
-          text_reset (&text_name);
-          if (!special_unit_file_string)
-            special_unit_file_string = "";
-          text_append (&text_name, document_name);
-          text_append (&text_name, special_unit_file_string);
-          if (extension && strlen (extension))
-            {
-              text_append (&text_name, ".");
-              text_append (&text_name, extension);
-            }
-          default_filename = strdup (text_name.text);
-        }
-      target_filename = call_file_id_setting_special_unit_target_file_name (
-                               self, special_unit, target, default_filename);
-      if (target_filename)
-        {
-          if (target_filename->target)
-            target = target_filename->target;
-          if (target_filename->filename)
-            {
-              filename = target_filename->filename;
-              free (default_filename);
-            }
-          else
-            filename = default_filename;
-        }
-      else
-        filename = default_filename;
-
-      if (self->conf->DEBUG.o.integer > 0)
-        {
-          const char *fileout = filename;
-          if (!fileout)
-            fileout = "UNDEF";
-          fprintf (stderr, "Add special %s: target %s,\n    filename %s\n",
-                            special_unit_variety, target, fileout);
-        }
-
-      HTML_TARGET *element_target
-        = add_element_target (self, special_unit->uc.special_unit_command,
-                              target);
-      element_target->special_unit_filename = filename;
-      html_register_id (self, target);
-
-      if (target_filename)
-        {
-          if (target_filename->target)
-            free (target_filename->target);
-
-          free (target_filename);
-        }
-    }
-  free (text_name.text);
-}
-
-/* calls customization function requiring output units */
-static void
-prepare_associated_special_units_targets (CONVERTER *self)
-{
-  OUTPUT_UNIT_LIST *associated_special_units = retrieve_output_units
-   (self->document,
-    self->output_units_descriptors[OUDT_associated_special_units]);
-
-  if (associated_special_units && associated_special_units->number > 0)
-    {
-      size_t i;
-      for (i = 0; i < associated_special_units->number; i++)
-        {
-          HTML_TARGET *element_target;
-          TARGET_FILENAME *target_filename;
-          char *filename = 0;
-          OUTPUT_UNIT *special_unit = associated_special_units->list[i];
-          char *special_unit_variety = special_unit->special_unit_variety;
-
-          /* it may be undef'ined in user customization code */
-          const char *target = html_special_unit_info (self, SUI_type_target,
-                                                       special_unit_variety);
-          target_filename
-            = call_file_id_setting_special_unit_target_file_name (
-                               self, special_unit, target, filename);
-          if (target_filename)
-            {
-              if (target_filename->target)
-                target = target_filename->target;
-              if (target_filename->filename)
-                filename = target_filename->filename;
-            }
-
-          if (self->conf->DEBUG.o.integer > 0)
-            {
-              const char *str_filename;
-              const char *str_target;
-              if (filename)
-                str_filename = filename;
-              else
-                str_filename = "UNDEF (default)";
-              if (target)
-                str_target = target;
-              else
-                str_target = "UNDEF";
-              fprintf (stderr, "Add content %s: target %s,\n"
-                                "    filename %s\n", special_unit_variety,
-                                str_target, str_filename);
-            }
-          element_target
-           = add_element_target (self, special_unit->uc.special_unit_command,
-             target);
-          if (target)
-            html_register_id (self, target);
-          if (filename)
-            element_target->special_unit_filename = filename;
-
-          if (target_filename)
-            {
-              if (target_filename->target)
-                free (target_filename->target);
-
-              free (target_filename);
-            }
-        }
-    }
-}
-
-static char *
-normalized_to_id (const char *id)
+char *
+html_normalized_to_id (const char *id)
 {
   if (isascii_digit (id[0]) || id[0] == '_')
     {
@@ -911,9 +707,9 @@ normalized_to_id (const char *id)
 }
 
 /* calls customization function requiring elements */
-static TARGET_FILENAME *
-normalized_label_id_file (CONVERTER *self, const char *normalized,
-                          const ELEMENT* label_element)
+TARGET_FILENAME *
+html_normalized_label_id_file (CONVERTER *self, const char *normalized,
+                               const ELEMENT* label_element)
 {
   int called;
   char *target = 0;
@@ -925,14 +721,14 @@ normalized_label_id_file (CONVERTER *self, const char 
*normalized,
   if (normalized)
     {
       normalized_label = strdup (normalized);
-      target = normalized_to_id (normalized);
+      target = html_normalized_to_id (normalized);
     }
   else if (label_element)
     {
       normalized_label
        = convert_contents_to_identifier (label_element);
       if (normalized_label)
-        target = normalized_to_id (normalized_label);
+        target = html_normalized_to_id (normalized_label);
     }
 
   if (!target)
@@ -958,246 +754,6 @@ normalized_label_id_file (CONVERTER *self, const char 
*normalized,
   return target_filename;
 }
 
-static char *
-unique_target (CONVERTER *self, const char *target_base)
-{
-  int nr = 1;
-  char *target = strdup (target_base);
-  while (1)
-    {
-      if (html_id_is_registered (self, target))
-        {
-          free (target);
-          xasprintf (&target, "%s-%d", target_base, nr);
-          nr++;
-          if (nr == 0)
-            fatal ("overflow");
-        }
-      else
-        return target;
-    }
-}
-
-/* calls customization function requiring elements */
-static void
-new_sectioning_command_target (CONVERTER *self, const ELEMENT *command)
-{
-  char *normalized_name;
-  char *filename;
-  char *target_base;
-  char *target;
-  char *target_contents = 0;
-  char *target_shortcontents = 0;
-  TARGET_CONTENTS_FILENAME *target_contents_filename;
-
-  TARGET_FILENAME *target_filename
-    = normalized_sectioning_command_filename (self, command);
-
-  /* should not be needed for a sectioning command, as it should not
-     be possible for that command to be a user-defined command,
-     but it is better to be consistent, and it may change in the future */
-  enum command_id data_cmd = element_builtin_data_cmd (command);
-  unsigned long flags = builtin_command_data[data_cmd].flags;
-
-  normalized_name = target_filename->target;
-  filename = target_filename->filename;
-
-  free (target_filename);
-
-  target_base = normalized_to_id (normalized_name);
-
-  if (!strlen (target_base) && command->e.c->cmd == CM_top)
-    {
-      /* @top is allowed to be empty.  In that case it gets this target name */
-      free (target_base);
-      target_base = strdup ("SEC_Top");
-      free (normalized_name);
-      normalized_name = strdup (target_base);
-    }
-
-  if (strlen (target_base))
-    target = unique_target (self, target_base);
-  else
-    target = strdup ("");
-
-  free (target_base);
-
-  if (strlen (target)
-      && (flags & CF_sectioning_heading))
-    {
-      char *target_base_contents;
-      char *target_base_shortcontents;
-      xasprintf (&target_base_contents, "toc-%s", normalized_name);
-      target_contents = unique_target (self, target_base_contents);
-      free (target_base_contents);
-
-      xasprintf (&target_base_shortcontents, "stoc-%s", normalized_name);
-      target_shortcontents = unique_target (self, target_base_shortcontents);
-      free (target_base_shortcontents);
-    }
-
-  free (normalized_name);
-
-  target_contents_filename
-    = call_file_id_setting_sectioning_command_target_name (self, command,
-                  target, target_contents, target_shortcontents, filename);
-  if (target_contents_filename)
-    {
-      free (target);
-      target = target_contents_filename->target;
-      free (filename);
-      filename = target_contents_filename->filename;
-      free (target_contents);
-      target_contents = target_contents_filename->target_contents;
-      free (target_shortcontents);
-      target_shortcontents = target_contents_filename->target_shortcontents;
-
-      free (target_contents_filename);
-    }
-
-  if (self->conf->DEBUG.o.integer > 0)
-    {
-      const char *command_name = element_command_name (command);
-      fprintf (stderr, "XS|Register %s %s\n", command_name, target);
-    }
-
-  HTML_TARGET *element_target
-    = add_element_target (self, command, target);
-  element_target->section_filename = filename;
-  html_register_id (self, target);
-
-  free (target);
-
-  if (target_contents)
-    {
-      element_target->contents_target = target_contents;
-      html_register_id (self, target_contents);
-    }
-  else
-    element_target->contents_target = strdup ("");
-
-  if (target_shortcontents)
-    {
-      element_target->shortcontents_target = target_shortcontents;
-      html_register_id (self, target_shortcontents);
-    }
-  else
-    element_target->shortcontents_target = strdup ("");
-}
-
-/* calls customization function requiring elements */
-/*
- This set with two different codes
-  * the target information, id and normalized filename of 'identifiers_target',
-    ie everything that may be the target of a ref, @node, @float label,
-    @anchor.
-  * The target information of sectioning elements
- @node and section commands targets are therefore both set.
-
- conversion to HTML is done on-demand, upon call to command_text
- and similar functions.
- Note that 'node_filename', which is set here for Top target information
- too, is not used later for Top anchors or links, see the NOTE below
- associated with setting TOP_NODE_FILE_TARGET.
- */
-void
-set_root_commands_targets_node_files (CONVERTER *self)
-{
-
-  if (self->document->identifiers_target.number > 0)
-    {
-      const char *extension = 0;
-
-      if (self->conf->EXTENSION.o.string)
-        extension = self->conf->EXTENSION.o.string;
-      /* use labels_list and not identifiers_target to process in the
-         document order */
-      const LABEL_LIST *label_targets = &self->document->labels_list;
-      size_t i;
-      for (i = 0; i < label_targets->number; i++)
-        {
-          int called = 0;
-          char *target;
-          char *node_filename;
-          char *user_node_filename;
-          const ELEMENT *label_element;
-          const ELEMENT *target_element;
-          LABEL *label = &label_targets->list[i];
-
-          if (!label->identifier || label->reference)
-            continue;
-
-          target_element = label->element;
-          label_element = get_label_element (target_element);
-
-          TARGET_FILENAME *target_filename =
-           normalized_label_id_file (self, label->identifier, label_element);
-          target = target_filename->target;
-          if (extension)
-            xasprintf (&node_filename, "%s.%s", target_filename->filename,
-                                                extension);
-          else
-            node_filename = strdup (target_filename->filename);
-
-          free (target_filename->filename);
-          free (target_filename);
-
-          /* a non defined filename is ok if called with convert, but not
-             if output in files.  We reset if undef, silently unless verbose
-             in case called by convert. */
-
-          user_node_filename = call_file_id_setting_node_file_name (self,
-                                               target_element, node_filename,
-                                               &called);
-          if (user_node_filename)
-            {
-              free (node_filename);
-              node_filename = user_node_filename;
-            }
-          else if (called)
-            {
-              if (self->conf->VERBOSE.o.integer > 0)
-                {
-                  message_list_document_warn (&self->error_messages, 
self->conf,
-                             0, "user-defined node file name not set for `%s'",
-                             node_filename);
-                }
-              else if (self->conf->DEBUG.o.integer > 0)
-                {
-                  fprintf (stderr,
-                     "user-defined node file name undef for `%s'\n",
-                       node_filename);
-                }
-            }
-
-          if (self->conf->DEBUG.o.integer > 0)
-            {
-              const char *command_name = element_command_name (target_element);
-              fprintf (stderr, "Label @%s %s, %s\n", command_name, target,
-                               node_filename);
-            }
-
-          HTML_TARGET *element_target
-            = add_element_target (self, target_element, target);
-          element_target->node_filename = node_filename;
-          html_register_id (self, target);
-
-          free (target);
-        }
-    }
-
-  if (self->document->sections_list)
-    {
-      const CONST_ELEMENT_LIST *sections_list = self->document->sections_list;
-      size_t i;
-      for (i = 0; i < sections_list->number; i++)
-        {
-          const ELEMENT *root_element = sections_list->list[i];
-          new_sectioning_command_target (self, root_element);
-        }
-    }
-}
-
 int
 html_run_stage_handlers (CONVERTER *self,
                          enum html_stage_handler_stage_type stage)
@@ -1939,7 +1495,7 @@ external_node_href (CONVERTER *self, const ELEMENT 
*external_node,
                                                   AI_key_manual_content);
 
   TARGET_FILENAME *target_filename =
-    normalized_label_id_file (self, normalized, node_contents);
+    html_normalized_label_id_file (self, normalized, node_contents);
 
   /* always undef if conversion is called through convert() */
   if (self->conf->EXTERNAL_CROSSREF_SPLIT.o.string
@@ -3251,544 +2807,103 @@ collect_css_element_class (CONVERTER *self, const 
char *selector)
       size_t i;
       size_t css_files_index;
       CSS_LIST *page_css_list;
-      if (self->document_global_context)
-        {
-          css_files_index = 0;
-        }
-      else
-        {
-          css_files_index = self->current_filename.file_number;
-          /* files not associated to output units.  Only try the
-             last one, as the files should be processed sequentially */
-          if (css_files_index == 0)
-            {
-              if (self->current_filename.filename)
-                {
-                  if (self->page_css.number > 1)
-                    {
-                      CSS_LIST *last_css_page
-                       = &self->page_css.list[self->page_css.number -1];
-                      if (last_css_page->page_name
-                          && !strcmp (self->current_filename.filename,
-                                   last_css_page->page_name))
-                        {
-                          css_files_index = self->page_css.number -1;
-                        }
-                    }
-                  if (css_files_index == 0)
-                    {
-                      add_new_css_page (&self->page_css,
-                                        self->current_filename.filename);
-                      css_files_index = self->page_css.number -1;
-                    }
-                }
-            }
-          if (css_files_index == 0)
-            {
-              fprintf (stderr, "BUG: %s: CSS no current file\n", selector);
-              return;
-            }
-        }
-      page_css_list = &self->page_css.list[css_files_index];
-      for (i = 0; i < page_css_list->number; i++)
-        {
-          if (!strcmp (page_css_list->list[i], selector))
-            return;
-        }
-      if (page_css_list->number == page_css_list->space)
-        {
-          page_css_list->list
-            = realloc (page_css_list->list,
-                   (page_css_list->space += 5) * sizeof (char *));
-        }
-      page_css_list->list[page_css_list->number] = strdup (selector);
-      page_css_list->number++;
-    }
-}
-
-void
-close_html_lone_element (const CONVERTER *self, TEXT *result)
-{
-  if (self->conf->USE_XML_SYNTAX.o.integer > 0)
-    text_append_n (result, "/>", 2);
-  else
-    text_append_n (result, ">", 1);
-}
-
-static char *
-protect_class_name (const char *class_name)
-{
-  TEXT result;
-  TEXT space_protected;
-  text_init (&result);
-  text_init (&space_protected);
-  const char *p = class_name;
-  while (*p)
-    {
-      int n = strcspn (p, " ");
-      if (n)
-        {
-          text_append_n (&space_protected, p, n);
-          p += n;
-        }
-      if (*p)
-        {
-          int n = strspn (p, " ");
-          if (n)
-            {
-              int i;
-              for (i = 0; i < n; i++)
-                text_append_n (&space_protected, "-", 1);
-              p += n;
-            }
-        }
-    }
-
-  /* do not use the customization API as in perl */
-  html_default_format_protect_text (space_protected.text, &result);
-  free (space_protected.text);
-  return result.text;
-}
-
-char *
-html_attribute_class (CONVERTER *self, const char *element,
-                      const STRING_LIST *classes)
-{
-  TEXT result;
-  char *style = 0;
-  size_t i;
-  int class_nr = 0;
-  if (!classes  || classes->number <= 0
-      || self->conf->NO_CSS.o.integer > 0)
-    {
-      if (!strcmp (element, "span"))
-        return strdup ("");
-      else
-        {
-          char *result;
-          xasprintf (&result, "<%s", element);
-          return result;
-        }
-    }
-
-  if (self->conf->INLINE_CSS_STYLE.o.integer > 0)
-    {
-      size_t i;
-      TEXT inline_styles;
-      text_init (&inline_styles);
-      int style_nr = 0;
-      for (i = 0; i < classes->number; i++)
-        {
-          const char *style_class = classes->list[i];
-          char *selector;
-          const CSS_SELECTOR_STYLE *selector_style;
-
-          xasprintf (&selector, "%s.%s", element, style_class);
-          selector_style
-            = find_css_selector_style (&self->css_element_class_styles,
-                                       selector);
-          free (selector);
-          if (selector_style && selector_style->style)
-            {
-              if (style_nr)
-                 text_printf (&inline_styles, ";%s", selector_style->style);
-              else
-                 text_append (&inline_styles, selector_style->style);
-              style_nr++;
-            }
-        }
-      if (inline_styles.end)
-        {
-          xasprintf (&style, " style=\"%s\"", inline_styles.text);
-        }
-      free (inline_styles.text);
-    }
-  else
-    {
-      size_t i;
-      for (i = 0; i < classes->number; i++)
-        {
-          const char *style_class = classes->list[i];
-          char *selector;
-
-          xasprintf (&selector, "%s.%s", element, style_class);
-          collect_css_element_class (self, selector);
-          free (selector);
-        }
-    }
-  text_init (&result);
-  text_printf (&result, "<%s class=\"", element);
-  for (i = 0; i < classes->number; i++)
-    {
-      const char *class_name = classes->list[i];
-      char *protected_class = protect_class_name (class_name);
-      if (class_nr)
-        text_printf (&result, " %s", protected_class);
-      else
-        text_append (&result, protected_class);
-      free (protected_class);
-      class_nr++;
-    }
-  text_append_n (&result, "\"", 1);
-  if (style)
-    {
-      text_append (&result, style);
-      free (style);
-    }
-  return result.text;
-}
-
-static char *copiable_link_array[] = {"copiable-link"};
-static const STRING_LIST copiable_link_classes = {copiable_link_array, 1, 1};
-
-static char *
-get_copiable_anchor (CONVERTER *self, const char *id)
-{
-  if (id && strlen (id) && self->conf->COPIABLE_LINKS.o.integer > 0)
-    {
-      TEXT result;
-      char *attribute_class = html_attribute_class (self, "a",
-                                                    &copiable_link_classes);
-      text_init (&result);
-      text_append (&result, attribute_class);
-      free (attribute_class);
-      text_printf (&result, " href=\"#%s\"> %s</a>",
-                   id, self->special_character[SC_paragraph_symbol].string);
-      return result.text;
-    }
-  return 0;
-}
-
-void
-prepare_index_entries_targets (CONVERTER *self)
-{
-  if (self->document->indices_info.number > 0)
-    {
-      size_t i;
-      self->shared_conversion_state.formatted_index_entries
-        = (int **) malloc (self->sorted_index_names.number * sizeof (int *));
-      for (i = 0; i < self->sorted_index_names.number; i++)
-        {
-          size_t j;
-          const INDEX *idx = self->sorted_index_names.list[i];
-          /* no need to test for idx->entries_number > 0 as indices without
-             entries are not kept in sorted_index_names. */
-          self->shared_conversion_state.formatted_index_entries[i]
-            = (int *) malloc (idx->entries_number * sizeof (int));
-          memset (self->shared_conversion_state.formatted_index_entries[i],
-                  0, idx->entries_number * sizeof (int));
-          for (j = 0; j < idx->entries_number; j++)
-            {
-              INDEX_ENTRY *index_entry;
-              const ELEMENT *main_entry_element;
-              const ELEMENT *seeentry;
-              const ELEMENT *seealso;
-              ELEMENT *entry_reference_content_element;
-              ELEMENT *normalize_index_element;
-              ELEMENT_LIST *subentries_tree;
-              const ELEMENT *target_element;
-              TEXT target_base;
-              char *normalized_index;
-              char *region = 0;
-              char *target;
-
-              index_entry = &idx->index_entries[j];
-              main_entry_element = index_entry->entry_element;
-              seeentry = lookup_extra_element (main_entry_element,
-                                               AI_key_seeentry);
-              if (seeentry)
-                continue;
-              seealso = lookup_extra_element (main_entry_element,
-                                              AI_key_seealso);
-              if (seealso)
-                continue;
-
-              region = lookup_extra_string (main_entry_element,
-                                            AI_key_element_region);
-              entry_reference_content_element
-               = index_content_element (main_entry_element, 1);
-        /* construct element to convert to a normalized identifier to use as
-           hrefs target */
-              normalize_index_element = new_element (ET_NONE);
-              add_to_contents_as_array (normalize_index_element,
-                                        entry_reference_content_element);
-
-              subentries_tree
-               = comma_index_subentries_tree (main_entry_element, " ");
-              if (subentries_tree)
-                {
-                  insert_list_slice_into_contents (normalize_index_element,
-                                   
normalize_index_element->e.c->contents.number,
-                                   subentries_tree, 0,
-                                   subentries_tree->number);
-                }
-              normalized_index
-                = normalize_transliterate_texinfo (normalize_index_element,
-                                            (self->conf->TEST.o.integer > 0));
-
-              destroy_element (normalize_index_element);
-              if (subentries_tree)
-                free_comma_index_subentries_tree (subentries_tree);
-
-              text_init (&target_base);
-              text_append (&target_base, "index-");
-              if (region)
-                {
-                  text_append (&target_base, region);
-                  text_append (&target_base, "-");
-                }
-              text_append (&target_base, normalized_index);
-              free (normalized_index);
-              target = unique_target (self, target_base.text);
-              free (target_base.text);
-              if (index_entry->entry_associated_element)
-                target_element = index_entry->entry_associated_element;
-              else
-                target_element = main_entry_element;
-
-              add_element_target (self, target_element, target);
-              html_register_id (self, target);
-
-              free (target);
-            }
-        }
-    }
-}
-
-static int
-compare_footnote_id (const void *a, const void *b)
-{
-  const FOOTNOTE_ID_NUMBER *fid_a = (const FOOTNOTE_ID_NUMBER *) a;
-  const FOOTNOTE_ID_NUMBER *fid_b = (const FOOTNOTE_ID_NUMBER *) b;
-
-  return strcmp (fid_a->footnote_id, fid_b->footnote_id);
-}
-
-FOOTNOTE_ID_NUMBER *
-find_footnote_id_number (const CONVERTER *self, const char *footnote_id)
-{
-  const ELEMENT_LIST *global_footnotes
-    = &self->document->global_commands.footnotes;
-
-  FOOTNOTE_ID_NUMBER *result = 0;
-  static FOOTNOTE_ID_NUMBER searched_footnote_id;
-  searched_footnote_id.footnote_id = footnote_id;
-  if (global_footnotes->number == 0)
-    {
-      char *msg;
-      xasprintf (&msg, "no footnotes, searching for '%s'\n", footnote_id);
-      fatal (msg);
-      free (msg);
-    }
-
-  result = (FOOTNOTE_ID_NUMBER *) bsearch (&searched_footnote_id,
-                self->shared_conversion_state.footnote_id_numbers,
-                global_footnotes->number, sizeof (FOOTNOTE_ID_NUMBER),
-                compare_footnote_id);
-  return result;
-}
-
-static const char *footid_base = "FOOT";
-static const char *docid_base = "DOCF";
-
-static void
-prepare_footnotes_targets (CONVERTER *self)
-{
-  const ELEMENT_LIST *global_footnotes
-    = &self->document->global_commands.footnotes;
-  if (global_footnotes->number > 0)
-    {
-      size_t i;
-      self->shared_conversion_state.footnote_id_numbers
-        = (FOOTNOTE_ID_NUMBER *) malloc (global_footnotes->number *
-                                         sizeof (FOOTNOTE_ID_NUMBER));
-      for (i = 0; i < global_footnotes->number; i++)
-        {
-          const HTML_TARGET *element_target;
-          const ELEMENT *footnote = global_footnotes->list[i];
-          TEXT footid;
-          TEXT docid;
-          int nr = i+1;
-
-          text_init (&footid);
-          text_init (&docid);
-          text_printf (&footid, "%s%d", footid_base, nr);
-          text_printf (&docid, "%s%d", docid_base, nr);
-
-          while (1)
+      if (self->document_global_context)
+        {
+          css_files_index = 0;
+        }
+      else
+        {
+          css_files_index = self->current_filename.file_number;
+          /* files not associated to output units.  Only try the
+             last one, as the files should be processed sequentially */
+          if (css_files_index == 0)
             {
-              if (html_id_is_registered (self, footid.text)
-                    || html_id_is_registered (self, docid.text))
+              if (self->current_filename.filename)
                 {
-                  nr++;
-                  if (nr == 0)
-                    fatal ("overflow footnote target nr");
-
-                  text_init (&footid);
-                  text_init (&docid);
-                  text_printf (&footid, "%s%d", footid_base, nr);
-                  text_printf (&docid, "%s%d", docid_base, nr);
+                  if (self->page_css.number > 1)
+                    {
+                      CSS_LIST *last_css_page
+                       = &self->page_css.list[self->page_css.number -1];
+                      if (last_css_page->page_name
+                          && !strcmp (self->current_filename.filename,
+                                   last_css_page->page_name))
+                        {
+                          css_files_index = self->page_css.number -1;
+                        }
+                    }
+                  if (css_files_index == 0)
+                    {
+                      add_new_css_page (&self->page_css,
+                                        self->current_filename.filename);
+                      css_files_index = self->page_css.number -1;
+                    }
                 }
-              else
-                break;
             }
-          html_register_id (self, footid.text);
-          html_register_id (self, docid.text);
-
-          element_target = add_element_target (self, footnote, footid.text);
-          add_special_target (self, ST_footnote_location, footnote,
-                              docid.text);
-
-          if (self->conf->DEBUG.o.integer > 0)
+          if (css_files_index == 0)
             {
-              char *footnote_txi = convert_to_texinfo (footnote);
-              fprintf (stderr, "Enter footnote: target %s, nr %d\n%s\n",
-                       footid.text, nr, footnote_txi);
-              free (footnote_txi);
+              fprintf (stderr, "BUG: %s: CSS no current file\n", selector);
+              return;
             }
-          self->shared_conversion_state.footnote_id_numbers[i].footnote_id
-             = element_target->target;
-          self->shared_conversion_state.footnote_id_numbers[i].number = 0;
-          free (footid.text);
-          free (docid.text);
         }
-      qsort (self->shared_conversion_state.footnote_id_numbers,
-             global_footnotes->number,
-             sizeof (FOOTNOTE_ID_NUMBER), compare_footnote_id);
-    }
-}
-
-/* keep the command names sorted alphabetically to match order in perl */
-static const enum command_id heading_commands_list[] = {
-  CM_chapheading, CM_heading, CM_majorheading, CM_subheading, CM_subsubheading,
-  0,
-};
-
-/* indirectly calls customization function requiring elements */
-void
-set_heading_commands_targets (CONVERTER *self)
-{
-  int i;
-  for (i = 0; heading_commands_list[i]; i++)
-    {
-      enum command_id cmd = heading_commands_list[i];
-      const ELEMENT_LIST *global_command
-        = get_cmd_global_multi_command (&self->document->global_commands, cmd);
-
-      if (global_command->number > 0)
+      page_css_list = &self->page_css.list[css_files_index];
+      for (i = 0; i < page_css_list->number; i++)
         {
-          size_t j;
-          for (j = 0; j < global_command->number; j++)
-            {
-              const ELEMENT *command = global_command->list[j];
-              new_sectioning_command_target (self, command);
-            }
+          if (!strcmp (page_css_list->list[i], selector))
+            return;
         }
-    }
-}
-
-/* For debug/check/optimization
-   used to check to what extent the targets are already ordered.
-   Return the number of elements ordered ok with respect to the
-   previous element
- */
-size_t
-check_targets_order (enum command_id cmd, HTML_TARGET_LIST *element_targets)
-{
-  size_t i;
-  size_t result = 0;
-  if (element_targets->number <= 1)
-    return result;
-  for (i = 1; i < element_targets->number; i++)
-    {
-      if (compare_element_target (&element_targets->list[i-1],
-                                  &element_targets->list[i]) > 0)
+      if (page_css_list->number == page_css_list->space)
         {
-          fprintf (stderr, "no %s %zu %ld %p %s %zu %ld %p %s\n",
-           builtin_command_name (cmd), i-1,
-           (uintptr_t)element_targets->list[i-1].element,
-           element_targets->list[i-1].element, 
element_targets->list[i-1].target,
-           i, (uintptr_t)element_targets->list[i].element,
-           element_targets->list[i].element, element_targets->list[i].target);
+          page_css_list->list
+            = realloc (page_css_list->list,
+                   (page_css_list->space += 5) * sizeof (char *));
         }
-      else
-        result++;
+      page_css_list->list[page_css_list->number] = strdup (selector);
+      page_css_list->number++;
     }
-  return result;
 }
 
-/* It may not be efficient to sort and find back with bsearch if there is
-   a small number of elements.  However, some target elements are more
-   likely to already be ordered when they are accessed in their order of
-   appearance in the document.  There is no guarantee, as it is only in the
-   same array that adresses are guaranteed to be increasing.  A check done
-   in 2024 with gcc, using check_targets_order, and also looking at the
-   address of newly allocated elements shows that elements are
-   not that much allocated in order.  However, overall, the addresses are
-   more in order when elements are accessed in the document order.
-   For indices, it is not really possible to get them in document order,
-   within an index they are in document order, but not across indices.
-   The other data are in document order, for nodes and similar because
-   the labels list is used instead of identifiers_target on purpose.
- */
 void
-sort_cmd_targets (CONVERTER *self)
+close_html_lone_element (const CONVERTER *self, TEXT *result)
 {
-  enum command_id cmd;
-  int type;
+  if (self->conf->USE_XML_SYNTAX.o.integer > 0)
+    text_append_n (result, "/>", 2);
+  else
+    text_append_n (result, ">", 1);
+}
 
-  for (cmd = 0; cmd < BUILTIN_CMD_NUMBER; cmd++)
+static char *
+protect_class_name (const char *class_name)
+{
+  TEXT result;
+  TEXT space_protected;
+  text_init (&result);
+  text_init (&space_protected);
+  const char *p = class_name;
+  while (*p)
     {
-      if (self->html_targets[cmd].number > 0)
+      int n = strcspn (p, " ");
+      if (n)
         {
-          HTML_TARGET_LIST *element_targets = &self->html_targets[cmd];
-           /* to check the order
-          size_t ordered_items = check_targets_order (cmd, element_targets);
-          fprintf (stderr, "ORDER %s %zu / %zu\n", builtin_command_name (cmd),
-                   ordered_items, element_targets->number -1);
-            */
-          qsort (element_targets->list,
-                 element_targets->number,
-                 sizeof (HTML_TARGET), compare_element_target);
-          push_command (&self->html_target_cmds, cmd);
+          text_append_n (&space_protected, p, n);
+          p += n;
         }
-    }
-  for (type = 0; type < ST_footnote_location+1; type++)
-    {
-     if (self->html_special_targets[type].number > 0)
+      if (*p)
         {
-          HTML_TARGET_LIST *element_targets = 
&self->html_special_targets[type];
-          qsort (element_targets->list,
-                 element_targets->number,
-                 sizeof (HTML_TARGET), compare_element_target);
+          int n = strspn (p, " ");
+          if (n)
+            {
+              int i;
+              for (i = 0; i < n; i++)
+                text_append_n (&space_protected, "-", 1);
+              p += n;
+            }
         }
     }
-}
-
-/* indirectly calls all the functions calling customization function
-   requiring elements and output units except for external nodes formatting */
-/* for conversion units except for associated special units that require
-   files for document units to be set */
-void
-html_prepare_conversion_units_targets (CONVERTER *self,
-                                       const char *document_name)
-{
-  /*
-   Do that before the other elements, to be sure that special page ids
-   are registered before elements id are.
-   */
-  set_special_units_targets_files (self, document_name);
-
-  prepare_associated_special_units_targets (self);
-
-  set_root_commands_targets_node_files (self);
 
-  prepare_index_entries_targets (self);
-  prepare_footnotes_targets (self);
-
-  set_heading_commands_targets (self);
-
-  sort_cmd_targets (self);
+  /* do not use the customization API as in perl */
+  html_default_format_protect_text (space_protected.text, &result);
+  free (space_protected.text);
+  return result.text;
 }
 
 /* Associate output units to the global targets, First, Last, Top, Index.
@@ -4723,6 +3838,94 @@ html_prepare_units_directions_files (CONVERTER *self,
   return files_source_info;
 }
 
+char *
+html_attribute_class (CONVERTER *self, const char *element,
+                      const STRING_LIST *classes)
+{
+  TEXT result;
+  char *style = 0;
+  size_t i;
+  int class_nr = 0;
+  if (!classes  || classes->number <= 0
+      || self->conf->NO_CSS.o.integer > 0)
+    {
+      if (!strcmp (element, "span"))
+        return strdup ("");
+      else
+        {
+          char *result;
+          xasprintf (&result, "<%s", element);
+          return result;
+        }
+    }
+
+  if (self->conf->INLINE_CSS_STYLE.o.integer > 0)
+    {
+      size_t i;
+      TEXT inline_styles;
+      text_init (&inline_styles);
+      int style_nr = 0;
+      for (i = 0; i < classes->number; i++)
+        {
+          const char *style_class = classes->list[i];
+          char *selector;
+          const CSS_SELECTOR_STYLE *selector_style;
+
+          xasprintf (&selector, "%s.%s", element, style_class);
+          selector_style
+            = find_css_selector_style (&self->css_element_class_styles,
+                                       selector);
+          free (selector);
+          if (selector_style && selector_style->style)
+            {
+              if (style_nr)
+                 text_printf (&inline_styles, ";%s", selector_style->style);
+              else
+                 text_append (&inline_styles, selector_style->style);
+              style_nr++;
+            }
+        }
+      if (inline_styles.end)
+        {
+          xasprintf (&style, " style=\"%s\"", inline_styles.text);
+        }
+      free (inline_styles.text);
+    }
+  else
+    {
+      size_t i;
+      for (i = 0; i < classes->number; i++)
+        {
+          const char *style_class = classes->list[i];
+          char *selector;
+
+          xasprintf (&selector, "%s.%s", element, style_class);
+          collect_css_element_class (self, selector);
+          free (selector);
+        }
+    }
+  text_init (&result);
+  text_printf (&result, "<%s class=\"", element);
+  for (i = 0; i < classes->number; i++)
+    {
+      const char *class_name = classes->list[i];
+      char *protected_class = protect_class_name (class_name);
+      if (class_nr)
+        text_printf (&result, " %s", protected_class);
+      else
+        text_append (&result, protected_class);
+      free (protected_class);
+      class_nr++;
+    }
+  text_append_n (&result, "\"", 1);
+  if (style)
+    {
+      text_append (&result, style);
+      free (style);
+    }
+  return result.text;
+}
+
 void
 html_default_format_separate_anchor (CONVERTER *self, const char *id,
                                      const char *class, TEXT *result)
@@ -4799,6 +4002,27 @@ direction_a (CONVERTER *self, int direction, const char 
*href,
   return result.text;
 }
 
+static char *copiable_link_array[] = {"copiable-link"};
+static const STRING_LIST copiable_link_classes = {copiable_link_array, 1, 1};
+
+static char *
+get_copiable_anchor (CONVERTER *self, const char *id)
+{
+  if (id && strlen (id) && self->conf->COPIABLE_LINKS.o.integer > 0)
+    {
+      TEXT result;
+      char *attribute_class = html_attribute_class (self, "a",
+                                                    &copiable_link_classes);
+      text_init (&result);
+      text_append (&result, attribute_class);
+      free (attribute_class);
+      text_printf (&result, " href=\"#%s\"> %s</a>",
+                   id, self->special_character[SC_paragraph_symbol].string);
+      return result.text;
+    }
+  return 0;
+}
+
 void
 html_default_format_heading_text (CONVERTER *self, const enum command_id cmd,
                      const STRING_LIST *classes, const char *text,
@@ -7842,6 +7066,39 @@ html_convert_anchor_command (CONVERTER *self, const enum 
command_id cmd,
     }
 }
 
+static int
+compare_footnote_id (const void *a, const void *b)
+{
+  const FOOTNOTE_ID_NUMBER *fid_a = (const FOOTNOTE_ID_NUMBER *) a;
+  const FOOTNOTE_ID_NUMBER *fid_b = (const FOOTNOTE_ID_NUMBER *) b;
+
+  return strcmp (fid_a->footnote_id, fid_b->footnote_id);
+}
+
+FOOTNOTE_ID_NUMBER *
+find_footnote_id_number (const CONVERTER *self, const char *footnote_id)
+{
+  const ELEMENT_LIST *global_footnotes
+    = &self->document->global_commands.footnotes;
+
+  FOOTNOTE_ID_NUMBER *result = 0;
+  static FOOTNOTE_ID_NUMBER searched_footnote_id;
+  searched_footnote_id.footnote_id = footnote_id;
+  if (global_footnotes->number == 0)
+    {
+      char *msg;
+      xasprintf (&msg, "no footnotes, searching for '%s'\n", footnote_id);
+      fatal (msg);
+      free (msg);
+    }
+
+  result = (FOOTNOTE_ID_NUMBER *) bsearch (&searched_footnote_id,
+                self->shared_conversion_state.footnote_id_numbers,
+                global_footnotes->number, sizeof (FOOTNOTE_ID_NUMBER),
+                compare_footnote_id);
+  return result;
+}
+
 void
 html_convert_footnote_command (CONVERTER *self, const enum command_id cmd,
                                const ELEMENT *element,
diff --git a/tp/Texinfo/XS/convert/convert_html.h 
b/tp/Texinfo/XS/convert/convert_html.h
index aeb6a8dd3b..72c5a63c6d 100644
--- a/tp/Texinfo/XS/convert/convert_html.h
+++ b/tp/Texinfo/XS/convert/convert_html.h
@@ -58,6 +58,11 @@ const char *html_special_unit_info (const CONVERTER *self,
                                     enum special_unit_info_type type,
                                     const char *special_unit_variety);
 
+char *html_normalized_to_id (const char *id);
+TARGET_FILENAME *html_normalized_label_id_file (CONVERTER *self,
+                                                const char *normalized,
+                                                const ELEMENT* label_element);
+
 int html_run_stage_handlers (CONVERTER *self,
                              enum html_stage_handler_stage_type stage);
 
@@ -118,9 +123,6 @@ FOOTNOTE_ID_NUMBER *find_footnote_id_number (const 
CONVERTER *self,
 char *html_attribute_class (CONVERTER *self, const char *element,
                             const STRING_LIST *classes);
 
-void html_prepare_conversion_units_targets (CONVERTER *self,
-                                     const char *document_name);
-
 FILE_SOURCE_INFO_LIST * html_prepare_units_directions_files (CONVERTER *self,
           const char *output_file, const char *destination_directory,
           const char *output_filename, const char *document_name);
diff --git a/tp/Texinfo/XS/convert/html_prepare_converter.c 
b/tp/Texinfo/XS/convert/html_prepare_converter.c
index f78c0bfdc3..63669ed549 100644
--- a/tp/Texinfo/XS/convert/html_prepare_converter.c
+++ b/tp/Texinfo/XS/convert/html_prepare_converter.c
@@ -29,6 +29,7 @@
 #include "conversion_data.h"
 /* new_element */
 #include "tree.h"
+#include "extra.h"
 #include "utils.h"
 #include "errors.h"
 /* unicode_character_brace_no_arg_commands */
@@ -36,6 +37,9 @@
 #include "builtin_commands.h"
 #include "command_stack.h"
 #include "customization_options.h"
+#include "convert_to_texinfo.h"
+#include "node_name_normalization.h"
+#include "manipulate_indices.h"
 /* nobrace_symbol_text text_brace_no_arg_commands */
 #include "convert_to_text.h"
 #include "output_unit.h"
@@ -3039,3 +3043,774 @@ html_prepare_conversion_units (CONVERTER *self)
   /* reset to the default */
   set_global_document_commands (self, CL_before, conf_for_special_units);
 }
+
+
+
+/* used for diverse elements: tree units, indices, footnotes, special
+  elements, contents elements... */
+static HTML_TARGET *
+add_element_target_to_list (HTML_TARGET_LIST *targets,
+                            const ELEMENT *element, const char *target)
+{
+  HTML_TARGET *element_target;
+
+  if (targets->number == targets->space)
+    {
+      targets->list = realloc (targets->list,
+                   sizeof (HTML_TARGET) * (targets->space += 5));
+    }
+  element_target = &targets->list[targets->number];
+  memset (element_target, 0, sizeof (HTML_TARGET));
+  element_target->element = element;
+  if (target)
+    element_target->target = strdup (target);
+
+  targets->number++;
+  return element_target;
+}
+
+/* setup a list per command id.  Note that elements associated to targets
+   without cmd are all associated to 0.  This is the case for the special
+   units associated elements with type ET_special_unit_element and cmd 0 */
+static HTML_TARGET *
+add_element_target (CONVERTER *self, const ELEMENT *element,
+                    const char *target)
+{
+  enum command_id cmd = element_builtin_cmd (element);
+  HTML_TARGET_LIST *targets = &self->html_targets[cmd];
+  return add_element_target_to_list (targets, element, target);
+}
+
+static HTML_TARGET *
+add_special_target (CONVERTER *self, enum special_target_type type,
+                    const ELEMENT *element, const char *target)
+{
+  HTML_TARGET_LIST *targets = &self->html_special_targets[type];
+  return add_element_target_to_list (targets, element, target);
+}
+
+static char *
+unique_target (CONVERTER *self, const char *target_base)
+{
+  int nr = 1;
+  char *target = strdup (target_base);
+  while (1)
+    {
+      if (html_id_is_registered (self, target))
+        {
+          free (target);
+          xasprintf (&target, "%s-%d", target_base, nr);
+          nr++;
+          if (nr == 0)
+            fatal ("overflow");
+        }
+      else
+        return target;
+    }
+}
+
+/* calls customization function requiring output units */
+void
+set_special_units_targets_files (CONVERTER *self, const char *document_name)
+{
+  size_t i;
+  TEXT text_name;
+  OUTPUT_UNIT_LIST *special_units = retrieve_output_units
+    (self->document, self->output_units_descriptors[OUDT_special_units]);
+
+  char *extension = "";
+  if (self->conf->EXTENSION.o.string)
+    extension = self->conf->EXTENSION.o.string;
+
+  text_init (&text_name);
+
+  for (i = 0; i < special_units->number; i++)
+    {
+      TARGET_FILENAME *target_filename;
+      char *default_filename = 0;
+      char *filename = 0;
+      OUTPUT_UNIT *special_unit = special_units->list[i];
+      const char *special_unit_variety = special_unit->special_unit_variety;
+
+      /* refers to self->special_unit_info */
+      const char *target = html_special_unit_info (self, SUI_type_target,
+                                                   special_unit_variety);
+
+      if (!target)
+        continue;
+
+      if (((self->conf->SPLIT.o.string && strlen (self->conf->SPLIT.o.string))
+           || self->conf->MONOLITHIC.o.integer <= 0)
+    /* in general document_name not defined means called through convert */
+          && document_name)
+        {
+          const char *special_unit_file_string
+            = html_special_unit_info (self, SUI_type_file_string,
+                                      special_unit_variety);
+          text_reset (&text_name);
+          if (!special_unit_file_string)
+            special_unit_file_string = "";
+          text_append (&text_name, document_name);
+          text_append (&text_name, special_unit_file_string);
+          if (extension && strlen (extension))
+            {
+              text_append (&text_name, ".");
+              text_append (&text_name, extension);
+            }
+          default_filename = strdup (text_name.text);
+        }
+      target_filename = call_file_id_setting_special_unit_target_file_name (
+                               self, special_unit, target, default_filename);
+      if (target_filename)
+        {
+          if (target_filename->target)
+            target = target_filename->target;
+          if (target_filename->filename)
+            {
+              filename = target_filename->filename;
+              free (default_filename);
+            }
+          else
+            filename = default_filename;
+        }
+      else
+        filename = default_filename;
+
+      if (self->conf->DEBUG.o.integer > 0)
+        {
+          const char *fileout = filename;
+          if (!fileout)
+            fileout = "UNDEF";
+          fprintf (stderr, "Add special %s: target %s,\n    filename %s\n",
+                            special_unit_variety, target, fileout);
+        }
+
+      HTML_TARGET *element_target
+        = add_element_target (self, special_unit->uc.special_unit_command,
+                              target);
+      element_target->special_unit_filename = filename;
+      html_register_id (self, target);
+
+      if (target_filename)
+        {
+          if (target_filename->target)
+            free (target_filename->target);
+
+          free (target_filename);
+        }
+    }
+  free (text_name.text);
+}
+
+/* calls customization function requiring output units */
+static void
+prepare_associated_special_units_targets (CONVERTER *self)
+{
+  OUTPUT_UNIT_LIST *associated_special_units = retrieve_output_units
+   (self->document,
+    self->output_units_descriptors[OUDT_associated_special_units]);
+
+  if (associated_special_units && associated_special_units->number > 0)
+    {
+      size_t i;
+      for (i = 0; i < associated_special_units->number; i++)
+        {
+          HTML_TARGET *element_target;
+          TARGET_FILENAME *target_filename;
+          char *filename = 0;
+          OUTPUT_UNIT *special_unit = associated_special_units->list[i];
+          char *special_unit_variety = special_unit->special_unit_variety;
+
+          /* it may be undef'ined in user customization code */
+          const char *target = html_special_unit_info (self, SUI_type_target,
+                                                       special_unit_variety);
+          target_filename
+            = call_file_id_setting_special_unit_target_file_name (
+                               self, special_unit, target, filename);
+          if (target_filename)
+            {
+              if (target_filename->target)
+                target = target_filename->target;
+              if (target_filename->filename)
+                filename = target_filename->filename;
+            }
+
+          if (self->conf->DEBUG.o.integer > 0)
+            {
+              const char *str_filename;
+              const char *str_target;
+              if (filename)
+                str_filename = filename;
+              else
+                str_filename = "UNDEF (default)";
+              if (target)
+                str_target = target;
+              else
+                str_target = "UNDEF";
+              fprintf (stderr, "Add content %s: target %s,\n"
+                                "    filename %s\n", special_unit_variety,
+                                str_target, str_filename);
+            }
+          element_target
+           = add_element_target (self, special_unit->uc.special_unit_command,
+             target);
+          if (target)
+            html_register_id (self, target);
+          if (filename)
+            element_target->special_unit_filename = filename;
+
+          if (target_filename)
+            {
+              if (target_filename->target)
+                free (target_filename->target);
+
+              free (target_filename);
+            }
+        }
+    }
+}
+
+/* calls customization function requiring elements */
+static void
+new_sectioning_command_target (CONVERTER *self, const ELEMENT *command)
+{
+  char *normalized_name;
+  char *filename;
+  char *target_base;
+  char *target;
+  char *target_contents = 0;
+  char *target_shortcontents = 0;
+  TARGET_CONTENTS_FILENAME *target_contents_filename;
+
+  TARGET_FILENAME *target_filename
+    = normalized_sectioning_command_filename (self, command);
+
+  /* should not be needed for a sectioning command, as it should not
+     be possible for that command to be a user-defined command,
+     but it is better to be consistent, and it may change in the future */
+  enum command_id data_cmd = element_builtin_data_cmd (command);
+  unsigned long flags = builtin_command_data[data_cmd].flags;
+
+  normalized_name = target_filename->target;
+  filename = target_filename->filename;
+
+  free (target_filename);
+
+  target_base = html_normalized_to_id (normalized_name);
+
+  if (!strlen (target_base) && command->e.c->cmd == CM_top)
+    {
+      /* @top is allowed to be empty.  In that case it gets this target name */
+      free (target_base);
+      target_base = strdup ("SEC_Top");
+      free (normalized_name);
+      normalized_name = strdup (target_base);
+    }
+
+  if (strlen (target_base))
+    target = unique_target (self, target_base);
+  else
+    target = strdup ("");
+
+  free (target_base);
+
+  if (strlen (target)
+      && (flags & CF_sectioning_heading))
+    {
+      char *target_base_contents;
+      char *target_base_shortcontents;
+      xasprintf (&target_base_contents, "toc-%s", normalized_name);
+      target_contents = unique_target (self, target_base_contents);
+      free (target_base_contents);
+
+      xasprintf (&target_base_shortcontents, "stoc-%s", normalized_name);
+      target_shortcontents = unique_target (self, target_base_shortcontents);
+      free (target_base_shortcontents);
+    }
+
+  free (normalized_name);
+
+  target_contents_filename
+    = call_file_id_setting_sectioning_command_target_name (self, command,
+                  target, target_contents, target_shortcontents, filename);
+  if (target_contents_filename)
+    {
+      free (target);
+      target = target_contents_filename->target;
+      free (filename);
+      filename = target_contents_filename->filename;
+      free (target_contents);
+      target_contents = target_contents_filename->target_contents;
+      free (target_shortcontents);
+      target_shortcontents = target_contents_filename->target_shortcontents;
+
+      free (target_contents_filename);
+    }
+
+  if (self->conf->DEBUG.o.integer > 0)
+    {
+      const char *command_name = element_command_name (command);
+      fprintf (stderr, "XS|Register %s %s\n", command_name, target);
+    }
+
+  HTML_TARGET *element_target
+    = add_element_target (self, command, target);
+  element_target->section_filename = filename;
+  html_register_id (self, target);
+
+  free (target);
+
+  if (target_contents)
+    {
+      element_target->contents_target = target_contents;
+      html_register_id (self, target_contents);
+    }
+  else
+    element_target->contents_target = strdup ("");
+
+  if (target_shortcontents)
+    {
+      element_target->shortcontents_target = target_shortcontents;
+      html_register_id (self, target_shortcontents);
+    }
+  else
+    element_target->shortcontents_target = strdup ("");
+}
+
+/* calls customization function requiring elements */
+/*
+ This set with two different codes
+  * the target information, id and normalized filename of 'identifiers_target',
+    ie everything that may be the target of a ref, @node, @float label,
+    @anchor.
+  * The target information of sectioning elements
+ @node and section commands targets are therefore both set.
+
+ conversion to HTML is done on-demand, upon call to command_text
+ and similar functions.
+ Note that 'node_filename', which is set here for Top target information
+ too, is not used later for Top anchors or links, see the NOTE below
+ associated with setting TOP_NODE_FILE_TARGET.
+ */
+void
+set_root_commands_targets_node_files (CONVERTER *self)
+{
+
+  if (self->document->identifiers_target.number > 0)
+    {
+      const char *extension = 0;
+
+      if (self->conf->EXTENSION.o.string)
+        extension = self->conf->EXTENSION.o.string;
+      /* use labels_list and not identifiers_target to process in the
+         document order */
+      const LABEL_LIST *label_targets = &self->document->labels_list;
+      size_t i;
+      for (i = 0; i < label_targets->number; i++)
+        {
+          int called = 0;
+          char *target;
+          char *node_filename;
+          char *user_node_filename;
+          const ELEMENT *label_element;
+          const ELEMENT *target_element;
+          LABEL *label = &label_targets->list[i];
+
+          if (!label->identifier || label->reference)
+            continue;
+
+          target_element = label->element;
+          label_element = get_label_element (target_element);
+
+          TARGET_FILENAME *target_filename =
+              html_normalized_label_id_file (self, label->identifier,
+                                             label_element);
+          target = target_filename->target;
+          if (extension)
+            xasprintf (&node_filename, "%s.%s", target_filename->filename,
+                                                extension);
+          else
+            node_filename = strdup (target_filename->filename);
+
+          free (target_filename->filename);
+          free (target_filename);
+
+          /* a non defined filename is ok if called with convert, but not
+             if output in files.  We reset if undef, silently unless verbose
+             in case called by convert. */
+
+          user_node_filename = call_file_id_setting_node_file_name (self,
+                                               target_element, node_filename,
+                                               &called);
+          if (user_node_filename)
+            {
+              free (node_filename);
+              node_filename = user_node_filename;
+            }
+          else if (called)
+            {
+              if (self->conf->VERBOSE.o.integer > 0)
+                {
+                  message_list_document_warn (&self->error_messages, 
self->conf,
+                             0, "user-defined node file name not set for `%s'",
+                             node_filename);
+                }
+              else if (self->conf->DEBUG.o.integer > 0)
+                {
+                  fprintf (stderr,
+                     "user-defined node file name undef for `%s'\n",
+                       node_filename);
+                }
+            }
+
+          if (self->conf->DEBUG.o.integer > 0)
+            {
+              const char *command_name = element_command_name (target_element);
+              fprintf (stderr, "Label @%s %s, %s\n", command_name, target,
+                               node_filename);
+            }
+
+          HTML_TARGET *element_target
+            = add_element_target (self, target_element, target);
+          element_target->node_filename = node_filename;
+          html_register_id (self, target);
+
+          free (target);
+        }
+    }
+
+  if (self->document->sections_list)
+    {
+      const CONST_ELEMENT_LIST *sections_list = self->document->sections_list;
+      size_t i;
+      for (i = 0; i < sections_list->number; i++)
+        {
+          const ELEMENT *root_element = sections_list->list[i];
+          new_sectioning_command_target (self, root_element);
+        }
+    }
+}
+
+void
+prepare_index_entries_targets (CONVERTER *self)
+{
+  if (self->document->indices_info.number > 0)
+    {
+      size_t i;
+      self->shared_conversion_state.formatted_index_entries
+        = (int **) malloc (self->sorted_index_names.number * sizeof (int *));
+      for (i = 0; i < self->sorted_index_names.number; i++)
+        {
+          size_t j;
+          const INDEX *idx = self->sorted_index_names.list[i];
+          /* no need to test for idx->entries_number > 0 as indices without
+             entries are not kept in sorted_index_names. */
+          self->shared_conversion_state.formatted_index_entries[i]
+            = (int *) malloc (idx->entries_number * sizeof (int));
+          memset (self->shared_conversion_state.formatted_index_entries[i],
+                  0, idx->entries_number * sizeof (int));
+          for (j = 0; j < idx->entries_number; j++)
+            {
+              INDEX_ENTRY *index_entry;
+              const ELEMENT *main_entry_element;
+              const ELEMENT *seeentry;
+              const ELEMENT *seealso;
+              ELEMENT *entry_reference_content_element;
+              ELEMENT *normalize_index_element;
+              ELEMENT_LIST *subentries_tree;
+              const ELEMENT *target_element;
+              TEXT target_base;
+              char *normalized_index;
+              char *region = 0;
+              char *target;
+
+              index_entry = &idx->index_entries[j];
+              main_entry_element = index_entry->entry_element;
+              seeentry = lookup_extra_element (main_entry_element,
+                                               AI_key_seeentry);
+              if (seeentry)
+                continue;
+              seealso = lookup_extra_element (main_entry_element,
+                                              AI_key_seealso);
+              if (seealso)
+                continue;
+
+              region = lookup_extra_string (main_entry_element,
+                                            AI_key_element_region);
+              entry_reference_content_element
+               = index_content_element (main_entry_element, 1);
+        /* construct element to convert to a normalized identifier to use as
+           hrefs target */
+              normalize_index_element = new_element (ET_NONE);
+              add_to_contents_as_array (normalize_index_element,
+                                        entry_reference_content_element);
+
+              subentries_tree
+               = comma_index_subentries_tree (main_entry_element, " ");
+              if (subentries_tree)
+                {
+                  insert_list_slice_into_contents (normalize_index_element,
+                                   
normalize_index_element->e.c->contents.number,
+                                   subentries_tree, 0,
+                                   subentries_tree->number);
+                }
+              normalized_index
+                = normalize_transliterate_texinfo (normalize_index_element,
+                                            (self->conf->TEST.o.integer > 0));
+
+              destroy_element (normalize_index_element);
+              if (subentries_tree)
+                free_comma_index_subentries_tree (subentries_tree);
+
+              text_init (&target_base);
+              text_append (&target_base, "index-");
+              if (region)
+                {
+                  text_append (&target_base, region);
+                  text_append (&target_base, "-");
+                }
+              text_append (&target_base, normalized_index);
+              free (normalized_index);
+              target = unique_target (self, target_base.text);
+              free (target_base.text);
+              if (index_entry->entry_associated_element)
+                target_element = index_entry->entry_associated_element;
+              else
+                target_element = main_entry_element;
+
+              add_element_target (self, target_element, target);
+              html_register_id (self, target);
+
+              free (target);
+            }
+        }
+    }
+}
+
+static int
+compare_footnote_id (const void *a, const void *b)
+{
+  const FOOTNOTE_ID_NUMBER *fid_a = (const FOOTNOTE_ID_NUMBER *) a;
+  const FOOTNOTE_ID_NUMBER *fid_b = (const FOOTNOTE_ID_NUMBER *) b;
+
+  return strcmp (fid_a->footnote_id, fid_b->footnote_id);
+}
+
+static const char *footid_base = "FOOT";
+static const char *docid_base = "DOCF";
+
+static void
+prepare_footnotes_targets (CONVERTER *self)
+{
+  const ELEMENT_LIST *global_footnotes
+    = &self->document->global_commands.footnotes;
+  if (global_footnotes->number > 0)
+    {
+      size_t i;
+      self->shared_conversion_state.footnote_id_numbers
+        = (FOOTNOTE_ID_NUMBER *) malloc (global_footnotes->number *
+                                         sizeof (FOOTNOTE_ID_NUMBER));
+      for (i = 0; i < global_footnotes->number; i++)
+        {
+          const HTML_TARGET *element_target;
+          const ELEMENT *footnote = global_footnotes->list[i];
+          TEXT footid;
+          TEXT docid;
+          int nr = i+1;
+
+          text_init (&footid);
+          text_init (&docid);
+          text_printf (&footid, "%s%d", footid_base, nr);
+          text_printf (&docid, "%s%d", docid_base, nr);
+
+          while (1)
+            {
+              if (html_id_is_registered (self, footid.text)
+                    || html_id_is_registered (self, docid.text))
+                {
+                  nr++;
+                  if (nr == 0)
+                    fatal ("overflow footnote target nr");
+
+                  text_init (&footid);
+                  text_init (&docid);
+                  text_printf (&footid, "%s%d", footid_base, nr);
+                  text_printf (&docid, "%s%d", docid_base, nr);
+                }
+              else
+                break;
+            }
+          html_register_id (self, footid.text);
+          html_register_id (self, docid.text);
+
+          element_target = add_element_target (self, footnote, footid.text);
+          add_special_target (self, ST_footnote_location, footnote,
+                              docid.text);
+
+          if (self->conf->DEBUG.o.integer > 0)
+            {
+              char *footnote_txi = convert_to_texinfo (footnote);
+              fprintf (stderr, "Enter footnote: target %s, nr %d\n%s\n",
+                       footid.text, nr, footnote_txi);
+              free (footnote_txi);
+            }
+          self->shared_conversion_state.footnote_id_numbers[i].footnote_id
+             = element_target->target;
+          self->shared_conversion_state.footnote_id_numbers[i].number = 0;
+          free (footid.text);
+          free (docid.text);
+        }
+      qsort (self->shared_conversion_state.footnote_id_numbers,
+             global_footnotes->number,
+             sizeof (FOOTNOTE_ID_NUMBER), compare_footnote_id);
+    }
+}
+
+/* keep the command names sorted alphabetically to match order in perl */
+static const enum command_id heading_commands_list[] = {
+  CM_chapheading, CM_heading, CM_majorheading, CM_subheading, CM_subsubheading,
+  0,
+};
+
+/* indirectly calls customization function requiring elements */
+void
+set_heading_commands_targets (CONVERTER *self)
+{
+  int i;
+  for (i = 0; heading_commands_list[i]; i++)
+    {
+      enum command_id cmd = heading_commands_list[i];
+      const ELEMENT_LIST *global_command
+        = get_cmd_global_multi_command (&self->document->global_commands, cmd);
+
+      if (global_command->number > 0)
+        {
+          size_t j;
+          for (j = 0; j < global_command->number; j++)
+            {
+              const ELEMENT *command = global_command->list[j];
+              new_sectioning_command_target (self, command);
+            }
+        }
+    }
+}
+
+/* duplicate in convert_html.c */
+static int
+compare_element_target (const void *a, const void *b)
+{
+  const HTML_TARGET *ete_a = (const HTML_TARGET *) a;
+  const HTML_TARGET *ete_b = (const HTML_TARGET *) b;
+  /* we cast to uintptr_t because comparison of pointers from different
+     objects is undefined behaviour in C.  In practice it is probably
+     not an issue */
+  uintptr_t a_element_addr = (uintptr_t)ete_a->element;
+  uintptr_t b_element_addr = (uintptr_t)ete_b->element;
+
+  return (a_element_addr > b_element_addr) - (a_element_addr < b_element_addr);
+}
+
+/* For debug/check/optimization
+   used to check to what extent the targets are already ordered.
+   Return the number of elements ordered ok with respect to the
+   previous element
+ */
+size_t
+check_targets_order (enum command_id cmd, HTML_TARGET_LIST *element_targets)
+{
+  size_t i;
+  size_t result = 0;
+  if (element_targets->number <= 1)
+    return result;
+  for (i = 1; i < element_targets->number; i++)
+    {
+      if (compare_element_target (&element_targets->list[i-1],
+                                  &element_targets->list[i]) > 0)
+        {
+          fprintf (stderr, "no %s %zu %ld %p %s %zu %ld %p %s\n",
+           builtin_command_name (cmd), i-1,
+           (uintptr_t)element_targets->list[i-1].element,
+           element_targets->list[i-1].element, 
element_targets->list[i-1].target,
+           i, (uintptr_t)element_targets->list[i].element,
+           element_targets->list[i].element, element_targets->list[i].target);
+        }
+      else
+        result++;
+    }
+  return result;
+}
+
+/* It may not be efficient to sort and find back with bsearch if there is
+   a small number of elements.  However, some target elements are more
+   likely to already be ordered when they are accessed in their order of
+   appearance in the document.  There is no guarantee, as it is only in the
+   same array that adresses are guaranteed to be increasing.  A check done
+   in 2024 with gcc, using check_targets_order, and also looking at the
+   address of newly allocated elements shows that elements are
+   not that much allocated in order.  However, overall, the addresses are
+   more in order when elements are accessed in the document order.
+   For indices, it is not really possible to get them in document order,
+   within an index they are in document order, but not across indices.
+   The other data are in document order, for nodes and similar because
+   the labels list is used instead of identifiers_target on purpose.
+ */
+void
+sort_cmd_targets (CONVERTER *self)
+{
+  enum command_id cmd;
+  int type;
+
+  for (cmd = 0; cmd < BUILTIN_CMD_NUMBER; cmd++)
+    {
+      if (self->html_targets[cmd].number > 0)
+        {
+          HTML_TARGET_LIST *element_targets = &self->html_targets[cmd];
+           /* to check the order
+          size_t ordered_items = check_targets_order (cmd, element_targets);
+          fprintf (stderr, "ORDER %s %zu / %zu\n", builtin_command_name (cmd),
+                   ordered_items, element_targets->number -1);
+            */
+          qsort (element_targets->list,
+                 element_targets->number,
+                 sizeof (HTML_TARGET), compare_element_target);
+          push_command (&self->html_target_cmds, cmd);
+        }
+    }
+  for (type = 0; type < ST_footnote_location+1; type++)
+    {
+     if (self->html_special_targets[type].number > 0)
+        {
+          HTML_TARGET_LIST *element_targets = 
&self->html_special_targets[type];
+          qsort (element_targets->list,
+                 element_targets->number,
+                 sizeof (HTML_TARGET), compare_element_target);
+        }
+    }
+}
+
+/* indirectly calls all the functions calling customization function
+   requiring elements and output units except for external nodes formatting */
+/* for conversion units except for associated special units that require
+   files for document units to be set */
+void
+html_prepare_conversion_units_targets (CONVERTER *self,
+                                       const char *document_name)
+{
+  /*
+   Do that before the other elements, to be sure that special page ids
+   are registered before elements id are.
+   */
+  set_special_units_targets_files (self, document_name);
+
+  prepare_associated_special_units_targets (self);
+
+  set_root_commands_targets_node_files (self);
+
+  prepare_index_entries_targets (self);
+  prepare_footnotes_targets (self);
+
+  set_heading_commands_targets (self);
+
+  sort_cmd_targets (self);
+}
+
diff --git a/tp/Texinfo/XS/convert/html_prepare_converter.h 
b/tp/Texinfo/XS/convert/html_prepare_converter.h
index aa51827359..4f626a9763 100644
--- a/tp/Texinfo/XS/convert/html_prepare_converter.h
+++ b/tp/Texinfo/XS/convert/html_prepare_converter.h
@@ -20,4 +20,7 @@ void html_setup_convert (CONVERTER *self);
 
 void html_prepare_conversion_units (CONVERTER *self);
 
+void html_prepare_conversion_units_targets (CONVERTER *self,
+                                     const char *document_name);
+
 #endif



reply via email to

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