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