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 12:02:13 -0400 (EDT)

branch: master
commit 28dd6be383762f7dc808115143bef23e843d1bf0
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Wed Aug 14 18:55:13 2024 +0200

    * tp/Texinfo/XS/convert/convert_html.c (html_get_target): call
    directly find_element_target_search and not find_element_target.
    Remove find_element_target, replace with html_get_target calls.
    
    * tp/Texinfo/XS/convert/convert_html.c (html_get_top_unit)
    (html_set_file_source_info, html_add_to_files_source_info)
    (html_find_file_source_info, html_setup_output_simple_page):
    
    * tp/Texinfo/XS/convert/html_prepare_converter.c (html_get_target)
    (html_prepare_output_units_global_targets)
    (compare_global_units_direction_name, add_to_unit_file_name_paths)
    (html_setup_global_units_direction_names)
    (html_find_direction_name_global_unit, html_set_pages_files)
    (prepare_special_units_directions, compare_page_name_number)
    (html_prepare_units_directions_files),
    tp/Texinfo/XS/convert/convert_html.c: move html_get_target,
    html_prepare_output_units_global_targets,
    compare_global_units_direction_name,
    html_setup_global_units_direction_names,
    html_find_direction_name_global_unit, add_to_unit_file_name_paths,
    html_set_pages_files, prepare_special_units_directions and
    html_prepare_units_directions_files to html_prepare_converter.c.
---
 ChangeLog                                      |   25 +
 tp/Texinfo/XS/convert/convert_html.c           | 1456 +++++-------------------
 tp/Texinfo/XS/convert/convert_html.h           |   35 +-
 tp/Texinfo/XS/convert/html_prepare_converter.c |  831 +++++++++++++-
 tp/Texinfo/XS/convert/html_prepare_converter.h |    4 +
 5 files changed, 1193 insertions(+), 1158 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b9ae151345..09a71df5b7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,31 @@
        * 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_get_target): call
+       directly find_element_target_search and not find_element_target.
+       Remove find_element_target, replace with html_get_target calls.
+
+       * tp/Texinfo/XS/convert/convert_html.c (html_get_top_unit)
+       (html_set_file_source_info, html_add_to_files_source_info)
+       (html_find_file_source_info, html_setup_output_simple_page):
+
+       * tp/Texinfo/XS/convert/html_prepare_converter.c (html_get_target)
+       (html_prepare_output_units_global_targets)
+       (compare_global_units_direction_name, add_to_unit_file_name_paths)
+       (html_setup_global_units_direction_names)
+       (html_find_direction_name_global_unit, html_set_pages_files)
+       (prepare_special_units_directions, compare_page_name_number)
+       (html_prepare_units_directions_files),
+       tp/Texinfo/XS/convert/convert_html.c: move html_get_target,
+       html_prepare_output_units_global_targets,
+       compare_global_units_direction_name,
+       html_setup_global_units_direction_names,
+       html_find_direction_name_global_unit, add_to_unit_file_name_paths,
+       html_set_pages_files, prepare_special_units_directions and
+       html_prepare_units_directions_files to html_prepare_converter.c.
+
 2024-08-14  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/XS/convert/convert_html.c (html_normalized_to_id)
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index 9670d4e42d..90c228ce9a 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -145,8 +145,8 @@ html_register_id (CONVERTER *self, const char *string)
  if OUTPUT_UNITS is defined, the first output unit is used if a proper
  top output unit is not found.
  */
-static OUTPUT_UNIT *
-get_top_unit (DOCUMENT *document, const OUTPUT_UNIT_LIST *output_units)
+OUTPUT_UNIT *
+html_get_top_unit (DOCUMENT *document, const OUTPUT_UNIT_LIST *output_units)
 {
   const ELEMENT *node_top = find_identifier_target
                           (&document->identifiers_target, "Top");
@@ -165,7 +165,7 @@ get_top_unit (DOCUMENT *document, const OUTPUT_UNIT_LIST 
*output_units)
 static int
 unit_is_top_output_unit (CONVERTER *self, const OUTPUT_UNIT *output_unit)
 {
-  OUTPUT_UNIT *top_output_unit = get_top_unit (self->document, 0);
+  OUTPUT_UNIT *top_output_unit = html_get_top_unit (self->document, 0);
   return (top_output_unit && top_output_unit == output_unit);
 }
 
@@ -357,6 +357,43 @@ html_after_escaped_characters (char *text)
   return 0;
 }
 
+/*
+static const char *xml_named_entity_nbsp = "&nbsp;";
+ */
+static const char *html_default_entity_nbsp = "&nbsp;";
+
+char *
+html_substitute_non_breaking_space (CONVERTER *self, const char *text)
+{
+  TEXT result;
+  text_init (&result);
+  text_append (&result, "");
+
+  const char *p = text;
+
+  while (*p)
+    {
+      const char *q = strstr (p, html_default_entity_nbsp);
+      if (q)
+        {
+          if (q - p)
+            {
+              text_append_n (&result, p, q - p);
+            }
+          text_append_n (&result,
+                self->special_character[SC_non_breaking_space].string,
+                self->special_character[SC_non_breaking_space].len);
+          p = q + 6; /* 6: length of html_default_entity_nbsp */
+        }
+      else
+        {
+          text_append (&result, p);
+          break;
+        }
+    }
+  return result.text;
+}
+
 /* this number should be safe to use even after targets list has been
    reallocated */
 
@@ -409,12 +446,14 @@ find_element_target_search (const HTML_TARGET_LIST 
*targets,
   return result;
 }
 
-/* becomes invalid if the targets list is reallocated */
+/* note that the returned pointer may be invalidated if the targets list
+   is reallocated.  Callers should make sure that the html target is
+   used before a reallocation is possible */
 HTML_TARGET *
-find_element_target (const HTML_TARGET_LIST *targets, const ELEMENT *element)
+html_get_target (const CONVERTER *self, const ELEMENT *element)
 {
   enum command_id cmd = element_builtin_cmd (element);
-  return find_element_target_search (&targets[cmd], element);
+  return find_element_target_search (&self->html_targets[cmd], element);
   /* with a linear search:
   size_t i = find_element_target_number_linear (&targets[cmd], element);
 
@@ -424,6 +463,7 @@ find_element_target (const HTML_TARGET_LIST *targets, const 
ELEMENT *element)
   return 0;
   */
 }
+
 /* the target may not be known already, so the caller may fill the
    HTML_TARGET in some cases */
 HTML_TARGET *
@@ -441,6 +481,94 @@ find_element_special_target (const HTML_TARGET_LIST 
*targets,
   */
 }
 
