From: Ben Pfaff Date: Sat, 15 Jan 2022 21:35:13 +0000 (-0800) Subject: check label positions for =OPPOSITE or =LAYER X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=9b58626a87f13d1835e56fccf65e98bcc248e107 check label positions for =OPPOSITE or =LAYER --- diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 8ced195ee3..0ce4a333e9 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -22,6 +22,7 @@ #include "data/dataset.h" #include "data/dictionary.h" #include "data/mrset.h" +#include "data/value-labels.h" #include "language/command.h" #include "language/lexer/format-parser.h" #include "language/lexer/lexer.h" @@ -284,6 +285,19 @@ enum ctables_label_position CTLP_LAYER, }; +static const char * +ctables_label_position_to_string (enum ctables_label_position p) +{ + switch (p) + { + case CTLP_NORMAL: return "NORMAL"; + case CTLP_OPPOSITE: return "OPPOSITE"; + case CTLP_LAYER: return "LAYER"; + } + + NOT_REACHED (); +} + struct ctables_summary_spec_set { struct ctables_summary_spec *specs; @@ -451,6 +465,46 @@ ctables_category_uninit (struct ctables_category *cat) } } +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 strcmp (a->string, b->string); + + case CCT_RANGE: + return a->range[0] == b->range[0] && a->range[1] == b->range[1]; + + case CCT_MISSING: + case CCT_OTHERNM: + return true; + + case CCT_SUBTOTAL: + case CCT_HSUBTOTAL: + 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); + } + + NOT_REACHED (); +} + static void ctables_categories_unref (struct ctables_categories *c) { @@ -467,6 +521,20 @@ ctables_categories_unref (struct ctables_categories *c) 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 { @@ -2973,6 +3041,73 @@ ctables_execute (struct dataset *ds, struct ctables *ct) return proc_commit (ds); } +static bool +ctables_check_label_position (struct ctables_table *t, + enum pivot_axis_type axis, + enum ctables_label_position label_pos, + const char *subcommand_name) +{ + if (label_pos == CTLP_NORMAL) + return true; + + const struct ctables_stack *stack = &t->stacks[axis]; + if (!stack->n) + return true; + + const struct ctables_nest *n0 = &stack->nests[0]; + const struct variable *v0 = n0->vars[n0->n - 1]; + struct ctables_categories *c0 = t->categories[var_get_dict_index (v0)]; + + for (size_t i = 0; i < c0->n_cats; i++) + if (c0->cats[i].type == CCT_FUNCTION) + { + msg (SE, _("%s=%s is not allowed with sorting based " + "on a summary function."), + subcommand_name, ctables_label_position_to_string (label_pos)); + return false; + } + + for (size_t i = 1; i < stack->n; i++) + { + const struct ctables_nest *ni = &stack->nests[i]; + const struct variable *vi = ni->vars[ni->n - 1]; + struct ctables_categories *ci = t->categories[var_get_dict_index (vi)]; + + if (var_get_width (v0) != var_get_width (vi)) + { + msg (SE, _("%s=%s requires the variables to be " + "moved to have the same width, but %s has " + "width %d and %s has width %d."), + subcommand_name, ctables_label_position_to_string (label_pos), + var_get_name (v0), var_get_width (v0), + var_get_name (vi), var_get_width (vi)); + return false; + } + if (!val_labs_equal (var_get_value_labels (v0), + var_get_value_labels (vi))) + { + msg (SE, _("%s=%s requires the variables to be " + "moved to have the same value labels, but %s " + "and %s have different value labels."), + subcommand_name, ctables_label_position_to_string (label_pos), + var_get_name (v0), var_get_name (vi)); + return false; + } + if (!ctables_categories_equal (c0, ci)) + { + msg (SE, _("%s=%s requires the variables to be " + "moved to have the same category " + "specifications, but %s and %s have different " + "category specifications."), + subcommand_name, ctables_label_position_to_string (label_pos), + var_get_name (v0), var_get_name (vi)); + return false; + } + } + + return true; +} + int cmd_ctables (struct lexer *lexer, struct dataset *ds) { @@ -3645,7 +3780,10 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) ctables_prepare_table (t); - + ctables_check_label_position (t, PIVOT_AXIS_ROW, t->row_labels, + "ROWLABELS"); + ctables_check_label_position (t, PIVOT_AXIS_COLUMN, t->col_labels, + "COLLABELS"); } while (lex_token (lexer) != T_ENDCMD);