texinfo-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Patrice Dumas
Date: Sat, 23 Dec 2023 06:34:39 -0500 (EST)

branch: master
commit 4ae5255b34bf902b7aa3366a888f5fe454bc67ce
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Sat Dec 23 12:34:30 2023 +0100

    * tp/Texinfo/XS/convert/convert_html.c (compare_footnote_id)
    (find_footnote_id_number, prepare_footnotes_targets)
    (convert_footnote_command, html_reset_converter),
    tp/Texinfo/XS/main/converter_types.h (FOOTNOTE_ID_NUMBER,
    HTML_SHARED_CONVERSION_STATE): setup and free shared conversion state
    footnote_id_numbers and associated functions.  Implement
    convert_footnote_command in C.  Do not use, because the shared
    conversion states are not passed properly between C and perl.
---
 ChangeLog                            |  11 +++
 tp/Texinfo/XS/convert/convert_html.c | 177 ++++++++++++++++++++++++++++++++++-
 tp/Texinfo/XS/convert/convert_html.h |   2 +-
 tp/Texinfo/XS/main/converter_types.h |   8 +-
 4 files changed, 192 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index af52567931..ec275f306e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2023-12-23  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/XS/convert/convert_html.c (compare_footnote_id)
+       (find_footnote_id_number, prepare_footnotes_targets)
+       (convert_footnote_command, html_reset_converter),
+       tp/Texinfo/XS/main/converter_types.h (FOOTNOTE_ID_NUMBER,
+       HTML_SHARED_CONVERSION_STATE): setup and free shared conversion state
+       footnote_id_numbers and associated functions.  Implement
+       convert_footnote_command in C.  Do not use, because the shared
+       conversion states are not passed properly between C and perl.
+
 2023-12-23  Patrice Dumas  <pertusus@free.fr>
 
        * tp/Texinfo/Convert/HTML.pm (_convert_footnote_command): distinguish
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index 63a2e59c2d..8744d11471 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -916,7 +916,7 @@ special_unit_info (CONVERTER *self, enum 
special_unit_info_type type,
 void
 html_register_footnote (CONVERTER *self, const ELEMENT *command,
      const char *footid, const char *docid, const int number_in_doc,
-     const char *footnote_location_filename, char *multi_expanded_region)
+     const char *footnote_location_filename, const char *multi_expanded_region)
 {
   HTML_PENDING_FOOTNOTE_STACK *stack;
   HTML_PENDING_FOOTNOTE *pending_footnote;
@@ -4524,18 +4524,56 @@ prepare_index_entries_targets (CONVERTER *self)
     }
 }
 
+static int
+compare_footnote_id (const void *a, const void *b)
+{
+  const FOOTNOTE_ID_NUMBER *fid_a = (const FOOTNOTE_ID_NUMBER *) a;
+  const FOOTNOTE_ID_NUMBER *fid_b = (const FOOTNOTE_ID_NUMBER *) b;
+
+  return strcmp (fid_a->footnote_id, fid_b->footnote_id);
+}
+
+FOOTNOTE_ID_NUMBER *
+find_footnote_id_number (CONVERTER *self, const char *footnote_id)
+{
+  const ELEMENT_LIST *global_footnotes
+    = &self->document->global_commands->footnotes;
+
+  FOOTNOTE_ID_NUMBER *result = 0;
+  static FOOTNOTE_ID_NUMBER searched_footnote_id;
+  searched_footnote_id.footnote_id = footnote_id;
+  if (global_footnotes->number == 0)
+    {
+      char *msg;
+      xasprintf (&msg, "no footnotes, searching for '%s'\n", footnote_id);
+      fatal (msg);
+      free (msg);
+    }
+
+  result = (FOOTNOTE_ID_NUMBER *) bsearch (&searched_footnote_id,
+                self->shared_conversion_state.footnote_id_numbers,
+                global_footnotes->number, sizeof(FOOTNOTE_ID_NUMBER),
+                compare_footnote_id);
+  return result;
+}
+
 static const char *footid_base = "FOOT";
 static const char *docid_base = "DOCF";
 
 static void
 prepare_footnotes_targets (CONVERTER *self)
 {
-  const ELEMENT_LIST *global_footnotes = 
&self->document->global_commands->footnotes;
+  const ELEMENT_LIST *global_footnotes
+    = &self->document->global_commands->footnotes;
   if (global_footnotes->number > 0)
     {
       int i;
+      self->shared_conversion_state.footnote_id_numbers
+        = (FOOTNOTE_ID_NUMBER *) malloc (global_footnotes->number *
+                                         sizeof (FOOTNOTE_ID_NUMBER));
       for (i = 0; i < global_footnotes->number; i++)
         {
+          HTML_TARGET *element_target;
           const ELEMENT *footnote = global_footnotes->list[i];
           TEXT footid;
           TEXT docid;
@@ -4565,7 +4603,7 @@ prepare_footnotes_targets (CONVERTER *self)
             }
           add_string (footid.text, &self->seen_ids);
           add_string (docid.text, &self->seen_ids);
-          add_element_target (self, footnote, footid.text);
+          element_target = add_element_target (self, footnote, footid.text);
           add_special_target (self, ST_footnote_location, footnote,
                               docid.text);
 
@@ -4576,9 +4614,15 @@ prepare_footnotes_targets (CONVERTER *self)
                        footid.text, nr, footnote_txi);
               free (footnote_txi);
             }
