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