texinfo-commits
[Top][All Lists]
Advanced

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

branch master updated: * tp/Texinfo/Convert/HTML.pm (html_get_css_elemen


From: Patrice Dumas
Subject: branch master updated: * tp/Texinfo/Convert/HTML.pm (html_get_css_elements_classes) (_default_format_css_lines), doc/texi2any_api.texi (Customizing CSS): have html_get_css_elements_classes return a reference on an array, not an array.
Date: Tue, 21 Nov 2023 19:01:37 -0500

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

pertusus pushed a commit to branch master
in repository texinfo.

The following commit(s) were added to refs/heads/master by this push:
     new 0bd02d6fae * tp/Texinfo/Convert/HTML.pm 
(html_get_css_elements_classes) (_default_format_css_lines), 
doc/texi2any_api.texi (Customizing CSS): have html_get_css_elements_classes 
return a reference on an array, not an array.
0bd02d6fae is described below

commit 0bd02d6fae86edade24a8558f67f8935f0099261
Author: Patrice Dumas <pertusus@free.fr>
AuthorDate: Wed Nov 22 00:56:23 2023 +0100

    * tp/Texinfo/Convert/HTML.pm (html_get_css_elements_classes)
    (_default_format_css_lines), doc/texi2any_api.texi (Customizing CSS):
    have html_get_css_elements_classes return a reference on an array, not
    an array.
    
    * tp/Texinfo/Convert/HTML.pm: rename $self->{'file_css'} as
    $self->{'page_css'}.
    
    * tp/Texinfo/Convert/HTML.pm (convert),
    tp/Texinfo/XS/convert/convert_html.c (html_convert_convert): set
    current_filename in _html_convert_convert.
    
    * tp/Texinfo/XS/main/get_perl_info.c (add_svav_to_string_list),
    tp/Texinfo/XS/main/get_perl_info.h (enum sv_string_type),
    tp/maintain/regenerate_C_options_info.pl: add the possibility to get
    utf-8 strings in add_svav_to_string_list, and use enum to specify the
    type of strings.  Update callers.
    
    * tp/Texinfo/XS/convert/ConvertXS.xs (html_prepare_title_titlepage),
    tp/Texinfo/XS/convert/get_html_perl_info.c
    (html_converter_prepare_output_sv),
    tp/Texinfo/XS/convert/convert_html.c (html_converter_prepare_output),
    tp/Texinfo/XS/main/converter_types.h (CSS_SELECTOR_STYLE)
    (CSS_SELECTOR_STYLE_LIST, CONVERTER): add
    html_converter_prepare_output_sv and call it in
    html_prepare_title_titlepage to have XS code called just before the
    conversion.  html_converter_prepare_output_sv calls
    html_converter_prepare_output for code that do not need interaction
    with perl.  Use those functions to import css_element_class_styles
    information from perl.
    
    * tp/Texinfo/XS/convert/build_html_perl_state.c
    (build_html_formatting_state), tp/Texinfo/XS/convert/convert_html.c
    (html_convert_convert, convert_output_output_unit_internal)
    (html_prepare_title_titlepage, html_convert_output),
    tp/Texinfo/XS/main/converter_types.h (CURRENT_FILE_INFO, CONVERTER):
    use CURRENT_FILE_INFO for current_file, adding the index in output
    files.
    
    * tp/Texinfo/Convert/HTML.pm (%XS_conversion_overrides),
    tp/Texinfo/XS/convert/ConvertXS.xs (html_attribute_class)
    (html_get_css_elements_classes), tp/Texinfo/XS/convert/convert_html.c
    (compare_page_name_number, find_page_name_number)
    (compare_selector_style, find_css_selector_style)
    (collect_css_element_class, compare_strings)
    (html_get_css_elements_classes, protect_class_name)
    (html_attribute_class, html_set_pages_files, setup_output_simple_page)
    (html_prepare_units_directions_files)
    (html_prepare_units_directions_files),
    tp/Texinfo/XS/main/converter_types.h (PAGE_NAME_NUMBER)
    (PAGE_NAME_NUMBER_LIST, CSS_LIST, PAGES_CSS_LIST, CONVERTER):
    implement collect_css_element_class, protect_class_name,
    html_get_css_elements_classes and html_attribute_class in C, and add
    XS interfaces for html_attribute_class and
    html_get_css_elements_classes.
---
 ChangeLog                                     |  58 ++
 doc/texi2any_api.texi                         |   6 +-
 tp/Texinfo/Convert/HTML.pm                    |  37 +-
 tp/Texinfo/XS/convert/ConvertXS.xs            |  78 +++
 tp/Texinfo/XS/convert/build_html_perl_state.c |   4 +-
 tp/Texinfo/XS/convert/convert_html.c          | 797 +++++++++++++++++++-------
 tp/Texinfo/XS/convert/convert_html.h          |   7 +
 tp/Texinfo/XS/convert/get_html_perl_info.c    |  50 +-
 tp/Texinfo/XS/convert/get_html_perl_info.h    |   1 +
 tp/Texinfo/XS/main/converter_types.h          |  45 +-
 tp/Texinfo/XS/main/get_perl_info.c            |  12 +-
 tp/Texinfo/XS/main/get_perl_info.h            |   8 +-
 tp/maintain/regenerate_C_options_info.pl      |   6 +-
 13 files changed, 871 insertions(+), 238 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d679040d3e..3fee5ba718 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,61 @@
+2023-11-21  Patrice Dumas  <pertusus@free.fr>
+
+       * tp/Texinfo/Convert/HTML.pm (html_get_css_elements_classes)
+       (_default_format_css_lines), doc/texi2any_api.texi (Customizing CSS):
+       have html_get_css_elements_classes return a reference on an array, not
+       an array.
+
+       * tp/Texinfo/Convert/HTML.pm: rename $self->{'file_css'} as
+       $self->{'page_css'}.
+
+       * tp/Texinfo/Convert/HTML.pm (convert),
+       tp/Texinfo/XS/convert/convert_html.c (html_convert_convert): set
+       current_filename in _html_convert_convert.
+
+       * tp/Texinfo/XS/main/get_perl_info.c (add_svav_to_string_list),
+       tp/Texinfo/XS/main/get_perl_info.h (enum sv_string_type),
+       tp/maintain/regenerate_C_options_info.pl: add the possibility to get
+       utf-8 strings in add_svav_to_string_list, and use enum to specify the
+       type of strings.  Update callers.
+
+       * tp/Texinfo/XS/convert/ConvertXS.xs (html_prepare_title_titlepage),
+       tp/Texinfo/XS/convert/get_html_perl_info.c
+       (html_converter_prepare_output_sv),
+       tp/Texinfo/XS/convert/convert_html.c (html_converter_prepare_output),
+       tp/Texinfo/XS/main/converter_types.h (CSS_SELECTOR_STYLE)
+       (CSS_SELECTOR_STYLE_LIST, CONVERTER): add
+       html_converter_prepare_output_sv and call it in
+       html_prepare_title_titlepage to have XS code called just before the
+       conversion.  html_converter_prepare_output_sv calls
+       html_converter_prepare_output for code that do not need interaction
+       with perl.  Use those functions to import css_element_class_styles
+       information from perl.
+
+       * tp/Texinfo/XS/convert/build_html_perl_state.c
+       (build_html_formatting_state), tp/Texinfo/XS/convert/convert_html.c
+       (html_convert_convert, convert_output_output_unit_internal)
+       (html_prepare_title_titlepage, html_convert_output),
+       tp/Texinfo/XS/main/converter_types.h (CURRENT_FILE_INFO, CONVERTER): 
+       use CURRENT_FILE_INFO for current_file, adding the index in output
+       files.
+
+       * tp/Texinfo/Convert/HTML.pm (%XS_conversion_overrides),
+       tp/Texinfo/XS/convert/ConvertXS.xs (html_attribute_class)
+       (html_get_css_elements_classes), tp/Texinfo/XS/convert/convert_html.c
+       (compare_page_name_number, find_page_name_number)
+       (compare_selector_style, find_css_selector_style)
+       (collect_css_element_class, compare_strings)
+       (html_get_css_elements_classes, protect_class_name)
+       (html_attribute_class, html_set_pages_files, setup_output_simple_page)
+       (html_prepare_units_directions_files)
+       (html_prepare_units_directions_files),
+       tp/Texinfo/XS/main/converter_types.h (PAGE_NAME_NUMBER)
+       (PAGE_NAME_NUMBER_LIST, CSS_LIST, PAGES_CSS_LIST, CONVERTER):
+       implement collect_css_element_class, protect_class_name,
+       html_get_css_elements_classes and html_attribute_class in C, and add
+       XS interfaces for html_attribute_class and
+       html_get_css_elements_classes.
+
 2023-11-21  Gavin Smith <gavinsmith0123@gmail.com>
 
        * tp/Texinfo/XS/Makefile.am (libtexinfoxs_la_LDFLAGS):
diff --git a/doc/texi2any_api.texi b/doc/texi2any_api.texi
index 61e991132e..f97d41317b 100644
--- a/doc/texi2any_api.texi
+++ b/doc/texi2any_api.texi
@@ -4300,10 +4300,10 @@ The CSS @var{element}.@var{class} that appeared in a 
file, gathered through
 Classes}) are available through the @code{html_get_css_elements_classes}
 function:
 
