From: Bruno Haible Date: Tue, 7 Nov 2006 14:47:35 +0000 (+0000) Subject: New module 'html-ostream': Output stream that produces HTML output. X-Git-Tag: v0.17~666 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7d70e00b072c32962e6d7c809b2226b0ab5b1c5;p=thirdparty%2Fgettext.git New module 'html-ostream': Output stream that produces HTML output. --- diff --git a/gnulib-local/lib/html-ostream.oo.c b/gnulib-local/lib/html-ostream.oo.c new file mode 100644 index 000000000..123f04076 --- /dev/null +++ b/gnulib-local/lib/html-ostream.oo.c @@ -0,0 +1,274 @@ +/* Output stream that produces HTML output. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 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 + +/* Specification. */ +#include "html-ostream.h" + +#include +#include +#include + +#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 /* */ 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, "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, ""); + 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, """); + break; + case '&': + ostream_write_str (stream->destination, "&"); + break; + case '<': + ostream_write_str (stream->destination, "<"); + break; + case '>': + /* Needed to avoid "]]>" in the output. */ + ostream_write_str (stream->destination, ">"); + break; + case ' ': + /* Needed because HTML viewers merge adjacent spaces and + drop spaces adjacent to
and similar. */ + ostream_write_str (stream->destination, " "); + 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, "
"); + 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 index 000000000..cf469ca1a --- /dev/null +++ b/gnulib-local/lib/html-ostream.oo.h @@ -0,0 +1,59 @@ +/* Output stream that produces HTML output. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 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 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 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 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 index 000000000..29a3acd7e --- /dev/null +++ b/gnulib-local/modules/html-ostream @@ -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 +