Sat Dec 27 16:16:49 2003 Ben Pfaff <blp@gnu.org>
[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 <assert.h>
22 #include <stdlib.h>
23 #include "algorithm.h"
24 #include "alloc.h"
25 #include "hash.h"
26 #include "misc.h"
27 #include "str.h"
28 #include "value-labels.h"
29 #include "var.h"
30
31 /* A dictionary. */
32 struct dictionary
33   {
34     struct variable **var;      /* Variables. */
35     size_t var_cnt, var_cap;    /* Number of variables, capacity. */
36     struct hsh_table *name_tab; /* Variable index by name. */
37     int value_cnt;              /* Number of `union value's per case. */
38     struct variable **split;    /* SPLIT FILE vars. */
39     size_t split_cnt;           /* SPLIT FILE count. */
40     struct variable *weight;    /* WEIGHT variable. */
41     struct variable *filter;    /* FILTER variable. */
42     int case_limit;             /* Current case limit (N command). */
43     char *label;                /* File label. */
44     char *documents;            /* Documents, as a string. */
45     struct vector **vector;     /* Vectors of variables. */
46     size_t vector_cnt;          /* Number of vectors. */
47   };
48
49 struct dictionary *
50 dict_create (void) 
51 {
52   struct dictionary *d = xmalloc (sizeof *d);
53   
54   d->var = NULL;
55   d->var_cnt = d->var_cap = 0;
56   d->name_tab = hsh_create (8, compare_variables, hash_variable, NULL, NULL);
57   d->value_cnt = 0;
58   d->split = NULL;
59   d->split_cnt = 0;
60   d->weight = NULL;
61   d->filter = NULL;
62   d->case_limit = 0;
63   d->label = NULL;
64   d->documents = NULL;
65   d->vector = NULL;
66   d->vector_cnt = 0;
67
68   return d;
69 }
70
71 struct dictionary *
72 dict_clone (const struct dictionary *s) 
73 {
74   struct dictionary *d;
75   size_t i;
76   
77   assert (s != NULL);
78   
79   d = dict_create ();
80   for (i = 0; i < s->var_cnt; i++)
81     dict_clone_var (d, s->var[i], s->var[i]->name);
82   d->value_cnt = s->value_cnt;
83
84   d->split_cnt = s->split_cnt;
85   if (d->split_cnt > 0) 
86     {
87       d->split = xmalloc (d->split_cnt * sizeof *d->split);
88       for (i = 0; i < d->split_cnt; i++) 
89         {
90           d->split[i] = dict_lookup_var (d, s->split[i]->name);
91           assert (d->split[i] != NULL);
92         }
93     }
94
95   if (s->weight != NULL) 
96     {
97       d->weight = dict_lookup_var (d, s->weight->name);
98       assert (d->weight != NULL); 
99     }
100
101   if (s->filter != NULL) 
102     {
103       d->filter = dict_lookup_var (d, s->filter->name);
104       assert (d->filter != NULL);
105     }
106
107   d->case_limit = s->case_limit;
108   dict_set_label (d, dict_get_label (s));
109   dict_set_documents (d, dict_get_documents (s));
110
111   for (i = 0; i < s->vector_cnt; i++) 
112     dict_create_vector (d, s->vector[i]->name,
113                         s->vector[i]->var, s->vector[i]->cnt);
114
115   return d;
116 }
117
118 void
119 dict_clear (struct dictionary *d) 
120 {
121   /* FIXME?  Should we really clear case_limit, label, documents?
122      Others are necessarily cleared by deleting all the variables.*/
123   int i;
124
125   assert (d != NULL);
126
127   for (i = 0; i < d->var_cnt; i++) 
128     {
129       struct variable *v = d->var[i];
130       val_labs_destroy (v->val_labs);
131       free (v->label);
132       free (v); 
133     }
134   free (d->var);
135   d->var = NULL;
136   d->var_cnt = d->var_cap = 0;
137   hsh_clear (d->name_tab);
138   d->value_cnt = 0;
139   free (d->split);
140   d->split = NULL;
141   d->split_cnt = 0;
142   d->weight = NULL;
143   d->filter = NULL;
144   d->case_limit = 0;
145   free (d->label);
146   d->label = NULL;
147   free (d->documents);
148   d->documents = NULL;
149   dict_clear_vectors (d);
150 }
151
152 void
153 dict_destroy (struct dictionary *d)
154 {
155   if (d != NULL) 
156     {
157       dict_clear (d);
158       hsh_destroy (d->name_tab);
159       free (d);
160     }
161 }
162
163 size_t
164 dict_get_var_cnt (const struct dictionary *d) 
165 {
166   assert (d != NULL);
167
168   return d->var_cnt;
169 }
170
171 struct variable *
172 dict_get_var (const struct dictionary *d, size_t idx) 
173 {
174   assert (d != NULL);
175   assert (idx < d->var_cnt);
176
177   return d->var[idx];
178 }
179
180 void
181 dict_get_vars (const struct dictionary *d, struct variable ***vars,
182                size_t *cnt, unsigned exclude_classes)
183 {
184   size_t count;
185   size_t i;
186   
187   assert (d != NULL);
188   assert (vars != NULL);
189   assert (cnt != NULL);
190   assert ((exclude_classes & ~((1u << DC_ORDINARY)
191                                | (1u << DC_SYSTEM)
192                                | (1u << DC_SCRATCH))) == 0);
193   
194   count = 0;
195   for (i = 0; i < d->var_cnt; i++)
196     if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
197       count++;
198
199   *vars = xmalloc (count * sizeof **vars);
200   *cnt = 0;
201   for (i = 0; i < d->var_cnt; i++)
202     if (!(exclude_classes & (1u << dict_class_from_id (d->var[i]->name))))
203       (*vars)[(*cnt)++] = d->var[i];
204   assert (*cnt == count);
205 }
206
207 struct variable *
208 dict_create_var (struct dictionary *d, const char *name, int width) 
209 {
210   struct variable *v;
211
212   assert (d != NULL);
213   assert (name != NULL);
214   assert (strlen (name) >= 1 && strlen (name) <= 8);
215   assert (width >= 0 && width < 256);
216
217   /* Make sure there's not already a variable by that name. */
218   if (dict_lookup_var (d, name) != NULL)
219     return NULL;
220
221   /* Allocate and initialize variable. */
222   v = xmalloc (sizeof *v);
223   strncpy (v->name, name, sizeof v->name);
224   v->name[8] = '\0';
225   v->index = d->var_cnt;
226   v->type = width == 0 ? NUMERIC : ALPHA;
227   v->width = width;
228   v->fv = d->value_cnt;
229   v->nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
230   v->left = name[0] == '#';
231   v->miss_type = MISSING_NONE;
232   if (v->type == NUMERIC)
233     {
234       v->print.type = FMT_F;
235       v->print.w = 8;
236       v->print.d = 2;
237     }
238   else
239     {
240       v->print.type = FMT_A;
241       v->print.w = v->width;
242       v->print.d = 0;
243     }
244   v->val_labs = val_labs_create (v->width);
245   v->label = NULL;
246
247   /* Update dictionary. */
248   if (d->var_cnt >= d->var_cap) 
249     {
250       d->var_cap = 8 + 2 * d->var_cap; 
251       d->var = xrealloc (d->var, d->var_cap * sizeof *d->var);
252     }
253   d->var[v->index] = v;
254   d->var_cnt++;
255   hsh_force_insert (d->name_tab, v);
256   d->value_cnt += v->nv;
257
258   return v;
259 }
260
261 struct variable *
262 dict_clone_var (struct dictionary *d, const struct variable *ov,
263                 const char *name)
264 {
265   struct variable *nv;
266
267   assert (d != NULL);
268   assert (ov != NULL);
269   assert (name != NULL);
270   assert (strlen (name) >= 1 && strlen (name) <= 8);
271
272   nv = dict_create_var (d, name, ov->width);
273   if (nv == NULL)
274     return NULL;
275
276   nv->left = ov->left;
277   nv->miss_type = ov->miss_type;
278   memcpy (nv->missing, ov->missing, sizeof nv->missing);
279   nv->print = ov->print;
280   nv->write = ov->write;
281   val_labs_destroy (nv->val_labs);
282   nv->val_labs = val_labs_copy (ov->val_labs);
283   if (ov->label != NULL)
284     nv->label = xstrdup (ov->label);
285
286   return nv;
287 }
288
289 void 
290 dict_rename_var (struct dictionary *d, struct variable *v,
291                  const char *new_name) 
292 {
293   assert (d != NULL);
294   assert (v != NULL);
295   assert (new_name != NULL);
296   assert (strlen (new_name) >= 1 && strlen (new_name) <= 8);
297
298   if (!strcmp (v->name, new_name))
299     return;
300
301   assert (dict_lookup_var (d, new_name) == NULL);
302
303   hsh_force_delete (d->name_tab, v);
304   strncpy (v->name, new_name, sizeof v->name);
305   v->name[8] = '\0';
306   hsh_force_insert (d->name_tab, v);
307 }
308
309 struct variable *
310 dict_lookup_var (const struct dictionary *d, const char *name)
311 {
312   struct variable v;
313   
314   assert (d != NULL);
315   assert (name != NULL);
316   assert (strlen (name) >= 1 && strlen (name) <= 8);
317
318   strncpy (v.name, name, sizeof v.name);
319   v.name[8] = '\0';
320
321   return hsh_find (d->name_tab, &v);
322 }
323
324 int
325 dict_contains_var (const struct dictionary *d, const struct variable *v)
326 {
327   assert (d != NULL);
328   assert (v != NULL);
329
330   return dict_lookup_var (d, v->name) == v;
331 }
332
333 static int
334 compare_variable_dblptrs (const void *a_, const void *b_, void *aux unused) 
335 {
336   struct variable *const *a = a_;
337   struct variable *const *b = b_;
338
339   if (a > b)
340     return 1;
341   else if (a < b)
342     return -1;
343   else
344     return 0;
345 }
346
347 void
348 dict_delete_var (struct dictionary *d, struct variable *v) 
349 {
350   size_t i;
351
352   /* FIXME?  Does not sync d->value_cnt. */
353   assert (d != NULL);
354   assert (v != NULL);
355   assert (dict_contains_var (d, v));
356   assert (d->var[v->index] == v);
357
358   /* Remove v from splits, weight, filter variables. */
359   d->split_cnt = remove_equal (d->split, d->split_cnt, sizeof *d->split,
360                                &v,
361                                compare_variable_dblptrs, NULL);
362   if (d->weight == v)
363     d->weight = NULL;
364   if (d->filter == v)
365     d->filter = NULL;
366   dict_clear_vectors (d);
367
368   /* Remove v from var array. */
369   d->var_cnt--;
370   memmove (d->var + v->index, d->var + v->index + 1,
371            (d->var_cnt - v->index) * sizeof *d->var);
372
373   /* Update index. */
374   for (i = v->index; i < d->var_cnt; i++)
375     d->var[i]->index = i;
376
377   /* Update name hash. */
378   hsh_force_delete (d->name_tab, v);
379
380   /* Free memory. */
381   val_labs_destroy (v->val_labs);
382   free (v->label);
383   free (v);
384
385 }
386
387 void 
388 dict_delete_vars (struct dictionary *d,
389                   struct variable *const *vars, size_t count) 
390 {
391   /* FIXME: this can be done in O(count) time, but this algorithm
392      is O(count**2). */
393   assert (d != NULL);
394   assert (count == 0 || vars != NULL);
395
396   while (count-- > 0)
397     dict_delete_var (d, *vars++);
398 }
399
400 void 
401 dict_reorder_vars (struct dictionary *d,
402                    struct variable *const *order, size_t count) 
403 {
404   struct variable **new_var;
405   size_t i;
406   
407   assert (d != NULL);
408   assert (count == 0 || order != NULL);
409   assert (count <= d->var_cnt);
410
411   new_var = xmalloc (d->var_cnt * sizeof *new_var);
412   memcpy (new_var, order, count * sizeof *new_var);
413   for (i = 0; i < count; i++) 
414     {
415       assert (d->var[order[i]->index] != NULL);
416       d->var[order[i]->index] = NULL;
417       order[i]->index = i;
418     }
419   for (i = 0; i < d->var_cnt; i++)
420     if (d->var[i] != NULL)
421       {
422         assert (count < d->var_cnt);
423         new_var[count] = d->var[i];
424         new_var[count]->index = count;
425         count++;
426       }
427   free (d->var);
428   d->var = new_var;
429 }
430
431 int
432 dict_rename_vars (struct dictionary *d,
433                   struct variable **vars, char **new_names,
434                   size_t count, char **err_name) 
435 {
436   char **old_names;
437   size_t i;
438   int success = 1;
439
440   assert (d != NULL);
441   assert (count == 0 || vars != NULL);
442   assert (count == 0 || new_names != NULL);
443
444   old_names = xmalloc (count * sizeof *old_names);
445   for (i = 0; i < count; i++) 
446     {
447       assert (d->var[vars[i]->index] == vars[i]);
448       hsh_force_delete (d->name_tab, vars[i]);
449       old_names[i] = xstrdup (vars[i]->name);
450     }
451   
452   for (i = 0; i < count; i++)
453     {
454       assert (new_names[i] != NULL);
455       assert (strlen (new_names[i]) < 9);
456       strcpy (vars[i]->name, new_names[i]);
457       if (hsh_insert (d->name_tab, vars[i]) != NULL) 
458         {
459           size_t fail_idx = i;
460           if (err_name != NULL) 
461             *err_name = new_names[i];
462
463           for (i = 0; i < fail_idx; i++)
464             hsh_force_delete (d->name_tab, vars[i]);
465           
466           for (i = 0; i < count; i++)
467             {
468               strcpy (vars[i]->name, old_names[i]);
469               hsh_force_insert (d->name_tab, vars[i]);
470             }
471
472           success = 0;
473           break;
474         }
475     }
476
477   for (i = 0; i < count; i++)
478     free (old_names[i]);
479   free (old_names);
480
481   return success;
482 }
483
484 struct variable *
485 dict_get_weight (const struct dictionary *d) 
486 {
487   assert (d != NULL);
488   assert (d->weight == NULL || dict_contains_var (d, d->weight));
489   
490   return d->weight;
491 }
492
493 double
494 dict_get_case_weight (const struct dictionary *d, const struct ccase *c)
495 {
496   assert (d != NULL);
497   assert (c != NULL);
498
499   if (d->weight == NULL)
500     return 1.0;
501   else 
502     {
503       double w = c->data[d->weight->fv].f;
504       if (w < 0.0)
505         w = 0.0;
506       return w;
507     }
508 }
509
510 void
511 dict_set_weight (struct dictionary *d, struct variable *v) 
512 {
513   assert (d != NULL);
514   assert (v == NULL || dict_contains_var (d, v));
515   assert (v == NULL || v->type == NUMERIC);
516
517   d->weight = v;
518 }
519
520 struct variable *
521 dict_get_filter (const struct dictionary *d) 
522 {
523   assert (d != NULL);
524   assert (d->filter == NULL || dict_contains_var (d, d->filter));
525   
526   return d->filter;
527 }
528
529 void
530 dict_set_filter (struct dictionary *d, struct variable *v)
531 {
532   assert (d != NULL);
533   assert (v == NULL || dict_contains_var (d, v));
534
535   d->filter = v;
536 }
537
538 int
539 dict_get_case_limit (const struct dictionary *d) 
540 {
541   assert (d != NULL);
542
543   return d->case_limit;
544 }
545
546 void
547 dict_set_case_limit (struct dictionary *d, int case_limit) 
548 {
549   assert (d != NULL);
550   assert (case_limit >= 0);
551
552   d->case_limit = case_limit;
553 }
554
555 int
556 dict_get_value_cnt (const struct dictionary *d) 
557 {
558   assert (d != NULL);
559
560   return d->value_cnt;
561 }
562
563 void
564 dict_compact_values (struct dictionary *d) 
565 {
566   size_t i;
567
568   d->value_cnt = 0;
569   for (i = 0; i < d->var_cnt; i++)
570     {
571       struct variable *v = d->var[i];
572
573       v->fv = d->value_cnt;
574       d->value_cnt += v->nv;
575     }
576 }
577
578 struct variable *const *
579 dict_get_split_vars (const struct dictionary *d) 
580 {
581   assert (d != NULL);
582   
583   return d->split;
584 }
585
586 size_t
587 dict_get_split_cnt (const struct dictionary *d) 
588 {
589   assert (d != NULL);
590
591   return d->split_cnt;
592 }
593
594 void
595 dict_set_split_vars (struct dictionary *d,
596                      struct variable *const *split, size_t cnt)
597 {
598   assert (d != NULL);
599   assert (cnt == 0 || split != NULL);
600
601   d->split_cnt = cnt;
602   d->split = xrealloc (d->split, cnt * sizeof *d->split);
603   memcpy (d->split, split, cnt * sizeof *d->split);
604 }
605
606 const char *
607 dict_get_label (const struct dictionary *d) 
608 {
609   assert (d != NULL);
610
611   return d->label;
612 }
613
614 void
615 dict_set_label (struct dictionary *d, const char *label) 
616 {
617   assert (d != NULL);
618
619   free (d->label);
620   if (label == NULL)
621     d->label = NULL;
622   else if (strlen (label) < 60)
623     d->label = xstrdup (label);
624   else 
625     {
626       d->label = xmalloc (61);
627       memcpy (d->label, label, 60);
628       d->label[60] = '\0';
629     }
630 }
631
632 const char *
633 dict_get_documents (const struct dictionary *d) 
634 {
635   assert (d != NULL);
636
637   return d->documents;
638 }
639
640 void
641 dict_set_documents (struct dictionary *d, const char *documents)
642 {
643   assert (d != NULL);
644
645   free (d->documents);
646   if (documents == NULL)
647     d->documents = NULL;
648   else
649     d->documents = xstrdup (documents);
650 }
651
652 int
653 dict_create_vector (struct dictionary *d,
654                     const char *name,
655                     struct variable **var, size_t cnt) 
656 {
657   struct vector *vector;
658
659   assert (d != NULL);
660   assert (name != NULL);
661   assert (strlen (name) > 0 && strlen (name) < 9);
662   assert (var != NULL);
663   assert (cnt > 0);
664   
665   if (dict_lookup_vector (d, name) != NULL)
666     return 0;
667
668   d->vector = xrealloc (d->vector, (d->vector_cnt + 1) * sizeof *d->vector);
669   vector = d->vector[d->vector_cnt] = xmalloc (sizeof *vector);
670   vector->idx = d->vector_cnt++;
671   strncpy (vector->name, name, 8);
672   vector->name[8] = '\0';
673   vector->var = xmalloc (cnt * sizeof *var);
674   memcpy (vector->var, var, cnt * sizeof *var);
675   vector->cnt = cnt;
676   
677   return 1;
678 }
679
680 const struct vector *
681 dict_get_vector (const struct dictionary *d, size_t idx) 
682 {
683   assert (d != NULL);
684   assert (idx < d->vector_cnt);
685
686   return d->vector[idx];
687 }
688
689 size_t
690 dict_get_vector_cnt (const struct dictionary *d) 
691 {
692   assert (d != NULL);
693
694   return d->vector_cnt;
695 }
696
697 const struct vector *
698 dict_lookup_vector (const struct dictionary *d, const char *name) 
699 {
700   size_t i;
701
702   assert (d != NULL);
703   assert (name != NULL);
704
705   for (i = 0; i < d->vector_cnt; i++)
706     if (!strcmp (d->vector[i]->name, name))
707       return d->vector[i];
708   return NULL;
709 }
710
711 void
712 dict_clear_vectors (struct dictionary *d) 
713 {
714   size_t i;
715   
716   assert (d != NULL);
717
718   for (i = 0; i < d->vector_cnt; i++) 
719     {
720       free (d->vector[i]->var);
721       free (d->vector[i]);
722     }
723   free (d->vector);
724   d->vector = NULL;
725   d->vector_cnt = 0;
726 }