text-item: Simplify text_item further to just hold a pivot_value.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 10 Jan 2021 21:52:34 +0000 (13:52 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 10 Jan 2021 21:52:34 +0000 (13:52 -0800)
pivot_value has built-in support for font styling, so it eliminates the
need for a separate font_style object.

13 files changed:
src/output/csv.c
src/output/driver-provider.h
src/output/driver.c
src/output/html.c
src/output/journal.c
src/output/odt.c
src/output/pivot-table.c
src/output/spv/spv-output.c
src/output/spv/spv-writer.c
src/output/tex.c
src/output/text-item.c
src/output/text-item.h
src/ui/gui/psppire-output-view.c

index b97bfda6004a3812597601de5905a3251a965f86..dd8296059d92e68d423b8d546938f7990a62df92 100644 (file)
@@ -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))
     {
index c44a2e303bed8238a9fa89b1ff856503fd57b396..0f01fa9b30438f083ebf5865d3c5c8509b4df970 100644 (file)
@@ -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 */
index 55eac27d186d49c23a6ca3c154db9a740b51f105..a4718c939aaf79c04dbe504856a9fd72b0eeb17e 100644 (file)
@@ -21,8 +21,6 @@
 
 #include <ctype.h>
 #include <errno.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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);
 }
 \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)
-{
-  xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL);
-  if (!parser)
-    return xstrdup (markup);
-
-  xmlParseChunk (parser, "<xml>", strlen ("<xml>"), false);
-  xmlParseChunk (parser, markup, strlen (markup), false);
-  xmlParseChunk (parser, "</xml>", strlen ("</xml>"), 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)
 {
index 644ef49eba9e84082141fc1d5ef1cbb917eb9231..0be011d12876acbac0f55c255aece5c8cb8d9227 100644 (file)
@@ -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, "</p>\n");
           break;
         }
+
+      free (s);
     }
   else if (is_message_item (output_item))
     {
index 9cab78805177592a00b0ca92041ab6cf0fc99f92..f93ed0bc840d7e4c98e6ae636ca85bf4bc8d7d71 100644 (file)
@@ -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))
     {
index 4a87815548d43b2473e58f977e233870470e2663..82480bb3e365e58caffcb0218c0e05f4377539a5 100644 (file)
@@ -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);
index 85ac16d09c1bf2f311bdc7a02dd3cd8c8b8f0c14..1b3014c629694900d0336007f6a19d8efb08429d 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "output/pivot-table.h"
 
+#include <libxml/parser.h>
+#include <libxml/tree.h>
 #include <math.h>
 #include <stdlib.h>
 
@@ -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, "<xml>", strlen ("<xml>"), false);
+  xmlParseChunk (parser, markup, strlen (markup), false);
+  xmlParseChunk (parser, "</xml>", strlen ("</xml>"), 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);
 }
index c21ec22bcb29bc0c80dfd98cc41462e24aeea527..edca066ed2442f11211672a16bc82d79a2068672 100644 (file)
@@ -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);
 }
index 7f8f1e4155aa6dc4a037ccd0d3b3f08ba91318cc..6256b32f12dff42a2698ed3686f6fabec3e7ba7d 100644 (file)
@@ -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 */
index c5591011f8e81ea99b57d78897c0cf5f63fa8648..e569a12788893c1ef01cfc7baf2a0ed87293777b 100644 (file)
@@ -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))
     {
index 371ee901e6260221bf19df7344a68bc70191e7bd..7bcf2aa10d67f8f72cf19fb23d9ed7c0f620d505 100644 (file)
@@ -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);
 }
 
index 8b4114e0061dc1b4960c04dcab43735d121cb552..49b5bbe1ebf531b5e216e46595395b7a10ffeb6b 100644 (file)
@@ -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);
index 4a9a666cef6dd4c149425cdb6da69053fbb80285..746f3b942be099ff7c650fdd19105773b14fed6e 100644 (file)
@@ -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;
     }