FREQUENCIES and layered split file has tests that work
[pspp] / src / output / pivot-table.h
index 2a5d8467f81037e152505df4a8e7ae1049e24faa..f2125c7058b3c103e09a3909a39be019c0cca337 100644 (file)
@@ -25,6 +25,8 @@
 #include "libpspp/hmap.h"
 #include "output/table.h"
 
+struct ccase;
+struct dictionary;
 struct pivot_value;
 struct variable;
 union value;
@@ -177,9 +179,8 @@ enum pivot_axis_type
   {
     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);
@@ -281,6 +282,55 @@ void pivot_dimension_destroy (struct pivot_dimension *);
 void pivot_dimension_dump (const struct pivot_dimension *,
                            const struct pivot_table *, int indentation);
 \f
+/* Split file handling with pivot tables.
+
+   When SPLIT FILE is in effect with the LAYERED option, values for the split
+   file variables need to be incorporated into pivot table output.  These
+   functions make that easier.
+
+   To use them:
+
+   1. After adding the rest of the dimensions to an output pivot table, call
+      pivot_splits_create().  If there are any and LAYERED mode is in use, then
+      pivot_splits_create() will add a dimension for each split file
+      variable and return a structure.  Otherwise, it returns NULL.
+
+   2. Before adding data to the pivot table for each SPLIT FILE group, call
+      pivot_splits_new_split(), passing in an example case from the group (the
+      first or last case is fine).  This will the split file handler add
+      categories for the group to the split dimensions.
+
+      pivot_splits_new_split() does nothing if given a null pivot_splits, so
+      it's fine to call it unconditionally.
+
+   3. Use pivot_splits_put*(), instead of pivot_table_put*(), to add data to
+      the pivot table.  These functions automatically add the current group
+      leaf indexes after the indexes passed in, as a convenience.
+
+      These functions still work fine if given a null pivot_splits, so it's
+      fine to use them in all cases.
+
+   4. Destroy the pivot_splits with pivot_splits_destroy() when the pivot table
+      has been fully constructed. */
+
+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 *);
+
+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 *);
+\f
 /* A pivot_category is a leaf (a category) or a group:
 
    - For a leaf, neither index is SIZE_MAX.
@@ -489,6 +539,12 @@ 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 *);
 
+/* 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);
@@ -579,7 +635,7 @@ void pivot_table_dump (const struct pivot_table *, int indentation);
 \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. */
@@ -647,71 +703,76 @@ enum pivot_value_type
 */
 struct pivot_value
   {
-    struct font_style *font_style;
-    struct cell_style *cell_style;
-
-    char **subscripts;
-    size_t n_subscripts;
-
-    size_t *footnote_indexes;
-    size_t n_footnotes;
-
-    enum pivot_value_type type;
+    struct pivot_value_ex *ex;
     union
       {
+        enum pivot_value_type type;
+
         /* 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'. */
+            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. */
-            enum settings_value_show show; /* Show value or label or both? */
-            bool honor_small;         /* Honor value of pivot table 'small'? */
           }
         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? */
+            char *s;                  /* The string value. */
             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
           {
+            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. */
-            enum settings_value_show show; /* Show name or label or both? */
           }
         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. */
-            bool user_provided;
           }
         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. */
-            struct pivot_argument *args;
-            size_t n_args;
           }
         template;
       };
@@ -734,6 +795,8 @@ 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 *);
+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 *);
@@ -788,6 +851,33 @@ 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
   {