+void
+html_set_file_source_info (FILE_SOURCE_INFO *file_source_info,
+                           const char *file_info_type,
+                           const char *file_info_name,
+                           const ELEMENT *file_info_element,
+                           const char *filepath)
+{
+  file_source_info->type = file_info_type;
+  file_source_info->name = file_info_name;
+  file_source_info->element = file_info_element;
+  if (filepath)
+    file_source_info->path = strdup (filepath);
+  else
+    file_source_info->path = 0;
+}
+
+FILE_SOURCE_INFO *
+html_add_to_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info,
+                              const char *filename,
+                              const char *file_info_type,
+                              const char *file_info_name,
+                              const ELEMENT *file_info_element,
+                              const char *filepath)
+{
+  FILE_SOURCE_INFO *new_file_source_info;
+  if (files_source_info->number == files_source_info->space)
+    {
+      files_source_info->list = realloc (files_source_info->list,
+               (files_source_info->space += 5) * sizeof (FILE_SOURCE_INFO));
+      if (!files_source_info->list)
+       fatal ("realloc failed");
+    }
+
+  new_file_source_info =
+   &files_source_info->list[files_source_info->number];
+
+  new_file_source_info->filename = strdup (filename);
+  html_set_file_source_info (new_file_source_info, file_info_type,
+                             file_info_name, file_info_element, filepath);
+
+  files_source_info->number++;
+
+  return new_file_source_info;
+}
+
+FILE_SOURCE_INFO *
+html_find_file_source_info (FILE_SOURCE_INFO_LIST *files_source_info,
+                            const char *filename)
+{
+  size_t i;
+  for (i = 0; i < files_source_info->number; i++)
+    {
+      FILE_SOURCE_INFO *file_source_info = &files_source_info->list[i];
+      if (!strcmp (file_source_info->filename, filename))
+        return file_source_info;
+    }
+  return 0;
+}
+
+/* setup a page (+global context) in case there are no files, ie called
+   with convert or output with an empty string as filename. */
+void
+html_setup_output_simple_page (CONVERTER *self, const char *output_filename)
+{
+  PAGE_NAME_NUMBER *page_name_number;
+  self->page_css.number = 1+1;
+  self->page_css.space = self->page_css.number;
+  self->page_css.list = (CSS_LIST *)
+       malloc (self->page_css.space * sizeof (CSS_LIST));
+  memset (self->page_css.list, 0,
+          self->page_css.number * sizeof (CSS_LIST));
+
+  self->html_files_information.number = 1+1;
+  self->html_files_information.list = (FILE_ASSOCIATED_INFO *)
+       malloc (self->html_files_information.number
+          * sizeof (FILE_ASSOCIATED_INFO));
+  memset (self->html_files_information.list, 0,
+          self->html_files_information.number * sizeof (FILE_ASSOCIATED_INFO));
+
+  self->page_name_number.number = 1;
+  self->page_name_number.list = (PAGE_NAME_NUMBER *)
+      malloc (self->page_name_number.number * sizeof (PAGE_NAME_NUMBER));
+
+  page_name_number = &self->page_name_number.list[0];
+  page_name_number->number = 1;
+  page_name_number->page_name = output_filename;
+}
+
 char *
 format_translate_message (CONVERTER *self,
                                   const char *message, const char *lang,
@@ -590,54 +718,6 @@ translate_convert_to_html_internal (const char *string,
   destroy_element_and_children (translation_tree);
 }
 
-
-static int
-compare_page_name_number (const void *a, const void *b)
-{
-  const PAGE_NAME_NUMBER *pnn_a = (const PAGE_NAME_NUMBER *) a;
-  const PAGE_NAME_NUMBER *pnn_b = (const PAGE_NAME_NUMBER *) b;
-
-  return strcmp (pnn_a->page_name, pnn_b->page_name);
-}
-
-
-/*
-static const char *xml_named_entity_nbsp = "&nbsp;";
- */
-static const char *html_default_entity_nbsp = "&nbsp;";
-
-char *
-html_substitute_non_breaking_space (CONVERTER *self, const char *text)
-{
-  TEXT result;
-  text_init (&result);
-  text_append (&result, "");
-
-  const char *p = text;
-
-  while (*p)
-    {
-      const char *q = strstr (p, html_default_entity_nbsp);
-      if (q)
-        {
-          if (q - p)
-            {
-              text_append_n (&result, p, q - p);
-            }
-          text_append_n (&result,
-                self->special_character[SC_non_breaking_space].string,
-                self->special_character[SC_non_breaking_space].len);
-          p = q + 6; /* 6: length of html_default_entity_nbsp */
-        }
-      else
-        {
-          text_append (&result, p);
-          break;
-        }
-    }
-  return result.text;
-}
-
 ELEMENT *
 special_unit_info_tree (CONVERTER *self, const enum special_unit_info_tree 
type,
                         const char *special_unit_variety)
@@ -1427,18 +1507,6 @@ html_add_special_unit_info (SPECIAL_UNIT_INFO_LIST 
*special_unit_info_list,
   return special_unit_info;
 }
 
-/* note that the returned pointer may be invalidated if the targets list
-   is reallocated.  Callers should make sure that the html target is
-   used before a reallocation is possible */
-HTML_TARGET *
-html_get_target (const CONVERTER *self, const ELEMENT *element)
-{
-  HTML_TARGET *result
-   = find_element_target (self->html_targets, element);
-
-  return result;
-}
-
 const char *
 html_command_id (const CONVERTER *self, const ELEMENT *command)
 {
@@ -2726,1116 +2794,184 @@ from_element_direction (CONVERTER *self, int 
direction,
                   const ELEMENT *associated_node
                     = lookup_extra_element (target_command,
                                             AI_key_associated_node);
-                  if (associated_node)
-                    command = associated_node;
-                }
-            }
-          type = HTT_text;
-        }
-      else if (type == HTT_section)
-        {
-          if (target_unit->unit_type == OU_unit && 
target_unit->uc.unit_command)
-            {
-              const ELEMENT *target_command = target_unit->uc.unit_command;
-              if (target_command->e.c->cmd != CM_node)
-                command = target_command;
-              else
-                {
-                  const ELEMENT *associated_section
-                    = lookup_extra_element (target_command,
-                                            AI_key_associated_section);
-                  if (associated_section)
-                    command = associated_section;
-                }
-            }
-          type = HTT_text_nonumber;
-        }
-      else
-        {
-          if (target_unit->unit_type == OU_special_unit)
-            command = target_unit->uc.special_unit_command;
-          else
-            command = target_unit->uc.unit_command;
-          if (type == HTT_href)
-            {
-              if (command)
-                return html_command_href (self, command,
-                                          filename_from, 0, 0);
-              else
-                return 0;
-            }
-        }
-    }
-  else
-    return 0;
-
-  if (command)
-    return html_command_text (self, command, type);
-
-  /*
-    We end up here if there is a target element, but not of the expected
-    'type'.  For example, if type is section but there is no section associated
-    to the target element node.
-   */
-  return 0;
-}
-
-static void
-add_new_css_page (PAGES_CSS_LIST *css_pages, const char *page_name)
-{
-  CSS_LIST *page_css_list;
-  if (css_pages->space <= css_pages->number)
-    {
-      css_pages->list = realloc (css_pages->list,
-          (css_pages->space += 10) * sizeof (CSS_LIST));
-    }
-
-  page_css_list = &css_pages->list[css_pages->number];
-  memset (page_css_list, 0, sizeof (CSS_LIST));
-  page_css_list->page_name = strdup (page_name);
-
-  css_pages->number++;
-}
-
-static void
-collect_css_element_class (CONVERTER *self, const char *selector)
-{
-  const CSS_SELECTOR_STYLE *selector_style
-    = find_css_selector_style (&self->css_element_class_styles, selector);
-  if (selector_style)
-    {
-      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;
-}
-
-/* Associate output units to the global targets, First, Last, Top, Index.
-   and special output units */
-void
-html_prepare_output_units_global_targets (CONVERTER *self)
-{
-  int i;
-  int all_special_units_nr = 0;
-  int s;
-  const OUTPUT_UNIT_LIST *output_units = retrieve_output_units
-   (self->document, self->output_units_descriptors[OUDT_units]);
-
-  const OUTPUT_UNIT *top_output_unit = get_top_unit (self->document,
-                                                     output_units);
-
-  size_t special_output_units_lists[2] = {
-    self->output_units_descriptors[OUDT_special_units],
-    self->output_units_descriptors[OUDT_associated_special_units]};
-
-  self->global_units_directions[D_First] = output_units->list[0];
-  self->global_units_directions[D_Last]
-    = output_units->list[output_units->number - 1];
-
-  self->global_units_directions[D_Top] = top_output_unit;
-
-  /* It is always the first printindex, even if it is not output (for example
-     it is in @copying and @titlepage, which are certainly wrong constructs).
-   */
-  if (self->document->global_commands.printindex.number > 0)
-    {
-      const ELEMENT *printindex
-        = self->document->global_commands.printindex.list[0];
-      ROOT_AND_UNIT *root_unit
-        = html_get_tree_root_element (self, printindex, 0);
-      if (root_unit->output_unit)
-        {
-          const OUTPUT_UNIT *document_unit = root_unit->output_unit;
-          const ELEMENT *root_command = root_unit->root;
-          if (root_command && root_command->e.c->cmd == CM_node)
-            {
-              const ELEMENT *associated_section
-                = lookup_extra_element (root_command,
-                                        AI_key_associated_section);
-              if (associated_section)
-                root_command = associated_section;
-            }
-       /* find the first level 1 sectioning element to associate the printindex
-           with */
-          if (root_command && root_command->e.c->cmd != CM_node)
-            {
-              while (1)
-                {
-                  int status;
-                  int section_level
-                    = lookup_extra_integer (root_command, AI_key_section_level,
-                                                               &status);
-                  if (!status && section_level <= 1)
-                    break;
-
-                  const ELEMENT * const *up_section_directions
-                    = lookup_extra_directions (root_command,
-                                         AI_key_section_directions);
-                  if (up_section_directions
-                      && up_section_directions[D_up]
-                      && up_section_directions[D_up]
-                                     ->e.c->associated_unit)
-                    {
-                      root_command = up_section_directions[D_up];
-                      document_unit = root_command->e.c->associated_unit;
-                    }
-                  else
-                    break;
-                }
-            }
-          self->global_units_directions[D_Index] = document_unit;
-        }
-      free (root_unit);
-    }
-
-  if (self->conf->DEBUG.o.integer > 0)
-    {
-      int i;
-      fprintf (stderr, "GLOBAL DIRECTIONS:\n");
-      for (i = 0; i < D_Last+1; i++)
-        {
-          if (self->global_units_directions[i])
-            {
-              const OUTPUT_UNIT *global_unit = 
self->global_units_directions[i];
-              char *unit_texi = output_unit_texi (global_unit);
-              fprintf (stderr, " %s: %s\n", 
html_global_unit_direction_names[i],
-                                            unit_texi);
-              free (unit_texi);
-            }
-        }
-      fprintf (stderr, "\n");
-    }
-
-  /* determine total number of special output units and fill
-     special_units_directions_name_unit.  Used to simplify building perl
-     directions */
-  for (i = 0; i < 2; i++)
-    {
-      size_t special_units_descriptor = special_output_units_lists[i];
-      const OUTPUT_UNIT_LIST *units_list
-       = retrieve_output_units (self->document, special_units_descriptor);
-      if (units_list && units_list->number)
-        all_special_units_nr += units_list->number;
-    }
-
-  self->special_units_direction_name = (SPECIAL_UNIT_DIRECTION *)
-   malloc (sizeof (SPECIAL_UNIT_DIRECTION) * (all_special_units_nr+1));
-  memset (self->special_units_direction_name, 0,
-          sizeof (SPECIAL_UNIT_DIRECTION) * (all_special_units_nr+1));
-
-  s = 0;
-  for (i = 0; i < 2; i++)
-    {
-      size_t special_units_descriptor = special_output_units_lists[i];
-      const OUTPUT_UNIT_LIST *units_list
-        = retrieve_output_units (self->document, special_units_descriptor);
-      if (units_list && units_list->number)
-        {
-          size_t j;
-          for (j = 0; j < units_list->number; j++)
-            {
-              const OUTPUT_UNIT *special_unit = units_list->list[j];
-              const char *special_unit_variety = 
special_unit->special_unit_variety;
-              int special_unit_direction_index
-                = html_special_unit_variety_direction_index (self,
-                                                special_unit_variety);
-              self->global_units_directions[special_unit_direction_index]
-                = special_unit;
-
-              self->special_units_direction_name[s].output_unit = special_unit;
-              self->special_units_direction_name[s].direction
-                = html_special_unit_info (self, SUI_type_direction,
-                                          special_unit_variety);
-              s++;
-            }
-        }
-    }
-}
-
-static int
-compare_global_units_direction_name (const void *a, const void *b)
-{
-  const SPECIAL_UNIT_DIRECTION *gudn_a = (const SPECIAL_UNIT_DIRECTION *) a;
-  const SPECIAL_UNIT_DIRECTION *gudn_b = (const SPECIAL_UNIT_DIRECTION *) b;
-
-  return strcmp (gudn_a->direction, gudn_b->direction);
-}
-
-/* To find more easily a global output unit based on a direction name, for an
-   XS interface, associate global output units to names and sort according
-   to names */
-void
-html_setup_global_units_direction_names (CONVERTER *self)
-{
-  SPECIAL_UNIT_DIRECTION *global_units_direction_names;
-  int i;
-  int global_directions_nr = 0;
-  int global_units_direction_idx = 0;
-  const SPECIAL_UNIT_DIRECTION *special_units_direction_name
-    = self->special_units_direction_name;
-
-  for (i = 0; i < D_Last+1; i++)
-    if (self->global_units_directions[i])
-      global_directions_nr++;
-
-  for (i = 0; special_units_direction_name[i].output_unit; i++)
-    global_directions_nr++;
-
-  global_units_direction_names = (SPECIAL_UNIT_DIRECTION *)
-   malloc (sizeof (SPECIAL_UNIT_DIRECTION) * (global_directions_nr));
-
-  for (i = 0; i < D_Last+1; i++)
-    {
-      if (self->global_units_directions[i])
-        {
-          global_units_direction_names[global_units_direction_idx].direction
-            = html_global_unit_direction_names[i];
-          global_units_direction_names[global_units_direction_idx].output_unit
-            = self->global_units_directions[i];
-          global_units_direction_idx++;
-        }
-    }
-
-  for (i = 0; special_units_direction_name[i].output_unit; i++)
-    {
-      global_units_direction_names[global_units_direction_idx].direction
-        = special_units_direction_name[i].direction;
-      global_units_direction_names[global_units_direction_idx].output_unit
-        = special_units_direction_name[i].output_unit;
-      global_units_direction_idx++;
-    }
-
-  qsort (global_units_direction_names,
-         global_directions_nr,
-         sizeof (SPECIAL_UNIT_DIRECTION), compare_global_units_direction_name);
-
-  self->global_units_direction_name.list = global_units_direction_names;
-  self->global_units_direction_name.number = global_directions_nr;
-}
-
-/* Used from Perl through an XS override, in similar C codes the
-   direction indices are used instead of the direction names */
-const OUTPUT_UNIT *
-html_find_direction_name_global_unit (const CONVERTER *self,
-                                      const char *direction_name)
-{
-  SPECIAL_UNIT_DIRECTION *result = 0;
-  static SPECIAL_UNIT_DIRECTION searched_direction;
-
-  searched_direction.direction = direction_name;
-  result = (SPECIAL_UNIT_DIRECTION *) bsearch (&searched_direction,
-                self->global_units_direction_name.list,
-                self->global_units_direction_name.number,
-                sizeof (SPECIAL_UNIT_DIRECTION),
-                compare_global_units_direction_name);
-  if (!result)
-    return 0;
-  return result->output_unit;
-}
-
-static void
-set_file_source_info (FILE_SOURCE_INFO *file_source_info,
-                          const char *file_info_type, const char 
*file_info_name,
-                          const ELEMENT *file_info_element, const char 
*filepath)
-{
-  file_source_info->type = file_info_type;
-  file_source_info->name = file_info_name;
-  file_source_info->element = file_info_element;
-  if (filepath)
-    file_source_info->path = strdup (filepath);
-  else
-    file_source_info->path = 0;
-}
-
-static FILE_SOURCE_INFO *
-add_to_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info,
-                          const char *filename,
-                          const char *file_info_type, const char 
*file_info_name,
-                          const ELEMENT *file_info_element, const char 
*filepath)
-{
-  FILE_SOURCE_INFO *new_file_source_info;
-  if (files_source_info->number == files_source_info->space)
-    {
-      files_source_info->list = realloc (files_source_info->list,
-               (files_source_info->space += 5) * sizeof (FILE_SOURCE_INFO));
-      if (!files_source_info->list)
-       fatal ("realloc failed");
-    }
-
-  new_file_source_info =
-   &files_source_info->list[files_source_info->number];
-
-  new_file_source_info->filename = strdup (filename);
-  set_file_source_info (new_file_source_info, file_info_type,
-                        file_info_name, file_info_element, filepath);
-
-  files_source_info->number++;
-
-  return new_file_source_info;
-}
-
-static FILE_SOURCE_INFO *
-find_file_source_info (FILE_SOURCE_INFO_LIST *files_source_info,
-                            const char *filename)
-{
-  size_t i;
-  for (i = 0; i < files_source_info->number; i++)
-    {
-      FILE_SOURCE_INFO *file_source_info = &files_source_info->list[i];
-      if (!strcmp (file_source_info->filename, filename))
-        return file_source_info;
-    }
-  return 0;
-}
-
-void
-html_reset_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
-{
-  size_t i;
-  for (i = 0; i < files_source_info->number; i++)
-    {
-      free (files_source_info->list[i].filename);
-      free (files_source_info->list[i].path);
-    }
-  files_source_info->number = 0;
-}
-
-void
-html_free_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
-{
-  html_reset_files_source_info (files_source_info);
-  free (files_source_info->list);
-  files_source_info->list = 0;
-  files_source_info->space = 0;
-}
-
-void
-html_destroy_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
-{
-  html_free_files_source_info (files_source_info);
-  free (files_source_info);
-}
-
-static char *
-add_to_unit_file_name_paths (char **unit_file_name_paths,
-                             const char *filename,
-                             const OUTPUT_UNIT *output_unit)
-{
-  unit_file_name_paths[output_unit->index] = strdup (filename);
-
-  return unit_file_name_paths[output_unit->index];
-}
-
-/* calls customization function requiring output units */
-static FILE_SOURCE_INFO_LIST *
-html_set_pages_files (CONVERTER *self, const OUTPUT_UNIT_LIST *output_units,
-                      const OUTPUT_UNIT_LIST *special_units,
-                      const OUTPUT_UNIT_LIST *associated_special_units,
-                      const char *output_file,
-                      const char *destination_directory, const char 
*output_filename,
-                      const char *document_name)
-{
-  FILE_SOURCE_INFO_LIST *files_source_info;
-  char **unit_file_name_paths;
-  size_t i;
-
-  initialize_output_units_files (self);
-
-  files_source_info = &self->files_source_info;
-
-  unit_file_name_paths = (char **)
-   malloc (output_units->number * sizeof (char *));
-  memset (unit_file_name_paths, 0,
-          output_units->number * sizeof (char *));
-
-  if (!self->conf->SPLIT.o.string || !strlen (self->conf->SPLIT.o.string))
-    {
-      size_t i;
-      add_to_files_source_info (files_source_info, output_filename,
-                                "special_file", "non_split", 0,
-                                output_file);
-      for (i = 0; i < output_units->number; i++)
-        {
-          add_to_unit_file_name_paths (unit_file_name_paths,
-                                       output_filename,
-                                       output_units->list[i]);
-        }
-    }
-  else
-    {
-      char *top_node_filename_str;
-      const OUTPUT_UNIT *node_top_output_unit = 0;
-      const char *extension = 0;
-      const ELEMENT *node_top = 0;
-      size_t file_nr = 0;
-      size_t i;
-
-      /* first determine the top node file name. */
-      if (self->document->identifiers_target.number > 0)
-        node_top = find_identifier_target (&self->document->identifiers_target,
-                                           "Top");
-
-      top_node_filename_str = top_node_filename (self, document_name);
-
-      if (node_top && top_node_filename_str)
-        {
-          size_t i;
-          node_top_output_unit = node_top->e.c->associated_unit;
-          for (i = 0; i < output_units->number; i++)
-            if (output_units->list[i] == node_top_output_unit)
-              break;
-          add_to_files_source_info (files_source_info, top_node_filename_str,
-                                    "special_file", "Top", 0, 0);
-          add_to_unit_file_name_paths (unit_file_name_paths,
-                                       top_node_filename_str,
-                                       node_top_output_unit);
-        }
-
-      if (self->conf->EXTENSION.o.string
-          && strlen (self->conf->EXTENSION.o.string))
-        extension = self->conf->EXTENSION.o.string;
-
-      for (i = 0; i < output_units->number; i++)
-        {
-          const OUTPUT_UNIT *output_unit = output_units->list[i];
-          const OUTPUT_UNIT *file_output_unit;
-          const char *output_unit_file_name;
-          /* For Top node. */
-          if (node_top_output_unit && node_top_output_unit == output_unit)
-            continue;
-
-          file_output_unit = output_unit->first_in_page;
-          output_unit_file_name
-           = unit_file_name_paths[file_output_unit->index];
-          if (!output_unit_file_name)
-            {
-              const char *node_filename = 0;
-              size_t j;
-              for (j = 0; j < file_output_unit->unit_contents.number; j++)
-                {
-                  const ELEMENT *root_command
-                     = file_output_unit->unit_contents.list[j];
-                  if (root_command->e.c->cmd == CM_node)
-                    {
-                      const ELEMENT *node_target = 0;
-                      const char *normalized = lookup_extra_string 
(root_command,
-                                                               
AI_key_normalized);
-                      if (normalized)
-                        node_target
-                         = find_identifier_target (
-                                  &self->document->identifiers_target,
-                                  normalized);
-                   /* double node are not normalized, they are handled here */
-                      if (!node_target)
-                        {
-                          const FILE_SOURCE_INFO *file_source_info = 0;
-
-                          TEXT file_name_text;
-                          text_init (&file_name_text);
-                          text_append (&file_name_text, "unknown_node");
-                          if (extension)
-                            {
-                              text_append (&file_name_text, ".");
-                              text_append (&file_name_text, extension);
-                            }
-                          file_source_info
-                            = find_file_source_info (files_source_info,
-                                                         file_name_text.text);
-                          if (!file_source_info)
-                            {
-                              file_source_info
-                                = add_to_files_source_info (files_source_info,
-                                                file_name_text.text, "node", 0,
-                                                              root_command, 0);
-                              node_filename = file_source_info->filename;
-                            }
-                          free (file_name_text.text);
-                        }
-                      else
-                        {
-          /* Nodes with {'extra'}->{'is_target'} should always be in
-            'identifiers_target', and thus in targets.  It is a bug otherwise. 
*/
-                          FILE_SOURCE_INFO *file_source_info = 0;
-                          HTML_TARGET *node_target
-                            = find_element_target (self->html_targets,
-                                                   root_command);
-                          node_filename = node_target->node_filename;
-
-                          file_source_info
-                            = find_file_source_info (files_source_info,
-                                                          node_filename);
-                          if (file_source_info)
-                            {
-                              if (!strcmp (file_source_info->type,
-                                           "stand_in_file"))
-                                {/* NOTE we keep the order, as in perl */
-                                  set_file_source_info (file_source_info,
-                                                        "node",
-                                                        0, root_command, 0);
-                                }
-                            }
-                          else
-                            add_to_files_source_info (files_source_info,
-                                                 node_filename, "node", 0,
-                                                 root_command, 0);
-                        }
-                      output_unit_file_name
-                        = add_to_unit_file_name_paths (unit_file_name_paths,
-                                                       node_filename,
-                                                       file_output_unit);
-                      break;
-                    }
-                }
-              if (!node_filename)
-                {
-                  /* use section to do the file name if there is no node */
-                  const ELEMENT *command = file_output_unit->uc.unit_command;
-                  if (command)
-                    {
-                      if (command->e.c->cmd == CM_top && !node_top
-                          && top_node_filename_str)
-                        {
-                   /* existing top_node_filename can happen, see
-                      html_tests.t top_file_name_and_node_name_collision */
-                          FILE_SOURCE_INFO *file_source_info
-                            = find_file_source_info (files_source_info,
-                                                  top_node_filename_str);
-                          if (file_source_info)
-                            {/* NOTE we keep the order, as in perl */
-                              set_file_source_info (file_source_info,
-                                                    "special_file", "Top",
-                                                    0, 0);
-                            }
-                          else
-                            {
-                              add_to_files_source_info (files_source_info,
-                                                       top_node_filename_str,
-                                                       "special_file", "Top",
-                                                       0, 0);
-                            }
-                          output_unit_file_name
-                           = add_to_unit_file_name_paths (unit_file_name_paths,
-                                                          
top_node_filename_str,
-                                                           file_output_unit);
-                        }
-                      else
-                        {
-                          const HTML_TARGET *section_target
-                            = find_element_target (self->html_targets,
-                                                   command);
-                          const char *section_filename
-                            = section_target->section_filename;
-
-                          FILE_SOURCE_INFO *file_source_info
-                            = find_file_source_info (files_source_info,
-                                                     section_filename);
-                          if (file_source_info)
-                            {
-                              if (!strcmp (file_source_info->type,
-                                           "stand_in_file"))
-                                {/* NOTE we keep the order, as in perl */
-                                  set_file_source_info (file_source_info,
-                                                        "section",
-                                                        0, command, 0);
-                                }
-                            }
-                          else
-                            add_to_files_source_info (files_source_info,
-                                                 section_filename, "section", 
0,
-                                                 command, 0);
-                          output_unit_file_name
-                            = add_to_unit_file_name_paths 
(unit_file_name_paths,
-                                                           section_filename,
-                                                           file_output_unit);
-                        }
-                    }
-                  else
-                    {
-                      /* when everything else has failed */
-                      if (file_nr == 0 && !node_top
-                          && top_node_filename_str)
-                        {
-                          const FILE_SOURCE_INFO *file_source_info
-                            = find_file_source_info (files_source_info,
-                                                  top_node_filename_str);
-                          if (!file_source_info)
-                            {
-                              add_to_files_source_info (files_source_info,
-                                                       top_node_filename_str,
-                                                       "stand_in_file", "Top",
-                                                       0, 0);
-                            }
-                          output_unit_file_name
-                           = add_to_unit_file_name_paths (unit_file_name_paths,
-                                                         top_node_filename_str,
-                                                           file_output_unit);
-                        }
-                      else
-                        {
-                          const FILE_SOURCE_INFO *file_source_info;
-
-                          TEXT file_name_text;
-                          text_init (&file_name_text);
-                          text_printf (&file_name_text, "%s_%zu", 
document_name,
-                                                                  file_nr);
-                          if (extension)
-                            {
-                              text_append (&file_name_text, ".");
-                              text_append (&file_name_text, extension);
-                            }
-                          file_source_info
-                            = find_file_source_info (files_source_info,
-                                                  file_name_text.text);
-                          if (!file_source_info)
-                            {
-                              add_to_files_source_info (files_source_info,
-                                                       file_name_text.text,
-                                                       "stand_in_file",
-                                                       "unknown",
-                                                       0, 0);
-                            }
-                          output_unit_file_name
-                           = add_to_unit_file_name_paths (unit_file_name_paths,
-                                                          file_name_text.text,
-                                                           file_output_unit);
-                          free (file_name_text.text);
-                        }
-                      file_nr++;
-                    }
-                }
-            }
-          if (output_unit != file_output_unit)
-            add_to_unit_file_name_paths (unit_file_name_paths,
-                                         output_unit_file_name,
-                                         output_unit);
-        }
-      free (top_node_filename_str);
-    }
-
-  self->output_unit_file_indices = (size_t *)
-    malloc (output_units->number * sizeof (size_t));
-
-  for (i = 0; i < output_units->number; i++)
-    {
-      size_t output_unit_file_idx = 0;
-      const FILE_NAME_PATH_COUNTER *output_unit_file;
-      OUTPUT_UNIT *output_unit = output_units->list[i];
-      char *filename = unit_file_name_paths[i];
-      const FILE_SOURCE_INFO *file_source_info
-        = find_file_source_info (files_source_info, filename);
-      const char *filepath = file_source_info->path;
-
-      FILE_NAME_PATH *file_name_path
-        = call_file_id_setting_unit_file_name (self, output_unit,
-                                               filename, filepath);
-      if (file_name_path)
-        {
-          if (file_name_path->filename)
-            {
-              FILE_SOURCE_INFO *file_source_info
-               = find_file_source_info (files_source_info,
-                                        file_name_path->filename);
-              if (file_source_info)
-                {
-          /*  It is likely that setting different paths for the same file is
-              not intended, so we warn. */
-                  if (file_source_info->path && file_name_path->filepath
-                      && strcmp (file_source_info->path,
-                                 file_name_path->filepath))
-                    {
-                      message_list_document_warn (&self->error_messages,
-                                                  self->conf, 0,
-                                     "resetting %s file path %s to %s",
-                                           file_name_path->filename,
-                                           file_source_info->path,
-                                           file_name_path->filepath);
-                    }
-                  else if (file_name_path->filepath
-                           && !file_source_info->path)
-                    {
-                      message_list_document_warn (&self->error_messages,
-                                                  self->conf, 0,
-                        "resetting %s file path from a relative path to %s",
-                                           file_name_path->filename,
-                                           file_name_path->filepath);
-                    }
-                  else if (!file_name_path->filepath
-                           && file_source_info->path)
-                    {
-                      message_list_document_warn (&self->error_messages,
-                                                  self->conf, 0,
-                        "resetting %s file path from %s to a relative path",
-                                           file_name_path->filename,
-                                           file_source_info->path);
-                    }
-                  set_file_source_info (file_source_info, "special_file",
-                                "user_defined", 0, file_name_path->filepath);
+                  if (associated_node)
+                    command = associated_node;
                 }
-              else
-                add_to_files_source_info (files_source_info,
-                                          file_name_path->filename,
-                                          "special_file", "user_defined",
-                                           0, file_name_path->filepath);
-              free (filename);
-              filename = file_name_path->filename;
             }
-          free (file_name_path->filepath);
-          free (file_name_path);
-        }
-      output_unit_file_idx
-        = set_output_unit_file (self, output_unit, filename, 1);
-      self->output_unit_file_indices[i] = output_unit_file_idx;
-      output_unit_file = &self->output_unit_files.list[output_unit_file_idx];
-      if (self->conf->DEBUG.o.integer > 0)
-        {
-          char *output_unit_text = output_unit_texi (output_unit);
-          fprintf (stderr, "Page %s: %s(%d)\n", output_unit_text,
-                 output_unit->unit_filename, output_unit_file->counter);
-          free (output_unit_text);
+          type = HTT_text;
         }
-      free (filename);
-    }
-
-  free (unit_file_name_paths);
-
-  if (special_units && special_units->number)
-    {
-      size_t i;
-      self->special_unit_file_indices = (size_t *)
-        malloc (special_units->number * sizeof (size_t));
-      for (i = 0; i < special_units->number; i++)
+      else if (type == HTT_section)
         {
-          size_t special_unit_file_idx = 0;
-          const FILE_NAME_PATH_COUNTER *special_unit_file;
-          OUTPUT_UNIT *special_unit = special_units->list[i];
-          const ELEMENT *unit_command = special_unit->uc.special_unit_command;
-          const HTML_TARGET *special_unit_target
-            = find_element_target (self->html_targets, unit_command);
-          const char *filename = special_unit_target->special_unit_filename;
-
-        /* Associate the special elements that have no page with the main page.
-           This may only happen if not split. */
-          if (!filename && special_units->number
-              && output_units->list[0]->unit_filename)
-            {
-              filename = output_units->list[0]->unit_filename;
-            }
-
-          if (filename)
+          if (target_unit->unit_type == OU_unit && 
target_unit->uc.unit_command)
             {
-              FILE_SOURCE_INFO *file_source_info
-               = find_file_source_info (files_source_info, filename);
-              if (file_source_info)
+              const ELEMENT *target_command = target_unit->uc.unit_command;
+              if (target_command->e.c->cmd != CM_node)
+                command = target_command;
+              else
                 {
-                  if (!strcmp (file_source_info->type, "stand_in_file"))
-                    {/* NOTE we keep the order, as in perl */
-                      set_file_source_info (file_source_info, "special_unit",
-                                            0, unit_command, 0);
-                    }
+                  const ELEMENT *associated_section
+                    = lookup_extra_element (target_command,
+                                            AI_key_associated_section);
+                  if (associated_section)
+                    command = associated_section;
                 }
+            }
+          type = HTT_text_nonumber;
+        }
+      else
+        {
+          if (target_unit->unit_type == OU_special_unit)
+            command = target_unit->uc.special_unit_command;
+          else
+            command = target_unit->uc.unit_command;
+          if (type == HTT_href)
+            {
+              if (command)
+                return html_command_href (self, command,
+                                          filename_from, 0, 0);
               else
-                add_to_files_source_info (files_source_info, filename,
-                                          "special_unit", 0, unit_command, 0);
+                return 0;
             }
-          special_unit_file_idx
-            = set_output_unit_file (self, special_unit, filename, 1);
-          self->special_unit_file_indices[i] = special_unit_file_idx;
-          special_unit_file
-             = &self->output_unit_files.list[special_unit_file_idx];
-          if (self->conf->DEBUG.o.integer > 0)
-            fprintf (stderr, "Special page: %s(%d)\n", filename,
-                             special_unit_file->counter);
         }
     }
+  else
+    return 0;
 
-  for (i = 0; i < files_source_info->number; i++)
-    {
-      FILE_SOURCE_INFO *file_source_info = &files_source_info->list[i];
-      set_file_path (self, file_source_info->filename, file_source_info->path,
-                     destination_directory);
-    }
+  if (command)
+    return html_command_text (self, command, type);
 
   /*
-   to be able to associate to the output unit file the associated
-   output units will be output into, this is done after document output
-   units got files.
-   In practice only used for contents and shortcontents.
+    We end up here if there is a target element, but not of the expected
+    'type'.  For example, if type is section but there is no section associated
+    to the target element node.
    */
-  if (associated_special_units && associated_special_units->number > 0)
-    {
-      size_t i;
-      for (i = 0; i < associated_special_units->number; i++)
-        {
-          const char *filename = 0;
-          OUTPUT_UNIT *special_unit = associated_special_units->list[i];
-          const OUTPUT_UNIT *associated_output_unit
-            = special_unit->associated_document_unit;
-          const ELEMENT *unit_command = special_unit->uc.special_unit_command;
-          HTML_TARGET *element_target
-            = find_element_target (self->html_targets, unit_command);
-
-          if (!element_target->special_unit_filename)
-            {/* set the file if not already set */
-              char *unit_filename = 0;
-              if (associated_output_unit)
-                unit_filename = strdup (associated_output_unit->unit_filename);
-              element_target->special_unit_filename = unit_filename;
-            }
-          filename = element_target->special_unit_filename;
-
-   /* set here the file name, but do not increment the counter as it is
-      already set for the output unit the special output unit is in. */
-          if (filename)
-            set_output_unit_file (self, special_unit, filename, 0);
-        }
-    }
-
-  /* 0 is for document_global_context_css, the remaining indices
-     for the output unit files */
-  self->page_css.number = self->output_unit_files.number +1;
-  self->page_css.space = self->page_css.number;
-  self->page_css.list = (CSS_LIST *)
-       malloc (self->page_css.space * sizeof (CSS_LIST));
-  memset (self->page_css.list, 0,
-          self->page_css.number * sizeof (CSS_LIST));
-
-  self->html_files_information.number = self->output_unit_files.number +1;
-  self->html_files_information.list = (FILE_ASSOCIATED_INFO *)
-   malloc (self->html_files_information.number * sizeof 
(FILE_ASSOCIATED_INFO));
-  memset (self->html_files_information.list, 0,
-          self->html_files_information.number * sizeof (FILE_ASSOCIATED_INFO));
-
-  self->pending_closes.number = self->output_unit_files.number +1;
-  self->pending_closes.list = (STRING_STACK *)
-    malloc (self->pending_closes.number * sizeof (STRING_STACK));
-  memset (self->pending_closes.list, 0,
-          self->pending_closes.number * sizeof (STRING_STACK));
-
-  return files_source_info;
+  return 0;
 }
 
