99ea5b8bcbec501a1cd3c57fa3252351b7d0fb17
[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   remove_element (d->var, d->var_cnt, sizeof *d->var, v->index);
439   d->var_cnt--;
440
441   /* Update index. */
442   for (i = v->index; i < d->var_cnt; i++)
443     d->var[i]->index = i;
444
445   /* Update name hash. */
446   hsh_force_delete (d->name_tab, v);
447
448   /* Free memory. */
449   val_labs_destroy (v->val_labs);
450   free (v->label);
451   free (v);
452 }
453
454 /* Deletes the COUNT variables listed in VARS from D.  This is
455    unsafe; see the comment on dict_delete_var() for details. */
456 void 
457 dict_delete_vars (struct dictionary *d,
458                   struct variable *const *vars, size_t count) 
459 {
460   /* FIXME: this can be done in O(count) time, but this algorithm
461      is O(count**2). */
462   assert (d != NULL);
463   assert (count == 0 || vars != NULL);
464
465   while (count-- > 0)
466     dict_delete_var (d, *vars++);
467 }
468
469 /* Reorders the variables in D, placing the COUNT variables
470    listed in ORDER in that order at the beginning of D.  The
471    other variables in D, if any, retain their relative
472    positions. */
473 void 
474 dict_reorder_vars (struct dictionary *d,
475                    struct variable *const *order, size_t count) 
476 {
477   struct variable **new_var;
478   size_t i;
479   
480   assert (d != NULL);
481   assert (count == 0 || order != NULL);
482   assert (count <= d->var_cnt);
483
484   new_var = xmalloc (d->var_cnt * sizeof *new_var);
485   memcpy (new_var, order, count * sizeof *new_var);
486   for (i = 0; i < count; i++) 
487     {
488       assert (d->var[order[i]->index] != NULL);
489       d->var[order[i]->index] = NULL;
490       order[i]->index = i;
491     }
492   for (i = 0; i < d->var_cnt; i++)
493     if (d->var[i] != NULL)
494       {
495         assert (count < d->var_cnt);
496         new_var[count] = d->var[i];
497         new_var[count]->index = count;
498         count++;
499       }
500   free (d->var);
501   d->var = new_var;
502 }
503
504 /* Renames COUNT variables specified in VARS to the names given
505    in NEW_NAMES within dictionary D.  If the renaming would
506    result in a duplicate variable name, returns zero and stores a
507    name that would be duplicated into *ERR_NAME (if ERR_NAME is
508    non-null).  Otherwise, the renaming is successful, and nonzero
509    is returned. */
510 int
511 dict_rename_vars (struct dictionary *d,
512                   struct variable **vars, char **new_names,
513                   size_t count, char **err_name) 
514 {
515   char **old_names;
516   size_t i;
517   int success = 1;
518
519   assert (d != NULL);
520   assert (count == 0 || vars != NULL);
521   assert (count == 0 || new_names != NULL);
522
523   old_names = xmalloc (count * sizeof *old_names);
524   for (i = 0; i < count; i++) 
525     {
526       assert (d->var[vars[i]->index] == vars[i]);
527       hsh_force_delete (d->name_tab, vars[i]);
528       old_names[i] = xstrdup (vars[i]->name);
529     }
530   
531   for (i = 0; i < count; i++)
532     {
533       assert (new_names[i] != NULL);
534       assert (*new_names[i] != '\0');
535       assert (strlen (new_names[i]) < 9);
536       strcpy (vars[i]->name, new_names[i]);
537       if (hsh_insert (d->name_tab, vars[i]) != NULL) 
538         {
539           size_t fail_idx = i;
540           if (err_name != NULL) 
541             *err_name = new_names[i];
542
543           for (i = 0; i < fail_idx; i++)
544             hsh_force_delete (d->name_tab, vars[i]);
545           
546           for (i = 0; i < count; i++)
547             {
548               strcpy (vars[i]->name, old_names[i]);
549               hsh_force_insert (d->name_tab, vars[i]);
550             }
551
552           success = 0;
553           break;
554         }
555     }
556
557   for (i = 0; i < count; i++)
558     free (old_names[i]);
559   free (old_names);
560
561   return success;
562 }
563
564 /* Returns the weighting variable in dictionary D, or a null
565    pointer if the dictionary is unweighted. */
566 struct variable *
567 dict_get_weight (const struct dictionary *d) 
568 {
569   assert (d != NULL);
570   assert (d->weight == NULL || dict_contains_var (d, d->weight));
571   
572   return d->weight;
573 }
574
575 /* Returns the value of D's weighting variable in case C, except that a
576    negative weight is returned as 0.  Returns 1 if the dictionary is
577    unweighted. Will warn about missing, negative, or zero values if
578    warn_on_invalid is nonzero. The function will set warn_on_invalid to zero
579    if an invalid weight is found. */
580 double
581 dict_get_case_weight (const struct dictionary *d, const struct ccase *c, 
582                       int *warn_on_invalid)
583 {
584   assert (d != NULL);
585   assert (c != NULL);
586
587   if (d->weight == NULL)
588     return 1.0;
589   else 
590     {
591       double w = case_num (c, d->weight->fv);
592       if ( w < 0.0 || w == SYSMIS || is_num_user_missing(w, d->weight) )
593         w = 0.0;
594       if ( w == 0.0 && *warn_on_invalid ) {
595           *warn_on_invalid = 0;
596           msg (SW, _("At least one case in the data file had a weight value "
597                      "that was user-missing, system-missing, zero, or "
598                      "negative.  These case(s) were ignored."));
599       }
600       return w;
601     }
602 }
603
604 /* Sets the weighting variable of D to V, or turning off
605    weighting if V is a null pointer. */
606 void
607 dict_set_weight (struct dictionary *d, struct variable *v) 
608 {
609   assert (d != NULL);
610   assert (v == NULL || dict_contains_var (d, v));
611   assert (v == NULL || v->type == NUMERIC);
612
613   d->weight = v;
614 }
615
616 /* Returns the filter variable in dictionary D (see cmd_filter())
617    or a null pointer if the dictionary is unfiltered. */
618 struct variable *
619 dict_get_filter (const struct dictionary *d) 
620 {
621   assert (d != NULL);
622   assert (d->filter == NULL || dict_contains_var (d, d->filter));
623   
624   return d->filter;
625 }
626
627 /* Sets V as the filter variable for dictionary D.  Passing a
628    null pointer for V turn off filtering. */
629 void
630 dict_set_filter (struct dictionary *d, struct variable *v)
631 {
632   assert (d != NULL);
633   assert (v == NULL || dict_contains_var (d, v));
634
635   d->filter = v;
636 }
637
638 /* Returns the case limit for dictionary D, or zero if the number
639    of cases is unlimited (see cmd_n()). */
640 int
641 dict_get_case_limit (const struct dictionary *d) 
642 {
643   assert (d != NULL);
644
645   return d->case_limit;
646 }
647
648 /* Sets CASE_LIMIT as the case limit for dictionary D.  Zero for
649    CASE_LIMIT indicates no limit. */
650 void
651 dict_set_case_limit (struct dictionary *d, int case_limit) 
652 {
653   assert (d != NULL);
654   assert (case_limit >= 0);
655
656   d->case_limit = case_limit;
657 }
658
659 /* Returns the index of the next value to be added to D.  This
660    value is the number of `union value's that need to be
661    allocated to store a case for dictionary D. */
662 int
663 dict_get_next_value_idx (const struct dictionary *d) 
664 {
665   assert (d != NULL);
666
667   return d->next_value_idx;
668 }
669
670 /* Returns the number of bytes needed to store a case for
671    dictionary D. */
672 size_t
673 dict_get_case_size (const struct dictionary *d) 
674 {
675   assert (d != NULL);
676
677   return sizeof (union value) * dict_get_next_value_idx (d);
678 }
679
680 /* Deletes scratch variables in dictionary D and reassigns values
681    so that fragmentation is eliminated. */
682 void
683 dict_compact_values (struct dictionary *d) 
684 {
685   size_t i;
686
687   d->next_value_idx = 0;
688   for (i = 0; i < d->var_cnt; )
689     {
690       struct variable *v = d->var[i];
691
692       if (dict_class_from_id (v->name) != DC_SCRATCH) 
693         {
694           v->fv = d->next_value_idx;
695           d->next_value_idx += v->nv;
696           i++;
697         }
698       else
699         dict_delete_var (default_dict, v);
700     }
701 }
702
703 /* Copies values from SRC, which represents a case arranged
704    according to dictionary D, to DST, which represents a case
705    arranged according to the dictionary that will be produced by
706    dict_compact_values(D). */
707 void
708 dict_compact_case (const struct dictionary *d,
709                    struct ccase *dst, const struct ccase *src)
710 {
711   size_t i;
712   size_t value_idx;
713
714   value_idx = 0;
715   for (i = 0; i < d->var_cnt; i++) 
716     {
717       struct variable *v = d->var[i];
718
719       if (dict_class_from_id (v->name) != DC_SCRATCH)
720         {
721           case_copy (dst, value_idx, src, v->fv, v->nv);
722           value_idx += v->nv;
723         }
724     }
725 }
726
727 /* Returns the number of values that would be used by a case if
728    dict_compact_values() were called. */
729 size_t
730 dict_get_compacted_value_cnt (const struct dictionary *d) 
731 {
732   size_t i;
733   size_t cnt;
734
735   cnt = 0;
736   for (i = 0; i < d->var_cnt; i++)
737     if (dict_class_from_id (d->var[i]->name) != DC_SCRATCH) 
738       cnt += d->var[i]->nv;
739   return cnt;
740 }
741
742 /* Creates and returns an array mapping from a dictionary index
743    to the `fv' that the corresponding variable will have after
744    calling dict_compact_values().  Scratch variables receive -1
745    for `fv' because dict_compact_values() will delete them. */
746 int *
747 dict_get_compacted_idx_to_fv (const struct dictionary *d) 
748 {
749   size_t i;
750   size_t next_value_idx;
751   int *idx_to_fv;
752   
753   idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv);
754   next_value_idx = 0;
755   for (i = 0; i < d->var_cnt; i++)
756     {
757       struct variable *v = d->var[i];
758
759       if (dict_class_from_id (v->name) != DC_SCRATCH) 
760         {
761           idx_to_fv[i] = next_value_idx;
762           next_value_idx += v->nv;
763         }
764       else 
765         idx_to_fv[i] = -1;
766     }
767   return idx_to_fv;
768 }
769
770 /* Returns the SPLIT FILE vars (see cmd_split_file()).  Call
771    dict_get_split_cnt() to determine how many SPLIT FILE vars
772    there are.  Returns a null pointer if and only if there are no
773    SPLIT FILE vars. */
774 struct variable *const *
775 dict_get_split_vars (const struct dictionary *d) 
776 {
777   assert (d != NULL);
778   
779   return d->split;
780 }
781
782 /* Returns the number of SPLIT FILE vars. */
783 size_t
784 dict_get_split_cnt (const struct dictionary *d) 
785 {
786   assert (d != NULL);
787
788   return d->split_cnt;
789 }
790
791 /* Sets CNT split vars SPLIT in dictionary D. */
792 void
793 dict_set_split_vars (struct dictionary *d,
794                      struct variable *const *split, size_t cnt)
795 {
796   assert (d != NULL);
797   assert (cnt == 0 || split != NULL);
798
799   d->split_cnt = cnt;
800   d->split = xrealloc (d->split, cnt * sizeof *d->split);
801   memcpy (d->split, split, cnt * sizeof *d->split);
802 }
803
804 /* Returns the file label for D, or a null pointer if D is
805    unlabeled (see cmd_file_label()). */
806 const char *
807 dict_get_label (const struct dictionary *d) 
808 {
809   assert (d != NULL);
810
811   return d->label;
812 }
813
814 /* Sets D's file label to LABEL, truncating it to a maximum of 60
815    characters. */
816 void
817 dict_set_label (struct dictionary *d, const char *label) 
818 {
819   assert (d != NULL);
820
821   free (d->label);
822   if (label == NULL)
823     d->label = NULL;
824   else if (strlen (label) < 60)
825     d->label = xstrdup (label);
826   else 
827     {
828       d->label = xmalloc (61);
829       memcpy (d->label, label, 60);
830       d->label[60] = '\0';
831     }
832 }
833
834 /* Returns the documents for D, or a null pointer if D has no
835    documents (see cmd_document()).. */
836 const char *
837 dict_get_documents (const struct dictionary *d) 
838 {
839   assert (d != NULL);
840
841   return d->documents;
842 }
843
844 /* Sets the documents for D to DOCUMENTS, or removes D's
845    documents if DOCUMENT is a null pointer. */
846 void
847 dict_set_documents (struct dictionary *d, const char *documents)
848 {
849   assert (d != NULL);
850
851   free (d->documents);
852   if (documents == NULL)
853     d->documents = NULL;
854   else
855     d->documents = xstrdup (documents);
856 }
857
858 /* Creates in D a vector named NAME that contains CNT variables
859    VAR (see cmd_vector()).  Returns nonzero if successful, or
860    zero if a vector named NAME already exists in D. */
861 int
862 dict_create_vector (struct dictionary *d,
863                     const char *name,
864                     struct variable **var, size_t cnt) 
865 {
866   struct vector *vector;
867
868   assert (d != NULL);
869   assert (name != NULL);
870   assert (strlen (name) > 0 && strlen (name) < 9);
871   assert (var != NULL);
872   assert (cnt > 0);
873   
874   if (dict_lookup_vector (d, name) != NULL)
875     return 0;
876
877   d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
878   vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
879   vector->idx = d->vector_cnt++;
880   strncpy (vector->name, name, 8);
881   vector->name[8] = '\0';
882   vector->var = xmalloc (cnt * sizeof *var);
883   memcpy (vector->var, var, cnt * sizeof *var);
884   vector->cnt = cnt;
885   
886   return 1;
887 }
888
889 /* Returns the vector in D with index IDX, which must be less
890    than dict_get_vector_cnt (D). */
891 const struct vector *
892 dict_get_vector (const struct dictionary *d, size_t idx) 
893 {
894   assert (d != NULL);
895   assert (idx < d->vector_cnt);
896
897   return d->vector[idx];
898 }
899
900 /* Returns the number of vectors in D. */
901 size_t
902 dict_get_vector_cnt (const struct dictionary *d) 
903 {
904   assert (d != NULL);
905
906   return d->vector_cnt;
907 }
908
909 /* Looks up and returns the vector within D with the given
910    NAME. */
911 const struct vector *
912 dict_lookup_vector (const struct dictionary *d, const char *name) 
913 {
914   size_t i;
915
916   assert (d != NULL);
917   assert (name != NULL);
918
919   for (i = 0; i < d->vector_cnt; i++)
920     if (!strcmp (d->vector[i]->name, name))
921       return d->vector[i];
922   return NULL;
923 }
924
925 /* Deletes all vectors from D. */
926 void
927 dict_clear_vectors (struct dictionary *d) 
928 {
929   size_t i;
930   
931   assert (d != NULL);
932
933   for (i = 0; i < d->vector_cnt; i++) 
934     {
935       free (d->vector[i]->var);
936       free (d->vector[i]);
937     }
938   free (d->vector);
939   d->vector = NULL;
940   d->vector_cnt = 0;
941 }