{
const struct text_item *text_item = to_text_item (output_item);
enum text_item_type type = text_item_get_type (text_item);
- const char *text = text_item_get_text (text_item);
switch (type)
{
break;
default:
- ascii_output_text (a, text);
+ ascii_output_table_item (a, text_item_to_table_item (text_item_ref (text_item)));
break;
}
}
}
}
+static char *
+add_footnote_markers (const char *text, const struct cell_contents *contents)
+{
+ struct string s = DS_EMPTY_INITIALIZER;
+ ds_put_cstr (&s, text);
+ for (size_t i = 0; i < contents->n_footnotes; i++)
+ ds_put_format (&s, "[%s]", contents->footnotes[i]->marker);
+ return ds_steal_cstr (&s);
+}
+
static int
ascii_layout_cell_text (struct ascii_driver *a,
const struct cell_contents *contents,
int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2],
int *widthp)
{
- size_t length;
- const char *text;
char *breaks;
int bb_width;
size_t pos;
- int y;
- y = bb[V][0];
- length = strlen (contents->text);
- if (contents->n_footnotes)
- {
- struct string s;
- int i;
+ int y = bb[V][0];
- ds_init_empty (&s);
- ds_extend (&s, length + contents->n_footnotes * 4);
- ds_put_cstr (&s, contents->text);
- for (i = 0; i < contents->n_footnotes; i++)
- ds_put_format (&s, "[%s]", contents->footnotes[i]->marker);
+ /* Get the basic textual contents. */
+ const char *plain_text = (contents->options & TAB_MARKUP
+ ? output_get_text_from_markup (contents->text)
+ : contents->text);
- length = ds_length (&s);
- text = ds_steal_cstr (&s);
+ /* Append footnote markers if any. */
+ const char *text;
+ if (contents->n_footnotes)
+ {
+ text = add_footnote_markers (plain_text, contents);
+ if (plain_text != contents->text)
+ free (CONST_CAST (char *, plain_text));
}
else
+ text = plain_text;
+
+ /* Calculate length; if it's zero, then there's nothing to do. */
+ size_t length = strlen (text);
+ if (!length)
{
- if (length == 0)
- return y;
- text = contents->text;
+ if (text != contents->text)
+ free (CONST_CAST (char *, text));
+ return y;
}
breaks = xmalloc (length + 1);
pango_attr_list_insert (list, attr);
}
+static void
+markup_escape (const char *in, struct string *out)
+{
+ for (int c = *in++; c; c = *in++)
+ switch (c)
+ {
+ case '&':
+ ds_put_cstr (out, "&");
+ break;
+ case '<':
+ ds_put_cstr (out, "<");
+ break;
+ case '>':
+ ds_put_cstr (out, ">");
+ break;
+ default:
+ ds_put_byte (out, c);
+ break;
+ }
+}
+
static int
xr_layout_cell_text (struct xr_driver *xr,
const struct cell_contents *contents,
}
size_t initial_length = ds_length (&tmp);
- cell_contents_format_footnote_markers (contents, &tmp);
- pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
+ for (size_t i = 0; i < contents->n_footnotes; i++)
+ {
+ if (i)
+ ds_put_byte (&tmp, ',');
+
+ const char *marker = contents->footnotes[i]->marker;
+ if (options & TAB_MARKUP)
+ markup_escape (marker, &tmp);
+ else
+ ds_put_cstr (&tmp, marker);
+ }
+
+ if (options & TAB_MARKUP)
+ pango_layout_set_markup (font->layout,
+ ds_cstr (&tmp), ds_length (&tmp));
+ else
+ pango_layout_set_text (font->layout, ds_cstr (&tmp), ds_length (&tmp));
PangoAttrList *attrs = pango_attr_list_new ();
if (style->underline)
else
{
const char *content = ds_is_empty (&tmp) ? text : ds_cstr (&tmp);
- pango_layout_set_text (font->layout, content, -1);
+ if (options & TAB_MARKUP)
+ pango_layout_set_markup (font->layout, content, -1);
+ else
+ pango_layout_set_text (font->layout, content, -1);
if (style->underline)
{
struct xr_table_state
{
struct xr_render_fsm fsm;
- struct table_item *table_item;
struct render_pager *p;
};
{
struct xr_table_state *ts = UP_CAST (fsm, struct xr_table_state, fsm);
- table_item_unref (ts->table_item);
render_pager_destroy (ts->p);
free (ts);
}
static struct xr_render_fsm *
-xr_render_table (struct xr_driver *xr, const struct table_item *table_item)
+xr_render_table (struct xr_driver *xr, struct table_item *table_item)
{
struct xr_table_state *ts;
ts = xmalloc (sizeof *ts);
ts->fsm.render = xr_table_render;
ts->fsm.destroy = xr_table_destroy;
- ts->table_item = table_item_ref (table_item);
if (xr->y > 0)
xr->y += xr->char_height;
ts->p = render_pager_create (xr->params, table_item);
+ table_item_unref (table_item);
return &ts->fsm;
}
return &eject_renderer;
}
\f
-static struct xr_render_fsm *
-xr_create_text_renderer (struct xr_driver *xr, const struct text_item *item)
-{
- struct tab_table *tab = tab_create (1, 1);
-
- struct cell_style *style = pool_alloc (tab->container, sizeof *style);
- *style = (struct cell_style) CELL_STYLE_INITIALIZER;
- if (item->font)
- style->font = pool_strdup (tab->container, item->font);
- style->font_size = item->font_size;
- style->bold = item->bold;
- style->italic = item->italic;
- style->underline = item->underline;
- tab->styles[0] = style;
-
- tab_text (tab, 0, 0, TAB_LEFT, text_item_get_text (item));
- struct table_item *table_item = table_item_create (&tab->table, NULL, NULL);
- struct xr_render_fsm *fsm = xr_render_table (xr, table_item);
- table_item_unref (table_item);
-
- return fsm;
-}
-
static struct xr_render_fsm *
xr_render_text (struct xr_driver *xr, const struct text_item *text_item)
{
break;
default:
- return xr_create_text_renderer (xr, text_item);
+ return xr_render_table (
+ xr, text_item_to_table_item (text_item_ref (text_item)));
}
return NULL;
char *s = msg_to_string (message_item_get_msg (message_item));
struct text_item *item = text_item_create (TEXT_ITEM_PARAGRAPH, s);
free (s);
- struct xr_render_fsm *fsm = xr_create_text_renderer (xr, item);
- text_item_unref (item);
-
- return fsm;
+ return xr_render_table (xr, text_item_to_table_item (item));
}
static struct xr_render_fsm *
const struct output_item *output_item)
{
if (is_table_item (output_item))
- return xr_render_table (xr, to_table_item (output_item));
+ return xr_render_table (xr, table_item_ref (to_table_item (output_item)));
else if (is_chart_item (output_item))
return xr_render_chart (to_chart_item (output_item));
else if (is_text_item (output_item))
if (i > 0)
ds_put_cstr (&s, "\n\n");
- ds_put_cstr (&s, c->text);
+ if (c->options & TAB_MARKUP)
+ {
+ char *t = output_get_text_from_markup (c->text);
+ ds_put_cstr (&s, t);
+ free (t);
+ }
+ else
+ ds_put_cstr (&s, c->text);
csv_format_footnotes (c->footnotes, c->n_footnotes, &s);
}
csv_output_field (csv, ds_cstr (&s));
return;
csv_put_separator (csv);
- csv_output_field (csv, text);
+ if (text_item->markup)
+ {
+ char *plain_text = output_get_text_from_markup (text);
+ csv_output_field (csv, plain_text);
+ free (plain_text);
+ }
+ else
+ csv_output_field (csv, text);
putc ('\n', csv->file);
}
else if (is_message_item (output_item))
struct string_map *options);
};
+char *output_get_text_from_markup (const char *markup);
#endif /* output/driver-provider.h */
#include <ctype.h>
#include <errno.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
char *value = xmemdup0 (equals + 1, strlen (equals + 1));
string_map_insert_nocopy (options, key, value);
}
+\f
+/* Extracts the actual text content from the given Pango MARKUP and returns it
+ as as a malloc()'d string. */
+char *
+output_get_text_from_markup (const char *markup)
+{
+ xmlDoc *doc = xmlReadMemory (markup, strlen (markup), "noname.xml", "UTF-8",
+ (XML_PARSE_NOERROR | XML_PARSE_NOWARNING
+ | XML_PARSE_NONET | XML_PARSE_NOCDATA));
+ if (!doc)
+ return xstrdup (markup);
+
+ char *content = CHAR_CAST (char *,
+ xmlNodeGetContent (xmlDocGetRootElement (doc)));
+ if (!content)
+ content = xstrdup (markup);
+
+ xmlFreeDoc (doc);
+
+ return content;
+}
else
xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Contents"));
- write_xml_with_line_breaks (odt, contents->text);
+ if (contents->options & TAB_MARKUP)
+ {
+ /* XXX */
+ char *s = output_get_text_from_markup (
+ contents->text);
+ write_xml_with_line_breaks (odt, s);
+ free (s);
+ }
+ else
+ write_xml_with_line_breaks (odt, contents->text);
for (j = 0; j < contents->n_footnotes; j++)
write_footnote (odt, contents->footnotes[j]);
/* These flags may be combined with any alignment. */
TAB_EMPH = 1 << 4, /* Emphasize cell contents. */
TAB_FIX = 1 << 5, /* Use fixed font. */
+ TAB_MARKUP = 1 << 6, /* Text contains Pango markup. */
/* Bits with values (1 << TAB_FIRST_AVAILABLE) and higher are
not used, so they are available for subclasses to use as
they wish. */
- TAB_FIRST_AVAILABLE = 6
+ TAB_FIRST_AVAILABLE = 7
};
/* Styles for the rules around table cells. */
#include <stdlib.h>
#include "libpspp/cast.h"
+#include "libpspp/pool.h"
#include "output/driver.h"
#include "output/output-item-provider.h"
+#include "output/tab.h"
+#include "output/table-item.h"
+#include "output/table-provider.h"
#include "gl/xalloc.h"
#include "gl/xvasprintf.h"
{
output_submit (&item->output_item);
}
-\f
+
+struct table_item *
+text_item_to_table_item (struct text_item *text_item)
+{
+ struct tab_table *tab = tab_create (1, 1);
+
+ struct cell_style *style = pool_alloc (tab->container, sizeof *style);
+ *style = (struct cell_style) CELL_STYLE_INITIALIZER;
+ if (text_item->font)
+ style->font = pool_strdup (tab->container, text_item->font);
+ style->font_size = text_item->font_size;
+ style->bold = text_item->bold;
+ style->italic = text_item->italic;
+ style->underline = text_item->underline;
+ tab->styles[0] = style;
+
+ int opts = TAB_LEFT;
+ if (text_item->markup)
+ opts |= TAB_MARKUP;
+ tab_text (tab, 0, 0, opts, text_item_get_text (text_item));
+ struct table_item *table_item = table_item_create (&tab->table, NULL, NULL);
+ text_item_unref (text_item);
+ return table_item;
+}\f
static void
text_item_destroy (struct output_item *output_item)
{
enum text_item_type type; /* Type. */
char *font;
int font_size;
- bool bold, italic, underline;
+ bool bold, italic, underline, markup;
};
struct text_item *text_item_create (enum text_item_type, const char *text);
enum text_item_type text_item_get_type (const struct text_item *);
const char *text_item_get_text (const struct text_item *);
+
+struct table_item *text_item_to_table_item (struct text_item *);
\f
/* This boilerplate for text_item, a subclass of output_item, was
autogenerated by mk-class-boilerplate. */