From 1c02620baa5dd413e3284071f6a5184c1e77bf40 Mon Sep 17 00:00:00 2001
From: Ben Pfaff
Date: Sun, 10 Jan 2021 13:52:34 -0800
Subject: [PATCH] text-item: Simplify text_item further to just hold a
pivot_value.
pivot_value has built-in support for font styling, so it eliminates the
need for a separate font_style object.
---
src/output/csv.c | 20 ++-----
src/output/driver-provider.h | 2 -
src/output/driver.c | 52 ++++-------------
src/output/html.c | 4 +-
src/output/journal.c | 6 +-
src/output/odt.c | 6 +-
src/output/pivot-table.c | 35 +++++++++++-
src/output/spv/spv-output.c | 20 ++-----
src/output/spv/spv-writer.c | 4 +-
src/output/tex.c | 3 +-
src/output/text-item.c | 97 +++++++++++++++++++++-----------
src/output/text-item.h | 10 ++--
src/ui/gui/psppire-output-view.c | 6 +-
13 files changed, 146 insertions(+), 119 deletions(-)
diff --git a/src/output/csv.c b/src/output/csv.c
index b97bfda600..dd8296059d 100644
--- a/src/output/csv.c
+++ b/src/output/csv.c
@@ -184,12 +184,6 @@ csv_output_table_cell (struct csv_driver *csv, const struct pivot_table *pt,
if (leader)
ds_put_format (&s, "%s: ", leader);
pivot_value_format (cell->value, pt, &s);
- if (cell->font_style->markup)
- {
- char *t = output_get_text_from_markup (ds_cstr (&s));
- ds_assign_cstr (&s, t);
- free (t);
- }
csv_output_field (csv, ds_cstr (&s));
ds_destroy (&s);
}
@@ -260,22 +254,16 @@ csv_submit (struct output_driver *driver,
else if (is_text_item (output_item))
{
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);
+ enum text_item_type type = text_item_get_type (text_item);
if (type == TEXT_ITEM_SYNTAX || type == TEXT_ITEM_PAGE_TITLE)
return;
csv_put_separator (csv);
- if (text_item->style.markup)
- {
- char *plain_text = output_get_text_from_markup (text);
- csv_output_lines (csv, plain_text);
- free (plain_text);
- }
- else
- csv_output_lines (csv, text);
+ char *text = text_item_get_plain_text (text_item);
+ csv_output_lines (csv, text);
+ free (text);
}
else if (is_page_break_item (output_item))
{
diff --git a/src/output/driver-provider.h b/src/output/driver-provider.h
index c44a2e303b..0f01fa9b30 100644
--- a/src/output/driver-provider.h
+++ b/src/output/driver-provider.h
@@ -105,6 +105,4 @@ struct output_driver_factory
struct string_map *options);
};
-char *output_get_text_from_markup (const char *markup);
-
#endif /* output/driver-provider.h */
diff --git a/src/output/driver.c b/src/output/driver.c
index 55eac27d18..a4718c939a 100644
--- a/src/output/driver.c
+++ b/src/output/driver.c
@@ -21,8 +21,6 @@
#include
#include
-#include
-#include
#include
#include
#include
@@ -240,27 +238,21 @@ output_submit (struct output_item *item)
size_t idx = --e->n_groups;
free (e->groups[idx]);
- if (idx >= 1 && idx <= 4)
- {
- char *key = xasprintf ("Head%zu", idx);
- free (string_map_find_and_delete (&e->heading_vars, key));
- free (key);
- }
+
+ char *key = xasprintf ("Head%zu", idx);
+ free (string_map_find_and_delete (&e->heading_vars, key));
+ free (key);
}
else if (is_text_item (item))
{
const struct text_item *text_item = to_text_item (item);
enum text_item_type type = text_item_get_type (text_item);
- const char *text = text_item_get_text (text_item);
- if (type == TEXT_ITEM_TITLE
- && e->n_groups >= 1 && e->n_groups <= 4)
- {
- char *key = xasprintf ("Head%zu", e->n_groups);
- string_map_replace (&e->heading_vars, key, text);
- free (key);
- }
- else if (type == TEXT_ITEM_PAGE_TITLE)
- string_map_replace (&e->heading_vars, "PageTitle", text);
+ char *key = (type == TEXT_ITEM_TITLE ? xasprintf ("Head%zu", e->n_groups)
+ : type == TEXT_ITEM_PAGE_TITLE ? xstrdup ("PageTitle")
+ : NULL);
+ if (key)
+ string_map_replace_nocopy (&e->heading_vars, key,
+ text_item_get_plain_text (text_item));
}
output_submit__ (e, item);
@@ -554,30 +546,6 @@ output_driver_parse_option (const char *option, struct string_map *options)
string_map_insert_nocopy (options, key, value);
}
-/* 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)
-{
- xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
- if (!parser)
- return xstrdup (markup);
-
- xmlParseChunk (parser, "", strlen (""), false);
- xmlParseChunk (parser, markup, strlen (markup), false);
- xmlParseChunk (parser, "", strlen (""), true);
-
- char *content
- = (parser->wellFormed
- ? CHAR_CAST (char *,
- xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc)))
- : xstrdup (markup));
- xmlFreeDoc (parser->myDoc);
- xmlFreeParserCtxt (parser);
-
- return content;
-}
-
char *
output_driver_substitute_heading_vars (const char *src, int page_number)
{
diff --git a/src/output/html.c b/src/output/html.c
index 644ef49eba..0be011d128 100644
--- a/src/output/html.c
+++ b/src/output/html.c
@@ -292,7 +292,7 @@ html_submit (struct output_driver *driver,
else if (is_text_item (output_item))
{
struct text_item *text_item = to_text_item (output_item);
- const char *s = text_item_get_text (text_item);
+ char *s = text_item_get_plain_text (text_item);
switch (text_item_get_type (text_item))
{
@@ -319,6 +319,8 @@ html_submit (struct output_driver *driver,
fprintf (html->file, "
\n");
break;
}
+
+ free (s);
}
else if (is_message_item (output_item))
{
diff --git a/src/output/journal.c b/src/output/journal.c
index 9cab788051..f93ed0bc84 100644
--- a/src/output/journal.c
+++ b/src/output/journal.c
@@ -109,7 +109,11 @@ journal_submit (struct output_driver *driver, const struct output_item *item)
enum text_item_type type = text_item_get_type (text_item);
if (type == TEXT_ITEM_SYNTAX)
- journal_output (j, text_item_get_text (text_item));
+ {
+ char *text = text_item_get_plain_text (text_item);
+ journal_output (j, text);
+ free (text);
+ }
}
else if (is_message_item (item))
{
diff --git a/src/output/odt.c b/src/output/odt.c
index 4a87815548..82480bb3e3 100644
--- a/src/output/odt.c
+++ b/src/output/odt.c
@@ -598,7 +598,11 @@ odt_submit (struct output_driver *driver,
if (is_table_item (output_item))
write_table (odt, to_table_item (output_item));
else if (is_text_item (output_item))
- odt_output_text (odt, text_item_get_text (to_text_item (output_item)));
+ {
+ char *text = text_item_get_plain_text (to_text_item (output_item));
+ odt_output_text (odt, text);
+ free (text);
+ }
else if (is_message_item (output_item))
{
const struct message_item *message_item = to_message_item (output_item);
diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c
index 85ac16d09c..1b3014c629 100644
--- a/src/output/pivot-table.c
+++ b/src/output/pivot-table.c
@@ -18,6 +18,8 @@
#include "output/pivot-table.h"
+#include
+#include
#include
#include
@@ -2301,6 +2303,33 @@ interpret_show (enum settings_value_show global_show,
: global_show);
}
+/* Appends to OUT the actual text content from the given Pango MARKUP. */
+static void
+get_text_from_markup (const char *markup, struct string *out)
+{
+ xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
+ if (!parser)
+ {
+ ds_put_cstr (out, markup);
+ return;
+ }
+
+ xmlParseChunk (parser, "", strlen (""), false);
+ xmlParseChunk (parser, markup, strlen (markup), false);
+ xmlParseChunk (parser, "", strlen (""), true);
+
+ if (parser->wellFormed)
+ {
+ xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc));
+ ds_put_cstr (out, CHAR_CAST (char *, s));
+ xmlFree (s);
+ }
+ else
+ ds_put_cstr (out, markup);
+ xmlFreeDoc (parser->myDoc);
+ xmlFreeParserCtxt (parser);
+}
+
/* Appends a text representation of the body of VALUE to OUT. Settings on
PT control whether variable and value labels are included.
@@ -2388,7 +2417,10 @@ pivot_value_format_body (const struct pivot_value *value,
break;
case PIVOT_VALUE_TEXT:
- ds_put_cstr (out, value->text.local);
+ if (value->font_style && value->font_style->markup)
+ get_text_from_markup (value->text.local, out);
+ else
+ ds_put_cstr (out, value->text.local);
break;
case PIVOT_VALUE_TEMPLATE:
@@ -2451,6 +2483,7 @@ pivot_value_to_string_defaults (const struct pivot_value *value)
static const struct pivot_table pt = {
.show_values = SETTINGS_VALUE_SHOW_DEFAULT,
.show_variables = SETTINGS_VALUE_SHOW_DEFAULT,
+ .settings = FMT_SETTINGS_INIT,
};
return pivot_value_to_string (value, &pt);
}
diff --git a/src/output/spv/spv-output.c b/src/output/spv/spv-output.c
index c21ec22bcb..edca066ed2 100644
--- a/src/output/spv/spv-output.c
+++ b/src/output/spv/spv-output.c
@@ -28,19 +28,11 @@ void
spv_text_submit (const struct spv_item *in)
{
enum spv_item_class class = spv_item_get_class (in);
- enum text_item_type type
- = (class == SPV_CLASS_HEADINGS ? TEXT_ITEM_TITLE
- : class == SPV_CLASS_PAGETITLE ? TEXT_ITEM_PAGE_TITLE
- : TEXT_ITEM_LOG);
- const struct pivot_value *value = spv_item_get_text (in);
- char *text = pivot_value_to_string_defaults (value);
- char *label = in->label ? xstrdup (in->label) : NULL;
- struct text_item *item = text_item_create_nocopy (type, text, label);
-
- if (value->font_style)
- {
- font_style_uninit (&item->style);
- font_style_copy (NULL, &item->style, value->font_style);
- }
+ struct text_item *item = text_item_create_value (
+ (class == SPV_CLASS_HEADINGS ? TEXT_ITEM_TITLE
+ : class == SPV_CLASS_PAGETITLE ? TEXT_ITEM_PAGE_TITLE
+ : TEXT_ITEM_LOG),
+ pivot_value_clone (spv_item_get_text (in)),
+ in->label ? xstrdup (in->label) : NULL);
text_item_submit (item);
}
diff --git a/src/output/spv/spv-writer.c b/src/output/spv/spv-writer.c
index 7f8f1e4155..6256b32f12 100644
--- a/src/output/spv/spv-writer.c
+++ b/src/output/spv/spv-writer.c
@@ -314,7 +314,9 @@ spv_writer_put_text (struct spv_writer *w, const struct text_item *text,
write_attr (w, "commandName", command_id);
start_elem (w, "html");
- write_text (w, text->text); /* XXX */
+ char *s = text_item_get_plain_text (text);
+ write_text (w, s);
+ free (s);
end_elem (w); /* html */
end_elem (w); /* vtx:text */
end_elem (w); /* container */
diff --git a/src/output/tex.c b/src/output/tex.c
index c5591011f8..e569a12788 100644
--- a/src/output/tex.c
+++ b/src/output/tex.c
@@ -350,7 +350,7 @@ tex_submit (struct output_driver *driver,
else if (is_text_item (output_item))
{
struct text_item *text_item = to_text_item (output_item);
- const char *s = text_item_get_text (text_item);
+ char *s = text_item_get_plain_text (text_item);
switch (text_item_get_type (text_item))
{
@@ -372,6 +372,7 @@ tex_submit (struct output_driver *driver,
printf ("Unhandled type %d\n", text_item_get_type (text_item));
break;
}
+ free (s);
}
else if (is_message_item (output_item))
{
diff --git a/src/output/text-item.c b/src/output/text-item.c
index 371ee901e6..7bcf2aa10d 100644
--- a/src/output/text-item.c
+++ b/src/output/text-item.c
@@ -63,22 +63,8 @@ text_item_type_to_string (enum text_item_type type)
struct text_item *
text_item_create_nocopy (enum text_item_type type, char *text, char *label)
{
- struct text_item *item = xzalloc (sizeof *item);
- *item = (struct text_item) {
- .output_item = OUTPUT_ITEM_INITIALIZER (&text_item_class),
- .output_item.label = label,
- .text = text,
- .type = type,
- .style = FONT_STYLE_INITIALIZER,
- };
-
- if (type == TEXT_ITEM_SYNTAX || type == TEXT_ITEM_LOG)
- {
- free (item->style.typeface);
- item->style.typeface = xstrdup ("Monospaced");
- }
-
- return item;
+ return text_item_create_value (type, pivot_value_new_user_text_nocopy (text),
+ label);
}
/* Creates and returns a new text item containing a copy of TEXT and the
@@ -92,6 +78,35 @@ text_item_create (enum text_item_type type, const char *text,
label ? xstrdup (label) : NULL);
}
+/* Creates and returns a new text item containing VALUE, TYPE, and LABEL.
+ Takes ownership of VALUE and LABEL. If LABEL is null, uses a default label
+ for TYPE. */
+struct text_item *
+text_item_create_value (enum text_item_type type, struct pivot_value *value,
+ char *label)
+{
+ if (type == TEXT_ITEM_SYNTAX || type == TEXT_ITEM_LOG)
+ {
+ if (!value->font_style)
+ {
+ value->font_style = xmalloc (sizeof *value->font_style);
+ *value->font_style = (struct font_style) FONT_STYLE_INITIALIZER;
+ }
+
+ free (value->font_style->typeface);
+ value->font_style->typeface = xstrdup ("Monospaced");
+ }
+
+ struct text_item *item = xzalloc (sizeof *item);
+ *item = (struct text_item) {
+ .output_item = OUTPUT_ITEM_INITIALIZER (&text_item_class),
+ .output_item.label = label,
+ .type = type,
+ .text = value,
+ };
+ return item;
+}
+
/* Returns ITEM's type. */
enum text_item_type
text_item_get_type (const struct text_item *item)
@@ -99,11 +114,11 @@ text_item_get_type (const struct text_item *item)
return item->type;
}
-/* Returns ITEM's text, which the caller may not modify or free. */
-const char *
-text_item_get_text (const struct text_item *item)
+/* Returns ITEM's text, which the caller must eventually free. */
+char *
+text_item_get_plain_text (const struct text_item *item)
{
- return item->text;
+ return pivot_value_to_string_defaults (item->text);
}
/* Submits ITEM to the configured output drivers, and transfers ownership to
@@ -125,13 +140,19 @@ text_item_unshare (struct text_item *old)
struct text_item *new = xmalloc (sizeof *new);
*new = (struct text_item) {
.output_item = OUTPUT_ITEM_CLONE_INITIALIZER (&old->output_item),
- .text = xstrdup (old->text),
+ .text = pivot_value_clone (old->text),
.type = old->type,
};
- font_style_copy (NULL, &new->style, &old->style);
return new;
}
+static bool
+nullable_font_style_equal (const struct font_style *a,
+ const struct font_style *b)
+{
+ return a && b ? font_style_equal (a, b) : !a && !b;
+}
+
/* Attempts to append the text in SRC to DST. If successful, returns true,
otherwise false.
@@ -147,14 +168,28 @@ text_item_append (struct text_item *dst, const struct text_item *src)
|| (dst->type != TEXT_ITEM_SYNTAX && dst->type != TEXT_ITEM_LOG)
|| strcmp (output_item_get_label (&dst->output_item),
output_item_get_label (&src->output_item))
- || !font_style_equal (&dst->style, &src->style)
- || dst->style.markup)
+ || !nullable_font_style_equal (dst->text->font_style,
+ src->text->font_style)
+ || (dst->text->font_style && dst->text->font_style->markup)
+ || src->text->type != PIVOT_VALUE_TEXT
+ || dst->text->type != PIVOT_VALUE_TEXT)
return false;
else
{
- char *new_text = xasprintf ("%s\n%s", dst->text, src->text);
- free (dst->text);
- dst->text = new_text;
+ char *new_text = xasprintf ("%s\n%s", dst->text->text.local,
+ src->text->text.local);
+
+ free (dst->text->text.local);
+ if (dst->text->text.c != dst->text->text.local)
+ free (dst->text->text.c);
+ if (dst->text->text.id != dst->text->text.local
+ && dst->text->text.id != dst->text->text.c)
+ free (dst->text->text.id);
+
+ dst->text->text.local = new_text;
+ dst->text->text.c = new_text;
+ dst->text->text.id = new_text;
+
return true;
}
}
@@ -187,10 +222,7 @@ text_item_to_table_item (struct text_item *text_item)
d->hide_all_labels = true;
pivot_category_create_leaf (d->root, pivot_value_new_text ("null"));
- struct pivot_value *content = pivot_value_new_user_text (
- text_item->text, SIZE_MAX);
- pivot_value_set_font_style (content, &text_item->style);
- pivot_table_put1 (table, 0, content);
+ pivot_table_put1 (table, 0, pivot_value_clone (text_item->text));
text_item_unref (text_item);
@@ -208,8 +240,7 @@ static void
text_item_destroy (struct output_item *output_item)
{
struct text_item *item = to_text_item (output_item);
- free (item->text);
- font_style_uninit (&item->style);
+ pivot_value_destroy (item->text);
free (item);
}
diff --git a/src/output/text-item.h b/src/output/text-item.h
index 8b4114e006..49b5bbe1eb 100644
--- a/src/output/text-item.h
+++ b/src/output/text-item.h
@@ -43,18 +43,20 @@ const char *text_item_type_to_string (enum text_item_type);
struct text_item
{
struct output_item output_item;
- char *text; /* The content. */
- enum text_item_type type; /* Type. */
- struct font_style style;
+ enum text_item_type type;
+ struct pivot_value *text;
};
struct text_item *text_item_create (enum text_item_type,
const char *text, const char *label);
struct text_item *text_item_create_nocopy (enum text_item_type,
char *text, char *label);
+struct text_item *text_item_create_value (enum text_item_type,
+ struct pivot_value *value,
+ char *label);
enum text_item_type text_item_get_type (const struct text_item *);
-const char *text_item_get_text (const struct text_item *);
+char *text_item_get_plain_text (const struct text_item *);
struct text_item *text_item_unshare (struct text_item *);
bool text_item_append (struct text_item *dst, const struct text_item *src);
diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c
index 4a9a666cef..746f3b942b 100644
--- a/src/ui/gui/psppire-output-view.c
+++ b/src/ui/gui/psppire-output-view.c
@@ -419,8 +419,10 @@ psppire_output_view_put (struct psppire_output_view *view,
else if (is_text_item (item))
{
const struct text_item *text_item = to_text_item (item);
- const char *text = text_item_get_text (text_item);
- if (text[0] == '\0')
+ char *text = text_item_get_plain_text (text_item);
+ bool text_is_empty = text[0] == '\0';
+ free (text);
+ if (text_is_empty)
return;
}
--
2.30.2