dictionary: Remove unused functions and prototypes.
[pspp.git] / src / data / dictionary.c
bloba55a12399150f566b6ca9a9842373ce4dc0c736e
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/>. */
18 #include <config.h>
20 #include "data/dictionary.h"
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <unistr.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"
55 #include "gettext.h"
56 #define _(msgid) gettext (msgid)
58 /* A dictionary. */
59 struct dictionary
61 int ref_cnt;
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
66 (updated lazily). */
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 /* Number of VAR### names created by dict_make_unique_var_name(), or
85 less. */
86 unsigned long int n_unique_names;
88 /* Whether variable names must be valid identifiers. Normally, this is
89 true, but sometimes a dictionary is prepared for external use
90 (e.g. output to a CSV file) where names don't have to be valid. */
91 bool names_must_be_ids;
93 char *encoding; /* Character encoding of string data */
95 const struct dict_callbacks *callbacks; /* Callbacks on dictionary
96 modification */
97 void *cb_data ; /* Data passed to callbacks */
99 void (*changed) (struct dictionary *, void *); /* Generic change callback */
100 void *changed_data;
103 static void dict_unset_split_var (struct dictionary *, struct variable *, bool);
104 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
105 static void dict_unset_varset_var (struct dictionary *, struct variable *);
107 /* Compares two double pointers to variables, which should point
108 to elements of a struct dictionary's `var' member array. */
109 static int
110 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
112 struct variable *const *a = a_;
113 struct variable *const *b = b_;
115 return *a < *b ? -1 : *a > *b;
118 static void
119 unindex_var (struct dictionary *d, struct vardict_info *vardict)
121 hmap_delete (&d->name_map, &vardict->name_node);
124 /* This function assumes that vardict->name_node.hash is valid, that is, that
125 its name has not changed since it was hashed (rename_var() updates this
126 hash along with the name itself). */
127 static void
128 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
130 struct variable *old = (d->callbacks && d->callbacks->var_changed
131 ? var_clone (vardict->var)
132 : NULL);
134 struct variable *var = vardict->var;
135 var_set_vardict (var, vardict);
136 hmap_insert_fast (&d->name_map, &vardict->name_node,
137 vardict->name_node.hash);
139 if (! skip_callbacks)
141 if (d->changed) d->changed (d, d->changed_data);
142 if (old)
144 d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
145 var_unref (old);
150 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
151 from name_map. */
152 static void
153 unindex_vars (struct dictionary *d, size_t from, size_t to)
155 size_t i;
157 for (i = from; i < to; i++)
158 unindex_var (d, &d->vars[i]);
161 /* Re-sets the dict_index in the dictionary variables with
162 indexes from FROM to TO (exclusive). */
163 static void
164 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
166 size_t i;
168 for (i = from; i < to; i++)
169 reindex_var (d, &d->vars[i], skip_callbacks);
174 /* Returns the encoding for data in dictionary D. The return value is a
175 nonnull string that contains an IANA character set name. */
176 const char *
177 dict_get_encoding (const struct dictionary *d)
179 return d->encoding ;
182 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
183 encoding for a variable in the classes in CLASSES. Returns true if it is,
184 otherwise an error message that the caller must free(). */
185 char * WARN_UNUSED_RESULT
186 dict_id_is_valid__ (const struct dictionary *dict, const char *id,
187 enum dict_class classes)
189 if (!dict->names_must_be_ids)
190 return NULL;
191 return id_is_valid__ (id, dict->encoding, classes);
194 static bool
195 error_to_bool (char *error)
197 if (error)
199 free (error);
200 return false;
202 else
203 return true;
206 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
207 encoding for a variable in the classes in CLASSES, false otherwise. */
208 bool
209 dict_id_is_valid (const struct dictionary *dict, const char *id,
210 enum dict_class classes)
212 return error_to_bool (dict_id_is_valid__ (dict, id, classes));
215 void
216 dict_set_change_callback (struct dictionary *d,
217 void (*changed) (struct dictionary *, void*),
218 void *data)
220 d->changed = changed;
221 d->changed_data = data;
224 /* Discards dictionary D's caseproto. (It will be regenerated
225 lazily, on demand.) */
226 static void
227 invalidate_proto (struct dictionary *d)
229 caseproto_unref (d->proto);
230 d->proto = NULL;
233 /* Print a representation of dictionary D to stdout, for
234 debugging purposes. */
235 void
236 dict_dump (const struct dictionary *d)
238 for (size_t i = 0; i < d->n_vars; ++i)
239 printf ("%zu: %s\n", i, var_get_name (d->vars[i].var));
242 /* Associate CALLBACKS with DICT. Callbacks will be invoked whenever
243 the dictionary or any of the variables it contains are modified.
244 Each callback will get passed CALLBACK_DATA.
245 Any callback may be NULL, in which case it'll be ignored.
247 void
248 dict_set_callbacks (struct dictionary *dict,
249 const struct dict_callbacks *callbacks,
250 void *callback_data)
252 dict->callbacks = callbacks;
253 dict->cb_data = callback_data;
256 /* Shallow copy the callbacks from SRC to DEST */
257 void
258 dict_copy_callbacks (struct dictionary *dest,
259 const struct dictionary *src)
261 dest->callbacks = src->callbacks;
262 dest->cb_data = src->cb_data;
265 /* Creates and returns a new dictionary with the specified ENCODING. */
266 struct dictionary *
267 dict_create (const char *encoding)
269 struct dictionary *d = xmalloc (sizeof *d);
271 *d = (struct dictionary) {
272 .encoding = xstrdup (encoding),
273 .names_must_be_ids = true,
274 .name_map = HMAP_INITIALIZER (d->name_map),
275 .attributes = ATTRSET_INITIALIZER (d->attributes),
276 .split_type = SPLIT_NONE,
277 .ref_cnt = 1,
280 return d;
283 /* Creates and returns a (deep) copy of an existing
284 dictionary.
286 Callbacks are not cloned. */
287 struct dictionary *
288 dict_clone (const struct dictionary *s)
290 struct dictionary *d = dict_create (s->encoding);
291 dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
293 for (size_t i = 0; i < s->n_vars; i++)
295 struct variable *sv = s->vars[i].var;
296 struct variable *dv = dict_clone_var_assert (d, sv);
298 for (size_t j = 0; j < var_get_n_short_names (sv); j++)
299 var_set_short_name (dv, j, var_get_short_name (sv, j));
302 d->n_splits = s->n_splits;
303 if (d->n_splits > 0)
305 d->split = xnmalloc (d->n_splits, sizeof *d->split);
306 for (size_t i = 0; i < d->n_splits; i++)
307 d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
309 d->split_type = s->split_type;
311 if (s->weight != NULL)
312 dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
314 if (s->filter != NULL)
315 dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
317 d->case_limit = s->case_limit;
318 dict_set_label (d, dict_get_label (s));
319 dict_set_documents (d, dict_get_documents (s));
321 d->n_vectors = s->n_vectors;
322 d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
323 for (size_t i = 0; i < s->n_vectors; i++)
324 d->vector[i] = vector_clone (s->vector[i], s, d);
326 dict_set_attributes (d, dict_get_attributes (s));
328 for (size_t i = 0; i < s->n_mrsets; i++)
330 const struct mrset *old = s->mrsets[i];
331 struct mrset *new;
332 size_t j;
334 /* Clone old mrset, then replace vars from D by vars from S. */
335 new = mrset_clone (old);
336 for (j = 0; j < new->n_vars; j++)
337 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
339 dict_add_mrset (d, new);
342 for (size_t i = 0; i < s->n_varsets; i++)
344 const struct varset *old = s->varsets[i];
346 /* Clone old varset, then replace vars from D by vars from S. */
347 struct varset *new = varset_clone (old);
348 for (size_t j = 0; j < new->n_vars; j++)
349 new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
351 dict_add_varset (d, new);
354 return d;
357 /* Returns the SPLIT FILE vars (see cmd_split_file()). Call
358 dict_get_n_splits() to determine how many SPLIT FILE vars
359 there are. Returns a null pointer if and only if there are no
360 SPLIT FILE vars. */
361 const struct variable *const *
362 dict_get_split_vars (const struct dictionary *d)
364 return d->split;
367 /* Returns the number of SPLIT FILE vars. */
368 size_t
369 dict_get_n_splits (const struct dictionary *d)
371 return d->n_splits;
374 /* Removes variable V, which must be in D, from D's set of split
375 variables. */
376 static void
377 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
379 int orig_count;
381 assert (dict_contains_var (d, v));
383 orig_count = d->n_splits;
384 d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
385 &v, compare_var_ptrs, NULL);
386 if (orig_count != d->n_splits && !skip_callbacks)
388 if (d->changed) d->changed (d, d->changed_data);
389 /* We changed the set of split variables so invoke the
390 callback. */
391 if (d->callbacks && d->callbacks->split_changed)
392 d->callbacks->split_changed (d, d->cb_data);
397 /* Sets N split vars SPLIT in dictionary D. N is silently capped to a maximum
398 of MAX_SPLITS. */
399 static void
400 dict_set_split_vars__ (struct dictionary *d,
401 struct variable *const *split, size_t n,
402 enum split_type type, bool skip_callbacks)
404 if (n > MAX_SPLITS)
405 n = MAX_SPLITS;
406 assert (n == 0 || split != NULL);
408 d->n_splits = n;
409 d->split_type = (n == 0 ? SPLIT_NONE
410 : type == SPLIT_NONE ? SPLIT_LAYERED
411 : type);
412 if (n > 0)
414 d->split = xnrealloc (d->split, n, sizeof *d->split) ;
415 memcpy (d->split, split, n * sizeof *d->split);
417 else
419 free (d->split);
420 d->split = NULL;
423 if (!skip_callbacks)
425 if (d->changed) d->changed (d, d->changed_data);
426 if (d->callbacks && d->callbacks->split_changed)
427 d->callbacks->split_changed (d, d->cb_data);
431 enum split_type
432 dict_get_split_type (const struct dictionary *d)
434 return d->split_type;
437 /* Sets N split vars SPLIT in dictionary D. */
438 void
439 dict_set_split_vars (struct dictionary *d,
440 struct variable *const *split, size_t n,
441 enum split_type type)
443 dict_set_split_vars__ (d, split, n, type, false);
446 void
447 dict_clear_split_vars (struct dictionary *d)
449 dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
453 /* Deletes variable V from dictionary D and frees V.
455 This is a very bad idea if there might be any pointers to V
456 from outside D. In general, no variable in the active dataset's
457 dictionary should be deleted when any transformations are
458 active on the dictionary's dataset, because those
459 transformations might reference the deleted variable. The
460 safest time to delete a variable is just after a procedure has
461 been executed, as done by DELETE VARIABLES.
463 Pointers to V within D are not a problem, because
464 dict_delete_var() knows to remove V from split variables,
465 weights, filters, etc. */
466 static void
467 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
469 d->n_unique_names = 0;
471 int dict_index = var_get_dict_index (v);
473 assert (dict_contains_var (d, v));
475 dict_unset_split_var (d, v, skip_callbacks);
476 dict_unset_mrset_var (d, v);
477 dict_unset_varset_var (d, v);
479 if (d->weight == v)
480 dict_set_weight (d, NULL);
482 if (d->filter == v)
483 dict_set_filter (d, NULL);
485 dict_clear_vectors (d);
487 /* Remove V from var array. */
488 unindex_vars (d, dict_index, d->n_vars);
489 remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
490 d->n_vars--;
492 /* Update dict_index for each affected variable. */
493 reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
495 /* Free memory. */
496 var_clear_vardict (v);
498 if (! skip_callbacks)
500 if (d->changed) d->changed (d, d->changed_data);
501 if (d->callbacks && d->callbacks->vars_deleted)
502 d->callbacks->vars_deleted (d, dict_index, 1, d->cb_data);
505 invalidate_proto (d);
506 var_unref (v);
509 /* Deletes variable V from dictionary D and frees V.
511 This is a very bad idea if there might be any pointers to V
512 from outside D. In general, no variable in the active dataset's
513 dictionary should be deleted when any transformations are
514 active on the dictionary's dataset, because those
515 transformations might reference the deleted variable. The
516 safest time to delete a variable is just after a procedure has
517 been executed, as done by DELETE VARIABLES.
519 Pointers to V within D are not a problem, because
520 dict_delete_var() knows to remove V from split variables,
521 weights, filters, etc. */
522 void
523 dict_delete_var (struct dictionary *d, struct variable *v)
525 dict_delete_var__ (d, v, false);
526 invalidate_proto (d);
530 /* Deletes the COUNT variables listed in VARS from D. This is
531 unsafe; see the comment on dict_delete_var() for details. */
532 void
533 dict_delete_vars (struct dictionary *d,
534 struct variable *const *vars, size_t count)
536 /* FIXME: this can be done in O(count) time, but this algorithm
537 is O(count**2). */
538 assert (count == 0 || vars != NULL);
540 while (count-- > 0)
541 dict_delete_var (d, *vars++);
542 invalidate_proto (d);
545 /* Deletes the COUNT variables in D starting at index IDX. This
546 is unsafe; see the comment on dict_delete_var() for
547 details. Deleting consecutive vars will result in less callbacks
548 compared to iterating over dict_delete_var.
549 A simple while loop over dict_delete_var will
550 produce (d->n_vars - IDX) * COUNT variable changed callbacks
551 plus COUNT variable delete callbacks.
552 This here produces d->n_vars - IDX variable changed callbacks
553 plus COUNT variable delete callbacks. */
554 void
555 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
557 assert (idx + count <= d->n_vars);
559 struct variable **vars = xnmalloc (count, sizeof *vars);
561 for (size_t i = 0; i < count; i++)
563 struct variable *v = d->vars[idx + i].var;
564 vars[i] = v;
566 dict_unset_split_var (d, v, false);
567 dict_unset_mrset_var (d, v);
568 dict_unset_varset_var (d, v);
570 if (d->weight == v)
571 dict_set_weight (d, NULL);
573 if (d->filter == v)
574 dict_set_filter (d, NULL);
577 dict_clear_vectors (d);
579 /* Remove variables from var array. */
580 unindex_vars (d, idx, d->n_vars);
581 remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
582 d->n_vars -= count;
584 /* Reindexing will result variable-changed callback */
585 reindex_vars (d, idx, d->n_vars, false);
587 invalidate_proto (d);
588 if (d->changed) d->changed (d, d->changed_data);
590 /* Now issue the variable delete callbacks and delete
591 the variables. The vardict is not valid at this point
592 anymore. */
593 if (d->callbacks && d->callbacks->vars_deleted)
594 d->callbacks->vars_deleted (d, idx, count, d->cb_data);
595 for (size_t i = 0; i < count; i++)
597 var_clear_vardict (vars[i]);
598 var_unref (vars[i]);
600 free (vars);
602 invalidate_proto (d);
605 /* Deletes scratch variables from dictionary D. */
606 void
607 dict_delete_scratch_vars (struct dictionary *d)
609 int i;
611 /* FIXME: this can be done in O(count) time, but this algorithm
612 is O(count**2). */
613 for (i = 0; i < d->n_vars;)
614 if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
615 dict_delete_var (d, d->vars[i].var);
616 else
617 i++;
619 invalidate_proto (d);
624 /* Clears the contents from a dictionary without destroying the
625 dictionary itself. */
626 static void
627 dict_clear__ (struct dictionary *d, bool skip_callbacks)
629 /* FIXME? Should we really clear case_limit, label, documents?
630 Others are necessarily cleared by deleting all the variables.*/
631 while (d->n_vars > 0)
632 dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
634 free (d->vars);
635 d->vars = NULL;
636 d->n_vars = d->allocated_vars = 0;
637 invalidate_proto (d);
638 hmap_clear (&d->name_map);
639 dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
641 if (skip_callbacks)
643 d->weight = NULL;
644 d->filter = NULL;
646 else
648 dict_set_weight (d, NULL);
649 dict_set_filter (d, NULL);
651 d->case_limit = 0;
652 free (d->label);
653 d->label = NULL;
654 string_array_clear (&d->documents);
655 dict_clear_vectors (d);
656 attrset_clear (&d->attributes);
659 /* Clears the contents from a dictionary without destroying the
660 dictionary itself. */
661 void
662 dict_clear (struct dictionary *d)
664 dict_clear__ (d, false);
667 /* Clears a dictionary and destroys it. */
668 static void
669 _dict_destroy (struct dictionary *d)
671 /* In general, we don't want callbacks occurring, if the dictionary
672 is being destroyed */
673 d->callbacks = NULL ;
675 dict_clear__ (d, true);
676 string_array_destroy (&d->documents);
677 hmap_destroy (&d->name_map);
678 attrset_destroy (&d->attributes);
679 dict_clear_mrsets (d);
680 dict_clear_varsets (d);
681 free (d->encoding);
682 free (d);
685 struct dictionary *
686 dict_ref (struct dictionary *d)
688 d->ref_cnt++;
689 return d;
692 void
693 dict_unref (struct dictionary *d)
695 if (d == NULL)
696 return;
697 d->ref_cnt--;
698 assert (d->ref_cnt >= 0);
699 if (d->ref_cnt == 0)
700 _dict_destroy (d);
703 /* Returns the number of variables in D. */
704 size_t
705 dict_get_n_vars (const struct dictionary *d)
707 return d->n_vars;
710 /* Returns the variable in D with dictionary index IDX, which
711 must be between 0 and the count returned by
712 dict_get_n_vars(), exclusive. */
713 struct variable *
714 dict_get_var (const struct dictionary *d, size_t idx)
716 assert (idx < d->n_vars);
718 return d->vars[idx].var;
721 /* Sets *VARS to an array of pointers to variables in D and *N
722 to the number of variables in *D. All variables are returned
723 except for those, if any, in the classes indicated by EXCLUDE.
724 (There is no point in putting DC_SYSTEM in EXCLUDE as
725 dictionaries never include system variables.) */
726 void
727 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
728 size_t *n, enum dict_class exclude)
730 dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
733 /* Sets *VARS to an array of pointers to variables in D and *N
734 to the number of variables in *D. All variables are returned
735 except for those, if any, in the classes indicated by EXCLUDE.
736 (There is no point in putting DC_SYSTEM in EXCLUDE as
737 dictionaries never include system variables.) */
738 void
739 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
740 size_t *n, enum dict_class exclude)
742 size_t count;
743 size_t i;
745 assert (exclude == (exclude & DC_ALL));
747 count = 0;
748 for (i = 0; i < d->n_vars; i++)
750 enum dict_class class = var_get_dict_class (d->vars[i].var);
751 if (!(class & exclude))
752 count++;
755 *vars = xnmalloc (count, sizeof **vars);
756 *n = 0;
757 for (i = 0; i < d->n_vars; i++)
759 enum dict_class class = var_get_dict_class (d->vars[i].var);
760 if (!(class & exclude))
761 (*vars)[(*n)++] = d->vars[i].var;
763 assert (*n == count);
766 static struct variable *
767 add_var (struct dictionary *d, struct variable *v)
769 /* Update dictionary. */
770 if (d->n_vars >= d->allocated_vars)
772 size_t i;
774 d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
775 hmap_clear (&d->name_map);
776 for (i = 0; i < d->n_vars; i++)
778 var_set_vardict (d->vars[i].var, &d->vars[i]);
779 hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
780 d->vars[i].name_node.hash);
784 struct vardict_info *vardict = &d->vars[d->n_vars++];
785 *vardict = (struct vardict_info) {
786 .dict = d,
787 .var = v,
789 hmap_insert (&d->name_map, &vardict->name_node,
790 utf8_hash_case_string (var_get_name (v), 0));
791 var_set_vardict (v, vardict);
793 if (d->changed) d->changed (d, d->changed_data);
794 if (d->callbacks && d->callbacks->var_added)
795 d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
797 invalidate_proto (d);
799 return v;
802 /* Creates and returns a new variable in D with the given NAME
803 and WIDTH. Returns a null pointer if the given NAME would
804 duplicate that of an existing variable in the dictionary. */
805 struct variable *
806 dict_create_var (struct dictionary *d, const char *name, int width)
808 return (dict_lookup_var (d, name) == NULL
809 ? dict_create_var_assert (d, name, width)
810 : NULL);
813 /* Creates and returns a new variable in D with the given NAME
814 and WIDTH. Assert-fails if the given NAME would duplicate
815 that of an existing variable in the dictionary. */
816 struct variable *
817 dict_create_var_assert (struct dictionary *d, const char *name, int width)
819 assert (dict_lookup_var (d, name) == NULL);
820 return add_var (d, var_create (name, width));
823 /* Creates and returns a new variable in D, as a copy of existing variable
824 OLD_VAR, which need not be in D or in any dictionary. Returns a null
825 pointer if OLD_VAR's name would duplicate that of an existing variable in
826 the dictionary. */
827 struct variable *
828 dict_clone_var (struct dictionary *d, const struct variable *old_var)
830 return dict_clone_var_as (d, old_var, var_get_name (old_var));
833 /* Creates and returns a new variable in D, as a copy of existing variable
834 OLD_VAR, which need not be in D or in any dictionary. Assert-fails if
835 OLD_VAR's name would duplicate that of an existing variable in the
836 dictionary. */
837 struct variable *
838 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
840 return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
843 /* Creates and returns a new variable in D with name NAME, as a copy of
844 existing variable OLD_VAR, which need not be in D or in any dictionary.
845 Returns a null pointer if the given NAME would duplicate that of an existing
846 variable in the dictionary. */
847 struct variable *
848 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
849 const char *name)
851 return (dict_lookup_var (d, name) == NULL
852 ? dict_clone_var_as_assert (d, old_var, name)
853 : NULL);
856 /* Creates and returns a new variable in D with name NAME, as a copy of
857 existing variable OLD_VAR, which need not be in D or in any dictionary.
858 Assert-fails if the given NAME would duplicate that of an existing variable
859 in the dictionary. */
860 struct variable *
861 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
862 const char *name)
864 struct variable *new_var = var_clone (old_var);
865 assert (dict_lookup_var (d, name) == NULL);
866 var_set_name (new_var, name);
867 return add_var (d, new_var);
870 /* Creates and returns a new variable in DICT with the given WIDTH. Uses HINT
871 as the variable name, if it is nonnull, not already in use in DICT, and a
872 valid name for a DC_ORDINARY variable; otherwise, chooses a unique name with
873 HINT as a hint. */
874 struct variable *
875 dict_create_var_with_unique_name (struct dictionary *dict, const char *hint,
876 int width)
878 const char *name = (hint
879 && dict_id_is_valid (dict, hint, DC_ORDINARY)
880 && !dict_lookup_var (dict, hint)
881 ? hint
882 : dict_make_unique_var_name (dict, hint));
883 struct variable *var = dict_create_var_assert (dict, name, width);
884 if (name != hint)
885 free (CONST_CAST (char *, name));
886 return var;
889 /* Returns the variable named NAME in D, or a null pointer if no
890 variable has that name. */
891 struct variable *
892 dict_lookup_var (const struct dictionary *d, const char *name)
894 struct vardict_info *vardict;
896 HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
897 utf8_hash_case_string (name, 0), &d->name_map)
899 struct variable *var = vardict->var;
900 if (!utf8_strcasecmp (var_get_name (var), name))
901 return var;
904 return NULL;
907 /* Returns the variable named NAME in D. Assert-fails if no
908 variable has that name. */
909 struct variable *
910 dict_lookup_var_assert (const struct dictionary *d, const char *name)
912 struct variable *v = dict_lookup_var (d, name);
913 assert (v != NULL);
914 return v;
917 /* Returns true if variable V is in dictionary D,
918 false otherwise. */
919 bool
920 dict_contains_var (const struct dictionary *d, const struct variable *v)
922 return (var_has_vardict (v)
923 && vardict_get_dictionary (var_get_vardict (v)) == d);
926 /* Moves V to 0-based position IDX in D. Other variables in D,
927 if any, retain their relative positions. Runs in time linear
928 in the distance moved. */
929 void
930 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
932 assert (new_index < d->n_vars);
934 size_t old_index = var_get_dict_index (v);
935 if (new_index == old_index)
936 return;
938 unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
939 move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
940 reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
942 if (d->callbacks && d->callbacks->var_moved)
943 d->callbacks->var_moved (d, new_index, old_index, d->cb_data);
946 /* Reorders the variables in D, placing the COUNT variables
947 listed in ORDER in that order at the beginning of D. The
948 other variables in D, if any, retain their relative
949 positions. */
950 void
951 dict_reorder_vars (struct dictionary *d,
952 struct variable *const *order, size_t count)
954 struct vardict_info *new_var;
955 size_t i;
957 assert (count == 0 || order != NULL);
958 assert (count <= d->n_vars);
960 new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
962 /* Add variables in ORDER to new_var. */
963 for (i = 0; i < count; i++)
965 struct vardict_info *old_var;
967 assert (dict_contains_var (d, order[i]));
969 old_var = var_get_vardict (order[i]);
970 new_var[i] = *old_var;
971 old_var->dict = NULL;
974 /* Add remaining variables to new_var. */
975 for (i = 0; i < d->n_vars; i++)
976 if (d->vars[i].dict != NULL)
977 new_var[count++] = d->vars[i];
978 assert (count == d->n_vars);
980 /* Replace old vardicts by new ones. */
981 free (d->vars);
982 d->vars = new_var;
984 hmap_clear (&d->name_map);
985 reindex_vars (d, 0, d->n_vars, false);
988 /* Changes the name of variable V that is currently in dictionary D to
989 NEW_NAME. */
990 static void
991 rename_var (struct dictionary *d, struct variable *v, const char *new_name)
993 d->n_unique_names = 0;
995 struct vardict_info *vardict = var_get_vardict (v);
996 var_clear_vardict (v);
997 var_set_name (v, new_name);
998 vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
999 var_set_vardict (v, vardict);
1002 /* Tries to changes the name of V in D to name NEW_NAME. Returns true if
1003 successful, false if a variable (other than V) with the given name already
1004 exists in D. */
1005 bool
1006 dict_try_rename_var (struct dictionary *d, struct variable *v,
1007 const char *new_name)
1009 struct variable *conflict = dict_lookup_var (d, new_name);
1010 if (conflict && v != conflict)
1011 return false;
1013 struct variable *old = var_clone (v);
1014 unindex_var (d, var_get_vardict (v));
1015 rename_var (d, v, new_name);
1016 reindex_var (d, var_get_vardict (v), false);
1018 if (settings_get_algorithm () == ENHANCED)
1019 var_clear_short_names (v);
1021 if (d->changed) d->changed (d, d->changed_data);
1022 if (d->callbacks && d->callbacks->var_changed)
1023 d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1025 var_unref (old);
1027 return true;
1030 /* Changes the name of V in D to name NEW_NAME. Assert-fails if
1031 a variable named NEW_NAME is already in D, except that
1032 NEW_NAME may be the same as V's existing name. */
1033 void
1034 dict_rename_var (struct dictionary *d, struct variable *v,
1035 const char *new_name)
1037 bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1038 assert (ok);
1041 /* Renames COUNT variables specified in VARS to the names given
1042 in NEW_NAMES within dictionary D. If the renaming would
1043 result in a duplicate variable name, returns false and stores a
1044 name that would be duplicated into *ERR_NAME (if ERR_NAME is
1045 non-null). Otherwise, the renaming is successful, and true
1046 is returned. */
1047 bool
1048 dict_rename_vars (struct dictionary *d,
1049 struct variable **vars, char **new_names, size_t count,
1050 char **err_name)
1052 struct pool *pool;
1053 char **old_names;
1054 size_t i;
1056 assert (count == 0 || vars != NULL);
1057 assert (count == 0 || new_names != NULL);
1059 /* Save the names of the variables to be renamed. */
1060 pool = pool_create ();
1061 old_names = pool_nalloc (pool, count, sizeof *old_names);
1062 for (i = 0; i < count; i++)
1063 old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1065 /* Remove the variables to be renamed from the name hash,
1066 and rename them. */
1067 for (i = 0; i < count; i++)
1069 unindex_var (d, var_get_vardict (vars[i]));
1070 rename_var (d, vars[i], new_names[i]);
1073 /* Add the renamed variables back into the name hash,
1074 checking for conflicts. */
1075 for (i = 0; i < count; i++)
1077 if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1079 /* There is a name conflict.
1080 Back out all the name changes that have already
1081 taken place, and indicate failure. */
1082 size_t fail_idx = i;
1083 if (err_name != NULL)
1084 *err_name = new_names[i];
1086 for (i = 0; i < fail_idx; i++)
1087 unindex_var (d, var_get_vardict (vars[i]));
1089 for (i = 0; i < count; i++)
1091 rename_var (d, vars[i], old_names[i]);
1092 reindex_var (d, var_get_vardict (vars[i]), false);
1095 pool_destroy (pool);
1096 return false;
1098 reindex_var (d, var_get_vardict (vars[i]), false);
1101 /* Clear short names. */
1102 if (settings_get_algorithm () == ENHANCED)
1103 for (i = 0; i < count; i++)
1104 var_clear_short_names (vars[i]);
1106 pool_destroy (pool);
1107 return true;
1110 /* Returns true if a variable named NAME may be inserted in DICT;
1111 that is, if there is not already a variable with that name in
1112 DICT and if NAME is not a reserved word. (The caller's checks
1113 have already verified that NAME is otherwise acceptable as a
1114 variable name.) */
1115 static bool
1116 var_name_is_insertable (const struct dictionary *dict, const char *name)
1118 return (dict_lookup_var (dict, name) == NULL
1119 && lex_id_to_token (ss_cstr (name)) == T_ID);
1122 static char *
1123 make_hinted_name (const struct dictionary *dict, const char *hint)
1125 size_t hint_len = strlen (hint);
1126 bool dropped = false;
1127 char *root, *rp;
1128 size_t ofs;
1129 int mblen;
1131 if (hint_len > ID_MAX_LEN)
1132 hint_len = ID_MAX_LEN;
1134 /* The allocation size here is OK: characters that are copied directly fit
1135 OK, and characters that are not copied directly are replaced by a single
1136 '_' byte. If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1137 replaced by '_' too. */
1138 root = rp = xmalloc (hint_len + 1);
1139 for (ofs = 0; ofs < hint_len; ofs += mblen)
1141 ucs4_t uc;
1143 mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1144 hint_len - ofs);
1145 if (rp == root
1146 ? lex_uc_is_id1 (uc) && uc != '$' && uc != '#' && uc != '@'
1147 : lex_uc_is_idn (uc))
1149 if (dropped)
1151 *rp++ = '_';
1152 dropped = false;
1154 rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1156 else if (rp != root)
1157 dropped = true;
1159 *rp = '\0';
1161 if (root[0] != '\0')
1163 unsigned long int i;
1165 if (var_name_is_insertable (dict, root))
1166 return root;
1168 for (i = 0; i < ULONG_MAX; i++)
1170 char suffix[1 + F26ADIC_STRLEN_MAX + 1];
1172 suffix[0] = '_';
1173 str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1);
1175 char *name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1176 if (var_name_is_insertable (dict, name))
1178 free (root);
1179 return name;
1181 free (name);
1185 free (root);
1187 return NULL;
1190 static char *
1191 make_numeric_name (struct dictionary *dict)
1193 while (dict->n_unique_names++ < ULONG_MAX)
1195 char *name = xasprintf ("VAR%03lu", dict->n_unique_names);
1196 if (dict_lookup_var (dict, name) == NULL)
1197 return name;
1198 free (name);
1201 NOT_REACHED ();
1204 /* Devises and returns a variable name unique within DICT. The variable name
1205 is owned by the caller, which must free it with free() when it is no longer
1206 needed. The variable name will not begin with '$' or '#' or '@'.
1208 HINT, if it is non-null, is used as a suggestion that will be
1209 modified for suitability as a variable name and for
1210 uniqueness.
1212 If HINT is null or entirely unsuitable, uses a name in the form "VAR%03d",
1213 using the smallest available integer. */
1214 char *
1215 dict_make_unique_var_name (const struct dictionary *dict_, const char *hint)
1217 struct dictionary *dict = CONST_CAST (struct dictionary *, dict_);
1218 if (hint != NULL)
1220 char *hinted_name = make_hinted_name (dict, hint);
1221 if (hinted_name != NULL)
1222 return hinted_name;
1225 return make_numeric_name (dict);
1228 /* Returns whether variable names must be valid identifiers. Normally, this is
1229 true, but sometimes a dictionary is prepared for external use (e.g. output
1230 to a CSV file) where names don't have to be valid. */
1231 bool
1232 dict_get_names_must_be_ids (const struct dictionary *d)
1234 return d->names_must_be_ids;
1237 /* Sets whether variable names must be valid identifiers. Normally, this is
1238 true, but sometimes a dictionary is prepared for external use (e.g. output
1239 to a CSV file) where names don't have to be valid.
1241 Changing this setting from false to true doesn't make the dictionary check
1242 all the existing variable names, so it can cause an invariant violation. */
1243 void
1244 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1246 d->names_must_be_ids = names_must_be_ids;
1249 /* Returns the weighting variable in dictionary D, or a null
1250 pointer if the dictionary is unweighted. */
1251 struct variable *
1252 dict_get_weight (const struct dictionary *d)
1254 assert (d->weight == NULL || dict_contains_var (d, d->weight));
1256 return d->weight;
1259 /* Returns the value of D's weighting variable in case C, except
1260 that a negative or missing weight is returned as 0. Returns 1 if the
1261 dictionary is unweighted. Will warn about missing, negative,
1262 or zero values if *WARN_ON_INVALID is true. The function will
1263 set *WARN_ON_INVALID to false if an invalid weight is
1264 found. */
1265 double
1266 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1267 bool *warn_on_invalid)
1269 assert (c != NULL);
1271 if (d->weight == NULL)
1272 return 1.0;
1273 else
1275 double w = case_num (c, d->weight);
1277 return var_force_valid_weight (d->weight, w, warn_on_invalid);
1281 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1282 nearest integer. */
1283 double
1284 dict_get_rounded_case_weight (const struct dictionary *d,
1285 const struct ccase *c, bool *warn_on_invalid)
1287 return floor (dict_get_case_weight (d, c, warn_on_invalid) + 0.5);
1290 /* Returns the format to use for weights. */
1291 struct fmt_spec
1292 dict_get_weight_format (const struct dictionary *d)
1294 return d->weight ? var_get_print_format (d->weight) : F_8_0;
1297 /* Sets the weighting variable of D to V, or turning off
1298 weighting if V is a null pointer. */
1299 void
1300 dict_set_weight (struct dictionary *d, struct variable *v)
1302 assert (v == NULL || dict_contains_var (d, v));
1303 assert (v == NULL || var_is_numeric (v));
1305 d->weight = v;
1307 if (d->changed) d->changed (d, d->changed_data);
1308 if (d->callbacks && d->callbacks->weight_changed)
1309 d->callbacks->weight_changed (d,
1310 v ? var_get_dict_index (v) : -1,
1311 d->cb_data);
1314 /* Returns the filter variable in dictionary D (see cmd_filter())
1315 or a null pointer if the dictionary is unfiltered. */
1316 struct variable *
1317 dict_get_filter (const struct dictionary *d)
1319 assert (d->filter == NULL || dict_contains_var (d, d->filter));
1321 return d->filter;
1324 /* Sets V as the filter variable for dictionary D. Passing a
1325 null pointer for V turn off filtering. */
1326 void
1327 dict_set_filter (struct dictionary *d, struct variable *v)
1329 assert (v == NULL || dict_contains_var (d, v));
1330 assert (v == NULL || var_is_numeric (v));
1332 d->filter = v;
1334 if (d->changed) d->changed (d, d->changed_data);
1335 if (d->callbacks && d->callbacks->filter_changed)
1336 d->callbacks->filter_changed (d,
1337 v ? var_get_dict_index (v) : -1,
1338 d->cb_data);
1341 /* Returns the case limit for dictionary D, or zero if the number
1342 of cases is unlimited. */
1343 casenumber
1344 dict_get_case_limit (const struct dictionary *d)
1346 return d->case_limit;
1349 /* Sets CASE_LIMIT as the case limit for dictionary D. Use
1350 0 for CASE_LIMIT to indicate no limit. */
1351 void
1352 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1354 d->case_limit = case_limit;
1357 /* Returns the prototype used for cases created by dictionary D. */
1358 const struct caseproto *
1359 dict_get_proto (const struct dictionary *d_)
1361 struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1362 if (d->proto == NULL)
1364 short int *widths = xnmalloc (d->n_vars, sizeof *widths);
1365 for (size_t i = 0; i < d->n_vars; i++)
1366 widths[i] = var_get_width (d->vars[i].var);
1367 d->proto = caseproto_from_widths (widths, d->n_vars);
1369 return d->proto;
1372 /* Returns the file label for D, or a null pointer if D is
1373 unlabeled (see cmd_file_label()). */
1374 const char *
1375 dict_get_label (const struct dictionary *d)
1377 return d->label;
1380 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1381 encoding.
1383 Removes D's label if LABEL is null or the empty string. */
1384 void
1385 dict_set_label (struct dictionary *d, const char *label)
1387 free (d->label);
1388 if (label == NULL || label[0] == '\0')
1389 d->label = NULL;
1390 else
1391 d->label = utf8_encoding_trunc (label, d->encoding, 60);
1394 /* Returns the documents for D, as an UTF-8 encoded string_array. The
1395 return value is always nonnull; if there are no documents then the
1396 string_arary is empty.*/
1397 const struct string_array *
1398 dict_get_documents (const struct dictionary *d)
1400 return &d->documents;
1403 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1404 void
1405 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1407 /* Swap out the old documents, instead of destroying them immediately, to
1408 allow the new documents to include pointers into the old ones. */
1409 struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1410 string_array_swap (&d->documents, &old_docs);
1412 for (size_t i = 0; i < new_docs->n; i++)
1413 dict_add_document_line (d, new_docs->strings[i], false);
1415 string_array_destroy (&old_docs);
1418 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1419 into individual lines at new-line characters. Each line is truncated to at
1420 most DOC_LINE_LENGTH bytes in D's encoding. */
1421 void
1422 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1424 const char *s;
1426 dict_clear_documents (d);
1427 for (s = new_docs; *s != '\0';)
1429 size_t len = strcspn (s, "\n");
1430 char *line = xmemdup0 (s, len);
1431 dict_add_document_line (d, line, false);
1432 free (line);
1434 s += len;
1435 if (*s == '\n')
1436 s++;
1440 /* Drops the documents from dictionary D. */
1441 void
1442 dict_clear_documents (struct dictionary *d)
1444 string_array_clear (&d->documents);
1447 /* Appends the UTF-8 encoded LINE to the documents in D. LINE will be
1448 truncated so that it is no more than 80 bytes in the dictionary's
1449 encoding. If this causes some text to be lost, and ISSUE_WARNING is true,
1450 then a warning will be issued. */
1451 bool
1452 dict_add_document_line (struct dictionary *d, const char *line,
1453 bool issue_warning)
1455 size_t trunc_len;
1456 bool truncated;
1458 trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1459 truncated = line[trunc_len] != '\0';
1460 if (truncated && issue_warning)
1462 /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1463 msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1466 string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1468 return !truncated;
1471 /* Returns the number of document lines in dictionary D. */
1472 size_t
1473 dict_get_document_n_lines (const struct dictionary *d)
1475 return d->documents.n;
1478 /* Returns document line number IDX in dictionary D. The caller must not
1479 modify or free the returned string. */
1480 const char *
1481 dict_get_document_line (const struct dictionary *d, size_t idx)
1483 assert (idx < d->documents.n);
1484 return d->documents.strings[idx];
1487 /* Creates in D a vector named NAME that contains the N
1488 variables in VAR. Returns true if successful, or false if a
1489 vector named NAME already exists in D. */
1490 bool
1491 dict_create_vector (struct dictionary *d,
1492 const char *name,
1493 struct variable **var, size_t n)
1495 assert (n > 0);
1496 for (size_t i = 0; i < n; i++)
1497 assert (dict_contains_var (d, var[i]));
1499 if (dict_lookup_vector (d, name) == NULL)
1501 d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1502 d->vector[d->n_vectors++] = vector_create (name, var, n);
1503 return true;
1505 else
1506 return false;
1509 /* Creates in D a vector named NAME that contains the N
1510 variables in VAR. A vector named NAME must not already exist
1511 in D. */
1512 void
1513 dict_create_vector_assert (struct dictionary *d,
1514 const char *name,
1515 struct variable **var, size_t n)
1517 assert (dict_lookup_vector (d, name) == NULL);
1518 dict_create_vector (d, name, var, n);
1521 /* Returns the vector in D with index IDX, which must be less
1522 than dict_get_n_vectors (D). */
1523 const struct vector *
1524 dict_get_vector (const struct dictionary *d, size_t idx)
1526 assert (idx < d->n_vectors);
1528 return d->vector[idx];
1531 /* Returns the number of vectors in D. */
1532 size_t
1533 dict_get_n_vectors (const struct dictionary *d)
1535 return d->n_vectors;
1538 /* Looks up and returns the vector within D with the given
1539 NAME. */
1540 const struct vector *
1541 dict_lookup_vector (const struct dictionary *d, const char *name)
1543 size_t i;
1544 for (i = 0; i < d->n_vectors; i++)
1545 if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1546 return d->vector[i];
1547 return NULL;
1550 /* Deletes all vectors from D. */
1551 void
1552 dict_clear_vectors (struct dictionary *d)
1554 size_t i;
1556 for (i = 0; i < d->n_vectors; i++)
1557 vector_destroy (d->vector[i]);
1558 free (d->vector);
1560 d->vector = NULL;
1561 d->n_vectors = 0;
1564 /* Multiple response sets. */
1566 /* Returns the multiple response set in DICT with index IDX, which must be
1567 between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1568 const struct mrset *
1569 dict_get_mrset (const struct dictionary *dict, size_t idx)
1571 assert (idx < dict->n_mrsets);
1572 return dict->mrsets[idx];
1575 /* Returns the number of multiple response sets in DICT. */
1576 size_t
1577 dict_get_n_mrsets (const struct dictionary *dict)
1579 return dict->n_mrsets;
1582 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1583 returns its index; otherwise, returns SIZE_MAX. */
1584 static size_t
1585 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1587 size_t i;
1589 for (i = 0; i < dict->n_mrsets; i++)
1590 if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1591 return i;
1593 return SIZE_MAX;
1596 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1597 returns it; otherwise, returns NULL. */
1598 const struct mrset *
1599 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1601 size_t idx = dict_lookup_mrset_idx (dict, name);
1602 return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1605 /* Adds MRSET to DICT, replacing any existing set with the same name. Returns
1606 true if a set was replaced, false if none existed with the specified name.
1608 Ownership of MRSET is transferred to DICT. */
1609 bool
1610 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1612 size_t idx;
1614 assert (mrset_ok (mrset, dict));
1616 idx = dict_lookup_mrset_idx (dict, mrset->name);
1617 if (idx == SIZE_MAX)
1619 dict->mrsets = xrealloc (dict->mrsets,
1620 (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1621 dict->mrsets[dict->n_mrsets++] = mrset;
1622 return true;
1624 else
1626 mrset_destroy (dict->mrsets[idx]);
1627 dict->mrsets[idx] = mrset;
1628 return false;
1632 /* Looks for a multiple response set in DICT named NAME. If found, removes it
1633 from DICT and returns true. If none is found, returns false without
1634 modifying DICT.
1636 Deleting one multiple response set causes the indexes of other sets within
1637 DICT to change. */
1638 bool
1639 dict_delete_mrset (struct dictionary *dict, const char *name)
1641 size_t idx = dict_lookup_mrset_idx (dict, name);
1642 if (idx != SIZE_MAX)
1644 mrset_destroy (dict->mrsets[idx]);
1645 dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1646 return true;
1648 else
1649 return false;
1652 /* Deletes all multiple response sets from DICT. */
1653 void
1654 dict_clear_mrsets (struct dictionary *dict)
1656 size_t i;
1658 for (i = 0; i < dict->n_mrsets; i++)
1659 mrset_destroy (dict->mrsets[i]);
1660 free (dict->mrsets);
1661 dict->mrsets = NULL;
1662 dict->n_mrsets = 0;
1665 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1666 static void
1667 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1669 size_t i;
1671 assert (dict_contains_var (dict, var));
1673 for (i = 0; i < dict->n_mrsets;)
1675 struct mrset *mrset = dict->mrsets[i];
1676 size_t j;
1678 for (j = 0; j < mrset->n_vars;)
1679 if (mrset->vars[j] == var)
1680 remove_element (mrset->vars, mrset->n_vars--,
1681 sizeof *mrset->vars, j);
1682 else
1683 j++;
1685 if (mrset->n_vars < 2)
1687 mrset_destroy (mrset);
1688 dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1690 else
1691 i++;
1696 /* Returns the variable set in DICT with index IDX, which must be between 0 and
1697 the count returned by dict_get_n_varsets(), exclusive. */
1698 const struct varset *
1699 dict_get_varset (const struct dictionary *dict, size_t idx)
1701 assert (idx < dict->n_varsets);
1702 return dict->varsets[idx];
1705 /* Returns the number of variable sets in DICT. */
1706 size_t
1707 dict_get_n_varsets (const struct dictionary *dict)
1709 return dict->n_varsets;
1712 /* Looks for a variable set named NAME in DICT. If it finds one, returns its
1713 index; otherwise, returns SIZE_MAX. */
1714 static size_t
1715 dict_lookup_varset_idx (const struct dictionary *dict, const char *name)
1717 for (size_t i = 0; i < dict->n_varsets; i++)
1718 if (!utf8_strcasecmp (name, dict->varsets[i]->name))
1719 return i;
1721 return SIZE_MAX;
1724 /* Looks for a multiple response set named NAME in DICT. If it finds one,
1725 returns it; otherwise, returns NULL. */
1726 const struct varset *
1727 dict_lookup_varset (const struct dictionary *dict, const char *name)
1729 size_t idx = dict_lookup_varset_idx (dict, name);
1730 return idx != SIZE_MAX ? dict->varsets[idx] : NULL;
1733 /* Adds VARSET to DICT, replacing any existing set with the same name. Returns
1734 true if a set was replaced, false if none existed with the specified name.
1736 Ownership of VARSET is transferred to DICT. */
1737 bool
1738 dict_add_varset (struct dictionary *dict, struct varset *varset)
1740 size_t idx = dict_lookup_varset_idx (dict, varset->name);
1741 if (idx == SIZE_MAX)
1743 dict->varsets = xrealloc (dict->varsets,
1744 (dict->n_varsets + 1) * sizeof *dict->varsets);
1745 dict->varsets[dict->n_varsets++] = varset;
1746 return true;
1748 else
1750 varset_destroy (dict->varsets[idx]);
1751 dict->varsets[idx] = varset;
1752 return false;
1756 /* Deletes all variable sets from DICT. */
1757 void
1758 dict_clear_varsets (struct dictionary *dict)
1760 for (size_t i = 0; i < dict->n_varsets; i++)
1761 varset_destroy (dict->varsets[i]);
1762 free (dict->varsets);
1763 dict->varsets = NULL;
1764 dict->n_varsets = 0;
1767 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1768 static void
1769 dict_unset_varset_var (struct dictionary *dict, struct variable *var)
1771 assert (dict_contains_var (dict, var));
1773 for (size_t i = 0; i < dict->n_varsets; i++)
1775 struct varset *varset = dict->varsets[i];
1777 for (size_t j = 0; j < varset->n_vars;)
1778 if (varset->vars[j] == var)
1779 remove_element (varset->vars, varset->n_vars--,
1780 sizeof *varset->vars, j);
1781 else
1782 j++;
1786 /* Returns D's attribute set. The caller may examine or modify
1787 the attribute set, but must not destroy it. Destroying D or
1788 calling dict_set_attributes for D will also destroy D's
1789 attribute set. */
1790 struct attrset *
1791 dict_get_attributes (const struct dictionary *d)
1793 return CONST_CAST (struct attrset *, &d->attributes);
1796 /* Replaces D's attributes set by a copy of ATTRS. */
1797 void
1798 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1800 attrset_destroy (&d->attributes);
1801 attrset_clone (&d->attributes, attrs);
1804 /* Returns true if D has at least one attribute in its attribute
1805 set, false if D's attribute set is empty. */
1806 bool
1807 dict_has_attributes (const struct dictionary *d)
1809 return attrset_count (&d->attributes) > 0;
1812 /* Called from variable.c to notify the dictionary that some property (indicated
1813 by WHAT) of the variable has changed. OLDVAR is a copy of V as it existed
1814 prior to the change. OLDVAR is destroyed by this function.
1816 void
1817 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1819 if (var_has_vardict (v))
1821 const struct vardict_info *vardict = var_get_vardict (v);
1822 struct dictionary *d = vardict->dict;
1824 if (NULL == d)
1825 return;
1827 if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1828 invalidate_proto (d);
1830 if (d->changed) d->changed (d, d->changed_data);
1831 if (d->callbacks && d->callbacks->var_changed)
1832 d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1834 var_unref (oldvar);
1840 vardict_get_dict_index (const struct vardict_info *vardict)
1842 return vardict - vardict->dict->vars;