Layered split file for FREQUENCIES works.
[pspp] / src / output / pivot-table.h
index 377579a013d356b3f5feb4cea5959381be201ae8..2904fd4f357c1211da1d3b95d5aeb193e3776f6e 100644 (file)
@@ -25,6 +25,8 @@
 #include "libpspp/hmap.h"
 #include "output/table.h"
 
 #include "libpspp/hmap.h"
 #include "output/table.h"
 
+struct ccase;
+struct dictionary;
 struct pivot_value;
 struct variable;
 union value;
 struct pivot_value;
 struct variable;
 union value;
@@ -60,15 +62,11 @@ union value;
    Creating a pivot table usually consists of the following steps:
 
    1. Create the table with pivot_table_create(), passing in the title.
    Creating a pivot table usually consists of the following steps:
 
    1. Create the table with pivot_table_create(), passing in the title.
-      It's commonly useful to set up a few options at this point:
 
 
-      - If empty rows or columns should not be displayed, set ->omit_empty to
-        true.
+   2. Optionally, set the format to use for "count" values with
+      pivot_table_set_weight_var() or pivot_table_set_weight_format().
 
 
-      - Set the format to use for "count" values with
-        pivot_table_set_weight_var() or pivot_table_set_weight_format().
-
-   2. Create each dimension with pivot_dimension_create() and populate it with
+   3. Create each dimension with pivot_dimension_create() and populate it with
       categories and, possibly, with groups that contain the categories.  This
       call also assigns the dimension to an axis.
 
       categories and, possibly, with groups that contain the categories.  This
       call also assigns the dimension to an axis.
 
@@ -81,14 +79,14 @@ union value;
       first cell for that variable.  In that case, creating categories and
       inserting data can be interleaved.
 
       first cell for that variable.  In that case, creating categories and
       inserting data can be interleaved.
 
-   3. Insert data.  For each cell, supply the category indexes, which are
+   4. Insert data.  For each cell, supply the category indexes, which are
       assigned starting from 0 in the order in which the categories were
       created in step 2, and the value to go in the cell.  If the table has a
       small, fixed number of dimensions, functions like, e.g.
       pivot_table_put3() for 3 dimensions, can be used.  The general function
       pivot_table_put() works for other cases.
 
       assigned starting from 0 in the order in which the categories were
       created in step 2, and the value to go in the cell.  If the table has a
       small, fixed number of dimensions, functions like, e.g.
       pivot_table_put3() for 3 dimensions, can be used.  The general function
       pivot_table_put() works for other cases.
 
-   4. Output the table for user consumption.  Use pivot_table_submit(). */
+   5. Output the table for user consumption.  Use pivot_table_submit(). */
 \f
 /* Pivot table display styling. */
 
 \f
 /* Pivot table display styling. */
 
@@ -107,7 +105,6 @@ enum pivot_area
   };
 
 const char *pivot_area_to_string (enum pivot_area);
   };
 
 const char *pivot_area_to_string (enum pivot_area);
-const struct area_style *pivot_area_get_default_style (enum pivot_area);
 
 /* Table borders for styling purposes. */
 enum pivot_border
 
 /* Table borders for styling purposes. */
 enum pivot_border
@@ -146,17 +143,12 @@ enum pivot_border
   };
 
 const char *pivot_border_to_string (enum pivot_border);
   };
 
 const char *pivot_border_to_string (enum pivot_border);
