1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
22 #include <language/data-io/inpt-pgm.h>
27 #include <data/case.h>
28 #include <data/dictionary.h>
29 #include <data/variable.h>
30 #include <language/command.h>
31 #include <language/data-io/data-list.h>
32 #include <language/data-io/data-reader.h>
33 #include <language/data-io/file-handle.h>
34 #include <language/expressions/public.h>
35 #include <language/lexer/lexer.h>
36 #include <libpspp/alloc.h>
37 #include <libpspp/compiler.h>
38 #include <libpspp/message.h>
39 #include <libpspp/message.h>
40 #include <libpspp/misc.h>
41 #include <libpspp/str.h>
42 #include <procedure.h>
45 #define _(msgid) gettext (msgid)
47 /* Indicates how a `union value' should be initialized. */
50 INP_NUMERIC = 01, /* Numeric. */
51 INP_STRING = 0, /* String. */
53 INP_INIT_ONCE = 02, /* Initialize only once. */
54 INP_REINIT = 0, /* Reinitialize for each iteration. */
57 struct input_program_pgm
59 enum value_init_type *init; /* How to initialize each `union value'. */
60 size_t init_cnt; /* Number of elements in inp_init. */
61 size_t case_size; /* Size of case in bytes. */
64 static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc;
65 static trns_free_func reread_trns_free;
66 static const struct case_source_class input_program_source_class;
67 static bool inside_input_program;
69 /* Returns true if we're parsing the inside of a INPUT
70 PROGRAM...END INPUT PROGRAM construct, false otherwise. */
72 in_input_program (void)
74 return inside_input_program;
78 cmd_input_program (void)
80 struct input_program_pgm *inp;
85 return lex_end_of_command ();
87 inside_input_program = true;
90 enum cmd_result result;
92 result = cmd_parse (CMD_STATE_INPUT_PROGRAM);
93 if (result == CMD_END_SUBLOOP)
95 if (result == CMD_EOF || result == CMD_QUIT || result == CMD_CASCADING_FAILURE)
97 if (result == CMD_EOF)
98 msg (SE, _("Unexpected end-of-file within INPUT PROGRAM."));
100 inside_input_program = false;
104 inside_input_program = false;
106 if (dict_get_next_value_idx (default_dict) == 0)
107 msg (SW, _("No data-input or transformation commands specified "
108 "between INPUT PROGRAM and END INPUT PROGRAM."));
110 /* Mark the boundary between INPUT PROGRAM transformations and
111 ordinary transformations. */
114 /* Figure out how to initialize each input case. */
115 inp = xmalloc (sizeof *inp);
116 inp->init_cnt = dict_get_next_value_idx (default_dict);
117 inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init);
118 for (i = 0; i < inp->init_cnt; i++)
120 for (i = 0; i < dict_get_var_cnt (default_dict); i++)
122 struct variable *var = dict_get_var (default_dict, i);
123 enum value_init_type value_init;
126 value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING;
127 value_init |= var->leave ? INP_INIT_ONCE : INP_REINIT;
129 for (j = 0; j < var->nv; j++)
130 inp->init[j + var->fv] = value_init;
132 for (i = 0; i < inp->init_cnt; i++)
133 assert (inp->init[i] != -1);
134 inp->case_size = dict_get_case_size (default_dict);
136 /* Create vfm_source. */
137 vfm_source = create_case_source (&input_program_source_class, inp);
143 cmd_end_input_program (void)
145 assert (in_input_program ());
146 return CMD_END_SUBLOOP;
149 /* Initializes case C. Called before the first case is read. */
151 init_case (const struct input_program_pgm *inp, struct ccase *c)
155 for (i = 0; i < inp->init_cnt; i++)
156 switch (inp->init[i])
158 case INP_NUMERIC | INP_INIT_ONCE:
159 case_data_rw (c, i)->f = 0.0;
161 case INP_NUMERIC | INP_REINIT:
162 case_data_rw (c, i)->f = SYSMIS;
164 case INP_STRING | INP_INIT_ONCE:
165 case INP_STRING | INP_REINIT:
166 memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
173 /* Clears case C. Called between reading successive records. */
175 clear_case (const struct input_program_pgm *inp, struct ccase *c)
179 for (i = 0; i < inp->init_cnt; i++)
180 switch (inp->init[i])
182 case INP_NUMERIC | INP_INIT_ONCE:
184 case INP_NUMERIC | INP_REINIT:
185 case_data_rw (c, i)->f = SYSMIS;
187 case INP_STRING | INP_INIT_ONCE:
189 case INP_STRING | INP_REINIT:
190 memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s);
197 /* Executes each transformation in turn on a `blank' case.
198 Returns true if successful, false if an I/O error occurred. */
200 input_program_source_read (struct case_source *source,
202 write_case_func *write_case,
203 write_case_data wc_data)
205 struct input_program_pgm *inp = source->aux;
208 /* Nonzero if there were any END CASE commands in the set of
209 transformations. If so, we don't automatically write out
213 /* FIXME? This is the number of cases sent out of the input
214 program, not the number of cases written to the procedure.
215 The difference should only show up in $CASENUM in COMPUTE.
216 We should check behavior against SPSS. */
217 int cases_written = 0;
219 assert (inp != NULL);
221 /* Figure end_case. */
222 for (i = 0; i < f_trns; i++)
223 if (t_trns[i].proc == end_case_trns_proc)
226 /* FIXME: This is an ugly kluge. */
227 for (i = 0; i < f_trns; i++)
228 if (t_trns[i].proc == repeating_data_trns_proc)
229 repeating_data_set_write_case (t_trns[i].private, write_case, wc_data);
234 /* Perform transformations on `blank' case. */
235 for (i = 0; i < f_trns; )
239 if (t_trns[i].proc == end_case_trns_proc)
242 if (!write_case (wc_data))
249 code = t_trns[i].proc (t_trns[i].private, c, cases_written + 1);
274 /* Write the case if appropriate. */
278 if (!write_case (wc_data))
282 /* Blank out the case for the next iteration. */
288 /* Destroys an INPUT PROGRAM source. */
290 input_program_source_destroy (struct case_source *source)
292 struct input_program_pgm *inp = source->aux;
294 cancel_transformations ();
303 static const struct case_source_class input_program_source_class =
307 input_program_source_read,
308 input_program_source_destroy,
314 assert (in_input_program ());
315 add_transformation (end_case_trns_proc, NULL, NULL);
317 return lex_end_of_command ();
320 /* Should never be called, because this is handled in
321 input_program_source_read(). */
323 end_case_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
329 /* REREAD transformation. */
332 struct dfm_reader *reader; /* File to move file pointer back on. */
333 struct expression *column; /* Column to reset file pointer to. */
336 /* Parses REREAD command. */
340 struct file_handle *fh; /* File to be re-read. */
341 struct expression *e; /* Expression for column to set. */
342 struct reread_trns *t; /* Created transformation. */
344 fh = fh_get_default_handle ();
348 if (lex_match_id ("COLUMN"))
354 msg (SE, _("COLUMN subcommand multiply specified."));
356 return CMD_CASCADING_FAILURE;
359 e = expr_parse (default_dict, EXPR_NUMBER);
361 return CMD_CASCADING_FAILURE;
363 else if (lex_match_id ("FILE"))
366 fh = fh_parse (FH_REF_FILE | FH_REF_INLINE);
370 return CMD_CASCADING_FAILURE;
381 t = xmalloc (sizeof *t);
382 t->reader = dfm_open_reader (fh);
384 add_transformation (reread_trns_proc, reread_trns_free, t);
389 /* Executes a REREAD transformation. */
391 reread_trns_proc (void *t_, struct ccase *c, int case_num)
393 struct reread_trns *t = t_;
395 if (t->column == NULL)
396 dfm_reread_record (t->reader, 1);
399 double column = expr_evaluate_num (t->column, c, case_num);
400 if (!finite (column) || column < 1)
402 msg (SE, _("REREAD: Column numbers must be positive finite "
403 "numbers. Column set to 1."));
404 dfm_reread_record (t->reader, 1);
407 dfm_reread_record (t->reader, column);
409 return TRNS_CONTINUE;
412 /* Frees a REREAD transformation.
413 Returns true if successful, false if an I/O error occurred. */
415 reread_trns_free (void *t_)
417 struct reread_trns *t = t_;
418 expr_free (t->column);
419 dfm_close_reader (t->reader);
423 /* Parses END FILE command. */
427 assert (in_input_program ());
429 add_transformation (end_file_trns_proc, NULL, NULL);
431 return lex_end_of_command ();
434 /* Executes an END FILE transformation. */
436 end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED,
439 return TRNS_END_FILE;