checkin of 0.3.0
[pspp-builds.git] / src / temporary.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 <stddef.h>
23 #include <stdlib.h>
24 #include "alloc.h"
25 #include "avl.h"
26 #include "command.h"
27 #include "do-ifP.h"
28 #include "error.h"
29 #include "lexer.h"
30 #include "str.h"
31 #include "var.h"
32
33 #undef DEBUGGING
34 /*#define DEBUGGING 1*/
35 #include "debug-print.h"
36
37 int temporary;
38 struct dictionary *temp_dict;
39 int temp_trns;
40
41 #if 0
42 /* Displays all the value labels in TREE, with label S. */
43 void
44 display_tree (char *s, avl_tree *tree)
45 {
46   value_label *iter;
47   avl_traverser *trav = NULL;
48
49   printf("%s tree:\n", s);
50   fflush(stdout);
51   while ((iter = avl_traverse (tree, &trav)) != NULL)
52     printf (" %g: %s\n", iter->v.f, iter->s);
53 }
54 #endif
55
56 /* Parses the TEMPORARY command. */
57 int
58 cmd_temporary (void)
59 {
60   lex_match_id ("TEMPORARY");
61
62   /* TEMPORARY is not allowed inside DO IF or LOOP. */
63   if (ctl_stack)
64     {
65       msg (SE, _("This command is not valid inside DO IF or LOOP."));
66       return CMD_FAILURE;
67     }
68
69   /* TEMPORARY can only appear once! */
70   if (temporary)
71     {
72       msg (SE, _("This command may only appear once between "
73            "procedures and procedure-like commands."));
74       return CMD_FAILURE;
75     }
76
77   /* Everything is temporary, even if we think it'll last forever.
78      Especially then. */
79   temporary = 1;
80   temp_dict = save_dictionary ();
81   if (f_trns == n_trns)
82     temp_trns = -1;
83   else
84     temp_trns = n_trns;
85   debug_printf (("TEMPORARY: temp_trns=%d\n", temp_trns));
86
87   return lex_end_of_command ();
88 }
89
90 /* Copies a variable structure. */
91 void
92 copy_variable (struct variable *dest, const struct variable *src)
93 {
94   int i, n;
95
96   assert (dest != src);
97   dest->type = src->type;
98   dest->left = src->left;
99   dest->width = src->width;
100   dest->fv = src->fv;
101   dest->nv = src->nv;
102   dest->miss_type = src->miss_type;
103   
104   switch (src->miss_type)
105     {
106     case MISSING_NONE:
107       n = 0;
108       break;
109     case MISSING_1:
110       n = 1;
111       break;
112     case MISSING_2:
113     case MISSING_RANGE:
114       n = 2;
115       break;
116     case MISSING_3:
117     case MISSING_RANGE_1:
118       n = 3;
119       break;
120     default:
121       assert (0);
122       break;
123     }
124   
125   for (i = 0; i < n; i++)
126     dest->missing[i] = src->missing[i];
127   dest->print = src->print;
128   dest->write = src->write;
129
130   dest->val_lab = copy_value_labels (src->val_lab);
131   dest->label = src->label ? xstrdup (src->label) : NULL;
132 }
133
134 /* Returns a newly created empty dictionary.  The file label and
135    documents are copied from default_dict if COPY is nonzero. */
136 struct dictionary *
137 new_dictionary (int copy)
138 {
139   struct dictionary *d = xmalloc (sizeof *d);
140   
141   d->var = NULL;
142   d->var_by_name = avl_create (NULL, cmp_variable, NULL);
143   d->nvar = 0;
144
145   d->N = 0;
146
147   d->nval = 0;
148
149   d->n_splits = 0;
150   d->splits = NULL;
151
152   if (default_dict.label && copy)
153     d->label = xstrdup (default_dict.label);
154   else
155     d->label = NULL;
156
157   if (default_dict.n_documents && copy)
158     {
159       d->n_documents = default_dict.n_documents;
160       if (d->n_documents)
161         {
162           d->documents = malloc (default_dict.n_documents * 80);
163           memcpy (d->documents, default_dict.documents,
164                   default_dict.n_documents * 80);
165         }
166     }
167   else
168     {
169       d->n_documents = 0;
170       d->documents = NULL;
171     }
172   
173   d->weight_index = -1;
174   d->weight_var[0] = 0;
175
176   d->filter_var[0] = 0;
177
178   return d;
179 }
180     
181 /* Copies the current dictionary info into a newly allocated
182    dictionary structure, which is returned. */
183 struct dictionary *
184 save_dictionary (void)
185 {
186   /* Dictionary being created. */
187   struct dictionary *d;
188
189   int i;
190
191   d = xmalloc (sizeof *d);
192
193   /* First the easy stuff. */
194   *d = default_dict;
195   d->label = default_dict.label ? xstrdup (default_dict.label) : NULL;
196   if (default_dict.n_documents)
197     {
198       d->documents = malloc (default_dict.n_documents * 80);
199       memcpy (d->documents, default_dict.documents,
200               default_dict.n_documents * 80);
201     }
202   else d->documents = NULL;
203
204   /* Then the variables. */
205   d->var_by_name = avl_create (NULL, cmp_variable, NULL);
206   d->var = xmalloc (default_dict.nvar * sizeof *d->var);
207   for (i = 0; i < default_dict.nvar; i++)
208     {
209       d->var[i] = xmalloc (sizeof *d->var[i]);
210       copy_variable (d->var[i], default_dict.var[i]);
211       strcpy (d->var[i]->name, default_dict.var[i]->name);
212       d->var[i]->index = i;
213       avl_force_insert (d->var_by_name, d->var[i]);
214     }
215
216   /* Then the SPLIT FILE variables. */
217   if (default_dict.splits)
218     {
219       int i;
220
221       d->n_splits = default_dict.n_splits;
222       d->splits = xmalloc ((default_dict.n_splits + 1) * sizeof *d->splits);
223       for (i = 0; i < default_dict.n_splits; i++)
224         d->splits[i] = d->var[default_dict.splits[i]->index];
225       d->splits[default_dict.n_splits] = NULL;
226     }
227   else
228     {
229       d->n_splits = 0;
230       d->splits = NULL;
231     }
232   
233   return d;
234 }
235
236 /* Copies dictionary D into the active file dictionary.  Deletes
237    dictionary D. */
238 void
239 restore_dictionary (struct dictionary * d)
240 {
241   int i;
242
243   /* 1. Delete the current dictionary. */
244   default_dict.n_splits = 0;
245   free (default_dict.splits);
246   default_dict.splits = NULL;
247   
248   avl_destroy (default_dict.var_by_name, NULL);
249   default_dict.var_by_name = NULL;
250   
251   for (i = 0; i < default_dict.nvar; i++)
252     {
253       clear_variable (&default_dict, default_dict.var[i]);
254       free (default_dict.var[i]);
255     }
256   
257   free (default_dict.var);
258   free (default_dict.label);
259   free (default_dict.documents);
260
261   /* 2. Copy dictionary D into the active file dictionary. */
262 #if __CHECKER__
263   {
264     size_t offset;
265     
266     offset = offsetof (struct dictionary, filter_var) + sizeof d->filter_var;
267     strncpy (d->weight_var, d->weight_var, 9);
268     strncpy (d->filter_var, d->filter_var, 9);
269     memset (&((char *) d)[offset], '*', sizeof *d - offset);
270   }
271 #endif
272   default_dict = *d;
273   if (!default_dict.var_by_name)
274     {
275       default_dict.var_by_name = avl_create (NULL, cmp_variable, NULL);
276       
277       for (i = 0; i < default_dict.nvar; i++)
278         avl_force_insert (default_dict.var_by_name, default_dict.var[i]);
279     }
280
281   /* 3. Destroy dictionary D. */
282   free (d);
283 }
284
285 /* Destroys dictionary D. */
286 void
287 free_dictionary (struct dictionary * d)
288 {
289   int i;
290
291   d->n_splits = 0;
292   free (d->splits);
293   d->splits = NULL;
294   
295   if (d->var_by_name)
296     avl_destroy (d->var_by_name, NULL);
297
298   for (i = 0; i < d->nvar; i++)
299     {
300       struct variable *v = d->var[i];
301
302       if (v->val_lab)
303         {
304           avl_destroy (v->val_lab, free_val_lab);
305           v->val_lab = NULL;
306         }
307       if (v->label)
308         {
309           free (v->label);
310           v->label = NULL;
311         }
312       free (d->var[i]);
313     }
314   free (d->var);
315
316   free (d->label);
317   free (d->documents);
318
319   free (d);
320 }
321
322 /* Cancels the temporary transformation, if any. */
323 void
324 cancel_temporary (void)
325 {
326   if (temporary)
327     {
328       if (temp_dict)
329         free_dictionary (temp_dict);
330       temporary = 0;
331       temp_trns = 0;
332     }
333 }