1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014,
3 2015, 2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "data/dictionary.h"
27 #include "data/attributes.h"
28 #include "data/case.h"
29 #include "data/identifier.h"
30 #include "data/mrset.h"
31 #include "data/settings.h"
32 #include "data/value-labels.h"
33 #include "data/vardict.h"
34 #include "data/variable.h"
35 #include "data/vector.h"
36 #include "libpspp/array.h"
37 #include "libpspp/assertion.h"
38 #include "libpspp/compiler.h"
39 #include "libpspp/hash-functions.h"
40 #include "libpspp/hmap.h"
41 #include "libpspp/i18n.h"
42 #include "libpspp/message.h"
43 #include "libpspp/misc.h"
44 #include "libpspp/pool.h"
45 #include "libpspp/str.h"
46 #include "libpspp/string-array.h"
47 #include "libpspp/ll.h"
49 #include "gl/intprops.h"
50 #include "gl/minmax.h"
51 #include "gl/xalloc.h"
52 #include "gl/xmemdup0.h"
55 #define _(msgid) gettext (msgid)
61 struct vardict_info *vars; /* Variables. */
62 size_t n_vars; /* Number of variables. */
63 size_t allocated_vars; /* Allocated space in 'vars'. */
64 struct caseproto *proto; /* Prototype for dictionary cases
66 struct hmap name_map; /* Variable index by name. */
67 int next_value_idx; /* Index of next `union value' to allocate. */
68 const struct variable **split; /* SPLIT FILE vars. */
69 size_t n_splits; /* SPLIT FILE count. */
70 enum split_type split_type;
71 struct variable *weight; /* WEIGHT variable. */
72 struct variable *filter; /* FILTER variable. */
73 casenumber case_limit; /* Current case limit (N command). */
74 char *label; /* File label. */
75 struct string_array documents; /* Documents. */
76 struct vector **vector; /* Vectors of variables. */
77 size_t n_vectors; /* Number of vectors. */
78 struct attrset attributes; /* Custom attributes. */
79 struct mrset **mrsets; /* Multiple response sets. */
80 size_t n_mrsets; /* Number of multiple response sets. */
82 /* Whether variable names must be valid identifiers. Normally, this is
83 true, but sometimes a dictionary is prepared for external use
84 (e.g. output to a CSV file) where names don't have to be valid. */
85 bool names_must_be_ids;
87 char *encoding; /* Character encoding of string data */
89 const struct dict_callbacks *callbacks; /* Callbacks on dictionary
91 void *cb_data ; /* Data passed to callbacks */
93 void (*changed) (struct dictionary *, void *); /* Generic change callback */
97 static void dict_unset_split_var (struct dictionary *, struct variable *, bool);
98 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
100 /* Compares two double pointers to variables, which should point
101 to elements of a struct dictionary's `var' member array. */
103 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
105 struct variable *const *a = a_;
106 struct variable *const *b = b_;
108 return *a < *b ? -1 : *a > *b;
112 unindex_var (struct dictionary *d, struct vardict_info *vardict)
114 hmap_delete (&d->name_map, &vardict->name_node);
117 /* This function assumes that vardict->name_node.hash is valid, that is, that
118 its name has not changed since it was hashed (rename_var() updates this
119 hash along with the name itself). */
121 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
123 struct variable *old = (d->callbacks && d->callbacks->var_changed
124 ? var_clone (vardict->var)
127 struct variable *var = vardict->var;
128 var_set_vardict (var, vardict);
129 hmap_insert_fast (&d->name_map, &vardict->name_node,
130 vardict->name_node.hash);
132 if (! skip_callbacks)
134 if (d->changed) d->changed (d, d->changed_data);
137 d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
143 /* Sets the case_index in V's vardict to CASE_INDEX. */
145 set_var_case_index (struct variable *v, int case_index)
147 var_get_vardict (v)->case_index = case_index;
150 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
153 unindex_vars (struct dictionary *d, size_t from, size_t to)
157 for (i = from; i < to; i++)
158 unindex_var (d, &d->vars[i]);
161 /* Re-sets the dict_index in the dictionary variables with
162 indexes from FROM to TO (exclusive). */
164 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
168 for (i = from; i < to; i++)
169 reindex_var (d, &d->vars[i], skip_callbacks);
174 /* Returns the encoding for data in dictionary D. The return value is a
175 nonnull string that contains an IANA character set name. */
177 dict_get_encoding (const struct dictionary *d)
182 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
183 encoding, false otherwise. If ISSUE_ERROR is true, issues an explanatory
184 error message on failure. */
186 dict_id_is_valid (const struct dictionary *dict, const char *id,
189 return (!dict->names_must_be_ids
190 || id_is_valid (id, dict->encoding, issue_error));
194 dict_set_change_callback (struct dictionary *d,
195 void (*changed) (struct dictionary *, void*),
198 d->changed = changed;
199 d->changed_data = data;
202 /* Discards dictionary D's caseproto. (It will be regenerated
203 lazily, on demand.) */
205 invalidate_proto (struct dictionary *d)
207 caseproto_unref (d->proto);
211 /* Print a representation of dictionary D to stdout, for
212 debugging purposes. */
214 dict_dump (const struct dictionary *d)
217 for (i = 0 ; i < d->n_vars ; ++i)
219 const struct variable *v = d->vars[i].var;
220 printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
222 var_get_dict_index (v),
223 var_get_case_index (v));
228 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
229 the dictionary or any of the variables it contains are modified.
230 Each callback will get passed CALLBACK_DATA.
231 Any callback may be NULL, in which case it'll be ignored.
234 dict_set_callbacks (struct dictionary *dict,
235 const struct dict_callbacks *callbacks,
238 dict->callbacks = callbacks;
239 dict->cb_data = callback_data;
242 /* Shallow copy the callbacks from SRC to DEST */
244 dict_copy_callbacks (struct dictionary *dest,
245 const struct dictionary *src)
247 dest->callbacks = src->callbacks;
248 dest->cb_data = src->cb_data;
251 /* Creates and returns a new dictionary with the specified ENCODING. */
253 dict_create (const char *encoding)
255 struct dictionary *d = xmalloc (sizeof *d);
257 *d = (struct dictionary) {
258 .encoding = xstrdup (encoding),
259 .names_must_be_ids = true,
260 .name_map = HMAP_INITIALIZER (d->name_map),
261 .attributes = ATTRSET_INITIALIZER (d->attributes),
262 .split_type = SPLIT_NONE,
269 /* Creates and returns a (deep) copy of an existing
272 The new dictionary's case indexes are copied from the old
273 dictionary. If the new dictionary won't be used to access
274 cases produced with the old dictionary, then the new
275 dictionary's case indexes should be compacted with
276 dict_compact_values to save space.
278 Callbacks are not cloned. */
280 dict_clone (const struct dictionary *s)
282 struct dictionary *d;
285 d = dict_create (s->encoding);
286 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
288 for (i = 0; i < s->n_vars; i++)
290 struct variable *sv = s->vars[i].var;
291 struct variable *dv = dict_clone_var_assert (d, sv);
294 for (i = 0; i < var_get_n_short_names (sv); i++)
295 var_set_short_name (dv, i, var_get_short_name (sv, i));
297 var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
300 d->next_value_idx = s->next_value_idx;
302 d->n_splits = s->n_splits;
305 d->split = xnmalloc (d->n_splits, sizeof *d->split);
306 for (i = 0; i < d->n_splits; i++)
307 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
309 d->split_type = s->split_type;
311 if (s->weight != NULL)
312 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
314 if (s->filter != NULL)
315 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
317 d->case_limit = s->case_limit;
318 dict_set_label (d, dict_get_label (s));
319 dict_set_documents (d, dict_get_documents (s));
321 d->n_vectors = s->n_vectors;
322 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
323 for (i = 0; i < s->n_vectors; i++)
324 d->vector[i] = vector_clone (s->vector[i], s, d);
326 dict_set_attributes (d, dict_get_attributes (s));
328 for (i = 0; i < s->n_mrsets; i++)
330 const struct mrset *old = s->mrsets[i];
334 /* Clone old mrset, then replace vars from D by vars from S. */
335 new = mrset_clone (old);
336 for (j = 0; j < new->n_vars; j++)
337 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
339 dict_add_mrset (d, new);
347 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
348 dict_get_n_splits() to determine how many SPLIT FILE vars
349 there are. Returns a null pointer if and only if there are no
351 const struct variable *const *
352 dict_get_split_vars (const struct dictionary *d)
357 /* Returns the number of SPLIT FILE vars. */
359 dict_get_n_splits (const struct dictionary *d)
364 /* Removes variable V, which must be in D, from D's set of split
367 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
371 assert (dict_contains_var (d, v));
373 orig_count = d->n_splits;
374 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
375 &v, compare_var_ptrs, NULL);
376 if (orig_count != d->n_splits && !skip_callbacks)
378 if (d->changed) d->changed (d, d->changed_data);
379 /* We changed the set of split variables so invoke the
381 if (d->callbacks && d->callbacks->split_changed)
382 d->callbacks->split_changed (d, d->cb_data);
387 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
390 dict_set_split_vars__ (struct dictionary *d,
391 struct variable *const *split, size_t n,
392 enum split_type type, bool skip_callbacks)
396 assert (n == 0 || split != NULL);
399 d->split_type = type == SPLIT_NONE ? SPLIT_LAYERED : type;
402 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
403 memcpy (d->split, split, n * sizeof *d->split);
413 if (d->changed) d->changed (d, d->changed_data);
414 if (d->callbacks && d->callbacks->split_changed)
415 d->callbacks->split_changed (d, d->cb_data);
419 /* Sets N split vars SPLIT in dictionary D. */
421 dict_set_split_vars (struct dictionary *d,
422 struct variable *const *split, size_t n,
423 enum split_type type)
425 dict_set_split_vars__ (d, split, n, type, false);
429 dict_clear_split_vars (struct dictionary *d)
431 dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
435 /* Deletes variable V from dictionary D and frees V.
437 This is a very bad idea if there might be any pointers to V
438 from outside D. In general, no variable in the active dataset's
439 dictionary should be deleted when any transformations are
440 active on the dictionary's dataset, because those
441 transformations might reference the deleted variable. The
442 safest time to delete a variable is just after a procedure has
443 been executed, as done by DELETE VARIABLES.
445 Pointers to V within D are not a problem, because
446 dict_delete_var() knows to remove V from split variables,
447 weights, filters, etc. */
449 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
451 int dict_index = var_get_dict_index (v);
452 const int case_index = var_get_case_index (v);
454 assert (dict_contains_var (d, v));
456 dict_unset_split_var (d, v, skip_callbacks);
457 dict_unset_mrset_var (d, v);
460 dict_set_weight (d, NULL);
463 dict_set_filter (d, NULL);
465 dict_clear_vectors (d);
467 /* Remove V from var array. */
468 unindex_vars (d, dict_index, d->n_vars);
469 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
472 /* Update dict_index for each affected variable. */
473 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
476 var_clear_vardict (v);
478 if (! skip_callbacks)
480 if (d->changed) d->changed (d, d->changed_data);
481 if (d->callbacks && d->callbacks->var_deleted)
482 d->callbacks->var_deleted (d, v, dict_index, case_index, d->cb_data);
485 invalidate_proto (d);
489 /* Deletes variable V from dictionary D and frees V.
491 This is a very bad idea if there might be any pointers to V
492 from outside D. In general, no variable in the active dataset's
493 dictionary should be deleted when any transformations are
494 active on the dictionary's dataset, because those
495 transformations might reference the deleted variable. The
496 safest time to delete a variable is just after a procedure has
497 been executed, as done by DELETE VARIABLES.
499 Pointers to V within D are not a problem, because
500 dict_delete_var() knows to remove V from split variables,
501 weights, filters, etc. */
503 dict_delete_var (struct dictionary *d, struct variable *v)
505 dict_delete_var__ (d, v, false);
509 /* Deletes the COUNT variables listed in VARS from D. This is
510 unsafe; see the comment on dict_delete_var() for details. */
512 dict_delete_vars (struct dictionary *d,
513 struct variable *const *vars, size_t count)
515 /* FIXME: this can be done in O(count) time, but this algorithm
517 assert (count == 0 || vars != NULL);
520 dict_delete_var (d, *vars++);
523 /* Deletes the COUNT variables in D starting at index IDX. This
524 is unsafe; see the comment on dict_delete_var() for
525 details. Deleting consecutive vars will result in less callbacks
526 compared to iterating over dict_delete_var.
527 A simple while loop over dict_delete_var will
528 produce (d->n_vars - IDX) * COUNT variable changed callbacks
529 plus COUNT variable delete callbacks.
530 This here produces d->n_vars - IDX variable changed callbacks
531 plus COUNT variable delete callbacks. */
533 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
535 assert (idx + count <= d->n_vars);
537 /* We need to store the variable and the corresponding case_index
538 for the delete callbacks later. We store them in a linked list.*/
541 struct variable *var;
544 struct ll_list list = LL_INITIALIZER (list);
546 for (size_t i = idx; i < idx + count; i++)
548 struct delvar *dv = xmalloc (sizeof (struct delvar));
550 struct variable *v = d->vars[i].var;
552 dict_unset_split_var (d, v, false);
553 dict_unset_mrset_var (d, v);
556 dict_set_weight (d, NULL);
559 dict_set_filter (d, NULL);
562 dv->case_index = var_get_case_index (v);
563 ll_push_tail (&list, (struct ll *)dv);
566 dict_clear_vectors (d);
568 /* Remove variables from var array. */
569 unindex_vars (d, idx, d->n_vars);
570 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
573 /* Reindexing will result variable-changed callback */
574 reindex_vars (d, idx, d->n_vars, false);
576 invalidate_proto (d);
577 if (d->changed) d->changed (d, d->changed_data);
579 /* Now issue the variable delete callbacks and delete
580 the variables. The vardict is not valid at this point
581 anymore. That is the reason why we stored the
582 caseindex before reindexing. */
583 for (size_t vi = idx; vi < idx + count; vi++)
585 struct delvar *dv = (struct delvar *) ll_pop_head (&list);
586 var_clear_vardict (dv->var);
587 if (d->callbacks && d->callbacks->var_deleted)
588 d->callbacks->var_deleted (d, dv->var, vi, dv->case_index, d->cb_data);
594 /* Deletes scratch variables from dictionary D. */
596 dict_delete_scratch_vars (struct dictionary *d)
600 /* FIXME: this can be done in O(count) time, but this algorithm
602 for (i = 0; i < d->n_vars;)
603 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
604 dict_delete_var (d, d->vars[i].var);
611 /* Clears the contents from a dictionary without destroying the
612 dictionary itself. */
614 dict_clear__ (struct dictionary *d, bool skip_callbacks)
616 /* FIXME? Should we really clear case_limit, label, documents?
617 Others are necessarily cleared by deleting all the variables.*/
618 while (d->n_vars > 0)
620 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
625 d->n_vars = d->allocated_vars = 0;
626 invalidate_proto (d);
627 hmap_clear (&d->name_map);
628 d->next_value_idx = 0;
629 dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
638 dict_set_weight (d, NULL);
639 dict_set_filter (d, NULL);
644 string_array_clear (&d->documents);
645 dict_clear_vectors (d);
646 attrset_clear (&d->attributes);
649 /* Clears the contents from a dictionary without destroying the
650 dictionary itself. */
652 dict_clear (struct dictionary *d)
654 dict_clear__ (d, false);
657 /* Clears a dictionary and destroys it. */
659 _dict_destroy (struct dictionary *d)
661 /* In general, we don't want callbacks occurring, if the dictionary
662 is being destroyed */
663 d->callbacks = NULL ;
665 dict_clear__ (d, true);
666 string_array_destroy (&d->documents);
667 hmap_destroy (&d->name_map);
668 attrset_destroy (&d->attributes);
669 dict_clear_mrsets (d);
675 dict_ref (struct dictionary *d)
682 dict_unref (struct dictionary *d)
687 assert (d->ref_cnt >= 0);
692 /* Returns the number of variables in D. */
694 dict_get_n_vars (const struct dictionary *d)
699 /* Returns the variable in D with dictionary index IDX, which
700 must be between 0 and the count returned by
701 dict_get_n_vars(), exclusive. */
703 dict_get_var (const struct dictionary *d, size_t idx)
705 assert (idx < d->n_vars);
707 return d->vars[idx].var;
710 /* Sets *VARS to an array of pointers to variables in D and *N
711 to the number of variables in *D. All variables are returned
712 except for those, if any, in the classes indicated by EXCLUDE.
713 (There is no point in putting DC_SYSTEM in EXCLUDE as
714 dictionaries never include system variables.) */
716 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
717 size_t *n, enum dict_class exclude)
719 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
722 /* Sets *VARS to an array of pointers to variables in D and *N
723 to the number of variables in *D. All variables are returned
724 except for those, if any, in the classes indicated by EXCLUDE.
725 (There is no point in putting DC_SYSTEM in EXCLUDE as
726 dictionaries never include system variables.) */
728 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
729 size_t *n, enum dict_class exclude)
734 assert (exclude == (exclude & DC_ALL));
737 for (i = 0; i < d->n_vars; i++)
739 enum dict_class class = var_get_dict_class (d->vars[i].var);
740 if (!(class & exclude))
744 *vars = xnmalloc (count, sizeof **vars);
746 for (i = 0; i < d->n_vars; i++)
748 enum dict_class class = var_get_dict_class (d->vars[i].var);
749 if (!(class & exclude))
750 (*vars)[(*n)++] = d->vars[i].var;
752 assert (*n == count);
755 static struct variable *
756 add_var_with_case_index (struct dictionary *d, struct variable *v,
759 struct vardict_info *vardict;
761 assert (case_index >= d->next_value_idx);
763 /* Update dictionary. */
764 if (d->n_vars >= d->allocated_vars)
768 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
769 hmap_clear (&d->name_map);
770 for (i = 0; i < d->n_vars; i++)
772 var_set_vardict (d->vars[i].var, &d->vars[i]);
773 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
774 d->vars[i].name_node.hash);
778 vardict = &d->vars[d->n_vars++];
781 hmap_insert (&d->name_map, &vardict->name_node,
782 utf8_hash_case_string (var_get_name (v), 0));
783 vardict->case_index = case_index;
784 var_set_vardict (v, vardict);
786 if (d->changed) d->changed (d, d->changed_data);
787 if (d->callbacks && d->callbacks->var_added)
788 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
790 invalidate_proto (d);
791 d->next_value_idx = case_index + 1;
796 static struct variable *
797 add_var (struct dictionary *d, struct variable *v)
799 return add_var_with_case_index (d, v, d->next_value_idx);
802 /* Creates and returns a new variable in D with the given NAME
803 and WIDTH. Returns a null pointer if the given NAME would
804 duplicate that of an existing variable in the dictionary. */
806 dict_create_var (struct dictionary *d, const char *name, int width)
808 return (dict_lookup_var (d, name) == NULL
809 ? dict_create_var_assert (d, name, width)
813 /* Creates and returns a new variable in D with the given NAME
814 and WIDTH. Assert-fails if the given NAME would duplicate
815 that of an existing variable in the dictionary. */
817 dict_create_var_assert (struct dictionary *d, const char *name, int width)
819 assert (dict_lookup_var (d, name) == NULL);
820 return add_var (d, var_create (name, width));
823 /* Creates and returns a new variable in D, as a copy of existing variable
824 OLD_VAR, which need not be in D or in any dictionary. Returns a null
825 pointer if OLD_VAR's name would duplicate that of an existing variable in
828 dict_clone_var (struct dictionary *d, const struct variable *old_var)
830 return dict_clone_var_as (d, old_var, var_get_name (old_var));
833 /* Creates and returns a new variable in D, as a copy of existing variable
834 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
835 OLD_VAR's name would duplicate that of an existing variable in the
838 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
840 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
843 /* Creates and returns a new variable in D with name NAME, as a copy of
844 existing variable OLD_VAR, which need not be in D or in any dictionary.
845 Returns a null pointer if the given NAME would duplicate that of an existing
846 variable in the dictionary. */
848 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
851 return (dict_lookup_var (d, name) == NULL
852 ? dict_clone_var_as_assert (d, old_var, name)
856 /* Creates and returns a new variable in D with name NAME, as a copy of
857 existing variable OLD_VAR, which need not be in D or in any dictionary.
858 Assert-fails if the given NAME would duplicate that of an existing variable
859 in the dictionary. */
861 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
864 struct variable *new_var = var_clone (old_var);
865 assert (dict_lookup_var (d, name) == NULL);
866 var_set_name (new_var, name);
867 return add_var (d, new_var);
871 dict_clone_var_in_place_assert (struct dictionary *d,
872 const struct variable *old_var)
874 assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
875 return add_var_with_case_index (d, var_clone (old_var),
876 var_get_case_index (old_var));
879 /* Returns the variable named NAME in D, or a null pointer if no
880 variable has that name. */
882 dict_lookup_var (const struct dictionary *d, const char *name)
884 struct vardict_info *vardict;
886 HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
887 utf8_hash_case_string (name, 0), &d->name_map)
889 struct variable *var = vardict->var;
890 if (!utf8_strcasecmp (var_get_name (var), name))
897 /* Returns the variable named NAME in D. Assert-fails if no
898 variable has that name. */
900 dict_lookup_var_assert (const struct dictionary *d, const char *name)
902 struct variable *v = dict_lookup_var (d, name);
907 /* Returns true if variable V is in dictionary D,
910 dict_contains_var (const struct dictionary *d, const struct variable *v)
912 return (var_has_vardict (v)
913 && vardict_get_dictionary (var_get_vardict (v)) == d);
916 /* Moves V to 0-based position IDX in D. Other variables in D,
917 if any, retain their relative positions. Runs in time linear
918 in the distance moved. */
920 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
922 size_t old_index = var_get_dict_index (v);
924 assert (new_index < d->n_vars);
926 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
927 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
928 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
931 /* Reorders the variables in D, placing the COUNT variables
932 listed in ORDER in that order at the beginning of D. The
933 other variables in D, if any, retain their relative
936 dict_reorder_vars (struct dictionary *d,
937 struct variable *const *order, size_t count)
939 struct vardict_info *new_var;
942 assert (count == 0 || order != NULL);
943 assert (count <= d->n_vars);
945 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
947 /* Add variables in ORDER to new_var. */
948 for (i = 0; i < count; i++)
950 struct vardict_info *old_var;
952 assert (dict_contains_var (d, order[i]));
954 old_var = var_get_vardict (order[i]);
955 new_var[i] = *old_var;
956 old_var->dict = NULL;
959 /* Add remaining variables to new_var. */
960 for (i = 0; i < d->n_vars; i++)
961 if (d->vars[i].dict != NULL)
962 new_var[count++] = d->vars[i];
963 assert (count == d->n_vars);
965 /* Replace old vardicts by new ones. */
969 hmap_clear (&d->name_map);
970 reindex_vars (d, 0, d->n_vars, false);
973 /* Changes the name of variable V that is currently in a dictionary to
976 rename_var (struct variable *v, const char *new_name)
978 struct vardict_info *vardict = var_get_vardict (v);
979 var_clear_vardict (v);
980 var_set_name (v, new_name);
981 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
982 var_set_vardict (v, vardict);
985 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
986 successful, false if a variable (other than V) with the given name already
989 dict_try_rename_var (struct dictionary *d, struct variable *v,
990 const char *new_name)
992 struct variable *conflict = dict_lookup_var (d, new_name);
993 if (conflict && v != conflict)
996 struct variable *old = var_clone (v);
997 unindex_var (d, var_get_vardict (v));
998 rename_var (v, new_name);
999 reindex_var (d, var_get_vardict (v), false);
1001 if (settings_get_algorithm () == ENHANCED)
1002 var_clear_short_names (v);
1004 if (d->changed) d->changed (d, d->changed_data);
1005 if (d->callbacks && d->callbacks->var_changed)
1006 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1013 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1014 a variable named NEW_NAME is already in D, except that
1015 NEW_NAME may be the same as V's existing name. */
1017 dict_rename_var (struct dictionary *d, struct variable *v,
1018 const char *new_name)
1020 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1024 /* Renames COUNT variables specified in VARS to the names given
1025 in NEW_NAMES within dictionary D. If the renaming would
1026 result in a duplicate variable name, returns false and stores a
1027 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1028 non-null). Otherwise, the renaming is successful, and true
1031 dict_rename_vars (struct dictionary *d,
1032 struct variable **vars, char **new_names, size_t count,
1039 assert (count == 0 || vars != NULL);
1040 assert (count == 0 || new_names != NULL);
1042 /* Save the names of the variables to be renamed. */
1043 pool = pool_create ();
1044 old_names = pool_nalloc (pool, count, sizeof *old_names);
1045 for (i = 0; i < count; i++)
1046 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1048 /* Remove the variables to be renamed from the name hash,
1050 for (i = 0; i < count; i++)
1052 unindex_var (d, var_get_vardict (vars[i]));
1053 rename_var (vars[i], new_names[i]);
1056 /* Add the renamed variables back into the name hash,
1057 checking for conflicts. */
1058 for (i = 0; i < count; i++)
1060 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1062 /* There is a name conflict.
1063 Back out all the name changes that have already
1064 taken place, and indicate failure. */
1065 size_t fail_idx = i;
1066 if (err_name != NULL)
1067 *err_name = new_names[i];
1069 for (i = 0; i < fail_idx; i++)
1070 unindex_var (d, var_get_vardict (vars[i]));
1072 for (i = 0; i < count; i++)
1074 rename_var (vars[i], old_names[i]);
1075 reindex_var (d, var_get_vardict (vars[i]), false);
1078 pool_destroy (pool);
1081 reindex_var (d, var_get_vardict (vars[i]), false);
1084 /* Clear short names. */
1085 if (settings_get_algorithm () == ENHANCED)
1086 for (i = 0; i < count; i++)
1087 var_clear_short_names (vars[i]);
1089 pool_destroy (pool);
1093 /* Returns true if a variable named NAME may be inserted in DICT;
1094 that is, if there is not already a variable with that name in
1095 DICT and if NAME is not a reserved word. (The caller's checks
1096 have already verified that NAME is otherwise acceptable as a
1099 var_name_is_insertable (const struct dictionary *dict, const char *name)
1101 return (dict_lookup_var (dict, name) == NULL
1102 && lex_id_to_token (ss_cstr (name)) == T_ID);
1106 make_hinted_name (const struct dictionary *dict, const char *hint)
1108 size_t hint_len = strlen (hint);
1109 bool dropped = false;
1114 if (hint_len > ID_MAX_LEN)
1115 hint_len = ID_MAX_LEN;
1117 /* The allocation size here is OK: characters that are copied directly fit
1118 OK, and characters that are not copied directly are replaced by a single
1119 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1120 replaced by '_' too. */
1121 root = rp = xmalloc (hint_len + 1);
1122 for (ofs = 0; ofs < hint_len; ofs += mblen)
1126 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1129 ? lex_uc_is_id1 (uc) && uc != '$'
1130 : lex_uc_is_idn (uc))
1137 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1139 else if (rp != root)
1144 if (root[0] != '\0')
1146 unsigned long int i;
1148 if (var_name_is_insertable (dict, root))
1151 for (i = 0; i < ULONG_MAX; i++)
1153 char suffix[INT_BUFSIZE_BOUND (i) + 1];
1157 if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1160 name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1161 if (var_name_is_insertable (dict, name))
1176 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1178 unsigned long int number;
1180 for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1184 char name[3 + INT_STRLEN_BOUND (number) + 1];
1186 sprintf (name, "VAR%03lu", number);
1187 if (dict_lookup_var (dict, name) == NULL)
1189 if (num_start != NULL)
1190 *num_start = number + 1;
1191 return xstrdup (name);
1199 /* Devises and returns a variable name unique within DICT. The variable name
1200 is owned by the caller, which must free it with free() when it is no longer
1203 HINT, if it is non-null, is used as a suggestion that will be
1204 modified for suitability as a variable name and for
1207 If HINT is null or entirely unsuitable, a name in the form
1208 "VAR%03d" will be generated, where the smallest unused integer
1209 value is used. If NUM_START is non-null, then its value is
1210 used as the minimum numeric value to check, and it is updated
1211 to the next value to be checked.
1214 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1215 unsigned long int *num_start)
1219 char *hinted_name = make_hinted_name (dict, hint);
1220 if (hinted_name != NULL)
1224 return make_numeric_name (dict, num_start);
1227 /* Returns whether variable names must be valid identifiers. Normally, this is
1228 true, but sometimes a dictionary is prepared for external use (e.g. output
1229 to a CSV file) where names don't have to be valid. */
1231 dict_get_names_must_be_ids (const struct dictionary *d)
1233 return d->names_must_be_ids;
1236 /* Sets whether variable names must be valid identifiers. Normally, this is
1237 true, but sometimes a dictionary is prepared for external use (e.g. output
1238 to a CSV file) where names don't have to be valid.
1240 Changing this setting from false to true doesn't make the dictionary check
1241 all the existing variable names, so it can cause an invariant violation. */
1243 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1245 d->names_must_be_ids = names_must_be_ids;
1248 /* Returns the weighting variable in dictionary D, or a null
1249 pointer if the dictionary is unweighted. */
1251 dict_get_weight (const struct dictionary *d)
1253 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1258 /* Returns the value of D's weighting variable in case C, except
1259 that a negative weight is returned as 0. Returns 1 if the
1260 dictionary is unweighted. Will warn about missing, negative,
1261 or zero values if *WARN_ON_INVALID is true. The function will
1262 set *WARN_ON_INVALID to false if an invalid weight is
1265 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1266 bool *warn_on_invalid)
1270 if (d->weight == NULL)
1274 double w = case_num (c, d->weight);
1276 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1280 /* Returns the format to use for weights. */
1281 const struct fmt_spec *
1282 dict_get_weight_format (const struct dictionary *d)
1284 return d->weight ? var_get_print_format (d->weight) : &F_8_0;
1287 /* Sets the weighting variable of D to V, or turning off
1288 weighting if V is a null pointer. */
1290 dict_set_weight (struct dictionary *d, struct variable *v)
1292 assert (v == NULL || dict_contains_var (d, v));
1293 assert (v == NULL || var_is_numeric (v));
1297 if (d->changed) d->changed (d, d->changed_data);
1298 if (d->callbacks && d->callbacks->weight_changed)
1299 d->callbacks->weight_changed (d,
1300 v ? var_get_dict_index (v) : -1,
1304 /* Returns the filter variable in dictionary D (see cmd_filter())
1305 or a null pointer if the dictionary is unfiltered. */
1307 dict_get_filter (const struct dictionary *d)
1309 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1314 /* Sets V as the filter variable for dictionary D. Passing a
1315 null pointer for V turn off filtering. */
1317 dict_set_filter (struct dictionary *d, struct variable *v)
1319 assert (v == NULL || dict_contains_var (d, v));
1320 assert (v == NULL || var_is_numeric (v));
1324 if (d->changed) d->changed (d, d->changed_data);
1325 if (d->callbacks && d->callbacks->filter_changed)
1326 d->callbacks->filter_changed (d,
1327 v ? var_get_dict_index (v) : -1,
1331 /* Returns the case limit for dictionary D, or zero if the number
1332 of cases is unlimited. */
1334 dict_get_case_limit (const struct dictionary *d)
1336 return d->case_limit;
1339 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1340 0 for CASE_LIMIT to indicate no limit. */
1342 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1344 d->case_limit = case_limit;
1347 /* Returns the prototype used for cases created by dictionary D. */
1348 const struct caseproto *
1349 dict_get_proto (const struct dictionary *d_)
1351 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1352 if (d->proto == NULL)
1356 d->proto = caseproto_create ();
1357 d->proto = caseproto_reserve (d->proto, d->n_vars);
1358 for (i = 0; i < d->n_vars; i++)
1359 d->proto = caseproto_set_width (d->proto,
1360 var_get_case_index (d->vars[i].var),
1361 var_get_width (d->vars[i].var));
1366 /* Returns the case index of the next value to be added to D.
1367 This value is the number of `union value's that need to be
1368 allocated to store a case for dictionary D. */
1370 dict_get_next_value_idx (const struct dictionary *d)
1372 return d->next_value_idx;
1375 /* Returns the number of bytes needed to store a case for
1378 dict_get_case_size (const struct dictionary *d)
1380 return sizeof (union value) * dict_get_next_value_idx (d);
1383 /* Reassigns values in dictionary D so that fragmentation is
1386 dict_compact_values (struct dictionary *d)
1390 d->next_value_idx = 0;
1391 for (i = 0; i < d->n_vars; i++)
1393 struct variable *v = d->vars[i].var;
1394 set_var_case_index (v, d->next_value_idx++);
1396 invalidate_proto (d);
1399 /* Returns the number of values occupied by the variables in
1400 dictionary D. All variables are considered if EXCLUDE_CLASSES
1401 is 0, or it may contain one or more of (1u << DC_ORDINARY),
1402 (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to exclude the
1403 corresponding type of variable.
1405 The return value may be less than the number of values in one
1406 of dictionary D's cases (as returned by
1407 dict_get_next_value_idx) even if E is 0, because there may be
1408 gaps in D's cases due to deleted variables. */
1410 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1412 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1414 | (1u << DC_SCRATCH))) == 0);
1417 for (size_t i = 0; i < d->n_vars; i++)
1419 enum dict_class class = var_get_dict_class (d->vars[i].var);
1420 if (!(exclude_classes & (1u << class)))
1426 /* Returns the case prototype that would result after deleting
1427 all variables from D that are not in one of the
1428 EXCLUDE_CLASSES and compacting the dictionary with
1431 The caller must unref the returned caseproto when it is no
1434 dict_get_compacted_proto (const struct dictionary *d,
1435 unsigned int exclude_classes)
1437 struct caseproto *proto;
1440 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1442 | (1u << DC_SCRATCH))) == 0);
1444 proto = caseproto_create ();
1445 for (i = 0; i < d->n_vars; i++)
1447 struct variable *v = d->vars[i].var;
1448 if (!(exclude_classes & (1u << var_get_dict_class (v))))
1449 proto = caseproto_add_width (proto, var_get_width (v));
1453 /* Returns the file label for D, or a null pointer if D is
1454 unlabeled (see cmd_file_label()). */
1456 dict_get_label (const struct dictionary *d)
1461 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1464 Removes D's label if LABEL is null or the empty string. */
1466 dict_set_label (struct dictionary *d, const char *label)
1469 if (label == NULL || label[0] == '\0')
1472 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1475 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1476 return value is always nonnull; if there are no documents then the
1477 string_arary is empty.*/
1478 const struct string_array *
1479 dict_get_documents (const struct dictionary *d)
1481 return &d->documents;
1484 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1486 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1488 /* Swap out the old documents, instead of destroying them immediately, to
1489 allow the new documents to include pointers into the old ones. */
1490 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1491 string_array_swap (&d->documents, &old_docs);
1493 for (size_t i = 0; i < new_docs->n; i++)
1494 dict_add_document_line (d, new_docs->strings[i], false);
1496 string_array_destroy (&old_docs);
1499 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1500 into individual lines at new-line characters. Each line is truncated to at
1501 most DOC_LINE_LENGTH bytes in D's encoding. */
1503 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1507 dict_clear_documents (d);
1508 for (s = new_docs; *s != '\0';)
1510 size_t len = strcspn (s, "\n");
1511 char *line = xmemdup0 (s, len);
1512 dict_add_document_line (d, line, false);
1521 /* Drops the documents from dictionary D. */
1523 dict_clear_documents (struct dictionary *d)
1525 string_array_clear (&d->documents);
1528 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1529 truncated so that it is no more than 80 bytes in the dictionary's
1530 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1531 then a warning will be issued. */
1533 dict_add_document_line (struct dictionary *d, const char *line,
1539 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1540 truncated = line[trunc_len] != '\0';
1541 if (truncated && issue_warning)
1543 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1544 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1547 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1552 /* Returns the number of document lines in dictionary D. */
1554 dict_get_document_n_lines (const struct dictionary *d)
1556 return d->documents.n;
1559 /* Returns document line number IDX in dictionary D. The caller must not
1560 modify or free the returned string. */
1562 dict_get_document_line (const struct dictionary *d, size_t idx)
1564 assert (idx < d->documents.n);
1565 return d->documents.strings[idx];
1568 /* Creates in D a vector named NAME that contains the N
1569 variables in VAR. Returns true if successful, or false if a
1570 vector named NAME already exists in D. */
1572 dict_create_vector (struct dictionary *d,
1574 struct variable **var, size_t n)
1577 for (size_t i = 0; i < n; i++)
1578 assert (dict_contains_var (d, var[i]));
1580 if (dict_lookup_vector (d, name) == NULL)
1582 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1583 d->vector[d->n_vectors++] = vector_create (name, var, n);
1590 /* Creates in D a vector named NAME that contains the N
1591 variables in VAR. A vector named NAME must not already exist
1594 dict_create_vector_assert (struct dictionary *d,
1596 struct variable **var, size_t n)
1598 assert (dict_lookup_vector (d, name) == NULL);
1599 dict_create_vector (d, name, var, n);
1602 /* Returns the vector in D with index IDX, which must be less
1603 than dict_get_n_vectors (D). */
1604 const struct vector *
1605 dict_get_vector (const struct dictionary *d, size_t idx)
1607 assert (idx < d->n_vectors);
1609 return d->vector[idx];
1612 /* Returns the number of vectors in D. */
1614 dict_get_n_vectors (const struct dictionary *d)
1616 return d->n_vectors;
1619 /* Looks up and returns the vector within D with the given
1621 const struct vector *
1622 dict_lookup_vector (const struct dictionary *d, const char *name)
1625 for (i = 0; i < d->n_vectors; i++)
1626 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1627 return d->vector[i];
1631 /* Deletes all vectors from D. */
1633 dict_clear_vectors (struct dictionary *d)
1637 for (i = 0; i < d->n_vectors; i++)
1638 vector_destroy (d->vector[i]);
1645 /* Multiple response sets. */
1647 /* Returns the multiple response set in DICT with index IDX, which must be
1648 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1649 const struct mrset *
1650 dict_get_mrset (const struct dictionary *dict, size_t idx)
1652 assert (idx < dict->n_mrsets);
1653 return dict->mrsets[idx];
1656 /* Returns the number of multiple response sets in DICT. */
1658 dict_get_n_mrsets (const struct dictionary *dict)
1660 return dict->n_mrsets;
1663 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1664 returns its index; otherwise, returns SIZE_MAX. */
1666 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1670 for (i = 0; i < dict->n_mrsets; i++)
1671 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1677 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1678 returns it; otherwise, returns NULL. */
1679 const struct mrset *
1680 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1682 size_t idx = dict_lookup_mrset_idx (dict, name);
1683 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1686 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1687 true if a set was replaced, false if none existed with the specified name.
1689 Ownership of MRSET is transferred to DICT. */
1691 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1695 assert (mrset_ok (mrset, dict));
1697 idx = dict_lookup_mrset_idx (dict, mrset->name);
1698 if (idx == SIZE_MAX)
1700 dict->mrsets = xrealloc (dict->mrsets,
1701 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1702 dict->mrsets[dict->n_mrsets++] = mrset;
1707 mrset_destroy (dict->mrsets[idx]);
1708 dict->mrsets[idx] = mrset;
1713 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1714 from DICT and returns true. If none is found, returns false without
1717 Deleting one multiple response set causes the indexes of other sets within
1720 dict_delete_mrset (struct dictionary *dict, const char *name)
1722 size_t idx = dict_lookup_mrset_idx (dict, name);
1723 if (idx != SIZE_MAX)
1725 mrset_destroy (dict->mrsets[idx]);
1726 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1733 /* Deletes all multiple response sets from DICT. */
1735 dict_clear_mrsets (struct dictionary *dict)
1739 for (i = 0; i < dict->n_mrsets; i++)
1740 mrset_destroy (dict->mrsets[i]);
1741 free (dict->mrsets);
1742 dict->mrsets = NULL;
1746 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1748 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1752 assert (dict_contains_var (dict, var));
1754 for (i = 0; i < dict->n_mrsets;)
1756 struct mrset *mrset = dict->mrsets[i];
1759 for (j = 0; j < mrset->n_vars;)
1760 if (mrset->vars[j] == var)
1761 remove_element (mrset->vars, mrset->n_vars--,
1762 sizeof *mrset->vars, j);
1766 if (mrset->n_vars < 2)
1768 mrset_destroy (mrset);
1769 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1776 /* Returns D's attribute set. The caller may examine or modify
1777 the attribute set, but must not destroy it. Destroying D or
1778 calling dict_set_attributes for D will also destroy D's
1781 dict_get_attributes (const struct dictionary *d)
1783 return CONST_CAST (struct attrset *, &d->attributes);
1786 /* Replaces D's attributes set by a copy of ATTRS. */
1788 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1790 attrset_destroy (&d->attributes);
1791 attrset_clone (&d->attributes, attrs);
1794 /* Returns true if D has at least one attribute in its attribute
1795 set, false if D's attribute set is empty. */
1797 dict_has_attributes (const struct dictionary *d)
1799 return attrset_count (&d->attributes) > 0;
1802 /* Called from variable.c to notify the dictionary that some property (indicated
1803 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1804 prior to the change. OLDVAR is destroyed by this function.
1807 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1809 if (var_has_vardict (v))
1811 const struct vardict_info *vardict = var_get_vardict (v);
1812 struct dictionary *d = vardict->dict;
1817 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1818 invalidate_proto (d);
1820 if (d->changed) d->changed (d, d->changed_data);
1821 if (d->callbacks && d->callbacks->var_changed)
1822 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1829 /* Dictionary used to contain "internal variables". */
1830 static struct dictionary *internal_dict;
1832 /* Create a variable of the specified WIDTH to be used for internal
1833 calculations only. The variable is assigned case index CASE_IDX. */
1835 dict_create_internal_var (int case_idx, int width)
1837 if (internal_dict == NULL)
1838 internal_dict = dict_create ("UTF-8");
1842 static int counter = INT_MAX / 2;
1843 struct variable *var;
1846 if (++counter == INT_MAX)
1847 counter = INT_MAX / 2;
1849 sprintf (name, "$internal%d", counter);
1850 var = dict_create_var (internal_dict, name, width);
1853 set_var_case_index (var, case_idx);
1859 /* Destroys VAR, which must have been created with
1860 dict_create_internal_var(). */
1862 dict_destroy_internal_var (struct variable *var)
1866 dict_delete_var (internal_dict, var);
1868 /* Destroy internal_dict if it has no variables left, just so that
1869 valgrind --leak-check --show-reachable won't show internal_dict. */
1870 if (dict_get_n_vars (internal_dict) == 0)
1872 dict_unref (internal_dict);
1873 internal_dict = NULL;
1879 vardict_get_dict_index (const struct vardict_info *vardict)
1881 return vardict - vardict->dict->vars;