ed456da5a85dc3db0d3ab3253764bea7b4252399
[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   default_dict = *d;
263   if (!default_dict.var_by_name)
264     {
265       default_dict.var_by_name = avl_create (NULL, cmp_variable, NULL);
266       
267       for (i = 0; i < default_dict.nvar; i++)
268         avl_force_insert (default_dict.var_by_name, default_dict.var[i]);
269     }
270
271   /* 3. Destroy dictionary D. */
272   free (d);
273 }
274
275 /* Destroys dictionary D. */
276 void
277 free_dictionary (struct dictionary * d)
278 {
279   int i;
280
281   d->n_splits = 0;
282   free (d->splits);
283   d->splits = NULL;
284   
285   if (d->var_by_name)
286     avl_destroy (d->var_by_name, NULL);
287
288   for (i = 0; i < d->nvar; i++)
289     {
290       struct variable *v = d->var[i];
291
292       if (v->val_lab)
293         {
294           avl_destroy (v->val_lab, free_val_lab);
295           v->val_lab = NULL;
296         }
297       if (v->label)
298         {
299           free (v->label);
300           v->label = NULL;
301         }
302       free (d->var[i]);
303     }
304   free (d->var);
305
306   free (d->label);
307   free (d->documents);
308
309   free (d);
310 }
311
312 /* Cancels the temporary transformation, if any. */
313 void
314 cancel_temporary (void)
315 {
316   if (temporary)
317     {
318       if (temp_dict)
319         free_dictionary (temp_dict);
320       temporary = 0;
321       temp_trns = 0;
322     }
323 }