-@deftypefun {@var{@@css_element_classes} =} 
@var{$converter}->html_get_css_elements_classes @
+@deftypefun {@var{\@@css_element_classes} =} 
@var{$converter}->html_get_css_elements_classes @
     (@var{$file_name})
-Returns an array containing @code{element.class} pairs of elements and classes
-appearing in @var{$file_name}.
+Returns a reference on an array containing @code{element.class} pairs of 
elements
+and classes appearing in @var{$file_name}.
 @end deftypefun
 
 It is possible to change completely how CSS lines are generated
diff --git a/tp/Texinfo/Convert/HTML.pm b/tp/Texinfo/Convert/HTML.pm
index 7a32ddce63..8e59f103d0 100644
--- a/tp/Texinfo/Convert/HTML.pm
+++ b/tp/Texinfo/Convert/HTML.pm
@@ -126,6 +126,10 @@ my %XS_conversion_overrides = (
    => "Texinfo::Convert::ConvertXS::html_register_opened_section_level",
   "Texinfo::Convert::HTML::close_registered_sections_level"
    => "Texinfo::Convert::ConvertXS::html_close_registered_sections_level",
+  "Texinfo::Convert::HTML::html_attribute_class"
+   => "Texinfo::Convert::ConvertXS::html_attribute_class",
+  "Texinfo::Convert::HTML::html_get_css_elements_classes"
+   => "Texinfo::Convert::ConvertXS::html_get_css_elements_classes",
   "Texinfo::Convert::HTML::_XS_get_index_entries_sorted_by_letter"
    => "Texinfo::Convert::ConvertXS::get_index_entries_sorted_by_letter",
   "Texinfo::Convert::HTML::_XS_html_merge_index_entries"
@@ -238,9 +242,9 @@ sub _collect_css_element_class($$)
     if ($self->{'document_global_context'}) {
       $self->{'document_global_context_css'}->{$element_class} = 1;
     } elsif (defined($self->{'current_filename'})) {
-      $self->{'file_css'}->{$self->{'current_filename'}} = {}
-        if (!$self->{'file_css'}->{$self->{'current_filename'}});
-      $self->{'file_css'}->{$self->{'current_filename'}}->{$element_class} = 1;
+      $self->{'page_css'}->{$self->{'current_filename'}} = {}
+        if (!$self->{'page_css'}->{$self->{'current_filename'}});
+      $self->{'page_css'}->{$self->{'current_filename'}}->{$element_class} = 1;
     }
   }
 }
@@ -314,17 +318,18 @@ sub html_get_css_elements_classes($;$)
                               %{$self->{'document_global_context_css'}} );
   }
 
-  if (defined($filename) and $self->{'file_css'}
-      and $self->{'file_css'}->{$filename}) {
+  if (defined($filename) and $self->{'page_css'}
+      and $self->{'page_css'}->{$filename}) {
     %css_elements_classes = ( %css_elements_classes,
-                              %{$self->{'file_css'}->{$filename}} );
+                              %{$self->{'page_css'}->{$filename}} );
   }
 
   if ($css_elements_classes{'a.copiable-link'}) {
     $css_elements_classes{'span:hover a.copiable-link'} = 1;
   }
 
