Fri Feb 11 00:08:36 2005 Ben Pfaff <blp@gnu.org>
[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_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 /* Returns the number of values that would be used by a case if
705    dict_compact_values() were called. */
706 size_t
707 dict_get_compacted_value_cnt (const struct dictionary *d) 
708 {
709   size_t i;
710   size_t cnt;
711
712   cnt = 0;
713   for (i = 0; i < d->var_cnt; i++)
714     if (dict_class_from_id (d->var[i]->name) != DC_SCRATCH) 
715       cnt += d->var[i]->nv;
716   return cnt;
717 }
718
719 /* Creates and returns an array mapping from a dictionary index
720    to the `fv' that the corresponding variable will have after
721    calling dict_compact_values().  Scratch variables receive -1
722    for `fv' because dict_compact_values() will delete them. */
723 int *
724 dict_get_compacted_idx_to_fv (const struct dictionary *d) 
725 {
726   size_t i;
727   size_t next_value_idx;
728   int *idx_to_fv;
729   
730   idx_to_fv = xmalloc (d->var_cnt * sizeof *idx_to_fv);
731   next_value_idx = 0;
732   for (i = 0; i < d->var_cnt; i++)
733     {
734       struct variable *v = d->var[i];
735
736       if (dict_class_from_id (v->name) != DC_SCRATCH) 
737         {
738           idx_to_fv[i] = next_value_idx;
739           next_value_idx += v->nv;
740         }
741       else 
742         idx_to_fv[i] = -1;
743     }
744   return idx_to_fv;
745 }
746
747 /* Returns the SPLIT FILE vars (see cmd_split_file()).  Call
748    dict_get_split_cnt() to determine how many SPLIT FILE vars
749    there are.  Returns a null pointer if and only if there are no
750    SPLIT FILE vars. */
751 struct variable *const *
752 dict_get_split_vars (const struct dictionary *d) 
753 {
754   assert (d != NULL);
755   
756   return d->split;
757 }
758
759 /* Returns the number of SPLIT FILE vars. */
760 size_t
761 dict_get_split_cnt (const struct dictionary *d) 
762 {
763   assert (d != NULL);
764
765   return d->split_cnt;
766 }
767
768 /* Sets CNT split vars SPLIT in dictionary D. */
769 void
770 dict_set_split_vars (struct dictionary *d,
771                      struct variable *const *split, size_t cnt)
772 {
773   assert (d != NULL);
774   assert (cnt == 0 || split != NULL);
775
776   d->split_cnt = cnt;
777   d->split = xrealloc (d->split, cnt * sizeof *d->split);
778   memcpy (d->split, split, cnt * sizeof *d->split);
779 }
780
781 /* Returns the file label for D, or a null pointer if D is
782    unlabeled (see cmd_file_label()). */
783 const char *
784 dict_get_label (const struct dictionary *d) 
785 {
786   assert (d != NULL);
787
788   return d->label;
789 }
790
791 /* Sets D's file label to LABEL, truncating it to a maximum of 60
792    characters. */
793 void
794 dict_set_label (struct dictionary *d, const char *label) 
795 {
796   assert (d != NULL);
797
798   free (d->label);
799   if (label == NULL)
800     d->label = NULL;
801   else if (strlen (label) < 60)
802     d->label = xstrdup (label);
803   else 
804     {
805       d->label = xmalloc (61);
806       memcpy (d->label, label, 60);
807       d->label[60] = '\0';
808     }
809 }
810
811 /* Returns the documents for D, or a null pointer if D has no
812    documents (see cmd_document()).. */
813 const char *
814 dict_get_documents (const struct dictionary *d) 
815 {
816   assert (d != NULL);
817
818   return d->documents;
819 }
820
821 /* Sets the documents for D to DOCUMENTS, or removes D's
822    documents if DOCUMENT is a null pointer. */
823 void
824 dict_set_documents (struct dictionary *d, const char *documents)
825 {
826   assert (d != NULL);
827
828   free (d->documents);
829   if (documents == NULL)
830     d->documents = NULL;
831   else
832     d->documents = xstrdup (documents);
833 }
834
835 /* Creates in D a vector named NAME that contains CNT variables
836    VAR (see cmd_vector()).  Returns nonzero if successful, or
837    zero if a vector named NAME already exists in D. */
838 int
839 dict_create_vector (struct dictionary *d,
840                     const char *name,
841                     struct variable **var, size_t cnt) 
842 {
843   struct vector *vector;
844
845   assert (d != NULL);
846   assert (name != NULL);
847   assert (strlen (name) > 0 && strlen (name) < 9);
848   assert (var != NULL);
849   assert (cnt > 0);
850   
851   if (dict_lookup_vector (d, name) != NULL)
852     return 0;
853
854   d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
855   vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
856   vector->idx = d->vector_cnt++;
857   strncpy (vector->name, name, 8);
858   vector->name[8] = '\0';
859   vector->var = xmalloc (cnt * sizeof *var);
860   memcpy (vector->var, var, cnt * sizeof *var);
861   vector->cnt = cnt;
862   
863   return 1;
864 }
865
866 /* Returns the vector in D with index IDX, which must be less
867    than dict_get_vector_cnt (D). */
868 const struct vector *
869 dict_get_vector (const struct dictionary *d, size_t idx) 
870 {
871   assert (d != NULL);
872   assert (idx < d->vector_cnt);
873
874   return d->vector[idx];
875 }
876
877 /* Returns the number of vectors in D. */
878 size_t
879 dict_get_vector_cnt (const struct dictionary *d) 
880 {
881   assert (d != NULL);
882
883   return d->vector_cnt;
884 }
885
886 /* Looks up and returns the vector within D with the given
887    NAME. */
888 const struct vector *
889 dict_lookup_vector (const struct dictionary *d, const char *name) 
890 {
891   size_t i;
892
893   assert (d != NULL);
894   assert (name != NULL);
895
896   for (i = 0; i < d->vector_cnt; i++)
897     if (!strcmp (d->vector[i]->name, name))
898       return d->vector[i];
899   return NULL;
900 }
901
902 /* Deletes all vectors from D. */
903 void
904 dict_clear_vectors (struct dictionary *d) 
905 {
906   size_t i;
907   
908   assert (d != NULL);
909
910   for (i = 0; i < d->vector_cnt; i++) 
911     {
912       free (d->vector[i]->var);
913       free (d->vector[i]);
914     }
915   free (d->vector);
916   d->vector = NULL;
917   d->vector_cnt = 0;
918 }