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 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
183 encoding. Returns true if it is, otherwise an error message that the caller
185 char * WARN_UNUSED_RESULT
186 dict_id_is_valid__ (const struct dictionary *dict, const char *id)
188 if (!dict->names_must_be_ids)
190 return id_is_valid__ (id, dict->encoding);
194 error_to_bool (char *error)
205 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
206 encoding, false otherwise. */
208 dict_id_is_valid (const struct dictionary *dict, const char *id)
210 return error_to_bool (dict_id_is_valid__ (dict, id));
214 dict_set_change_callback (struct dictionary *d,
215 void (*changed) (struct dictionary *, void*),
218 d->changed = changed;
219 d->changed_data = data;
222 /* Discards dictionary D's caseproto. (It will be regenerated
223 lazily, on demand.) */
225 invalidate_proto (struct dictionary *d)
227 caseproto_unref (d->proto);
231 /* Print a representation of dictionary D to stdout, for
232 debugging purposes. */
234 dict_dump (const struct dictionary *d)
237 for (i = 0 ; i < d->n_vars ; ++i)
239 const struct variable *v = d->vars[i].var;
240 printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
242 var_get_dict_index (v),
243 var_get_case_index (v));
248 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
249 the dictionary or any of the variables it contains are modified.
250 Each callback will get passed CALLBACK_DATA.
251 Any callback may be NULL, in which case it'll be ignored.
254 dict_set_callbacks (struct dictionary *dict,
255 const struct dict_callbacks *callbacks,
258 dict->callbacks = callbacks;
259 dict->cb_data = callback_data;
262 /* Shallow copy the callbacks from SRC to DEST */
264 dict_copy_callbacks (struct dictionary *dest,
265 const struct dictionary *src)
267 dest->callbacks = src->callbacks;
268 dest->cb_data = src->cb_data;
271 /* Creates and returns a new dictionary with the specified ENCODING. */
273 dict_create (const char *encoding)
275 struct dictionary *d = xmalloc (sizeof *d);
277 *d = (struct dictionary) {
278 .encoding = xstrdup (encoding),
279 .names_must_be_ids = true,
280 .name_map = HMAP_INITIALIZER (d->name_map),
281 .attributes = ATTRSET_INITIALIZER (d->attributes),
282 .split_type = SPLIT_NONE,
289 /* Creates and returns a (deep) copy of an existing
292 The new dictionary's case indexes are copied from the old
293 dictionary. If the new dictionary won't be used to access
294 cases produced with the old dictionary, then the new
295 dictionary's case indexes should be compacted with
296 dict_compact_values to save space.
298 Callbacks are not cloned. */
300 dict_clone (const struct dictionary *s)
302 struct dictionary *d;
305 d = dict_create (s->encoding);
306 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
308 for (i = 0; i < s->n_vars; i++)
310 struct variable *sv = s->vars[i].var;
311 struct variable *dv = dict_clone_var_assert (d, sv);
314 for (i = 0; i < var_get_n_short_names (sv); i++)
315 var_set_short_name (dv, i, var_get_short_name (sv, i));
317 var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
320 d->next_value_idx = s->next_value_idx;
322 d->n_splits = s->n_splits;
325 d->split = xnmalloc (d->n_splits, sizeof *d->split);
326 for (i = 0; i < d->n_splits; i++)
327 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
329 d->split_type = s->split_type;
331 if (s->weight != NULL)
332 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
334 if (s->filter != NULL)
335 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
337 d->case_limit = s->case_limit;
338 dict_set_label (d, dict_get_label (s));
339 dict_set_documents (d, dict_get_documents (s));
341 d->n_vectors = s->n_vectors;
342 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
343 for (i = 0; i < s->n_vectors; i++)
344 d->vector[i] = vector_clone (s->vector[i], s, d);
346 dict_set_attributes (d, dict_get_attributes (s));
348 for (i = 0; i < s->n_mrsets; i++)
350 const struct mrset *old = s->mrsets[i];
354 /* Clone old mrset, then replace vars from D by vars from S. */
355 new = mrset_clone (old);
356 for (j = 0; j < new->n_vars; j++)
357 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
359 dict_add_mrset (d, new);
367 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
368 dict_get_n_splits() to determine how many SPLIT FILE vars
369 there are. Returns a null pointer if and only if there are no
371 const struct variable *const *
372 dict_get_split_vars (const struct dictionary *d)
377 /* Returns the number of SPLIT FILE vars. */
379 dict_get_n_splits (const struct dictionary *d)
384 /* Removes variable V, which must be in D, from D's set of split
387 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
391 assert (dict_contains_var (d, v));
393 orig_count = d->n_splits;
394 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
395 &v, compare_var_ptrs, NULL);
396 if (orig_count != d->n_splits && !skip_callbacks)
398 if (d->changed) d->changed (d, d->changed_data);
399 /* We changed the set of split variables so invoke the
401 if (d->callbacks && d->callbacks->split_changed)
402 d->callbacks->split_changed (d, d->cb_data);
407 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
410 dict_set_split_vars__ (struct dictionary *d,
411 struct variable *const *split, size_t n,
412 enum split_type type, bool skip_callbacks)
416 assert (n == 0 || split != NULL);
419 d->split_type = (n == 0 ? SPLIT_NONE
420 : type == SPLIT_NONE ? SPLIT_LAYERED
424 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
425 memcpy (d->split, split, n * sizeof *d->split);
435 if (d->changed) d->changed (d, d->changed_data);
436 if (d->callbacks && d->callbacks->split_changed)
437 d->callbacks->split_changed (d, d->cb_data);
442 dict_get_split_type (const struct dictionary *d)
444 return d->split_type;
447 /* Sets N split vars SPLIT in dictionary D. */
449 dict_set_split_vars (struct dictionary *d,
450 struct variable *const *split, size_t n,
451 enum split_type type)
453 dict_set_split_vars__ (d, split, n, type, false);
457 dict_clear_split_vars (struct dictionary *d)
459 dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
463 /* Deletes variable V from dictionary D and frees V.
465 This is a very bad idea if there might be any pointers to V
466 from outside D. In general, no variable in the active dataset's
467 dictionary should be deleted when any transformations are
468 active on the dictionary's dataset, because those
469 transformations might reference the deleted variable. The
470 safest time to delete a variable is just after a procedure has
471 been executed, as done by DELETE VARIABLES.
473 Pointers to V within D are not a problem, because
474 dict_delete_var() knows to remove V from split variables,
475 weights, filters, etc. */
477 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
479 int dict_index = var_get_dict_index (v);
480 const int case_index = var_get_case_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);
488 dict_set_weight (d, NULL);
491 dict_set_filter (d, NULL);
493 dict_clear_vectors (d);
495 /* Remove V from var array. */
496 unindex_vars (d, dict_index, d->n_vars);
497 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
500 /* Update dict_index for each affected variable. */
501 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
504 var_clear_vardict (v);
506 if (! skip_callbacks)
508 if (d->changed) d->changed (d, d->changed_data);
509 if (d->callbacks && d->callbacks->var_deleted)
510 d->callbacks->var_deleted (d, v, dict_index, case_index, d->cb_data);
513 invalidate_proto (d);
517 /* Deletes variable V from dictionary D and frees V.
519 This is a very bad idea if there might be any pointers to V
520 from outside D. In general, no variable in the active dataset's
521 dictionary should be deleted when any transformations are
522 active on the dictionary's dataset, because those
523 transformations might reference the deleted variable. The
524 safest time to delete a variable is just after a procedure has
525 been executed, as done by DELETE VARIABLES.
527 Pointers to V within D are not a problem, because
528 dict_delete_var() knows to remove V from split variables,
529 weights, filters, etc. */
531 dict_delete_var (struct dictionary *d, struct variable *v)
533 dict_delete_var__ (d, v, false);
537 /* Deletes the COUNT variables listed in VARS from D. This is
538 unsafe; see the comment on dict_delete_var() for details. */
540 dict_delete_vars (struct dictionary *d,
541 struct variable *const *vars, size_t count)
543 /* FIXME: this can be done in O(count) time, but this algorithm
545 assert (count == 0 || vars != NULL);
548 dict_delete_var (d, *vars++);
551 /* Deletes the COUNT variables in D starting at index IDX. This
552 is unsafe; see the comment on dict_delete_var() for
553 details. Deleting consecutive vars will result in less callbacks
554 compared to iterating over dict_delete_var.
555 A simple while loop over dict_delete_var will
556 produce (d->n_vars - IDX) * COUNT variable changed callbacks
557 plus COUNT variable delete callbacks.
558 This here produces d->n_vars - IDX variable changed callbacks
559 plus COUNT variable delete callbacks. */
561 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
563 assert (idx + count <= d->n_vars);
565 /* We need to store the variable and the corresponding case_index
566 for the delete callbacks later. We store them in a linked list.*/
569 struct variable *var;
572 struct ll_list list = LL_INITIALIZER (list);
574 for (size_t i = idx; i < idx + count; i++)
576 struct delvar *dv = xmalloc (sizeof (struct delvar));
578 struct variable *v = d->vars[i].var;
580 dict_unset_split_var (d, v, false);
581 dict_unset_mrset_var (d, v);
584 dict_set_weight (d, NULL);
587 dict_set_filter (d, NULL);
590 dv->case_index = var_get_case_index (v);
591 ll_push_tail (&list, (struct ll *)dv);
594 dict_clear_vectors (d);
596 /* Remove variables from var array. */
597 unindex_vars (d, idx, d->n_vars);
598 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
601 /* Reindexing will result variable-changed callback */
602 reindex_vars (d, idx, d->n_vars, false);
604 invalidate_proto (d);
605 if (d->changed) d->changed (d, d->changed_data);
607 /* Now issue the variable delete callbacks and delete
608 the variables. The vardict is not valid at this point
609 anymore. That is the reason why we stored the
610 caseindex before reindexing. */
611 for (size_t vi = idx; vi < idx + count; vi++)
613 struct delvar *dv = (struct delvar *) ll_pop_head (&list);
614 var_clear_vardict (dv->var);
615 if (d->callbacks && d->callbacks->var_deleted)
616 d->callbacks->var_deleted (d, dv->var, vi, dv->case_index, d->cb_data);
622 /* Deletes scratch variables from dictionary D. */
624 dict_delete_scratch_vars (struct dictionary *d)
628 /* FIXME: this can be done in O(count) time, but this algorithm
630 for (i = 0; i < d->n_vars;)
631 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
632 dict_delete_var (d, d->vars[i].var);
639 /* Clears the contents from a dictionary without destroying the
640 dictionary itself. */
642 dict_clear__ (struct dictionary *d, bool skip_callbacks)
644 /* FIXME? Should we really clear case_limit, label, documents?
645 Others are necessarily cleared by deleting all the variables.*/
646 while (d->n_vars > 0)
648 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
653 d->n_vars = d->allocated_vars = 0;
654 invalidate_proto (d);
655 hmap_clear (&d->name_map);
656 d->next_value_idx = 0;
657 dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
666 dict_set_weight (d, NULL);
667 dict_set_filter (d, NULL);
672 string_array_clear (&d->documents);
673 dict_clear_vectors (d);
674 attrset_clear (&d->attributes);
677 /* Clears the contents from a dictionary without destroying the
678 dictionary itself. */
680 dict_clear (struct dictionary *d)
682 dict_clear__ (d, false);
685 /* Clears a dictionary and destroys it. */
687 _dict_destroy (struct dictionary *d)
689 /* In general, we don't want callbacks occurring, if the dictionary
690 is being destroyed */
691 d->callbacks = NULL ;
693 dict_clear__ (d, true);
694 string_array_destroy (&d->documents);
695 hmap_destroy (&d->name_map);
696 attrset_destroy (&d->attributes);
697 dict_clear_mrsets (d);
703 dict_ref (struct dictionary *d)
710 dict_unref (struct dictionary *d)
715 assert (d->ref_cnt >= 0);
720 /* Returns the number of variables in D. */
722 dict_get_n_vars (const struct dictionary *d)
727 /* Returns the variable in D with dictionary index IDX, which
728 must be between 0 and the count returned by
729 dict_get_n_vars(), exclusive. */
731 dict_get_var (const struct dictionary *d, size_t idx)
733 assert (idx < d->n_vars);
735 return d->vars[idx].var;
738 /* Sets *VARS to an array of pointers to variables in D and *N
739 to the number of variables in *D. All variables are returned
740 except for those, if any, in the classes indicated by EXCLUDE.
741 (There is no point in putting DC_SYSTEM in EXCLUDE as
742 dictionaries never include system variables.) */
744 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
745 size_t *n, enum dict_class exclude)
747 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
750 /* Sets *VARS to an array of pointers to variables in D and *N
751 to the number of variables in *D. All variables are returned
752 except for those, if any, in the classes indicated by EXCLUDE.
753 (There is no point in putting DC_SYSTEM in EXCLUDE as
754 dictionaries never include system variables.) */
756 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
757 size_t *n, enum dict_class exclude)
762 assert (exclude == (exclude & DC_ALL));
765 for (i = 0; i < d->n_vars; i++)
767 enum dict_class class = var_get_dict_class (d->vars[i].var);
768 if (!(class & exclude))
772 *vars = xnmalloc (count, sizeof **vars);
774 for (i = 0; i < d->n_vars; i++)
776 enum dict_class class = var_get_dict_class (d->vars[i].var);
777 if (!(class & exclude))
778 (*vars)[(*n)++] = d->vars[i].var;
780 assert (*n == count);
783 static struct variable *
784 add_var_with_case_index (struct dictionary *d, struct variable *v,
787 struct vardict_info *vardict;
789 assert (case_index >= d->next_value_idx);
791 /* Update dictionary. */
792 if (d->n_vars >= d->allocated_vars)
796 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
797 hmap_clear (&d->name_map);
798 for (i = 0; i < d->n_vars; i++)
800 var_set_vardict (d->vars[i].var, &d->vars[i]);
801 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
802 d->vars[i].name_node.hash);
806 vardict = &d->vars[d->n_vars++];
809 hmap_insert (&d->name_map, &vardict->name_node,
810 utf8_hash_case_string (var_get_name (v), 0));
811 vardict->case_index = case_index;
812 var_set_vardict (v, vardict);
814 if (d->changed) d->changed (d, d->changed_data);
815 if (d->callbacks && d->callbacks->var_added)
816 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
818 invalidate_proto (d);
819 d->next_value_idx = case_index + 1;
824 static struct variable *
825 add_var (struct dictionary *d, struct variable *v)
827 return add_var_with_case_index (d, v, d->next_value_idx);
830 /* Creates and returns a new variable in D with the given NAME
831 and WIDTH. Returns a null pointer if the given NAME would
832 duplicate that of an existing variable in the dictionary. */
834 dict_create_var (struct dictionary *d, const char *name, int width)
836 return (dict_lookup_var (d, name) == NULL
837 ? dict_create_var_assert (d, name, width)
841 /* Creates and returns a new variable in D with the given NAME
842 and WIDTH. Assert-fails if the given NAME would duplicate
843 that of an existing variable in the dictionary. */
845 dict_create_var_assert (struct dictionary *d, const char *name, int width)
847 assert (dict_lookup_var (d, name) == NULL);
848 return add_var (d, var_create (name, width));
851 /* Creates and returns a new variable in D, as a copy of existing variable
852 OLD_VAR, which need not be in D or in any dictionary. Returns a null
853 pointer if OLD_VAR's name would duplicate that of an existing variable in
856 dict_clone_var (struct dictionary *d, const struct variable *old_var)
858 return dict_clone_var_as (d, old_var, var_get_name (old_var));
861 /* Creates and returns a new variable in D, as a copy of existing variable
862 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
863 OLD_VAR's name would duplicate that of an existing variable in the
866 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
868 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
871 /* Creates and returns a new variable in D with name NAME, as a copy of
872 existing variable OLD_VAR, which need not be in D or in any dictionary.
873 Returns a null pointer if the given NAME would duplicate that of an existing
874 variable in the dictionary. */
876 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
879 return (dict_lookup_var (d, name) == NULL
880 ? dict_clone_var_as_assert (d, old_var, name)
884 /* Creates and returns a new variable in D with name NAME, as a copy of
885 existing variable OLD_VAR, which need not be in D or in any dictionary.
886 Assert-fails if the given NAME would duplicate that of an existing variable
887 in the dictionary. */
889 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
892 struct variable *new_var = var_clone (old_var);
893 assert (dict_lookup_var (d, name) == NULL);
894 var_set_name (new_var, name);
895 return add_var (d, new_var);
899 dict_clone_var_in_place_assert (struct dictionary *d,
900 const struct variable *old_var)
902 assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
903 return add_var_with_case_index (d, var_clone (old_var),
904 var_get_case_index (old_var));
907 /* Returns the variable named NAME in D, or a null pointer if no
908 variable has that name. */
910 dict_lookup_var (const struct dictionary *d, const char *name)
912 struct vardict_info *vardict;
914 HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
915 utf8_hash_case_string (name, 0), &d->name_map)
917 struct variable *var = vardict->var;
918 if (!utf8_strcasecmp (var_get_name (var), name))
925 /* Returns the variable named NAME in D. Assert-fails if no
926 variable has that name. */
928 dict_lookup_var_assert (const struct dictionary *d, const char *name)
930 struct variable *v = dict_lookup_var (d, name);
935 /* Returns true if variable V is in dictionary D,
938 dict_contains_var (const struct dictionary *d, const struct variable *v)
940 return (var_has_vardict (v)
941 && vardict_get_dictionary (var_get_vardict (v)) == d);
944 /* Moves V to 0-based position IDX in D. Other variables in D,
945 if any, retain their relative positions. Runs in time linear
946 in the distance moved. */
948 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
950 size_t old_index = var_get_dict_index (v);
952 assert (new_index < d->n_vars);
954 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
955 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
956 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
959 /* Reorders the variables in D, placing the COUNT variables
960 listed in ORDER in that order at the beginning of D. The
961 other variables in D, if any, retain their relative
964 dict_reorder_vars (struct dictionary *d,
965 struct variable *const *order, size_t count)
967 struct vardict_info *new_var;
970 assert (count == 0 || order != NULL);
971 assert (count <= d->n_vars);
973 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
975 /* Add variables in ORDER to new_var. */
976 for (i = 0; i < count; i++)
978 struct vardict_info *old_var;
980 assert (dict_contains_var (d, order[i]));
982 old_var = var_get_vardict (order[i]);
983 new_var[i] = *old_var;
984 old_var->dict = NULL;
987 /* Add remaining variables to new_var. */
988 for (i = 0; i < d->n_vars; i++)
989 if (d->vars[i].dict != NULL)
990 new_var[count++] = d->vars[i];
991 assert (count == d->n_vars);
993 /* Replace old vardicts by new ones. */
997 hmap_clear (&d->name_map);
998 reindex_vars (d, 0, d->n_vars, false);
1001 /* Changes the name of variable V that is currently in a dictionary to
1004 rename_var (struct variable *v, const char *new_name)
1006 struct vardict_info *vardict = var_get_vardict (v);
1007 var_clear_vardict (v);
1008 var_set_name (v, new_name);
1009 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
1010 var_set_vardict (v, vardict);
1013 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
1014 successful, false if a variable (other than V) with the given name already
1017 dict_try_rename_var (struct dictionary *d, struct variable *v,
1018 const char *new_name)
1020 struct variable *conflict = dict_lookup_var (d, new_name);
1021 if (conflict && v != conflict)
1024 struct variable *old = var_clone (v);
1025 unindex_var (d, var_get_vardict (v));
1026 rename_var (v, new_name);
1027 reindex_var (d, var_get_vardict (v), false);
1029 if (settings_get_algorithm () == ENHANCED)
1030 var_clear_short_names (v);
1032 if (d->changed) d->changed (d, d->changed_data);
1033 if (d->callbacks && d->callbacks->var_changed)
1034 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1041 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1042 a variable named NEW_NAME is already in D, except that
1043 NEW_NAME may be the same as V's existing name. */
1045 dict_rename_var (struct dictionary *d, struct variable *v,
1046 const char *new_name)
1048 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1052 /* Renames COUNT variables specified in VARS to the names given
1053 in NEW_NAMES within dictionary D. If the renaming would
1054 result in a duplicate variable name, returns false and stores a
1055 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1056 non-null). Otherwise, the renaming is successful, and true
1059 dict_rename_vars (struct dictionary *d,
1060 struct variable **vars, char **new_names, size_t count,
1067 assert (count == 0 || vars != NULL);
1068 assert (count == 0 || new_names != NULL);
1070 /* Save the names of the variables to be renamed. */
1071 pool = pool_create ();
1072 old_names = pool_nalloc (pool, count, sizeof *old_names);
1073 for (i = 0; i < count; i++)
1074 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1076 /* Remove the variables to be renamed from the name hash,
1078 for (i = 0; i < count; i++)
1080 unindex_var (d, var_get_vardict (vars[i]));
1081 rename_var (vars[i], new_names[i]);
1084 /* Add the renamed variables back into the name hash,
1085 checking for conflicts. */
1086 for (i = 0; i < count; i++)
1088 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1090 /* There is a name conflict.
1091 Back out all the name changes that have already
1092 taken place, and indicate failure. */
1093 size_t fail_idx = i;
1094 if (err_name != NULL)
1095 *err_name = new_names[i];
1097 for (i = 0; i < fail_idx; i++)
1098 unindex_var (d, var_get_vardict (vars[i]));
1100 for (i = 0; i < count; i++)
1102 rename_var (vars[i], old_names[i]);
1103 reindex_var (d, var_get_vardict (vars[i]), false);
1106 pool_destroy (pool);
1109 reindex_var (d, var_get_vardict (vars[i]), false);
1112 /* Clear short names. */
1113 if (settings_get_algorithm () == ENHANCED)
1114 for (i = 0; i < count; i++)
1115 var_clear_short_names (vars[i]);
1117 pool_destroy (pool);
1121 /* Returns true if a variable named NAME may be inserted in DICT;
1122 that is, if there is not already a variable with that name in
1123 DICT and if NAME is not a reserved word. (The caller's checks
1124 have already verified that NAME is otherwise acceptable as a
1127 var_name_is_insertable (const struct dictionary *dict, const char *name)
1129 return (dict_lookup_var (dict, name) == NULL
1130 && lex_id_to_token (ss_cstr (name)) == T_ID);
1134 make_hinted_name (const struct dictionary *dict, const char *hint)
1136 size_t hint_len = strlen (hint);
1137 bool dropped = false;
1142 if (hint_len > ID_MAX_LEN)
1143 hint_len = ID_MAX_LEN;
1145 /* The allocation size here is OK: characters that are copied directly fit
1146 OK, and characters that are not copied directly are replaced by a single
1147 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1148 replaced by '_' too. */
1149 root = rp = xmalloc (hint_len + 1);
1150 for (ofs = 0; ofs < hint_len; ofs += mblen)
1154 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1157 ? lex_uc_is_id1 (uc) && uc != '$'
1158 : lex_uc_is_idn (uc))
1165 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1167 else if (rp != root)
1172 if (root[0] != '\0')
1174 unsigned long int i;
1176 if (var_name_is_insertable (dict, root))
1179 for (i = 0; i < ULONG_MAX; i++)
1181 char suffix[INT_BUFSIZE_BOUND (i) + 1];
1185 if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1188 name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1189 if (var_name_is_insertable (dict, name))
1204 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1206 unsigned long int number;
1208 for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1212 char name[3 + INT_STRLEN_BOUND (number) + 1];
1214 sprintf (name, "VAR%03lu", number);
1215 if (dict_lookup_var (dict, name) == NULL)
1217 if (num_start != NULL)
1218 *num_start = number + 1;
1219 return xstrdup (name);
1227 /* Devises and returns a variable name unique within DICT. The variable name
1228 is owned by the caller, which must free it with free() when it is no longer
1231 HINT, if it is non-null, is used as a suggestion that will be
1232 modified for suitability as a variable name and for
1235 If HINT is null or entirely unsuitable, a name in the form
1236 "VAR%03d" will be generated, where the smallest unused integer
1237 value is used. If NUM_START is non-null, then its value is
1238 used as the minimum numeric value to check, and it is updated
1239 to the next value to be checked.
1242 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1243 unsigned long int *num_start)
1247 char *hinted_name = make_hinted_name (dict, hint);
1248 if (hinted_name != NULL)
1252 return make_numeric_name (dict, num_start);
1255 /* Returns whether variable names must be valid identifiers. Normally, this is
1256 true, but sometimes a dictionary is prepared for external use (e.g. output
1257 to a CSV file) where names don't have to be valid. */
1259 dict_get_names_must_be_ids (const struct dictionary *d)
1261 return d->names_must_be_ids;
1264 /* Sets whether variable names must be valid identifiers. Normally, this is
1265 true, but sometimes a dictionary is prepared for external use (e.g. output
1266 to a CSV file) where names don't have to be valid.
1268 Changing this setting from false to true doesn't make the dictionary check
1269 all the existing variable names, so it can cause an invariant violation. */
1271 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1273 d->names_must_be_ids = names_must_be_ids;
1276 /* Returns the weighting variable in dictionary D, or a null
1277 pointer if the dictionary is unweighted. */
1279 dict_get_weight (const struct dictionary *d)
1281 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1286 /* Returns the value of D's weighting variable in case C, except
1287 that a negative or missing weight is returned as 0. Returns 1 if the
1288 dictionary is unweighted. Will warn about missing, negative,
1289 or zero values if *WARN_ON_INVALID is true. The function will
1290 set *WARN_ON_INVALID to false if an invalid weight is
1293 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1294 bool *warn_on_invalid)
1298 if (d->weight == NULL)
1302 double w = case_num (c, d->weight);
1304 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1308 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1311 dict_get_rounded_case_weight (const struct dictionary *d,
1312 const struct ccase *c, bool *warn_on_invalid)
1314 return floor (dict_get_case_weight (d, c, warn_on_invalid) + 0.5);
1317 /* Returns the format to use for weights. */
1318 const struct fmt_spec *
1319 dict_get_weight_format (const struct dictionary *d)
1321 return d->weight ? var_get_print_format (d->weight) : &F_8_0;
1324 /* Sets the weighting variable of D to V, or turning off
1325 weighting if V is a null pointer. */
1327 dict_set_weight (struct dictionary *d, struct variable *v)
1329 assert (v == NULL || dict_contains_var (d, v));
1330 assert (v == NULL || var_is_numeric (v));
1334 if (d->changed) d->changed (d, d->changed_data);
1335 if (d->callbacks && d->callbacks->weight_changed)
1336 d->callbacks->weight_changed (d,
1337 v ? var_get_dict_index (v) : -1,
1341 /* Returns the filter variable in dictionary D (see cmd_filter())
1342 or a null pointer if the dictionary is unfiltered. */
1344 dict_get_filter (const struct dictionary *d)
1346 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1351 /* Sets V as the filter variable for dictionary D. Passing a
1352 null pointer for V turn off filtering. */
1354 dict_set_filter (struct dictionary *d, struct variable *v)
1356 assert (v == NULL || dict_contains_var (d, v));
1357 assert (v == NULL || var_is_numeric (v));
1361 if (d->changed) d->changed (d, d->changed_data);
1362 if (d->callbacks && d->callbacks->filter_changed)
1363 d->callbacks->filter_changed (d,
1364 v ? var_get_dict_index (v) : -1,
1368 /* Returns the case limit for dictionary D, or zero if the number
1369 of cases is unlimited. */
1371 dict_get_case_limit (const struct dictionary *d)
1373 return d->case_limit;
1376 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1377 0 for CASE_LIMIT to indicate no limit. */
1379 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1381 d->case_limit = case_limit;
1384 /* Returns the prototype used for cases created by dictionary D. */
1385 const struct caseproto *
1386 dict_get_proto (const struct dictionary *d_)
1388 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1389 if (d->proto == NULL)
1393 d->proto = caseproto_create ();
1394 d->proto = caseproto_reserve (d->proto, d->n_vars);
1395 for (i = 0; i < d->n_vars; i++)
1396 d->proto = caseproto_set_width (d->proto,
1397 var_get_case_index (d->vars[i].var),
1398 var_get_width (d->vars[i].var));
1403 /* Returns the case index of the next value to be added to D.
1404 This value is the number of `union value's that need to be
1405 allocated to store a case for dictionary D. */
1407 dict_get_next_value_idx (const struct dictionary *d)
1409 return d->next_value_idx;
1412 /* Returns the number of bytes needed to store a case for
1415 dict_get_case_size (const struct dictionary *d)
1417 return sizeof (union value) * dict_get_next_value_idx (d);
1420 /* Reassigns values in dictionary D so that fragmentation is
1423 dict_compact_values (struct dictionary *d)
1427 d->next_value_idx = 0;
1428 for (i = 0; i < d->n_vars; i++)
1430 struct variable *v = d->vars[i].var;
1431 set_var_case_index (v, d->next_value_idx++);
1433 invalidate_proto (d);
1436 /* Returns the number of values occupied by the variables in
1437 dictionary D. All variables are considered if EXCLUDE_CLASSES
1438 is 0, or it may contain one or more of (1u << DC_ORDINARY),
1439 (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to exclude the
1440 corresponding type of variable.
1442 The return value may be less than the number of values in one
1443 of dictionary D's cases (as returned by
1444 dict_get_next_value_idx) even if E is 0, because there may be
1445 gaps in D's cases due to deleted variables. */
1447 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1449 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1451 | (1u << DC_SCRATCH))) == 0);
1454 for (size_t i = 0; i < d->n_vars; i++)
1456 enum dict_class class = var_get_dict_class (d->vars[i].var);
1457 if (!(exclude_classes & (1u << class)))
1463 /* Returns the case prototype that would result after deleting
1464 all variables from D that are not in one of the
1465 EXCLUDE_CLASSES and compacting the dictionary with
1468 The caller must unref the returned caseproto when it is no
1471 dict_get_compacted_proto (const struct dictionary *d,
1472 unsigned int exclude_classes)
1474 struct caseproto *proto;
1477 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1479 | (1u << DC_SCRATCH))) == 0);
1481 proto = caseproto_create ();
1482 for (i = 0; i < d->n_vars; i++)
1484 struct variable *v = d->vars[i].var;
1485 if (!(exclude_classes & (1u << var_get_dict_class (v))))
1486 proto = caseproto_add_width (proto, var_get_width (v));
1490 /* Returns the file label for D, or a null pointer if D is
1491 unlabeled (see cmd_file_label()). */
1493 dict_get_label (const struct dictionary *d)
1498 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1501 Removes D's label if LABEL is null or the empty string. */
1503 dict_set_label (struct dictionary *d, const char *label)
1506 if (label == NULL || label[0] == '\0')
1509 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1512 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1513 return value is always nonnull; if there are no documents then the
1514 string_arary is empty.*/
1515 const struct string_array *
1516 dict_get_documents (const struct dictionary *d)
1518 return &d->documents;
1521 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1523 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1525 /* Swap out the old documents, instead of destroying them immediately, to
1526 allow the new documents to include pointers into the old ones. */
1527 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1528 string_array_swap (&d->documents, &old_docs);
1530 for (size_t i = 0; i < new_docs->n; i++)
1531 dict_add_document_line (d, new_docs->strings[i], false);
1533 string_array_destroy (&old_docs);
1536 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1537 into individual lines at new-line characters. Each line is truncated to at
1538 most DOC_LINE_LENGTH bytes in D's encoding. */
1540 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1544 dict_clear_documents (d);
1545 for (s = new_docs; *s != '\0';)
1547 size_t len = strcspn (s, "\n");
1548 char *line = xmemdup0 (s, len);
1549 dict_add_document_line (d, line, false);
1558 /* Drops the documents from dictionary D. */
1560 dict_clear_documents (struct dictionary *d)
1562 string_array_clear (&d->documents);
1565 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1566 truncated so that it is no more than 80 bytes in the dictionary's
1567 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1568 then a warning will be issued. */
1570 dict_add_document_line (struct dictionary *d, const char *line,
1576 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1577 truncated = line[trunc_len] != '\0';
1578 if (truncated && issue_warning)
1580 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1581 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1584 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1589 /* Returns the number of document lines in dictionary D. */
1591 dict_get_document_n_lines (const struct dictionary *d)
1593 return d->documents.n;
1596 /* Returns document line number IDX in dictionary D. The caller must not
1597 modify or free the returned string. */
1599 dict_get_document_line (const struct dictionary *d, size_t idx)
1601 assert (idx < d->documents.n);
1602 return d->documents.strings[idx];
1605 /* Creates in D a vector named NAME that contains the N
1606 variables in VAR. Returns true if successful, or false if a
1607 vector named NAME already exists in D. */
1609 dict_create_vector (struct dictionary *d,
1611 struct variable **var, size_t n)
1614 for (size_t i = 0; i < n; i++)
1615 assert (dict_contains_var (d, var[i]));
1617 if (dict_lookup_vector (d, name) == NULL)
1619 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1620 d->vector[d->n_vectors++] = vector_create (name, var, n);
1627 /* Creates in D a vector named NAME that contains the N
1628 variables in VAR. A vector named NAME must not already exist
1631 dict_create_vector_assert (struct dictionary *d,
1633 struct variable **var, size_t n)
1635 assert (dict_lookup_vector (d, name) == NULL);
1636 dict_create_vector (d, name, var, n);
1639 /* Returns the vector in D with index IDX, which must be less
1640 than dict_get_n_vectors (D). */
1641 const struct vector *
1642 dict_get_vector (const struct dictionary *d, size_t idx)
1644 assert (idx < d->n_vectors);
1646 return d->vector[idx];
1649 /* Returns the number of vectors in D. */
1651 dict_get_n_vectors (const struct dictionary *d)
1653 return d->n_vectors;
1656 /* Looks up and returns the vector within D with the given
1658 const struct vector *
1659 dict_lookup_vector (const struct dictionary *d, const char *name)
1662 for (i = 0; i < d->n_vectors; i++)
1663 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1664 return d->vector[i];
1668 /* Deletes all vectors from D. */
1670 dict_clear_vectors (struct dictionary *d)
1674 for (i = 0; i < d->n_vectors; i++)
1675 vector_destroy (d->vector[i]);
1682 /* Multiple response sets. */
1684 /* Returns the multiple response set in DICT with index IDX, which must be
1685 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1686 const struct mrset *
1687 dict_get_mrset (const struct dictionary *dict, size_t idx)
1689 assert (idx < dict->n_mrsets);
1690 return dict->mrsets[idx];
1693 /* Returns the number of multiple response sets in DICT. */
1695 dict_get_n_mrsets (const struct dictionary *dict)
1697 return dict->n_mrsets;
1700 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1701 returns its index; otherwise, returns SIZE_MAX. */
1703 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1707 for (i = 0; i < dict->n_mrsets; i++)
1708 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1714 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1715 returns it; otherwise, returns NULL. */
1716 const struct mrset *
1717 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1719 size_t idx = dict_lookup_mrset_idx (dict, name);
1720 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1723 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1724 true if a set was replaced, false if none existed with the specified name.
1726 Ownership of MRSET is transferred to DICT. */
1728 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1732 assert (mrset_ok (mrset, dict));
1734 idx = dict_lookup_mrset_idx (dict, mrset->name);
1735 if (idx == SIZE_MAX)
1737 dict->mrsets = xrealloc (dict->mrsets,
1738 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1739 dict->mrsets[dict->n_mrsets++] = mrset;
1744 mrset_destroy (dict->mrsets[idx]);
1745 dict->mrsets[idx] = mrset;
1750 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1751 from DICT and returns true. If none is found, returns false without
1754 Deleting one multiple response set causes the indexes of other sets within
1757 dict_delete_mrset (struct dictionary *dict, const char *name)
1759 size_t idx = dict_lookup_mrset_idx (dict, name);
1760 if (idx != SIZE_MAX)
1762 mrset_destroy (dict->mrsets[idx]);
1763 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1770 /* Deletes all multiple response sets from DICT. */
1772 dict_clear_mrsets (struct dictionary *dict)
1776 for (i = 0; i < dict->n_mrsets; i++)
1777 mrset_destroy (dict->mrsets[i]);
1778 free (dict->mrsets);
1779 dict->mrsets = NULL;
1783 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1785 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1789 assert (dict_contains_var (dict, var));
1791 for (i = 0; i < dict->n_mrsets;)
1793 struct mrset *mrset = dict->mrsets[i];
1796 for (j = 0; j < mrset->n_vars;)
1797 if (mrset->vars[j] == var)
1798 remove_element (mrset->vars, mrset->n_vars--,
1799 sizeof *mrset->vars, j);
1803 if (mrset->n_vars < 2)
1805 mrset_destroy (mrset);
1806 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1813 /* Returns D's attribute set. The caller may examine or modify
1814 the attribute set, but must not destroy it. Destroying D or
1815 calling dict_set_attributes for D will also destroy D's
1818 dict_get_attributes (const struct dictionary *d)
1820 return CONST_CAST (struct attrset *, &d->attributes);
1823 /* Replaces D's attributes set by a copy of ATTRS. */
1825 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1827 attrset_destroy (&d->attributes);
1828 attrset_clone (&d->attributes, attrs);
1831 /* Returns true if D has at least one attribute in its attribute
1832 set, false if D's attribute set is empty. */
1834 dict_has_attributes (const struct dictionary *d)
1836 return attrset_count (&d->attributes) > 0;
1839 /* Called from variable.c to notify the dictionary that some property (indicated
1840 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1841 prior to the change. OLDVAR is destroyed by this function.
1844 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1846 if (var_has_vardict (v))
1848 const struct vardict_info *vardict = var_get_vardict (v);
1849 struct dictionary *d = vardict->dict;
1854 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1855 invalidate_proto (d);
1857 if (d->changed) d->changed (d, d->changed_data);
1858 if (d->callbacks && d->callbacks->var_changed)
1859 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1866 /* Dictionary used to contain "internal variables". */
1867 static struct dictionary *internal_dict;
1869 /* Create a variable of the specified WIDTH to be used for internal
1870 calculations only. The variable is assigned case index CASE_IDX. */
1872 dict_create_internal_var (int case_idx, int width)
1874 if (internal_dict == NULL)
1875 internal_dict = dict_create ("UTF-8");
1879 static int counter = INT_MAX / 2;
1880 struct variable *var;
1883 if (++counter == INT_MAX)
1884 counter = INT_MAX / 2;
1886 sprintf (name, "$internal%d", counter);
1887 var = dict_create_var (internal_dict, name, width);
1890 set_var_case_index (var, case_idx);
1896 /* Destroys VAR, which must have been created with
1897 dict_create_internal_var(). */
1899 dict_destroy_internal_var (struct variable *var)
1903 dict_delete_var (internal_dict, var);
1905 /* Destroy internal_dict if it has no variables left, just so that
1906 valgrind --leak-check --show-reachable won't show internal_dict. */
1907 if (dict_get_n_vars (internal_dict) == 0)
1909 dict_unref (internal_dict);
1910 internal_dict = NULL;
1916 vardict_get_dict_index (const struct vardict_info *vardict)
1918 return vardict - vardict->dict->vars;