-/* setup a page (+global context) in case there are no files, ie called
-   with convert or output with an empty string as filename. */
-void
-setup_output_simple_page (CONVERTER *self, const char *output_filename)
+static void
+add_new_css_page (PAGES_CSS_LIST *css_pages, const char *page_name)
 {
-  PAGE_NAME_NUMBER *page_name_number;
-  self->page_css.number = 1+1;
-  self->page_css.space = self->page_css.number;
-  self->page_css.list = (CSS_LIST *)
-       malloc (self->page_css.space * sizeof (CSS_LIST));
-  memset (self->page_css.list, 0,
-          self->page_css.number * sizeof (CSS_LIST));
-
-  self->html_files_information.number = 1+1;
-  self->html_files_information.list = (FILE_ASSOCIATED_INFO *)
-       malloc (self->html_files_information.number
-          * sizeof (FILE_ASSOCIATED_INFO));
-  memset (self->html_files_information.list, 0,
-          self->html_files_information.number * sizeof (FILE_ASSOCIATED_INFO));
-
-  self->pending_closes.number = 1+1;
-  self->pending_closes.list = (STRING_STACK *)
-       malloc (self->pending_closes.number * sizeof (STRING_STACK));
-  memset (self->pending_closes.list, 0,
-          self->pending_closes.number * sizeof (STRING_STACK));
+  CSS_LIST *page_css_list;
+  if (css_pages->space <= css_pages->number)
+    {
+      css_pages->list = realloc (css_pages->list,
+          (css_pages->space += 10) * sizeof (CSS_LIST));
+    }
 
-  self->page_name_number.number = 1;
-  self->page_name_number.list = (PAGE_NAME_NUMBER *)
-      malloc (self->page_name_number.number * sizeof (PAGE_NAME_NUMBER));
+  page_css_list = &css_pages->list[css_pages->number];
+  memset (page_css_list, 0, sizeof (CSS_LIST));
+  page_css_list->page_name = strdup (page_name);
 
-  page_name_number = &self->page_name_number.list[0];
-  page_name_number->number = 1;
-  page_name_number->page_name = output_filename;
+  css_pages->number++;
 }
 
 static void