-  return sort(keys(%css_elements_classes));
+  my @result = sort(keys(%css_elements_classes));
+  return \@result;
 }
 
 sub close_html_lone_element($$) {
@@ -8026,7 +8031,7 @@ sub _load_htmlxref_files {
 #
 #     API exists
 #  document_global_context_css
-#  file_css
+#  page_css
 #
 #     API exists
 #  files_information
@@ -8642,18 +8647,18 @@ sub _default_format_css_lines($;$)
   return '' if ($self->get_conf('NO_CSS'));
 
   my $css_refs = $self->get_conf('CSS_REFS');
-  my @css_element_classes = $self->html_get_css_elements_classes($filename);
+  my $css_element_classes = $self->html_get_css_elements_classes($filename);
   my $css_import_lines = $self->css_get_info('imports');
   my $css_rule_lines = $self->css_get_info('rules');
 
-  return '' if !@$css_import_lines and !@css_element_classes
+  return '' if !@$css_import_lines and !@$css_element_classes
                  and !@$css_rule_lines
                  and (!defined($css_refs) or !@$css_refs);
 
   my $css_text = "<style type=\"text/css\">\n<!--\n";
   $css_text .= join('', @$css_import_lines) . "\n"
     if (@$css_import_lines);
-  foreach my $element_class (@css_element_classes) {
+  foreach my $element_class (@$css_element_classes) {
     my $css_style = $self->css_selector_style($element_class);
     $css_text .= "$element_class {$css_style}\n"
       if defined($css_style );
@@ -11036,7 +11041,7 @@ sub _initialize_output_state($$)
 
   # Needed for CSS gathering, even if nothing related to CSS is output
   $self->{'document_global_context_css'} = {};
-  $self->{'file_css'} = {};
+  $self->{'page_css'} = {};
 
   # direction strings
   foreach my $string_type (keys(%default_translated_directions_strings)) {
@@ -11112,6 +11117,8 @@ sub _html_convert_convert($$$$)
 
   my $result = '';
 
+  $self->{'current_filename'} = '';
+
   if (!defined($output_units)) {
     print STDERR "\nC NO UNIT\n" if ($self->get_conf('DEBUG'));
     $result = $self->_convert($root, 'convert no unit');
@@ -11129,6 +11136,7 @@ sub _html_convert_convert($$$$)
       $unit_nr++;
     }
   }
+  $self->{'current_filename'} = undef;
   return $result;
 }
 
@@ -11198,12 +11206,9 @@ sub convert($$)
   # complete information should be available.
   $self->_reset_info();
 
-  $self->{'current_filename'} = '';
-
   # main conversion here
   my $result = $self->_html_convert_convert ($root, $output_units,
                                              $special_units);
-  $self->{'current_filename'} = undef;
 
   $self->_finalize_output_state();
   return $result;
@@ -11753,6 +11758,7 @@ sub output($$)
   }
 
   # Get the list of output units to be processed.
+  # Customization information in $self->{'conf'} is passed to XS code too.
   my ($output_units, $special_units, $associated_special_units)
     = $self->_prepare_conversion_units($root, $document_name);
 
@@ -11882,6 +11888,7 @@ sub output($$)
     return undef;
   }
 
+  # information settable by customization files is passed to XS too
   $self->_prepare_title_titlepage($output_units, $output_file,
                                   $output_filename);
 
diff --git a/tp/Texinfo/XS/convert/ConvertXS.xs 
b/tp/Texinfo/XS/convert/ConvertXS.xs
index 95c0c3499f..63941151f9 100644
--- a/tp/Texinfo/XS/convert/ConvertXS.xs
+++ b/tp/Texinfo/XS/convert/ConvertXS.xs
@@ -346,6 +346,82 @@ html_close_registered_sections_level (SV *converter_in, 
int level)
     OUTPUT:
          RETVAL
 
+SV *
+html_attribute_class (SV *converter_in, element, ...)
+         char *element = (char *)SvPVutf8_nolen($arg);
+    PROTOTYPE: $$;$
+    PREINIT:
+         CONVERTER *self;
+         SV *classes_sv = 0;
+         STRING_LIST *classes = 0;
+    CODE:
+         self = get_sv_converter (converter_in,
+                                  "html_attribute_class");
+         if (items > 2 && SvOK(ST(2)))
+           classes_sv = ST(2);
+
+         if (self)
+           {
+             char *result;
+             if (classes_sv)
+               {
+                 classes = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+                 memset (classes, 0, sizeof (STRING_LIST));
+                 add_svav_to_string_list (classes_sv, classes, svt_char);
+               }
+             result = html_attribute_class (self, element, classes);
+             if (classes)
+               destroy_strings_list (classes);
+             RETVAL = newSVpv_utf8 (result, 0);
+             free (result);
+           }
+         else
+           RETVAL = newSV (0);
+    OUTPUT:
+         RETVAL
+
+SV *
+html_get_css_elements_classes (SV *converter_in, ...)
+    PROTOTYPE: $;$
+    PREINIT:
+         CONVERTER *self;
+         SV *filename_sv = 0;
+         AV *css_selector_av;
+    CODE:
+         self = get_sv_converter (converter_in,
+                                  "html_attribute_class");
+         if (items > 1 && SvOK(ST(1)))
+           filename_sv = ST(1);
+
+         css_selector_av = newAV ();
+
+         if (self)
+           {
+             STRING_LIST *result;
+             char *filename = 0;
+             if (filename_sv)
+               filename = SvPVutf8_nolen (filename_sv);
+             result = html_get_css_elements_classes (self, filename);
+             if (result)
+               {
+                 if (result->number)
+                   {
+                     int i;
+                     for (i = 0; i < result->number; i++)
+                       {
+                         SV *selector_sv
+                            = newSVpv_utf8 (result->list[i], 0);
+                         av_push (css_selector_av, selector_sv);
+                       }
+                   }
+                 destroy_strings_list (result);
+               }
+           }
+         RETVAL = newRV_noinc ((SV *) css_selector_av);
+    OUTPUT:
+         RETVAL
+
+
 void
 html_merge_index_entries (SV *converter_in)
       PREINIT:
@@ -560,6 +636,8 @@ html_prepare_title_titlepage (SV *converter_in, SV 
*output_units_in, output_file
 
          if (self)
            {
+             html_converter_prepare_output_sv (converter_in, self);
+
              html_prepare_title_titlepage (self, output_units_descriptor,
                                            output_file, output_filename);
              if (self->modified_state)
diff --git a/tp/Texinfo/XS/convert/build_html_perl_state.c 
b/tp/Texinfo/XS/convert/build_html_perl_state.c
index 8ebbd4a438..9497c135ee 100644
--- a/tp/Texinfo/XS/convert/build_html_perl_state.c
+++ b/tp/Texinfo/XS/convert/build_html_perl_state.c
@@ -796,8 +796,8 @@ build_html_formatting_state (CONVERTER *converter, unsigned 
long flags)
       SV **current_filename_sv;
       current_filename_sv = hv_fetch (hv, "current_filename",
                                       strlen ("current_filename"), 1);
-      sv_setpv (*current_filename_sv, converter->current_filename);
-      if (converter->current_filename)
+      sv_setpv (*current_filename_sv, converter->current_filename.filename);
+      if (converter->current_filename.filename)
         SvUTF8_on (*current_filename_sv);
     }
 
diff --git a/tp/Texinfo/XS/convert/convert_html.c 
b/tp/Texinfo/XS/convert/convert_html.c
index 828d1ce3d8..a7463f9253 100644
--- a/tp/Texinfo/XS/convert/convert_html.c
+++ b/tp/Texinfo/XS/convert/convert_html.c
@@ -1429,13 +1429,521 @@ get_target (CONVERTER *self, const ELEMENT *element)
   return result;
 }
 
+/* to be inlined in text parsing codes */
+#define OTXI_PROTECT_XML_FORM_FEED_CASES(var) \
+        OTXI_PROTECT_XML_CASES(var) \
+        case '\f':          \
+          text_append_n (result, "&#12;", 5); var++; \
+          break;
+
+
+#define ADDN(str,nr) text_append_n (result, str, nr)
+
+void
+default_css_string_format_protect_text (const char *text, TEXT *result)
+{
+  const char *p = text;
+
+  while (*p)
+    {
+      int before_sep_nr = strcspn (p, "\\'");
+      if (before_sep_nr)
+        {
+          text_append_n (result, p, before_sep_nr);
+          p += before_sep_nr;
+        }
+      if (!*p)
+        break;
+      switch (*p)
+        {
+        case '\\':
+          ADDN("\\\\", 2);
+          break;
+        case '\'':
+          ADDN("\\'", 2);
+          break;
+        }
+      p++;
+    }
+}
+
+#define OTXI_ISO_ENTITY_TEXT_CASES(var) \
+        case '-': \
+          if (*(var+1) && !memcmp (var, "---", 3)) \
+            { \
+              text_append_n (result, "&mdash;", 7); \
+              var += 3; \
+            } \
+          else if (!memcmp (var, "--", 2)) \
+            { \
+              text_append_n (result, "&ndash;", 7); \
+              var += 2; \
+            } \
+          else \
+            { \
+              text_append_n (result, "-", 1); \
+              var++; \
+            } \
+          break; \
+        case '`': \
+          if (!memcmp (var, "``", 2)) \
+            { \
+              text_append_n (result, "&ldquo;", 7); \
+              var += 2; \
+            } \
+          else \
+            { \
+              text_append_n (result, "&lsquo;", 7); \
+              var++; \
+            } \
+          break; \
+        case '\'': \
+          if (!memcmp (var, "''", 2)) \
+            { \
+              text_append_n (result, "&rdquo;", 7); \
+              var += 2; \
+            } \
+          else \
+            { \
+              text_append_n (result, "&rsquo;", 7); \
+              var++; \
+            } \
+          break;
+
+#define OTXI_NO_ISO_ENTITY_TEXT_CASES(var) \
+        case '-': \
+          if (*(var+1) && !memcmp (var, "---", 3)) \
+            { \
+              text_append_n (result, "--", 2); \
+              var += 3; \
+            } \
+          else \
+            { \
+              text_append_n (result, "-", 1); \
+              if (!memcmp (var, "--", 2)) \
+                var += 2; \
+              else \
+                var++; \
+            } \
+          break; \
+        case '`': \
+          if (!memcmp (var, "``", 2)) \
+            { \
+              text_append_n (result, "&quot;", 6); \
+              var += 2; \
+            } \
+          else \
+            { \
+              text_append_n (result, var, 1); \
+              var++; \
+            } \
+          break; \
+        case '\'': \
+          if (!memcmp (var, "''", 2)) \
+            { \
+              text_append_n (result, "&quot;", 6); \
+              var += 2; \
+            } \
+          else \
+            { \
+              text_append_n (result, var, 1); \
+              var++; \
+            } \
+          break;
+
+#define OTXI_NO_BREAK_CASES(var) \
+        case ' ': \
+        case '\n': \
+          text_append_n (result, \
+               self->special_character[SC_non_breaking_space].string, \
+               self->special_character[SC_non_breaking_space].len); \
+          var += strspn (var, "\n "); \
+          break;
+
+#define OTXI_SPACE_PROTECTION_CASES(var) \
+        case ' ': \
+          text_append_n (result, \
+               self->special_character[SC_non_breaking_space].string, \
+               self->special_character[SC_non_breaking_space].len); \
+          var++; \
+          break; \
+        case '\n': \
+          text_append_n (result, self->line_break_element.string, \
+                         self->line_break_element.len); \
+          var++; \
+          break;
+
+/* text conversion loop, with the protection of XML special
+   characters and the possibility to add more delimiters and
+   more cases to handle those delimiters */
+#define OTXI_CONVERT_TEXT(delimiters,other_cases) \
+  { \
+  while (*p)  \
+    { \
+      int before_sep_nr = strcspn (p, "<>&\"\f" delimiters); \
+      if (before_sep_nr) \
+        { \
+          text_append_n (result, p, before_sep_nr); \
+          p += before_sep_nr; \
+        } \
+      if (!*p) \
+        break; \
+      switch (*p) \
+        { \
+          OTXI_PROTECT_XML_FORM_FEED_CASES(p) \
+          other_cases \
+        } \
+    } \
+  }
+
+/* conversion of text for all the possibilities regarding -- --- ''
+   conversion, with the possibility to add more for spaces protection */
+#define OTXI_ALL_CONVERT_TEXT(additional_delim,other_cases) \
+  const char *p = content_used; \
+      if (in_code (self) || in_math (self)) \
+        OTXI_CONVERT_TEXT(additional_delim,  \
+          other_cases) \
+      else if (self->use_unicode_text) \
+        OTXI_CONVERT_TEXT("-`'" additional_delim, \
+          OTXI_UNICODE_TEXT_CASES(p) \
+          other_cases) \
+      else if (self->conf->USE_NUMERIC_ENTITY > 0) \
+        OTXI_CONVERT_TEXT("-`'" additional_delim, \
+          OTXI_NUMERIC_ENTITY_TEXT_CASES(p) \
+          other_cases) \
+      else if (self->conf->USE_ISO > 0) \
+        OTXI_CONVERT_TEXT("-`'" additional_delim, \
+          OTXI_ISO_ENTITY_TEXT_CASES(p) \
+          other_cases) \
+      else \
+        OTXI_CONVERT_TEXT("-`'" additional_delim, \
+          OTXI_NO_ISO_ENTITY_TEXT_CASES(p) \
+          other_cases)
+
+void
+html_default_format_protect_text (const char *text, TEXT *result)
+{
+  const char *p = text;
+
+  OTXI_CONVERT_TEXT ( , )
+}
+
 char *html_command_id (CONVERTER *self, ELEMENT *command)
 {
   HTML_TARGET *target = get_target (self, command);
   if (target)
     return target->target;
   else
-    return 0;
+    return 0;
+}
+
+static int
+compare_page_name_number (const void *a, const void *b)
+{
+  const PAGE_NAME_NUMBER *css_a = (const PAGE_NAME_NUMBER *) a;
+  const PAGE_NAME_NUMBER *css_b = (const PAGE_NAME_NUMBER *) b;
+
+  return strcmp (css_a->page_name, css_b->page_name);
+}
+
+size_t
+find_page_name_number
+     (const PAGE_NAME_NUMBER_LIST *page_name_number,
+                                          const char *page_name)
+{
+  PAGE_NAME_NUMBER *result = 0;
+  static PAGE_NAME_NUMBER searched_page_name;
+  searched_page_name.page_name = page_name;
+
+  result = (PAGE_NAME_NUMBER *) bsearch (&searched_page_name,
+                page_name_number->list,
+                page_name_number->number, sizeof(PAGE_NAME_NUMBER),
+                compare_page_name_number);
+  return result->number;
+}
+
+static int
+compare_selector_style (const void *a, const void *b)
+{
+  const CSS_SELECTOR_STYLE *css_a = (const CSS_SELECTOR_STYLE *) a;
+  const CSS_SELECTOR_STYLE *css_b = (const CSS_SELECTOR_STYLE *) b;
+
+  return strcmp (css_a->selector, css_b->selector);
+}
+
+CSS_SELECTOR_STYLE *
+find_css_selector_style
+     (const CSS_SELECTOR_STYLE_LIST *css_element_class_styles,
+                                           const char *selector)
+{
+  CSS_SELECTOR_STYLE *result = 0;
+  static CSS_SELECTOR_STYLE searched_selector;
+  searched_selector.selector = selector;
+
+  result = (CSS_SELECTOR_STYLE *) bsearch (&searched_selector,
+                css_element_class_styles->list,
+                css_element_class_styles->number, sizeof(CSS_SELECTOR_STYLE),
+                compare_selector_style);
+
+  return result;
+}
+
+static void
+collect_css_element_class (CONVERTER *self, const char *selector)
+{
+  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;
+        }
+      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++;
+    }
+}
+
+int
+compare_strings (const void *a, const void *b)
+{
+  const char **str_a = (const char **) a;
+  const char **str_b = (const char **) b;
+
+  return strcmp (*str_a, *str_b);
+}
+
+STRING_LIST *
+html_get_css_elements_classes (CONVERTER *self, const char *filename)
+{
+  int j;
+  size_t page_number;
+  STRING_LIST *result;
+  const char **selectors;
+  size_t selector_nr = 0;
+
+  if (self->page_css.number <= 0)
+    return 0;
+
+  CSS_LIST *global_context_css_list = &self->page_css.list[0];
+
+  if (filename)
+    {
+      CSS_LIST *css_list;
+      page_number = find_page_name_number (&self->page_name_number,
+                                           filename);
+      if (!page_number)
+        fatal ("Could not find page number of file name");
+
+      css_list = &self->page_css.list[page_number];
+      if (css_list->number)
+        {
+          /* +1 for 'span:hover a.copiable-link' */
+          size_t space = css_list->number + global_context_css_list->number +1;
+          selectors = (const char **) malloc (sizeof (char *) * space);
+          memcpy (selectors, css_list->list,
+                  css_list->number * sizeof (char *));
+          selector_nr = css_list->number;
+        }
+    }
+
+  if (selector_nr <= 0)
+    {
+      if (global_context_css_list->number)
+        {
+          /* +1 for 'span:hover a.copiable-link' */
+          size_t space = global_context_css_list->number +1;
+          selectors = (const char **) malloc (sizeof (char *) * space);
+          selector_nr = global_context_css_list->number;
+        }
+      else
+        return 0;
+    }
+  else if (global_context_css_list->number)
+    {
+      int i;
+      size_t file_selector_nr = selector_nr;
+      /* add global context selectors if not already present */
+      for (i = 0; i < global_context_css_list->number; i++)
+        {
+          int j;
+          const char *global_selector = global_context_css_list->list[i];
+          int found = 0;
+          for (j = 0; j < file_selector_nr; j++)
+            {
+              if (!strcmp (global_selector, selectors[j]))
+                {
+                  found = 1;
+                  break;
+                }
+            }
+          if (!found)
+            {
+              selectors[selector_nr] = global_selector;
+              selector_nr++;
+            }
+        }
+    }
+  for (j = 0; j < selector_nr; j++)
+    {
+      if (!strcmp ("a.copiable-link", selectors[j]))
+         {
+           selectors[selector_nr] = "span:hover a.copiable-link";
+           selector_nr++;
+           break;
+         }
+    }
+
+  qsort (selectors, selector_nr, sizeof (char *), compare_strings);
+
+  result = (STRING_LIST *) malloc (sizeof (STRING_LIST));
+  memset (result, 0, sizeof (STRING_LIST));
+  for (j = 0; j < selector_nr; j++)
+    add_string (selectors[j], result);
+
+  return result;
+}
+
+static char *
+protect_class_name (const char *class_name)
+{
+  TEXT result;
+  TEXT space_protected;
+  text_init (&result);
+  text_init (&space_protected);
+  const char *p = class_name;
+  while (*p)
+    {
+      int n = strcspn (p, " ");
+      if (n)
+        {
+          text_append_n (&space_protected, p, n);
+          p += n;
+        }
+      if (*p)
+        {
+          int n = strspn (p, " ");
+          if (n)
+            {
+              int i;
+              for (i = 0; i < n; i++)
+                text_append_n (&space_protected, "-", 1);
+              p += n;
+            }
+        }
+    }
+
+  /* do not use the customization API as in perl */
+  html_default_format_protect_text (space_protected.text, &result);
+  free (space_protected.text);
+  return result.text;
+}
+
+char *
+html_attribute_class (CONVERTER *self, const char *element,
+                      const STRING_LIST *classes)
+{
+  TEXT result;
+  char *style = 0;
+  int i;
+  int class_nr = 0;
+  if (!classes  || classes->number <= 0
+      || self->conf->NO_CSS > 0)
+    {
+      if (!strcmp (element, "span"))
+        return strdup ("");
+      else
+        {
+          char *result;
+          xasprintf (&result, "<%s", element);
+          return result;
+        }
+    }
+
+  if (self->conf->INLINE_CSS_STYLE > 0)
+    {
+      int i;
+      TEXT inline_styles;
+      text_init (&inline_styles);
+      int style_nr = 0;
+      for (i = 0; i < classes->number; i++)
+        {
+          const char *style_class = classes->list[i];
+          char *selector;
+          CSS_SELECTOR_STYLE *selector_style;
+
+          xasprintf (&selector, "%s.%s", element, style_class);
+          selector_style
+            = find_css_selector_style (&self->css_element_class_styles,
+                                       selector);
+          free (selector);
+          if (selector_style)
+            {
+              if (style_nr)
+                 text_printf (&inline_styles, ";%s", selector_style->style);
+              else
+                 text_append (&inline_styles, selector_style->style);
+              style_nr++;
+            }
+        }
+      if (inline_styles.end)
+        {
+          xasprintf (&style, " style=\"%s\"", inline_styles.text);
+        }
+      free (inline_styles.text);
+    }
+  else
+    {
+      int i;
+      for (i = 0; i < classes->number; i++)
+        {
+          const char *style_class = classes->list[i];
+          char *selector;
+
+          xasprintf (&selector, "%s.%s", element, style_class);
+          collect_css_element_class (self, selector);
+          free (selector);
+        }
+    }
+  text_init (&result);
+  text_printf (&result, "<%s class=\"", element);
+  for (i = 0; i < classes->number; i++)
+    {
+      const char *class_name = classes->list[i];
+      char *protected_class = protect_class_name (class_name);
+      if (class_nr)
+        text_printf (&result, " %s", protected_class);
+      else
+        text_append (&result, protected_class);
+      free (protected_class);
+      class_nr++;
+    }
+  text_append_n (&result, "\"", 1);
+  if (style)
+    {
+      text_append (&result, style);
+      free (style);
+    }
+  return result.text;
 }
 
 void
