-struct ctables_value
- {
- struct hmap_node node;
- union value value;
- int leaf;
- };
-
-struct ctables_occurrence
- {
- struct hmap_node node;
- union value value;
- };
-
-struct ctables_section
- {
- /* Settings. */
- struct ctables_table *table;
- struct ctables_nest *nests[PIVOT_N_AXES];
-
- /* Data. */
- struct hmap *occurrences[PIVOT_N_AXES]; /* "struct ctables_occurrence"s. */
- struct hmap cells; /* Contains "struct ctables_cell"s. */
- struct hmap areas[N_CTATS]; /* Contains "struct ctables_area"s. */
- };
-
-static void ctables_section_uninit (struct ctables_section *);
-
-struct ctables_table
- {
- struct ctables *ctables;
- struct ctables_axis *axes[PIVOT_N_AXES];
- struct ctables_stack stacks[PIVOT_N_AXES];
- struct ctables_section *sections;
- size_t n_sections;
- enum pivot_axis_type summary_axis;
- struct ctables_summary_spec_set summary_specs;
- struct variable **sum_vars;
- size_t n_sum_vars;
-
- enum pivot_axis_type slabels_axis;
- bool slabels_visible;
-
- /* The innermost category labels for axis 'a' appear on axis label_axis[a].
-
- Most commonly, label_axis[a] == a, and in particular we always have
- label_axis{PIVOT_AXIS_LAYER] == PIVOT_AXIS_LAYER.
-
- If ROWLABELS or COLLABELS is specified, then one of
- label_axis[PIVOT_AXIS_ROW] or label_axis[PIVOT_AXIS_COLUMN] can be the
- opposite axis or PIVOT_AXIS_LAYER. Only one of them will differ.
-
- If any category labels are moved, then 'clabels_example' is one of the
- variables being moved (and it is otherwise NULL). All of the variables
- being moved have the same width, value labels, and categories, so this
- example variable can be used to find those out.
-
- The remaining members in this group are relevant only if category labels
- are moved.
-
- 'clabels_values_map' holds a "struct ctables_value" for all the values
- that appear in all of the variables in the moved categories. It is
- accumulated as the data is read. Once the data is fully read, its
- sorted values are put into 'clabels_values' and 'n_clabels_values'.
- */
- enum pivot_axis_type label_axis[PIVOT_N_AXES];
- enum pivot_axis_type clabels_from_axis;
- const struct variable *clabels_example;
- struct hmap clabels_values_map;
- struct ctables_value **clabels_values;
- size_t n_clabels_values;
-
- /* Indexed by variable dictionary index. */
- struct ctables_categories **categories;
- size_t n_categories;
-
- double cilevel;
-
- char *caption;
- char *corner;
- char *title;
-
- struct ctables_chisq *chisq;
- struct ctables_pairwise *pairwise;
- };
-
-struct ctables_categories
- {
- size_t n_refs;
- struct ctables_category *cats;
- size_t n_cats;
- bool show_empty;
- };
-
-struct ctables_category
- {
- enum ctables_category_type
- {
- /* Explicit category lists. */
- CCT_NUMBER,
- CCT_STRING,
- CCT_NRANGE, /* Numerical range. */
- CCT_SRANGE, /* String range. */
- CCT_MISSING,
- CCT_OTHERNM,
- CCT_POSTCOMPUTE,
-
- /* Totals and subtotals. */
- CCT_SUBTOTAL,
- CCT_TOTAL,
-
- /* Implicit category lists. */
- CCT_VALUE,
- CCT_LABEL,
- CCT_FUNCTION,
-
- /* For contributing to TOTALN. */
- CCT_EXCLUDED_MISSING,
- }
- type;
-
- struct ctables_category *subtotal;
-
- bool hide;
-
- union
- {
- double number; /* CCT_NUMBER. */
- struct substring string; /* CCT_STRING, in dictionary encoding. */
- double nrange[2]; /* CCT_NRANGE. */
- struct substring srange[2]; /* CCT_SRANGE. */
-
- struct
- {
- char *total_label; /* CCT_SUBTOTAL, CCT_TOTAL. */
- bool hide_subcategories; /* CCT_SUBTOTAL. */
- };
-
- /* CCT_POSTCOMPUTE. */
- struct
- {
- const struct ctables_postcompute *pc;
- enum fmt_type parse_format;
- };
-
- /* CCT_VALUE, CCT_LABEL, CCT_FUNCTION. */
- struct
- {
- bool include_missing;
- bool sort_ascending;
-
- /* CCT_FUNCTION. */
- enum ctables_summary_function sort_function;
- bool weighted;
- enum ctables_area_type area;
- struct variable *sort_var;
- double percentile;
- };
- };
-
- /* Source location. This is null for CCT_TOTAL, CCT_VALUE, CCT_LABEL,
- CCT_FUNCTION, CCT_EXCLUDED_MISSING. */
- struct msg_location *location;
- };
-
-static void
-ctables_category_uninit (struct ctables_category *cat)
-{
- if (!cat)
- return;
-
- msg_location_destroy (cat->location);
- switch (cat->type)
- {
- case CCT_NUMBER:
- case CCT_NRANGE:
- case CCT_MISSING:
- case CCT_OTHERNM:
- case CCT_POSTCOMPUTE:
- break;
-
- case CCT_STRING:
- ss_dealloc (&cat->string);
- break;
-
- case CCT_SRANGE:
- ss_dealloc (&cat->srange[0]);
- ss_dealloc (&cat->srange[1]);
- break;
-
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- free (cat->total_label);
- break;
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- break;
-
- case CCT_EXCLUDED_MISSING:
- break;
- }
-}
-
-static bool
-nullable_substring_equal (const struct substring *a,
- const struct substring *b)
-{
- return !a->string ? !b->string : b->string && ss_equals (*a, *b);
-}
-
-static bool
-ctables_category_equal (const struct ctables_category *a,
- const struct ctables_category *b)
-{
- if (a->type != b->type)
- return false;
-
- switch (a->type)
- {
- case CCT_NUMBER:
- return a->number == b->number;
-
- case CCT_STRING:
- return ss_equals (a->string, b->string);
-
- case CCT_NRANGE:
- return a->nrange[0] == b->nrange[0] && a->nrange[1] == b->nrange[1];
-
- case CCT_SRANGE:
- return (nullable_substring_equal (&a->srange[0], &b->srange[0])
- && nullable_substring_equal (&a->srange[1], &b->srange[1]));
-
- case CCT_MISSING:
- case CCT_OTHERNM:
- return true;
-
- case CCT_POSTCOMPUTE:
- return a->pc == b->pc;
-
- case CCT_SUBTOTAL:
- case CCT_TOTAL:
- return !strcmp (a->total_label, b->total_label);
-
- case CCT_VALUE:
- case CCT_LABEL:
- case CCT_FUNCTION:
- return (a->include_missing == b->include_missing
- && a->sort_ascending == b->sort_ascending
- && a->sort_function == b->sort_function
- && a->sort_var == b->sort_var
- && a->percentile == b->percentile);
-
- case CCT_EXCLUDED_MISSING:
- return true;
- }
-
- NOT_REACHED ();
-}
-
-static void
-ctables_categories_unref (struct ctables_categories *c)
-{
- if (!c)
- return;
-
- assert (c->n_refs > 0);
- if (--c->n_refs)
- return;
-
- for (size_t i = 0; i < c->n_cats; i++)
- ctables_category_uninit (&c->cats[i]);
- free (c->cats);
- free (c);
-}
-
-static bool
-ctables_categories_equal (const struct ctables_categories *a,
- const struct ctables_categories *b)
-{
- if (a->n_cats != b->n_cats || a->show_empty != b->show_empty)
- return false;
-
- for (size_t i = 0; i < a->n_cats; i++)
- if (!ctables_category_equal (&a->cats[i], &b->cats[i]))
- return false;
-
- return true;
-}
-
-/* Chi-square test (SIGTEST). */
-struct ctables_chisq
- {
- double alpha;
- bool include_mrsets;
- bool all_visible;
- };
-
-/* Pairwise comparison test (COMPARETEST). */
-struct ctables_pairwise
- {
- enum { PROP, MEAN } type;
- double alpha[2];
- bool include_mrsets;
- bool meansvariance_allcats;
- bool all_visible;
- enum { BONFERRONI = 1, BH } adjust;
- bool merge;
- bool apa_style;
- bool show_sig;
- };
-
-struct ctables_axis
- {
- enum ctables_axis_op
- {
- /* Terminals. */
- CTAO_VAR,
-
- /* Nonterminals. */
- CTAO_STACK, /* + */
- CTAO_NEST, /* > */
- }
- op;
-
- union
- {
- /* Terminals. */
- struct
- {
- struct variable *var;
- bool scale;
- struct ctables_summary_spec_set specs[N_CSVS];
- };
-
- /* Nonterminals. */
- struct ctables_axis *subs[2];
- };
-
- struct msg_location *loc;
- };
-
-static void ctables_axis_destroy (struct ctables_axis *);
-
-struct ctables_summary_spec
- {
- /* The calculation to be performed.
-
- 'function' is the function to calculate. 'weighted' specifies whether
- to use weighted or unweighted data (for functions that do not support a
- choice, it must be true). 'calc_area' is the area over which the
- calculation takes place (for functions that target only an individual
- cell, it must be 0). For CTSF_PTILE only, 'percentile' is the
- percentile between 0 and 100 (for other functions it must be 0). */
- enum ctables_summary_function function;
- bool weighted;
- enum ctables_area_type calc_area;
- double percentile; /* CTSF_PTILE only. */
-
- /* How to display the result of the calculation.
-
- 'label' is a user-specified label, NULL if the user didn't specify
- one.
-
- 'user_area' is usually the same as 'calc_area', but when category labels
- are rotated from one axis to another it swaps rows and columns.
-
- 'format' is the format for displaying the output. If
- 'is_ctables_format' is true, then 'format.type' is one of the special
- CTEF_* formats instead of the standard ones. */
- char *label;
- enum ctables_area_type user_area;
- struct fmt_spec format;
- bool is_ctables_format; /* Is 'format' one of CTEF_*? */
-
- size_t axis_idx;
- size_t sum_var_idx;
- };
-
-static void
-ctables_summary_spec_clone (struct ctables_summary_spec *dst,
- const struct ctables_summary_spec *src)
-{
- *dst = *src;
- dst->label = xstrdup_if_nonnull (src->label);
-}
-
-static void
-ctables_summary_spec_uninit (struct ctables_summary_spec *s)
-{
- if (s)
- free (s->label);
-}
-
-static void
-ctables_summary_spec_set_clone (struct ctables_summary_spec_set *dst,
- const struct ctables_summary_spec_set *src)
-{
- struct ctables_summary_spec *specs
- = (src->n ? xnmalloc (src->n, sizeof *specs) : NULL);
- for (size_t i = 0; i < src->n; i++)
- ctables_summary_spec_clone (&specs[i], &src->specs[i]);
-
- *dst = (struct ctables_summary_spec_set) {
- .specs = specs,
- .n = src->n,
- .allocated = src->n,
- .var = src->var,
- .is_scale = src->is_scale,
- };
-}
-
-static void
-ctables_summary_spec_set_uninit (struct ctables_summary_spec_set *set)
-{
- for (size_t i = 0; i < set->n; i++)
- ctables_summary_spec_uninit (&set->specs[i]);
- free (set->listwise_vars);
- free (set->specs);
-}
-
-static bool
-parse_col_width (struct lexer *lexer, const char *name, double *width)
-{
- lex_match (lexer, T_EQUALS);
- if (lex_match_id (lexer, "DEFAULT"))
- *width = SYSMIS;
- else if (lex_force_num_range_closed (lexer, name, 0, DBL_MAX))
- {
- *width = lex_number (lexer);
- lex_get (lexer);
- }
- else
- return false;
-
- return true;
-}
-
-static bool
-parse_bool (struct lexer *lexer, bool *b)
-{
- if (lex_match_id (lexer, "NO"))
- *b = false;
- else if (lex_match_id (lexer, "YES"))
- *b = true;
- else
- {
- lex_error_expecting (lexer, "YES", "NO");
- return false;
- }
- return true;
-}
-
-static enum ctables_function_availability
-ctables_function_availability (enum ctables_summary_function f)
-{
- static enum ctables_function_availability availability[] = {
-#define S(ENUM, NAME, TYPE, FORMAT, AVAILABILITY) [ENUM] = AVAILABILITY,
-#include "ctables.inc"
-#undef S
- };
-
- return availability[f];
-}
-
-static bool
-ctables_summary_function_is_count (enum ctables_summary_function f)
-{
- return f == CTSF_COUNT || f == CTSF_ECOUNT;
-}
-
-static bool
-parse_ctables_summary_function (struct lexer *lexer,
- enum ctables_summary_function *function,
- bool *weighted,
- enum ctables_area_type *area)
-{
- if (!lex_force_id (lexer))
- return false;
-
- struct substring name = lex_tokss (lexer);
- *weighted = !(ss_match_byte (&name, 'U') || ss_match_byte (&name, 'u'));
-
- bool has_area = false;
- *area = 0;
- for (enum ctables_area_type at = 0; at < N_CTATS; at++)
- if (ss_match_string_case (&name, ss_cstr (ctables_area_type_name[at])))
- {
- has_area = true;
- *area = at;
-
- if (ss_equals_case (name, ss_cstr ("PCT")))
- {
- /* Special case where .COUNT suffix is omitted. */
- *function = CTSF_areaPCT_COUNT;
- lex_get (lexer);
- return true;
- }
- break;
- }
-
- for (int f = 0; f < N_CTSF_FUNCTIONS; f++)
- {
- const struct ctables_function_info *cfi = &ctables_function_info[f];
- if (ss_equals_case (cfi->basename, name))
- {
- *function = f;
- if (!*weighted && !cfi->may_be_unweighted)
- break;
- if (has_area != cfi->is_area)
- break;
-
- lex_get (lexer);
- return true;
- }
- }
-
- lex_error (lexer, _("Expecting summary function name."));
- return false;
-}
-
-static void
-ctables_axis_destroy (struct ctables_axis *axis)
-{
- if (!axis)
- return;
-
- switch (axis->op)
- {
- case CTAO_VAR:
- for (size_t i = 0; i < N_CSVS; i++)
- ctables_summary_spec_set_uninit (&axis->specs[i]);
- break;
-
- case CTAO_STACK:
- case CTAO_NEST:
- ctables_axis_destroy (axis->subs[0]);
- ctables_axis_destroy (axis->subs[1]);
- break;
- }
- msg_location_destroy (axis->loc);
- free (axis);
-}
-
-static struct ctables_axis *
-ctables_axis_new_nonterminal (enum ctables_axis_op op,
- struct ctables_axis *sub0,
- struct ctables_axis *sub1,
- struct lexer *lexer, int start_ofs)
-{
- struct ctables_axis *axis = xmalloc (sizeof *axis);
- *axis = (struct ctables_axis) {
- .op = op,
- .subs = { sub0, sub1 },
- .loc = lex_ofs_location (lexer, start_ofs, lex_ofs (lexer) - 1),
- };
- return axis;
-}
-
-struct ctables_axis_parse_ctx
- {
- struct lexer *lexer;
- struct dictionary *dict;
- struct ctables *ct;
- struct ctables_table *t;
- };
-
-static struct fmt_spec
-ctables_summary_default_format (enum ctables_summary_function function,
- const struct variable *var)
-{
- static const enum ctables_format default_formats[] = {
-#define S(ENUM, NAME, TYPE, FORMAT, AVAILABILITY) [ENUM] = FORMAT,
-#include "ctables.inc"
-#undef S
- };
- switch (default_formats[function])
- {
- case CTF_COUNT:
- return (struct fmt_spec) { .type = FMT_F, .w = 40 };
-
- case CTF_PERCENT:
- return (struct fmt_spec) { .type = FMT_PCT, .w = 40, .d = 1 };
-
- case CTF_GENERAL:
- return *var_get_print_format (var);
-
- default:
- NOT_REACHED ();
- }
-}
-
-static const char *
-ctables_summary_label__ (const struct ctables_summary_spec *spec)
-{
- bool w = spec->weighted;
- enum ctables_area_type a = spec->user_area;
- switch (spec->function)
- {
- case CTSF_COUNT:
- return w ? N_("Count") : N_("Unweighted Count");
-
- case CTSF_ECOUNT:
- return N_("Adjusted Count");
-
- case CTSF_areaPCT_COUNT:
- switch (a)
- {
- case CTAT_TABLE: return w ? N_("Table %") : N_("Unweighted Table %");
- case CTAT_LAYER: return w ? N_("Layer %") : N_("Unweighted Layer %");
- case CTAT_LAYERROW: return w ? N_("Layer Row %") : N_("Unweighted Layer Row %");
- case CTAT_LAYERCOL: return w ? N_("Layer Column %") : N_("Unweighted Layer Column %");
- case CTAT_SUBTABLE: return w ? N_("Subtable %") : N_("Unweighted Subtable %");
- case CTAT_ROW: return w ? N_("Row %") : N_("Unweighted Row %");
- case CTAT_COL: return w ? N_("Column %") : N_("Unweighted Column %");
- }
- NOT_REACHED ();
-
- case CTSF_areaPCT_VALIDN:
- switch (a)
- {
- case CTAT_TABLE: return w ? N_("Table Valid N %") : N_("Unweighted Table Valid N %");
- case CTAT_LAYER: return w ? N_("Layer Valid N %") : N_("Unweighted Layer Valid N %");
- case CTAT_LAYERROW: return w ? N_("Layer Row Valid N %") : N_("Unweighted Layer Row Valid N %");
- case CTAT_LAYERCOL: return w ? N_("Layer Column Valid N %") : N_("Unweighted Layer Column Valid N %");
- case CTAT_SUBTABLE: return w ? N_("Subtable Valid N %") : N_("Unweighted Subtable Valid N %");
- case CTAT_ROW: return w ? N_("Row Valid N %") : N_("Unweighted Row Valid N %");
- case CTAT_COL: return w ? N_("Column Valid N %") : N_("Unweighted Column Valid N %");
- }
- NOT_REACHED ();
-
- case CTSF_areaPCT_TOTALN:
- switch (a)
- {
- case CTAT_TABLE: return w ? N_("Table Total N %") : N_("Unweighted Table Total N %");
- case CTAT_LAYER: return w ? N_("Layer Total N %") : N_("Unweighted Layer Total N %");
- case CTAT_LAYERROW: return w ? N_("Layer Row Total N %") : N_("Unweighted Layer Row Total N %");
- case CTAT_LAYERCOL: return w ? N_("Layer Column Total N %") : N_("Unweighted Layer Column Total N %");
- case CTAT_SUBTABLE: return w ? N_("Subtable Total N %") : N_("Unweighted Subtable Total N %");
- case CTAT_ROW: return w ? N_("Row Total N %") : N_("Unweighted Row Total N %");
- case CTAT_COL: return w ? N_("Column Total N %") : N_("Unweighted Column Total N %");
- }
- NOT_REACHED ();
-
- case CTSF_MAXIMUM: return N_("Maximum");
- case CTSF_MEAN: return w ? N_("Mean") : N_("Unweighted Mean");
- case CTSF_MEDIAN: return N_("Median");
- case CTSF_MINIMUM: return N_("Minimum");
- case CTSF_MISSING: return N_("Missing");
- case CTSF_MODE: return N_("Mode");
- case CTSF_PTILE: NOT_REACHED ();
- case CTSF_RANGE: return N_("Range");
- case CTSF_SEMEAN: return N_("Std Error of Mean");
- case CTSF_STDDEV: return N_("Std Deviation");
- case CTSF_SUM: return N_("Sum");
- case CTSF_TOTALN: return N_("Total N");
- case CTSF_ETOTALN: return N_("Adjusted Total N");
- case CTSF_VALIDN: return N_("Valid N");
- case CTSF_EVALIDN: return N_("Adjusted Valid N");
- case CTSF_VARIANCE: return N_("Variance");
- case CTSF_areaPCT_SUM:
- switch (a)
- {
- case CTAT_TABLE: return w ? N_("Table Sum %") : N_("Unweighted Table Sum %");
- case CTAT_LAYER: return w ? N_("Layer Sum %") : N_("Unweighted Layer Sum %");
- case CTAT_LAYERROW: return w ? N_("Layer Row Sum %") : N_("Unweighted Layer Row Sum %");
- case CTAT_LAYERCOL: return w ? N_("Layer Column Sum %") : N_("Unweighted Layer Column Sum %");
- case CTAT_SUBTABLE: return w ? N_("Subtable Sum %") : N_("Unweighted Subtable Sum %");
- case CTAT_ROW: return w ? N_("Row Sum %") : N_("Unweighted Row Sum %");
- case CTAT_COL: return w ? N_("Column Sum %") : N_("Unweighted Column Sum %");
- }
- NOT_REACHED ();
-
- case CTSF_areaID:
- switch (a)
- {
- /* Don't bother translating these: they are for developers only. */
- case CTAT_TABLE: return "Table ID";
- case CTAT_LAYER: return "Layer ID";
- case CTAT_LAYERROW: return "Layer Row ID";
- case CTAT_LAYERCOL: return "Layer Column ID";
- case CTAT_SUBTABLE: return "Subtable ID";
- case CTAT_ROW: return "Row ID";
- case CTAT_COL: return "Column ID";
- }
- NOT_REACHED ();
- }
-
- NOT_REACHED ();
-}
-
-static struct pivot_value *
-ctables_summary_label (const struct ctables_summary_spec *spec, double cilevel)
-{
- if (!spec->label)
- {
- if (spec->function == CTSF_PTILE)
- {
- double p = spec->percentile;
- char *s = (spec->weighted
- ? xasprintf (_("Percentile %.2f"), p)
- : xasprintf (_("Unweighted Percentile %.2f"), p));
- return pivot_value_new_user_text_nocopy (s);
- }
- else
- return pivot_value_new_text (ctables_summary_label__ (spec));
- }
- else
- {
- struct substring in = ss_cstr (spec->label);
- struct substring target = ss_cstr (")CILEVEL");
-
- struct string out = DS_EMPTY_INITIALIZER;
- for (;;)
- {
- size_t chunk = ss_find_substring (in, target);
- ds_put_substring (&out, ss_head (in, chunk));
- ss_advance (&in, chunk);
- if (!in.length)
- return pivot_value_new_user_text_nocopy (ds_steal_cstr (&out));
-
- ss_advance (&in, target.length);
- ds_put_format (&out, "%g", cilevel);
- }
- }
-}
-
-static const char *
-ctables_summary_function_name (enum ctables_summary_function function,
- bool weighted,
- enum ctables_area_type area,
- char *buffer, size_t bufsize)
-{
- const struct ctables_function_info *cfi = &ctables_function_info[function];
- snprintf (buffer, bufsize, "%s%s%s",
- weighted ? "" : "U",
- cfi->is_area ? ctables_area_type_name[area] : "",
- cfi->basename.string);
- return buffer;
-}
-
-static bool
-add_summary_spec (struct ctables_axis *axis,
- enum ctables_summary_function function, bool weighted,
- enum ctables_area_type area, double percentile,
- const char *label, const struct fmt_spec *format,
- bool is_ctables_format, const struct msg_location *loc,
- enum ctables_summary_variant sv)
-{
- if (axis->op == CTAO_VAR)
- {
- char function_name[128];
- ctables_summary_function_name (function, weighted, area,
- function_name, sizeof function_name);
- const char *var_name = var_get_name (axis->var);
- switch (ctables_function_availability (function))
- {
-#if 0
- case CTFA_MRSETS:
- msg_at (SE, loc, _("Summary function %s applies only to multiple "
- "response sets."), function_name);
- msg_at (SN, axis->loc, _("'%s' is not a multiple response set."),
- var_name);
- return false;
-#endif
-
- case CTFA_SCALE:
- if (!axis->scale && sv != CSV_TOTAL)
- {
- msg_at (SE, loc,
- _("Summary function %s applies only to scale variables."),
- function_name);
- msg_at (SN, axis->loc, _("'%s' is not a scale variable."),
- var_name);
- return false;
- }
- break;
-
- case CTFA_ALL:
- break;
- }
-
- struct ctables_summary_spec_set *set = &axis->specs[sv];
- if (set->n >= set->allocated)
- set->specs = x2nrealloc (set->specs, &set->allocated,
- sizeof *set->specs);
-
- struct ctables_summary_spec *dst = &set->specs[set->n++];
- *dst = (struct ctables_summary_spec) {
- .function = function,
- .weighted = weighted,
- .calc_area = area,
- .user_area = area,
- .percentile = percentile,
- .label = xstrdup_if_nonnull (label),
- .format = (format ? *format
- : ctables_summary_default_format (function, axis->var)),
- .is_ctables_format = is_ctables_format,
- };
- return true;
- }
- else
- {
- for (size_t i = 0; i < 2; i++)
- if (!add_summary_spec (axis->subs[i], function, weighted, area,
- percentile, label, format, is_ctables_format,
- loc, sv))
- return false;
- return true;
- }
-}
-
-static struct ctables_axis *ctables_axis_parse_stack (
- struct ctables_axis_parse_ctx *);