-prepare_special_units_directions (CONVERTER *self,
-                                  OUTPUT_UNIT_LIST *special_units)
+collect_css_element_class (CONVERTER *self, const char *selector)
 {
-  size_t i;
-
-  if (!special_units)
-    return;
-
-  for (i = 0; i < special_units->number; i++)
+  const CSS_SELECTOR_STYLE *selector_style
+    = find_css_selector_style (&self->css_element_class_styles, selector);
+  if (selector_style)
     {
-      OUTPUT_UNIT *special_unit = special_units->list[i];
-      special_unit->directions[RUD_type_This] = special_unit;
+      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++;
     }
 }
 
-/* Return structure to be freed by the caller */
-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)
+void
+close_html_lone_element (const CONVERTER *self, TEXT *result)
 {
-  size_t i;
-  FILE_SOURCE_INFO_LIST *files_source_info = 0;
-  size_t external_nodes_units_descriptor
-     = new_output_units_descriptor (self->document);
-  OUTPUT_UNIT_LIST *external_node_target_units
-    = retrieve_output_units (self->document, external_nodes_units_descriptor);
-  OUTPUT_UNIT_LIST *output_units = retrieve_output_units
-    (self->document, self->output_units_descriptors[OUDT_units]);
-  OUTPUT_UNIT_LIST *special_units = retrieve_output_units
-    (self->document, self->output_units_descriptors[OUDT_special_units]);
-  OUTPUT_UNIT_LIST *associated_special_units = retrieve_output_units
-    (self->document,
-     self->output_units_descriptors[OUDT_associated_special_units]);
-
-   self->output_units_descriptors[OUDT_external_nodes_units]
-     = external_nodes_units_descriptor;
-
-  html_prepare_output_units_global_targets (self);
-
-  split_pages (output_units, self->conf->SPLIT.o.string);
-
-  if (strlen (output_file))
-    {
-      files_source_info =
-        html_set_pages_files (self, output_units, special_units,
-                        associated_special_units, output_file,
-                        destination_directory, output_filename, document_name);
-    }
+  if (self->conf->USE_XML_SYNTAX.o.integer > 0)
+    text_append_n (result, "/>", 2);
   else
-    setup_output_simple_page (self, output_filename);
-
-  units_directions (&self->document->identifiers_target, output_units,
-                    external_node_target_units,
-                    self->conf->DEBUG.o.integer);
-
-  prepare_special_units_directions (self, special_units);
-
-  units_file_directions (output_units);
+    text_append_n (result, ">", 1);
+}
 