-void pivot_border_get_default_style (enum pivot_border,
-                                     struct table_border_style *);
 
 /* Sizing for rows or columns of a rendered table.  The comments below talk
    about columns and their widths but they apply equally to rows and their
    heights. */
 struct pivot_table_sizing
   {
 
 /* Sizing for rows or columns of a rendered table.  The comments below talk
    about columns and their widths but they apply equally to rows and their
    heights. */
 struct pivot_table_sizing
   {
-    /* Minimum and maximum column width, in 1/96" units. */
-    int range[2];
-
     /* Specific column widths, in 1/96" units. */
     int *widths;
     size_t n_widths;
     /* Specific column widths, in 1/96" units. */
     int *widths;
     size_t n_widths;
@@ -187,9 +179,8 @@ enum pivot_axis_type
   {
     PIVOT_AXIS_LAYER,
     PIVOT_AXIS_ROW,
   {
     PIVOT_AXIS_LAYER,
     PIVOT_AXIS_ROW,
-    PIVOT_AXIS_COLUMN,
-
-    PIVOT_N_AXES
+    PIVOT_AXIS_COLUMN
+#define PIVOT_N_AXES 3
   };
 
 const char *pivot_axis_type_to_string (enum pivot_axis_type);
   };
 
 const char *pivot_axis_type_to_string (enum pivot_axis_type);
@@ -288,7 +279,30 @@ struct pivot_dimension *pivot_dimension_create__ (struct pivot_table *,
 
 void pivot_dimension_destroy (struct pivot_dimension *);
 
 
 void pivot_dimension_destroy (struct pivot_dimension *);
 
-void pivot_dimension_dump (const struct pivot_dimension *, int indentation);
+void pivot_dimension_dump (const struct pivot_dimension *,
+                           const struct pivot_table *, int indentation);
+\f
+struct pivot_splits *pivot_splits_create (struct pivot_table *,
+                                          enum pivot_axis_type,
+                                          const struct dictionary *);
+void pivot_splits_destroy (struct pivot_splits *);
+
+void pivot_splits_new_split (struct pivot_splits *, const struct ccase *);
+size_t pivot_splits_get_dindexes (const struct pivot_splits *,
+                                  size_t *dindexes);
+
+void pivot_splits_put1 (struct pivot_splits *, struct pivot_table *,
+                        size_t idx1, struct pivot_value *);
+void pivot_splits_put2 (struct pivot_splits *, struct pivot_table *,
+                        size_t idx1, size_t idx2, struct pivot_value *);
+void pivot_splits_put3 (struct pivot_splits *, struct pivot_table *,
+                        size_t idx1, size_t idx2, size_t idx3,
+                        struct pivot_value *);
+void pivot_splits_put4 (struct pivot_splits *, struct pivot_table *,
+                        size_t idx1, size_t idx2, size_t idx3, size_t idx4,
+                        struct pivot_value *);
+
+size_t pivot_splits_count (const struct pivot_splits *);
 \f
 /* A pivot_category is a leaf (a category) or a group:
 
 \f
 /* A pivot_category is a leaf (a category) or a group:
 
@@ -316,10 +330,11 @@ struct pivot_category
     bool show_label_in_corner;
 
     /* Leaf only. */
     bool show_label_in_corner;
 
     /* Leaf only. */
-    struct fmt_spec format;
     size_t group_index;        /* In ->parent->subs[]. */
     size_t data_index;         /* In ->dimension->data_leaves[]. */
     size_t presentation_index; /* In ->dimension->presentation_leaves[]. */
     size_t group_index;        /* In ->parent->subs[]. */
     size_t data_index;         /* In ->dimension->data_leaves[]. */
     size_t presentation_index; /* In ->dimension->presentation_leaves[]. */
+    struct fmt_spec format;    /* Default format for values in this category. */
+    bool honor_small;          /* Honor pivot_table 'small' setting? */
   };
 
 static inline bool
   };
 
 static inline bool
@@ -371,6 +386,56 @@ void pivot_category_destroy (struct pivot_category *);
 #define PIVOT_RC_COUNT ("RC_COUNT")
 
 bool pivot_result_class_change (const char *, const struct fmt_spec *);
 #define PIVOT_RC_COUNT ("RC_COUNT")
 
 bool pivot_result_class_change (const char *, const struct fmt_spec *);
+bool is_pivot_result_class (const char *);
+\f
+/* Styling for a pivot table.
+
+   The division between this and the style information in struct pivot_table
+   seems fairly arbitrary.  The ultimate reason for the division is simply
+   because that's how SPSS documentation and file formats do it. */
+struct pivot_table_look
+  {
+    /* Reference count.  A pivot_table_look may be shared between multiple
+       owners, indicated by a reference count greater than 1.  When this is the
+       case, the pivot_table must not be modified. */
+    int ref_cnt;
+
+    char *name;                 /* May be null. */
+
+    /* General properties. */
+    bool omit_empty;
+    bool row_labels_in_corner;
+    int width_ranges[TABLE_N_AXES][2];      /* In 1/96" units. */
+
+    /* Footnote display settings. */
+    bool show_numeric_markers;
+    bool footnote_marker_superscripts;
+
+    /* Styles. */
+    struct table_area_style areas[PIVOT_N_AREAS];
+    struct table_border_style borders[PIVOT_N_BORDERS];
+
+    /* Print settings. */
+    bool print_all_layers;
+    bool paginate_layers;
+    bool shrink_to_fit[TABLE_N_AXES];
+    bool top_continuation, bottom_continuation;
+    char *continuation;
+    size_t n_orphan_lines;
+  };
+
+const struct pivot_table_look *pivot_table_look_get_default (void);
+void pivot_table_look_set_default (const struct pivot_table_look *);
+
+char *pivot_table_look_read (const char *, struct pivot_table_look **)
+  WARN_UNUSED_RESULT;
+
+const struct pivot_table_look *pivot_table_look_builtin_default (void);
+struct pivot_table_look *pivot_table_look_new_builtin_default (void);
+struct pivot_table_look *pivot_table_look_ref (
+  const struct pivot_table_look *);
+void pivot_table_look_unref (struct pivot_table_look *);
+struct pivot_table_look *pivot_table_look_unshare (struct pivot_table_look *);
 \f
 /* A pivot table.  See the top of this file for more information. */
 struct pivot_table
 \f
 /* A pivot table.  See the top of this file for more information. */
 struct pivot_table
@@ -380,40 +445,27 @@ struct pivot_table
        the pivot_table must not be modified. */
     int ref_cnt;
 
        the pivot_table must not be modified. */
     int ref_cnt;
 
+    /* Styling. */
+    struct pivot_table_look *look;
+
     /* Display settings. */
     bool rotate_inner_column_labels;
     bool rotate_outer_row_labels;
     /* Display settings. */
     bool rotate_inner_column_labels;
     bool rotate_outer_row_labels;
-    bool row_labels_in_corner;
     bool show_grid_lines;
     bool show_grid_lines;
+    bool show_title;
     bool show_caption;
     bool show_caption;
-    bool omit_empty;       /* Omit empty rows and columns? */
-    size_t *current_layer; /* axis[PIVOT_AXIS_LAYER].n_dimensions elements. */
-    char *table_look;
+    size_t *current_layer; /* axes[PIVOT_AXIS_LAYER].n_dimensions elements. */
     enum settings_value_show show_values;
     enum settings_value_show show_variables;
     struct fmt_spec weight_format;
 
     enum settings_value_show show_values;
     enum settings_value_show show_variables;
     struct fmt_spec weight_format;
 
-    /* Footnote display settings. */
-    bool show_numeric_markers;
-    bool footnote_marker_superscripts;
-
     /* Column and row sizing and page breaks.
        sizing[TABLE_HORZ] is for columns, sizing[TABLE_VERT] is for rows. */
     struct pivot_table_sizing sizing[TABLE_N_AXES];
 
     /* Column and row sizing and page breaks.
        sizing[TABLE_HORZ] is for columns, sizing[TABLE_VERT] is for rows. */
     struct pivot_table_sizing sizing[TABLE_N_AXES];
 
-    /* Print settings. */
-    bool print_all_layers;
-    bool paginate_layers;
-    bool shrink_to_fit[TABLE_N_AXES];
-    bool top_continuation, bottom_continuation;
-    char *continuation;
-    size_t n_orphan_lines;
-
     /* Format settings. */
     /* Format settings. */
-    int epoch;
-    char decimal;               /* Usually ',' or '.'. */
+    struct fmt_settings settings;
     char grouping;              /* Usually '.' or ','. */
     char grouping;              /* Usually '.' or ','. */
-    char *ccs[5];               /* Custom currency. */
     double small;
 
     /* Command information. */
     double small;
 
     /* Command information. */
@@ -436,11 +488,7 @@ struct pivot_table
     struct pivot_value *subtype;  /* Same as spv_item's subtype. */
     struct pivot_value *corner_text;
     struct pivot_value *caption;
     struct pivot_value *subtype;  /* Same as spv_item's subtype. */
     struct pivot_value *corner_text;
     struct pivot_value *caption;
-    char *notes;
-
-    /* Styles. */
-    struct area_style areas[PIVOT_N_AREAS];
-    struct table_border_style borders[PIVOT_N_BORDERS];
+    char *notes;                /* Shown as tooltip. */
 
     /* Dimensions. */
     struct pivot_dimension **dimensions;
 
     /* Dimensions. */
     struct pivot_dimension **dimensions;
@@ -460,9 +508,30 @@ struct pivot_table *pivot_table_create_for_text (struct pivot_value *title,
                                                  struct pivot_value *content);
 
 struct pivot_table *pivot_table_ref (const struct pivot_table *);
                                                  struct pivot_value *content);
 
 struct pivot_table *pivot_table_ref (const struct pivot_table *);
