]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
New module 'html-ostream': Output stream that produces HTML output.
authorBruno Haible <bruno@clisp.org>
Tue, 7 Nov 2006 14:47:35 +0000 (14:47 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:14:20 +0000 (12:14 +0200)
gnulib-local/lib/html-ostream.oo.c [new file with mode: 0644]
gnulib-local/lib/html-ostream.oo.h [new file with mode: 0644]
gnulib-local/modules/html-ostream [new file with mode: 0644]

diff --git a/gnulib-local/lib/html-ostream.oo.c b/gnulib-local/lib/html-ostream.oo.c
new file mode 100644 (file)
index 0000000..123f040
--- /dev/null
@@ -0,0 +1,274 @@
+/* Output stream that produces HTML output.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2006.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "html-ostream.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gl_list.h"
+#include "gl_array_list.h"
+#include "utf8-ucs4.h"
+#include "xalloc.h"
+
+struct html_ostream : struct ostream
+{
+fields:
+  /* The destination stream.  */
+  ostream_t destination;
+  /* The stack of active CSS classes.  */
+  gl_list_t /* <char *> */ class_stack;
+  /* Current and last size of the active portion of this stack.  Always
+     size(class_stack) == max(curr_class_stack_size,last_class_stack_size).  */
+  size_t curr_class_stack_size;
+  size_t last_class_stack_size;
+  /* Last few bytes that could not yet be converted.  */
+  #define BUFSIZE 6
+  char buf[BUFSIZE];
+  size_t buflen;
+};
+
+/* Implementation of ostream_t methods.  */
+
+static void
+emit_pending_spans (html_ostream_t stream, bool shrink_stack)
+{
+  if (stream->curr_class_stack_size > stream->last_class_stack_size)
+    {
+      size_t i;
+
+      for (i = stream->last_class_stack_size; i < stream->curr_class_stack_size; i++)
+       {
+         char *classname = (char *) gl_list_get_at (stream->class_stack, i);
+
+         ostream_write_str (stream->destination, "<span class=\"");
+         ostream_write_str (stream->destination, classname);
+         ostream_write_str (stream->destination, ">");
+       }
+      stream->last_class_stack_size = stream->curr_class_stack_size;
+    }
+  else if (stream->curr_class_stack_size < stream->last_class_stack_size)
+    {
+      size_t i = stream->last_class_stack_size;
+
+      while (i > stream->curr_class_stack_size)
+       {
+         char *classname;
+
+         --i;
+         classname = (char *) gl_list_get_at (stream->class_stack, i);
+         ostream_write_str (stream->destination, "</span>");
+         if (shrink_stack)
+           {
+             gl_list_remove_at (stream->class_stack, i);
+             free (classname);
+           }
+       }
+      stream->last_class_stack_size = stream->curr_class_stack_size;
+    }
+}
+
+static void
+html_ostream::write_mem (html_ostream_t stream, const void *data, size_t len)
+{
+  if (len > 0)
+    {
+      #define BUFFERSIZE 2048
+      char inbuffer[BUFFERSIZE];
+      size_t inbufcount;
+
+      emit_pending_spans (stream, true);
+
+      inbufcount = stream->buflen;
+      if (inbufcount > 0)
+       memcpy (inbuffer, stream->buf, inbufcount);
+      for (;;)
+       {
+         /* At this point, inbuffer[0..inbufcount-1] is filled.  */
+         {
+           /* Combine the previous rest with a chunk of new input.  */
+           size_t n =
+             (len <= BUFFERSIZE - inbufcount ? len : BUFFERSIZE - inbufcount);
+
+           if (n > 0)
+             {
+               memcpy (inbuffer + inbufcount, data, n);
+               data = (char *) data + n;
+               inbufcount += n;
+               len -= n;
+             }
+         }
+         {
+           /* Handle complete UTF-8 characters.  */
+           const char *inptr = inbuffer;
+           size_t insize = inbufcount;
+
+           while (insize > 0)
+             {
+               unsigned char c0;
+               unsigned int uc;
+               int nbytes;
+
+               c0 = ((const unsigned char *) inptr)[0];
+               if (insize < (c0 < 0xc0 ? 1 : c0 < 0xe0 ? 2 : c0 < 0xf0 ? 3 :
+                             c0 < 0xf8 ? 4 : c0 < 0xfc ? 5 : 6))
+                 break;
+
+               nbytes = u8_mbtouc (&uc, (const unsigned char *) inptr, insize);
+
+               switch (uc)
+                 {
+                 case '"':
+                   ostream_write_str (stream->destination, "&quot;");
+                   break;
+                 case '&':
+                   ostream_write_str (stream->destination, "&amp;");
+                   break;
+                 case '<':
+                   ostream_write_str (stream->destination, "&lt;");
+                   break;
+                 case '>':
+                   /* Needed to avoid "]]>" in the output.  */
+                   ostream_write_str (stream->destination, "&gt;");
+                   break;
+                 case ' ':
+                   /* Needed because HTML viewers merge adjacent spaces and
+                      drop spaces adjacent to <br> and similar.  */
+                   ostream_write_str (stream->destination, "&nbsp;");
+                   break;
+                 case '\n':
+                   {
+                     size_t prev_class_stack_size = stream->curr_class_stack_size;
+                     stream->curr_class_stack_size = 0;
+                     emit_pending_spans (stream, false);
+                     ostream_write_str (stream->destination, "<br/>");
+                     stream->curr_class_stack_size = prev_class_stack_size;
+                   }
+                   break;
+                 default:
+                   if (uc >= 0x20 && uc < 0x7F)
+                     {
+                       /* Output ASCII characters as such.  */
+                       char bytes[1];
+                       bytes[0] = uc;
+                       ostream_write_mem (stream->destination, bytes, 1);
+                     }
+                   else
+                     {
+                       /* Output non-ASCII characters in #&nnn; notation.  */
+                       char bytes[32];
+                       sprintf (bytes, "&#%d;", uc);
+                       ostream_write_str (stream->destination, bytes);
+                     }
+                   break;
+                 }
+
+               inptr += nbytes;
+               insize -= nbytes;
+             }
+           /* Put back the unconverted part.  */
+           if (insize > BUFSIZE)
+             abort ();
+           if (len == 0)
+             {
+               if (insize > 0)
+                 memcpy (stream->buf, inptr, insize);
+               stream->buflen = insize;
+               break;
+             }
+           if (insize > 0)
+             memmove (inbuffer, inptr, insize);
+           inbufcount = insize;
+         }
+       }
+      #undef BUFFERSIZE
+    }
+}
+
+static void
+html_ostream::flush (html_ostream_t stream)
+{
+  /* There's nothing to do here, since stream->buf[] contains only a few
+     bytes that don't correspond to a character, and it's not worth closing
+     the open spans.  */
+}
+
+static void
+html_ostream::free (html_ostream_t stream)
+{
+  stream->curr_class_stack_size = 0;
+  emit_pending_spans (stream, true);
+  gl_list_free (stream->class_stack);
+  free (stream);
+}
+
+/* Implementation of html_ostream_t methods.  */
+
+void
+html_ostream::begin_span (html_ostream_t stream, const char *classname)
+{
+  if (stream->last_class_stack_size > stream->curr_class_stack_size
+      && strcmp ((char *) gl_list_get_at (stream->class_stack,
+                                         stream->curr_class_stack_size),
+                classname) != 0)
+    emit_pending_spans (stream, true);
+  /* Now either
+       last_class_stack_size <= curr_class_stack_size
+       - in this case we have to append the given CLASSNAME -
+     or
+       last_class_stack_size > curr_class_stack_size
+       && class_stack[curr_class_stack_size] == CLASSNAME
+       - in this case we only need to increment curr_class_stack_size.  */
+  if (stream->last_class_stack_size <= stream->curr_class_stack_size)
+    gl_list_add_at (stream->class_stack, stream->curr_class_stack_size,
+                   xstrdup (classname));
+  stream->curr_class_stack_size++;
+}
+
+void
+html_ostream::end_span (html_ostream_t stream, const char *classname)
+{
+  if (!(stream->curr_class_stack_size > 0
+       && strcmp ((char *) gl_list_get_at (stream->class_stack,
+                                           stream->curr_class_stack_size - 1),
+                  classname) == 0))
+    /* Improperly nested begin_span/end_span calls.  */
+    abort ();
+  stream->curr_class_stack_size--;
+}
+
+/* Constructor.  */
+
+html_ostream_t
+html_ostream_create (ostream_t destination)
+{
+  html_ostream_t stream = XMALLOC (struct html_ostream_representation);
+
+  stream->base.vtable = &html_ostream_vtable;
+  stream->destination = destination;
+  stream->class_stack = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, true);
+  stream->curr_class_stack_size = 0;
+  stream->last_class_stack_size = 0;
+  stream->buflen = 0;
+
+  return stream;
+}
diff --git a/gnulib-local/lib/html-ostream.oo.h b/gnulib-local/lib/html-ostream.oo.h
new file mode 100644 (file)
index 0000000..cf469ca
--- /dev/null
@@ -0,0 +1,59 @@
+/* Output stream that produces HTML output.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2006.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _HTML_OSTREAM_H
+#define _HTML_OSTREAM_H
+
+#include "ostream.h"
+
+
+struct html_ostream : struct ostream
+{
+methods:
+
+  /* Start a <span class="CLASSNAME"> element.  The CLASSNAME is the name
+     of a CSS class.  It can be chosen arbitrarily and customized through
+     an inline or external CSS.  */
+  void begin_span (html_ostream_t stream, const char *classname);
+
+  /* End a <span class="CLASSNAME"> element.
+     The begin_span / end_span calls must match properly.  */
+  void end_span (html_ostream_t stream, const char *classname);
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Create an output stream that takes input in the UTF-8 encoding and
+   writes it in HTML form on DESTINATION.
+   This stream produces a sequence of lines.  The caller is responsible
+   for opening the <body><html> elements before and for closing them after
+   the use of this stream.
+   Note that the resulting stream must be closed before DESTINATION can be
+   closed.  */
+extern html_ostream_t html_ostream_create (ostream_t destination);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HTML_OSTREAM_H */
diff --git a/gnulib-local/modules/html-ostream b/gnulib-local/modules/html-ostream
new file mode 100644 (file)
index 0000000..29a3acd
--- /dev/null
@@ -0,0 +1,32 @@
+Description:
+Output stream that produces HTML output.
+
+Files:
+lib/html-ostream.oo.h
+lib/html-ostream.oo.c
+
+Depends-on:
+ostream
+array-list
+list
+utf8-ucs4
+xalloc
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += html-ostream.c
+html-ostream.h html-ostream.c : $(top_srcdir)/build-aux/moopp html-ostream.oo.h html-ostream.oo.c ostream.oo.h
+       $(top_srcdir)/build-aux/moopp $(srcdir)/html-ostream.oo.c $(srcdir)/html-ostream.oo.h $(srcdir)/ostream.oo.h
+BUILT_SOURCES += html-ostream.h html-ostream.c html_ostream.priv.h html_ostream.vt.h
+CLEANFILES += html-ostream.h html-ostream.c html_ostream.priv.h html_ostream.vt.h
+
+Include:
+"html-ostream.h"
+
+License:
+GPL
+
+Maintainer:
+Bruno Haible
+