- /* elements_in_file_count is only set in HTML, not in
-    Texinfo::Convert::Converter */
-  if (self->output_unit_files.number)
+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)
     {
-      /* set elements_in_file_count and prepare page_name_number
-         for sorting */
-      self->page_name_number.number = self->output_unit_files.number;
-      self->page_name_number.list = (PAGE_NAME_NUMBER *)
-        malloc (self->page_name_number.number * sizeof (PAGE_NAME_NUMBER));
-
-      for (i = 0; i < self->output_unit_files.number; i++)
+      int n = strcspn (p, " ");
+      if (n)
         {
-          FILE_NAME_PATH_COUNTER *file_counter
-            = &self->output_unit_files.list[i];
-          PAGE_NAME_NUMBER *page_name_number = &self->page_name_number.list[i];
-
-          /* counter is dynamic, decreased when the element is encountered
-             elements_in_file_count is not modified afterwards */
-          file_counter->elements_in_file_count = file_counter->counter;
-
-          page_name_number->number = i+1;
-          page_name_number->page_name = file_counter->filename;
+          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;
+            }
         }
-
-      qsort (self->page_name_number.list,
-             self->page_name_number.number,
-             sizeof (PAGE_NAME_NUMBER), compare_page_name_number);
     }
 
-  return files_source_info;
+  /* 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 *
@@ -12646,7 +11782,7 @@ html_convert_menu_entry_type (CONVERTER *self, const 
enum element_type type,
                 {
         /* update the number of time the node description was formatted */
                   HTML_TARGET *target_info
-                     = find_element_target (self->html_targets, node);
+                     = html_get_target (self, node);
                   target_info->formatted_nodedescription_nr++;
                   formatted_nodedescription_nr
                     = target_info->formatted_nodedescription_nr;
@@ -14655,6 +13791,34 @@ clear_type_explanations (EXPLAINED_COMMAND_TYPE_LIST 
*type_explanations)
     }
 }
 
