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