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