@@ -2328,9 +2836,36 @@ html_set_pages_files (CONVERTER *self, OUTPUT_UNIT_LIST 
*output_units,
   memset (self->file_changed_counter.list, 0,
           self->output_unit_files.number * sizeof (size_t));
 
+  /* 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.list = (CSS_LIST *)
+       malloc (self->page_css.number * sizeof (CSS_LIST));
+  memset (self->page_css.list, 0,
+          self->page_css.number * sizeof (CSS_LIST));
+
   return files_source_info;
 }
 
+void
+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.list = (CSS_LIST *)
+       malloc (self->page_css.number * sizeof (CSS_LIST));
+  memset (self->page_css.list, 0,
+          self->page_css.number * 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_name_number = &self->page_name_number.list[0];
+  page_name_number->number = 1;
+  page_name_number->page_name = output_filename;
+}
+
 static void
 prepare_special_units_directions (CONVERTER *self,
                                   OUTPUT_UNIT_LIST *special_units)
@@ -2376,6 +2911,9 @@ html_prepare_units_directions_files (CONVERTER *self,
                         associated_special_units, output_file,
                         destination_directory, output_filename, document_name);
     }
+  else
+    setup_output_simple_page (self, output_filename);
+
 
   units_directions (self->conf, self->document->identifiers_target,
                     output_units);
@@ -2388,217 +2926,32 @@ html_prepare_units_directions_files (CONVERTER *self,
     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;
-        }
-    }
-
-  return files_source_info;
-}
-
-/* to be inlined in text parsing codes */
-#define OTXI_PROTECT_XML_FORM_FEED_CASES(var) \
-        OTXI_PROTECT_XML_CASES(var) \
-        case '\f':          \
-          text_append_n (result, "&#12;", 5); var++; \
-          break;
-
-
-#define ADDN(str,nr) text_append_n (result, str, nr)
-
-void
-default_css_string_format_protect_text (const char *text, TEXT *result)
-{
-  const char *p = text;
 
-  while (*p)
-    {
-      int before_sep_nr = strcspn (p, "\\'");
-      if (before_sep_nr)
-        {
-          text_append_n (result, p, before_sep_nr);
-          p += before_sep_nr;
-        }
-      if (!*p)
-        break;
-      switch (*p)
-        {
-        case '\\':
-          ADDN("\\\\", 2);
-          break;
-        case '\'':
-          ADDN("\\'", 2);
-          break;
+          page_name_number->number = i+1;
+          page_name_number->page_name = file_counter->filename;
         }
-      p++;
-    }
-}
-
-#define OTXI_ISO_ENTITY_TEXT_CASES(var) \
-        case '-': \
-          if (*(var+1) && !memcmp (var, "---", 3)) \
-            { \
-              text_append_n (result, "&mdash;", 7); \
-              var += 3; \
-            } \
-          else if (!memcmp (var, "--", 2)) \
-            { \
-              text_append_n (result, "&ndash;", 7); \
-              var += 2; \
-            } \
-          else \
-            { \
-              text_append_n (result, "-", 1); \
-              var++; \
-            } \
-          break; \
-        case '`': \
-          if (!memcmp (var, "``", 2)) \
-            { \
-              text_append_n (result, "&ldquo;", 7); \
-              var += 2; \
-            } \
-          else \
-            { \
-              text_append_n (result, "&lsquo;", 7); \
-              var++; \
-            } \
-          break; \
-        case '\'': \
-          if (!memcmp (var, "''", 2)) \
-            { \
-              text_append_n (result, "&rdquo;", 7); \
-              var += 2; \
-            } \
-          else \
-            { \
-              text_append_n (result, "&rsquo;", 7); \
-              var++; \
-            } \
-          break;
-
-#define OTXI_NO_ISO_ENTITY_TEXT_CASES(var) \
-        case '-': \
-          if (*(var+1) && !memcmp (var, "---", 3)) \
-            { \
-              text_append_n (result, "--", 2); \
-              var += 3; \
-            } \
-          else \
-            { \
-              text_append_n (result, "-", 1); \
-              if (!memcmp (var, "--", 2)) \
-                var += 2; \
-              else \
-                var++; \
-            } \
-          break; \
-        case '`': \
-          if (!memcmp (var, "``", 2)) \
-            { \
-              text_append_n (result, "&quot;", 6); \
-              var += 2; \
-            } \
-          else \
-            { \
-              text_append_n (result, var, 1); \
-              var++; \
-            } \
-          break; \
-        case '\'': \
-          if (!memcmp (var, "''", 2)) \
-            { \
-              text_append_n (result, "&quot;", 6); \
-              var += 2; \
-            } \
-          else \
-            { \
-              text_append_n (result, var, 1); \
-              var++; \
-            } \
-          break;
-
-#define OTXI_NO_BREAK_CASES(var) \
-        case ' ': \
-        case '\n': \
-          text_append_n (result, \
-               self->special_character[SC_non_breaking_space].string, \
-               self->special_character[SC_non_breaking_space].len); \
-          var += strspn (var, "\n "); \
-          break;
-
-#define OTXI_SPACE_PROTECTION_CASES(var) \
-        case ' ': \
-          text_append_n (result, \
-               self->special_character[SC_non_breaking_space].string, \
-               self->special_character[SC_non_breaking_space].len); \
-          var++; \
-          break; \
-        case '\n': \
-          text_append_n (result, self->line_break_element.string, \
-                         self->line_break_element.len); \
-          var++; \
-          break;
-
-/* text conversion loop, with the protection of XML special
-   characters and the possibility to add more delimiters and
-   more cases to handle those delimiters */
-#define OTXI_CONVERT_TEXT(delimiters,other_cases) \
-  { \
-  while (*p)  \
-    { \
-      int before_sep_nr = strcspn (p, "<>&\"\f" delimiters); \
-      if (before_sep_nr) \
-        { \
-          text_append_n (result, p, before_sep_nr); \
-          p += before_sep_nr; \
-        } \
-      if (!*p) \
-        break; \
-      switch (*p) \
-        { \
-          OTXI_PROTECT_XML_FORM_FEED_CASES(p) \
-          other_cases \
-        } \
-    } \
-  }
-
-/* conversion of text for all the possibilities regarding -- --- ''
-   conversion, with the possibility to add more for spaces protection */
-#define OTXI_ALL_CONVERT_TEXT(additional_delim,other_cases) \
-  const char *p = content_used; \
-      if (in_code (self) || in_math (self)) \
-        OTXI_CONVERT_TEXT(additional_delim,  \
-          other_cases) \
-      else if (self->use_unicode_text) \
-        OTXI_CONVERT_TEXT("-`'" additional_delim, \
-          OTXI_UNICODE_TEXT_CASES(p) \
-          other_cases) \
-      else if (self->conf->USE_NUMERIC_ENTITY > 0) \
-        OTXI_CONVERT_TEXT("-`'" additional_delim, \
-          OTXI_NUMERIC_ENTITY_TEXT_CASES(p) \
-          other_cases) \
-      else if (self->conf->USE_ISO > 0) \
-        OTXI_CONVERT_TEXT("-`'" additional_delim, \
-          OTXI_ISO_ENTITY_TEXT_CASES(p) \
-          other_cases) \
-      else \
-        OTXI_CONVERT_TEXT("-`'" additional_delim, \
-          OTXI_NO_ISO_ENTITY_TEXT_CASES(p) \
-          other_cases)
 
-void
-html_default_format_protect_text (const char *text, TEXT *result)
-{
-  const char *p = text;
+      qsort (self->page_name_number.list,
+             self->page_name_number.number,
+             sizeof (PAGE_NAME_NUMBER), compare_page_name_number);
+    }
 
-  OTXI_CONVERT_TEXT ( , )
+  return files_source_info;
 }
 
 void
