697d7f5ba59726120f77492504eeeb603dc35c83
[pspp-builds.git] / src / inpt-pgm.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 <float.h>
23 #include <stdlib.h>
24 #include "alloc.h"
25 #include "command.h"
26 #include "data-list.h"
27 #include "dfm.h"
28 #include "error.h"
29 #include "expr.h"
30 #include "file-handle.h"
31 #include "lexer.h"
32 #include "misc.h"
33 #include "str.h"
34 #include "var.h"
35 #include "vfm.h"
36
37 #include "debug-print.h"
38
39 /* Indicates how a `union value' should be initialized. */
40 enum value_init_type
41   {
42     INP_NUMERIC = 01,           /* Numeric. */
43     INP_STRING = 0,             /* String. */
44     
45     INP_INIT_ONCE = 02,         /* Initialize only once. */
46     INP_REINIT = 0,             /* Reinitialize for each iteration. */
47   };
48
49 struct input_program_pgm 
50   {
51     enum value_init_type *init; /* How to initialize each `union value'. */
52     size_t init_cnt;            /* Number of elements in inp_init. */
53   };
54
55 static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
56 static trns_free_func reread_trns_free;
57
58 int
59 cmd_input_program (void)
60 {
61   lex_match_id ("INPUT");
62   lex_match_id ("PROGRAM");
63   discard_variables ();
64
65   vfm_source = create_case_source (&input_program_source_class, NULL);
66
67   return lex_end_of_command ();
68 }
69
70 int
71 cmd_end_input_program (void)
72 {
73   struct input_program_pgm *inp;
74   size_t i;
75
76   lex_match_id ("END");
77   lex_match_id ("INPUT");
78   lex_match_id ("PROGRAM");
79
80   if (!case_source_is_class (vfm_source, &input_program_source_class))
81     {
82       msg (SE, _("No matching INPUT PROGRAM command."));
83       return CMD_FAILURE;
84     }
85   
86   if (dict_get_next_value_idx (default_dict) == 0)
87     msg (SW, _("No data-input or transformation commands specified "
88          "between INPUT PROGRAM and END INPUT PROGRAM."));
89
90   /* Mark the boundary between INPUT PROGRAM transformations and
91      ordinary transformations. */
92   f_trns = n_trns;
93
94   /* Figure out how to initialize temp_case. */
95   inp = xmalloc (sizeof *inp);
96   inp->init_cnt = dict_get_next_value_idx (default_dict);
97   inp->init = xmalloc (inp->init_cnt * sizeof *inp->init);
98   for (i = 0; i < inp->init_cnt; i++)
99     inp->init[i] = -1;
100   for (i = 0; i < dict_get_var_cnt (default_dict); i++)
101     {
102       struct variable *var = dict_get_var (default_dict, i);
103       enum value_init_type value_init;
104       size_t j;
105       
106       value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING;
107       value_init |= var->reinit ? INP_REINIT : INP_INIT_ONCE;
108
109       for (j = 0; j < var->nv; j++)
110         inp->init[j + var->fv] = value_init;
111     }
112   for (i = 0; i < inp->init_cnt; i++)
113     assert (inp->init[i] != -1);
114
115   /* Put inp into vfm_source for later use. */
116   vfm_source->aux = inp;
117
118   return lex_end_of_command ();
119 }
120
121 /* Initializes temp_case.  Called before the first case is read. */
122 static void
123 init_case (struct input_program_pgm *inp)
124 {
125   size_t i;
126
127   for (i = 0; i < inp->init_cnt; i++)
128     switch (inp->init[i]) 
129       {
130       case INP_NUMERIC | INP_INIT_ONCE:
131         temp_case->data[i].f = 0.0;
132         break;
133       case INP_NUMERIC | INP_REINIT:
134         temp_case->data[i].f = SYSMIS;
135         break;
136       case INP_STRING | INP_INIT_ONCE:
137       case INP_STRING | INP_REINIT:
138         memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s);
139         break;
140       default:
141         assert (0);
142       }
143 }
144
145 /* Clears temp_case.  Called between reading successive records. */
146 static void
147 clear_case (struct input_program_pgm *inp)
148 {
149   size_t i;
150
151   for (i = 0; i < inp->init_cnt; i++)
152     switch (inp->init[i]) 
153       {
154       case INP_NUMERIC | INP_INIT_ONCE:
155         break;
156       case INP_NUMERIC | INP_REINIT:
157         temp_case->data[i].f = SYSMIS;
158         break;
159       case INP_STRING | INP_INIT_ONCE:
160         break;
161       case INP_STRING | INP_REINIT:
162         memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s);
163         break;
164       default:
165         assert (0);
166       }
167 }
168
169 /* Executes each transformation in turn on a `blank' case.  When a
170    transformation fails, returning -2, then that's the end of the
171    file.  -1 means go on to the next transformation.  Otherwise the
172    return value is the index of the transformation to go to next. */
173 static void
174 input_program_source_read (struct case_source *source,
175                            write_case_func *write_case,
176                            write_case_data wc_data)
177 {
178   struct input_program_pgm *inp = source->aux;
179   int i;
180
181   /* Nonzero if there were any END CASE commands in the set of
182      transformations.  If so, we don't automatically write out
183      cases. */
184   int end_case = 0;
185
186   /* FIXME?  This is the number of cases sent out of the input
187      program, not the number of cases written to the procedure.
188      The difference should only show up in $CASENUM in COMPUTE.
189      We should check behavior against SPSS. */
190   int cases_written = 0;
191
192   assert (inp != NULL);
193   
194   /* Figure end_case. */
195   for (i = 0; i < f_trns; i++)
196     if (t_trns[i]->proc == end_case_trns_proc)
197       end_case = 1;
198
199   /* FIXME: This code should not be necessary.  It is an ugly
200      kluge. */
201   for (i = 0; i < f_trns; i++)
202     if (t_trns[i]->proc == repeating_data_trns_proc)
203       repeating_data_set_write_case (t_trns[i], write_case, wc_data);
204
205   init_case (inp);
206   for (;;)
207     {
208       /* Index of current transformation. */
209       int i;
210
211       /* Return value of last-called transformation. */
212       int code;
213
214       debug_printf (("input-program: "));
215
216       /* Perform transformations on `blank' case. */
217       for (i = 0; i < f_trns;)
218         {
219 #if DEBUGGING
220           printf ("/%d", i);
221           if (t_trns[i]->proc == end_case_trns_proc)
222             printf ("\n");
223 #endif
224
225           if (t_trns[i]->proc == end_case_trns_proc) 
226             {
227               cases_written++;
228               if (!write_case (wc_data))
229                 return;
230               clear_case (inp);
231               i++;
232               continue;
233             }
234
235           code = t_trns[i]->proc (t_trns[i], temp_case, cases_written + 1);
236           switch (code)
237             {
238             case -1:
239               i++;
240               break;
241             case -2:
242               return;
243             case -3:
244               goto next_case;
245             default:
246               i = code;
247               break;
248             }
249         }
250
251 #if DEBUGGING
252       if (!end_case)
253         printf ("\n");
254 #endif
255
256       /* Write the case if appropriate. */
257       if (!end_case)
258         if (!write_case (wc_data))
259           return;
260
261       /* Blank out the case for the next iteration. */
262     next_case:
263       clear_case (inp);
264     }
265 }
266
267 static void
268 input_program_source_destroy (struct case_source *source)
269 {
270   struct input_program_pgm *inp = source->aux;
271
272   cancel_transformations ();
273
274   if (inp != NULL) 
275     {
276       free (inp->init);
277       free (inp);
278     }
279 }
280
281 const struct case_source_class input_program_source_class =
282   {
283     "INPUT PROGRAM",
284     NULL,
285     input_program_source_read,
286     input_program_source_destroy,
287   };
288 \f
289 int
290 cmd_end_case (void)
291 {
292   struct trns_header *t;
293
294   lex_match_id ("END");
295   lex_match_id ("CASE");
296
297   if (!case_source_is_class (vfm_source, &input_program_source_class))
298     {
299       msg (SE, _("This command may only be executed between INPUT PROGRAM "
300                  "and END INPUT PROGRAM."));
301       return CMD_FAILURE;
302     }
303
304   t = xmalloc (sizeof *t);
305   t->proc = end_case_trns_proc;
306   t->free = NULL;
307   add_transformation ((struct trns_header *) t);
308
309   return lex_end_of_command ();
310 }
311
312 int
313 end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
314                     int case_num UNUSED)
315 {
316   assert (0);
317 }
318
319 /* REREAD transformation. */
320 struct reread_trns
321   {
322     struct trns_header h;
323
324     struct file_handle *handle; /* File to move file pointer back on. */
325     struct expression *column;  /* Column to reset file pointer to. */
326   };
327
328 /* Parses REREAD command. */
329 int
330 cmd_reread (void)
331 {
332   /* File to be re-read. */
333   struct file_handle *h;
334   
335   /* Expression for column to set file pointer to. */
336   struct expression *e;
337
338   /* Created transformation. */
339   struct reread_trns *t;
340
341   lex_match_id ("REREAD");
342
343   h = default_handle;
344   e = NULL;
345   while (token != '.')
346     {
347       if (lex_match_id ("COLUMN"))
348         {
349           lex_match ('=');
350           
351           if (e)
352             {
353               msg (SE, _("COLUMN subcommand multiply specified."));
354               expr_free (e);
355               return CMD_FAILURE;
356             }
357           
358           e = expr_parse (PXP_NUMERIC);
359           if (!e)
360             return CMD_FAILURE;
361         }
362       else if (lex_match_id ("FILE"))
363         {
364           lex_match ('=');
365           if (token != T_ID)
366             {
367               lex_error (_("expecting file handle name"));
368               expr_free (e);
369               return CMD_FAILURE;
370             }
371           h = fh_get_handle_by_name (tokid);
372           if (!h)
373             {
374               expr_free (e);
375               return CMD_FAILURE;
376             }
377           lex_get ();
378         }
379       else
380         {
381           lex_error (NULL);
382           expr_free (e);
383         }
384     }
385
386   t = xmalloc (sizeof *t);
387   t->h.proc = reread_trns_proc;
388   t->h.free = reread_trns_free;
389   t->handle = h;
390   t->column = e;
391   add_transformation ((struct trns_header *) t);
392
393   return CMD_SUCCESS;
394 }
395
396 static int
397 reread_trns_proc (struct trns_header * pt, struct ccase * c,
398                   int case_num)
399 {
400   struct reread_trns *t = (struct reread_trns *) pt;
401
402   if (t->column == NULL)
403     dfm_bkwd_record (t->handle, 1);
404   else
405     {
406       union value column;
407
408       expr_evaluate (t->column, c, case_num, &column);
409       if (!finite (column.f) || column.f < 1)
410         {
411           msg (SE, _("REREAD: Column numbers must be positive finite "
412                "numbers.  Column set to 1."));
413           dfm_bkwd_record (t->handle, 1);
414         }
415       else
416         dfm_bkwd_record (t->handle, column.f);
417     }
418   return -1;
419 }
420
421 static void
422 reread_trns_free (struct trns_header * t)
423 {
424   expr_free (((struct reread_trns *) t)->column);
425 }
426
427 /* Parses END FILE command. */
428 int
429 cmd_end_file (void)
430 {
431   struct trns_header *t;
432
433   lex_match_id ("END");
434   lex_match_id ("FILE");
435
436   if (!case_source_is_class (vfm_source, &input_program_source_class))
437     {
438       msg (SE, _("This command may only be executed between INPUT PROGRAM "
439                  "and END INPUT PROGRAM."));
440       return CMD_FAILURE;
441     }
442
443   t = xmalloc (sizeof *t);
444   t->proc = end_file_trns_proc;
445   t->free = NULL;
446   add_transformation ((struct trns_header *) t);
447
448   return lex_end_of_command ();
449 }
450
451 static int
452 end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED,
453                     int case_num UNUSED)
454 {
455 #if DEBUGGING
456   printf ("END FILE\n");
457 #endif
458   return -2;
459 }