1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014,
3 2015, 2020 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #include "data/dictionary.h"
27 #include "data/attributes.h"
28 #include "data/case.h"
29 #include "data/identifier.h"
30 #include "data/mrset.h"
31 #include "data/settings.h"
32 #include "data/value-labels.h"
33 #include "data/vardict.h"
34 #include "data/variable.h"
35 #include "data/varset.h"
36 #include "data/vector.h"
37 #include "libpspp/array.h"
38 #include "libpspp/assertion.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/hash-functions.h"
41 #include "libpspp/hmap.h"
42 #include "libpspp/i18n.h"
43 #include "libpspp/message.h"
44 #include "libpspp/misc.h"
45 #include "libpspp/pool.h"
46 #include "libpspp/str.h"
47 #include "libpspp/string-array.h"
48 #include "libpspp/ll.h"
50 #include "gl/intprops.h"
51 #include "gl/minmax.h"
52 #include "gl/xalloc.h"
53 #include "gl/xmemdup0.h"
56 #define _(msgid) gettext (msgid)
62 struct vardict_info *vars; /* Variables. */
63 size_t n_vars; /* Number of variables. */
64 size_t allocated_vars; /* Allocated space in 'vars'. */
65 struct caseproto *proto; /* Prototype for dictionary cases
67 struct hmap name_map; /* Variable index by name. */
68 const struct variable **split; /* SPLIT FILE vars. */
69 size_t n_splits; /* SPLIT FILE count. */
70 enum split_type split_type;
71 struct variable *weight; /* WEIGHT variable. */
72 struct variable *filter; /* FILTER variable. */
73 casenumber case_limit; /* Current case limit (N command). */
74 char *label; /* File label. */
75 struct string_array documents; /* Documents. */
76 struct vector **vector; /* Vectors of variables. */
77 size_t n_vectors; /* Number of vectors. */
78 struct attrset attributes; /* Custom attributes. */
79 struct mrset **mrsets; /* Multiple response sets. */
80 size_t n_mrsets; /* Number of multiple response sets. */
81 struct varset **varsets; /* Variable sets. */
82 size_t n_varsets; /* Number of variable sets. */
84 /* Whether variable names must be valid identifiers. Normally, this is
85 true, but sometimes a dictionary is prepared for external use
86 (e.g. output to a CSV file) where names don't have to be valid. */
87 bool names_must_be_ids;
89 char *encoding; /* Character encoding of string data */
91 const struct dict_callbacks *callbacks; /* Callbacks on dictionary
93 void *cb_data ; /* Data passed to callbacks */
95 void (*changed) (struct dictionary *, void *); /* Generic change callback */
99 static void dict_unset_split_var (struct dictionary *, struct variable *, bool);
100 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
101 static void dict_unset_varset_var (struct dictionary *, struct variable *);
103 /* Compares two double pointers to variables, which should point
104 to elements of a struct dictionary's `var' member array. */
106 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
108 struct variable *const *a = a_;
109 struct variable *const *b = b_;
111 return *a < *b ? -1 : *a > *b;
115 unindex_var (struct dictionary *d, struct vardict_info *vardict)
117 hmap_delete (&d->name_map, &vardict->name_node);
120 /* This function assumes that vardict->name_node.hash is valid, that is, that
121 its name has not changed since it was hashed (rename_var() updates this
122 hash along with the name itself). */
124 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
126 struct variable *old = (d->callbacks && d->callbacks->var_changed
127 ? var_clone (vardict->var)
130 struct variable *var = vardict->var;
131 var_set_vardict (var, vardict);
132 hmap_insert_fast (&d->name_map, &vardict->name_node,
133 vardict->name_node.hash);
135 if (! skip_callbacks)
137 if (d->changed) d->changed (d, d->changed_data);
140 d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
146 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
149 unindex_vars (struct dictionary *d, size_t from, size_t to)
153 for (i = from; i < to; i++)
154 unindex_var (d, &d->vars[i]);
157 /* Re-sets the dict_index in the dictionary variables with
158 indexes from FROM to TO (exclusive). */
160 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
164 for (i = from; i < to; i++)
165 reindex_var (d, &d->vars[i], skip_callbacks);
170 /* Returns the encoding for data in dictionary D. The return value is a
171 nonnull string that contains an IANA character set name. */
173 dict_get_encoding (const struct dictionary *d)
178 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
179 encoding. Returns true if it is, otherwise an error message that the caller
181 char * WARN_UNUSED_RESULT
182 dict_id_is_valid__ (const struct dictionary *dict, const char *id)
184 if (!dict->names_must_be_ids)
186 return id_is_valid__ (id, dict->encoding);
190 error_to_bool (char *error)
201 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
202 encoding, false otherwise. */
204 dict_id_is_valid (const struct dictionary *dict, const char *id)
206 return error_to_bool (dict_id_is_valid__ (dict, id));
210 dict_set_change_callback (struct dictionary *d,
211 void (*changed) (struct dictionary *, void*),
214 d->changed = changed;
215 d->changed_data = data;
218 /* Discards dictionary D's caseproto. (It will be regenerated
219 lazily, on demand.) */
221 invalidate_proto (struct dictionary *d)
223 caseproto_unref (d->proto);
227 /* Print a representation of dictionary D to stdout, for
228 debugging purposes. */
230 dict_dump (const struct dictionary *d)
232 for (size_t i = 0; i < d->n_vars; ++i)
233 printf ("%zu: %s\n", i, var_get_name (d->vars[i].var));
236 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
237 the dictionary or any of the variables it contains are modified.
238 Each callback will get passed CALLBACK_DATA.
239 Any callback may be NULL, in which case it'll be ignored.
242 dict_set_callbacks (struct dictionary *dict,
243 const struct dict_callbacks *callbacks,
246 dict->callbacks = callbacks;
247 dict->cb_data = callback_data;
250 /* Shallow copy the callbacks from SRC to DEST */
252 dict_copy_callbacks (struct dictionary *dest,
253 const struct dictionary *src)
255 dest->callbacks = src->callbacks;
256 dest->cb_data = src->cb_data;
259 /* Creates and returns a new dictionary with the specified ENCODING. */
261 dict_create (const char *encoding)
263 struct dictionary *d = xmalloc (sizeof *d);
265 *d = (struct dictionary) {
266 .encoding = xstrdup (encoding),
267 .names_must_be_ids = true,
268 .name_map = HMAP_INITIALIZER (d->name_map),
269 .attributes = ATTRSET_INITIALIZER (d->attributes),
270 .split_type = SPLIT_NONE,
277 /* Creates and returns a (deep) copy of an existing
280 Callbacks are not cloned. */
282 dict_clone (const struct dictionary *s)
284 struct dictionary *d = dict_create (s->encoding);
285 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
287 for (size_t i = 0; i < s->n_vars; i++)
289 struct variable *sv = s->vars[i].var;
290 struct variable *dv = dict_clone_var_assert (d, sv);
292 for (size_t j = 0; j < var_get_n_short_names (sv); j++)
293 var_set_short_name (dv, j, var_get_short_name (sv, j));
296 d->n_splits = s->n_splits;
299 d->split = xnmalloc (d->n_splits, sizeof *d->split);
300 for (size_t i = 0; i < d->n_splits; i++)
301 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
303 d->split_type = s->split_type;
305 if (s->weight != NULL)
306 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
308 if (s->filter != NULL)
309 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
311 d->case_limit = s->case_limit;
312 dict_set_label (d, dict_get_label (s));
313 dict_set_documents (d, dict_get_documents (s));
315 d->n_vectors = s->n_vectors;
316 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
317 for (size_t i = 0; i < s->n_vectors; i++)
318 d->vector[i] = vector_clone (s->vector[i], s, d);
320 dict_set_attributes (d, dict_get_attributes (s));
322 for (size_t i = 0; i < s->n_mrsets; i++)
324 const struct mrset *old = s->mrsets[i];
328 /* Clone old mrset, then replace vars from D by vars from S. */
329 new = mrset_clone (old);
330 for (j = 0; j < new->n_vars; j++)
331 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
333 dict_add_mrset (d, new);
336 for (size_t i = 0; i < s->n_varsets; i++)
338 const struct varset *old = s->varsets[i];
340 /* Clone old varset, then replace vars from D by vars from S. */
341 struct varset *new = varset_clone (old);
342 for (size_t j = 0; j < new->n_vars; j++)
343 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
345 dict_add_varset (d, new);
351 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
352 dict_get_n_splits() to determine how many SPLIT FILE vars
353 there are. Returns a null pointer if and only if there are no
355 const struct variable *const *
356 dict_get_split_vars (const struct dictionary *d)
361 /* Returns the number of SPLIT FILE vars. */
363 dict_get_n_splits (const struct dictionary *d)
368 /* Removes variable V, which must be in D, from D's set of split
371 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
375 assert (dict_contains_var (d, v));
377 orig_count = d->n_splits;
378 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
379 &v, compare_var_ptrs, NULL);
380 if (orig_count != d->n_splits && !skip_callbacks)
382 if (d->changed) d->changed (d, d->changed_data);
383 /* We changed the set of split variables so invoke the
385 if (d->callbacks && d->callbacks->split_changed)
386 d->callbacks->split_changed (d, d->cb_data);
391 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
394 dict_set_split_vars__ (struct dictionary *d,
395 struct variable *const *split, size_t n,
396 enum split_type type, bool skip_callbacks)
400 assert (n == 0 || split != NULL);
403 d->split_type = (n == 0 ? SPLIT_NONE
404 : type == SPLIT_NONE ? SPLIT_LAYERED
408 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
409 memcpy (d->split, split, n * sizeof *d->split);
419 if (d->changed) d->changed (d, d->changed_data);
420 if (d->callbacks && d->callbacks->split_changed)
421 d->callbacks->split_changed (d, d->cb_data);
426 dict_get_split_type (const struct dictionary *d)
428 return d->split_type;
431 /* Sets N split vars SPLIT in dictionary D. */
433 dict_set_split_vars (struct dictionary *d,
434 struct variable *const *split, size_t n,
435 enum split_type type)
437 dict_set_split_vars__ (d, split, n, type, false);
441 dict_clear_split_vars (struct dictionary *d)
443 dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
447 /* Deletes variable V from dictionary D and frees V.
449 This is a very bad idea if there might be any pointers to V
450 from outside D. In general, no variable in the active dataset's
451 dictionary should be deleted when any transformations are
452 active on the dictionary's dataset, because those
453 transformations might reference the deleted variable. The
454 safest time to delete a variable is just after a procedure has
455 been executed, as done by DELETE VARIABLES.
457 Pointers to V within D are not a problem, because
458 dict_delete_var() knows to remove V from split variables,
459 weights, filters, etc. */
461 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
463 int dict_index = var_get_dict_index (v);
465 assert (dict_contains_var (d, v));
467 dict_unset_split_var (d, v, skip_callbacks);
468 dict_unset_mrset_var (d, v);
469 dict_unset_varset_var (d, v);
472 dict_set_weight (d, NULL);
475 dict_set_filter (d, NULL);
477 dict_clear_vectors (d);
479 /* Remove V from var array. */
480 unindex_vars (d, dict_index, d->n_vars);
481 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
484 /* Update dict_index for each affected variable. */
485 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
488 var_clear_vardict (v);
490 if (! skip_callbacks)
492 if (d->changed) d->changed (d, d->changed_data);
493 if (d->callbacks && d->callbacks->vars_deleted)
494 d->callbacks->vars_deleted (d, dict_index, 1, d->cb_data);
497 invalidate_proto (d);
501 /* Deletes variable V from dictionary D and frees V.
503 This is a very bad idea if there might be any pointers to V
504 from outside D. In general, no variable in the active dataset's
505 dictionary should be deleted when any transformations are
506 active on the dictionary's dataset, because those
507 transformations might reference the deleted variable. The
508 safest time to delete a variable is just after a procedure has
509 been executed, as done by DELETE VARIABLES.
511 Pointers to V within D are not a problem, because
512 dict_delete_var() knows to remove V from split variables,
513 weights, filters, etc. */
515 dict_delete_var (struct dictionary *d, struct variable *v)
517 dict_delete_var__ (d, v, false);
518 invalidate_proto (d);
522 /* Deletes the COUNT variables listed in VARS from D. This is
523 unsafe; see the comment on dict_delete_var() for details. */
525 dict_delete_vars (struct dictionary *d,
526 struct variable *const *vars, size_t count)
528 /* FIXME: this can be done in O(count) time, but this algorithm
530 assert (count == 0 || vars != NULL);
533 dict_delete_var (d, *vars++);
534 invalidate_proto (d);
537 /* Deletes the COUNT variables in D starting at index IDX. This
538 is unsafe; see the comment on dict_delete_var() for
539 details. Deleting consecutive vars will result in less callbacks
540 compared to iterating over dict_delete_var.
541 A simple while loop over dict_delete_var will
542 produce (d->n_vars - IDX) * COUNT variable changed callbacks
543 plus COUNT variable delete callbacks.
544 This here produces d->n_vars - IDX variable changed callbacks
545 plus COUNT variable delete callbacks. */
547 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
549 assert (idx + count <= d->n_vars);
551 struct variable **vars = xnmalloc (count, sizeof *vars);
553 for (size_t i = 0; i < count; i++)
555 struct variable *v = d->vars[idx + i].var;
558 dict_unset_split_var (d, v, false);
559 dict_unset_mrset_var (d, v);
560 dict_unset_varset_var (d, v);
563 dict_set_weight (d, NULL);
566 dict_set_filter (d, NULL);
569 dict_clear_vectors (d);
571 /* Remove variables from var array. */
572 unindex_vars (d, idx, d->n_vars);
573 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
576 /* Reindexing will result variable-changed callback */
577 reindex_vars (d, idx, d->n_vars, false);
579 invalidate_proto (d);
580 if (d->changed) d->changed (d, d->changed_data);
582 /* Now issue the variable delete callbacks and delete
583 the variables. The vardict is not valid at this point
585 if (d->callbacks && d->callbacks->vars_deleted)
586 d->callbacks->vars_deleted (d, idx, count, d->cb_data);
587 for (size_t i = 0; i < count; i++)
589 var_clear_vardict (vars[i]);
594 invalidate_proto (d);
597 /* Deletes scratch variables from dictionary D. */
599 dict_delete_scratch_vars (struct dictionary *d)
603 /* FIXME: this can be done in O(count) time, but this algorithm
605 for (i = 0; i < d->n_vars;)
606 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
607 dict_delete_var (d, d->vars[i].var);
611 invalidate_proto (d);
616 /* Clears the contents from a dictionary without destroying the
617 dictionary itself. */
619 dict_clear__ (struct dictionary *d, bool skip_callbacks)
621 /* FIXME? Should we really clear case_limit, label, documents?
622 Others are necessarily cleared by deleting all the variables.*/
623 while (d->n_vars > 0)
625 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
630 d->n_vars = d->allocated_vars = 0;
631 invalidate_proto (d);
632 hmap_clear (&d->name_map);
633 dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
642 dict_set_weight (d, NULL);
643 dict_set_filter (d, NULL);
648 string_array_clear (&d->documents);
649 dict_clear_vectors (d);
650 attrset_clear (&d->attributes);
653 /* Clears the contents from a dictionary without destroying the
654 dictionary itself. */
656 dict_clear (struct dictionary *d)
658 dict_clear__ (d, false);
661 /* Clears a dictionary and destroys it. */
663 _dict_destroy (struct dictionary *d)
665 /* In general, we don't want callbacks occurring, if the dictionary
666 is being destroyed */
667 d->callbacks = NULL ;
669 dict_clear__ (d, true);
670 string_array_destroy (&d->documents);
671 hmap_destroy (&d->name_map);
672 attrset_destroy (&d->attributes);
673 dict_clear_mrsets (d);
674 dict_clear_varsets (d);
680 dict_ref (struct dictionary *d)
687 dict_unref (struct dictionary *d)
692 assert (d->ref_cnt >= 0);
697 /* Returns the number of variables in D. */
699 dict_get_n_vars (const struct dictionary *d)
704 /* Returns the variable in D with dictionary index IDX, which
705 must be between 0 and the count returned by
706 dict_get_n_vars(), exclusive. */
708 dict_get_var (const struct dictionary *d, size_t idx)
710 assert (idx < d->n_vars);
712 return d->vars[idx].var;
715 /* Sets *VARS to an array of pointers to variables in D and *N
716 to the number of variables in *D. All variables are returned
717 except for those, if any, in the classes indicated by EXCLUDE.
718 (There is no point in putting DC_SYSTEM in EXCLUDE as
719 dictionaries never include system variables.) */
721 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
722 size_t *n, enum dict_class exclude)
724 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
727 /* Sets *VARS to an array of pointers to variables in D and *N
728 to the number of variables in *D. All variables are returned
729 except for those, if any, in the classes indicated by EXCLUDE.
730 (There is no point in putting DC_SYSTEM in EXCLUDE as
731 dictionaries never include system variables.) */
733 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
734 size_t *n, enum dict_class exclude)
739 assert (exclude == (exclude & DC_ALL));
742 for (i = 0; i < d->n_vars; i++)
744 enum dict_class class = var_get_dict_class (d->vars[i].var);
745 if (!(class & exclude))
749 *vars = xnmalloc (count, sizeof **vars);
751 for (i = 0; i < d->n_vars; i++)
753 enum dict_class class = var_get_dict_class (d->vars[i].var);
754 if (!(class & exclude))
755 (*vars)[(*n)++] = d->vars[i].var;
757 assert (*n == count);
760 static struct variable *
761 add_var (struct dictionary *d, struct variable *v)
763 /* Update dictionary. */
764 if (d->n_vars >= d->allocated_vars)
768 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
769 hmap_clear (&d->name_map);
770 for (i = 0; i < d->n_vars; i++)
772 var_set_vardict (d->vars[i].var, &d->vars[i]);
773 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
774 d->vars[i].name_node.hash);
778 struct vardict_info *vardict = &d->vars[d->n_vars++];
779 *vardict = (struct vardict_info) {
783 hmap_insert (&d->name_map, &vardict->name_node,
784 utf8_hash_case_string (var_get_name (v), 0));
785 var_set_vardict (v, vardict);
787 if (d->changed) d->changed (d, d->changed_data);
788 if (d->callbacks && d->callbacks->var_added)
789 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
791 invalidate_proto (d);
796 /* Creates and returns a new variable in D with the given NAME
797 and WIDTH. Returns a null pointer if the given NAME would
798 duplicate that of an existing variable in the dictionary. */
800 dict_create_var (struct dictionary *d, const char *name, int width)
802 return (dict_lookup_var (d, name) == NULL
803 ? dict_create_var_assert (d, name, width)
807 /* Creates and returns a new variable in D with the given NAME
808 and WIDTH. Assert-fails if the given NAME would duplicate
809 that of an existing variable in the dictionary. */
811 dict_create_var_assert (struct dictionary *d, const char *name, int width)
813 assert (dict_lookup_var (d, name) == NULL);
814 return add_var (d, var_create (name, width));
817 /* Creates and returns a new variable in D, as a copy of existing variable
818 OLD_VAR, which need not be in D or in any dictionary. Returns a null
819 pointer if OLD_VAR's name would duplicate that of an existing variable in
822 dict_clone_var (struct dictionary *d, const struct variable *old_var)
824 return dict_clone_var_as (d, old_var, var_get_name (old_var));
827 /* Creates and returns a new variable in D, as a copy of existing variable
828 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
829 OLD_VAR's name would duplicate that of an existing variable in the
832 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
834 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
837 /* Creates and returns a new variable in D with name NAME, as a copy of
838 existing variable OLD_VAR, which need not be in D or in any dictionary.
839 Returns a null pointer if the given NAME would duplicate that of an existing
840 variable in the dictionary. */
842 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
845 return (dict_lookup_var (d, name) == NULL
846 ? dict_clone_var_as_assert (d, old_var, name)
850 /* Creates and returns a new variable in D with name NAME, as a copy of
851 existing variable OLD_VAR, which need not be in D or in any dictionary.
852 Assert-fails if the given NAME would duplicate that of an existing variable
853 in the dictionary. */
855 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
858 struct variable *new_var = var_clone (old_var);
859 assert (dict_lookup_var (d, name) == NULL);
860 var_set_name (new_var, name);
861 return add_var (d, new_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 assert (new_index < d->n_vars);
909 size_t old_index = var_get_dict_index (v);
910 if (new_index == old_index)
913 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
914 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
915 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
917 if (d->callbacks && d->callbacks->var_moved)
918 d->callbacks->var_moved (d, new_index, old_index, d->cb_data);
921 /* Reorders the variables in D, placing the COUNT variables
922 listed in ORDER in that order at the beginning of D. The
923 other variables in D, if any, retain their relative
926 dict_reorder_vars (struct dictionary *d,
927 struct variable *const *order, size_t count)
929 struct vardict_info *new_var;
932 assert (count == 0 || order != NULL);
933 assert (count <= d->n_vars);
935 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
937 /* Add variables in ORDER to new_var. */
938 for (i = 0; i < count; i++)
940 struct vardict_info *old_var;
942 assert (dict_contains_var (d, order[i]));
944 old_var = var_get_vardict (order[i]);
945 new_var[i] = *old_var;
946 old_var->dict = NULL;
949 /* Add remaining variables to new_var. */
950 for (i = 0; i < d->n_vars; i++)
951 if (d->vars[i].dict != NULL)
952 new_var[count++] = d->vars[i];
953 assert (count == d->n_vars);
955 /* Replace old vardicts by new ones. */
959 hmap_clear (&d->name_map);
960 reindex_vars (d, 0, d->n_vars, false);
963 /* Changes the name of variable V that is currently in a dictionary to
966 rename_var (struct variable *v, const char *new_name)
968 struct vardict_info *vardict = var_get_vardict (v);
969 var_clear_vardict (v);
970 var_set_name (v, new_name);
971 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
972 var_set_vardict (v, vardict);
975 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
976 successful, false if a variable (other than V) with the given name already
979 dict_try_rename_var (struct dictionary *d, struct variable *v,
980 const char *new_name)
982 struct variable *conflict = dict_lookup_var (d, new_name);
983 if (conflict && v != conflict)
986 struct variable *old = var_clone (v);
987 unindex_var (d, var_get_vardict (v));
988 rename_var (v, new_name);
989 reindex_var (d, var_get_vardict (v), false);
991 if (settings_get_algorithm () == ENHANCED)
992 var_clear_short_names (v);
994 if (d->changed) d->changed (d, d->changed_data);
995 if (d->callbacks && d->callbacks->var_changed)
996 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1003 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1004 a variable named NEW_NAME is already in D, except that
1005 NEW_NAME may be the same as V's existing name. */
1007 dict_rename_var (struct dictionary *d, struct variable *v,
1008 const char *new_name)
1010 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1014 /* Renames COUNT variables specified in VARS to the names given
1015 in NEW_NAMES within dictionary D. If the renaming would
1016 result in a duplicate variable name, returns false and stores a
1017 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1018 non-null). Otherwise, the renaming is successful, and true
1021 dict_rename_vars (struct dictionary *d,
1022 struct variable **vars, char **new_names, size_t count,
1029 assert (count == 0 || vars != NULL);
1030 assert (count == 0 || new_names != NULL);
1032 /* Save the names of the variables to be renamed. */
1033 pool = pool_create ();
1034 old_names = pool_nalloc (pool, count, sizeof *old_names);
1035 for (i = 0; i < count; i++)
1036 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1038 /* Remove the variables to be renamed from the name hash,
1040 for (i = 0; i < count; i++)
1042 unindex_var (d, var_get_vardict (vars[i]));
1043 rename_var (vars[i], new_names[i]);
1046 /* Add the renamed variables back into the name hash,
1047 checking for conflicts. */
1048 for (i = 0; i < count; i++)
1050 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1052 /* There is a name conflict.
1053 Back out all the name changes that have already
1054 taken place, and indicate failure. */
1055 size_t fail_idx = i;
1056 if (err_name != NULL)
1057 *err_name = new_names[i];
1059 for (i = 0; i < fail_idx; i++)
1060 unindex_var (d, var_get_vardict (vars[i]));
1062 for (i = 0; i < count; i++)
1064 rename_var (vars[i], old_names[i]);
1065 reindex_var (d, var_get_vardict (vars[i]), false);
1068 pool_destroy (pool);
1071 reindex_var (d, var_get_vardict (vars[i]), false);
1074 /* Clear short names. */
1075 if (settings_get_algorithm () == ENHANCED)
1076 for (i = 0; i < count; i++)
1077 var_clear_short_names (vars[i]);
1079 pool_destroy (pool);
1083 /* Returns true if a variable named NAME may be inserted in DICT;
1084 that is, if there is not already a variable with that name in
1085 DICT and if NAME is not a reserved word. (The caller's checks
1086 have already verified that NAME is otherwise acceptable as a
1089 var_name_is_insertable (const struct dictionary *dict, const char *name)
1091 return (dict_lookup_var (dict, name) == NULL
1092 && lex_id_to_token (ss_cstr (name)) == T_ID);
1096 make_hinted_name (const struct dictionary *dict, const char *hint)
1098 size_t hint_len = strlen (hint);
1099 bool dropped = false;
1104 if (hint_len > ID_MAX_LEN)
1105 hint_len = ID_MAX_LEN;
1107 /* The allocation size here is OK: characters that are copied directly fit
1108 OK, and characters that are not copied directly are replaced by a single
1109 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1110 replaced by '_' too. */
1111 root = rp = xmalloc (hint_len + 1);
1112 for (ofs = 0; ofs < hint_len; ofs += mblen)
1116 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1119 ? lex_uc_is_id1 (uc) && uc != '$'
1120 : lex_uc_is_idn (uc))
1127 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1129 else if (rp != root)
1134 if (root[0] != '\0')
1136 unsigned long int i;
1138 if (var_name_is_insertable (dict, root))
1141 for (i = 0; i < ULONG_MAX; i++)
1143 char suffix[INT_BUFSIZE_BOUND (i) + 1];
1147 if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1150 name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1151 if (var_name_is_insertable (dict, name))
1166 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1168 unsigned long int number;
1170 for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1174 char name[3 + INT_STRLEN_BOUND (number) + 1];
1176 sprintf (name, "VAR%03lu", number);
1177 if (dict_lookup_var (dict, name) == NULL)
1179 if (num_start != NULL)
1180 *num_start = number + 1;
1181 return xstrdup (name);
1189 /* Devises and returns a variable name unique within DICT. The variable name
1190 is owned by the caller, which must free it with free() when it is no longer
1193 HINT, if it is non-null, is used as a suggestion that will be
1194 modified for suitability as a variable name and for
1197 If HINT is null or entirely unsuitable, a name in the form
1198 "VAR%03d" will be generated, where the smallest unused integer
1199 value is used. If NUM_START is non-null, then its value is
1200 used as the minimum numeric value to check, and it is updated
1201 to the next value to be checked.
1204 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1205 unsigned long int *num_start)
1209 char *hinted_name = make_hinted_name (dict, hint);
1210 if (hinted_name != NULL)
1214 return make_numeric_name (dict, num_start);
1217 /* Returns whether variable names must be valid identifiers. Normally, this is
1218 true, but sometimes a dictionary is prepared for external use (e.g. output
1219 to a CSV file) where names don't have to be valid. */
1221 dict_get_names_must_be_ids (const struct dictionary *d)
1223 return d->names_must_be_ids;
1226 /* Sets whether variable names must be valid identifiers. Normally, this is
1227 true, but sometimes a dictionary is prepared for external use (e.g. output
1228 to a CSV file) where names don't have to be valid.
1230 Changing this setting from false to true doesn't make the dictionary check
1231 all the existing variable names, so it can cause an invariant violation. */
1233 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1235 d->names_must_be_ids = names_must_be_ids;
1238 /* Returns the weighting variable in dictionary D, or a null
1239 pointer if the dictionary is unweighted. */
1241 dict_get_weight (const struct dictionary *d)
1243 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1248 /* Returns the value of D's weighting variable in case C, except
1249 that a negative or missing weight is returned as 0. Returns 1 if the
1250 dictionary is unweighted. Will warn about missing, negative,
1251 or zero values if *WARN_ON_INVALID is true. The function will
1252 set *WARN_ON_INVALID to false if an invalid weight is
1255 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1256 bool *warn_on_invalid)
1260 if (d->weight == NULL)
1264 double w = case_num (c, d->weight);
1266 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1270 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1273 dict_get_rounded_case_weight (const struct dictionary *d,
1274 const struct ccase *c, bool *warn_on_invalid)
1276 return floor (dict_get_case_weight (d, c, warn_on_invalid) + 0.5);
1279 /* Returns the format to use for weights. */
1281 dict_get_weight_format (const struct dictionary *d)
1283 return d->weight ? var_get_print_format (d->weight) : F_8_0;
1286 /* Sets the weighting variable of D to V, or turning off
1287 weighting if V is a null pointer. */
1289 dict_set_weight (struct dictionary *d, struct variable *v)
1291 assert (v == NULL || dict_contains_var (d, v));
1292 assert (v == NULL || var_is_numeric (v));
1296 if (d->changed) d->changed (d, d->changed_data);
1297 if (d->callbacks && d->callbacks->weight_changed)
1298 d->callbacks->weight_changed (d,
1299 v ? var_get_dict_index (v) : -1,
1303 /* Returns the filter variable in dictionary D (see cmd_filter())
1304 or a null pointer if the dictionary is unfiltered. */
1306 dict_get_filter (const struct dictionary *d)
1308 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1313 /* Sets V as the filter variable for dictionary D. Passing a
1314 null pointer for V turn off filtering. */
1316 dict_set_filter (struct dictionary *d, struct variable *v)
1318 assert (v == NULL || dict_contains_var (d, v));
1319 assert (v == NULL || var_is_numeric (v));
1323 if (d->changed) d->changed (d, d->changed_data);
1324 if (d->callbacks && d->callbacks->filter_changed)
1325 d->callbacks->filter_changed (d,
1326 v ? var_get_dict_index (v) : -1,
1330 /* Returns the case limit for dictionary D, or zero if the number
1331 of cases is unlimited. */
1333 dict_get_case_limit (const struct dictionary *d)
1335 return d->case_limit;
1338 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1339 0 for CASE_LIMIT to indicate no limit. */
1341 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1343 d->case_limit = case_limit;
1346 /* Returns the prototype used for cases created by dictionary D. */
1347 const struct caseproto *
1348 dict_get_proto (const struct dictionary *d_)
1350 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1351 if (d->proto == NULL)
1353 short int *widths = xnmalloc (d->n_vars, sizeof *widths);
1354 for (size_t i = 0; i < d->n_vars; i++)
1355 widths[i] = var_get_width (d->vars[i].var);
1356 d->proto = caseproto_from_widths (widths, d->n_vars);
1361 /* Returns the number of values occupied by the variables in
1362 dictionary D. All variables are considered if EXCLUDE_CLASSES
1363 is 0, or it may contain one or more of DC_ORDINARY, DC_SYSTEM,
1364 or DC_SCRATCH to exclude the corresponding type of variable. */
1366 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1368 assert (!(exclude_classes & ~DC_ALL));
1371 for (size_t i = 0; i < d->n_vars; i++)
1373 enum dict_class class = var_get_dict_class (d->vars[i].var);
1374 if (!(exclude_classes & class))
1380 /* Returns the file label for D, or a null pointer if D is
1381 unlabeled (see cmd_file_label()). */
1383 dict_get_label (const struct dictionary *d)
1388 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1391 Removes D's label if LABEL is null or the empty string. */
1393 dict_set_label (struct dictionary *d, const char *label)
1396 if (label == NULL || label[0] == '\0')
1399 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1402 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1403 return value is always nonnull; if there are no documents then the
1404 string_arary is empty.*/
1405 const struct string_array *
1406 dict_get_documents (const struct dictionary *d)
1408 return &d->documents;
1411 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1413 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1415 /* Swap out the old documents, instead of destroying them immediately, to
1416 allow the new documents to include pointers into the old ones. */
1417 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1418 string_array_swap (&d->documents, &old_docs);
1420 for (size_t i = 0; i < new_docs->n; i++)
1421 dict_add_document_line (d, new_docs->strings[i], false);
1423 string_array_destroy (&old_docs);
1426 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1427 into individual lines at new-line characters. Each line is truncated to at
1428 most DOC_LINE_LENGTH bytes in D's encoding. */
1430 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1434 dict_clear_documents (d);
1435 for (s = new_docs; *s != '\0';)
1437 size_t len = strcspn (s, "\n");
1438 char *line = xmemdup0 (s, len);
1439 dict_add_document_line (d, line, false);
1448 /* Drops the documents from dictionary D. */
1450 dict_clear_documents (struct dictionary *d)
1452 string_array_clear (&d->documents);
1455 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1456 truncated so that it is no more than 80 bytes in the dictionary's
1457 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1458 then a warning will be issued. */
1460 dict_add_document_line (struct dictionary *d, const char *line,
1466 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1467 truncated = line[trunc_len] != '\0';
1468 if (truncated && issue_warning)
1470 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1471 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1474 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1479 /* Returns the number of document lines in dictionary D. */
1481 dict_get_document_n_lines (const struct dictionary *d)
1483 return d->documents.n;
1486 /* Returns document line number IDX in dictionary D. The caller must not
1487 modify or free the returned string. */
1489 dict_get_document_line (const struct dictionary *d, size_t idx)
1491 assert (idx < d->documents.n);
1492 return d->documents.strings[idx];
1495 /* Creates in D a vector named NAME that contains the N
1496 variables in VAR. Returns true if successful, or false if a
1497 vector named NAME already exists in D. */
1499 dict_create_vector (struct dictionary *d,
1501 struct variable **var, size_t n)
1504 for (size_t i = 0; i < n; i++)
1505 assert (dict_contains_var (d, var[i]));
1507 if (dict_lookup_vector (d, name) == NULL)
1509 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1510 d->vector[d->n_vectors++] = vector_create (name, var, n);
1517 /* Creates in D a vector named NAME that contains the N
1518 variables in VAR. A vector named NAME must not already exist
1521 dict_create_vector_assert (struct dictionary *d,
1523 struct variable **var, size_t n)
1525 assert (dict_lookup_vector (d, name) == NULL);
1526 dict_create_vector (d, name, var, n);
1529 /* Returns the vector in D with index IDX, which must be less
1530 than dict_get_n_vectors (D). */
1531 const struct vector *
1532 dict_get_vector (const struct dictionary *d, size_t idx)
1534 assert (idx < d->n_vectors);
1536 return d->vector[idx];
1539 /* Returns the number of vectors in D. */
1541 dict_get_n_vectors (const struct dictionary *d)
1543 return d->n_vectors;
1546 /* Looks up and returns the vector within D with the given
1548 const struct vector *
1549 dict_lookup_vector (const struct dictionary *d, const char *name)
1552 for (i = 0; i < d->n_vectors; i++)
1553 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1554 return d->vector[i];
1558 /* Deletes all vectors from D. */
1560 dict_clear_vectors (struct dictionary *d)
1564 for (i = 0; i < d->n_vectors; i++)
1565 vector_destroy (d->vector[i]);
1572 /* Multiple response sets. */
1574 /* Returns the multiple response set in DICT with index IDX, which must be
1575 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1576 const struct mrset *
1577 dict_get_mrset (const struct dictionary *dict, size_t idx)
1579 assert (idx < dict->n_mrsets);
1580 return dict->mrsets[idx];
1583 /* Returns the number of multiple response sets in DICT. */
1585 dict_get_n_mrsets (const struct dictionary *dict)
1587 return dict->n_mrsets;
1590 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1591 returns its index; otherwise, returns SIZE_MAX. */
1593 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1597 for (i = 0; i < dict->n_mrsets; i++)
1598 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1604 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1605 returns it; otherwise, returns NULL. */
1606 const struct mrset *
1607 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1609 size_t idx = dict_lookup_mrset_idx (dict, name);
1610 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1613 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1614 true if a set was replaced, false if none existed with the specified name.
1616 Ownership of MRSET is transferred to DICT. */
1618 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1622 assert (mrset_ok (mrset, dict));
1624 idx = dict_lookup_mrset_idx (dict, mrset->name);
1625 if (idx == SIZE_MAX)
1627 dict->mrsets = xrealloc (dict->mrsets,
1628 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1629 dict->mrsets[dict->n_mrsets++] = mrset;
1634 mrset_destroy (dict->mrsets[idx]);
1635 dict->mrsets[idx] = mrset;
1640 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1641 from DICT and returns true. If none is found, returns false without
1644 Deleting one multiple response set causes the indexes of other sets within
1647 dict_delete_mrset (struct dictionary *dict, const char *name)
1649 size_t idx = dict_lookup_mrset_idx (dict, name);
1650 if (idx != SIZE_MAX)
1652 mrset_destroy (dict->mrsets[idx]);
1653 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1660 /* Deletes all multiple response sets from DICT. */
1662 dict_clear_mrsets (struct dictionary *dict)
1666 for (i = 0; i < dict->n_mrsets; i++)
1667 mrset_destroy (dict->mrsets[i]);
1668 free (dict->mrsets);
1669 dict->mrsets = NULL;
1673 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1675 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1679 assert (dict_contains_var (dict, var));
1681 for (i = 0; i < dict->n_mrsets;)
1683 struct mrset *mrset = dict->mrsets[i];
1686 for (j = 0; j < mrset->n_vars;)
1687 if (mrset->vars[j] == var)
1688 remove_element (mrset->vars, mrset->n_vars--,
1689 sizeof *mrset->vars, j);
1693 if (mrset->n_vars < 2)
1695 mrset_destroy (mrset);
1696 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1704 /* Returns the variable set in DICT with index IDX, which must be between 0 and
1705 the count returned by dict_get_n_varsets(), exclusive. */
1706 const struct varset *
1707 dict_get_varset (const struct dictionary *dict, size_t idx)
1709 assert (idx < dict->n_varsets);
1710 return dict->varsets[idx];
1713 /* Returns the number of variable sets in DICT. */
1715 dict_get_n_varsets (const struct dictionary *dict)
1717 return dict->n_varsets;
1720 /* Looks for a variable set named NAME in DICT. If it finds one, returns its
1721 index; otherwise, returns SIZE_MAX. */
1723 dict_lookup_varset_idx (const struct dictionary *dict, const char *name)
1725 for (size_t i = 0; i < dict->n_varsets; i++)
1726 if (!utf8_strcasecmp (name, dict->varsets[i]->name))
1732 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1733 returns it; otherwise, returns NULL. */
1734 const struct varset *
1735 dict_lookup_varset (const struct dictionary *dict, const char *name)
1737 size_t idx = dict_lookup_varset_idx (dict, name);
1738 return idx != SIZE_MAX ? dict->varsets[idx] : NULL;
1741 /* Adds VARSET to DICT, replacing any existing set with the same name. Returns
1742 true if a set was replaced, false if none existed with the specified name.
1744 Ownership of VARSET is transferred to DICT. */
1746 dict_add_varset (struct dictionary *dict, struct varset *varset)
1748 size_t idx = dict_lookup_varset_idx (dict, varset->name);
1749 if (idx == SIZE_MAX)
1751 dict->varsets = xrealloc (dict->varsets,
1752 (dict->n_varsets + 1) * sizeof *dict->varsets);
1753 dict->varsets[dict->n_varsets++] = varset;
1758 varset_destroy (dict->varsets[idx]);
1759 dict->varsets[idx] = varset;
1764 /* Deletes all variable sets from DICT. */
1766 dict_clear_varsets (struct dictionary *dict)
1768 for (size_t i = 0; i < dict->n_varsets; i++)
1769 varset_destroy (dict->varsets[i]);
1770 free (dict->varsets);
1771 dict->varsets = NULL;
1772 dict->n_varsets = 0;
1775 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1777 dict_unset_varset_var (struct dictionary *dict, struct variable *var)
1779 assert (dict_contains_var (dict, var));
1781 for (size_t i = 0; i < dict->n_varsets; i++)
1783 struct varset *varset = dict->varsets[i];
1785 for (size_t j = 0; j < varset->n_vars;)
1786 if (varset->vars[j] == var)
1787 remove_element (varset->vars, varset->n_vars--,
1788 sizeof *varset->vars, j);
1794 /* Returns D's attribute set. The caller may examine or modify
1795 the attribute set, but must not destroy it. Destroying D or
1796 calling dict_set_attributes for D will also destroy D's
1799 dict_get_attributes (const struct dictionary *d)
1801 return CONST_CAST (struct attrset *, &d->attributes);
1804 /* Replaces D's attributes set by a copy of ATTRS. */
1806 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1808 attrset_destroy (&d->attributes);
1809 attrset_clone (&d->attributes, attrs);
1812 /* Returns true if D has at least one attribute in its attribute
1813 set, false if D's attribute set is empty. */
1815 dict_has_attributes (const struct dictionary *d)
1817 return attrset_count (&d->attributes) > 0;
1820 /* Called from variable.c to notify the dictionary that some property (indicated
1821 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1822 prior to the change. OLDVAR is destroyed by this function.
1825 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1827 if (var_has_vardict (v))
1829 const struct vardict_info *vardict = var_get_vardict (v);
1830 struct dictionary *d = vardict->dict;
1835 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1836 invalidate_proto (d);
1838 if (d->changed) d->changed (d, d->changed_data);
1839 if (d->callbacks && d->callbacks->var_changed)
1840 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1848 vardict_get_dict_index (const struct vardict_info *vardict)
1850 return vardict - vardict->dict->vars;