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/varset.h"
36 #include "data/vector.h"
37 #include "libpspp/array.h"
38 #include "libpspp/assertion.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/hash-functions.h"
41 #include "libpspp/hmap.h"
42 #include "libpspp/i18n.h"
43 #include "libpspp/message.h"
44 #include "libpspp/misc.h"
45 #include "libpspp/pool.h"
46 #include "libpspp/str.h"
47 #include "libpspp/string-array.h"
48 #include "libpspp/ll.h"
50 #include "gl/intprops.h"
51 #include "gl/minmax.h"
52 #include "gl/xalloc.h"
53 #include "gl/xmemdup0.h"
56 #define _(msgid) gettext (msgid)
62 struct vardict_info *vars; /* Variables. */
63 size_t n_vars; /* Number of variables. */
64 size_t allocated_vars; /* Allocated space in 'vars'. */
65 struct caseproto *proto; /* Prototype for dictionary cases
67 struct hmap name_map; /* Variable index by name. */
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. */
81 struct varset **varsets; /* Variable sets. */
82 size_t n_varsets; /* Number of variable sets. */
84 /* Whether variable names must be valid identifiers. Normally, this is
85 true, but sometimes a dictionary is prepared for external use
86 (e.g. output to a CSV file) where names don't have to be valid. */
87 bool names_must_be_ids;
89 char *encoding; /* Character encoding of string data */
91 const struct dict_callbacks *callbacks; /* Callbacks on dictionary
93 void *cb_data ; /* Data passed to callbacks */
95 void (*changed) (struct dictionary *, void *); /* Generic change callback */
99 static void dict_unset_split_var (struct dictionary *, struct variable *, bool);
100 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
101 static void dict_unset_varset_var (struct dictionary *, struct variable *);
103 /* Compares two double pointers to variables, which should point
104 to elements of a struct dictionary's `var' member array. */
106 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
108 struct variable *const *a = a_;
109 struct variable *const *b = b_;
111 return *a < *b ? -1 : *a > *b;
115 unindex_var (struct dictionary *d, struct vardict_info *vardict)
117 hmap_delete (&d->name_map, &vardict->name_node);
120 /* This function assumes that vardict->name_node.hash is valid, that is, that
121 its name has not changed since it was hashed (rename_var() updates this
122 hash along with the name itself). */
124 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
126 struct variable *old = (d->callbacks && d->callbacks->var_changed
127 ? var_clone (vardict->var)
130 struct variable *var = vardict->var;
131 var_set_vardict (var, vardict);
132 hmap_insert_fast (&d->name_map, &vardict->name_node,
133 vardict->name_node.hash);
135 if (! skip_callbacks)
137 if (d->changed) d->changed (d, d->changed_data);
140 d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
146 /* Sets the case_index in V's vardict to CASE_INDEX. */
148 set_var_case_index (struct variable *v, int case_index)
150 var_get_vardict (v)->case_index = case_index;
153 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
156 unindex_vars (struct dictionary *d, size_t from, size_t to)
160 for (i = from; i < to; i++)
161 unindex_var (d, &d->vars[i]);
164 /* Re-sets the dict_index in the dictionary variables with
165 indexes from FROM to TO (exclusive). */
167 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
171 for (i = from; i < to; i++)
172 reindex_var (d, &d->vars[i], skip_callbacks);
177 /* Returns the encoding for data in dictionary D. The return value is a
178 nonnull string that contains an IANA character set name. */
180 dict_get_encoding (const struct dictionary *d)
185 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
186 encoding. Returns true if it is, otherwise an error message that the caller
188 char * WARN_UNUSED_RESULT
189 dict_id_is_valid__ (const struct dictionary *dict, const char *id)
191 if (!dict->names_must_be_ids)
193 return id_is_valid__ (id, dict->encoding);
197 error_to_bool (char *error)
208 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
209 encoding, false otherwise. */
211 dict_id_is_valid (const struct dictionary *dict, const char *id)
213 return error_to_bool (dict_id_is_valid__ (dict, id));
217 dict_set_change_callback (struct dictionary *d,
218 void (*changed) (struct dictionary *, void*),
221 d->changed = changed;
222 d->changed_data = data;
225 /* Discards dictionary D's caseproto. (It will be regenerated
226 lazily, on demand.) */
228 invalidate_proto (struct dictionary *d)
230 caseproto_unref (d->proto);
234 /* Print a representation of dictionary D to stdout, for
235 debugging purposes. */
237 dict_dump (const struct dictionary *d)
240 for (i = 0 ; i < d->n_vars ; ++i)
242 const struct variable *v = d->vars[i].var;
243 printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
245 var_get_dict_index (v),
246 var_get_case_index (v));
251 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
252 the dictionary or any of the variables it contains are modified.
253 Each callback will get passed CALLBACK_DATA.
254 Any callback may be NULL, in which case it'll be ignored.
257 dict_set_callbacks (struct dictionary *dict,
258 const struct dict_callbacks *callbacks,
261 dict->callbacks = callbacks;
262 dict->cb_data = callback_data;
265 /* Shallow copy the callbacks from SRC to DEST */
267 dict_copy_callbacks (struct dictionary *dest,
268 const struct dictionary *src)
270 dest->callbacks = src->callbacks;
271 dest->cb_data = src->cb_data;
274 /* Creates and returns a new dictionary with the specified ENCODING. */
276 dict_create (const char *encoding)
278 struct dictionary *d = xmalloc (sizeof *d);
280 *d = (struct dictionary) {
281 .encoding = xstrdup (encoding),
282 .names_must_be_ids = true,
283 .name_map = HMAP_INITIALIZER (d->name_map),
284 .attributes = ATTRSET_INITIALIZER (d->attributes),
285 .split_type = SPLIT_NONE,
292 /* Creates and returns a (deep) copy of an existing
295 Callbacks are not cloned. */
297 dict_clone (const struct dictionary *s)
299 struct dictionary *d = dict_create (s->encoding);
300 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
302 for (size_t i = 0; i < s->n_vars; i++)
304 struct variable *sv = s->vars[i].var;
305 struct variable *dv = dict_clone_var_assert (d, sv);
307 for (size_t j = 0; j < var_get_n_short_names (sv); j++)
308 var_set_short_name (dv, j, var_get_short_name (sv, j));
310 var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
313 d->n_splits = s->n_splits;
316 d->split = xnmalloc (d->n_splits, sizeof *d->split);
317 for (size_t i = 0; i < d->n_splits; i++)
318 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
320 d->split_type = s->split_type;
322 if (s->weight != NULL)
323 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
325 if (s->filter != NULL)
326 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
328 d->case_limit = s->case_limit;
329 dict_set_label (d, dict_get_label (s));
330 dict_set_documents (d, dict_get_documents (s));
332 d->n_vectors = s->n_vectors;
333 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
334 for (size_t i = 0; i < s->n_vectors; i++)
335 d->vector[i] = vector_clone (s->vector[i], s, d);
337 dict_set_attributes (d, dict_get_attributes (s));
339 for (size_t i = 0; i < s->n_mrsets; i++)
341 const struct mrset *old = s->mrsets[i];
345 /* Clone old mrset, then replace vars from D by vars from S. */
346 new = mrset_clone (old);
347 for (j = 0; j < new->n_vars; j++)
348 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
350 dict_add_mrset (d, new);
353 for (size_t i = 0; i < s->n_varsets; i++)
355 const struct varset *old = s->varsets[i];
357 /* Clone old varset, then replace vars from D by vars from S. */
358 struct varset *new = varset_clone (old);
359 for (size_t j = 0; j < new->n_vars; j++)
360 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
362 dict_add_varset (d, new);
368 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
369 dict_get_n_splits() to determine how many SPLIT FILE vars
370 there are. Returns a null pointer if and only if there are no
372 const struct variable *const *
373 dict_get_split_vars (const struct dictionary *d)
378 /* Returns the number of SPLIT FILE vars. */
380 dict_get_n_splits (const struct dictionary *d)
385 /* Removes variable V, which must be in D, from D's set of split
388 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
392 assert (dict_contains_var (d, v));
394 orig_count = d->n_splits;
395 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
396 &v, compare_var_ptrs, NULL);
397 if (orig_count != d->n_splits && !skip_callbacks)
399 if (d->changed) d->changed (d, d->changed_data);
400 /* We changed the set of split variables so invoke the
402 if (d->callbacks && d->callbacks->split_changed)
403 d->callbacks->split_changed (d, d->cb_data);
408 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
411 dict_set_split_vars__ (struct dictionary *d,
412 struct variable *const *split, size_t n,
413 enum split_type type, bool skip_callbacks)
417 assert (n == 0 || split != NULL);
420 d->split_type = (n == 0 ? SPLIT_NONE
421 : type == SPLIT_NONE ? SPLIT_LAYERED
425 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
426 memcpy (d->split, split, n * sizeof *d->split);
436 if (d->changed) d->changed (d, d->changed_data);
437 if (d->callbacks && d->callbacks->split_changed)
438 d->callbacks->split_changed (d, d->cb_data);
443 dict_get_split_type (const struct dictionary *d)
445 return d->split_type;
448 /* Sets N split vars SPLIT in dictionary D. */
450 dict_set_split_vars (struct dictionary *d,
451 struct variable *const *split, size_t n,
452 enum split_type type)
454 dict_set_split_vars__ (d, split, n, type, false);
458 dict_clear_split_vars (struct dictionary *d)
460 dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
464 /* Deletes variable V from dictionary D and frees V.
466 This is a very bad idea if there might be any pointers to V
467 from outside D. In general, no variable in the active dataset's
468 dictionary should be deleted when any transformations are
469 active on the dictionary's dataset, because those
470 transformations might reference the deleted variable. The
471 safest time to delete a variable is just after a procedure has
472 been executed, as done by DELETE VARIABLES.
474 Pointers to V within D are not a problem, because
475 dict_delete_var() knows to remove V from split variables,
476 weights, filters, etc. */
478 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
480 int dict_index = var_get_dict_index (v);
482 assert (dict_contains_var (d, v));
484 dict_unset_split_var (d, v, skip_callbacks);
485 dict_unset_mrset_var (d, v);
486 dict_unset_varset_var (d, v);
489 dict_set_weight (d, NULL);
492 dict_set_filter (d, NULL);
494 dict_clear_vectors (d);
496 /* Remove V from var array. */
497 unindex_vars (d, dict_index, d->n_vars);
498 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
501 /* Update dict_index for each affected variable. */
502 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
505 var_clear_vardict (v);
507 if (! skip_callbacks)
509 if (d->changed) d->changed (d, d->changed_data);
510 if (d->callbacks && d->callbacks->vars_deleted)
511 d->callbacks->vars_deleted (d, dict_index, 1, d->cb_data);
514 invalidate_proto (d);
518 /* Deletes variable V from dictionary D and frees V.
520 This is a very bad idea if there might be any pointers to V
521 from outside D. In general, no variable in the active dataset's
522 dictionary should be deleted when any transformations are
523 active on the dictionary's dataset, because those
524 transformations might reference the deleted variable. The
525 safest time to delete a variable is just after a procedure has
526 been executed, as done by DELETE VARIABLES.
528 Pointers to V within D are not a problem, because
529 dict_delete_var() knows to remove V from split variables,
530 weights, filters, etc. */
532 dict_delete_var (struct dictionary *d, struct variable *v)
534 dict_delete_var__ (d, v, false);
535 dict_compact_values (d);
539 /* Deletes the COUNT variables listed in VARS from D. This is
540 unsafe; see the comment on dict_delete_var() for details. */
542 dict_delete_vars (struct dictionary *d,
543 struct variable *const *vars, size_t count)
545 /* FIXME: this can be done in O(count) time, but this algorithm
547 assert (count == 0 || vars != NULL);
550 dict_delete_var (d, *vars++);
551 dict_compact_values (d);
554 /* Deletes the COUNT variables in D starting at index IDX. This
555 is unsafe; see the comment on dict_delete_var() for
556 details. Deleting consecutive vars will result in less callbacks
557 compared to iterating over dict_delete_var.
558 A simple while loop over dict_delete_var will
559 produce (d->n_vars - IDX) * COUNT variable changed callbacks
560 plus COUNT variable delete callbacks.
561 This here produces d->n_vars - IDX variable changed callbacks
562 plus COUNT variable delete callbacks. */
564 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
566 assert (idx + count <= d->n_vars);
568 /* We need to store the variable and the corresponding case_index
569 for the delete callbacks later. We store them in a linked list.*/
572 struct variable *var;
574 struct ll_list list = LL_INITIALIZER (list);
576 for (size_t i = idx; i < idx + count; i++)
578 struct delvar *dv = xmalloc (sizeof (struct delvar));
580 struct variable *v = d->vars[i].var;
582 dict_unset_split_var (d, v, false);
583 dict_unset_mrset_var (d, v);
584 dict_unset_varset_var (d, v);
587 dict_set_weight (d, NULL);
590 dict_set_filter (d, NULL);
593 ll_push_tail (&list, (struct ll *)dv);
596 dict_clear_vectors (d);
598 /* Remove variables from var array. */
599 unindex_vars (d, idx, d->n_vars);
600 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
603 /* Reindexing will result variable-changed callback */
604 reindex_vars (d, idx, d->n_vars, false);
606 invalidate_proto (d);
607 if (d->changed) d->changed (d, d->changed_data);
609 /* Now issue the variable delete callbacks and delete
610 the variables. The vardict is not valid at this point
611 anymore. That is the reason why we stored the
612 caseindex before reindexing. */
613 if (d->callbacks && d->callbacks->vars_deleted)
614 d->callbacks->vars_deleted (d, idx, count, d->cb_data);
615 for (size_t vi = idx; vi < idx + count; vi++)
617 struct delvar *dv = (struct delvar *) ll_pop_head (&list);
618 var_clear_vardict (dv->var);
623 dict_compact_values (d);
626 /* Deletes scratch variables from dictionary D. */
628 dict_delete_scratch_vars (struct dictionary *d)
632 /* FIXME: this can be done in O(count) time, but this algorithm
634 for (i = 0; i < d->n_vars;)
635 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
636 dict_delete_var (d, d->vars[i].var);
640 dict_compact_values (d);
645 /* Clears the contents from a dictionary without destroying the
646 dictionary itself. */
648 dict_clear__ (struct dictionary *d, bool skip_callbacks)
650 /* FIXME? Should we really clear case_limit, label, documents?
651 Others are necessarily cleared by deleting all the variables.*/
652 while (d->n_vars > 0)
654 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
659 d->n_vars = d->allocated_vars = 0;
660 invalidate_proto (d);
661 hmap_clear (&d->name_map);
662 dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
671 dict_set_weight (d, NULL);
672 dict_set_filter (d, NULL);
677 string_array_clear (&d->documents);
678 dict_clear_vectors (d);
679 attrset_clear (&d->attributes);
682 /* Clears the contents from a dictionary without destroying the
683 dictionary itself. */
685 dict_clear (struct dictionary *d)
687 dict_clear__ (d, false);
690 /* Clears a dictionary and destroys it. */
692 _dict_destroy (struct dictionary *d)
694 /* In general, we don't want callbacks occurring, if the dictionary
695 is being destroyed */
696 d->callbacks = NULL ;
698 dict_clear__ (d, true);
699 string_array_destroy (&d->documents);
700 hmap_destroy (&d->name_map);
701 attrset_destroy (&d->attributes);
702 dict_clear_mrsets (d);
703 dict_clear_varsets (d);
709 dict_ref (struct dictionary *d)
716 dict_unref (struct dictionary *d)
721 assert (d->ref_cnt >= 0);
726 /* Returns the number of variables in D. */
728 dict_get_n_vars (const struct dictionary *d)
733 /* Returns the variable in D with dictionary index IDX, which
734 must be between 0 and the count returned by
735 dict_get_n_vars(), exclusive. */
737 dict_get_var (const struct dictionary *d, size_t idx)
739 assert (idx < d->n_vars);
741 return d->vars[idx].var;
744 /* Sets *VARS to an array of pointers to variables in D and *N
745 to the number of variables in *D. All variables are returned
746 except for those, if any, in the classes indicated by EXCLUDE.
747 (There is no point in putting DC_SYSTEM in EXCLUDE as
748 dictionaries never include system variables.) */
750 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
751 size_t *n, enum dict_class exclude)
753 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
756 /* Sets *VARS to an array of pointers to variables in D and *N
757 to the number of variables in *D. All variables are returned
758 except for those, if any, in the classes indicated by EXCLUDE.
759 (There is no point in putting DC_SYSTEM in EXCLUDE as
760 dictionaries never include system variables.) */
762 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
763 size_t *n, enum dict_class exclude)
768 assert (exclude == (exclude & DC_ALL));
771 for (i = 0; i < d->n_vars; i++)
773 enum dict_class class = var_get_dict_class (d->vars[i].var);
774 if (!(class & exclude))
778 *vars = xnmalloc (count, sizeof **vars);
780 for (i = 0; i < d->n_vars; i++)
782 enum dict_class class = var_get_dict_class (d->vars[i].var);
783 if (!(class & exclude))
784 (*vars)[(*n)++] = d->vars[i].var;
786 assert (*n == count);
789 static struct variable *
790 add_var_with_case_index (struct dictionary *d, struct variable *v,
793 struct vardict_info *vardict;
795 /* Update dictionary. */
796 if (d->n_vars >= d->allocated_vars)
800 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
801 hmap_clear (&d->name_map);
802 for (i = 0; i < d->n_vars; i++)
804 var_set_vardict (d->vars[i].var, &d->vars[i]);
805 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
806 d->vars[i].name_node.hash);
810 vardict = &d->vars[d->n_vars++];
813 hmap_insert (&d->name_map, &vardict->name_node,
814 utf8_hash_case_string (var_get_name (v), 0));
815 vardict->case_index = case_index;
816 var_set_vardict (v, vardict);
818 if (d->changed) d->changed (d, d->changed_data);
819 if (d->callbacks && d->callbacks->var_added)
820 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
822 invalidate_proto (d);
827 static struct variable *
828 add_var (struct dictionary *d, struct variable *v)
830 return add_var_with_case_index (d, v, dict_get_n_vars (d));
833 /* Creates and returns a new variable in D with the given NAME
834 and WIDTH. Returns a null pointer if the given NAME would
835 duplicate that of an existing variable in the dictionary. */
837 dict_create_var (struct dictionary *d, const char *name, int width)
839 return (dict_lookup_var (d, name) == NULL
840 ? dict_create_var_assert (d, name, width)
844 /* Creates and returns a new variable in D with the given NAME
845 and WIDTH. Assert-fails if the given NAME would duplicate
846 that of an existing variable in the dictionary. */
848 dict_create_var_assert (struct dictionary *d, const char *name, int width)
850 assert (dict_lookup_var (d, name) == NULL);
851 return add_var (d, var_create (name, width));
854 /* Creates and returns a new variable in D, as a copy of existing variable
855 OLD_VAR, which need not be in D or in any dictionary. Returns a null
856 pointer if OLD_VAR's name would duplicate that of an existing variable in
859 dict_clone_var (struct dictionary *d, const struct variable *old_var)
861 return dict_clone_var_as (d, old_var, var_get_name (old_var));
864 /* Creates and returns a new variable in D, as a copy of existing variable
865 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
866 OLD_VAR's name would duplicate that of an existing variable in the
869 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
871 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
874 /* Creates and returns a new variable in D with name NAME, as a copy of
875 existing variable OLD_VAR, which need not be in D or in any dictionary.
876 Returns a null pointer if the given NAME would duplicate that of an existing
877 variable in the dictionary. */
879 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
882 return (dict_lookup_var (d, name) == NULL
883 ? dict_clone_var_as_assert (d, old_var, name)
887 /* Creates and returns a new variable in D with name NAME, as a copy of
888 existing variable OLD_VAR, which need not be in D or in any dictionary.
889 Assert-fails if the given NAME would duplicate that of an existing variable
890 in the dictionary. */
892 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
895 struct variable *new_var = var_clone (old_var);
896 assert (dict_lookup_var (d, name) == NULL);
897 var_set_name (new_var, name);
898 return add_var (d, new_var);
902 dict_clone_var_in_place_assert (struct dictionary *d,
903 const struct variable *old_var)
905 assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
906 return add_var_with_case_index (d, var_clone (old_var),
907 var_get_case_index (old_var));
910 /* Returns the variable named NAME in D, or a null pointer if no
911 variable has that name. */
913 dict_lookup_var (const struct dictionary *d, const char *name)
915 struct vardict_info *vardict;
917 HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
918 utf8_hash_case_string (name, 0), &d->name_map)
920 struct variable *var = vardict->var;
921 if (!utf8_strcasecmp (var_get_name (var), name))
928 /* Returns the variable named NAME in D. Assert-fails if no
929 variable has that name. */
931 dict_lookup_var_assert (const struct dictionary *d, const char *name)
933 struct variable *v = dict_lookup_var (d, name);
938 /* Returns true if variable V is in dictionary D,
941 dict_contains_var (const struct dictionary *d, const struct variable *v)
943 return (var_has_vardict (v)
944 && vardict_get_dictionary (var_get_vardict (v)) == d);
947 /* Moves V to 0-based position IDX in D. Other variables in D,
948 if any, retain their relative positions. Runs in time linear
949 in the distance moved. */
951 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
953 assert (new_index < d->n_vars);
955 size_t old_index = var_get_dict_index (v);
956 if (new_index == old_index)
959 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
960 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
961 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
964 /* Reorders the variables in D, placing the COUNT variables
965 listed in ORDER in that order at the beginning of D. The
966 other variables in D, if any, retain their relative
969 dict_reorder_vars (struct dictionary *d,
970 struct variable *const *order, size_t count)
972 struct vardict_info *new_var;
975 assert (count == 0 || order != NULL);
976 assert (count <= d->n_vars);
978 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
980 /* Add variables in ORDER to new_var. */
981 for (i = 0; i < count; i++)
983 struct vardict_info *old_var;
985 assert (dict_contains_var (d, order[i]));
987 old_var = var_get_vardict (order[i]);
988 new_var[i] = *old_var;
989 old_var->dict = NULL;
992 /* Add remaining variables to new_var. */
993 for (i = 0; i < d->n_vars; i++)
994 if (d->vars[i].dict != NULL)
995 new_var[count++] = d->vars[i];
996 assert (count == d->n_vars);
998 /* Replace old vardicts by new ones. */
1002 hmap_clear (&d->name_map);
1003 reindex_vars (d, 0, d->n_vars, false);
1006 /* Changes the name of variable V that is currently in a dictionary to
1009 rename_var (struct variable *v, const char *new_name)
1011 struct vardict_info *vardict = var_get_vardict (v);
1012 var_clear_vardict (v);
1013 var_set_name (v, new_name);
1014 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
1015 var_set_vardict (v, vardict);
1018 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
1019 successful, false if a variable (other than V) with the given name already
1022 dict_try_rename_var (struct dictionary *d, struct variable *v,
1023 const char *new_name)
1025 struct variable *conflict = dict_lookup_var (d, new_name);
1026 if (conflict && v != conflict)
1029 struct variable *old = var_clone (v);
1030 unindex_var (d, var_get_vardict (v));
1031 rename_var (v, new_name);
1032 reindex_var (d, var_get_vardict (v), false);
1034 if (settings_get_algorithm () == ENHANCED)
1035 var_clear_short_names (v);
1037 if (d->changed) d->changed (d, d->changed_data);
1038 if (d->callbacks && d->callbacks->var_changed)
1039 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1046 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1047 a variable named NEW_NAME is already in D, except that
1048 NEW_NAME may be the same as V's existing name. */
1050 dict_rename_var (struct dictionary *d, struct variable *v,
1051 const char *new_name)
1053 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1057 /* Renames COUNT variables specified in VARS to the names given
1058 in NEW_NAMES within dictionary D. If the renaming would
1059 result in a duplicate variable name, returns false and stores a
1060 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1061 non-null). Otherwise, the renaming is successful, and true
1064 dict_rename_vars (struct dictionary *d,
1065 struct variable **vars, char **new_names, size_t count,
1072 assert (count == 0 || vars != NULL);
1073 assert (count == 0 || new_names != NULL);
1075 /* Save the names of the variables to be renamed. */
1076 pool = pool_create ();
1077 old_names = pool_nalloc (pool, count, sizeof *old_names);
1078 for (i = 0; i < count; i++)
1079 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1081 /* Remove the variables to be renamed from the name hash,
1083 for (i = 0; i < count; i++)
1085 unindex_var (d, var_get_vardict (vars[i]));
1086 rename_var (vars[i], new_names[i]);
1089 /* Add the renamed variables back into the name hash,
1090 checking for conflicts. */
1091 for (i = 0; i < count; i++)
1093 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1095 /* There is a name conflict.
1096 Back out all the name changes that have already
1097 taken place, and indicate failure. */
1098 size_t fail_idx = i;
1099 if (err_name != NULL)
1100 *err_name = new_names[i];
1102 for (i = 0; i < fail_idx; i++)
1103 unindex_var (d, var_get_vardict (vars[i]));
1105 for (i = 0; i < count; i++)
1107 rename_var (vars[i], old_names[i]);
1108 reindex_var (d, var_get_vardict (vars[i]), false);
1111 pool_destroy (pool);
1114 reindex_var (d, var_get_vardict (vars[i]), false);
1117 /* Clear short names. */
1118 if (settings_get_algorithm () == ENHANCED)
1119 for (i = 0; i < count; i++)
1120 var_clear_short_names (vars[i]);
1122 pool_destroy (pool);
1126 /* Returns true if a variable named NAME may be inserted in DICT;
1127 that is, if there is not already a variable with that name in
1128 DICT and if NAME is not a reserved word. (The caller's checks
1129 have already verified that NAME is otherwise acceptable as a
1132 var_name_is_insertable (const struct dictionary *dict, const char *name)
1134 return (dict_lookup_var (dict, name) == NULL
1135 && lex_id_to_token (ss_cstr (name)) == T_ID);
1139 make_hinted_name (const struct dictionary *dict, const char *hint)
1141 size_t hint_len = strlen (hint);
1142 bool dropped = false;
1147 if (hint_len > ID_MAX_LEN)
1148 hint_len = ID_MAX_LEN;
1150 /* The allocation size here is OK: characters that are copied directly fit
1151 OK, and characters that are not copied directly are replaced by a single
1152 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1153 replaced by '_' too. */
1154 root = rp = xmalloc (hint_len + 1);
1155 for (ofs = 0; ofs < hint_len; ofs += mblen)
1159 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1162 ? lex_uc_is_id1 (uc) && uc != '$'
1163 : lex_uc_is_idn (uc))
1170 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1172 else if (rp != root)
1177 if (root[0] != '\0')
1179 unsigned long int i;
1181 if (var_name_is_insertable (dict, root))
1184 for (i = 0; i < ULONG_MAX; i++)
1186 char suffix[INT_BUFSIZE_BOUND (i) + 1];
1190 if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1193 name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1194 if (var_name_is_insertable (dict, name))
1209 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1211 unsigned long int number;
1213 for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1217 char name[3 + INT_STRLEN_BOUND (number) + 1];
1219 sprintf (name, "VAR%03lu", number);
1220 if (dict_lookup_var (dict, name) == NULL)
1222 if (num_start != NULL)
1223 *num_start = number + 1;
1224 return xstrdup (name);
1232 /* Devises and returns a variable name unique within DICT. The variable name
1233 is owned by the caller, which must free it with free() when it is no longer
1236 HINT, if it is non-null, is used as a suggestion that will be
1237 modified for suitability as a variable name and for
1240 If HINT is null or entirely unsuitable, a name in the form
1241 "VAR%03d" will be generated, where the smallest unused integer
1242 value is used. If NUM_START is non-null, then its value is
1243 used as the minimum numeric value to check, and it is updated
1244 to the next value to be checked.
1247 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1248 unsigned long int *num_start)
1252 char *hinted_name = make_hinted_name (dict, hint);
1253 if (hinted_name != NULL)
1257 return make_numeric_name (dict, num_start);
1260 /* Returns whether variable names must be valid identifiers. Normally, this is
1261 true, but sometimes a dictionary is prepared for external use (e.g. output
1262 to a CSV file) where names don't have to be valid. */
1264 dict_get_names_must_be_ids (const struct dictionary *d)
1266 return d->names_must_be_ids;
1269 /* Sets whether variable names must be valid identifiers. Normally, this is
1270 true, but sometimes a dictionary is prepared for external use (e.g. output
1271 to a CSV file) where names don't have to be valid.
1273 Changing this setting from false to true doesn't make the dictionary check
1274 all the existing variable names, so it can cause an invariant violation. */
1276 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1278 d->names_must_be_ids = names_must_be_ids;
1281 /* Returns the weighting variable in dictionary D, or a null
1282 pointer if the dictionary is unweighted. */
1284 dict_get_weight (const struct dictionary *d)
1286 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1291 /* Returns the value of D's weighting variable in case C, except
1292 that a negative or missing weight is returned as 0. Returns 1 if the
1293 dictionary is unweighted. Will warn about missing, negative,
1294 or zero values if *WARN_ON_INVALID is true. The function will
1295 set *WARN_ON_INVALID to false if an invalid weight is
1298 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1299 bool *warn_on_invalid)
1303 if (d->weight == NULL)
1307 double w = case_num (c, d->weight);
1309 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1313 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1316 dict_get_rounded_case_weight (const struct dictionary *d,
1317 const struct ccase *c, bool *warn_on_invalid)
1319 return floor (dict_get_case_weight (d, c, warn_on_invalid) + 0.5);
1322 /* Returns the format to use for weights. */
1324 dict_get_weight_format (const struct dictionary *d)
1326 return d->weight ? var_get_print_format (d->weight) : F_8_0;
1329 /* Sets the weighting variable of D to V, or turning off
1330 weighting if V is a null pointer. */
1332 dict_set_weight (struct dictionary *d, struct variable *v)
1334 assert (v == NULL || dict_contains_var (d, v));
1335 assert (v == NULL || var_is_numeric (v));
1339 if (d->changed) d->changed (d, d->changed_data);
1340 if (d->callbacks && d->callbacks->weight_changed)
1341 d->callbacks->weight_changed (d,
1342 v ? var_get_dict_index (v) : -1,
1346 /* Returns the filter variable in dictionary D (see cmd_filter())
1347 or a null pointer if the dictionary is unfiltered. */
1349 dict_get_filter (const struct dictionary *d)
1351 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1356 /* Sets V as the filter variable for dictionary D. Passing a
1357 null pointer for V turn off filtering. */
1359 dict_set_filter (struct dictionary *d, struct variable *v)
1361 assert (v == NULL || dict_contains_var (d, v));
1362 assert (v == NULL || var_is_numeric (v));
1366 if (d->changed) d->changed (d, d->changed_data);
1367 if (d->callbacks && d->callbacks->filter_changed)
1368 d->callbacks->filter_changed (d,
1369 v ? var_get_dict_index (v) : -1,
1373 /* Returns the case limit for dictionary D, or zero if the number
1374 of cases is unlimited. */
1376 dict_get_case_limit (const struct dictionary *d)
1378 return d->case_limit;
1381 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1382 0 for CASE_LIMIT to indicate no limit. */
1384 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1386 d->case_limit = case_limit;
1389 /* Returns the prototype used for cases created by dictionary D. */
1390 const struct caseproto *
1391 dict_get_proto (const struct dictionary *d_)
1393 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1394 if (d->proto == NULL)
1396 short int *widths = xnmalloc (d->n_vars, sizeof *widths);
1397 for (size_t i = 0; i < d->n_vars; i++)
1399 for (size_t i = 0; i < d->n_vars; i++)
1401 const struct variable *var = d->vars[i].var;
1402 size_t case_idx = var_get_case_index (var);
1403 assert (case_idx < d->n_vars);
1404 assert (widths[case_idx] == -1);
1405 widths[case_idx] = var_get_width (var);
1408 d->proto = caseproto_from_widths (widths, d->n_vars);
1413 /* Reassigns values in dictionary D so that fragmentation is
1416 dict_compact_values (struct dictionary *d)
1418 for (size_t i = 0; i < d->n_vars; i++)
1420 struct variable *v = d->vars[i].var;
1421 set_var_case_index (v, i);
1423 invalidate_proto (d);
1426 /* Returns the number of values occupied by the variables in
1427 dictionary D. All variables are considered if EXCLUDE_CLASSES
1428 is 0, or it may contain one or more of DC_ORDINARY, DC_SYSTEM,
1429 or DC_SCRATCH to exclude the corresponding type of variable. */
1431 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1433 assert (!(exclude_classes & ~DC_ALL));
1436 for (size_t i = 0; i < d->n_vars; i++)
1438 enum dict_class class = var_get_dict_class (d->vars[i].var);
1439 if (!(exclude_classes & class))
1445 /* Returns the file label for D, or a null pointer if D is
1446 unlabeled (see cmd_file_label()). */
1448 dict_get_label (const struct dictionary *d)
1453 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1456 Removes D's label if LABEL is null or the empty string. */
1458 dict_set_label (struct dictionary *d, const char *label)
1461 if (label == NULL || label[0] == '\0')
1464 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1467 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1468 return value is always nonnull; if there are no documents then the
1469 string_arary is empty.*/
1470 const struct string_array *
1471 dict_get_documents (const struct dictionary *d)
1473 return &d->documents;
1476 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1478 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1480 /* Swap out the old documents, instead of destroying them immediately, to
1481 allow the new documents to include pointers into the old ones. */
1482 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1483 string_array_swap (&d->documents, &old_docs);
1485 for (size_t i = 0; i < new_docs->n; i++)
1486 dict_add_document_line (d, new_docs->strings[i], false);
1488 string_array_destroy (&old_docs);
1491 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1492 into individual lines at new-line characters. Each line is truncated to at
1493 most DOC_LINE_LENGTH bytes in D's encoding. */
1495 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1499 dict_clear_documents (d);
1500 for (s = new_docs; *s != '\0';)
1502 size_t len = strcspn (s, "\n");
1503 char *line = xmemdup0 (s, len);
1504 dict_add_document_line (d, line, false);
1513 /* Drops the documents from dictionary D. */
1515 dict_clear_documents (struct dictionary *d)
1517 string_array_clear (&d->documents);
1520 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1521 truncated so that it is no more than 80 bytes in the dictionary's
1522 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1523 then a warning will be issued. */
1525 dict_add_document_line (struct dictionary *d, const char *line,
1531 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1532 truncated = line[trunc_len] != '\0';
1533 if (truncated && issue_warning)
1535 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1536 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1539 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1544 /* Returns the number of document lines in dictionary D. */
1546 dict_get_document_n_lines (const struct dictionary *d)
1548 return d->documents.n;
1551 /* Returns document line number IDX in dictionary D. The caller must not
1552 modify or free the returned string. */
1554 dict_get_document_line (const struct dictionary *d, size_t idx)
1556 assert (idx < d->documents.n);
1557 return d->documents.strings[idx];
1560 /* Creates in D a vector named NAME that contains the N
1561 variables in VAR. Returns true if successful, or false if a
1562 vector named NAME already exists in D. */
1564 dict_create_vector (struct dictionary *d,
1566 struct variable **var, size_t n)
1569 for (size_t i = 0; i < n; i++)
1570 assert (dict_contains_var (d, var[i]));
1572 if (dict_lookup_vector (d, name) == NULL)
1574 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1575 d->vector[d->n_vectors++] = vector_create (name, var, n);
1582 /* Creates in D a vector named NAME that contains the N
1583 variables in VAR. A vector named NAME must not already exist
1586 dict_create_vector_assert (struct dictionary *d,
1588 struct variable **var, size_t n)
1590 assert (dict_lookup_vector (d, name) == NULL);
1591 dict_create_vector (d, name, var, n);
1594 /* Returns the vector in D with index IDX, which must be less
1595 than dict_get_n_vectors (D). */
1596 const struct vector *
1597 dict_get_vector (const struct dictionary *d, size_t idx)
1599 assert (idx < d->n_vectors);
1601 return d->vector[idx];
1604 /* Returns the number of vectors in D. */
1606 dict_get_n_vectors (const struct dictionary *d)
1608 return d->n_vectors;
1611 /* Looks up and returns the vector within D with the given
1613 const struct vector *
1614 dict_lookup_vector (const struct dictionary *d, const char *name)
1617 for (i = 0; i < d->n_vectors; i++)
1618 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1619 return d->vector[i];
1623 /* Deletes all vectors from D. */
1625 dict_clear_vectors (struct dictionary *d)
1629 for (i = 0; i < d->n_vectors; i++)
1630 vector_destroy (d->vector[i]);
1637 /* Multiple response sets. */
1639 /* Returns the multiple response set in DICT with index IDX, which must be
1640 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1641 const struct mrset *
1642 dict_get_mrset (const struct dictionary *dict, size_t idx)
1644 assert (idx < dict->n_mrsets);
1645 return dict->mrsets[idx];
1648 /* Returns the number of multiple response sets in DICT. */
1650 dict_get_n_mrsets (const struct dictionary *dict)
1652 return dict->n_mrsets;
1655 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1656 returns its index; otherwise, returns SIZE_MAX. */
1658 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1662 for (i = 0; i < dict->n_mrsets; i++)
1663 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1669 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1670 returns it; otherwise, returns NULL. */
1671 const struct mrset *
1672 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1674 size_t idx = dict_lookup_mrset_idx (dict, name);
1675 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1678 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1679 true if a set was replaced, false if none existed with the specified name.
1681 Ownership of MRSET is transferred to DICT. */
1683 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1687 assert (mrset_ok (mrset, dict));
1689 idx = dict_lookup_mrset_idx (dict, mrset->name);
1690 if (idx == SIZE_MAX)
1692 dict->mrsets = xrealloc (dict->mrsets,
1693 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1694 dict->mrsets[dict->n_mrsets++] = mrset;
1699 mrset_destroy (dict->mrsets[idx]);
1700 dict->mrsets[idx] = mrset;
1705 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1706 from DICT and returns true. If none is found, returns false without
1709 Deleting one multiple response set causes the indexes of other sets within
1712 dict_delete_mrset (struct dictionary *dict, const char *name)
1714 size_t idx = dict_lookup_mrset_idx (dict, name);
1715 if (idx != SIZE_MAX)
1717 mrset_destroy (dict->mrsets[idx]);
1718 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1725 /* Deletes all multiple response sets from DICT. */
1727 dict_clear_mrsets (struct dictionary *dict)
1731 for (i = 0; i < dict->n_mrsets; i++)
1732 mrset_destroy (dict->mrsets[i]);
1733 free (dict->mrsets);
1734 dict->mrsets = NULL;
1738 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1740 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1744 assert (dict_contains_var (dict, var));
1746 for (i = 0; i < dict->n_mrsets;)
1748 struct mrset *mrset = dict->mrsets[i];
1751 for (j = 0; j < mrset->n_vars;)
1752 if (mrset->vars[j] == var)
1753 remove_element (mrset->vars, mrset->n_vars--,
1754 sizeof *mrset->vars, j);
1758 if (mrset->n_vars < 2)
1760 mrset_destroy (mrset);
1761 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1769 /* Returns the variable set in DICT with index IDX, which must be between 0 and
1770 the count returned by dict_get_n_varsets(), exclusive. */
1771 const struct varset *
1772 dict_get_varset (const struct dictionary *dict, size_t idx)
1774 assert (idx < dict->n_varsets);
1775 return dict->varsets[idx];
1778 /* Returns the number of variable sets in DICT. */
1780 dict_get_n_varsets (const struct dictionary *dict)
1782 return dict->n_varsets;
1785 /* Looks for a variable set named NAME in DICT. If it finds one, returns its
1786 index; otherwise, returns SIZE_MAX. */
1788 dict_lookup_varset_idx (const struct dictionary *dict, const char *name)
1790 for (size_t i = 0; i < dict->n_varsets; i++)
1791 if (!utf8_strcasecmp (name, dict->varsets[i]->name))
1797 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1798 returns it; otherwise, returns NULL. */
1799 const struct varset *
1800 dict_lookup_varset (const struct dictionary *dict, const char *name)
1802 size_t idx = dict_lookup_varset_idx (dict, name);
1803 return idx != SIZE_MAX ? dict->varsets[idx] : NULL;
1806 /* Adds VARSET to DICT, replacing any existing set with the same name. Returns
1807 true if a set was replaced, false if none existed with the specified name.
1809 Ownership of VARSET is transferred to DICT. */
1811 dict_add_varset (struct dictionary *dict, struct varset *varset)
1813 size_t idx = dict_lookup_varset_idx (dict, varset->name);
1814 if (idx == SIZE_MAX)
1816 dict->varsets = xrealloc (dict->varsets,
1817 (dict->n_varsets + 1) * sizeof *dict->varsets);
1818 dict->varsets[dict->n_varsets++] = varset;
1823 varset_destroy (dict->varsets[idx]);
1824 dict->varsets[idx] = varset;
1829 /* Deletes all variable sets from DICT. */
1831 dict_clear_varsets (struct dictionary *dict)
1833 for (size_t i = 0; i < dict->n_varsets; i++)
1834 varset_destroy (dict->varsets[i]);
1835 free (dict->varsets);
1836 dict->varsets = NULL;
1837 dict->n_varsets = 0;
1840 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1842 dict_unset_varset_var (struct dictionary *dict, struct variable *var)
1844 assert (dict_contains_var (dict, var));
1846 for (size_t i = 0; i < dict->n_varsets; i++)
1848 struct varset *varset = dict->varsets[i];
1850 for (size_t j = 0; j < varset->n_vars;)
1851 if (varset->vars[j] == var)
1852 remove_element (varset->vars, varset->n_vars--,
1853 sizeof *varset->vars, j);
1859 /* Returns D's attribute set. The caller may examine or modify
1860 the attribute set, but must not destroy it. Destroying D or
1861 calling dict_set_attributes for D will also destroy D's
1864 dict_get_attributes (const struct dictionary *d)
1866 return CONST_CAST (struct attrset *, &d->attributes);
1869 /* Replaces D's attributes set by a copy of ATTRS. */
1871 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1873 attrset_destroy (&d->attributes);
1874 attrset_clone (&d->attributes, attrs);
1877 /* Returns true if D has at least one attribute in its attribute
1878 set, false if D's attribute set is empty. */
1880 dict_has_attributes (const struct dictionary *d)
1882 return attrset_count (&d->attributes) > 0;
1885 /* Called from variable.c to notify the dictionary that some property (indicated
1886 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1887 prior to the change. OLDVAR is destroyed by this function.
1890 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1892 if (var_has_vardict (v))
1894 const struct vardict_info *vardict = var_get_vardict (v);
1895 struct dictionary *d = vardict->dict;
1900 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1901 invalidate_proto (d);
1903 if (d->changed) d->changed (d, d->changed_data);
1904 if (d->callbacks && d->callbacks->var_changed)
1905 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1913 vardict_get_dict_index (const struct vardict_info *vardict)
1915 return vardict - vardict->dict->vars;