+          self->shared_conversion_state.footnote_id_numbers[i].footnote_id
+             = element_target->target;
+          self->shared_conversion_state.footnote_id_numbers[i].number = 0;
           free (footid.text);
           free (docid.text);
         }
+      qsort (self->shared_conversion_state.footnote_id_numbers,
+             global_footnotes->number,
+             sizeof (FOOTNOTE_ID_NUMBER), compare_footnote_id);
     }
 }
 
@@ -8398,7 +8442,6 @@ convert_anchor_command (CONVERTER *self, const enum 
command_id cmd,
                     const HTML_ARGS_FORMATTED *args_formatted,
                     const char *content, TEXT *result)
 {
-
   if (!html_in_multi_expanded (self) && !html_in_string (self))
     {
       char *id = html_command_id (self, element);
@@ -8409,6 +8452,127 @@ convert_anchor_command (CONVERTER *self, const enum 
command_id cmd,
     }
 }
 
+void
+convert_footnote_command (CONVERTER *self, const enum command_id cmd,
+                    const ELEMENT *element,
+                    const HTML_ARGS_FORMATTED *args_formatted,
+                    const char *content, TEXT *result)
+{
+  const static char *target_prefix = "t_f";
+  char *footnote_mark;
+  const char *footnote_id;
+  const char *footnote_docid;
+  char *footid;
+  char *docid;
+  int multiple_expanded_footnote = 0;
+  const char *multi_expanded_region;
+  int foot_num;
+  char *footnote_href;
+  char *attribute_class;
+  STRING_LIST *classes;
+
+  self->shared_conversion_state.footnote_number++;
+  foot_num = self->shared_conversion_state.footnote_number;
+
+  if (self->conf->NUMBER_FOOTNOTES > 0)
+    xasprintf (&footnote_mark, "%d", foot_num);
+  else
+    footnote_mark = strdup (self->conf->NO_NUMBER_FOOTNOTE_SYMBOL);
+
+  if (html_in_string (self))
+    {
+      text_printf (result, "(%s)", footnote_mark);
+      free (footnote_mark);
+      return;
+    }
+
+  footnote_id = html_command_id (self, element);
+
+  /* happens for bogus footnotes */
+  if (!footnote_id)
+    return;
+
+  /* ID for linking back to the main text from the footnote. */
+  footnote_docid = html_footnote_location_target (self, element);
+
+  multi_expanded_region = html_in_multi_expanded (self);
+  if (multi_expanded_region)
+    {
+    /* to avoid duplicate names, use a prefix that cannot happen in anchors */
+      xasprintf (&footid, "%s%s_%s_%d\n", target_prefix, multi_expanded_region,
+                 footnote_id, foot_num);
+      xasprintf (&docid, "%s%s_%s_%d\n", target_prefix, multi_expanded_region,
+                 footnote_docid, foot_num);
+    }
+  else
+    {
+      FOOTNOTE_ID_NUMBER *footnote_id_number
+        = find_footnote_id_number (self, footnote_id);
+      if (!footnote_id_number)
+        fatal ("footnote_id not found");
+      if (!footnote_id_number->number)
+        {
+          footid = strdup (footnote_id);
+          docid = strdup (footnote_docid);
+        }
+      else
+        {
+    /* This should rarely happen, except for @footnote in @copying and
+       multiple @insertcopying...
+       Here it is not checked that there is no clash with another anchor.
+       However, unless there are more than 1000 footnotes this should not
+       happen at all, and even in that case it is very unlikely.
+     */
+          xasprintf (&footid, "%s_%d", footnote_id, foot_num);
+          xasprintf (&docid, "%s_%d", footnote_docid, foot_num);
+          multiple_expanded_footnote = 1;
+        }
+      footnote_id_number->number++;
+    }
+
+  if (!strcmp (self->conf->footnotestyle, "end")
+      && (multi_expanded_region || multiple_expanded_footnote))
+    {
+   /* if the footnote appears multiple times, command_href() will select
+      one, but it may not be the one expanded at the location currently
+      formatted (in general the first one, but it depends if it is in a
+      tree element or not, for instance in @titlepage).
+      With footnotestyle end, considering that the footnote is in the same file
+      has a better chance of being correct.
+    */
+      xasprintf (&footnote_href, "#%s", footid);
+    }
+  else
+    footnote_href = html_command_href (self, element, 0, 0, footid);
+
+  html_register_footnote (self, element, footid, docid, foot_num,
+                          self->current_filename.filename,
+                          multi_expanded_region);
+
+  classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+  memset (classes, 0, sizeof (STRING_LIST));
+  add_string (builtin_command_name (cmd), classes);
+
+  attribute_class = html_attribute_class (self, "a", classes);
+  destroy_strings_list (classes);
+  text_append (result, attribute_class);
+  free (attribute_class);
+
+  text_printf (result, " id=\"%s\" href=\"%s\">", docid, footnote_href);
+
+  if (html_in_preformatted_context (self))
+    text_printf (result, "(%s)", footnote_mark);
+  else
+    text_printf (result, "<sup>%s</sup>", footnote_mark);
+
+  text_append_n (result, "</a>", 4);
+
+  free (footnote_href);
+  free (footnote_mark);
+  free (footid);
+  free (docid);
+}
+
 void
 convert_indicateurl_command (CONVERTER *self, const enum command_id cmd,
                     const ELEMENT *element,
@@ -9901,6 +10065,9 @@ static COMMAND_INTERNAL_CONVERSION 
commands_internal_conversion_table[] = {
   {CM_abbr, &convert_explained_command},
   {CM_acronym, &convert_explained_command},
   {CM_anchor, &convert_anchor_command},
+  /* TODO shared_conversion_state not passed to/from perl
+  {CM_footnote, &convert_footnote_command},
+   */
 
   /* note that if indicateurl had been in self->style_formatted_cmd this
      would have prevented indicateurl to be associated to
@@ -11075,6 +11242,8 @@ html_reset_converter (CONVERTER *self)
       reset_html_targets (self, &self->html_special_targets[i]);
     }
 
+  free (self->shared_conversion_state.footnote_id_numbers);
+
   self->added_targets.number = 0;
 
   free (self->special_units_direction_name);
diff --git a/tp/Texinfo/XS/convert/convert_html.h 
b/tp/Texinfo/XS/convert/convert_html.h
index d247bbdd28..25243e4a56 100644
--- a/tp/Texinfo/XS/convert/convert_html.h
+++ b/tp/Texinfo/XS/convert/convert_html.h
@@ -94,7 +94,7 @@ STRING_LIST *html_get_css_elements_classes (CONVERTER *self,
 
 void html_register_footnote (CONVERTER *self, const ELEMENT *command,
      const char *footid, const char *docid, const int number_in_doc,
-     const char *footnote_location_filename, char *multi_expanded_region);
+     const char *footnote_location_filename, const char 
*multi_expanded_region);
 HTML_PENDING_FOOTNOTE_STACK *html_get_pending_footnotes (CONVERTER *self);
 void destroy_pending_footnotes (HTML_PENDING_FOOTNOTE_STACK *stack);
 
diff --git a/tp/Texinfo/XS/main/converter_types.h 
b/tp/Texinfo/XS/main/converter_types.h
index 12e4527d3f..06416a386d 100644
--- a/tp/Texinfo/XS/main/converter_types.h
+++ b/tp/Texinfo/XS/main/converter_types.h
@@ -294,11 +294,17 @@ typedef struct EXPLAINED_COMMAND_TYPE_LIST {
     EXPLAINED_COMMAND_TYPE *list;
 } EXPLAINED_COMMAND_TYPE_LIST;
 
+typedef struct FOOTNOTE_ID_NUMBER {
+    const char *footnote_id;
+    int number;
+} FOOTNOTE_ID_NUMBER;
+
 typedef struct HTML_SHARED_CONVERSION_STATE {
     EXPLAINED_COMMAND_TYPE_LIST explained_commands;
         /* explained_commands->{char $cmdname}->{char $normalized_type}
                                = explanation */
-    int footnote_id_numbers; /* footnote_id_numbers->{char $footid} = int */
+    int footnote_number;
+    FOOTNOTE_ID_NUMBER *footnote_id_numbers; /* footnote_id_numbers->{char 
$footid} = int */
     /* Not useful, directly use expanded formats in the converter.
        Needed in perl as expanded formats are accessed per format in the API
     int expanded_format_raw;



reply via email to

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