dictionary: Short-circuit no-op case in dict_reorder_var().
[pspp] / src / data / dictionary.c
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.
4
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.
9
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.
14
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/>. */
17
18 #include <config.h>
19
20 #include "data/dictionary.h"
21
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <unistr.h>
26
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"
49
50 #include "gl/intprops.h"
51 #include "gl/minmax.h"
52 #include "gl/xalloc.h"
53 #include "gl/xmemdup0.h"
54
55 #include "gettext.h"
56 #define _(msgid) gettext (msgid)
57
58 /* A dictionary. */
59 struct dictionary
60   {
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. */
83
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;
88
89     char *encoding;             /* Character encoding of string data */
90
91     const struct dict_callbacks *callbacks; /* Callbacks on dictionary
92                                                modification */
93     void *cb_data ;                  /* Data passed to callbacks */
94
95     void (*changed) (struct dictionary *, void *); /* Generic change callback */
96     void *changed_data;
97   };
98
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 *);
102
103 /* Compares two double pointers to variables, which should point
104    to elements of a struct dictionary's `var' member array. */
105 static int
106 compare_var_ptrs (const void *a_, const void *b_, const void *aux UNUSED)
107 {
108   struct variable *const *a = a_;
109   struct variable *const *b = b_;
110
111   return *a < *b ? -1 : *a > *b;
112 }
113
114 static void
115 unindex_var (struct dictionary *d, struct vardict_info *vardict)
116 {
117   hmap_delete (&d->name_map, &vardict->name_node);
118 }
119
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). */
123 static void
124 reindex_var (struct dictionary *d, struct vardict_info *vardict, bool skip_callbacks)
125 {
126   struct variable *old = (d->callbacks && d->callbacks->var_changed
127                           ? var_clone (vardict->var)
128                           : NULL);
129
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);
134
135   if (! skip_callbacks)
136     {
137       if (d->changed) d->changed (d, d->changed_data);
138       if (old)
139         {
140           d->callbacks->var_changed (d, var_get_dict_index (var), VAR_TRAIT_POSITION, old, d->cb_data);
141           var_unref (old);
142         }
143     }
144 }
145
146 /* Sets the case_index in V's vardict to CASE_INDEX. */
147 static void
148 set_var_case_index (struct variable *v, int case_index)
149 {
150   var_get_vardict (v)->case_index = case_index;
151 }
152
153 /* Removes the dictionary variables with indexes from FROM to TO (exclusive)
154    from name_map. */
155 static void
156 unindex_vars (struct dictionary *d, size_t from, size_t to)
157 {
158   size_t i;
159
160   for (i = from; i < to; i++)
161     unindex_var (d, &d->vars[i]);
162 }
163
164 /* Re-sets the dict_index in the dictionary variables with
165    indexes from FROM to TO (exclusive). */
166 static void
167 reindex_vars (struct dictionary *d, size_t from, size_t to, bool skip_callbacks)
168 {
169   size_t i;
170
171   for (i = from; i < to; i++)
172     reindex_var (d, &d->vars[i], skip_callbacks);
173 }
174
175 \f
176
177 /* Returns the encoding for data in dictionary D.  The return value is a
178    nonnull string that contains an IANA character set name. */
179 const char *
180 dict_get_encoding (const struct dictionary *d)
181 {
182   return d->encoding ;
183 }
184
185 /* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
186    encoding.  Returns true if it is, otherwise an error message that the caller
187    must free(). */
188 char * WARN_UNUSED_RESULT
189 dict_id_is_valid__ (const struct dictionary *dict, const char *id)
190 {
191   if (!dict->names_must_be_ids)
192     return NULL;
193   return id_is_valid__ (id, dict->encoding);
194 }
195
196 static bool
197 error_to_bool (char *error)
198 {
199   if (error)
200     {
201       free (error);
202       return false;
203     }
204   else
205     return true;
206 }
207
208 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
209    encoding, false otherwise. */
210 bool
211 dict_id_is_valid (const struct dictionary *dict, const char *id)
212 {
213   return error_to_bool (dict_id_is_valid__ (dict, id));
214 }
215
216 void
217 dict_set_change_callback (struct dictionary *d,
218                           void (*changed) (struct dictionary *, void*),
219                           void *data)
220 {
221   d->changed = changed;
222   d->changed_data = data;
223 }
224
225 /* Discards dictionary D's caseproto.  (It will be regenerated
226    lazily, on demand.) */
227 static void
228 invalidate_proto (struct dictionary *d)
229 {
230   caseproto_unref (d->proto);
231   d->proto = NULL;
232 }
233
234 /* Print a representation of dictionary D to stdout, for
235    debugging purposes. */
236 void
237 dict_dump (const struct dictionary *d)
238 {
239   int i;
240   for (i = 0 ; i < d->n_vars ; ++i)
241     {
242       const struct variable *v = d->vars[i].var;
243       printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
244               var_get_name (v),
245               var_get_dict_index (v),
246               var_get_case_index (v));
247
248     }
249 }
250
251 /* Associate CALLBACKS with DICT.  Callbacks will be invoked whenever
252    the dictionary or any of the variables it contains are modified.
253    Each callback will get passed CALLBACK_DATA.
254    Any callback may be NULL, in which case it'll be ignored.
255 */
256 void
257 dict_set_callbacks (struct dictionary *dict,
258                     const struct dict_callbacks *callbacks,
259                     void *callback_data)
260 {
261   dict->callbacks = callbacks;
262   dict->cb_data = callback_data;
263 }
264
265 /* Shallow copy the callbacks from SRC to DEST */
266 void
267 dict_copy_callbacks (struct dictionary *dest,
268                      const struct dictionary *src)
269 {
270   dest->callbacks = src->callbacks;
271   dest->cb_data = src->cb_data;
272 }
273
274 /* Creates and returns a new dictionary with the specified ENCODING. */
275 struct dictionary *
276 dict_create (const char *encoding)
277 {
278   struct dictionary *d = xmalloc (sizeof *d);
279
280   *d = (struct dictionary) {
281     .encoding = xstrdup (encoding),
282     .names_must_be_ids = true,
283     .name_map = HMAP_INITIALIZER (d->name_map),
284     .attributes = ATTRSET_INITIALIZER (d->attributes),
285     .split_type = SPLIT_NONE,
286     .ref_cnt = 1,
287   };
288
289   return d;
290 }
291
292 /* Creates and returns a (deep) copy of an existing
293    dictionary.
294
295    Callbacks are not cloned. */
296 struct dictionary *
297 dict_clone (const struct dictionary *s)
298 {
299   struct dictionary *d = dict_create (s->encoding);
300   dict_set_names_must_be_ids (d, dict_get_names_must_be_ids (s));
301
302   for (size_t i = 0; i < s->n_vars; i++)
303     {
304       struct variable *sv = s->vars[i].var;
305       struct variable *dv = dict_clone_var_assert (d, sv);
306
307       for (size_t j = 0; j < var_get_n_short_names (sv); j++)
308         var_set_short_name (dv, j, var_get_short_name (sv, j));
309
310       var_get_vardict (dv)->case_index = var_get_vardict (sv)->case_index;
311     }
312
313   d->n_splits = s->n_splits;
314   if (d->n_splits > 0)
315     {
316        d->split = xnmalloc (d->n_splits, sizeof *d->split);
317        for (size_t i = 0; i < d->n_splits; i++)
318          d->split[i] = dict_lookup_var_assert (d, var_get_name (s->split[i]));
319     }
320   d->split_type = s->split_type;
321
322   if (s->weight != NULL)
323     dict_set_weight (d, dict_lookup_var_assert (d, var_get_name (s->weight)));
324
325   if (s->filter != NULL)
326     dict_set_filter (d, dict_lookup_var_assert (d, var_get_name (s->filter)));
327
328   d->case_limit = s->case_limit;
329   dict_set_label (d, dict_get_label (s));
330   dict_set_documents (d, dict_get_documents (s));
331
332   d->n_vectors = s->n_vectors;
333   d->vector = xnmalloc (d->n_vectors, sizeof *d->vector);
334   for (size_t i = 0; i < s->n_vectors; i++)
335     d->vector[i] = vector_clone (s->vector[i], s, d);
336
337   dict_set_attributes (d, dict_get_attributes (s));
338
339   for (size_t i = 0; i < s->n_mrsets; i++)
340     {
341       const struct mrset *old = s->mrsets[i];
342       struct mrset *new;
343       size_t j;
344
345       /* Clone old mrset, then replace vars from D by vars from S. */
346       new = mrset_clone (old);
347       for (j = 0; j < new->n_vars; j++)
348         new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
349
350       dict_add_mrset (d, new);
351     }
352
353   for (size_t i = 0; i < s->n_varsets; i++)
354     {
355       const struct varset *old = s->varsets[i];
356
357       /* Clone old varset, then replace vars from D by vars from S. */
358       struct varset *new = varset_clone (old);
359       for (size_t j = 0; j < new->n_vars; j++)
360         new->vars[j] = dict_lookup_var_assert (d, var_get_name (new->vars[j]));
361
362       dict_add_varset (d, new);
363     }
364
365   return d;
366 }
367 \f
368 /* Returns the SPLIT FILE vars (see cmd_split_file()).  Call
369    dict_get_n_splits() to determine how many SPLIT FILE vars
370    there are.  Returns a null pointer if and only if there are no
371    SPLIT FILE vars. */
372 const struct variable *const *
373 dict_get_split_vars (const struct dictionary *d)
374 {
375   return d->split;
376 }
377
378 /* Returns the number of SPLIT FILE vars. */
379 size_t
380 dict_get_n_splits (const struct dictionary *d)
381 {
382   return d->n_splits;
383 }
384
385 /* Removes variable V, which must be in D, from D's set of split
386    variables. */
387 static void
388 dict_unset_split_var (struct dictionary *d, struct variable *v, bool skip_callbacks)
389 {
390   int orig_count;
391
392   assert (dict_contains_var (d, v));
393
394   orig_count = d->n_splits;
395   d->n_splits = remove_equal (d->split, d->n_splits, sizeof *d->split,
396                                &v, compare_var_ptrs, NULL);
397   if (orig_count != d->n_splits && !skip_callbacks)
398     {
399       if (d->changed) d->changed (d, d->changed_data);
400       /* We changed the set of split variables so invoke the
401          callback. */
402       if (d->callbacks &&  d->callbacks->split_changed)
403         d->callbacks->split_changed (d, d->cb_data);
404     }
405 }
406
407
408 /* Sets N split vars SPLIT in dictionary D.  N is silently capped to a maximum
409    of MAX_SPLITS. */
410 static void
411 dict_set_split_vars__ (struct dictionary *d,
412                        struct variable *const *split, size_t n,
413                        enum split_type type, bool skip_callbacks)
414 {
415   if (n > MAX_SPLITS)
416     n = MAX_SPLITS;
417   assert (n == 0 || split != NULL);
418
419   d->n_splits = n;
420   d->split_type = (n == 0 ? SPLIT_NONE
421                    : type == SPLIT_NONE ? SPLIT_LAYERED
422                    : type);
423   if (n > 0)
424     {
425       d->split = xnrealloc (d->split, n, sizeof *d->split) ;
426       memcpy (d->split, split, n * sizeof *d->split);
427     }
428   else
429     {
430       free (d->split);
431       d->split = NULL;
432     }
433
434   if (!skip_callbacks)
435     {
436       if (d->changed) d->changed (d, d->changed_data);
437       if (d->callbacks &&  d->callbacks->split_changed)
438         d->callbacks->split_changed (d, d->cb_data);
439     }
440 }
441
442 enum split_type
443 dict_get_split_type (const struct dictionary *d)
444 {
445   return d->split_type;
446 }
447
448 /* Sets N split vars SPLIT in dictionary D. */
449 void
450 dict_set_split_vars (struct dictionary *d,
451                      struct variable *const *split, size_t n,
452                      enum split_type type)
453 {
454   dict_set_split_vars__ (d, split, n, type, false);
455 }
456
457 void
458 dict_clear_split_vars (struct dictionary *d)
459 {
460   dict_set_split_vars (d, NULL, 0, SPLIT_NONE);
461 }
462 \f
463
464 /* Deletes variable V from dictionary D and frees V.
465
466    This is a very bad idea if there might be any pointers to V
467    from outside D.  In general, no variable in the active dataset's
468    dictionary should be deleted when any transformations are
469    active on the dictionary's dataset, because those
470    transformations might reference the deleted variable.  The
471    safest time to delete a variable is just after a procedure has
472    been executed, as done by DELETE VARIABLES.
473
474    Pointers to V within D are not a problem, because
475    dict_delete_var() knows to remove V from split variables,
476    weights, filters, etc. */
477 static void
478 dict_delete_var__ (struct dictionary *d, struct variable *v, bool skip_callbacks)
479 {
480   int dict_index = var_get_dict_index (v);
481
482   assert (dict_contains_var (d, v));
483
484   dict_unset_split_var (d, v, skip_callbacks);
485   dict_unset_mrset_var (d, v);
486   dict_unset_varset_var (d, v);
487
488   if (d->weight == v)
489     dict_set_weight (d, NULL);
490
491   if (d->filter == v)
492     dict_set_filter (d, NULL);
493
494   dict_clear_vectors (d);
495
496   /* Remove V from var array. */
497   unindex_vars (d, dict_index, d->n_vars);
498   remove_element (d->vars, d->n_vars, sizeof *d->vars, dict_index);
499   d->n_vars--;
500
501   /* Update dict_index for each affected variable. */
502   reindex_vars (d, dict_index, d->n_vars, skip_callbacks);
503
504   /* Free memory. */
505   var_clear_vardict (v);
506
507   if (! skip_callbacks)
508     {
509       if (d->changed) d->changed (d, d->changed_data);
510       if (d->callbacks &&  d->callbacks->vars_deleted)
511         d->callbacks->vars_deleted (d, dict_index, 1, d->cb_data);
512     }
513
514   invalidate_proto (d);
515   var_unref (v);
516 }
517
518 /* Deletes variable V from dictionary D and frees V.
519
520    This is a very bad idea if there might be any pointers to V
521    from outside D.  In general, no variable in the active dataset's
522    dictionary should be deleted when any transformations are
523    active on the dictionary's dataset, because those
524    transformations might reference the deleted variable.  The
525    safest time to delete a variable is just after a procedure has
526    been executed, as done by DELETE VARIABLES.
527
528    Pointers to V within D are not a problem, because
529    dict_delete_var() knows to remove V from split variables,
530    weights, filters, etc. */
531 void
532 dict_delete_var (struct dictionary *d, struct variable *v)
533 {
534   dict_delete_var__ (d, v, false);
535   dict_compact_values (d);
536 }
537
538
539 /* Deletes the COUNT variables listed in VARS from D.  This is
540    unsafe; see the comment on dict_delete_var() for details. */
541 void
542 dict_delete_vars (struct dictionary *d,
543                   struct variable *const *vars, size_t count)
544 {
545   /* FIXME: this can be done in O(count) time, but this algorithm
546      is O(count**2). */
547   assert (count == 0 || vars != NULL);
548
549   while (count-- > 0)
550     dict_delete_var (d, *vars++);
551   dict_compact_values (d);
552 }
553
554 /* Deletes the COUNT variables in D starting at index IDX.  This
555    is unsafe; see the comment on dict_delete_var() for
556    details. Deleting consecutive vars will result in less callbacks
557    compared to iterating over dict_delete_var.
558    A simple while loop over dict_delete_var will
559    produce (d->n_vars - IDX) * COUNT variable changed callbacks
560    plus COUNT variable delete callbacks.
561    This here produces d->n_vars - IDX variable changed callbacks
562    plus COUNT variable delete callbacks. */
563 void
564 dict_delete_consecutive_vars (struct dictionary *d, size_t idx, size_t count)
565 {
566   assert (idx + count <= d->n_vars);
567
568   /* We need to store the variable and the corresponding case_index
569      for the delete callbacks later. We store them in a linked list.*/
570   struct delvar {
571     struct ll ll;
572     struct variable *var;
573   };
574   struct ll_list list = LL_INITIALIZER (list);
575
576   for (size_t i = idx; i < idx + count; i++)
577     {
578       struct delvar *dv = xmalloc (sizeof (struct delvar));
579       assert (dv);
580       struct variable *v = d->vars[i].var;
581
582       dict_unset_split_var (d, v, false);
583       dict_unset_mrset_var (d, v);
584       dict_unset_varset_var (d, v);
585
586       if (d->weight == v)
587         dict_set_weight (d, NULL);
588
589       if (d->filter == v)
590         dict_set_filter (d, NULL);
591
592       dv->var = v;
593       ll_push_tail (&list, (struct ll *)dv);
594     }
595
596   dict_clear_vectors (d);
597
598   /* Remove variables from var array. */
599   unindex_vars (d, idx, d->n_vars);
600   remove_range (d->vars, d->n_vars, sizeof *d->vars, idx, count);
601   d->n_vars -= count;
602
603   /* Reindexing will result variable-changed callback */
604   reindex_vars (d, idx, d->n_vars, false);
605
606   invalidate_proto (d);
607   if (d->changed) d->changed (d, d->changed_data);
608
609   /* Now issue the variable delete callbacks and delete
610      the variables. The vardict is not valid at this point
611      anymore. That is the reason why we stored the
612      caseindex before reindexing. */
613   if (d->callbacks &&  d->callbacks->vars_deleted)
614     d->callbacks->vars_deleted (d, idx, count, d->cb_data);
615   for (size_t vi = idx; vi < idx + count; vi++)
616     {
617       struct delvar *dv = (struct delvar *) ll_pop_head (&list);
618       var_clear_vardict (dv->var);
619       var_unref (dv->var);
620       free (dv);
621     }
622
623   dict_compact_values (d);
624 }
625
626 /* Deletes scratch variables from dictionary D. */
627 void
628 dict_delete_scratch_vars (struct dictionary *d)
629 {
630   int i;
631
632   /* FIXME: this can be done in O(count) time, but this algorithm
633      is O(count**2). */
634   for (i = 0; i < d->n_vars;)
635     if (var_get_dict_class (d->vars[i].var) == DC_SCRATCH)
636       dict_delete_var (d, d->vars[i].var);
637     else
638       i++;
639
640   dict_compact_values (d);
641 }
642
643 \f
644
645 /* Clears the contents from a dictionary without destroying the
646    dictionary itself. */
647 static void
648 dict_clear__ (struct dictionary *d, bool skip_callbacks)
649 {
650   /* FIXME?  Should we really clear case_limit, label, documents?
651      Others are necessarily cleared by deleting all the variables.*/
652   while (d->n_vars > 0)
653     {
654       dict_delete_var__ (d, d->vars[d->n_vars - 1].var, skip_callbacks);
655     }
656
657   free (d->vars);
658   d->vars = NULL;
659   d->n_vars = d->allocated_vars = 0;
660   invalidate_proto (d);
661   hmap_clear (&d->name_map);
662   dict_set_split_vars__ (d, NULL, 0, SPLIT_NONE, skip_callbacks);
663
664   if (skip_callbacks)
665     {
666       d->weight = NULL;
667       d->filter = NULL;
668     }
669   else
670     {
671       dict_set_weight (d, NULL);
672       dict_set_filter (d, NULL);
673     }
674   d->case_limit = 0;
675   free (d->label);
676   d->label = NULL;
677   string_array_clear (&d->documents);
678   dict_clear_vectors (d);
679   attrset_clear (&d->attributes);
680 }
681
682 /* Clears the contents from a dictionary without destroying the
683    dictionary itself. */
684 void
685 dict_clear (struct dictionary *d)
686 {
687   dict_clear__ (d, false);
688 }
689
690 /* Clears a dictionary and destroys it. */
691 static void
692 _dict_destroy (struct dictionary *d)
693 {
694   /* In general, we don't want callbacks occurring, if the dictionary
695      is being destroyed */
696   d->callbacks  = NULL ;
697
698   dict_clear__ (d, true);
699   string_array_destroy (&d->documents);
700   hmap_destroy (&d->name_map);
701   attrset_destroy (&d->attributes);
702   dict_clear_mrsets (d);
703   dict_clear_varsets (d);
704   free (d->encoding);
705   free (d);
706 }
707
708 struct dictionary *
709 dict_ref (struct dictionary *d)
710 {
711   d->ref_cnt++;
712   return d;
713 }
714
715 void
716 dict_unref (struct dictionary *d)
717 {
718   if (d == NULL)
719     return;
720   d->ref_cnt--;
721   assert (d->ref_cnt >= 0);
722   if (d->ref_cnt == 0)
723     _dict_destroy (d);
724 }
725
726 /* Returns the number of variables in D. */
727 size_t
728 dict_get_n_vars (const struct dictionary *d)
729 {
730   return d->n_vars;
731 }
732
733 /* Returns the variable in D with dictionary index IDX, which
734    must be between 0 and the count returned by
735    dict_get_n_vars(), exclusive. */
736 struct variable *
737 dict_get_var (const struct dictionary *d, size_t idx)
738 {
739   assert (idx < d->n_vars);
740
741   return d->vars[idx].var;
742 }
743
744 /* Sets *VARS to an array of pointers to variables in D and *N
745    to the number of variables in *D.  All variables are returned
746    except for those, if any, in the classes indicated by EXCLUDE.
747    (There is no point in putting DC_SYSTEM in EXCLUDE as
748    dictionaries never include system variables.) */
749 void
750 dict_get_vars (const struct dictionary *d, const struct variable ***vars,
751                size_t *n, enum dict_class exclude)
752 {
753   dict_get_vars_mutable (d, (struct variable ***) vars, n, exclude);
754 }
755
756 /* Sets *VARS to an array of pointers to variables in D and *N
757    to the number of variables in *D.  All variables are returned
758    except for those, if any, in the classes indicated by EXCLUDE.
759    (There is no point in putting DC_SYSTEM in EXCLUDE as
760    dictionaries never include system variables.) */
761 void
762 dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
763                        size_t *n, enum dict_class exclude)
764 {
765   size_t count;
766   size_t i;
767
768   assert (exclude == (exclude & DC_ALL));
769
770   count = 0;
771   for (i = 0; i < d->n_vars; i++)
772     {
773       enum dict_class class = var_get_dict_class (d->vars[i].var);
774       if (!(class & exclude))
775         count++;
776     }
777
778   *vars = xnmalloc (count, sizeof **vars);
779   *n = 0;
780   for (i = 0; i < d->n_vars; i++)
781     {
782       enum dict_class class = var_get_dict_class (d->vars[i].var);
783       if (!(class & exclude))
784         (*vars)[(*n)++] = d->vars[i].var;
785     }
786   assert (*n == count);
787 }
788
789 static struct variable *
790 add_var_with_case_index (struct dictionary *d, struct variable *v,
791                          int case_index)
792 {
793   struct vardict_info *vardict;
794
795   /* Update dictionary. */
796   if (d->n_vars >= d->allocated_vars)
797     {
798       size_t i;
799
800       d->vars = x2nrealloc (d->vars, &d->allocated_vars, sizeof *d->vars);
801       hmap_clear (&d->name_map);
802       for (i = 0; i < d->n_vars; i++)
803         {
804           var_set_vardict (d->vars[i].var, &d->vars[i]);
805           hmap_insert_fast (&d->name_map, &d->vars[i].name_node,
806                             d->vars[i].name_node.hash);
807         }
808     }
809
810   vardict = &d->vars[d->n_vars++];
811   vardict->dict = d;
812   vardict->var = v;
813   hmap_insert (&d->name_map, &vardict->name_node,
814                utf8_hash_case_string (var_get_name (v), 0));
815   vardict->case_index = case_index;
816   var_set_vardict (v, vardict);
817
818   if (d->changed) d->changed (d, d->changed_data);
819   if (d->callbacks &&  d->callbacks->var_added)
820     d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
821
822   invalidate_proto (d);
823
824   return v;
825 }
826
827 static struct variable *
828 add_var (struct dictionary *d, struct variable *v)
829 {
830   return add_var_with_case_index (d, v, dict_get_n_vars (d));
831 }
832
833 /* Creates and returns a new variable in D with the given NAME
834    and WIDTH.  Returns a null pointer if the given NAME would
835    duplicate that of an existing variable in the dictionary. */
836 struct variable *
837 dict_create_var (struct dictionary *d, const char *name, int width)
838 {
839   return (dict_lookup_var (d, name) == NULL
840           ? dict_create_var_assert (d, name, width)
841           : NULL);
842 }
843
844 /* Creates and returns a new variable in D with the given NAME
845    and WIDTH.  Assert-fails if the given NAME would duplicate
846    that of an existing variable in the dictionary. */
847 struct variable *
848 dict_create_var_assert (struct dictionary *d, const char *name, int width)
849 {
850   assert (dict_lookup_var (d, name) == NULL);
851   return add_var (d, var_create (name, width));
852 }
853
854 /* Creates and returns a new variable in D, as a copy of existing variable
855    OLD_VAR, which need not be in D or in any dictionary.  Returns a null
856    pointer if OLD_VAR's name would duplicate that of an existing variable in
857    the dictionary. */
858 struct variable *
859 dict_clone_var (struct dictionary *d, const struct variable *old_var)
860 {
861   return dict_clone_var_as (d, old_var, var_get_name (old_var));
862 }
863
864 /* Creates and returns a new variable in D, as a copy of existing variable
865    OLD_VAR, which need not be in D or in any dictionary.  Assert-fails if
866    OLD_VAR's name would duplicate that of an existing variable in the
867    dictionary. */
868 struct variable *
869 dict_clone_var_assert (struct dictionary *d, const struct variable *old_var)
870 {
871   return dict_clone_var_as_assert (d, old_var, var_get_name (old_var));
872 }
873
874 /* Creates and returns a new variable in D with name NAME, as a copy of
875    existing variable OLD_VAR, which need not be in D or in any dictionary.
876    Returns a null pointer if the given NAME would duplicate that of an existing
877    variable in the dictionary. */
878 struct variable *
879 dict_clone_var_as (struct dictionary *d, const struct variable *old_var,
880                    const char *name)
881 {
882   return (dict_lookup_var (d, name) == NULL
883           ? dict_clone_var_as_assert (d, old_var, name)
884           : NULL);
885 }
886
887 /* Creates and returns a new variable in D with name NAME, as a copy of
888    existing variable OLD_VAR, which need not be in D or in any dictionary.
889    Assert-fails if the given NAME would duplicate that of an existing variable
890    in the dictionary. */
891 struct variable *
892 dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
893                           const char *name)
894 {
895   struct variable *new_var = var_clone (old_var);
896   assert (dict_lookup_var (d, name) == NULL);
897   var_set_name (new_var, name);
898   return add_var (d, new_var);
899 }
900
901 struct variable *
902 dict_clone_var_in_place_assert (struct dictionary *d,
903                                 const struct variable *old_var)
904 {
905   assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
906   return add_var_with_case_index (d, var_clone (old_var),
907                                   var_get_case_index (old_var));
908 }
909
910 /* Returns the variable named NAME in D, or a null pointer if no
911    variable has that name. */
912 struct variable *
913 dict_lookup_var (const struct dictionary *d, const char *name)
914 {
915   struct vardict_info *vardict;
916
917   HMAP_FOR_EACH_WITH_HASH (vardict, struct vardict_info, name_node,
918                            utf8_hash_case_string (name, 0), &d->name_map)
919     {
920       struct variable *var = vardict->var;
921       if (!utf8_strcasecmp (var_get_name (var), name))
922         return var;
923     }
924
925   return NULL;
926 }
927
928 /* Returns the variable named NAME in D.  Assert-fails if no
929    variable has that name. */
930 struct variable *
931 dict_lookup_var_assert (const struct dictionary *d, const char *name)
932 {
933   struct variable *v = dict_lookup_var (d, name);
934   assert (v != NULL);
935   return v;
936 }
937
938 /* Returns true if variable V is in dictionary D,
939    false otherwise. */
940 bool
941 dict_contains_var (const struct dictionary *d, const struct variable *v)
942 {
943   return (var_has_vardict (v)
944           && vardict_get_dictionary (var_get_vardict (v)) == d);
945 }
946
947 /* Moves V to 0-based position IDX in D.  Other variables in D,
948    if any, retain their relative positions.  Runs in time linear
949    in the distance moved. */
950 void
951 dict_reorder_var (struct dictionary *d, struct variable *v, size_t new_index)
952 {
953   assert (new_index < d->n_vars);
954
955   size_t old_index = var_get_dict_index (v);
956   if (new_index == old_index)
957     return;
958
959   unindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1);
960   move_element (d->vars, d->n_vars, sizeof *d->vars, old_index, new_index);
961   reindex_vars (d, MIN (old_index, new_index), MAX (old_index, new_index) + 1, false);
962 }
963
964 /* Reorders the variables in D, placing the COUNT variables
965    listed in ORDER in that order at the beginning of D.  The
966    other variables in D, if any, retain their relative
967    positions. */
968 void
969 dict_reorder_vars (struct dictionary *d,
970                    struct variable *const *order, size_t count)
971 {
972   struct vardict_info *new_var;
973   size_t i;
974
975   assert (count == 0 || order != NULL);
976   assert (count <= d->n_vars);
977
978   new_var = xnmalloc (d->allocated_vars, sizeof *new_var);
979
980   /* Add variables in ORDER to new_var. */
981   for (i = 0; i < count; i++)
982     {
983       struct vardict_info *old_var;
984
985       assert (dict_contains_var (d, order[i]));
986
987       old_var = var_get_vardict (order[i]);
988       new_var[i] = *old_var;
989       old_var->dict = NULL;
990     }
991
992   /* Add remaining variables to new_var. */
993   for (i = 0; i < d->n_vars; i++)
994     if (d->vars[i].dict != NULL)
995       new_var[count++] = d->vars[i];
996   assert (count == d->n_vars);
997
998   /* Replace old vardicts by new ones. */
999   free (d->vars);
1000   d->vars = new_var;
1001
1002   hmap_clear (&d->name_map);
1003   reindex_vars (d, 0, d->n_vars, false);
1004 }
1005
1006 /* Changes the name of variable V that is currently in a dictionary to
1007    NEW_NAME. */
1008 static void
1009 rename_var (struct variable *v, const char *new_name)
1010 {
1011   struct vardict_info *vardict = var_get_vardict (v);
1012   var_clear_vardict (v);
1013   var_set_name (v, new_name);
1014   vardict->name_node.hash = utf8_hash_case_string (new_name, 0);
1015   var_set_vardict (v, vardict);
1016 }
1017
1018 /* Tries to changes the name of V in D to name NEW_NAME.  Returns true if
1019    successful, false if a variable (other than V) with the given name already
1020    exists in D. */
1021 bool
1022 dict_try_rename_var (struct dictionary *d, struct variable *v,
1023                      const char *new_name)
1024 {
1025   struct variable *conflict = dict_lookup_var (d, new_name);
1026   if (conflict && v != conflict)
1027     return false;
1028
1029   struct variable *old = var_clone (v);
1030   unindex_var (d, var_get_vardict (v));
1031   rename_var (v, new_name);
1032   reindex_var (d, var_get_vardict (v), false);
1033
1034   if (settings_get_algorithm () == ENHANCED)
1035     var_clear_short_names (v);
1036
1037   if (d->changed) d->changed (d, d->changed_data);
1038   if (d->callbacks &&  d->callbacks->var_changed)
1039     d->callbacks->var_changed (d, var_get_dict_index (v), VAR_TRAIT_NAME, old, d->cb_data);
1040
1041   var_unref (old);
1042
1043   return true;
1044 }
1045
1046 /* Changes the name of V in D to name NEW_NAME.  Assert-fails if
1047    a variable named NEW_NAME is already in D, except that
1048    NEW_NAME may be the same as V's existing name. */
1049 void
1050 dict_rename_var (struct dictionary *d, struct variable *v,
1051                  const char *new_name)
1052 {
1053   bool ok UNUSED = dict_try_rename_var (d, v, new_name);
1054   assert (ok);
1055 }
1056
1057 /* Renames COUNT variables specified in VARS to the names given
1058    in NEW_NAMES within dictionary D.  If the renaming would
1059    result in a duplicate variable name, returns false and stores a
1060    name that would be duplicated into *ERR_NAME (if ERR_NAME is
1061    non-null).  Otherwise, the renaming is successful, and true
1062    is returned. */
1063 bool
1064 dict_rename_vars (struct dictionary *d,
1065                   struct variable **vars, char **new_names, size_t count,
1066                   char **err_name)
1067 {
1068   struct pool *pool;
1069   char **old_names;
1070   size_t i;
1071
1072   assert (count == 0 || vars != NULL);
1073   assert (count == 0 || new_names != NULL);
1074
1075   /* Save the names of the variables to be renamed. */
1076   pool = pool_create ();
1077   old_names = pool_nalloc (pool, count, sizeof *old_names);
1078   for (i = 0; i < count; i++)
1079     old_names[i] = pool_strdup (pool, var_get_name (vars[i]));
1080
1081   /* Remove the variables to be renamed from the name hash,
1082      and rename them. */
1083   for (i = 0; i < count; i++)
1084     {
1085       unindex_var (d, var_get_vardict (vars[i]));
1086       rename_var (vars[i], new_names[i]);
1087     }
1088
1089   /* Add the renamed variables back into the name hash,
1090      checking for conflicts. */
1091   for (i = 0; i < count; i++)
1092     {
1093       if (dict_lookup_var (d, var_get_name (vars[i])) != NULL)
1094         {
1095           /* There is a name conflict.
1096              Back out all the name changes that have already
1097              taken place, and indicate failure. */
1098           size_t fail_idx = i;
1099           if (err_name != NULL)
1100             *err_name = new_names[i];
1101
1102           for (i = 0; i < fail_idx; i++)
1103             unindex_var (d, var_get_vardict (vars[i]));
1104
1105           for (i = 0; i < count; i++)
1106             {
1107               rename_var (vars[i], old_names[i]);
1108               reindex_var (d, var_get_vardict (vars[i]), false);
1109             }
1110
1111           pool_destroy (pool);
1112           return false;
1113         }
1114       reindex_var (d, var_get_vardict (vars[i]), false);
1115     }
1116
1117   /* Clear short names. */
1118   if (settings_get_algorithm () == ENHANCED)
1119     for (i = 0; i < count; i++)
1120       var_clear_short_names (vars[i]);
1121
1122   pool_destroy (pool);
1123   return true;
1124 }
1125
1126 /* Returns true if a variable named NAME may be inserted in DICT;
1127    that is, if there is not already a variable with that name in
1128    DICT and if NAME is not a reserved word.  (The caller's checks
1129    have already verified that NAME is otherwise acceptable as a
1130    variable name.) */
1131 static bool
1132 var_name_is_insertable (const struct dictionary *dict, const char *name)
1133 {
1134   return (dict_lookup_var (dict, name) == NULL
1135           && lex_id_to_token (ss_cstr (name)) == T_ID);
1136 }
1137
1138 static char *
1139 make_hinted_name (const struct dictionary *dict, const char *hint)
1140 {
1141   size_t hint_len = strlen (hint);
1142   bool dropped = false;
1143   char *root, *rp;
1144   size_t ofs;
1145   int mblen;
1146
1147   if (hint_len > ID_MAX_LEN)
1148     hint_len = ID_MAX_LEN;
1149
1150   /* The allocation size here is OK: characters that are copied directly fit
1151      OK, and characters that are not copied directly are replaced by a single
1152      '_' byte.  If u8_mbtouc() replaces bad input by 0xfffd, then that will get
1153      replaced by '_' too.  */
1154   root = rp = xmalloc (hint_len + 1);
1155   for (ofs = 0; ofs < hint_len; ofs += mblen)
1156     {
1157       ucs4_t uc;
1158
1159       mblen = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, hint + ofs),
1160                          hint_len - ofs);
1161       if (rp == root
1162           ? lex_uc_is_id1 (uc) && uc != '$'
1163           : lex_uc_is_idn (uc))
1164         {
1165           if (dropped)
1166             {
1167               *rp++ = '_';
1168               dropped = false;
1169             }
1170           rp += u8_uctomb (CHAR_CAST (uint8_t *, rp), uc, 6);
1171         }
1172       else if (rp != root)
1173         dropped = true;
1174     }
1175   *rp = '\0';
1176
1177   if (root[0] != '\0')
1178     {
1179       unsigned long int i;
1180
1181       if (var_name_is_insertable (dict, root))
1182         return root;
1183
1184       for (i = 0; i < ULONG_MAX; i++)
1185         {
1186           char suffix[INT_BUFSIZE_BOUND (i) + 1];
1187           char *name;
1188
1189           suffix[0] = '_';
1190           if (!str_format_26adic (i + 1, true, &suffix[1], sizeof suffix - 1))
1191             NOT_REACHED ();
1192
1193           name = utf8_encoding_concat (root, suffix, dict->encoding, 64);
1194           if (var_name_is_insertable (dict, name))
1195             {
1196               free (root);
1197               return name;
1198             }
1199           free (name);
1200         }
1201     }
1202
1203   free (root);
1204
1205   return NULL;
1206 }
1207
1208 static char *
1209 make_numeric_name (const struct dictionary *dict, unsigned long int *num_start)
1210 {
1211   unsigned long int number;
1212
1213   for (number = num_start != NULL ? MAX (*num_start, 1) : 1;
1214        number < ULONG_MAX;
1215        number++)
1216     {
1217       char name[3 + INT_STRLEN_BOUND (number) + 1];
1218
1219       sprintf (name, "VAR%03lu", number);
1220       if (dict_lookup_var (dict, name) == NULL)
1221         {
1222           if (num_start != NULL)
1223             *num_start = number + 1;
1224           return xstrdup (name);
1225         }
1226     }
1227
1228   NOT_REACHED ();
1229 }
1230
1231
1232 /* Devises and returns a variable name unique within DICT.  The variable name
1233    is owned by the caller, which must free it with free() when it is no longer
1234    needed.
1235
1236    HINT, if it is non-null, is used as a suggestion that will be
1237    modified for suitability as a variable name and for
1238    uniqueness.
1239
1240    If HINT is null or entirely unsuitable, a name in the form
1241    "VAR%03d" will be generated, where the smallest unused integer
1242    value is used.  If NUM_START is non-null, then its value is
1243    used as the minimum numeric value to check, and it is updated
1244    to the next value to be checked.
1245 */
1246 char *
1247 dict_make_unique_var_name (const struct dictionary *dict, const char *hint,
1248                            unsigned long int *num_start)
1249 {
1250   if (hint != NULL)
1251     {
1252       char *hinted_name = make_hinted_name (dict, hint);
1253       if (hinted_name != NULL)
1254         return hinted_name;
1255     }
1256
1257   return make_numeric_name (dict, num_start);
1258 }
1259
1260 /* Returns whether variable names must be valid identifiers.  Normally, this is
1261    true, but sometimes a dictionary is prepared for external use (e.g. output
1262    to a CSV file) where names don't have to be valid. */
1263 bool
1264 dict_get_names_must_be_ids (const struct dictionary *d)
1265 {
1266   return d->names_must_be_ids;
1267 }
1268
1269 /* Sets whether variable names must be valid identifiers.  Normally, this is
1270    true, but sometimes a dictionary is prepared for external use (e.g. output
1271    to a CSV file) where names don't have to be valid.
1272
1273    Changing this setting from false to true doesn't make the dictionary check
1274    all the existing variable names, so it can cause an invariant violation. */
1275 void
1276 dict_set_names_must_be_ids (struct dictionary *d, bool names_must_be_ids)
1277 {
1278   d->names_must_be_ids = names_must_be_ids;
1279 }
1280
1281 /* Returns the weighting variable in dictionary D, or a null
1282    pointer if the dictionary is unweighted. */
1283 struct variable *
1284 dict_get_weight (const struct dictionary *d)
1285 {
1286   assert (d->weight == NULL || dict_contains_var (d, d->weight));
1287
1288   return d->weight;
1289 }
1290
1291 /* Returns the value of D's weighting variable in case C, except
1292    that a negative or missing weight is returned as 0.  Returns 1 if the
1293    dictionary is unweighted.  Will warn about missing, negative,
1294    or zero values if *WARN_ON_INVALID is true.  The function will
1295    set *WARN_ON_INVALID to false if an invalid weight is
1296    found. */
1297 double
1298 dict_get_case_weight (const struct dictionary *d, const struct ccase *c,
1299                       bool *warn_on_invalid)
1300 {
1301   assert (c != NULL);
1302
1303   if (d->weight == NULL)
1304     return 1.0;
1305   else
1306     {
1307       double w = case_num (c, d->weight);
1308
1309       return var_force_valid_weight (d->weight, w, warn_on_invalid);
1310     }
1311 }
1312
1313 /* Like dict_get_case_weight(), but additionally rounds each weight to the
1314    nearest integer.  */
1315 double
1316 dict_get_rounded_case_weight (const struct dictionary *d,
1317                               const struct ccase *c, bool *warn_on_invalid)
1318 {
1319   return floor (dict_get_case_weight (d, c, warn_on_invalid) + 0.5);
1320 }
1321
1322 /* Returns the format to use for weights. */
1323 struct fmt_spec
1324 dict_get_weight_format (const struct dictionary *d)
1325 {
1326   return d->weight ? var_get_print_format (d->weight) : F_8_0;
1327 }
1328
1329 /* Sets the weighting variable of D to V, or turning off
1330    weighting if V is a null pointer. */
1331 void
1332 dict_set_weight (struct dictionary *d, struct variable *v)
1333 {
1334   assert (v == NULL || dict_contains_var (d, v));
1335   assert (v == NULL || var_is_numeric (v));
1336
1337   d->weight = v;
1338
1339   if (d->changed) d->changed (d, d->changed_data);
1340   if (d->callbacks &&  d->callbacks->weight_changed)
1341     d->callbacks->weight_changed (d,
1342                                   v ? var_get_dict_index (v) : -1,
1343                                   d->cb_data);
1344 }
1345
1346 /* Returns the filter variable in dictionary D (see cmd_filter())
1347    or a null pointer if the dictionary is unfiltered. */
1348 struct variable *
1349 dict_get_filter (const struct dictionary *d)
1350 {
1351   assert (d->filter == NULL || dict_contains_var (d, d->filter));
1352
1353   return d->filter;
1354 }
1355
1356 /* Sets V as the filter variable for dictionary D.  Passing a
1357    null pointer for V turn off filtering. */
1358 void
1359 dict_set_filter (struct dictionary *d, struct variable *v)
1360 {
1361   assert (v == NULL || dict_contains_var (d, v));
1362   assert (v == NULL || var_is_numeric (v));
1363
1364   d->filter = v;
1365
1366   if (d->changed) d->changed (d, d->changed_data);
1367   if (d->callbacks && d->callbacks->filter_changed)
1368     d->callbacks->filter_changed (d,
1369                                   v ? var_get_dict_index (v) : -1,
1370                                       d->cb_data);
1371 }
1372
1373 /* Returns the case limit for dictionary D, or zero if the number
1374    of cases is unlimited. */
1375 casenumber
1376 dict_get_case_limit (const struct dictionary *d)
1377 {
1378   return d->case_limit;
1379 }
1380
1381 /* Sets CASE_LIMIT as the case limit for dictionary D.  Use
1382    0 for CASE_LIMIT to indicate no limit. */
1383 void
1384 dict_set_case_limit (struct dictionary *d, casenumber case_limit)
1385 {
1386   d->case_limit = case_limit;
1387 }
1388
1389 /* Returns the prototype used for cases created by dictionary D. */
1390 const struct caseproto *
1391 dict_get_proto (const struct dictionary *d_)
1392 {
1393   struct dictionary *d = CONST_CAST (struct dictionary *, d_);
1394   if (d->proto == NULL)
1395     {
1396       short int *widths = xnmalloc (d->n_vars, sizeof *widths);
1397       for (size_t i = 0; i < d->n_vars; i++)
1398         widths[i] = -1;
1399       for (size_t i = 0; i < d->n_vars; i++)
1400         {
1401           const struct variable *var = d->vars[i].var;
1402           size_t case_idx = var_get_case_index (var);
1403           assert (case_idx < d->n_vars);
1404           assert (widths[case_idx] == -1);
1405           widths[case_idx] = var_get_width (var);
1406         }
1407
1408       d->proto = caseproto_from_widths (widths, d->n_vars);
1409     }
1410   return d->proto;
1411 }
1412
1413 /* Reassigns values in dictionary D so that fragmentation is
1414    eliminated. */
1415 void
1416 dict_compact_values (struct dictionary *d)
1417 {
1418   for (size_t i = 0; i < d->n_vars; i++)
1419     {
1420       struct variable *v = d->vars[i].var;
1421       set_var_case_index (v, i);
1422     }
1423   invalidate_proto (d);
1424 }
1425
1426 /* Returns the number of values occupied by the variables in
1427    dictionary D.  All variables are considered if EXCLUDE_CLASSES
1428    is 0, or it may contain one or more of DC_ORDINARY, DC_SYSTEM,
1429    or DC_SCRATCH to exclude the corresponding type of variable. */
1430 size_t
1431 dict_count_values (const struct dictionary *d, unsigned int exclude_classes)
1432 {
1433   assert (!(exclude_classes & ~DC_ALL));
1434
1435   size_t n = 0;
1436   for (size_t i = 0; i < d->n_vars; i++)
1437     {
1438       enum dict_class class = var_get_dict_class (d->vars[i].var);
1439       if (!(exclude_classes & class))
1440         n++;
1441     }
1442   return n;
1443 }
1444
1445 /* Returns the file label for D, or a null pointer if D is
1446    unlabeled (see cmd_file_label()). */
1447 const char *
1448 dict_get_label (const struct dictionary *d)
1449 {
1450   return d->label;
1451 }
1452
1453 /* Sets D's file label to LABEL, truncating it to at most 60 bytes in D's
1454    encoding.
1455
1456    Removes D's label if LABEL is null or the empty string. */
1457 void
1458 dict_set_label (struct dictionary *d, const char *label)
1459 {
1460   free (d->label);
1461   if (label == NULL || label[0] == '\0')
1462     d->label = NULL;
1463   else
1464     d->label = utf8_encoding_trunc (label, d->encoding, 60);
1465 }
1466
1467 /* Returns the documents for D, as an UTF-8 encoded string_array.  The
1468    return value is always nonnull; if there are no documents then the
1469    string_arary is empty.*/
1470 const struct string_array *
1471 dict_get_documents (const struct dictionary *d)
1472 {
1473   return &d->documents;
1474 }
1475
1476 /* Replaces the documents for D by NEW_DOCS, a UTF-8 encoded string_array. */
1477 void
1478 dict_set_documents (struct dictionary *d, const struct string_array *new_docs)
1479 {
1480   /* Swap out the old documents, instead of destroying them immediately, to
1481      allow the new documents to include pointers into the old ones. */
1482   struct string_array old_docs = STRING_ARRAY_INITIALIZER;
1483   string_array_swap (&d->documents, &old_docs);
1484
1485   for (size_t i = 0; i < new_docs->n; i++)
1486     dict_add_document_line (d, new_docs->strings[i], false);
1487
1488   string_array_destroy (&old_docs);
1489 }
1490
1491 /* Replaces the documents for D by UTF-8 encoded string NEW_DOCS, dividing it
1492    into individual lines at new-line characters.  Each line is truncated to at
1493    most DOC_LINE_LENGTH bytes in D's encoding. */
1494 void
1495 dict_set_documents_string (struct dictionary *d, const char *new_docs)
1496 {
1497   const char *s;
1498
1499   dict_clear_documents (d);
1500   for (s = new_docs; *s != '\0';)
1501     {
1502       size_t len = strcspn (s, "\n");
1503       char *line = xmemdup0 (s, len);
1504       dict_add_document_line (d, line, false);
1505       free (line);
1506
1507       s += len;
1508       if (*s == '\n')
1509         s++;
1510     }
1511 }
1512
1513 /* Drops the documents from dictionary D. */
1514 void
1515 dict_clear_documents (struct dictionary *d)
1516 {
1517   string_array_clear (&d->documents);
1518 }
1519
1520 /* Appends the UTF-8 encoded LINE to the documents in D.  LINE will be
1521    truncated so that it is no more than 80 bytes in the dictionary's
1522    encoding.  If this causes some text to be lost, and ISSUE_WARNING is true,
1523    then a warning will be issued. */
1524 bool
1525 dict_add_document_line (struct dictionary *d, const char *line,
1526                         bool issue_warning)
1527 {
1528   size_t trunc_len;
1529   bool truncated;
1530
1531   trunc_len = utf8_encoding_trunc_len (line, d->encoding, DOC_LINE_LENGTH);
1532   truncated = line[trunc_len] != '\0';
1533   if (truncated && issue_warning)
1534     {
1535       /* TRANSLATORS: "bytes" is correct, not characters due to UTF encoding */
1536       msg (SW, _("Truncating document line to %d bytes."), DOC_LINE_LENGTH);
1537     }
1538
1539   string_array_append_nocopy (&d->documents, xmemdup0 (line, trunc_len));
1540
1541   return !truncated;
1542 }
1543
1544 /* Returns the number of document lines in dictionary D. */
1545 size_t
1546 dict_get_document_n_lines (const struct dictionary *d)
1547 {
1548   return d->documents.n;
1549 }
1550
1551 /* Returns document line number IDX in dictionary D.  The caller must not
1552    modify or free the returned string. */
1553 const char *
1554 dict_get_document_line (const struct dictionary *d, size_t idx)
1555 {
1556   assert (idx < d->documents.n);
1557   return d->documents.strings[idx];
1558 }
1559
1560 /* Creates in D a vector named NAME that contains the N
1561    variables in VAR.  Returns true if successful, or false if a
1562    vector named NAME already exists in D. */
1563 bool
1564 dict_create_vector (struct dictionary *d,
1565                     const char *name,
1566                     struct variable **var, size_t n)
1567 {
1568   assert (n > 0);
1569   for (size_t i = 0; i < n; i++)
1570     assert (dict_contains_var (d, var[i]));
1571
1572   if (dict_lookup_vector (d, name) == NULL)
1573     {
1574       d->vector = xnrealloc (d->vector, d->n_vectors + 1, sizeof *d->vector);
1575       d->vector[d->n_vectors++] = vector_create (name, var, n);
1576       return true;
1577     }
1578   else
1579     return false;
1580 }
1581
1582 /* Creates in D a vector named NAME that contains the N
1583    variables in VAR.  A vector named NAME must not already exist
1584    in D. */
1585 void
1586 dict_create_vector_assert (struct dictionary *d,
1587                            const char *name,
1588                            struct variable **var, size_t n)
1589 {
1590   assert (dict_lookup_vector (d, name) == NULL);
1591   dict_create_vector (d, name, var, n);
1592 }
1593
1594 /* Returns the vector in D with index IDX, which must be less
1595    than dict_get_n_vectors (D). */
1596 const struct vector *
1597 dict_get_vector (const struct dictionary *d, size_t idx)
1598 {
1599   assert (idx < d->n_vectors);
1600
1601   return d->vector[idx];
1602 }
1603
1604 /* Returns the number of vectors in D. */
1605 size_t
1606 dict_get_n_vectors (const struct dictionary *d)
1607 {
1608   return d->n_vectors;
1609 }
1610
1611 /* Looks up and returns the vector within D with the given
1612    NAME. */
1613 const struct vector *
1614 dict_lookup_vector (const struct dictionary *d, const char *name)
1615 {
1616   size_t i;
1617   for (i = 0; i < d->n_vectors; i++)
1618     if (!utf8_strcasecmp (vector_get_name (d->vector[i]), name))
1619       return d->vector[i];
1620   return NULL;
1621 }
1622
1623 /* Deletes all vectors from D. */
1624 void
1625 dict_clear_vectors (struct dictionary *d)
1626 {
1627   size_t i;
1628
1629   for (i = 0; i < d->n_vectors; i++)
1630     vector_destroy (d->vector[i]);
1631   free (d->vector);
1632
1633   d->vector = NULL;
1634   d->n_vectors = 0;
1635 }
1636 \f
1637 /* Multiple response sets. */
1638
1639 /* Returns the multiple response set in DICT with index IDX, which must be
1640    between 0 and the count returned by dict_get_n_mrsets(), exclusive. */
1641 const struct mrset *
1642 dict_get_mrset (const struct dictionary *dict, size_t idx)
1643 {
1644   assert (idx < dict->n_mrsets);
1645   return dict->mrsets[idx];
1646 }
1647
1648 /* Returns the number of multiple response sets in DICT. */
1649 size_t
1650 dict_get_n_mrsets (const struct dictionary *dict)
1651 {
1652   return dict->n_mrsets;
1653 }
1654
1655 /* Looks for a multiple response set named NAME in DICT.  If it finds one,
1656    returns its index; otherwise, returns SIZE_MAX. */
1657 static size_t
1658 dict_lookup_mrset_idx (const struct dictionary *dict, const char *name)
1659 {
1660   size_t i;
1661
1662   for (i = 0; i < dict->n_mrsets; i++)
1663     if (!utf8_strcasecmp (name, dict->mrsets[i]->name))
1664       return i;
1665
1666   return SIZE_MAX;
1667 }
1668
1669 /* Looks for a multiple response set named NAME in DICT.  If it finds one,
1670    returns it; otherwise, returns NULL. */
1671 const struct mrset *
1672 dict_lookup_mrset (const struct dictionary *dict, const char *name)
1673 {
1674   size_t idx = dict_lookup_mrset_idx (dict, name);
1675   return idx != SIZE_MAX ? dict->mrsets[idx] : NULL;
1676 }
1677
1678 /* Adds MRSET to DICT, replacing any existing set with the same name.  Returns
1679    true if a set was replaced, false if none existed with the specified name.
1680
1681    Ownership of MRSET is transferred to DICT. */
1682 bool
1683 dict_add_mrset (struct dictionary *dict, struct mrset *mrset)
1684 {
1685   size_t idx;
1686
1687   assert (mrset_ok (mrset, dict));
1688
1689   idx = dict_lookup_mrset_idx (dict, mrset->name);
1690   if (idx == SIZE_MAX)
1691     {
1692       dict->mrsets = xrealloc (dict->mrsets,
1693                                (dict->n_mrsets + 1) * sizeof *dict->mrsets);
1694       dict->mrsets[dict->n_mrsets++] = mrset;
1695       return true;
1696     }
1697   else
1698     {
1699       mrset_destroy (dict->mrsets[idx]);
1700       dict->mrsets[idx] = mrset;
1701       return false;
1702     }
1703 }
1704
1705 /* Looks for a multiple response set in DICT named NAME.  If found, removes it
1706    from DICT and returns true.  If none is found, returns false without
1707    modifying DICT.
1708
1709    Deleting one multiple response set causes the indexes of other sets within
1710    DICT to change. */
1711 bool
1712 dict_delete_mrset (struct dictionary *dict, const char *name)
1713 {
1714   size_t idx = dict_lookup_mrset_idx (dict, name);
1715   if (idx != SIZE_MAX)
1716     {
1717       mrset_destroy (dict->mrsets[idx]);
1718       dict->mrsets[idx] = dict->mrsets[--dict->n_mrsets];
1719       return true;
1720     }
1721   else
1722     return false;
1723 }
1724
1725 /* Deletes all multiple response sets from DICT. */
1726 void
1727 dict_clear_mrsets (struct dictionary *dict)
1728 {
1729   size_t i;
1730
1731   for (i = 0; i < dict->n_mrsets; i++)
1732     mrset_destroy (dict->mrsets[i]);
1733   free (dict->mrsets);
1734   dict->mrsets = NULL;
1735   dict->n_mrsets = 0;
1736 }
1737
1738 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1739 static void
1740 dict_unset_mrset_var (struct dictionary *dict, struct variable *var)
1741 {
1742   size_t i;
1743
1744   assert (dict_contains_var (dict, var));
1745
1746   for (i = 0; i < dict->n_mrsets;)
1747     {
1748       struct mrset *mrset = dict->mrsets[i];
1749       size_t j;
1750
1751       for (j = 0; j < mrset->n_vars;)
1752         if (mrset->vars[j] == var)
1753           remove_element (mrset->vars, mrset->n_vars--,
1754                           sizeof *mrset->vars, j);
1755         else
1756           j++;
1757
1758       if (mrset->n_vars < 2)
1759         {
1760           mrset_destroy (mrset);
1761           dict->mrsets[i] = dict->mrsets[--dict->n_mrsets];
1762         }
1763       else
1764         i++;
1765     }
1766 }
1767 \f
1768
1769 /* Returns the variable set in DICT with index IDX, which must be between 0 and
1770    the count returned by dict_get_n_varsets(), exclusive. */
1771 const struct varset *
1772 dict_get_varset (const struct dictionary *dict, size_t idx)
1773 {
1774   assert (idx < dict->n_varsets);
1775   return dict->varsets[idx];
1776 }
1777
1778 /* Returns the number of variable sets in DICT. */
1779 size_t
1780 dict_get_n_varsets (const struct dictionary *dict)
1781 {
1782   return dict->n_varsets;
1783 }
1784
1785 /* Looks for a variable set named NAME in DICT.  If it finds one, returns its
1786    index; otherwise, returns SIZE_MAX. */
1787 static size_t
1788 dict_lookup_varset_idx (const struct dictionary *dict, const char *name)
1789 {
1790   for (size_t i = 0; i < dict->n_varsets; i++)
1791     if (!utf8_strcasecmp (name, dict->varsets[i]->name))
1792       return i;
1793
1794   return SIZE_MAX;
1795 }
1796
1797 /* Looks for a multiple response set named NAME in DICT.  If it finds one,
1798    returns it; otherwise, returns NULL. */
1799 const struct varset *
1800 dict_lookup_varset (const struct dictionary *dict, const char *name)
1801 {
1802   size_t idx = dict_lookup_varset_idx (dict, name);
1803   return idx != SIZE_MAX ? dict->varsets[idx] : NULL;
1804 }
1805
1806 /* Adds VARSET to DICT, replacing any existing set with the same name.  Returns
1807    true if a set was replaced, false if none existed with the specified name.
1808
1809    Ownership of VARSET is transferred to DICT. */
1810 bool
1811 dict_add_varset (struct dictionary *dict, struct varset *varset)
1812 {
1813   size_t idx = dict_lookup_varset_idx (dict, varset->name);
1814   if (idx == SIZE_MAX)
1815     {
1816       dict->varsets = xrealloc (dict->varsets,
1817                                (dict->n_varsets + 1) * sizeof *dict->varsets);
1818       dict->varsets[dict->n_varsets++] = varset;
1819       return true;
1820     }
1821   else
1822     {
1823       varset_destroy (dict->varsets[idx]);
1824       dict->varsets[idx] = varset;
1825       return false;
1826     }
1827 }
1828
1829 /* Deletes all variable sets from DICT. */
1830 void
1831 dict_clear_varsets (struct dictionary *dict)
1832 {
1833   for (size_t i = 0; i < dict->n_varsets; i++)
1834     varset_destroy (dict->varsets[i]);
1835   free (dict->varsets);
1836   dict->varsets = NULL;
1837   dict->n_varsets = 0;
1838 }
1839
1840 /* Removes VAR, which must be in DICT, from DICT's multiple response sets. */
1841 static void
1842 dict_unset_varset_var (struct dictionary *dict, struct variable *var)
1843 {
1844   assert (dict_contains_var (dict, var));
1845
1846   for (size_t i = 0; i < dict->n_varsets; i++)
1847     {
1848       struct varset *varset = dict->varsets[i];
1849
1850       for (size_t j = 0; j < varset->n_vars;)
1851         if (varset->vars[j] == var)
1852           remove_element (varset->vars, varset->n_vars--,
1853                           sizeof *varset->vars, j);
1854         else
1855           j++;
1856     }
1857 }
1858 \f
1859 /* Returns D's attribute set.  The caller may examine or modify
1860    the attribute set, but must not destroy it.  Destroying D or
1861    calling dict_set_attributes for D will also destroy D's
1862    attribute set. */
1863 struct attrset *
1864 dict_get_attributes (const struct dictionary *d)
1865 {
1866   return CONST_CAST (struct attrset *, &d->attributes);
1867 }
1868
1869 /* Replaces D's attributes set by a copy of ATTRS. */
1870 void
1871 dict_set_attributes (struct dictionary *d, const struct attrset *attrs)
1872 {
1873   attrset_destroy (&d->attributes);
1874   attrset_clone (&d->attributes, attrs);
1875 }
1876
1877 /* Returns true if D has at least one attribute in its attribute
1878    set, false if D's attribute set is empty. */
1879 bool
1880 dict_has_attributes (const struct dictionary *d)
1881 {
1882   return attrset_count (&d->attributes) > 0;
1883 }
1884
1885 /* Called from variable.c to notify the dictionary that some property (indicated
1886    by WHAT) of the variable has changed.  OLDVAR is a copy of V as it existed
1887    prior to the change.  OLDVAR is destroyed by this function.
1888 */
1889 void
1890 dict_var_changed (const struct variable *v, unsigned int what, struct variable *oldvar)
1891 {
1892   if (var_has_vardict (v))
1893     {
1894       const struct vardict_info *vardict = var_get_vardict (v);
1895       struct dictionary *d = vardict->dict;
1896
1897       if (NULL == d)
1898         return;
1899
1900       if (what & (VAR_TRAIT_WIDTH | VAR_TRAIT_POSITION))
1901         invalidate_proto (d);
1902
1903       if (d->changed) d->changed (d, d->changed_data);
1904       if (d->callbacks && d->callbacks->var_changed)
1905         d->callbacks->var_changed (d, var_get_dict_index (v), what, oldvar, d->cb_data);
1906     }
1907   var_unref (oldvar);
1908 }
1909
1910
1911 \f
1912 int
1913 vardict_get_dict_index (const struct vardict_info *vardict)
1914 {
1915   return vardict - vardict->dict->vars;
1916 }