]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
libtextstyle: html-ostream: Add hyperlink support.
authorBruno Haible <bruno@clisp.org>
Wed, 14 Aug 2019 18:52:25 +0000 (20:52 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 14 Aug 2019 18:52:25 +0000 (20:52 +0200)
* libtextstyle/gnulib-local/lib/html-ostream.oo.h (struct html_ostream): Add
methods get_hyperlink_ref, set_hyperlink_ref.
* libtextstyle/gnulib-local/lib/html-ostream.oo.c (struct html_ostream): Add
field hyperlink_ref;
(write_attribute_value): New function.
(html_ostream::free): Emit an anchor end if needed.
(html_ostream::get_hyperlink_ref, html_ostream::set_hyperlink_ref): New
functions.
(html_ostream_create): Initialize the hyperlink_ref field.
* libtextstyle/lib/textstyle.h (html_ostream_get_hyperlink_ref,
html_ostream_set_hyperlink_ref): New declarations.

libtextstyle/gnulib-local/lib/html-ostream.oo.c
libtextstyle/gnulib-local/lib/html-ostream.oo.h
libtextstyle/lib/textstyle.h

index 6c55847a85b958d36600328d4bbbb0ec793a839a..07e436a13d9431036df9537fb424836308138444 100644 (file)
@@ -35,6 +35,8 @@ struct html_ostream : struct ostream
 fields:
   /* The destination stream.  */
   ostream_t destination;
+  /* The current hyperlink ref.  */
+  char *hyperlink_ref;
   /* The stack of active CSS classes.  */
   gl_list_t /* <char *> */ class_stack;
   /* Current and last size of the active portion of this stack.  Always
@@ -47,6 +49,49 @@ fields:
   size_t buflen;
 };
 
+/* Emit an HTML attribute value.
+   quote is either '"' or '\''.  */
+static void
+write_attribute_value (html_ostream_t stream, const char *value, char quote)
+{
+  /* Need to escape the '<', '>', '&', quote characters.  */
+  ostream_t destination = stream->destination;
+  const char *p = value;
+
+  for (;;)
+    {
+      const char *q = p;
+
+      while (*q != '\0' && *q != '<' && *q != '>' && *q != '&' && *q != quote)
+        q++;
+      if (p < q)
+        ostream_write_mem (destination, p, q - p);
+      if (*q == '\0')
+        break;
+      switch (*q)
+        {
+        case '<':
+          ostream_write_str (destination, "&lt;");
+          break;
+        case '>':
+          ostream_write_str (destination, "&gt;");
+          break;
+        case '&':
+          ostream_write_str (destination, "&amp;");
+          break;
+        case '"':
+          ostream_write_str (destination, "&quot;");
+          break;
+        case '\'':
+          ostream_write_str (destination, "&apos;");
+          break;
+        default:
+          abort ();
+        }
+      p = q + 1;
+    }
+}
+
 /* Implementation of ostream_t methods.  */
 
 static void
@@ -261,6 +306,12 @@ html_ostream::free (html_ostream_t stream)
 {
   stream->curr_class_stack_size = 0;
   emit_pending_spans (stream, true);
+  if (stream->hyperlink_ref != NULL)
+    {
+      /* Close the current <a> element.  */
+      ostream_write_str (stream->destination, "</a>");
+      free (stream->hyperlink_ref);
+    }
   verify_invariants (stream);
   gl_list_free (stream->class_stack);
   free (stream);
@@ -312,6 +363,50 @@ html_ostream::end_span (html_ostream_t stream, const char *classname)
   abort ();
 }
 
+static const char *
+html_ostream::get_hyperlink_ref (html_ostream_t stream)
+{
+  return stream->hyperlink_ref;
+}
+
+static void
+html_ostream::set_hyperlink_ref (html_ostream_t stream, const char *ref)
+{
+  char *ref_copy = (ref != NULL ? xstrdup (ref) : NULL);
+
+  verify_invariants (stream);
+  if (stream->hyperlink_ref != NULL)
+    {
+      /* Close the open <span> tags, and prepare for reopening the same <span>
+         tags.  */
+      size_t prev_class_stack_size = stream->curr_class_stack_size;
+      stream->curr_class_stack_size = 0;
+      emit_pending_spans (stream, false);
+      stream->curr_class_stack_size = prev_class_stack_size;
+      /* Close the current <a> element.  */
+      ostream_write_str (stream->destination, "</a>");
+      shrink_class_stack (stream);
+
+      free (stream->hyperlink_ref);
+    }
+  stream->hyperlink_ref = ref_copy;
+  if (stream->hyperlink_ref != NULL)
+    {
+      /* Close the open <span> tags, and prepare for reopening the same <span>
+         tags.  */
+      size_t prev_class_stack_size = stream->curr_class_stack_size;
+      stream->curr_class_stack_size = 0;
+      emit_pending_spans (stream, false);
+      stream->curr_class_stack_size = prev_class_stack_size;
+      /* Open an <a> element.  */
+      ostream_write_str (stream->destination, "<a href=\"");
+      write_attribute_value (stream, stream->hyperlink_ref, '"');
+      ostream_write_str (stream->destination, "\">");
+      shrink_class_stack (stream);
+    }
+  verify_invariants (stream);
+}
+
 static void
 html_ostream::flush_to_current_style (html_ostream_t stream)
 {
@@ -332,6 +427,7 @@ html_ostream_create (ostream_t destination)
 
   stream->base.vtable = &html_ostream_vtable;
   stream->destination = destination;
+  stream->hyperlink_ref = NULL;
   stream->class_stack =
     gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, NULL, true);
   stream->curr_class_stack_size = 0;
index dd25aabacc9d699ef33e51d4f45409a467a3032c..05649c1283458b20aab634ae045f0b27169f5dbc 100644 (file)
@@ -34,6 +34,10 @@ methods:
      The begin_span / end_span calls must match properly.  */
   void end_span (html_ostream_t stream, const char *classname);
 
+  /* Get/set the hyperlink attribute.  */
+  const char * get_hyperlink_ref (html_ostream_t stream);
+  void set_hyperlink_ref (html_ostream_t stream, const char *ref);
+
   /* Like html_ostream_flush (first_arg, FLUSH_THIS_STREAM), except that it
      leaves the destination with the current text style enabled, instead
      of with the default text style.
index ecb669179297fdaa7e4d5ca4161b6053d92ee79b..00471d481fb9c949afa1fd7c63f92c2879c48dc3 100644 (file)
@@ -358,6 +358,8 @@ extern void html_ostream_flush (html_ostream_t first_arg, ostream_flush_scope_t
 extern void html_ostream_free (html_ostream_t first_arg);
 extern void html_ostream_begin_span (html_ostream_t first_arg, const char *classname);
 extern void html_ostream_end_span (html_ostream_t first_arg, const char *classname);
+extern const char *html_ostream_get_hyperlink_ref (html_ostream_t first_arg);
+extern void html_ostream_set_hyperlink_ref (html_ostream_t first_arg, const char *ref);
 /* Like html_ostream_flush (first_arg, FLUSH_THIS_STREAM), except that it
    leaves the destination with the current text style enabled, instead
    of with the default text style.