@@ -3098,6 +3451,16 @@ html_converter_initialize (CONVERTER *self)
             &self->css_string_command_conversion_function[i], i,
              &self->css_string_commands_conversion[i]);
     }
+
+}
+
+/* called in the end of html_converter_prepare_output_sv */
+void
+html_converter_prepare_output (CONVERTER* self)
+{
+  qsort (self->css_element_class_styles.list,
+         self->css_element_class_styles.number,
+         sizeof (CSS_SELECTOR_STYLE), compare_selector_style);
 }
 
 void
@@ -4655,6 +5018,10 @@ html_convert_convert (CONVERTER *self, const ELEMENT 
*root,
 
   text_init (&result);
 
+  self->current_filename.filename = "";
+  self->current_filename.file_number = 1;
+  self->modified_state |= HMSF_current_filename;
+
   if (!output_units || !output_units->number)
     {
       char *footnotes_segment;
@@ -4694,6 +5061,9 @@ html_convert_convert (CONVERTER *self, const ELEMENT 
*root,
             }
         }
     }
+  self->current_filename.filename = 0;
+  self->modified_state |= HMSF_current_filename;
+
   return result.text;
 }
 
@@ -4709,7 +5079,7 @@ convert_output_output_unit_internal (CONVERTER *self,
   int empty_body = 0; /* set if body is empty and it is a special unit */
   char *output_unit_filename = output_unit->unit_filename;
 
-  self->current_filename = output_unit_filename;
+  self->current_filename.filename = output_unit_filename;
   self->modified_state |= HMSF_current_filename;
 
   text_reset (text);
@@ -4721,6 +5091,7 @@ convert_output_output_unit_internal (CONVERTER *self,
       char *special_unit_variety = output_unit->special_unit_variety;
 
       file_index = self->special_unit_file_indices[output_unit->index];
+      self->current_filename.file_number = file_index +1;
       unit_file = &self->output_unit_files.list[file_index];
 
       xasprintf (&debug_str, "UNIT SPECIAL %s", special_unit_variety);
@@ -4734,6 +5105,7 @@ convert_output_output_unit_internal (CONVERTER *self,
   else
     {
       file_index = self->output_unit_file_indices[output_unit->index];
+      self->current_filename.file_number = file_index +1;
       unit_file = &self->output_unit_files.list[file_index];
 
       convert_convert_output_unit_internal (self, text, output_unit,
@@ -4871,16 +5243,26 @@ html_prepare_title_titlepage (CONVERTER *self, int 
output_units_descriptor,
     = retrieve_output_units (output_units_descriptor);
 
   if (strlen (output_file))
-    self->current_filename = output_units->list[0]->unit_filename;
+    {
+      self->current_filename.filename = output_units->list[0]->unit_filename;
+      self->current_filename.file_number
+        = self->output_unit_file_indices[0]+1;
+    }
   else
-    self->current_filename = output_filename;
+    {
+      /* case of convert() call.  Need to setup the page here */
+      if (self->page_name_number.number <= 0)
+         setup_output_simple_page (self, output_filename);
+      self->current_filename.filename = output_filename;
+      self->current_filename.file_number = 1;
+    }
 
   self->modified_state |= HMSF_current_filename;
 
   title_titlepage
     = call_formatting_function_format_title_titlepage (self);
   self->title_titlepage = title_titlepage;
-  self->current_filename = 0;
+  memset (&self->current_filename, 0, sizeof (CURRENT_FILE_INFO));
   self->modified_state |= HMSF_current_filename;
 }
 
@@ -4911,7 +5293,8 @@ html_convert_output (CONVERTER *self, const ELEMENT *root,
       char *file_end;
       char *file_beginning;
 
-      self->current_filename = output_filename;
+      self->current_filename.filename = output_filename;
+      self->current_filename.file_number = 1;
       self->modified_state |= HMSF_current_filename;
 
       text_append (&text, "");
@@ -4976,7 +5359,7 @@ html_convert_output (CONVERTER *self, const ELEMENT *root,
           text_append (&result, file_end);
           free (file_end);
         }
-      self->current_filename = 0;
+      self->current_filename.filename = 0;
       self->modified_state |= HMSF_current_filename;
     }
   else
@@ -5022,7 +5405,7 @@ html_convert_output (CONVERTER *self, const ELEMENT *root,
               unit_nr++;
             }
         }
-      self->current_filename = 0;
+      memset (&self->current_filename, 0, sizeof (CURRENT_FILE_INFO));
       self->modified_state |= HMSF_current_filename;
     }
 
diff --git a/tp/Texinfo/XS/convert/convert_html.h 
b/tp/Texinfo/XS/convert/convert_html.h
index 2052f366d1..9194726a80 100644
--- a/tp/Texinfo/XS/convert/convert_html.h
+++ b/tp/Texinfo/XS/convert/convert_html.h
@@ -21,6 +21,8 @@ void html_converter_initialize (CONVERTER *self);
 void html_initialize_output_state (CONVERTER *self, char *context);
 void html_finalize_output_state (CONVERTER *self);
 
+void html_converter_prepare_output (CONVERTER* self);
+
 void html_new_document_context (CONVERTER *self,
         char *context_name, char *document_global_context,
         enum command_id block_command);
@@ -31,6 +33,11 @@ void html_register_opened_section_level (CONVERTER *self, 
int level,
 STRING_LIST *html_close_registered_sections_level (CONVERTER *self,
                                                    int level);
 
+char *html_attribute_class (CONVERTER *self, const char *element,
+                            const STRING_LIST *classes);
+STRING_LIST *html_get_css_elements_classes (CONVERTER *self,
+                                            const char *filename);
+
 void html_merge_index_entries (CONVERTER *self);
 
 void html_prepare_conversion_units (CONVERTER *self,
diff --git a/tp/Texinfo/XS/convert/get_html_perl_info.c 
b/tp/Texinfo/XS/convert/get_html_perl_info.c
index d980e95ca0..d85dec558b 100644
--- a/tp/Texinfo/XS/convert/get_html_perl_info.c
+++ b/tp/Texinfo/XS/convert/get_html_perl_info.c
@@ -370,7 +370,7 @@ html_converter_initialize_sv (SV *converter_sv,
       STRING_LIST *special_unit_varieties = &converter->special_unit_varieties;
       if (sorted_special_unit_varieties_sv)
         add_svav_to_string_list (*sorted_special_unit_varieties_sv,
-                                 special_unit_varieties, 0);
+                                 special_unit_varieties, svt_char);
 
       FETCH(special_unit_info);
 
@@ -742,8 +742,6 @@ html_converter_initialize_sv (SV *converter_sv,
         }
     }
 
-#undef FETCH
-
   html_converter_initialize (converter);
 
   converter->hv = converter_hv;
@@ -756,3 +754,49 @@ html_converter_initialize_sv (SV *converter_sv,
   return converter_descriptor;
 }
 
+void
+html_converter_prepare_output_sv (SV *converter_sv, CONVERTER *converter)
+{
+  HV *converter_hv;
+  SV **css_element_class_styles_sv;
+
+  dTHX;
+
+  converter_hv = (HV *)SvRV (converter_sv);
+
+  FETCH(css_element_class_styles)
+
+  if (css_element_class_styles_sv)
+    {
+      I32 hv_number;
+      I32 i;
+
+      HV *css_element_class_styles_hv
+        = (HV *)SvRV (*css_element_class_styles_sv);
+
+      hv_number = hv_iterinit (css_element_class_styles_hv);
+
+      converter->css_element_class_styles.list = (CSS_SELECTOR_STYLE *)
+        malloc (hv_number * sizeof (CSS_SELECTOR_STYLE));
+      converter->css_element_class_styles.number = hv_number;
+
+      for (i = 0; i < hv_number; i++)
+        {
+          HE *next = hv_iternext (css_element_class_styles_hv);
+          SV *selector_sv = hv_iterkeysv (next);
+          char *selector = (char *) SvPVutf8_nolen (selector_sv);
+          SV *style_sv = HeVAL(next);
+          char *style = (char *) SvPVutf8_nolen (style_sv);
+
+          CSS_SELECTOR_STYLE *selector_style
+            = &converter->css_element_class_styles.list[i];
+          selector_style->selector = strdup (selector);
+          selector_style->style = strdup (style);
+        }
+    }
+
+  html_converter_prepare_output (converter);
+}
+
+#undef FETCH
+
diff --git a/tp/Texinfo/XS/convert/get_html_perl_info.h 
b/tp/Texinfo/XS/convert/get_html_perl_info.h
index f59d81b80e..5340fb8cc7 100644
--- a/tp/Texinfo/XS/convert/get_html_perl_info.h
+++ b/tp/Texinfo/XS/convert/get_html_perl_info.h
@@ -16,4 +16,5 @@ int html_converter_initialize_sv (SV *converter_sv,
                                   SV *default_css_string_types_conversion,
                                   SV *default_output_units_conversion);
 
+void html_converter_prepare_output_sv (SV *converter_sv, CONVERTER *converter);
 #endif
diff --git a/tp/Texinfo/XS/main/converter_types.h 
b/tp/Texinfo/XS/main/converter_types.h
index e138fcb696..639af88641 100644
--- a/tp/Texinfo/XS/main/converter_types.h
+++ b/tp/Texinfo/XS/main/converter_types.h
@@ -261,6 +261,29 @@ typedef struct ARRAY_INDEX_LIST {
     size_t *list;
 } ARRAY_INDEX_LIST;
 
+typedef struct PAGE_NAME_NUMBER {
+    size_t number;
+    const char *page_name;
+} PAGE_NAME_NUMBER;
+
+typedef struct PAGE_NAME_NUMBER_LIST {
+    size_t number;
+    PAGE_NAME_NUMBER *list;
+} PAGE_NAME_NUMBER_LIST;
+
+typedef struct CSS_LIST {
+    const char *page_name;
+    size_t number;
+    size_t space;
+    const char **list;
+} CSS_LIST;
+
+typedef struct PAGES_CSS_LIST {
+    size_t number;
+    CSS_LIST *list; /* index 0 is for document_global_context_css
+                       others for the output files */
+} PAGES_CSS_LIST;
+
 typedef struct COMMAND_ID_INDEX {
     enum command_id cmd;
     size_t index;
@@ -290,6 +313,11 @@ typedef struct FILE_NAME_PATH_COUNTER_LIST {
     FILE_NAME_PATH_COUNTER *list;
 } FILE_NAME_PATH_COUNTER_LIST;
 
+typedef struct CURRENT_FILE_INFO {
+    size_t file_number;
+    char *filename;
+} CURRENT_FILE_INFO;
+
 typedef struct FILE_STREAM {
     char *file_path;
     FILE *stream;
@@ -367,6 +395,16 @@ typedef struct HTML_ADDED_TARGET_LIST {
     HTML_TARGET **list;
 } HTML_ADDED_TARGET_LIST;
 
+typedef struct CSS_SELECTOR_STYLE {
+    const char *selector;
+    const char *style;
+} CSS_SELECTOR_STYLE;
+
+typedef struct CSS_SELECTOR_STYLE_LIST {
+    size_t number;
+    CSS_SELECTOR_STYLE *list;
+} CSS_SELECTOR_STYLE_LIST;
+
 /* we have a circular reference with TYPE_CONVERSION_FUNCTION
    and CONVERTER and with COMMAND_CONVERSION_FUNCTION and CONVERTER */
 struct CONVERTER;
@@ -428,6 +466,9 @@ typedef struct CONVERTER {
   /* output unit files API */
     FILE_NAME_PATH_COUNTER_LIST output_unit_files;
 
+  /* to find index in output_unit_files based on name */
+    PAGE_NAME_NUMBER_LIST page_name_number;
+
   /* API to open, set encoding and register files */
     OUTPUT_FILES_INFORMATION output_files_information;
 
@@ -442,6 +483,7 @@ typedef struct CONVERTER {
     int upper_case[BUILTIN_CMD_NUMBER];
     STRING_WITH_LEN special_character[SC_non_breaking_space+1];
     STRING_WITH_LEN line_break_element;
+    CSS_SELECTOR_STYLE_LIST css_element_class_styles;
     FORMATTING_REFERENCE
        formatting_references[FR_format_translate_message+1];
     FORMATTING_REFERENCE
@@ -476,6 +518,7 @@ typedef struct CONVERTER {
     size_t *output_unit_file_indices;   /* array of indices in 
output_unit_files
               each position corresponding to an output unit. */
     size_t *special_unit_file_indices;  /* same for special output units */
+    PAGES_CSS_LIST page_css;
 
     /* state only in C converter */
     unsigned long modified_state; /* specifies which perl state to rebuild */
@@ -508,7 +551,7 @@ typedef struct CONVERTER {
     HTML_DOCUMENT_CONTEXT_STACK html_document_context;
     STRING_STACK multiple_pass;
     STRING_STACK pending_closes;
-    char *current_filename;
+    CURRENT_FILE_INFO current_filename;
     /* state common with perl converter, not transmitted to perl */
     int use_unicode_text;
 } CONVERTER;
diff --git a/tp/Texinfo/XS/main/get_perl_info.c 
b/tp/Texinfo/XS/main/get_perl_info.c
index b57ffe708e..e1d799fa53 100644
--- a/tp/Texinfo/XS/main/get_perl_info.c
+++ b/tp/Texinfo/XS/main/get_perl_info.c
@@ -164,7 +164,7 @@ get_sv_output_units (SV *output_units_in, char *warn_string)
 }
 
 void
-add_svav_to_string_list (SV *sv, STRING_LIST *string_list, int dir_strings)
+add_svav_to_string_list (SV *sv, STRING_LIST *string_list, enum sv_string_type 
type)
 {
   int i;
   SSize_t strings_nr;
@@ -178,8 +178,12 @@ add_svav_to_string_list (SV *sv, STRING_LIST *string_list, 
int dir_strings)
       SV** string_sv = av_fetch (av, i, 0);
       if (string_sv)
         {
-          char *string = SvPVbyte_nolen (*string_sv);
-          if (dir_strings)
+          char *string;
+          if (type == svt_char)
+            string = SvPVutf8_nolen (*string_sv);
+          else
+            string = SvPVbyte_nolen (*string_sv);
+          if (type == svt_dir)
             add_include_directory (string, string_list);
           else
             add_string (string, string_list);
@@ -699,7 +703,7 @@ copy_sv_options_for_convert_text (SV *sv_in)
 
   if (include_directories_sv)
     add_svav_to_string_list (*include_directories_sv,
-                             &text_options->include_directories, 1);
+                             &text_options->include_directories, svt_dir);
 
   get_expanded_formats (hv_in, &text_options->expanded_formats);
 
diff --git a/tp/Texinfo/XS/main/get_perl_info.h 
b/tp/Texinfo/XS/main/get_perl_info.h
index 28e2e3e4e0..ece0e189da 100644
--- a/tp/Texinfo/XS/main/get_perl_info.h
+++ b/tp/Texinfo/XS/main/get_perl_info.h
@@ -11,6 +11,12 @@
 #include "converter_types.h"
 #include "convert_to_text.h"
 
+enum sv_string_type {
+  svt_byte,
+  svt_dir,
+  svt_char,
+};
+
 DOCUMENT *get_sv_tree_document (SV *tree_in, char *warn_string);
 DOCUMENT *get_sv_document_document (SV *document_in, char *warn_string);
 
@@ -18,7 +24,7 @@ OUTPUT_UNIT_LIST *get_sv_output_units (SV *output_units_in, 
char *warn_string);
 int get_sv_output_units_descriptor (SV *output_units_in, char *warn_string);
 
 void add_svav_to_string_list (SV *sv, STRING_LIST *string_list,
-                              int dir_strings);
+                              enum sv_string_type type);
 
 OPTIONS *copy_sv_options (SV *sv_in);
 void set_conf (CONVERTER *converter, const char *conf, SV *value);
diff --git a/tp/maintain/regenerate_C_options_info.pl 
b/tp/maintain/regenerate_C_options_info.pl
index dc189a4ba7..f82810023e 100755
--- a/tp/maintain/regenerate_C_options_info.pl
+++ b/tp/maintain/regenerate_C_options_info.pl
@@ -253,6 +253,8 @@ close(CODE);
 open (GET, ">$get_file") or die "Open $get_file: $!\n";
 print GET "/* Automatically generated from $0 */\n\n";
 
+print GET '#include "get_perl_info.h"'."\n\n";
+
 print GET 'void
 get_sv_option (OPTIONS *options, const char *key, SV *value)
 {
@@ -290,8 +292,8 @@ foreach my $category (sort(keys(%option_categories))) {
     } elsif ($type eq 'int') {
       print GET "    options->$option = SvIV (value);\n";
     } elsif ($type eq 'STRING_LIST') {
-      my $dir_string_arg = 0;
-      $dir_string_arg = 1
+      my $dir_string_arg = 'svt_byte';
+      $dir_string_arg = 'svt_dir'
         if ($option eq 'INCLUDE_DIRECTORIES');
       print GET "    add_svav_to_string_list (value, &options->$option, 
$dir_string_arg);\n";
     } else {



reply via email to

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