ef9c3646440cc889c8d0fcd2fee0e93ee927bd28
[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., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "error.h"
22 #include <float.h>
23 #include <stdlib.h>
24 #include "alloc.h"
25 #include "case.h"
26 #include "command.h"
27 #include "data-list.h"
28 #include "dfm-read.h"
29 #include "dictionary.h"
30 #include "error.h"
31 #include "expressions/public.h"
32 #include "file-handle.h"
33 #include "lexer.h"
34 #include "misc.h"
35 #include "str.h"
36 #include "var.h"
37 #include "vfm.h"
38
39 #include "debug-print.h"
40
41 /* Indicates how a `union value' should be initialized. */
42 enum value_init_type
43   {
44     INP_NUMERIC = 01,           /* Numeric. */
45     INP_STRING = 0,             /* String. */
46     
47     INP_INIT_ONCE = 02,         /* Initialize only once. */
48     INP_REINIT = 0,             /* Reinitialize for each iteration. */
49   };
50
51 struct input_program_pgm 
52   {
53     enum value_init_type *init; /* How to initialize each `union value'. */
54     size_t init_cnt;            /* Number of elements in inp_init. */
55     size_t case_size;           /* Size of case in bytes. */
56   };
57
58 static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
59 static trns_free_func reread_trns_free;
60
61 int
62 cmd_input_program (void)
63 {
64   discard_variables ();
65
66   /* FIXME: we shouldn't do this here, but I'm afraid that other
67      code will check the class of vfm_source. */
68   vfm_source = create_case_source (&input_program_source_class, NULL);
69
70   return lex_end_of_command ();
71 }
72
73 int
74 cmd_end_input_program (void)
75 {
76   struct input_program_pgm *inp;
77   size_t i;
78
79   if (!case_source_is_class (vfm_source, &input_program_source_class))
80     {
81       msg (SE, _("No matching INPUT PROGRAM command."));
82       return CMD_FAILURE;
83     }
84   
85   if (dict_get_next_value_idx (default_dict) == 0)
86     msg (SW, _("No data-input or transformation commands specified "
87          "between INPUT PROGRAM and END INPUT PROGRAM."));
88
89   /* Mark the boundary between INPUT PROGRAM transformations and
90      ordinary transformations. */
91   f_trns = n_trns;
92
93   /* Figure out how to initialize each input case. */
94   inp = xmalloc (sizeof *inp);
95   inp->init_cnt = dict_get_next_value_idx (default_dict);
96   inp->init = xmalloc (inp->init_cnt * sizeof *inp->init);
97   for (i = 0; i < inp->init_cnt; i++)
98     inp->init[i] = -1;
99   for (i = 0; i < dict_get_var_cnt (default_dict); i++)
100     {
101       struct variable *var = dict_get_var (default_dict, i);
102       enum value_init_type value_init;
103       size_t j;
104       
105       value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING;
106       value_init |= var->reinit ? INP_REINIT : INP_INIT_ONCE;
107
108       for (j = 0; j < var->nv; j++)
109         inp->init[j + var->fv] = value_init;
110     }
111   for (i = 0; i < inp->init_cnt; i++)
112     assert (inp->init[i] != -1);
113   inp->case_size = dict_get_case_size (default_dict);
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 case C.  Called before the first case is read. */
122 static void
123 init_case (const struct input_program_pgm *inp, struct ccase *c)
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         case_data_rw (c, i)->f = 0.0;
132         break;
133       case INP_NUMERIC | INP_REINIT:
134         case_data_rw (c, i)->f = SYSMIS;
135         break;
136       case INP_STRING | INP_INIT_ONCE:
137       case INP_STRING | INP_REINIT:
138         memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
139         break;
140       default:
141         assert (0);
142       }
143 }
144
145 /* Clears case C.  Called between reading successive records. */
146 static void
147 clear_case (const struct input_program_pgm *inp, struct ccase *c)
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         case_data_rw (c, i)->f = SYSMIS;
158         break;
159       case INP_STRING | INP_INIT_ONCE:
160         break;
161       case INP_STRING | INP_REINIT:
162         memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, 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                            struct ccase *c,
176                            write_case_func *write_case,
177                            write_case_data wc_data)
178 {
179   struct input_program_pgm *inp = source->aux;
180   int i;
181
182   /* Nonzero if there were any END CASE commands in the set of
183      transformations.  If so, we don't automatically write out
184      cases. */
185   int end_case = 0;
186
187   /* FIXME?  This is the number of cases sent out of the input
188      program, not the number of cases written to the procedure.
189      The difference should only show up in $CASENUM in COMPUTE.
190      We should check behavior against SPSS. */
191   int cases_written = 0;
192
193   assert (inp != NULL);
194
195   /* Figure end_case. */
196   for (i = 0; i < f_trns; i++)
197     if (t_trns[i]->proc == end_case_trns_proc)
198       end_case = 1;
199
200   /* FIXME: This is an ugly 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, c);
206   for (;;)
207     {
208       /* Perform transformations on `blank' case. */
209       for (i = 0; i < f_trns; )
210         {
211           int code;     /* Return value of last-called transformation. */
212
213           if (t_trns[i]->proc == end_case_trns_proc) 
214             {
215               cases_written++;
216               if (!write_case (wc_data))
217                 goto done;
218               clear_case (inp, c);
219               i++;
220               continue;
221             }
222
223           code = t_trns[i]->proc (t_trns[i], c, cases_written + 1);
224           switch (code)
225             {
226             case -1:
227               i++;
228               break;
229             case -2:
230               goto done;
231             case -3:
232               goto next_case;
233             default:
234               i = code;
235               break;
236             }
237         }
238
239       /* Write the case if appropriate. */
240       if (!end_case) 
241         {
242           cases_written++;
243           if (!write_case (wc_data))
244             break;
245         }
246
247       /* Blank out the case for the next iteration. */
248     next_case:
249       clear_case (inp, c);
250     }
251  done: ;
252 }
253
254 /* Destroys an INPUT PROGRAM source. */
255 static void
256 input_program_source_destroy (struct case_source *source)
257 {
258   struct input_program_pgm *inp = source->aux;
259
260   cancel_transformations ();
261
262   if (inp != NULL) 
263     {
264       free (inp->init);
265       free (inp);
266     }
267 }
268
269 const struct case_source_class input_program_source_class =
270   {
271     "INPUT PROGRAM",
272     NULL,
273     input_program_source_read,
274     input_program_source_destroy,
275   };
276 \f
277 int
278 cmd_end_case (void)
279 {
280   struct trns_header *t;
281
282   if (!case_source_is_class (vfm_source, &input_program_source_class))
283     {
284       msg (SE, _("This command may only be executed between INPUT PROGRAM "
285                  "and END INPUT PROGRAM."));
286       return CMD_FAILURE;
287     }
288
289   t = xmalloc (sizeof *t);
290   t->proc = end_case_trns_proc;
291   t->free = NULL;
292   add_transformation ((struct trns_header *) t);
293
294   return lex_end_of_command ();
295 }
296
297 /* Should never be called, because this is handled in
298    input_program_source_read(). */
299 int
300 end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED,
301                     int case_num UNUSED)
302 {
303   assert (0);
304   abort ();
305 }
306
307 /* REREAD transformation. */
308 struct reread_trns
309   {
310     struct trns_header h;
311
312     struct dfm_reader *reader;  /* File to move file pointer back on. */
313     struct expression *column;  /* Column to reset file pointer to. */
314   };
315
316 /* Parses REREAD command. */
317 int
318 cmd_reread (void)
319 {
320   struct file_handle *fh;       /* File to be re-read. */
321   struct expression *e;         /* Expression for column to set. */
322   struct reread_trns *t;        /* Created transformation. */
323
324   fh = default_handle;
325   e = NULL;
326   while (token != '.')
327     {
328       if (lex_match_id ("COLUMN"))
329         {
330           lex_match ('=');
331           
332           if (e)
333             {
334               msg (SE, _("COLUMN subcommand multiply specified."));
335               expr_free (e);
336               return CMD_FAILURE;
337             }
338           
339           e = expr_parse (default_dict, EXPR_NUMBER);
340           if (!e)
341             return CMD_FAILURE;
342         }
343       else if (lex_match_id ("FILE"))
344         {
345           lex_match ('=');
346           fh = fh_parse ();
347           if (fh == NULL)
348             {
349               expr_free (e);
350               return CMD_FAILURE;
351             }
352           lex_get ();
353         }
354       else
355         {
356           lex_error (NULL);
357           expr_free (e);
358         }
359     }
360
361   t = xmalloc (sizeof *t);
362   t->h.proc = reread_trns_proc;
363   t->h.free = reread_trns_free;
364   t->reader = dfm_open_reader (fh);
365   t->column = e;
366   add_transformation ((struct trns_header *) t);
367
368   return CMD_SUCCESS;
369 }
370
371 /* Executes a REREAD transformation. */
372 static int
373 reread_trns_proc (struct trns_header * pt, struct ccase * c,
374                   int case_num)
375 {
376   struct reread_trns *t = (struct reread_trns *) pt;
377
378   if (t->column == NULL)
379     dfm_reread_record (t->reader, 1);
380   else
381     {
382       double column = expr_evaluate_num (t->column, c, case_num);
383       if (!finite (column) || column < 1)
384         {
385           msg (SE, _("REREAD: Column numbers must be positive finite "
386                "numbers.  Column set to 1."));
387           dfm_reread_record (t->reader, 1);
388         }
389       else
390         dfm_reread_record (t->reader, column);
391     }
392   return -1;
393 }
394
395 /* Frees a REREAD transformation. */
396 static void
397 reread_trns_free (struct trns_header *t_)
398 {
399   struct reread_trns *t = (struct reread_trns *) t_;
400   expr_free (t->column);
401   dfm_close_reader (t->reader);
402 }
403
404 /* Parses END FILE command. */
405 int
406 cmd_end_file (void)
407 {
408   struct trns_header *t;
409
410   if (!case_source_is_class (vfm_source, &input_program_source_class))
411     {
412       msg (SE, _("This command may only be executed between INPUT PROGRAM "
413                  "and END INPUT PROGRAM."));
414       return CMD_FAILURE;
415     }
416
417   t = xmalloc (sizeof *t);
418   t->proc = end_file_trns_proc;
419   t->free = NULL;
420   add_transformation ((struct trns_header *) t);
421
422   return lex_end_of_command ();
423 }
424
425 /* Executes an END FILE transformation. */
426 static int
427 end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED,
428                     int case_num UNUSED)
429 {
430   return -2;
431 }