X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdata-io%2Finpt-pgm.c;h=51c369810f9d2872810a00341a0623321f4f04c8;hb=a4ae68f966bc574326d429119878e733069ced14;hp=90f22ec2a11712b43808f8a00eac94b5491d4444;hpb=147ca04d11f632e63cef3ce395b471a12897f5f9;p=pspp-builds.git diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index 90f22ec2..51c36981 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -26,7 +26,10 @@ #include #include +#include #include +#include +#include #include #include #include @@ -39,11 +42,17 @@ #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 +65,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,45 +94,67 @@ in_input_program (void) return inside_input_program; } +/* Emits an END CASE transformation for INP. */ +static void +emit_END_CASE (struct input_program_pgm *inp) +{ + add_transformation (end_case_trns_proc, NULL, inp); +} + int cmd_input_program (void) { struct input_program_pgm *inp; size_t i; + bool saw_END_CASE = false; discard_variables (); 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) + 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 (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 (); + destroy_input_program (inp); return result; } } + if (!saw_END_CASE) + emit_END_CASE (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 (default_dict) == 0) + { + msg (SE, _("Input program did not create any variables.")); + discard_variables (); + destroy_input_program (inp); + return CMD_FAILURE; + } + + inp->trns_chain = proc_capture_transformations (); + 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 = xnmalloc (inp->init_cnt, sizeof *inp->init); for (i = 0; i < inp->init_cnt; i++) @@ -133,8 +175,7 @@ cmd_input_program (void) assert (inp->init[i] != -1); inp->case_size = dict_get_case_size (default_dict); - /* Create vfm_source. */ - vfm_source = create_case_source (&input_program_source_class, inp); + proc_set_source (create_case_source (&input_program_source_class, inp)); return CMD_SUCCESS; } @@ -143,7 +184,7 @@ int cmd_end_input_program (void) { assert (in_input_program ()); - return CMD_END_SUBLOOP; + return CMD_END_INPUT_PROGRAM; } /* Initializes case C. Called before the first case is read. */ @@ -203,80 +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; - 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); } } @@ -286,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 = @@ -307,18 +291,23 @@ int cmd_end_case (void) { 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, int 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. */