+struct pivot_table *pivot_table_unshare (struct pivot_table *);
 void pivot_table_unref (struct pivot_table *);
 bool pivot_table_is_shared (const struct pivot_table *);
 
 void pivot_table_unref (struct pivot_table *);
 bool pivot_table_is_shared (const struct pivot_table *);
 
+/* Titles. */
+void pivot_table_set_title (struct pivot_table *, struct pivot_value *);
+void pivot_table_set_subtype (struct pivot_table *, struct pivot_value *);
+void pivot_table_set_corner_text (struct pivot_table *, struct pivot_value *);
+void pivot_table_set_caption (struct pivot_table *, struct pivot_value *);
+
+/* Axes. */
+void pivot_table_swap_axes (struct pivot_table *,
+                            enum pivot_axis_type, enum pivot_axis_type);
+void pivot_table_transpose (struct pivot_table *);
+void pivot_table_move_dimension (struct pivot_table *,
+                                 struct pivot_dimension *,
+                                 enum pivot_axis_type, size_t ofs);
+
+/* Styling. */
+const struct pivot_table_look *pivot_table_get_look (
+  const struct pivot_table *);
+void pivot_table_set_look (struct pivot_table *,
+                           const struct pivot_table_look *);
+
 /* Format of PIVOT_RC_COUNT cells. */
 void pivot_table_set_weight_var (struct pivot_table *,
                                  const struct variable *);
 /* Format of PIVOT_RC_COUNT cells. */
 void pivot_table_set_weight_var (struct pivot_table *,
                                  const struct variable *);
