First phase of making SORT CASES stable (PR 12035).
[pspp-builds.git] / src / dictionary.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "dictionary.h"
22 #include <stdlib.h>
23 #include "algorithm.h"
24 #include "alloc.h"
25 #include "case.h"
26 #include "error.h"
27 #include "hash.h"
28 #include "misc.h"
29 #include "str.h"
30 #include "value-labels.h"
31 #include "var.h"
32
33 /* A dictionary. */
34 struct dictionary
35   {
36     struct variable **var;      /* Variables. */
37     size_t var_cnt, var_cap;    /* Number of variables, capacity. */
38     struct hsh_table *name_tab; /* Variable index by name. */
39     int next_value_idx;         /* Index of next `union value' to allocate. */
40     struct variable **split;    /* SPLIT FILE vars. */
41     size_t split_cnt;           /* SPLIT FILE count. */
42     struct variable *weight;    /* WEIGHT variable. */
43     struct variable *filter;    /* FILTER variable. */
44     int case_limit;             /* Current case limit (N command). */
45     char *label;                /* File label. */
46     char *documents;            /* Documents, as a string. */
47     struct vector **vector;     /* Vectors of variables. */
48     size_t vector_cnt;          /* Number of vectors. */
49   };
50
51 /* Creates and returns a new dictionary. */
52 struct dictionary *
53 dict_create (void) 
54 {
55   struct dictionary *d = xmalloc (sizeof *d);
56   
57   d->var = NULL;
58   d->var_cnt = d->var_cap = 0;
59   d->name_tab = hsh_create (8, compare_var_names, hash_var_name, NULL, NULL);
60   d->next_value_idx = 0;
61   d->split = NULL;
62   d->split_cnt = 0;
63   d->weight = NULL;
64   d->filter = NULL;
65   d->case_limit = 0;
66   d->label = NULL;
67   d->documents = NULL;
68   d->vector = NULL;
69   d->vector_cnt = 0;
70
71   return d;
72 }
73
74 /* Creates and returns a (deep) copy of an existing
75    dictionary. */
76 struct dictionary *
77 dict_clone (const struct dictionary *s) 
78 {
79   struct dictionary *d;
80   size_t i;
81   
82   assert (s != NULL);
83   
84   d = dict_create ();
85   for (i = 0; i < s->var_cnt; i++)
86     dict_clone_var (d, s->var[i], s->var[i]->name);
87   d->next_value_idx = s->next_value_idx;
88
89   d->split_cnt = s->split_cnt;
90   if (d->split_cnt > 0) 
91     {
92       d->split = xmalloc (d->split_cnt * sizeof *d->split);
93       for (i = 0; i < d->split_cnt; i++) 
94         d->split[i] = dict_lookup_var_assert (d, s->split[i]->name);
95     }
96
97   if (s->weight != NULL) 
98     d->weight = dict_lookup_var_assert (d, s->weight->name);
99
100   if (s->filter != NULL) 
101     d->filter = dict_lookup_var_assert (d, s->filter->name);
102
103   d->case_limit = s->case_limit;
104   dict_set_label (d, dict_get_label (s));
105   dict_set_documents (d, dict_get_documents (s));
106
107   for (i = 0; i < s->vector_cnt; i++) 
108     dict_create_vector (d, s->vector[i]->name,
109                         s->vector[i]->var, s->vector[i]->cnt);
110
111   return d;
112 }
113
114 /* Clears the contents from a dictionary without destroying the
115    dictionary itself. */
116 void
117 dict_clear (struct dictionary *d) 
118 {
119   /* FIXME?  Should we really clear case_limit, label, documents?
120      Others are necessarily cleared by deleting all the variables.*/
121   int i;
122
123   assert (d != NULL);
124
125   for (i = 0; i < d->var_cnt; i++) 
126     {
127       struct variable *v = d->var[i];
128       var_clear_aux (v);
129       val_labs_destroy (v->val_labs);
130       free (v->label);
131       free (v); 
132     }
133   free (d->var);
134   d->var = NULL;
135   d->var_cnt = d->var_cap = 0;
136   hsh_clear (d->name_tab);
137   d->next_value_idx = 0;
138   free (d->split);
139   d->split = NULL;
140   d->split_cnt = 0;
141   d->weight = NULL;
142   d->filter = NULL;
143   d->case_limit = 0;
144   free (d->label);
145   d->label = NULL;
146   free (d->documents);
147   d->documents = NULL;
148   dict_clear_vectors (d);
149 }
150
151 /* Destroys the aux data for every variable in D, by calling
152    var_clear_aux() for each variable. */
153 void
154 dict_clear_aux (struct dictionary *d) 
155 {
156   int i;
157   
158   assert (d != NULL);
159   
160   for (i = 0; i < d->var_cnt; i++)
161     var_clear_aux (d->var[i]);
162 }
163
164 /* Clears a dictionary and destroys it. */
165 void
166 dict_destroy (struct dictionary *d)
167 {
168   if (d != NULL) 
169     {
170       dict_clear (d);
171       hsh_destroy (d->name_tab);
172       free (d);
173     }
174 }
175
176 /* Returns the number of variables in D. */
177 size_t
178 dict_get_var_cnt (const struct dictionary *d) 
179 {
180   assert (d != NULL);
181
182   return d->var_cnt;
183 }
184
185 /* Returns the variable in D with index IDX, which must be
186    between 0 and the count returned by dict_get_var_cnt(),
187    exclusive. */
188 struct variable *
189 dict_get_var (const struct dictionary *d, size_t idx) 
190 {
191   assert (d != NULL);
192   assert (idx < d->var_cnt);
193
194   return d->var[idx];
195 }
196
197 /* Sets *VARS to an array of pointers to variables in D and *CNT
198    to the number of variables in *D.  By default all variables
199    are returned, but bits may be set in EXCLUDE_CLASSES to
200    exclude ordinary, system, and/or scratch variables. */
201 void
202 dict_get_vars (const struct dictionary *d, struct variable ***vars,
203                size_t *cnt, unsigned exclude_classes)
204 {
205   size_t count;
206   size_t i;
207   
208   assert (d != NULL);
209   assert (vars != NULL);
210   assert (cnt != NULL);
211   assert ((exclude_classes & ~((1u << DC_ORDINARY)
212                                | (1u << DC_SYSTEM)
213                                | (1u << DC_SCRATCH))) == 0);
214   
215   count = 0;
216   for (i = 0; i < d->var_cnt; i++)
217     if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
218       count++;
219
220   *vars = xmalloc (count * sizeof **vars);
221   *cnt = 0;
222   for (i = 0; i < d->var_cnt; i++)
223     if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
224       (*vars)[(*cnt)++] = d->var[i];
225   assert (*cnt == count);
226 }
227
228 /* Creates and returns a new variable in D with the given NAME
229    and WIDTH.  Returns a null pointer if the given NAME would
230    duplicate that of an existing variable in the dictionary. */
231 struct variable *
232 dict_create_var (struct dictionary *d, const char *name, int width) 
233 {
234   struct variable *v;
235
236   assert (d != NULL);
237   assert (name != NULL);
238   assert (strlen (name) >= 1 && strlen (name) <= 8);
239   assert (width >= 0 && width < 256);
240
241   /* Make sure there's not already a variable by that name. */
242   if (dict_lookup_var (d, name) != NULL)
243     return NULL;
244
245   /* Allocate and initialize variable. */
246   v = xmalloc (sizeof *v);
247   strncpy (v->name, name, sizeof v->name);
248   v->name[8] = '\0';
249   v->index = d->var_cnt;
250   v->type = width == 0 ? NUMERIC : ALPHA;
251   v->width = width;
252   v->fv = d->next_value_idx;
253   v->nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
254   v->init = 1;
255   v->reinit = dict_class_from_id (name) != DC_SCRATCH;
256   v->miss_type = MISSING_NONE;
257   if (v->type == NUMERIC)
258     {
259       v->print.type = FMT_F;
260       v->print.w = 8;
261       v->print.d = 2;
262     }
263   else
264     {
265       v->print.type = FMT_A;
266       v->print.w = v->width;
267       v->print.d = 0;
268     }
269   v->write = v->print;
270   v->val_labs = val_labs_create (v->width);
271   v->label = NULL;
272   v->aux = NULL;
273   v->aux_dtor = NULL;
274
275   /* Update dictionary. */
276   if (d->var_cnt >= d->var_cap) 
277     {
278       d->var_cap = 8 + 2 * d->var_cap; 
279       d->var = xrealloc (d->var, d->var_cap * sizeof *d->var);
280     }
281   d->var[v->index] = v;
282   d->var_cnt++;
283   hsh_force_insert (d->name_tab, v);
284   d->next_value_idx += v->nv;
285
286   return v;
287 }
288
289 /* Creates and returns a new variable in D with the given NAME
290    and WIDTH.  Assert-fails if the given NAME would duplicate
291    that of an existing variable in the dictionary. */
292 struct variable *
293 dict_create_var_assert (struct dictionary *d, const char *name, int width) 
294 {
295   struct variable *v = dict_create_var (d, name, width);
296   assert (v != NULL);
297   return v;
298 }
299
300 /* Creates a new variable in D named NAME, as a copy of existing
301    variable OV, which need not be in D or in any dictionary. */
302 struct variable *
303 dict_clone_var (struct dictionary *d, const struct variable *ov,
304                 const char *name)
305 {
306   struct variable *nv;
307
308   assert (d != NULL);
309   assert (ov != NULL);
310   assert (name != NULL);
311   assert (strlen (name) >= 1 && strlen (name) <= 8);
312
313   nv = dict_create_var (d, name, ov->width);
314   if (nv == NULL)
315     return NULL;
316
317   nv->init = 1;
318   nv->reinit = ov->reinit;
319   nv->miss_type = ov->miss_type;
320   memcpy (nv->missing, ov->missing, sizeof nv->missing);
321   nv->print = ov->print;
322   nv->write = ov->write;
323   val_labs_destroy (nv->val_labs);
324   nv->val_labs = val_labs_copy (ov->val_labs);
325   if (ov->label != NULL)
326     nv->label = xstrdup (ov->label);
327
328   return nv;
329 }
330
331 /* Changes the name of V in D to name NEW_NAME.  Assert-fails if
332    a variable named NEW_NAME is already in D, except that
333    NEW_NAME may be the same as V's existing name. */
334 void 
335 dict_rename_var (struct dictionary *d, struct variable *v,
336                  const char *new_name) 
337 {
338   assert (d != NULL);
339   assert (v != NULL);
340   assert (new_name != NULL);
341   assert (strlen (new_name) >= 1 && strlen (new_name) <= 8);
342   assert (dict_contains_var (d, v));
343
344   if (!strcmp (v->name, new_name))
345     return;
346
347   assert (dict_lookup_var (d, new_name) == NULL);
348
349   hsh_force_delete (d->name_tab, v);
350   strncpy (v->name, new_name, sizeof v->name);
351   v->name[8] = '\0';
352   hsh_force_insert (d->name_tab, v);
353 }
354
355 /* Returns the variable named NAME in D, or a null pointer if no
356    variable has that name. */
357 struct variable *
358 dict_lookup_var (const struct dictionary *d, const char *name)
359 {
360   struct variable v;
361   
362   assert (d != NULL);
363   assert (name != NULL);
364   assert (strlen (name) >= 1 && strlen (name) <= 8);
365
366   strncpy (v.name, name, sizeof v.name);
367   v.name[8] = '\0';
368
369   return hsh_find (d->name_tab, &v);
370 }
371
372 /* Returns the variable named NAME in D.  Assert-fails if no
373    variable has that name. */
374 struct variable *
375 dict_lookup_var_assert (const struct dictionary *d, const char *name)
376 {
377   struct variable *v = dict_lookup_var (d, name);
378   assert (v != NULL);
379   return v;
380 }
381
382 /* Returns nonzero if variable V is in dictionary D. */
383 int
384 dict_contains_var (const struct dictionary *d, const struct variable *v)
385 {
386   assert (d != NULL);
387   assert (v != NULL);
388
389   return v->index >= 0 && v->index < d->var_cnt && d->var[v->index] == v;
390 }
391
392 /* Compares two double pointers to variables, which should point
393    to elements of a struct dictionary's `var' member array. */
394 static int
395 compare_var_ptrs (const void *a_, const void *b_, void *aux UNUSED) 
396 {
397   struct variable *const *a = a_;
398   struct variable *const *b = b_;
399
400   return *a < *b ? -1 : *a > *b;
401 }
402
403 /* Deletes variable V from dictionary D and frees V.
404
405    This is a very bad idea if there might be any pointers to V
406    from outside D.  In general, no variable in default_dict
407    should be deleted when any transformations are active, because
408    those transformations might reference the deleted variable.
409    The safest time to delete a variable is just after a procedure
410    has been executed, as done by MODIFY VARS.
411
412    Pointers to V within D are not a problem, because
413    dict_delete_var() knows to remove V from split variables,
414    weights, filters, etc. */
415 void
416 dict_delete_var (struct dictionary *d, struct variable *v) 
417 {
418   size_t i;
419
420   assert (d != NULL);
421   assert (v != NULL);
422   assert (dict_contains_var (d, v));
423   assert (d->var[v->index] == v);
424
425   /* Delete aux data. */
426   var_clear_aux (v);
427
428   /* Remove V from splits, weight, filter variables. */
429   d->split_cnt = remove_equal (d->split, d->split_cnt, sizeof *d->split,
430                                &v, compare_var_ptrs, NULL);
431   if (d->weight == v)
432     d->weight = NULL;
433   if (d->filter == v)
434     d->filter = NULL;
435   dict_clear_vectors (d);
436
437   /* Remove V from var array. */
438   d->var_cnt--;
439   memmove (d->var + v->index, d->var + v->index + 1,
440            (d->var_cnt - v->index) * sizeof *d->var);
441
442   /* Update index. */
443   for (i = v->index; i < d->var_cnt; i++)
444     d->var[i]->index = i;
445
446   /* Update name hash. */
447   hsh_force_delete (d->name_tab, v);
448
449   /* Free memory. */
450   val_labs_destroy (v->val_labs);
451   free (v->label);
452   free (v);
453 }
454
455 /* Deletes the COUNT variables listed in VARS from D.  This is
456    unsafe; see the comment on dict_delete_var() for details. */
457 void 
458 dict_delete_vars (struct dictionary *d,
459                   struct variable *const *vars, size_t count) 
460 {
461   /* FIXME: this can be done in O(count) time, but this algorithm
462      is O(count**2). */
463   assert (d != NULL);
464   assert (count == 0 || vars != NULL);
465
466   while (count-- > 0)
467     dict_delete_var (d, *vars++);
468 }
469
470 /* Reorders the variables in D, placing the COUNT variables
471    listed in ORDER in that order at the beginning of D.  The
472    other variables in D, if any, retain their relative
473    positions. */
474 void 
475 dict_reorder_vars (struct dictionary *d,
476                    struct variable *const *order, size_t count) 
477 {
478   struct variable **new_var;
479   size_t i;
480   
481   assert (d != NULL);
482   assert (count == 0 || order != NULL);
483   assert (count <= d->var_cnt);
484
485   new_var = xmalloc (d->var_cnt * sizeof *new_var);
486   memcpy (new_var, order, count * sizeof *new_var);
487   for (i = 0; i < count; i++) 
488     {
489       assert (d->var[order[i]->index] != NULL);
490       d->var[order[i]->index] = NULL;
491       order[i]->index = i;
492     }
493   for (i = 0; i < d->var_cnt; i++)
494     if (d->var[i] != NULL)
495       {
496         assert (count < d->var_cnt);
497         new_var[count] = d->var[i];
498         new_var[count]->index = count;
499         count++;
500       }
501   free (d->var);
502   d->var = new_var;
503 }
504
505 /* Renames COUNT variables specified in VARS to the names given
506    in NEW_NAMES within dictionary D.  If the renaming would
507    result in a duplicate variable name, returns zero and stores a
508    name that would be duplicated into *ERR_NAME (if ERR_NAME is
509    non-null).  Otherwise, the renaming is successful, and nonzero
510    is returned. */
511 int
512 dict_rename_vars (struct dictionary *d,
513                   struct variable **vars, char **new_names,
514                   size_t count, char **err_name) 
515 {
516   char **old_names;
517   size_t i;
518   int success = 1;
519
520   assert (d != NULL);
521   assert (count == 0 || vars != NULL);
522   assert (count == 0 || new_names != NULL);
523
524   old_names = xmalloc (count * sizeof *old_names);
525   for (i = 0; i < count; i++) 
526     {
527       assert (d->var[vars[i]->index] == vars[i]);
528       hsh_force_delete (d->name_tab, vars[i]);
529       old_names[i] = xstrdup (vars[i]->name);
530     }
531   
532   for (i = 0; i < count; i++)
533     {
534       assert (new_names[i] != NULL);
535       assert (*new_names[i] != '\0');
536       assert (strlen (new_names[i]) < 9);
537       strcpy (vars[i]->name, new_names[i]);
538       if (hsh_insert (d->name_tab, vars[i]) != NULL) 
539         {
540           size_t fail_idx = i;
541           if (err_name != NULL) 
542             *err_name = new_names[i];
543
544           for (i = 0; i < fail_idx; i++)
545             hsh_force_delete (d->name_tab, vars[i]);
546           
547           for (i = 0; i < count; i++)
548             {
549               strcpy (vars[i]->name, old_names[i]);
550               hsh_force_insert (d->name_tab, vars[i]);
551             }
552
553           success = 0;
554           break;
555         }
556     }
557
558   for (i = 0; i < count; i++)
559     free (old_names[i]);
560   free (old_names);
561
562   return success;
563 }
564
565 /* Returns the weighting variable in dictionary D, or a null
566    pointer if the dictionary is unweighted. */
567 struct variable *
568 dict_get_weight (const struct dictionary *d) 
569 {
570   assert (d != NULL);
571   assert (d->weight == NULL || dict_contains_var (d, d->weight));
572   
573   return d->weight;
574 }
575
576 /* Returns the value of D's weighting variable in case C, except that a
577    negative weight is returned as 0.  Returns 1 if the dictionary is
578    unweighted. Will warn about missing, negative, or zero values if
579    warn_on_invalid is nonzero. The function will set warn_on_invalid to zero
580    if an invalid weight is found. */
581 double
582 dict_get_case_weight (const struct dictionary *d, const struct ccase *c, 
583                       int *warn_on_invalid)
584 {
585   assert (d != NULL);
586   assert (c != NULL);
587
588   if (d->weight == NULL)
589     return 1.0;
590   else 
591     {
592       double w = case_num (c, d->weight->fv);
593       if ( w < 0.0 || w == SYSMIS || is_num_user_missing(w, d->weight) )
594         w = 0.0;
595       if ( w == 0.0 && *warn_on_invalid ) {
596           *warn_on_invalid = 0;
597           msg (SW, _("At least one case in the data file had a weight value "
598                      "that was user-missing, system-missing, zero, or "
599                      "negative.  These case(s) were ignored."));
600       }
601       return w;
602     }
603 }
604
605 /* Sets the weighting variable of D to V, or turning off
606    weighting if V is a null pointer. */
607 void
608 dict_set_weight (struct dictionary *d, struct variable *v) 
609 {
610   assert (d != NULL);
611   assert (v == NULL || dict_contains_var (d, v));
612   assert (v == NULL || v->type == NUMERIC);
613
614   d->weight = v;
615 }
616
617 /* Returns the filter variable in dictionary D (see cmd_filter())
618    or a null pointer if the dictionary is unfiltered. */
619 struct variable *
620 dict_get_filter (const struct dictionary *d) 
621 {
622   assert (d != NULL);
623   assert (d->filter == NULL || dict_contains_var (d, d->filter));
624   
625   return d->filter;
626 }
627
628 /* Sets V as the filter variable for dictionary D.  Passing a
629    null pointer for V turn off filtering. */
630 void
631 dict_set_filter (struct dictionary *d, struct variable *v)
632 {
633   assert (d != NULL);
634   assert (v == NULL || dict_contains_var (d, v));
635
636   d->filter = v;
637 }
638
639 /* Returns the case limit for dictionary D, or zero if the number
640    of cases is unlimited (see cmd_n()). */
641 int
642 dict_get_case_limit (const struct dictionary *d) 
643 {
644   assert (d != NULL);
645
646   return d->case_limit;
647 }
648
649 /* Sets CASE_LIMIT as the case limit for dictionary D.  Zero for
650    CASE_LIMIT indicates no limit. */
651 void
652 dict_set_case_limit (struct dictionary *d, int case_limit) 
653 {
654   assert (d != NULL);
655   assert (case_limit >= 0);
656
657   d->case_limit = case_limit;
658 }
659
660 /* Returns the index of the next value to be added to D.  This
661    value is the number of `union value's that need to be
662    allocated to store a case for dictionary D. */
663 int
664 dict_get_next_value_idx (const struct dictionary *d) 
665 {
666   assert (d != NULL);
667
668   return d->next_value_idx;
669 }
670
671 /* Returns the number of bytes needed to store a case for
672    dictionary D. */
673 size_t
674 dict_get_case_size (const struct dictionary *d) 
675 {
676   assert (d != NULL);
677
678   return sizeof (union value) * dict_get_next_value_idx (d);
679 }
680
681 /* Deletes scratch variables in dictionary D and reassigns values
682    so that fragmentation is eliminated. */
683 void
684 dict_compact_values (struct dictionary *d) 
685 {
686   size_t i;
687
688   d->next_value_idx = 0;
689   for (i = 0; i < d->var_cnt; )
690     {
691       struct variable *v = d->var[i];
692
693       if (dict_class_from_id (v->name) != DC_SCRATCH) 
694         {
695           v->fv = d->next_value_idx;
696           d->next_value_idx += v->nv;
697           i++;
698         }
699       else
700         dict_delete_var (default_dict, v);
701     }
702 }
703
704 /* Copies values from SRC, which represents a case arranged
705    according to dictionary D, to DST, which represents a case
706    arranged according to the dictionary that will be produced by
707    dict_compact_values(D). */
708 void
709 dict_compact_case (const struct dictionary *d,
710                    struct ccase *dst, const struct ccase *src)
711 {
712   size_t i;
713   size_t value_idx;
714
715   value_idx = 0;
716   for (i = 0; i < d->var_cnt; i++) 
717     {
718       struct variable *v = d->var[i];
719
720       if (dict_class_from_id (v->name) != DC_SCRATCH)
721         {
722           case_copy (dst, value_idx, src, v->fv, v->nv);
723           value_idx += v->nv;
724         }
725     }
726 }
727
728 /* Returns the number of values that would be used by a case if
729    dict_compact_values() were called. */
730 size_t
731 dict_get_compacted_value_cnt (const struct dictionary *d) 
732 {
733   size_t i;
734   size_t cnt;
735
736   cnt = 0;
737   for (i = 0; i < d->var_cnt; i++)
738     if (dict_class_from_id (d->var[i]->name) != DC_SCRATCH) 
739       cnt += d->var[i]->nv;
740   return cnt;
741 }
742
743 /* Creates and returns an array mapping from a dictionary index
744    to the `fv' that the corresponding variable will have after
745    calling dict_compact_values().  Scratch variables receive -1
746    for `fv' because dict_compact_values() will delete them. */
747 int *
748 dict_get_compacted_idx_to_fv (const struct dictionary *d) 
749 {
750   size_t i;
751   size_t next_value_idx;
752   int *idx_to_fv;
753   
754   idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv);
755   next_value_idx = 0;
756   for (i = 0; i < d->var_cnt; i++)
757     {
758       struct variable *v = d->var[i];
759
760       if (dict_class_from_id (v->name) != DC_SCRATCH) 
761         {
762           idx_to_fv[i] = next_value_idx;
763           next_value_idx += v->nv;
764         }
765       else 
766         idx_to_fv[i] = -1;
767     }
768   return idx_to_fv;
769 }
770
771 /* Returns the SPLIT FILE vars (see cmd_split_file()).  Call
772    dict_get_split_cnt() to determine how many SPLIT FILE vars
773    there are.  Returns a null pointer if and only if there are no
774    SPLIT FILE vars. */
775 struct variable *const *
776 dict_get_split_vars (const struct dictionary *d) 
777 {
778   assert (d != NULL);
779   
780   return d->split;
781 }
782
783 /* Returns the number of SPLIT FILE vars. */
784 size_t
785 dict_get_split_cnt (const struct dictionary *d) 
786 {
787   assert (d != NULL);
788
789   return d->split_cnt;
790 }
791
792 /* Sets CNT split vars SPLIT in dictionary D. */
793 void
794 dict_set_split_vars (struct dictionary *d,
795                      struct variable *const *split, size_t cnt)
796 {
797   assert (d != NULL);
798   assert (cnt == 0 || split != NULL);
799
800   d->split_cnt = cnt;
801   d->split = xrealloc (d->split, cnt * sizeof *d->split);
802   memcpy (d->split, split, cnt * sizeof *d->split);
803 }
804
805 /* Returns the file label for D, or a null pointer if D is
806    unlabeled (see cmd_file_label()). */
807 const char *
808 dict_get_label (const struct dictionary *d) 
809 {
810   assert (d != NULL);
811
812   return d->label;
813 }
814
815 /* Sets D's file label to LABEL, truncating it to a maximum of 60
816    characters. */
817 void
818 dict_set_label (struct dictionary *d, const char *label) 
819 {
820   assert (d != NULL);
821
822   free (d->label);
823   if (label == NULL)
824     d->label = NULL;
825   else if (strlen (label) < 60)
826     d->label = xstrdup (label);
827   else 
828     {
829       d->label = xmalloc (61);
830       memcpy (d->label, label, 60);
831       d->label[60] = '\0';
832     }
833 }
834
835 /* Returns the documents for D, or a null pointer if D has no
836    documents (see cmd_document()).. */
837 const char *
838 dict_get_documents (const struct dictionary *d) 
839 {
840   assert (d != NULL);
841
842   return d->documents;
843 }
844
845 /* Sets the documents for D to DOCUMENTS, or removes D's
846    documents if DOCUMENT is a null pointer. */
847 void
848 dict_set_documents (struct dictionary *d, const char *documents)
849 {
850   assert (d != NULL);
851
852   free (d->documents);
853   if (documents == NULL)
854     d->documents = NULL;
855   else
856     d->documents = xstrdup (documents);
857 }
858
859 /* Creates in D a vector named NAME that contains CNT variables
860    VAR (see cmd_vector()).  Returns nonzero if successful, or
861    zero if a vector named NAME already exists in D. */
862 int
863 dict_create_vector (struct dictionary *d,
864                     const char *name,
865                     struct variable **var, size_t cnt) 
866 {
867   struct vector *vector;
868
869   assert (d != NULL);
870   assert (name != NULL);
871   assert (strlen (name) > 0 && strlen (name) < 9);
872   assert (var != NULL);
873   assert (cnt > 0);
874   
875   if (dict_lookup_vector (d, name) != NULL)
876     return 0;
877
878   d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
879   vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
880   vector->idx = d->vector_cnt++;
881   strncpy (vector->name, name, 8);
882   vector->name[8] = '\0';
883   vector->var = xmalloc (cnt * sizeof *var);
884   memcpy (vector->var, var, cnt * sizeof *var);
885   vector->cnt = cnt;
886   
887   return 1;
888 }
889
890 /* Returns the vector in D with index IDX, which must be less
891    than dict_get_vector_cnt (D). */
892 const struct vector *
893 dict_get_vector (const struct dictionary *d, size_t idx) 
894 {
895   assert (d != NULL);
896   assert (idx < d->vector_cnt);
897
898   return d->vector[idx];
899 }
900
901 /* Returns the number of vectors in D. */
902 size_t
903 dict_get_vector_cnt (const struct dictionary *d) 
904 {
905   assert (d != NULL);
906
907   return d->vector_cnt;
908 }
909
910 /* Looks up and returns the vector within D with the given
911    NAME. */
912 const struct vector *
913 dict_lookup_vector (const struct dictionary *d, const char *name) 
914 {
915   size_t i;
916
917   assert (d != NULL);
918   assert (name != NULL);
919
920   for (i = 0; i < d->vector_cnt; i++)
921     if (!strcmp (d->vector[i]->name, name))
922       return d->vector[i];
923   return NULL;
924 }
925
926 /* Deletes all vectors from D. */
927 void
928 dict_clear_vectors (struct dictionary *d) 
929 {
930   size_t i;
931   
932   assert (d != NULL);
933
934   for (i = 0; i < d->vector_cnt; i++) 
935     {
936       free (d->vector[i]->var);
937       free (d->vector[i]);
938     }
939   free (d->vector);
940   d->vector = NULL;
941   d->vector_cnt = 0;
942 }