+void
+html_reset_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
+{
+  size_t i;
+  for (i = 0; i < files_source_info->number; i++)
+    {
+      free (files_source_info->list[i].filename);
+      free (files_source_info->list[i].path);
+    }
+  files_source_info->number = 0;
+}
+
+void
+html_free_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
+{
+  html_reset_files_source_info (files_source_info);
+  free (files_source_info->list);
+  files_source_info->list = 0;
+  files_source_info->space = 0;
+}
+
+void
+html_destroy_files_source_info (FILE_SOURCE_INFO_LIST *files_source_info)
+{
+  html_free_files_source_info (files_source_info);
+  free (files_source_info);
+}
+
 void
 html_reset_converter (CONVERTER *self)
 {
@@ -15188,7 +14352,7 @@ html_translate_names (CONVERTER *self)
               if (command)
                 {
                   HTML_TARGET *target_info
-                    = find_element_target (self->html_targets, command);
+                    = html_get_target (self, command);
                   if (target_info)
                     {
        /* the tree is a reference to special_unit_info_tree, so it should
@@ -16237,7 +15401,7 @@ html_prepare_title_titlepage (CONVERTER *self, const 
char *output_file,
     {
       /* case of convert() call.  Need to setup the page here */
       if (self->page_name_number.number <= 0)
-         setup_output_simple_page (self, output_filename);
+         html_setup_output_simple_page (self, output_filename);
       self->current_filename.filename = output_filename;
       self->current_filename.file_number = 1;
     }
@@ -16883,8 +16047,8 @@ html_node_redirections (CONVERTER *self,
                 = output_unit_file->elements_in_file_count;
 
               FILE_SOURCE_INFO *file_source_info
-                 = find_file_source_info (files_source_info,
-                                          redirection_filename);
+                 = html_find_file_source_info (files_source_info,
+                                               redirection_filename);
               if (file_source_info
                /* first condition finds conflict with tree elements */
                   && (redirection_filename_total_count > 0
@@ -16990,7 +16154,7 @@ html_node_redirections (CONVERTER *self,
                   int overwritten_file;
                   int status;
 
-                  add_to_files_source_info (files_source_info,
+                  html_add_to_files_source_info (files_source_info,
                                  redirection_filename, "redirection", 0,
                                                        target_element, 0);
 
diff --git a/tp/Texinfo/XS/convert/convert_html.h 
b/tp/Texinfo/XS/convert/convert_html.h
index 72c5a63c6d..a3d3eafcac 100644
--- a/tp/Texinfo/XS/convert/convert_html.h
+++ b/tp/Texinfo/XS/convert/convert_html.h
@@ -47,6 +47,12 @@ extern COMMAND_ID_LIST no_arg_formatted_cmd;
 
 void html_conversion_finalization (CONVERTER *self);
 
+int html_id_is_registered (CONVERTER *self, const char *string);
+void html_register_id (CONVERTER *self, const char *string);
+
+OUTPUT_UNIT *html_get_top_unit (DOCUMENT *document,
+                                const OUTPUT_UNIT_LIST *output_units);
+
 ROOT_AND_UNIT *html_get_tree_root_element (CONVERTER *self,
                                            const ELEMENT *command,
                                            int find_container);
@@ -54,6 +60,27 @@ ROOT_AND_UNIT *html_get_tree_root_element (CONVERTER *self,
 char *html_after_escaped_characters (char *text);
 char *html_substitute_non_breaking_space (CONVERTER *self, const char *text);
 
+HTML_TARGET *html_get_target (const CONVERTER *self, const ELEMENT *element);
+
+void html_set_file_source_info (FILE_SOURCE_INFO *file_source_info,
+                                const char *file_info_type,
+                                const char *file_info_name,
+                                const ELEMENT *file_info_element,
+                                const char *filepath);
+FILE_SOURCE_INFO *html_add_to_files_source_info (
+                              FILE_SOURCE_INFO_LIST *files_source_info,
+                              const char *filename,
+                              const char *file_info_type,
+                              const char *file_info_name,
+                              const ELEMENT *file_info_element,
+                              const char *filepath);
+FILE_SOURCE_INFO *html_find_file_source_info (
+                            FILE_SOURCE_INFO_LIST *files_source_info,
+                            const char *filename);
+
+void html_setup_output_simple_page (CONVERTER *self,
+                                    const char *output_filename);
+
 const char *html_special_unit_info (const CONVERTER *self,
                                     enum special_unit_info_type type,
                                     const char *special_unit_variety);
@@ -82,13 +109,9 @@ SPECIAL_UNIT_INFO *html_add_special_unit_info (
                             SPECIAL_UNIT_INFO_LIST *special_unit_info_list,
                             int type, size_t variety_nr, const char *value);
 
-int html_id_is_registered (CONVERTER *self, const char *string);
-void html_register_id (CONVERTER *self, const char *string);
-
 int html_special_unit_variety_direction_index (const CONVERTER *self,
                                         const char *special_unit_variety);
 
-HTML_TARGET *html_get_target (const CONVERTER *self, const ELEMENT *element);
 const char *html_command_id (const CONVERTER *self, const ELEMENT *command);
 const char *html_command_contents_target (CONVERTER *self,
                                     const ELEMENT *command,
@@ -123,10 +146,6 @@ FOOTNOTE_ID_NUMBER *find_footnote_id_number (const 
CONVERTER *self,
 char *html_attribute_class (CONVERTER *self, const char *element,
                             const STRING_LIST *classes);
 
-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);
-
 
 void
 html_command_conversion_external (CONVERTER *self, const enum command_id cmd,
diff --git a/tp/Texinfo/XS/convert/html_prepare_converter.c 
b/tp/Texinfo/XS/convert/html_prepare_converter.c
index 63669ed549..c1d4bbb80d 100644
--- a/tp/Texinfo/XS/convert/html_prepare_converter.c
+++ b/tp/Texinfo/XS/convert/html_prepare_converter.c
@@ -29,14 +29,15 @@
 #include "conversion_data.h"
 /* new_element */
 #include "tree.h"
-#include "extra.h"
-#include "utils.h"
 #include "errors.h"
-/* unicode_character_brace_no_arg_commands */
-#include "unicode.h"
 #include "builtin_commands.h"
 #include "command_stack.h"
+#include "utils.h"
 #include "customization_options.h"
+#include "extra.h"
+#include "targets.h"
+/* unicode_character_brace_no_arg_commands */
+#include "unicode.h"
 #include "convert_to_texinfo.h"
 #include "node_name_normalization.h"
 #include "manipulate_indices.h"
@@ -3814,3 +3815,825 @@ html_prepare_conversion_units_targets (CONVERTER *self,
   sort_cmd_targets (self);
 }
 
+
+
+/* Associate output units to the global targets, First, Last, Top, Index.
+   and special output units */
+void
+html_prepare_output_units_global_targets (CONVERTER *self)
+{
+  int i;
+  int all_special_units_nr = 0;
+  int s;
+  const OUTPUT_UNIT_LIST *output_units = retrieve_output_units
+   (self->document, self->output_units_descriptors[OUDT_units]);
+
+  const OUTPUT_UNIT *top_output_unit = html_get_top_unit (self->document,
+                                                          output_units);
+
+  size_t special_output_units_lists[2] = {
+    self->output_units_descriptors[OUDT_special_units],
+    self->output_units_descriptors[OUDT_associated_special_units]};
+
+  self->global_units_directions[D_First] = output_units->list[0];
+  self->global_units_directions[D_Last]
+    = output_units->list[output_units->number - 1];
+
+  self->global_units_directions[D_Top] = top_output_unit;
+
+  /* It is always the first printindex, even if it is not output (for example
+     it is in @copying and @titlepage, which are certainly wrong constructs).
+   */
+  if (self->document->global_commands.printindex.number > 0)
+    {
+      const ELEMENT *printindex
+        = self->document->global_commands.printindex.list[0];
+      ROOT_AND_UNIT *root_unit
+        = html_get_tree_root_element (self, printindex, 0);
+      if (root_unit->output_unit)
+        {
+          const OUTPUT_UNIT *document_unit = root_unit->output_unit;
+          const ELEMENT *root_command = root_unit->root;
+          if (root_command && root_command->e.c->cmd == CM_node)
+            {
+              const ELEMENT *associated_section
+                = lookup_extra_element (root_command,
+                                        AI_key_associated_section);
+              if (associated_section)
+                root_command = associated_section;
+            }
+       /* find the first level 1 sectioning element to associate the printindex
+           with */
+          if (root_command && root_command->e.c->cmd != CM_node)
+            {
+              while (1)
+                {
+                  int status;
+                  int section_level
+                    = lookup_extra_integer (root_command, AI_key_section_level,
+                                                               &status);
+                  if (!status && section_level <= 1)
+                    break;
+
+                  const ELEMENT * const *up_section_directions
+                    = lookup_extra_directions (root_command,
+                                         AI_key_section_directions);
+                  if (up_section_directions
+                      && up_section_directions[D_up]
+                      && up_section_directions[D_up]
+                                     ->e.c->associated_unit)
+                    {
+                      root_command = up_section_directions[D_up];
+                      document_unit = root_command->e.c->associated_unit;
+                    }
+                  else
+                    break;
+                }
+            }
+          self->global_units_directions[D_Index] = document_unit;
+        }
+      free (root_unit);
+    }
+
+  if (self->conf->DEBUG.o.integer > 0)
+    {
+      int i;
+      fprintf (stderr, "GLOBAL DIRECTIONS:\n");
+      for (i = 0; i < D_Last+1; i++)
+        {
+          if (self->global_units_directions[i])
+            {
+              const OUTPUT_UNIT *global_unit = 
self->global_units_directions[i];
+              char *unit_texi = output_unit_texi (global_unit);
+              fprintf (stderr, " %s: %s\n", 
html_global_unit_direction_names[i],
+                                            unit_texi);
+              free (unit_texi);
+            }
+        }
+      fprintf (stderr, "\n");
+    }
+
+  /* determine total number of special output units and fill
+     special_units_directions_name_unit.  Used to simplify building perl
+     directions */
+  for (i = 0; i < 2; i++)
+    {
+      size_t special_units_descriptor = special_output_units_lists[i];
+      const OUTPUT_UNIT_LIST *units_list
+       = retrieve_output_units (self->document, special_units_descriptor);
+      if (units_list && units_list->number)
+        all_special_units_nr += units_list->number;
+    }
+
+  self->special_units_direction_name = (SPECIAL_UNIT_DIRECTION *)
+   malloc (sizeof (SPECIAL_UNIT_DIRECTION) * (all_special_units_nr+1));
+  memset (self->special_units_direction_name, 0,
+          sizeof (SPECIAL_UNIT_DIRECTION) * (all_special_units_nr+1));
+
+  s = 0;
+  for (i = 0; i < 2; i++)
+    {
+      size_t special_units_descriptor = special_output_units_lists[i];
+      const OUTPUT_UNIT_LIST *units_list
+        = retrieve_output_units (self->document, special_units_descriptor);
+      if (units_list && units_list->number)
+        {
+          size_t j;
+          for (j = 0; j < units_list->number; j++)
+            {
+              const OUTPUT_UNIT *special_unit = units_list->list[j];
+              const char *special_unit_variety = 
special_unit->special_unit_variety;
+              int special_unit_direction_index
+                = html_special_unit_variety_direction_index (self,
+                                                special_unit_variety);
+              self->global_units_directions[special_unit_direction_index]
+                = special_unit;
+
+              self->special_units_direction_name[s].output_unit = special_unit;
+              self->special_units_direction_name[s].direction
+                = html_special_unit_info (self, SUI_type_direction,
+                                          special_unit_variety);
+              s++;
+            }
+        }
+    }
+}
+
+static int
+compare_global_units_direction_name (const void *a, const void *b)
+{
+  const SPECIAL_UNIT_DIRECTION *gudn_a = (const SPECIAL_UNIT_DIRECTION *) a;
+  const SPECIAL_UNIT_DIRECTION *gudn_b = (const SPECIAL_UNIT_DIRECTION *) b;
+
+  return strcmp (gudn_a->direction, gudn_b->direction);
+}
+
+/* To find more easily a global output unit based on a direction name, for an
+   XS interface, associate global output units to names and sort according
+   to names */
+void
+html_setup_global_units_direction_names (CONVERTER *self)
+{
+  SPECIAL_UNIT_DIRECTION *global_units_direction_names;
+  int i;
+  int global_directions_nr = 0;
+  int global_units_direction_idx = 0;
+  const SPECIAL_UNIT_DIRECTION *special_units_direction_name
+    = self->special_units_direction_name;
+
+  for (i = 0; i < D_Last+1; i++)
+    if (self->global_units_directions[i])
+      global_directions_nr++;
+
+  for (i = 0; special_units_direction_name[i].output_unit; i++)
+    global_directions_nr++;
+
+  global_units_direction_names = (SPECIAL_UNIT_DIRECTION *)
+   malloc (sizeof (SPECIAL_UNIT_DIRECTION) * (global_directions_nr));
+
+  for (i = 0; i < D_Last+1; i++)
+    {
+      if (self->global_units_directions[i])
+        {
+          global_units_direction_names[global_units_direction_idx].direction
+            = html_global_unit_direction_names[i];
+          global_units_direction_names[global_units_direction_idx].output_unit
+            = self->global_units_directions[i];
+          global_units_direction_idx++;
+        }
+    }
+
+  for (i = 0; special_units_direction_name[i].output_unit; i++)
+    {
+      global_units_direction_names[global_units_direction_idx].direction
+        = special_units_direction_name[i].direction;
+      global_units_direction_names[global_units_direction_idx].output_unit
+        = special_units_direction_name[i].output_unit;
+      global_units_direction_idx++;
+    }
+
+  qsort (global_units_direction_names,
+         global_directions_nr,
+         sizeof (SPECIAL_UNIT_DIRECTION), compare_global_units_direction_name);
+
+  self->global_units_direction_name.list = global_units_direction_names;
+  self->global_units_direction_name.number = global_directions_nr;
+}
+
+/* Used from Perl through an XS override, in similar C codes the
+   direction indices are used instead of the direction names */
+const OUTPUT_UNIT *
+html_find_direction_name_global_unit (const CONVERTER *self,
+                                      const char *direction_name)
+{
+  SPECIAL_UNIT_DIRECTION *result = 0;
+  static SPECIAL_UNIT_DIRECTION searched_direction;
+
+  searched_direction.direction = direction_name;
+  result = (SPECIAL_UNIT_DIRECTION *) bsearch (&searched_direction,
+                self->global_units_direction_name.list,
+                self->global_units_direction_name.number,
+                sizeof (SPECIAL_UNIT_DIRECTION),
+                compare_global_units_direction_name);
+  if (!result)
+    return 0;
+  return result->output_unit;
+}
+
+
+static char *
+add_to_unit_file_name_paths (char **unit_file_name_paths,
+                             const char *filename,
+                             const OUTPUT_UNIT *output_unit)
+{
+  unit_file_name_paths[output_unit->index] = strdup (filename);
+
+  return unit_file_name_paths[output_unit->index];
+}
+
+/* calls customization function requiring output units */
+static FILE_SOURCE_INFO_LIST *
+html_set_pages_files (CONVERTER *self, const OUTPUT_UNIT_LIST *output_units,
+                      const OUTPUT_UNIT_LIST *special_units,
+                      const OUTPUT_UNIT_LIST *associated_special_units,
+                      const char *output_file,
+                      const char *destination_directory, const char 
*output_filename,
+                      const char *document_name)
+{
+  FILE_SOURCE_INFO_LIST *files_source_info;
+  char **unit_file_name_paths;
+  size_t i;
+
+  initialize_output_units_files (self);
+
+  files_source_info = &self->files_source_info;
+
+  unit_file_name_paths = (char **)
+   malloc (output_units->number * sizeof (char *));
+  memset (unit_file_name_paths, 0,
+          output_units->number * sizeof (char *));
+
+  if (!self->conf->SPLIT.o.string || !strlen (self->conf->SPLIT.o.string))
+    {
+      size_t i;
+      html_add_to_files_source_info (files_source_info, output_filename,
+                                     "special_file", "non_split", 0,
+                                     output_file);
+      for (i = 0; i < output_units->number; i++)
+        {
+          add_to_unit_file_name_paths (unit_file_name_paths,
+                                       output_filename,
+                                       output_units->list[i]);
+        }
+    }
+  else
+    {
+      char *top_node_filename_str;
+      const OUTPUT_UNIT *node_top_output_unit = 0;
+      const char *extension = 0;
+      const ELEMENT *node_top = 0;
+      size_t file_nr = 0;
+      size_t i;
+
+      /* first determine the top node file name. */
+      if (self->document->identifiers_target.number > 0)
+        node_top = find_identifier_target (&self->document->identifiers_target,
+                                           "Top");
+
+      top_node_filename_str = top_node_filename (self, document_name);
+
+      if (node_top && top_node_filename_str)
+        {
+          size_t i;
+          node_top_output_unit = node_top->e.c->associated_unit;
+          for (i = 0; i < output_units->number; i++)
+            if (output_units->list[i] == node_top_output_unit)
+              break;
+          html_add_to_files_source_info (files_source_info,
+                                        top_node_filename_str,
+                                        "special_file", "Top", 0, 0);
+          add_to_unit_file_name_paths (unit_file_name_paths,
+                                       top_node_filename_str,
+                                       node_top_output_unit);
+        }
+
+      if (self->conf->EXTENSION.o.string
+          && strlen (self->conf->EXTENSION.o.string))
+        extension = self->conf->EXTENSION.o.string;
+
+      for (i = 0; i < output_units->number; i++)
+        {
+          const OUTPUT_UNIT *output_unit = output_units->list[i];
+          const OUTPUT_UNIT *file_output_unit;
+          const char *output_unit_file_name;
+          /* For Top node. */
+          if (node_top_output_unit && node_top_output_unit == output_unit)
+            continue;
+
+          file_output_unit = output_unit->first_in_page;
+          output_unit_file_name
+           = unit_file_name_paths[file_output_unit->index];
+          if (!output_unit_file_name)
+            {
+              const char *node_filename = 0;
+              size_t j;
+              for (j = 0; j < file_output_unit->unit_contents.number; j++)
+                {
+                  const ELEMENT *root_command
+                     = file_output_unit->unit_contents.list[j];
+                  if (root_command->e.c->cmd == CM_node)
+                    {
+                      const ELEMENT *node_target = 0;
+                      const char *normalized = lookup_extra_string 
(root_command,
+                                                               
AI_key_normalized);
+                      if (normalized)
+                        node_target
+                         = find_identifier_target (
+                                  &self->document->identifiers_target,
+                                  normalized);
+                   /* double node are not normalized, they are handled here */
+                      if (!node_target)
+                        {
+                          const FILE_SOURCE_INFO *file_source_info = 0;
+
+                          TEXT file_name_text;
+                          text_init (&file_name_text);
+                          text_append (&file_name_text, "unknown_node");
+                          if (extension)
+                            {
+                              text_append (&file_name_text, ".");
+                              text_append (&file_name_text, extension);
+                            }
+                          file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                         file_name_text.text);
+                          if (!file_source_info)
+                            {
+                              file_source_info
+                                = html_add_to_files_source_info (
+                                                           files_source_info,
+                                                file_name_text.text, "node", 0,
+                                                              root_command, 0);
+                              node_filename = file_source_info->filename;
+                            }
+                          free (file_name_text.text);
+                        }
+                      else
+                        {
+          /* Nodes with {'extra'}->{'is_target'} should always be in
+            'identifiers_target', and thus in targets.  It is a bug otherwise. 
*/
+                          FILE_SOURCE_INFO *file_source_info = 0;
+                          HTML_TARGET *node_target
+                            = html_get_target (self, root_command);
+                          node_filename = node_target->node_filename;
+
+                          file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                          node_filename);
+                          if (file_source_info)
+                            {
+                              if (!strcmp (file_source_info->type,
+                                           "stand_in_file"))
+                                {/* NOTE we keep the order, as in perl */
+                                  html_set_file_source_info (file_source_info,
+                                                             "node",
+                                                           0, root_command, 0);
+                                }
+                            }
+                          else
+                            html_add_to_files_source_info (files_source_info,
+                                                    node_filename, "node", 0,
+                                                      root_command, 0);
+                        }
+                      output_unit_file_name
+                        = add_to_unit_file_name_paths (unit_file_name_paths,
+                                                       node_filename,
+                                                       file_output_unit);
+                      break;
+                    }
+                }
+              if (!node_filename)
+                {
+                  /* use section to do the file name if there is no node */
+                  const ELEMENT *command = file_output_unit->uc.unit_command;
+                  if (command)
+                    {
+                      if (command->e.c->cmd == CM_top && !node_top
+                          && top_node_filename_str)
+                        {
+                   /* existing top_node_filename can happen, see
+                      html_tests.t top_file_name_and_node_name_collision */
+                          FILE_SOURCE_INFO *file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                      top_node_filename_str);
+                          if (file_source_info)
+                            {/* NOTE we keep the order, as in perl */
+                              html_set_file_source_info (file_source_info,
+                                                        "special_file", "Top",
+                                                        0, 0);
+                            }
+                          else
+                            {
+                              html_add_to_files_source_info (files_source_info,
+                                                       top_node_filename_str,
+                                                       "special_file", "Top",
+                                                       0, 0);
+                            }
+                          output_unit_file_name
+                           = add_to_unit_file_name_paths (unit_file_name_paths,
+                                                          
top_node_filename_str,
+                                                           file_output_unit);
+                        }
+                      else
+                        {
+                          const HTML_TARGET *section_target
+                            = html_get_target (self, command);
+                          const char *section_filename
+                            = section_target->section_filename;
+
+                          FILE_SOURCE_INFO *file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                          section_filename);
+                          if (file_source_info)
+                            {
+                              if (!strcmp (file_source_info->type,
+                                           "stand_in_file"))
+                                {/* NOTE we keep the order, as in perl */
+                                  html_set_file_source_info (file_source_info,
+                                                            "section",
+                                                            0, command, 0);
+                                }
+                            }
+                          else
+                            html_add_to_files_source_info (files_source_info,
+                                                 section_filename, "section", 
0,
+                                                 command, 0);
+                          output_unit_file_name
+                            = add_to_unit_file_name_paths 
(unit_file_name_paths,
+                                                           section_filename,
+                                                           file_output_unit);
+                        }
+                    }
+                  else
+                    {
+                      /* when everything else has failed */
+                      if (file_nr == 0 && !node_top
+                          && top_node_filename_str)
+                        {
+                          const FILE_SOURCE_INFO *file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                       top_node_filename_str);
+                          if (!file_source_info)
+                            {
+                              html_add_to_files_source_info (files_source_info,
+                                                       top_node_filename_str,
+                                                       "stand_in_file", "Top",
+                                                       0, 0);
+                            }
+                          output_unit_file_name
+                           = add_to_unit_file_name_paths (unit_file_name_paths,
+                                                         top_node_filename_str,
+                                                           file_output_unit);
+                        }
+                      else
+                        {
+                          const FILE_SOURCE_INFO *file_source_info;
+
+                          TEXT file_name_text;
+                          text_init (&file_name_text);
+                          text_printf (&file_name_text, "%s_%zu", 
document_name,
+                                                                  file_nr);
+                          if (extension)
+                            {
+                              text_append (&file_name_text, ".");
+                              text_append (&file_name_text, extension);
+                            }
+                          file_source_info
+                            = html_find_file_source_info (files_source_info,
+                                                        file_name_text.text);
+                          if (!file_source_info)
+                            {
+                              html_add_to_files_source_info (files_source_info,
+                                                       file_name_text.text,
+                                                       "stand_in_file",
+                                                       "unknown",
+                                                       0, 0);
+                            }
+                          output_unit_file_name
+                           = add_to_unit_file_name_paths (unit_file_name_paths,
+                                                          file_name_text.text,
+                                                           file_output_unit);
+                          free (file_name_text.text);
+                        }
+                      file_nr++;
+                    }
+                }
+            }
+          if (output_unit != file_output_unit)
+            add_to_unit_file_name_paths (unit_file_name_paths,
+                                         output_unit_file_name,
+                                         output_unit);
+        }
+      free (top_node_filename_str);
+    }
+
+  self->output_unit_file_indices = (size_t *)
+    malloc (output_units->number * sizeof (size_t));
+
+  for (i = 0; i < output_units->number; i++)
+    {
+      size_t output_unit_file_idx = 0;
+      const FILE_NAME_PATH_COUNTER *output_unit_file;
+      OUTPUT_UNIT *output_unit = output_units->list[i];
+      char *filename = unit_file_name_paths[i];
+      const FILE_SOURCE_INFO *file_source_info
+        = html_find_file_source_info (files_source_info, filename);
+      const char *filepath = file_source_info->path;
+
+      FILE_NAME_PATH *file_name_path
+        = call_file_id_setting_unit_file_name (self, output_unit,
+                                               filename, filepath);
+      if (file_name_path)
+        {
+          if (file_name_path->filename)
+            {
+              FILE_SOURCE_INFO *file_source_info
+               = html_find_file_source_info (files_source_info,
+                                             file_name_path->filename);
+              if (file_source_info)
+                {
+          /*  It is likely that setting different paths for the same file is
+              not intended, so we warn. */
+                  if (file_source_info->path && file_name_path->filepath
+                      && strcmp (file_source_info->path,
+                                 file_name_path->filepath))
+                    {
+                      message_list_document_warn (&self->error_messages,
+                                                  self->conf, 0,
+                                     "resetting %s file path %s to %s",
+                                           file_name_path->filename,
+                                           file_source_info->path,
+                                           file_name_path->filepath);
+                    }
+                  else if (file_name_path->filepath
+                           && !file_source_info->path)
+                    {
+                      message_list_document_warn (&self->error_messages,
+                                                  self->conf, 0,
+                        "resetting %s file path from a relative path to %s",
+                                           file_name_path->filename,
+                                           file_name_path->filepath);
+                    }
+                  else if (!file_name_path->filepath
+                           && file_source_info->path)
+                    {
+                      message_list_document_warn (&self->error_messages,
+                                                  self->conf, 0,
+                        "resetting %s file path from %s to a relative path",
+                                           file_name_path->filename,
+                                           file_source_info->path);
+                    }
+                  html_set_file_source_info (file_source_info, "special_file",
+                                "user_defined", 0, file_name_path->filepath);
+                }
+              else
+                html_add_to_files_source_info (files_source_info,
+                                          file_name_path->filename,
+                                          "special_file", "user_defined",
+                                           0, file_name_path->filepath);
+              free (filename);
+              filename = file_name_path->filename;
+            }
+          free (file_name_path->filepath);
+          free (file_name_path);
+        }
+      output_unit_file_idx
+        = set_output_unit_file (self, output_unit, filename, 1);
+      self->output_unit_file_indices[i] = output_unit_file_idx;
+      output_unit_file = &self->output_unit_files.list[output_unit_file_idx];
+      if (self->conf->DEBUG.o.integer > 0)
+        {
+          char *output_unit_text = output_unit_texi (output_unit);
+          fprintf (stderr, "Page %s: %s(%d)\n", output_unit_text,
+                 output_unit->unit_filename, output_unit_file->counter);
+          free (output_unit_text);
+        }
+      free (filename);
+    }
+
+  free (unit_file_name_paths);
+
+  if (special_units && special_units->number)
+    {
+      size_t i;
+      self->special_unit_file_indices = (size_t *)
+        malloc (special_units->number * sizeof (size_t));
+      for (i = 0; i < special_units->number; i++)
+        {
+          size_t special_unit_file_idx = 0;
+          const FILE_NAME_PATH_COUNTER *special_unit_file;
+          OUTPUT_UNIT *special_unit = special_units->list[i];
+          const ELEMENT *unit_command = special_unit->uc.special_unit_command;
+          const HTML_TARGET *special_unit_target
+            = html_get_target (self, unit_command);
+          const char *filename = special_unit_target->special_unit_filename;
+
+        /* Associate the special elements that have no page with the main page.
+           This may only happen if not split. */
+          if (!filename && special_units->number
+              && output_units->list[0]->unit_filename)
+            {
+              filename = output_units->list[0]->unit_filename;
+            }
+
+          if (filename)
+            {
+              FILE_SOURCE_INFO *file_source_info
+               = html_find_file_source_info (files_source_info, filename);
+              if (file_source_info)
+                {
+                  if (!strcmp (file_source_info->type, "stand_in_file"))
+                    {/* NOTE we keep the order, as in perl */
+                      html_set_file_source_info (file_source_info,
+                                                 "special_unit",
+                                                 0, unit_command, 0);
+                    }
+                }
+              else
+                html_add_to_files_source_info (files_source_info, filename,
+                                               "special_unit", 0,
+                                               unit_command, 0);
+            }
+          special_unit_file_idx
+            = set_output_unit_file (self, special_unit, filename, 1);
+          self->special_unit_file_indices[i] = special_unit_file_idx;
+          special_unit_file
+             = &self->output_unit_files.list[special_unit_file_idx];
+          if (self->conf->DEBUG.o.integer > 0)
+            fprintf (stderr, "Special page: %s(%d)\n", filename,
+                             special_unit_file->counter);
+        }
+    }
+
+  for (i = 0; i < files_source_info->number; i++)
+    {
+      FILE_SOURCE_INFO *file_source_info = &files_source_info->list[i];
+      set_file_path (self, file_source_info->filename, file_source_info->path,
+                     destination_directory);
+    }
+
+  /*
+   to be able to associate to the output unit file the associated
+   output units will be output into, this is done after document output
+   units got files.
+   In practice only used for contents and shortcontents.
+   */
+  if (associated_special_units && associated_special_units->number > 0)
+    {
+      size_t i;
+      for (i = 0; i < associated_special_units->number; i++)
+        {
+          const char *filename = 0;
+          OUTPUT_UNIT *special_unit = associated_special_units->list[i];
+          const OUTPUT_UNIT *associated_output_unit
+            = special_unit->associated_document_unit;
+          const ELEMENT *unit_command = special_unit->uc.special_unit_command;
+          HTML_TARGET *element_target
+            = html_get_target (self, unit_command);
+
+          if (!element_target->special_unit_filename)
+            {/* set the file if not already set */
+              char *unit_filename = 0;
+              if (associated_output_unit)
+                unit_filename = strdup (associated_output_unit->unit_filename);
+              element_target->special_unit_filename = unit_filename;
+            }
+          filename = element_target->special_unit_filename;
+
+   /* set here the file name, but do not increment the counter as it is
+      already set for the output unit the special output unit is in. */
+          if (filename)
+            set_output_unit_file (self, special_unit, filename, 0);
+        }
+    }
+
+  /* 0 is for document_global_context_css, the remaining indices
+     for the output unit files */
+  self->page_css.number = self->output_unit_files.number +1;
+  self->page_css.space = self->page_css.number;
+  self->page_css.list = (CSS_LIST *)
+       malloc (self->page_css.space * sizeof (CSS_LIST));
+  memset (self->page_css.list, 0,
+          self->page_css.number * sizeof (CSS_LIST));
+
+  self->html_files_information.number = self->output_unit_files.number +1;
+  self->html_files_information.list = (FILE_ASSOCIATED_INFO *)
+   malloc (self->html_files_information.number * sizeof 
(FILE_ASSOCIATED_INFO));
+  memset (self->html_files_information.list, 0,
+          self->html_files_information.number * sizeof (FILE_ASSOCIATED_INFO));
+
+  return files_source_info;
+}
+
+static void
+prepare_special_units_directions (CONVERTER *self,
+                                  OUTPUT_UNIT_LIST *special_units)
+{
+  size_t i;
+
+  if (!special_units)
+    return;
+
+  for (i = 0; i < special_units->number; i++)
+    {
+      OUTPUT_UNIT *special_unit = special_units->list[i];
+      special_unit->directions[RUD_type_This] = special_unit;
+    }
+}
+
+static int
+compare_page_name_number (const void *a, const void *b)
+{
+  const PAGE_NAME_NUMBER *pnn_a = (const PAGE_NAME_NUMBER *) a;
+  const PAGE_NAME_NUMBER *pnn_b = (const PAGE_NAME_NUMBER *) b;
+
+  return strcmp (pnn_a->page_name, pnn_b->page_name);
+}
+
+/* Return structure to be freed by the caller */
+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)
+{
+  size_t i;
+  FILE_SOURCE_INFO_LIST *files_source_info = 0;
+  size_t external_nodes_units_descriptor
+     = new_output_units_descriptor (self->document);
+  OUTPUT_UNIT_LIST *external_node_target_units
+    = retrieve_output_units (self->document, external_nodes_units_descriptor);
+  OUTPUT_UNIT_LIST *output_units = retrieve_output_units
+    (self->document, self->output_units_descriptors[OUDT_units]);
+  OUTPUT_UNIT_LIST *special_units = retrieve_output_units
+    (self->document, self->output_units_descriptors[OUDT_special_units]);
+  OUTPUT_UNIT_LIST *associated_special_units = retrieve_output_units
+    (self->document,
+     self->output_units_descriptors[OUDT_associated_special_units]);
+
+   self->output_units_descriptors[OUDT_external_nodes_units]
+     = external_nodes_units_descriptor;
+
+  html_prepare_output_units_global_targets (self);
+
+  split_pages (output_units, self->conf->SPLIT.o.string);
+
+  if (strlen (output_file))
+    {
+      files_source_info =
+        html_set_pages_files (self, output_units, special_units,
+                        associated_special_units, output_file,
+                        destination_directory, output_filename, document_name);
+    }
+  else
+    html_setup_output_simple_page (self, output_filename);
+
+  units_directions (&self->document->identifiers_target, output_units,
+                    external_node_target_units,
+                    self->conf->DEBUG.o.integer);
+
+  prepare_special_units_directions (self, special_units);
+
+  units_file_directions (output_units);
+
+ /* elements_in_file_count is only set in HTML, not in
+    Texinfo::Convert::Converter */
+  if (self->output_unit_files.number)
+    {
+      /* set elements_in_file_count and prepare page_name_number
+         for sorting */
+      self->page_name_number.number = self->output_unit_files.number;
+      self->page_name_number.list = (PAGE_NAME_NUMBER *)
+        malloc (self->page_name_number.number * sizeof (PAGE_NAME_NUMBER));
+
+      for (i = 0; i < self->output_unit_files.number; i++)
+        {
+          FILE_NAME_PATH_COUNTER *file_counter
+            = &self->output_unit_files.list[i];
+          PAGE_NAME_NUMBER *page_name_number = &self->page_name_number.list[i];
+
+          /* counter is dynamic, decreased when the element is encountered
+             elements_in_file_count is not modified afterwards */
+          file_counter->elements_in_file_count = file_counter->counter;
+
+          page_name_number->number = i+1;
+          page_name_number->page_name = file_counter->filename;
+        }
+
+      qsort (self->page_name_number.list,
+             self->page_name_number.number,
+             sizeof (PAGE_NAME_NUMBER), compare_page_name_number);
+    }
+
+  return files_source_info;
+}
+
diff --git a/tp/Texinfo/XS/convert/html_prepare_converter.h 
b/tp/Texinfo/XS/convert/html_prepare_converter.h
index 4f626a9763..9dab29f8a3 100644
--- a/tp/Texinfo/XS/convert/html_prepare_converter.h
+++ b/tp/Texinfo/XS/convert/html_prepare_converter.h
@@ -23,4 +23,8 @@ void html_prepare_conversion_units (CONVERTER *self);
 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);
+
 #endif



reply via email to

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