X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdata-io%2Finpt-pgm.c;h=f07e119a40808859f376d1f65d5157dbccdceed4;hb=e7d0a9f16192ceeff9243f0ede8e399ee1ef0d44;hp=abda6c930691ce1ddfec33447149d154200e8b56;hpb=30728b09540b323fef43b23dd5f1e4d1e8298c92;p=pspp-builds.git diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index abda6c93..f07e119a 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -24,26 +24,36 @@ #include #include +#include #include +#include #include +#include +#include #include #include -#include #include #include #include #include #include +#include #include #include #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) +/* Private result codes for use within INPUT PROGRAM. */ +enum cmd_result_extensions + { + CMD_END_INPUT_PROGRAM = CMD_PRIVATE_FIRST, + CMD_END_CASE + }; + /* Indicates how a `union value' should be initialized. */ enum value_init_type { @@ -56,14 +66,25 @@ enum value_init_type struct input_program_pgm { + struct trns_chain *trns_chain; + + size_t case_nr; /* Incremented by END CASE transformation. */ + write_case_func *write_case;/* Called by END CASE. */ + write_case_data wc_data; /* Aux data used by END CASE. */ + enum value_init_type *init; /* How to initialize each `union value'. */ size_t init_cnt; /* Number of elements in inp_init. */ size_t case_size; /* Size of case in bytes. */ }; -static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc; +static void destroy_input_program (struct input_program_pgm *); +static trns_proc_func end_case_trns_proc; +static trns_proc_func reread_trns_proc; +static trns_proc_func end_file_trns_proc; static trns_free_func reread_trns_free; + static const struct case_source_class input_program_source_class; + static bool inside_input_program; /* Returns true if we're parsing the inside of a INPUT @@ -74,76 +95,96 @@ in_input_program (void) return inside_input_program; } +/* Emits an END CASE transformation for INP. */ +static void +emit_END_CASE (struct dataset *ds, struct input_program_pgm *inp) +{ + add_transformation (ds, end_case_trns_proc, NULL, inp); +} + int -cmd_input_program (void) +cmd_input_program (struct dataset *ds) { struct input_program_pgm *inp; size_t i; + bool saw_END_CASE = false; - discard_variables (); + discard_variables (ds); if (token != '.') return lex_end_of_command (); + inp = xmalloc (sizeof *inp); + inp->trns_chain = NULL; + inp->init = NULL; + inside_input_program = true; for (;;) { - enum cmd_result result; - lex_get (); - result = cmd_parse (CMD_STATE_INPUT_PROGRAM); - if (result == CMD_END_SUBLOOP) + enum cmd_result result = cmd_parse (ds, CMD_STATE_INPUT_PROGRAM); + if (result == CMD_END_INPUT_PROGRAM) break; - if (result == CMD_EOF || result == CMD_QUIT || result == CMD_CASCADING_FAILURE) + else if (result == CMD_END_CASE) + { + emit_END_CASE (ds, inp); + saw_END_CASE = true; + } + else if (cmd_result_is_failure (result) && result != CMD_FAILURE) { if (result == CMD_EOF) msg (SE, _("Unexpected end-of-file within INPUT PROGRAM.")); - discard_variables (); inside_input_program = false; + discard_variables (ds); + destroy_input_program (inp); return result; } } + if (!saw_END_CASE) + emit_END_CASE (ds, inp); inside_input_program = false; - if (dict_get_next_value_idx (default_dict) == 0) - msg (SW, _("No data-input or transformation commands specified " - "between INPUT PROGRAM and END INPUT PROGRAM.")); - - /* Mark the boundary between INPUT PROGRAM transformations and - ordinary transformations. */ - f_trns = n_trns; + if (dict_get_next_value_idx (dataset_dict (ds)) == 0) + { + msg (SE, _("Input program did not create any variables.")); + discard_variables (ds); + destroy_input_program (inp); + return CMD_FAILURE; + } + + inp->trns_chain = proc_capture_transformations (ds); + trns_chain_finalize (inp->trns_chain); /* Figure out how to initialize each input case. */ - inp = xmalloc (sizeof *inp); - inp->init_cnt = dict_get_next_value_idx (default_dict); + inp->init_cnt = dict_get_next_value_idx (dataset_dict (ds)); inp->init = xnmalloc (inp->init_cnt, sizeof *inp->init); for (i = 0; i < inp->init_cnt; i++) inp->init[i] = -1; - for (i = 0; i < dict_get_var_cnt (default_dict); i++) + for (i = 0; i < dict_get_var_cnt (dataset_dict (ds)); i++) { - struct variable *var = dict_get_var (default_dict, i); + struct variable *var = dict_get_var (dataset_dict (ds), i); enum value_init_type value_init; size_t j; value_init = var->type == NUMERIC ? INP_NUMERIC : INP_STRING; - value_init |= var->reinit ? INP_REINIT : INP_INIT_ONCE; + value_init |= var->leave ? INP_INIT_ONCE : INP_REINIT; for (j = 0; j < var->nv; j++) inp->init[j + var->fv] = value_init; } for (i = 0; i < inp->init_cnt; i++) assert (inp->init[i] != -1); - inp->case_size = dict_get_case_size (default_dict); + inp->case_size = dict_get_case_size (dataset_dict (ds)); - /* Create vfm_source. */ - vfm_source = create_case_source (&input_program_source_class, inp); + proc_set_source (ds, + create_case_source (&input_program_source_class, inp)); return CMD_SUCCESS; } int -cmd_end_input_program (void) +cmd_end_input_program (struct dataset *ds UNUSED) { assert (in_input_program ()); - return CMD_END_SUBLOOP; + return CMD_END_INPUT_PROGRAM; } /* Initializes case C. Called before the first case is read. */ @@ -166,7 +207,7 @@ init_case (const struct input_program_pgm *inp, struct ccase *c) memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s); break; default: - assert (0); + NOT_REACHED (); } } @@ -190,7 +231,7 @@ clear_case (const struct input_program_pgm *inp, struct ccase *c) memset (case_data_rw (c, i)->s, ' ', sizeof case_data_rw (c, i)->s); break; default: - assert (0); + NOT_REACHED (); } } @@ -203,85 +244,29 @@ input_program_source_read (struct case_source *source, write_case_data wc_data) { struct input_program_pgm *inp = source->aux; - size_t i; - - /* Nonzero if there were any END CASE commands in the set of - transformations. If so, we don't automatically write out - cases. */ - int end_case = 0; - - /* FIXME? This is the number of cases sent out of the input - program, not the number of cases written to the procedure. - The difference should only show up in $CASENUM in COMPUTE. - We should check behavior against SPSS. */ - int cases_written = 0; - - assert (inp != NULL); - - /* Figure end_case. */ - for (i = 0; i < f_trns; i++) - if (t_trns[i].proc == end_case_trns_proc) - end_case = 1; - - /* FIXME: This is an ugly kluge. */ - for (i = 0; i < f_trns; i++) - if (t_trns[i].proc == repeating_data_trns_proc) - repeating_data_set_write_case (t_trns[i].private, write_case, wc_data); - init_case (inp, c); - for (;;) + inp->case_nr = 1; + inp->write_case = write_case; + inp->wc_data = wc_data; + for (init_case (inp, c); ; clear_case (inp, c)) { - /* Perform transformations on `blank' case. */ - for (i = 0; i < f_trns; ) - { - int code; - - if (t_trns[i].proc == end_case_trns_proc) - { - cases_written++; - if (!write_case (wc_data)) - return false; - clear_case (inp, c); - i++; - continue; - } - - code = t_trns[i].proc (t_trns[i].private, c, cases_written + 1); - switch (code) - { - case TRNS_CONTINUE: - i++; - break; - - case TRNS_DROP_CASE: - abort (); - - case TRNS_ERROR: - return false; - - case TRNS_NEXT_CASE: - goto next_case; - - case TRNS_END_FILE: - return true; - - default: - i = code; - break; - } - } - - /* Write the case if appropriate. */ - if (!end_case) - { - cases_written++; - if (!write_case (wc_data)) - return false; - } + enum trns_result result = trns_chain_execute (inp->trns_chain, c, + &inp->case_nr); + if (result == TRNS_ERROR) + return false; + else if (result == TRNS_END_FILE) + return true; + } +} - /* Blank out the case for the next iteration. */ - next_case: - clear_case (inp, c); +static void +destroy_input_program (struct input_program_pgm *pgm) +{ + if (pgm != NULL) + { + trns_chain_destroy (pgm->trns_chain); + free (pgm->init); + free (pgm); } } @@ -291,13 +276,7 @@ input_program_source_destroy (struct case_source *source) { struct input_program_pgm *inp = source->aux; - cancel_transformations (); - - if (inp != NULL) - { - free (inp->init); - free (inp); - } + destroy_input_program (inp); } static const struct case_source_class input_program_source_class = @@ -309,21 +288,26 @@ static const struct case_source_class input_program_source_class = }; int -cmd_end_case (void) +cmd_end_case (struct dataset *ds UNUSED) { assert (in_input_program ()); - add_transformation (end_case_trns_proc, NULL, NULL); - + if (token == '.') + return CMD_END_CASE; return lex_end_of_command (); } -/* Should never be called, because this is handled in - input_program_source_read(). */ +/* Sends the current case as the source's output. */ int -end_case_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED, - int case_num UNUSED) +end_case_trns_proc (void *inp_, struct ccase *c, casenumber case_nr UNUSED) { - abort (); + struct input_program_pgm *inp = inp_; + + if (!inp->write_case (inp->wc_data)) + return TRNS_ERROR; + + inp->case_nr++; + clear_case (inp, c); + return TRNS_CONTINUE; } /* REREAD transformation. */ @@ -335,7 +319,7 @@ struct reread_trns /* Parses REREAD command. */ int -cmd_reread (void) +cmd_reread (struct dataset *ds) { struct file_handle *fh; /* File to be re-read. */ struct expression *e; /* Expression for column to set. */ @@ -356,7 +340,7 @@ cmd_reread (void) return CMD_CASCADING_FAILURE; } - e = expr_parse (default_dict, EXPR_NUMBER); + e = expr_parse (ds, EXPR_NUMBER); if (!e) return CMD_CASCADING_FAILURE; } @@ -369,7 +353,6 @@ cmd_reread (void) expr_free (e); return CMD_CASCADING_FAILURE; } - lex_get (); } else { @@ -381,14 +364,14 @@ cmd_reread (void) t = xmalloc (sizeof *t); t->reader = dfm_open_reader (fh); t->column = e; - add_transformation (reread_trns_proc, reread_trns_free, t); + add_transformation (ds, reread_trns_proc, reread_trns_free, t); return CMD_SUCCESS; } /* Executes a REREAD transformation. */ static int -reread_trns_proc (void *t_, struct ccase *c, int case_num) +reread_trns_proc (void *t_, struct ccase *c, casenumber case_num) { struct reread_trns *t = t_; @@ -422,11 +405,11 @@ reread_trns_free (void *t_) /* Parses END FILE command. */ int -cmd_end_file (void) +cmd_end_file (struct dataset *ds) { assert (in_input_program ()); - add_transformation (end_file_trns_proc, NULL, NULL); + add_transformation (ds, end_file_trns_proc, NULL, NULL); return lex_end_of_command (); } @@ -434,7 +417,7 @@ cmd_end_file (void) /* Executes an END FILE transformation. */ static int end_file_trns_proc (void *trns_ UNUSED, struct ccase *c UNUSED, - int case_num UNUSED) + casenumber case_num UNUSED) { return TRNS_END_FILE; }