@@ -493,6 +562,8 @@ const struct pivot_value *pivot_table_get (const struct pivot_table *,
 struct pivot_value *pivot_table_get_rw (struct pivot_table *,
                                         const size_t *dindexes);
 
 struct pivot_value *pivot_table_get_rw (struct pivot_table *,
                                         const size_t *dindexes);
 
+bool pivot_table_delete (struct pivot_table *, const size_t *dindexes);
+
 /* Footnotes.
 
    Use pivot_table_create_footnote() to create a footnote.
 /* Footnotes.
 
    Use pivot_table_create_footnote() to create a footnote.
@@ -511,6 +582,12 @@ struct pivot_footnote *pivot_table_create_footnote__ (
   struct pivot_table *, size_t idx,
   struct pivot_value *marker, struct pivot_value *content);
 
   struct pivot_table *, size_t idx,
   struct pivot_value *marker, struct pivot_value *content);
 
+void pivot_footnote_format_marker (const struct pivot_footnote *,
+                                   const struct pivot_table *,
+                                   struct string *);
+char *pivot_footnote_marker_string (const struct pivot_footnote *,
+                                    const struct pivot_table *);
+
 void pivot_footnote_destroy (struct pivot_footnote *);
 
 /* Internals. */
 void pivot_footnote_destroy (struct pivot_footnote *);
 
 /* Internals. */
@@ -531,7 +608,7 @@ void pivot_table_dump (const struct pivot_table *, int indentation);
 \f
 /* pivot_value. */
 
 \f
 /* pivot_value. */
 
-enum pivot_value_type
+enum ATTRIBUTE ((packed)) pivot_value_type
   {
     PIVOT_VALUE_NUMERIC,          /* A value of a numeric variable. */
     PIVOT_VALUE_STRING,           /* A value of a string variable. */
   {
     PIVOT_VALUE_NUMERIC,          /* A value of a numeric variable. */
     PIVOT_VALUE_STRING,           /* A value of a string variable. */
@@ -599,73 +676,85 @@ enum pivot_value_type
 */
 struct pivot_value
   {
 */
 struct pivot_value
   {
-    struct font_style *font_style;
-    struct cell_style *cell_style;
-
-    char **subscripts;
-    size_t n_subscripts;
-
-    char *superscript;
-
-    const struct pivot_footnote **footnotes;
-    size_t n_footnotes;
-
-    enum pivot_value_type type;
+    struct pivot_value_ex *ex;
     union
       {
     union
       {
+        enum pivot_value_type type;
+
         /* PIVOT_VALUE_NUMERIC. */
         struct
           {
         /* PIVOT_VALUE_NUMERIC. */
         struct
           {
-            double x;                 /* The numeric value. */
+            enum pivot_value_type type;
+            enum settings_value_show show; /* Show value or label or both? */
             struct fmt_spec format;   /* Format to display 'x'. */
             struct fmt_spec format;   /* Format to display 'x'. */
+            bool honor_small;         /* Honor value of pivot table 'small'? */
+            double x;                 /* The numeric value. */
             char *var_name;           /* May be NULL. */
             char *value_label;        /* May be NULL. */
             char *var_name;           /* May be NULL. */
             char *value_label;        /* May be NULL. */
-            enum settings_value_show show; /* Show value or label or both? */
           }
         numeric;
 
         /* PIVOT_VALUE_STRING. */
         struct
           {
           }
         numeric;
 
         /* PIVOT_VALUE_STRING. */
         struct
           {
-            char *s;                  /* The string value. */
+            enum pivot_value_type type;
+            enum settings_value_show show; /* Show value or label or both? */
             bool hex;                 /* Display in hex? */
             bool hex;                 /* Display in hex? */
+            char *s;                  /* The string value. */
             char *var_name;           /* May be NULL. */
             char *value_label;        /* May be NULL. */
             char *var_name;           /* May be NULL. */
             char *value_label;        /* May be NULL. */
-            enum settings_value_show show; /* Show value or label or both? */
           }
         string;
 
         /* PIVOT_VALUE_VARIABLE. */
         struct
           {
           }
         string;
 
         /* PIVOT_VALUE_VARIABLE. */
         struct
           {
+            enum pivot_value_type type;
+            enum settings_value_show show; /* Show name or label or both? */
             char *var_name;
             char *var_label;          /* May be NULL. */
             char *var_name;
             char *var_label;          /* May be NULL. */
-            enum settings_value_show show; /* Show name or label or both? */
           }
         variable;
 
         /* PIVOT_VALUE_TEXT. */
         struct
           {
           }
         variable;
 
         /* PIVOT_VALUE_TEXT. */
         struct
           {
+            enum pivot_value_type type;
+
+            /* 'local', 'c', and 'id' must all be nonnull, but they are allowed
+               to be the same pointer. */
+            bool user_provided;
             char *local;              /* Localized. */
             char *c;                  /* English. */
             char *id;                 /* Identifier. */
             char *local;              /* Localized. */
             char *c;                  /* English. */
             char *id;                 /* Identifier. */
-            bool user_provided;
           }
         text;
 
         /* PIVOT_VALUE_TEMPLATE. */
         struct
           {
           }
         text;
 
         /* PIVOT_VALUE_TEMPLATE. */
         struct
           {
+            enum pivot_value_type type;
+
+            /* Arguments.
+
+               The odd ordering in this struct reduces the overall size
+               of struct pivot_value. */
+            unsigned int n_args;
+            struct pivot_argument *args;
+
+            /* Both 'local' and 'id' must be nonnull, but they are allowed to
+               be the same pointer. */
             char *local;              /* Localized. */
             char *id;                 /* Identifier. */
             char *local;              /* Localized. */
             char *id;                 /* Identifier. */
-            struct pivot_argument *args;
-            size_t n_args;
           }
         template;
       };
   };
 
           }
         template;
       };
   };
 
+/* Life cycle. */
+struct pivot_value *pivot_value_clone (const struct pivot_value *);
+void pivot_value_destroy (struct pivot_value *);
+
 /* Numbers resulting from calculations. */
 struct pivot_value *pivot_value_new_number (double);
 struct pivot_value *pivot_value_new_integer (double);
 /* Numbers resulting from calculations. */
 struct pivot_value *pivot_value_new_number (double);
 struct pivot_value *pivot_value_new_integer (double);
@@ -679,17 +768,24 @@ struct pivot_value *pivot_value_new_value (const union value *, int width,
 
 /* Values from variable names. */
 struct pivot_value *pivot_value_new_variable (const struct variable *);
 
 /* Values from variable names. */
 struct pivot_value *pivot_value_new_variable (const struct variable *);
+struct pivot_value *pivot_value_new_variable__ (const char *name,
+                                                const char *label);
 
 /* Values from text strings. */
 struct pivot_value *pivot_value_new_text (const char *);
 struct pivot_value *pivot_value_new_text_format (const char *, ...)
 
 /* Values from text strings. */
 struct pivot_value *pivot_value_new_text (const char *);
 struct pivot_value *pivot_value_new_text_format (const char *, ...)
-  PRINTF_FORMAT (1, 2);
+#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
+  __attribute__((format(gnu_printf, 1, 2)));
+#else
+  __attribute__((format(__printf__, 1, 2)));
+#endif
 
 struct pivot_value *pivot_value_new_user_text (const char *, size_t length);
 struct pivot_value *pivot_value_new_user_text_nocopy (char *);
 
 /* Footnotes. */
 void pivot_value_add_footnote (struct pivot_value *, const struct pivot_footnote *);
 
 struct pivot_value *pivot_value_new_user_text (const char *, size_t length);
 struct pivot_value *pivot_value_new_user_text_nocopy (char *);
 
 /* Footnotes. */
 void pivot_value_add_footnote (struct pivot_value *, const struct pivot_footnote *);
+void pivot_value_sort_footnotes (struct pivot_value *);
 
 /* Numeric formats. */
 void pivot_value_set_rc (const struct pivot_table *, struct pivot_value *,
 
 /* Numeric formats. */
 void pivot_value_set_rc (const struct pivot_table *, struct pivot_value *,
@@ -697,25 +793,25 @@ void pivot_value_set_rc (const struct pivot_table *, struct pivot_value *,
 
 /* Converting a pivot_value to a string for display. */
 char *pivot_value_to_string (const struct pivot_value *,
 
 /* Converting a pivot_value to a string for display. */
 char *pivot_value_to_string (const struct pivot_value *,
-                             enum settings_value_show show_values,
-                             enum settings_value_show show_variables);
-void pivot_value_format (const struct pivot_value *,
-                         enum settings_value_show show_values,
-                         enum settings_value_show show_variables,
-                         struct string *);
+                             const struct pivot_table *);
+char *pivot_value_to_string_defaults (const struct pivot_value *);
+bool pivot_value_format (const struct pivot_value *,
+                         const struct pivot_table *, struct string *);
 bool pivot_value_format_body (const struct pivot_value *,
 bool pivot_value_format_body (const struct pivot_value *,
-                              enum settings_value_show show_values,
-                              enum settings_value_show show_variables,
+                              const struct pivot_table *,
                               struct string *);
 
                               struct string *);
 
-void pivot_value_destroy (struct pivot_value *);
-
 /* Styling. */
 void pivot_value_get_style (struct pivot_value *,
                             const struct font_style *base_font_style,
                             const struct cell_style *base_cell_style,
 /* Styling. */
 void pivot_value_get_style (struct pivot_value *,
                             const struct font_style *base_font_style,
                             const struct cell_style *base_cell_style,
-                            struct area_style *);
-void pivot_value_set_style (struct pivot_value *, const struct area_style *);
+                            struct table_area_style *);
+void pivot_value_set_style (struct pivot_value *,
+                            const struct table_area_style *);
+void pivot_value_set_font_style (struct pivot_value *,
+                                 const struct font_style *);
+void pivot_value_set_cell_style (struct pivot_value *,
+                                 const struct cell_style *);
 
 /* Template arguments. */
 struct pivot_argument
 
 /* Template arguments. */
 struct pivot_argument
@@ -725,6 +821,35 @@ struct pivot_argument
   };
 
 void pivot_argument_uninit (struct pivot_argument *);
   };
 
 void pivot_argument_uninit (struct pivot_argument *);
+void pivot_argument_copy (struct pivot_argument *,
+                          const struct pivot_argument *);
+\f
+/* Extra styling for a pivot_value.
+
+   This is logically part of pivot_value itself.  It is broken into a separate
+   structure to save memory because it is rarely used. */
+struct pivot_value_ex
+  {
+    struct font_style *font_style;
+    struct cell_style *cell_style;
+
+    char **subscripts;
+    size_t n_subscripts;
+
+    size_t *footnote_indexes;
+    size_t n_footnotes;
+  };
+
+static inline const struct pivot_value_ex *
+pivot_value_ex (const struct pivot_value *value)
+{
+  static const struct pivot_value_ex empty_ex = { .font_style = NULL };
+  return value->ex ? value->ex : &empty_ex;
+}
+
+struct pivot_value_ex *pivot_value_ex_rw (struct pivot_value *);
+struct pivot_value_ex *pivot_value_ex_clone (const struct pivot_value_ex *);
+void pivot_value_ex_destroy (struct pivot_value_ex *);
 \f
 /* One piece of data within a pivot table. */
 struct pivot_cell
 \f
 /* One piece of data within a pivot table. */
 struct pivot_cell