X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fdictionary.c;h=427cae3669eb695ef282650965ebb5df0ca4cb23;hb=a49b940e58f148bf111c647d9b4822025636ff80;hp=0b930d579c3defc7ec19dc0b81de6bb10a07b3d9;hpb=7bf210c4fd179a22dd8c6a071f0b23f7ae4e14c2;p=pspp diff --git a/src/data/dictionary.c b/src/data/dictionary.c index 0b930d579c..427cae3669 100644 --- a/src/data/dictionary.c +++ b/src/data/dictionary.c @@ -55,6 +55,7 @@ /* A dictionary. */ struct dictionary { + int ref_cnt; struct vardict_info *var; /* Variables. */ size_t var_cnt, var_cap; /* Number of variables, capacity. */ struct caseproto *proto; /* Prototype for dictionary cases @@ -74,6 +75,11 @@ struct dictionary struct mrset **mrsets; /* Multiple response sets. */ size_t n_mrsets; /* Number of multiple response sets. */ + /* Whether variable names must be valid identifiers. Normally, this is + true, but sometimes a dictionary is prepared for external use + (e.g. output to a CSV file) where names don't have to be valid. */ + bool names_must_be_ids; + char *encoding; /* Character encoding of string data */ const struct dict_callbacks *callbacks; /* Callbacks on dictionary @@ -102,7 +108,8 @@ bool dict_id_is_valid (const struct dictionary *dict, const char *id, bool issue_error) { - return id_is_valid (id, dict->encoding, issue_error); + return (!dict->names_must_be_ids + || id_is_valid (id, dict->encoding, issue_error)); } void @@ -170,12 +177,21 @@ dict_create (const char *encoding) struct dictionary *d = xzalloc (sizeof *d); d->encoding = xstrdup (encoding); + d->names_must_be_ids = true; hmap_init (&d->name_map); attrset_init (&d->attributes); + d->ref_cnt = 1; return d; } +struct dictionary * +dict_ref (struct dictionary *s) +{ + s->ref_cnt++; + return s; +} + /* Creates and returns a (deep) copy of an existing dictionary. @@ -193,6 +209,7 @@ dict_clone (const struct dictionary *s) size_t i; d = dict_create (s->encoding); + dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s)); for (i = 0; i < s->var_cnt; i++) { @@ -211,7 +228,7 @@ dict_clone (const struct dictionary *s) d->split_cnt = s->split_cnt; if (d->split_cnt > 0) { - d->split = xnmalloc (d->split_cnt, sizeof *d->split); + d->split = xnmalloc (d->split_cnt, sizeof *d->split); for (i = 0; i < d->split_cnt; i++) d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i])); } @@ -280,23 +297,31 @@ dict_clear (struct dictionary *d) } /* Clears a dictionary and destroys it. */ +static void +_dict_destroy (struct dictionary *d) +{ + /* In general, we don't want callbacks occurring, if the dictionary + is being destroyed */ + d->callbacks = NULL ; + + dict_clear (d); + string_array_destroy (&d->documents); + hmap_destroy (&d->name_map); + attrset_destroy (&d->attributes); + dict_clear_mrsets (d); + free (d->encoding); + free (d); +} + void -dict_destroy (struct dictionary *d) +dict_unref (struct dictionary *d) { - if (d != NULL) - { - /* In general, we don't want callbacks occurring, if the dictionary - is being destroyed */ - d->callbacks = NULL ; - - dict_clear (d); - string_array_destroy (&d->documents); - hmap_destroy (&d->name_map); - attrset_destroy (&d->attributes); - dict_clear_mrsets (d); - free (d->encoding); - free (d); - } + if (d == NULL) + return; + d->ref_cnt--; + assert (d->ref_cnt >= 0); + if (d->ref_cnt == 0) + _dict_destroy (d); } /* Returns the number of variables in D. */ @@ -994,6 +1019,27 @@ dict_make_unique_var_name (const struct dictionary *dict, const char *hint, return make_numeric_name (dict, num_start); } +/* Returns whether variable names must be valid identifiers. Normally, this is + true, but sometimes a dictionary is prepared for external use (e.g. output + to a CSV file) where names don't have to be valid. */ +bool +dict_get_names_must_be_ids (const struct dictionary *d) +{ + return d->names_must_be_ids; +} + +/* Sets whether variable names must be valid identifiers. Normally, this is + true, but sometimes a dictionary is prepared for external use (e.g. output + to a CSV file) where names don't have to be valid. + + Changing this setting from false to true doesn't make the dictionary check + all the existing variable names, so it can cause an invariant violation. */ +void +dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids) +{ + d->names_must_be_ids = names_must_be_ids; +} + /* Returns the weighting variable in dictionary D, or a null pointer if the dictionary is unweighted. */ struct variable * @@ -1026,6 +1072,13 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c, } } +/* Returns the format to use for weights. */ +const struct fmt_spec * +dict_get_weight_format (const struct dictionary *d) +{ + return d->weight ? var_get_print_format (d->weight) : &F_8_0; +} + /* Sets the weighting variable of D to V, or turning off weighting if V is a null pointer. */ void @@ -1061,6 +1114,22 @@ dict_set_filter (struct dictionary *d, struct variable *v) assert (v == NULL || dict_contains_var (d, v)); assert (v == NULL || var_is_numeric (v)); + /* When a filter is set, we ref the dictionary. + This is because the GUI maintains a pointer + to the dict's variables, and the variables' + addresses change in the callback. */ + if (d->filter == NULL && v != NULL) + { + d = dict_ref (d); + } + + /* Deref the dict when a filter is removed. */ + if (d->filter != NULL && v == NULL) + { + assert (d->ref_cnt > 0); + dict_unref (d); + } + d->filter = v; if (d->changed) d->changed (d, d->changed_data); @@ -1674,7 +1743,7 @@ dict_destroy_internal_var (struct variable *var) valgrind --leak-check --show-reachable won't show internal_dict. */ if (dict_get_var_cnt (internal_dict) == 0) { - dict_destroy (internal_dict); + dict_unref (internal_dict); internal_dict = NULL; } }