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 struct variable *weight; /* WEIGHT variable. */
71 struct variable *filter; /* FILTER variable. */
72 casenumber case_limit; /* Current case limit (N command). */
73 char *label; /* File label. */
74 struct string_array documents; /* Documents. */
75 struct vector **vector; /* Vectors of variables. */
76 size_t n_vectors; /* Number of vectors. */
77 struct attrset attributes; /* Custom attributes. */
78 struct mrset **mrsets; /* Multiple response sets. */
79 size_t n_mrsets; /* Number of multiple response sets. */
81 /* Whether variable names must be valid identifiers. Normally, this is
82 true, but sometimes a dictionary is prepared for external use
83 (e.g. output to a CSV file) where names don't have to be valid. */
84 bool names_must_be_ids;
86 char *encoding; /* Character encoding of string data */
88 const struct dict_callbacks *callbacks; /* Callbacks on dictionary
90 void *cb_data ; /* Data passed to callbacks */
92 void (*changed) (struct dictionary *, void *); /* Generic change callback */
96 static void dict_unset_split_var (struct dictionary *, struct variable *, bool);
97 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
99 /* Compares two double pointers to variables, which should point
100 to elements of a struct dictionary's `var' member array. */
102 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
104 struct variable *const *a = a_;
105 struct variable *const *b = b_;
107 return *a < *b ? -1 : *a > *b;
111 unindex_var (struct dictionary *d, struct vardict_info *vardict)
113 hmap_delete (&d->name_map, &vardict->name_node);
116 /* This function assumes that vardict->name_node.hash is valid, that is, that
117 its name has not changed since it was hashed (rename_var() updates this
118 hash along with the name itself). */
120 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
122 struct variable *old = (d->callbacks && d->callbacks->var_changed
123 ? var_clone (vardict->var)
126 struct variable *var = vardict->var;
127 var_set_vardict (var, vardict);
128 hmap_insert_fast (&d->name_map, &vardict->name_node,
129 vardict->name_node.hash);
131 if (! skip_callbacks)
133 if (d->changed) d->changed (d, d->changed_data);
136 d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
142 /* Sets the case_index in V's vardict to CASE_INDEX. */
144 set_var_case_index (struct variable *v, int case_index)
146 var_get_vardict (v)->case_index = case_index;
149 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
152 unindex_vars (struct dictionary *d, size_t from, size_t to)
156 for (i = from; i < to; i++)
157 unindex_var (d, &d->vars[i]);
160 /* Re-sets the dict_index in the dictionary variables with
161 indexes from FROM to TO (exclusive). */
163 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
167 for (i = from; i < to; i++)
168 reindex_var (d, &d->vars[i], skip_callbacks);
173 /* Returns the encoding for data in dictionary D. The return value is a
174 nonnull string that contains an IANA character set name. */
176 dict_get_encoding (const struct dictionary *d)
181 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
182 encoding, false otherwise. If ISSUE_ERROR is true, issues an explanatory
183 error message on failure. */
185 dict_id_is_valid (const struct dictionary *dict, const char *id,
188 return (!dict->names_must_be_ids
189 || id_is_valid (id, dict->encoding, issue_error));
193 dict_set_change_callback (struct dictionary *d,
194 void (*changed) (struct dictionary *, void*),
197 d->changed = changed;
198 d->changed_data = data;
201 /* Discards dictionary D's caseproto. (It will be regenerated
202 lazily, on demand.) */
204 invalidate_proto (struct dictionary *d)
206 caseproto_unref (d->proto);
210 /* Print a representation of dictionary D to stdout, for
211 debugging purposes. */
213 dict_dump (const struct dictionary *d)
216 for (i = 0 ; i < d->n_vars ; ++i)
218 const struct variable *v = d->vars[i].var;
219 printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
221 var_get_dict_index (v),
222 var_get_case_index (v));
227 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
228 the dictionary or any of the variables it contains are modified.
229 Each callback will get passed CALLBACK_DATA.
230 Any callback may be NULL, in which case it'll be ignored.
233 dict_set_callbacks (struct dictionary *dict,
234 const struct dict_callbacks *callbacks,
237 dict->callbacks = callbacks;
238 dict->cb_data = callback_data;
241 /* Shallow copy the callbacks from SRC to DEST */
243 dict_copy_callbacks (struct dictionary *dest,
244 const struct dictionary *src)
246 dest->callbacks = src->callbacks;
247 dest->cb_data = src->cb_data;
250 /* Creates and returns a new dictionary with the specified ENCODING. */
252 dict_create (const char *encoding)
254 struct dictionary *d = XZALLOC (struct dictionary);
256 d->encoding = xstrdup (encoding);
257 d->names_must_be_ids = true;
258 hmap_init (&d->name_map);
259 attrset_init (&d->attributes);
265 /* Creates and returns a (deep) copy of an existing
268 The new dictionary's case indexes are copied from the old
269 dictionary. If the new dictionary won't be used to access
270 cases produced with the old dictionary, then the new
271 dictionary's case indexes should be compacted with
272 dict_compact_values to save space.
274 Callbacks are not cloned. */
276 dict_clone (const struct dictionary *s)
278 struct dictionary *d;
281 d = dict_create (s->encoding);
282 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
284 for (i = 0; i < s->n_vars; i++)
286 struct variable *sv = s->vars[i].var;
287 struct variable *dv = dict_clone_var_assert (d, sv);
290 for (i = 0; i < var_get_n_short_names (sv); i++)
291 var_set_short_name (dv, i, var_get_short_name (sv, i));
293 var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
296 d->next_value_idx = s->next_value_idx;
298 d->n_splits = s->n_splits;
301 d->split = xnmalloc (d->n_splits, sizeof *d->split);
302 for (i = 0; i < d->n_splits; i++)
303 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
306 if (s->weight != NULL)
307 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
309 if (s->filter != NULL)
310 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
312 d->case_limit = s->case_limit;
313 dict_set_label (d, dict_get_label (s));
314 dict_set_documents (d, dict_get_documents (s));
316 d->n_vectors = s->n_vectors;
317 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
318 for (i = 0; i < s->n_vectors; i++)
319 d->vector[i] = vector_clone (s->vector[i], s, d);
321 dict_set_attributes (d, dict_get_attributes (s));
323 for (i = 0; i < s->n_mrsets; i++)
325 const struct mrset *old = s->mrsets[i];
329 /* Clone old mrset, then replace vars from D by vars from S. */
330 new = mrset_clone (old);
331 for (j = 0; j < new->n_vars; j++)
332 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
334 dict_add_mrset (d, new);
342 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
343 dict_get_n_splits() to determine how many SPLIT FILE vars
344 there are. Returns a null pointer if and only if there are no
346 const struct variable *const *
347 dict_get_split_vars (const struct dictionary *d)
352 /* Returns the number of SPLIT FILE vars. */
354 dict_get_n_splits (const struct dictionary *d)
359 /* Removes variable V, which must be in D, from D's set of split
362 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
366 assert (dict_contains_var (d, v));
368 orig_count = d->n_splits;
369 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
370 &v, compare_var_ptrs, NULL);
371 if (orig_count != d->n_splits && !skip_callbacks)
373 if (d->changed) d->changed (d, d->changed_data);
374 /* We changed the set of split variables so invoke the
376 if (d->callbacks && d->callbacks->split_changed)
377 d->callbacks->split_changed (d, d->cb_data);
382 /* Sets N split vars SPLIT in dictionary D. */
384 dict_set_split_vars__ (struct dictionary *d,
385 struct variable *const *split, size_t n,
388 assert (n == 0 || split != NULL);
393 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
394 memcpy (d->split, split, n * sizeof *d->split);
404 if (d->changed) d->changed (d, d->changed_data);
405 if (d->callbacks && d->callbacks->split_changed)
406 d->callbacks->split_changed (d, d->cb_data);
410 /* Sets N split vars SPLIT in dictionary D. */
412 dict_set_split_vars (struct dictionary *d,
413 struct variable *const *split, size_t n)
415 dict_set_split_vars__ (d, split, n, false);
420 /* Deletes variable V from dictionary D and frees V.
422 This is a very bad idea if there might be any pointers to V
423 from outside D. In general, no variable in the active dataset's
424 dictionary should be deleted when any transformations are
425 active on the dictionary's dataset, because those
426 transformations might reference the deleted variable. The
427 safest time to delete a variable is just after a procedure has
428 been executed, as done by DELETE VARIABLES.
430 Pointers to V within D are not a problem, because
431 dict_delete_var() knows to remove V from split variables,
432 weights, filters, etc. */
434 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
436 int dict_index = var_get_dict_index (v);
437 const int case_index = var_get_case_index (v);
439 assert (dict_contains_var (d, v));
441 dict_unset_split_var (d, v, skip_callbacks);
442 dict_unset_mrset_var (d, v);
445 dict_set_weight (d, NULL);
448 dict_set_filter (d, NULL);
450 dict_clear_vectors (d);
452 /* Remove V from var array. */
453 unindex_vars (d, dict_index, d->n_vars);
454 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
457 /* Update dict_index for each affected variable. */
458 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
461 var_clear_vardict (v);
463 if (! skip_callbacks)
465 if (d->changed) d->changed (d, d->changed_data);
466 if (d->callbacks && d->callbacks->var_deleted)
467 d->callbacks->var_deleted (d, v, dict_index, case_index, d->cb_data);
470 invalidate_proto (d);
474 /* Deletes variable V from dictionary D and frees V.
476 This is a very bad idea if there might be any pointers to V
477 from outside D. In general, no variable in the active dataset's
478 dictionary should be deleted when any transformations are
479 active on the dictionary's dataset, because those
480 transformations might reference the deleted variable. The
481 safest time to delete a variable is just after a procedure has
482 been executed, as done by DELETE VARIABLES.
484 Pointers to V within D are not a problem, because
485 dict_delete_var() knows to remove V from split variables,
486 weights, filters, etc. */
488 dict_delete_var (struct dictionary *d, struct variable *v)
490 dict_delete_var__ (d, v, false);
494 /* Deletes the COUNT variables listed in VARS from D. This is
495 unsafe; see the comment on dict_delete_var() for details. */
497 dict_delete_vars (struct dictionary *d,
498 struct variable *const *vars, size_t count)
500 /* FIXME: this can be done in O(count) time, but this algorithm
502 assert (count == 0 || vars != NULL);
505 dict_delete_var (d, *vars++);
508 /* Deletes the COUNT variables in D starting at index IDX. This
509 is unsafe; see the comment on dict_delete_var() for
510 details. Deleting consecutive vars will result in less callbacks
511 compared to iterating over dict_delete_var.
512 A simple while loop over dict_delete_var will
513 produce (d->n_vars - IDX) * COUNT variable changed callbacks
514 plus COUNT variable delete callbacks.
515 This here produces d->n_vars - IDX variable changed callbacks
516 plus COUNT variable delete callbacks. */
518 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
520 assert (idx + count <= d->n_vars);
522 /* We need to store the variable and the corresponding case_index
523 for the delete callbacks later. We store them in a linked list.*/
526 struct variable *var;
529 struct ll_list list = LL_INITIALIZER (list);
531 for (size_t i = idx; i < idx + count; i++)
533 struct delvar *dv = xmalloc (sizeof (struct delvar));
535 struct variable *v = d->vars[i].var;
537 dict_unset_split_var (d, v, false);
538 dict_unset_mrset_var (d, v);
541 dict_set_weight (d, NULL);
544 dict_set_filter (d, NULL);
547 dv->case_index = var_get_case_index (v);
548 ll_push_tail (&list, (struct ll *)dv);
551 dict_clear_vectors (d);
553 /* Remove variables from var array. */
554 unindex_vars (d, idx, d->n_vars);
555 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
558 /* Reindexing will result variable-changed callback */
559 reindex_vars (d, idx, d->n_vars, false);
561 invalidate_proto (d);
562 if (d->changed) d->changed (d, d->changed_data);
564 /* Now issue the variable delete callbacks and delete
565 the variables. The vardict is not valid at this point
566 anymore. That is the reason why we stored the
567 caseindex before reindexing. */
568 for (size_t vi = idx; vi < idx + count; vi++)
570 struct delvar *dv = (struct delvar *) ll_pop_head (&list);
571 var_clear_vardict (dv->var);
572 if (d->callbacks && d->callbacks->var_deleted)
573 d->callbacks->var_deleted (d, dv->var, vi, dv->case_index, d->cb_data);
579 /* Deletes scratch variables from dictionary D. */
581 dict_delete_scratch_vars (struct dictionary *d)
585 /* FIXME: this can be done in O(count) time, but this algorithm
587 for (i = 0; i < d->n_vars;)
588 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
589 dict_delete_var (d, d->vars[i].var);
596 /* Clears the contents from a dictionary without destroying the
597 dictionary itself. */
599 dict_clear__ (struct dictionary *d, bool skip_callbacks)
601 /* FIXME? Should we really clear case_limit, label, documents?
602 Others are necessarily cleared by deleting all the variables.*/
603 while (d->n_vars > 0)
605 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
610 d->n_vars = d->allocated_vars = 0;
611 invalidate_proto (d);
612 hmap_clear (&d->name_map);
613 d->next_value_idx = 0;
614 dict_set_split_vars__ (d, NULL, 0, skip_callbacks);
623 dict_set_weight (d, NULL);
624 dict_set_filter (d, NULL);
629 string_array_clear (&d->documents);
630 dict_clear_vectors (d);
631 attrset_clear (&d->attributes);
634 /* Clears the contents from a dictionary without destroying the
635 dictionary itself. */
637 dict_clear (struct dictionary *d)
639 dict_clear__ (d, false);
642 /* Clears a dictionary and destroys it. */
644 _dict_destroy (struct dictionary *d)
646 /* In general, we don't want callbacks occurring, if the dictionary
647 is being destroyed */
648 d->callbacks = NULL ;
650 dict_clear__ (d, true);
651 string_array_destroy (&d->documents);
652 hmap_destroy (&d->name_map);
653 attrset_destroy (&d->attributes);
654 dict_clear_mrsets (d);
660 dict_ref (struct dictionary *d)
667 dict_unref (struct dictionary *d)
672 assert (d->ref_cnt >= 0);
677 /* Returns the number of variables in D. */
679 dict_get_n_vars (const struct dictionary *d)
684 /* Returns the variable in D with dictionary index IDX, which
685 must be between 0 and the count returned by
686 dict_get_n_vars(), exclusive. */
688 dict_get_var (const struct dictionary *d, size_t idx)
690 assert (idx < d->n_vars);
692 return d->vars[idx].var;
695 /* Sets *VARS to an array of pointers to variables in D and *N
696 to the number of variables in *D. All variables are returned
697 except for those, if any, in the classes indicated by EXCLUDE.
698 (There is no point in putting DC_SYSTEM in EXCLUDE as
699 dictionaries never include system variables.) */
701 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
702 size_t *n, enum dict_class exclude)
704 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
707 /* Sets *VARS to an array of pointers to variables in D and *N
708 to the number of variables in *D. All variables are returned
709 except for those, if any, in the classes indicated by EXCLUDE.
710 (There is no point in putting DC_SYSTEM in EXCLUDE as
711 dictionaries never include system variables.) */
713 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
714 size_t *n, enum dict_class exclude)
719 assert (exclude == (exclude & DC_ALL));
722 for (i = 0; i < d->n_vars; i++)
724 enum dict_class class = var_get_dict_class (d->vars[i].var);
725 if (!(class & exclude))
729 *vars = xnmalloc (count, sizeof **vars);
731 for (i = 0; i < d->n_vars; i++)
733 enum dict_class class = var_get_dict_class (d->vars[i].var);
734 if (!(class & exclude))
735 (*vars)[(*n)++] = d->vars[i].var;
737 assert (*n == count);
740 static struct variable *
741 add_var_with_case_index (struct dictionary *d, struct variable *v,
744 struct vardict_info *vardict;
746 assert (case_index >= d->next_value_idx);
748 /* Update dictionary. */
749 if (d->n_vars >= d->allocated_vars)
753 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
754 hmap_clear (&d->name_map);
755 for (i = 0; i < d->n_vars; i++)
757 var_set_vardict (d->vars[i].var, &d->vars[i]);
758 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
759 d->vars[i].name_node.hash);
763 vardict = &d->vars[d->n_vars++];
766 hmap_insert (&d->name_map, &vardict->name_node,
767 utf8_hash_case_string (var_get_name (v), 0));
768 vardict->case_index = case_index;
769 var_set_vardict (v, vardict);
771 if (d->changed) d->changed (d, d->changed_data);
772 if (d->callbacks && d->callbacks->var_added)
773 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
775 invalidate_proto (d);
776 d->next_value_idx = case_index + 1;
781 static struct variable *
782 add_var (struct dictionary *d, struct variable *v)
784 return add_var_with_case_index (d, v, d->next_value_idx);
787 /* Creates and returns a new variable in D with the given NAME
788 and WIDTH. Returns a null pointer if the given NAME would
789 duplicate that of an existing variable in the dictionary. */
791 dict_create_var (struct dictionary *d, const char *name, int width)
793 return (dict_lookup_var (d, name) == NULL
794 ? dict_create_var_assert (d, name, width)
798 /* Creates and returns a new variable in D with the given NAME
799 and WIDTH. Assert-fails if the given NAME would duplicate
800 that of an existing variable in the dictionary. */
802 dict_create_var_assert (struct dictionary *d, const char *name, int width)
804 assert (dict_lookup_var (d, name) == NULL);
805 return add_var (d, var_create (name, width));
808 /* Creates and returns a new variable in D, as a copy of existing variable
809 OLD_VAR, which need not be in D or in any dictionary. Returns a null
810 pointer if OLD_VAR's name would duplicate that of an existing variable in
813 dict_clone_var (struct dictionary *d, const struct variable *old_var)
815 return dict_clone_var_as (d, old_var, var_get_name (old_var));
818 /* Creates and returns a new variable in D, as a copy of existing variable
819 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
820 OLD_VAR's name would duplicate that of an existing variable in the
823 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
825 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
828 /* Creates and returns a new variable in D with name NAME, as a copy of
829 existing variable OLD_VAR, which need not be in D or in any dictionary.
830 Returns a null pointer if the given NAME would duplicate that of an existing
831 variable in the dictionary. */
833 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
836 return (dict_lookup_var (d, name) == NULL
837 ? dict_clone_var_as_assert (d, old_var, name)
841 /* Creates and returns a new variable in D with name NAME, as a copy of
842 existing variable OLD_VAR, which need not be in D or in any dictionary.
843 Assert-fails if the given NAME would duplicate that of an existing variable
844 in the dictionary. */
846 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
849 struct variable *new_var = var_clone (old_var);
850 assert (dict_lookup_var (d, name) == NULL);
851 var_set_name (new_var, name);
852 return add_var (d, new_var);
856 dict_clone_var_in_place_assert (struct dictionary *d,
857 const struct variable *old_var)
859 assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
860 return add_var_with_case_index (d, var_clone (old_var),
861 var_get_case_index (old_var));
864 /* Returns the variable named NAME in D, or a null pointer if no
865 variable has that name. */
867 dict_lookup_var (const struct dictionary *d, const char *name)
869 struct vardict_info *vardict;
871 HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
872 utf8_hash_case_string (name, 0), &d->name_map)
874 struct variable *var = vardict->var;
875 if (!utf8_strcasecmp (var_get_name (var), name))
882 /* Returns the variable named NAME in D. Assert-fails if no
883 variable has that name. */
885 dict_lookup_var_assert (const struct dictionary *d, const char *name)
887 struct variable *v = dict_lookup_var (d, name);
892 /* Returns true if variable V is in dictionary D,
895 dict_contains_var (const struct dictionary *d, const struct variable *v)
897 return (var_has_vardict (v)
898 && vardict_get_dictionary (var_get_vardict (v)) == d);
901 /* Moves V to 0-based position IDX in D. Other variables in D,
902 if any, retain their relative positions. Runs in time linear
903 in the distance moved. */
905 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
907 size_t old_index = var_get_dict_index (v);
909 assert (new_index < d->n_vars);
911 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
912 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
913 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
916 /* Reorders the variables in D, placing the COUNT variables
917 listed in ORDER in that order at the beginning of D. The
918 other variables in D, if any, retain their relative
921 dict_reorder_vars (struct dictionary *d,
922 struct variable *const *order, size_t count)
924 struct vardict_info *new_var;
927 assert (count == 0 || order != NULL);
928 assert (count <= d->n_vars);
930 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
932 /* Add variables in ORDER to new_var. */
933 for (i = 0; i < count; i++)
935 struct vardict_info *old_var;
937 assert (dict_contains_var (d, order[i]));
939 old_var = var_get_vardict (order[i]);
940 new_var[i] = *old_var;
941 old_var->dict = NULL;
944 /* Add remaining variables to new_var. */
945 for (i = 0; i < d->n_vars; i++)
946 if (d->vars[i].dict != NULL)
947 new_var[count++] = d->vars[i];
948 assert (count == d->n_vars);
950 /* Replace old vardicts by new ones. */
954 hmap_clear (&d->name_map);
955 reindex_vars (d, 0, d->n_vars, false);
958 /* Changes the name of variable V that is currently in a dictionary to
961 rename_var (struct variable *v, const char *new_name)
963 struct vardict_info *vardict = var_get_vardict (v);
964 var_clear_vardict (v);
965 var_set_name (v, new_name);
966 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
967 var_set_vardict (v, vardict);
970 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
971 successful, false if a variable (other than V) with the given name already
974 dict_try_rename_var (struct dictionary *d, struct variable *v,
975 const char *new_name)
977 struct variable *conflict = dict_lookup_var (d, new_name);
978 if (conflict && v != conflict)
981 struct variable *old = var_clone (v);
982 unindex_var (d, var_get_vardict (v));
983 rename_var (v, new_name);
984 reindex_var (d, var_get_vardict (v), false);
986 if (settings_get_algorithm () == ENHANCED)
987 var_clear_short_names (v);
989 if (d->changed) d->changed (d, d->changed_data);
990 if (d->callbacks && d->callbacks->var_changed)
991 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
998 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
999 a variable named NEW_NAME is already in D, except that
1000 NEW_NAME may be the same as V's existing name. */
1002 dict_rename_var (struct dictionary *d, struct variable *v,
1003 const char *new_name)
1005 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1009 /* Renames COUNT variables specified in VARS to the names given
1010 in NEW_NAMES within dictionary D. If the renaming would
1011 result in a duplicate variable name, returns false and stores a
1012 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1013 non-null). Otherwise, the renaming is successful, and true
1016 dict_rename_vars (struct dictionary *d,
1017 struct variable **vars, char **new_names, size_t count,
1024 assert (count == 0 || vars != NULL);
1025 assert (count == 0 || new_names != NULL);
1027 /* Save the names of the variables to be renamed. */
1028 pool = pool_create ();
1029 old_names = pool_nalloc (pool, count, sizeof *old_names);
1030 for (i = 0; i < count; i++)
1031 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1033 /* Remove the variables to be renamed from the name hash,
1035 for (i = 0; i < count; i++)
1037 unindex_var (d, var_get_vardict (vars[i]));
1038 rename_var (vars[i], new_names[i]);
1041 /* Add the renamed variables back into the name hash,
1042 checking for conflicts. */
1043 for (i = 0; i < count; i++)
1045 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1047 /* There is a name conflict.
1048 Back out all the name changes that have already
1049 taken place, and indicate failure. */
1050 size_t fail_idx = i;
1051 if (err_name != NULL)
1052 *err_name = new_names[i];
1054 for (i = 0; i < fail_idx; i++)
1055 unindex_var (d, var_get_vardict (vars[i]));
1057 for (i = 0; i < count; i++)
1059 rename_var (vars[i], old_names[i]);
1060 reindex_var (d, var_get_vardict (vars[i]), false);
1063 pool_destroy (pool);
1066 reindex_var (d, var_get_vardict (vars[i]), false);
1069 /* Clear short names. */
1070 if (settings_get_algorithm () == ENHANCED)
1071 for (i = 0; i < count; i++)
1072 var_clear_short_names (vars[i]);
1074 pool_destroy (pool);
1078 /* Returns true if a variable named NAME may be inserted in DICT;
1079 that is, if there is not already a variable with that name in
1080 DICT and if NAME is not a reserved word. (The caller's checks
1081 have already verified that NAME is otherwise acceptable as a
1084 var_name_is_insertable (const struct dictionary *dict, const char *name)
1086 return (dict_lookup_var (dict, name) == NULL
1087 && lex_id_to_token (ss_cstr (name)) == T_ID);
1091 make_hinted_name (const struct dictionary *dict, const char *hint)
1093 size_t hint_len = strlen (hint);
1094 bool dropped = false;
1099 if (hint_len > ID_MAX_LEN)
1100 hint_len = ID_MAX_LEN;
1102 /* The allocation size here is OK: characters that are copied directly fit
1103 OK, and characters that are not copied directly are replaced by a single
1104 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1105 replaced by '_' too. */
1106 root = rp = xmalloc (hint_len + 1);
1107 for (ofs = 0; ofs < hint_len; ofs += mblen)
1111 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1114 ? lex_uc_is_id1 (uc) && uc != '$'
1115 : lex_uc_is_idn (uc))
1122 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1124 else if (rp != root)
1129 if (root[0] != '\0')
1131 unsigned long int i;
1133 if (var_name_is_insertable (dict, root))
1136 for (i = 0; i < ULONG_MAX; i++)
1138 char suffix[INT_BUFSIZE_BOUND (i) + 1];
1142 if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1145 name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1146 if (var_name_is_insertable (dict, name))
1161 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1163 unsigned long int number;
1165 for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1169 char name[3 + INT_STRLEN_BOUND (number) + 1];
1171 sprintf (name, "VAR%03lu", number);
1172 if (dict_lookup_var (dict, name) == NULL)
1174 if (num_start != NULL)
1175 *num_start = number + 1;
1176 return xstrdup (name);
1184 /* Devises and returns a variable name unique within DICT. The variable name
1185 is owned by the caller, which must free it with free() when it is no longer
1188 HINT, if it is non-null, is used as a suggestion that will be
1189 modified for suitability as a variable name and for
1192 If HINT is null or entirely unsuitable, a name in the form
1193 "VAR%03d" will be generated, where the smallest unused integer
1194 value is used. If NUM_START is non-null, then its value is
1195 used as the minimum numeric value to check, and it is updated
1196 to the next value to be checked.
1199 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1200 unsigned long int *num_start)
1204 char *hinted_name = make_hinted_name (dict, hint);
1205 if (hinted_name != NULL)
1209 return make_numeric_name (dict, num_start);
1212 /* Returns whether variable names must be valid identifiers. Normally, this is
1213 true, but sometimes a dictionary is prepared for external use (e.g. output
1214 to a CSV file) where names don't have to be valid. */
1216 dict_get_names_must_be_ids (const struct dictionary *d)
1218 return d->names_must_be_ids;
1221 /* Sets whether variable names must be valid identifiers. Normally, this is
1222 true, but sometimes a dictionary is prepared for external use (e.g. output
1223 to a CSV file) where names don't have to be valid.
1225 Changing this setting from false to true doesn't make the dictionary check
1226 all the existing variable names, so it can cause an invariant violation. */
1228 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1230 d->names_must_be_ids = names_must_be_ids;
1233 /* Returns the weighting variable in dictionary D, or a null
1234 pointer if the dictionary is unweighted. */
1236 dict_get_weight (const struct dictionary *d)
1238 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1243 /* Returns the value of D's weighting variable in case C, except
1244 that a negative weight is returned as 0. Returns 1 if the
1245 dictionary is unweighted. Will warn about missing, negative,
1246 or zero values if *WARN_ON_INVALID is true. The function will
1247 set *WARN_ON_INVALID to false if an invalid weight is
1250 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1251 bool *warn_on_invalid)
1255 if (d->weight == NULL)
1259 double w = case_num (c, d->weight);
1261 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1265 /* Returns the format to use for weights. */
1266 const struct fmt_spec *
1267 dict_get_weight_format (const struct dictionary *d)
1269 return d->weight ? var_get_print_format (d->weight) : &F_8_0;
1272 /* Sets the weighting variable of D to V, or turning off
1273 weighting if V is a null pointer. */
1275 dict_set_weight (struct dictionary *d, struct variable *v)
1277 assert (v == NULL || dict_contains_var (d, v));
1278 assert (v == NULL || var_is_numeric (v));
1282 if (d->changed) d->changed (d, d->changed_data);
1283 if (d->callbacks && d->callbacks->weight_changed)
1284 d->callbacks->weight_changed (d,
1285 v ? var_get_dict_index (v) : -1,
1289 /* Returns the filter variable in dictionary D (see cmd_filter())
1290 or a null pointer if the dictionary is unfiltered. */
1292 dict_get_filter (const struct dictionary *d)
1294 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1299 /* Sets V as the filter variable for dictionary D. Passing a
1300 null pointer for V turn off filtering. */
1302 dict_set_filter (struct dictionary *d, struct variable *v)
1304 assert (v == NULL || dict_contains_var (d, v));
1305 assert (v == NULL || var_is_numeric (v));
1309 if (d->changed) d->changed (d, d->changed_data);
1310 if (d->callbacks && d->callbacks->filter_changed)
1311 d->callbacks->filter_changed (d,
1312 v ? var_get_dict_index (v) : -1,
1316 /* Returns the case limit for dictionary D, or zero if the number
1317 of cases is unlimited. */
1319 dict_get_case_limit (const struct dictionary *d)
1321 return d->case_limit;
1324 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1325 0 for CASE_LIMIT to indicate no limit. */
1327 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1329 d->case_limit = case_limit;
1332 /* Returns the prototype used for cases created by dictionary D. */
1333 const struct caseproto *
1334 dict_get_proto (const struct dictionary *d_)
1336 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1337 if (d->proto == NULL)
1341 d->proto = caseproto_create ();
1342 d->proto = caseproto_reserve (d->proto, d->n_vars);
1343 for (i = 0; i < d->n_vars; i++)
1344 d->proto = caseproto_set_width (d->proto,
1345 var_get_case_index (d->vars[i].var),
1346 var_get_width (d->vars[i].var));
1351 /* Returns the case index of the next value to be added to D.
1352 This value is the number of `union value's that need to be
1353 allocated to store a case for dictionary D. */
1355 dict_get_next_value_idx (const struct dictionary *d)
1357 return d->next_value_idx;
1360 /* Returns the number of bytes needed to store a case for
1363 dict_get_case_size (const struct dictionary *d)
1365 return sizeof (union value) * dict_get_next_value_idx (d);
1368 /* Reassigns values in dictionary D so that fragmentation is
1371 dict_compact_values (struct dictionary *d)
1375 d->next_value_idx = 0;
1376 for (i = 0; i < d->n_vars; i++)
1378 struct variable *v = d->vars[i].var;
1379 set_var_case_index (v, d->next_value_idx++);
1381 invalidate_proto (d);
1384 /* Returns the number of values occupied by the variables in
1385 dictionary D. All variables are considered if EXCLUDE_CLASSES
1386 is 0, or it may contain one or more of (1u << DC_ORDINARY),
1387 (1u << DC_SYSTEM), or (1u << DC_SCRATCH) to exclude the
1388 corresponding type of variable.
1390 The return value may be less than the number of values in one
1391 of dictionary D's cases (as returned by
1392 dict_get_next_value_idx) even if E is 0, because there may be
1393 gaps in D's cases due to deleted variables. */
1395 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1397 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1399 | (1u << DC_SCRATCH))) == 0);
1402 for (size_t i = 0; i < d->n_vars; i++)
1404 enum dict_class class = var_get_dict_class (d->vars[i].var);
1405 if (!(exclude_classes & (1u << class)))
1411 /* Returns the case prototype that would result after deleting
1412 all variables from D that are not in one of the
1413 EXCLUDE_CLASSES and compacting the dictionary with
1416 The caller must unref the returned caseproto when it is no
1419 dict_get_compacted_proto (const struct dictionary *d,
1420 unsigned int exclude_classes)
1422 struct caseproto *proto;
1425 assert ((exclude_classes & ~((1u << DC_ORDINARY)
1427 | (1u << DC_SCRATCH))) == 0);
1429 proto = caseproto_create ();
1430 for (i = 0; i < d->n_vars; i++)
1432 struct variable *v = d->vars[i].var;
1433 if (!(exclude_classes & (1u << var_get_dict_class (v))))
1434 proto = caseproto_add_width (proto, var_get_width (v));
1438 /* Returns the file label for D, or a null pointer if D is
1439 unlabeled (see cmd_file_label()). */
1441 dict_get_label (const struct dictionary *d)
1446 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1449 Removes D's label if LABEL is null or the empty string. */
1451 dict_set_label (struct dictionary *d, const char *label)
1454 if (label == NULL || label[0] == '\0')
1457 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1460 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1461 return value is always nonnull; if there are no documents then the
1462 string_arary is empty.*/
1463 const struct string_array *
1464 dict_get_documents (const struct dictionary *d)
1466 return &d->documents;
1469 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1471 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1473 /* Swap out the old documents, instead of destroying them immediately, to
1474 allow the new documents to include pointers into the old ones. */
1475 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1476 string_array_swap (&d->documents, &old_docs);
1478 for (size_t i = 0; i < new_docs->n; i++)
1479 dict_add_document_line (d, new_docs->strings[i], false);
1481 string_array_destroy (&old_docs);
1484 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1485 into individual lines at new-line characters. Each line is truncated to at
1486 most DOC_LINE_LENGTH bytes in D's encoding. */
1488 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1492 dict_clear_documents (d);
1493 for (s = new_docs; *s != '\0';)
1495 size_t len = strcspn (s, "\n");
1496 char *line = xmemdup0 (s, len);
1497 dict_add_document_line (d, line, false);
1506 /* Drops the documents from dictionary D. */
1508 dict_clear_documents (struct dictionary *d)
1510 string_array_clear (&d->documents);
1513 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1514 truncated so that it is no more than 80 bytes in the dictionary's
1515 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1516 then a warning will be issued. */
1518 dict_add_document_line (struct dictionary *d, const char *line,
1524 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1525 truncated = line[trunc_len] != '\0';
1526 if (truncated && issue_warning)
1528 /* Note to translators: "bytes" is correct, not characters */
1529 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1532 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1537 /* Returns the number of document lines in dictionary D. */
1539 dict_get_document_n_lines (const struct dictionary *d)
1541 return d->documents.n;
1544 /* Returns document line number IDX in dictionary D. The caller must not
1545 modify or free the returned string. */
1547 dict_get_document_line (const struct dictionary *d, size_t idx)
1549 assert (idx < d->documents.n);
1550 return d->documents.strings[idx];
1553 /* Creates in D a vector named NAME that contains the N
1554 variables in VAR. Returns true if successful, or false if a
1555 vector named NAME already exists in D. */
1557 dict_create_vector (struct dictionary *d,
1559 struct variable **var, size_t n)
1562 for (size_t i = 0; i < n; i++)
1563 assert (dict_contains_var (d, var[i]));
1565 if (dict_lookup_vector (d, name) == NULL)
1567 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1568 d->vector[d->n_vectors++] = vector_create (name, var, n);
1575 /* Creates in D a vector named NAME that contains the N
1576 variables in VAR. A vector named NAME must not already exist
1579 dict_create_vector_assert (struct dictionary *d,
1581 struct variable **var, size_t n)
1583 assert (dict_lookup_vector (d, name) == NULL);
1584 dict_create_vector (d, name, var, n);
1587 /* Returns the vector in D with index IDX, which must be less
1588 than dict_get_n_vectors (D). */
1589 const struct vector *
1590 dict_get_vector (const struct dictionary *d, size_t idx)
1592 assert (idx < d->n_vectors);
1594 return d->vector[idx];
1597 /* Returns the number of vectors in D. */
1599 dict_get_n_vectors (const struct dictionary *d)
1601 return d->n_vectors;
1604 /* Looks up and returns the vector within D with the given
1606 const struct vector *
1607 dict_lookup_vector (const struct dictionary *d, const char *name)
1610 for (i = 0; i < d->n_vectors; i++)
1611 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1612 return d->vector[i];
1616 /* Deletes all vectors from D. */
1618 dict_clear_vectors (struct dictionary *d)
1622 for (i = 0; i < d->n_vectors; i++)
1623 vector_destroy (d->vector[i]);
1630 /* Multiple response sets. */
1632 /* Returns the multiple response set in DICT with index IDX, which must be
1633 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1634 const struct mrset *
1635 dict_get_mrset (const struct dictionary *dict, size_t idx)
1637 assert (idx < dict->n_mrsets);
1638 return dict->mrsets[idx];
1641 /* Returns the number of multiple response sets in DICT. */
1643 dict_get_n_mrsets (const struct dictionary *dict)
1645 return dict->n_mrsets;
1648 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1649 returns its index; otherwise, returns SIZE_MAX. */
1651 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1655 for (i = 0; i < dict->n_mrsets; i++)
1656 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1662 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1663 returns it; otherwise, returns NULL. */
1664 const struct mrset *
1665 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1667 size_t idx = dict_lookup_mrset_idx (dict, name);
1668 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1671 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1672 true if a set was replaced, false if none existed with the specified name.
1674 Ownership of MRSET is transferred to DICT. */
1676 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1680 assert (mrset_ok (mrset, dict));
1682 idx = dict_lookup_mrset_idx (dict, mrset->name);
1683 if (idx == SIZE_MAX)
1685 dict->mrsets = xrealloc (dict->mrsets,
1686 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1687 dict->mrsets[dict->n_mrsets++] = mrset;
1692 mrset_destroy (dict->mrsets[idx]);
1693 dict->mrsets[idx] = mrset;
1698 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1699 from DICT and returns true. If none is found, returns false without
1702 Deleting one multiple response set causes the indexes of other sets within
1705 dict_delete_mrset (struct dictionary *dict, const char *name)
1707 size_t idx = dict_lookup_mrset_idx (dict, name);
1708 if (idx != SIZE_MAX)
1710 mrset_destroy (dict->mrsets[idx]);
1711 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1718 /* Deletes all multiple response sets from DICT. */
1720 dict_clear_mrsets (struct dictionary *dict)
1724 for (i = 0; i < dict->n_mrsets; i++)
1725 mrset_destroy (dict->mrsets[i]);
1726 free (dict->mrsets);
1727 dict->mrsets = NULL;
1731 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1733 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1737 assert (dict_contains_var (dict, var));
1739 for (i = 0; i < dict->n_mrsets;)
1741 struct mrset *mrset = dict->mrsets[i];
1744 for (j = 0; j < mrset->n_vars;)
1745 if (mrset->vars[j] == var)
1746 remove_element (mrset->vars, mrset->n_vars--,
1747 sizeof *mrset->vars, j);
1751 if (mrset->n_vars < 2)
1753 mrset_destroy (mrset);
1754 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1761 /* Returns D's attribute set. The caller may examine or modify
1762 the attribute set, but must not destroy it. Destroying D or
1763 calling dict_set_attributes for D will also destroy D's
1766 dict_get_attributes (const struct dictionary *d)
1768 return CONST_CAST (struct attrset *, &d->attributes);
1771 /* Replaces D's attributes set by a copy of ATTRS. */
1773 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1775 attrset_destroy (&d->attributes);
1776 attrset_clone (&d->attributes, attrs);
1779 /* Returns true if D has at least one attribute in its attribute
1780 set, false if D's attribute set is empty. */
1782 dict_has_attributes (const struct dictionary *d)
1784 return attrset_count (&d->attributes) > 0;
1787 /* Called from variable.c to notify the dictionary that some property (indicated
1788 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1789 prior to the change. OLDVAR is destroyed by this function.
1792 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1794 if (var_has_vardict (v))
1796 const struct vardict_info *vardict = var_get_vardict (v);
1797 struct dictionary *d = vardict->dict;
1802 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1803 invalidate_proto (d);
1805 if (d->changed) d->changed (d, d->changed_data);
1806 if (d->callbacks && d->callbacks->var_changed)
1807 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1814 /* Dictionary used to contain "internal variables". */
1815 static struct dictionary *internal_dict;
1817 /* Create a variable of the specified WIDTH to be used for internal
1818 calculations only. The variable is assigned case index CASE_IDX. */
1820 dict_create_internal_var (int case_idx, int width)
1822 if (internal_dict == NULL)
1823 internal_dict = dict_create ("UTF-8");
1827 static int counter = INT_MAX / 2;
1828 struct variable *var;
1831 if (++counter == INT_MAX)
1832 counter = INT_MAX / 2;
1834 sprintf (name, "$internal%d", counter);
1835 var = dict_create_var (internal_dict, name, width);
1838 set_var_case_index (var, case_idx);
1844 /* Destroys VAR, which must have been created with
1845 dict_create_internal_var(). */
1847 dict_destroy_internal_var (struct variable *var)
1851 dict_delete_var (internal_dict, var);
1853 /* Destroy internal_dict if it has no variables left, just so that
1854 valgrind --leak-check --show-reachable won't show internal_dict. */
1855 if (dict_get_n_vars (internal_dict) == 0)
1857 dict_unref (internal_dict);
1858 internal_dict = NULL;
1864 vardict_get_dict_index (const struct vardict_info *vardict)
1866 return vardict - vardict->dict->vars;