X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fpivot-table.c;h=93dc74c2d86e8299cbbe3e03e2d6de8a790ef799;hb=c4bc3574d974d3aaf4d291097c995a31515a308a;hp=1e7d2fbb5ac6b72308f54ace365ade5c4a6053f9;hpb=1edfb965b2d68da0b46f34ec78222d129dc12782;p=pspp diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c index 1e7d2fbb5a..93dc74c2d8 100644 --- a/src/output/pivot-table.c +++ b/src/output/pivot-table.c @@ -2374,8 +2374,15 @@ get_text_from_markup (const char *markup, struct string *out) xmlFreeParserCtxt (parser); } -/* Appends a text representation of the body of VALUE to OUT. Settings on - PT control whether variable and value labels are included. +static const struct pivot_table pivot_value_format_defaults = { + .show_values = SETTINGS_VALUE_SHOW_DEFAULT, + .show_variables = SETTINGS_VALUE_SHOW_DEFAULT, + .settings = FMT_SETTINGS_INIT, +}; + +/* Appends a text representation of the body of VALUE to OUT. Settings on PT + control whether variable and value labels are included (pass NULL for PT to + get default formatting in the absence of a pivot table). The "body" omits subscripts and superscripts and footnotes. @@ -2383,9 +2390,10 @@ get_text_from_markup (const char *markup, struct string *out) otherwise. */ bool pivot_value_format_body (const struct pivot_value *value, - const struct pivot_table *pt, + const struct pivot_table *pt_, struct string *out) { + const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults; enum settings_value_show show; bool numeric = false; @@ -2476,8 +2484,9 @@ pivot_value_format_body (const struct pivot_value *value, return numeric; } -/* Appends a text representation of VALUE to OUT. Settings on - PT control whether variable and value labels are included. +/* Appends a text representation of VALUE to OUT. Settings on PT control + whether variable and value labels are included (pass NULL for PT to get + default formatting in the absence of a pivot table). Subscripts and footnotes are included. @@ -2485,9 +2494,10 @@ pivot_value_format_body (const struct pivot_value *value, otherwise. */ bool pivot_value_format (const struct pivot_value *value, - const struct pivot_table *pt, + const struct pivot_table *pt_, struct string *out) { + const struct pivot_table *pt = pt_ ? pt_ : &pivot_value_format_defaults; bool numeric = pivot_value_format_body (value, pt, out); const struct pivot_value_ex *ex = value->ex; @@ -2515,7 +2525,9 @@ pivot_value_format (const struct pivot_value *value, } /* Returns a text representation of VALUE. The caller must free the string, - with free(). */ + with free(). Settings on PT control whether variable and value labels are + included (pass NULL for PT to get default formatting in the absence of a + pivot table). */ char * pivot_value_to_string (const struct pivot_value *value, const struct pivot_table *pt) @@ -2525,17 +2537,6 @@ pivot_value_to_string (const struct pivot_value *value, return ds_steal_cstr (&s); } -char * -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); -} - struct pivot_value * pivot_value_clone (const struct pivot_value *old) { @@ -3043,21 +3044,37 @@ struct pivot_splits_value struct pivot_splits_var { struct pivot_dimension *dimension; + const struct variable *var; int width; - size_t idx; - struct fmt_spec format; struct hmap values; }; +struct pivot_splits_dup + { + struct hmap_node hmap_node; + union value *values; + }; + struct pivot_splits { struct pivot_splits_var *vars; size_t n; char *encoding; + struct hmap dups; + size_t dindexes[MAX_SPLITS]; + + int warnings_left; }; +/* Adds a dimension for each layered split file variable in DICT to PT on AXIS. + These dimensions should be the last dimensions added to PT (the + pivot_splits_put*() functions rely on this). Returns a new pivot_splits + structure if any dimensions were added, otherwise a null pointer. + + See the large comment on split file handling in pivot-table.h for more + information. */ struct pivot_splits * pivot_splits_create (struct pivot_table *pt, enum pivot_axis_type axis, @@ -3071,7 +3088,7 @@ pivot_splits_create (struct pivot_table *pt, const struct variable *const *vars = dict_get_split_vars (dict); struct pivot_splits_var *psvars = xnmalloc (n, sizeof *psvars); - for (size_t i = 0; i < n; i++) + for (size_t i = n - 1; i < n; i--) { const struct variable *var = vars[i]; struct pivot_splits_var *psvar = &psvars[i]; @@ -3082,10 +3099,9 @@ pivot_splits_create (struct pivot_table *pt, *psvar = (struct pivot_splits_var) { .width = var_get_width (var), - .idx = var_get_case_index (var), - .format = *var_get_print_format (var), .values = HMAP_INITIALIZER (psvar->values), .dimension = d, + .var = var, }; } @@ -3094,17 +3110,38 @@ pivot_splits_create (struct pivot_table *pt, .vars = psvars, .n = n, .encoding = xstrdup (dict_get_encoding (dict)), + .dups = HMAP_INITIALIZER (ps->dups), .dindexes = { [0] = SIZE_MAX }, + .warnings_left = 5, }; return ps; } +/* Destroys PS. */ void pivot_splits_destroy (struct pivot_splits *ps) { if (!ps) return; + if (ps->warnings_left < 0) + msg (SW, ngettext ("Suppressed %d additional warning about duplicate " + "split values.", + "Suppressed %d additional warnings about duplicate " + "split values.", -ps->warnings_left), + -ps->warnings_left); + + struct pivot_splits_dup *dup, *next_dup; + HMAP_FOR_EACH_SAFE (dup, next_dup, struct pivot_splits_dup, hmap_node, + &ps->dups) + { + for (size_t i = 0; i < ps->n; i++) + value_destroy (&dup->values[i], ps->vars[i].width); + free (dup->values); + free (dup); + } + hmap_destroy (&ps->dups); + for (size_t i = 0; i < ps->n; i++) { struct pivot_splits_var *psvar = &ps->vars[i]; @@ -3119,6 +3156,7 @@ pivot_splits_destroy (struct pivot_splits *ps) hmap_destroy (&psvar->values); } free (ps->vars); + free (ps->encoding); free (ps); } @@ -3135,16 +3173,62 @@ pivot_splits_value_find (struct pivot_splits_var *psvar, return NULL; } +static bool +pivot_splits_find_dup (struct pivot_splits *ps, const struct ccase *example) +{ + unsigned int hash = 0; + for (size_t i = 0; i < ps->n; i++) + { + struct pivot_splits_var *psvar = &ps->vars[i]; + const union value *value = case_data (example, psvar->var); + hash = value_hash (value, psvar->width, hash); + } + struct pivot_splits_dup *dup; + HMAP_FOR_EACH_WITH_HASH (dup, struct pivot_splits_dup, hmap_node, hash, + &ps->dups) + { + bool equal = true; + for (size_t i = 0; i < ps->n && equal; i++) + { + struct pivot_splits_var *psvar = &ps->vars[i]; + const union value *value = case_data (example, psvar->var); + equal = value_equal (value, &dup->values[i], psvar->width); + } + if (equal) + return true; + } + + union value *values = xmalloc (ps->n * sizeof *values); + for (size_t i = 0; i < ps->n; i++) + { + struct pivot_splits_var *psvar = &ps->vars[i]; + const union value *value = case_data (example, psvar->var); + value_clone (&values[i], value, psvar->width); + } + + dup = xmalloc (sizeof *dup); + dup->values = values; + hmap_insert (&ps->dups, &dup->hmap_node, hash); + return false; +} + +/* Begins adding data for a new split file group to the pivot table associated + with PS. EXAMPLE should be a case from the new split file group. + + This is a no-op if PS is NULL. + + See the large comment on split file handling in pivot-table.h for more + information. */ void -pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *c) +pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *example) { if (!ps) return; - for (size_t i = ps->n - 1; i < ps->n; i--) + for (size_t i = 0; i < ps->n; i++) { struct pivot_splits_var *psvar = &ps->vars[i]; - const union value *value = case_data_idx (c, psvar->idx); + const union value *value = case_data (example, psvar->var); struct pivot_splits_value *psval = pivot_splits_value_find (psvar, value); if (!psval) { @@ -3154,15 +3238,50 @@ pivot_splits_new_split (struct pivot_splits *ps, const struct ccase *c) value_clone (&psval->value, value, psvar->width); psval->leaf = pivot_category_create_leaf ( psvar->dimension->root, - pivot_value_new_value (value, psvar->width, &psvar->format, - ps->encoding)); + pivot_value_new_var_value (psvar->var, value)); } ps->dindexes[i] = psval->leaf; } + + if (pivot_splits_find_dup (ps, example)) + { + if (ps->warnings_left-- > 0) + { + struct string s = DS_EMPTY_INITIALIZER; + for (size_t i = 0; i < ps->n; i++) + { + if (i > 0) + ds_put_cstr (&s, ", "); + + struct pivot_splits_var *psvar = &ps->vars[i]; + const union value *value = case_data (example, psvar->var); + ds_put_format (&s, "%s = ", var_get_name (psvar->var)); + + char *s2 = data_out (value, ps->encoding, + var_get_print_format (psvar->var), + settings_get_fmt_settings ()); + ds_put_cstr (&s, s2 + strspn (s2, " ")); + free (s2); + } + msg (SW, _("When SPLIT FILE is in effect, the input data must be " + "sorted by the split variables (for example, using SORT " + "CASES), but multiple runs of cases with the same split " + "values were found separated by cases with different " + "values. Each run will be analyzed separately. The " + "duplicate split values are: %s"), ds_cstr (&s)); + ds_destroy (&s); + } + + struct pivot_splits_var *psvar = &ps->vars[0]; + const union value *value = case_data (example, psvar->var); + ps->dindexes[0] = pivot_category_create_leaf ( + psvar->dimension->root, + pivot_value_new_var_value (psvar->var, value)); + } } -size_t +static size_t pivot_splits_get_dindexes (const struct pivot_splits *ps, size_t *dindexes) { if (!ps) @@ -3170,10 +3289,16 @@ pivot_splits_get_dindexes (const struct pivot_splits *ps, size_t *dindexes) assert (ps->dindexes[0] != SIZE_MAX); for (size_t i = 0; i < ps->n; i++) - dindexes[i] = ps->dindexes[i]; + dindexes[ps->n - i - 1] = ps->dindexes[i]; return ps->n; } +/* Puts VALUE in the cell in TABLE with index IDX1. TABLE must have 1 + dimension plus the split file dimensions from PS (if nonnull). Takes + ownership of VALUE. + + See the large comment on split file handling in pivot-table.h for more + information. */ void pivot_splits_put1 (struct pivot_splits *ps, struct pivot_table *table, size_t idx1, struct pivot_value *value) @@ -3185,6 +3310,12 @@ pivot_splits_put1 (struct pivot_splits *ps, struct pivot_table *table, pivot_table_put (table, dindexes, p - dindexes, value); } +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2). TABLE must have 2 + dimensions plus the split file dimensions from PS (if nonnull). Takes + ownership of VALUE. + + See the large comment on split file handling in pivot-table.h for more + information. */ void pivot_splits_put2 (struct pivot_splits *ps, struct pivot_table *table, size_t idx1, size_t idx2, struct pivot_value *value) @@ -3197,6 +3328,12 @@ pivot_splits_put2 (struct pivot_splits *ps, struct pivot_table *table, pivot_table_put (table, dindexes, p - dindexes, value); } +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3). TABLE must + have 3 dimensions plus the split file dimensions from PS (if nonnull). + Takes ownership of VALUE. + + See the large comment on split file handling in pivot-table.h for more + information. */ void pivot_splits_put3 (struct pivot_splits *ps, struct pivot_table *table, size_t idx1, size_t idx2, size_t idx3, @@ -3211,6 +3348,12 @@ pivot_splits_put3 (struct pivot_splits *ps, struct pivot_table *table, pivot_table_put (table, dindexes, p - dindexes, value); } +/* Puts VALUE in the cell in TABLE with index (IDX1, IDX2, IDX3, IDX4). TABLE + must have 4 dimensions plus the split file dimensions from PS (if nonnull). + Takes ownership of VALUE. + + See the large comment on split file handling in pivot-table.h for more + information. */ void pivot_splits_put4 (struct pivot_splits *ps, struct pivot_table *table, size_t idx1, size_t idx2, size_t idx3, size_t idx4,