From: Ben Pfaff Date: Fri, 5 May 2006 04:53:12 +0000 (+0000) Subject: Continue reforming procedure execution. In this phase, move X-Git-Tag: v0.6.0~900 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81fff61a96bece351e381ad3fef8ab1248a952ba;p=pspp-builds.git Continue reforming procedure execution. In this phase, move procedure.c and procedure.h from src to src/data. Update makefiles and #includes accordingly. --- diff --git a/src/ChangeLog b/src/ChangeLog index 0fded64c..d64ac34a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,15 @@ +Thu May 4 21:47:48 2006 Ben Pfaff + + Continue reforming procedure execution. In this phase, move + procedure.c and procedure.h from src to src/data. Update + makefiles and #includes accordingly. + + * automake.mk: Remove special rule for src/procedure.o. + + * procedure.c: Moved to src/data. + + * procedure.h: Moved to src/data. + Wed May 3 22:24:34 2006 Ben Pfaff Continue reforming procedure execution. In this phase, get rid of diff --git a/src/automake.mk b/src/automake.mk index 64b49284..3d309a6c 100644 --- a/src/automake.mk +++ b/src/automake.mk @@ -14,12 +14,3 @@ include $(top_srcdir)/src/ui/gui/automake.mk endif AM_CPPFLAGS += -DPKGDATADIR=\"$(pkgdatadir)\" - -src/procedure.o: AM_CPPFLAGS += \ - -I$(top_srcdir)/src/language \ - -I$(top_srcdir)/src/language/control \ - -I$(top_srcdir)/src/output \ - -I$(top_srcdir)/src/data \ - -I$(top_srcdir)/src/libpspp - - diff --git a/src/data/ChangeLog b/src/data/ChangeLog index 49c1af84..0da663bf 100644 --- a/src/data/ChangeLog +++ b/src/data/ChangeLog @@ -1,3 +1,13 @@ +Thu May 4 21:50:11 2006 Ben Pfaff + + Continue reforming procedure execution. In this phase, move + procedure.c and procedure.h from src to src/data. Update + makefiles and #includes accordingly. + + * procedure.c: Moved here from src/. + + * procedure.h: Moved here from src/. + Wed May 3 22:42:12 2006 Ben Pfaff Continue reforming procedure execution. In this phase, get rid of diff --git a/src/data/automake.mk b/src/data/automake.mk index 2084e4f6..d79828b7 100644 --- a/src/data/automake.mk +++ b/src/data/automake.mk @@ -38,6 +38,8 @@ src_data_libdata_a_SOURCES = \ src/data/missing-values.h \ src/data/make-file.c \ src/data/make-file.h \ + src/data/procedure.c \ + src/data/procedure.h \ src/data/por-file-reader.c \ src/data/por-file-reader.h \ src/data/por-file-writer.c \ diff --git a/src/data/procedure.c b/src/data/procedure.c new file mode 100644 index 00000000..4a5e9ddb --- /dev/null +++ b/src/data/procedure.c @@ -0,0 +1,1015 @@ +/* PSPP - computes sample statistics. + Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Written by Ben Pfaff . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include + +#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) + +/* + Virtual File Manager (vfm): + + vfm is used to process data files. It uses the model that + data is read from one stream (the data source), processed, + then written to another (the data sink). The data source is + then deleted and the data sink becomes the data source for the + next procedure. */ + +/* Procedure execution data. */ +struct write_case_data + { + /* Function to call for each case. */ + bool (*proc_func) (struct ccase *, void *); /* Function. */ + void *aux; /* Auxiliary data. */ + + struct ccase trns_case; /* Case used for transformations. */ + struct ccase sink_case; /* Case written to sink, if + compaction is necessary. */ + size_t cases_written; /* Cases output so far. */ + size_t cases_analyzed; /* Cases passed to procedure so far. */ + }; + +/* Cases are read from vfm_source, + pass through permanent_trns_chain (which transforms them into + the format described by permanent_dict), + are written to vfm_sink, + pass through temporary_trns_chain (which transforms them into + the format described by default_dict), + and are finally passed to the procedure. */ +static struct case_source *vfm_source; +static struct trns_chain *permanent_trns_chain; +static struct dictionary *permanent_dict; +static struct case_sink *vfm_sink; +static struct trns_chain *temporary_trns_chain; +struct dictionary *default_dict; + +/* The transformation chain that the next transformation will be + added to. */ +static struct trns_chain *cur_trns_chain; + +/* The compactor used to compact a case, if necessary; + otherwise a null pointer. */ +static struct dict_compactor *compactor; + +/* Time at which vfm was last invoked. */ +static time_t last_vfm_invocation; + +/* Lag queue. */ +int n_lag; /* Number of cases to lag. */ +static int lag_count; /* Number of cases in lag_queue so far. */ +static int lag_head; /* Index where next case will be added. */ +static struct ccase *lag_queue; /* Array of n_lag ccase * elements. */ + +static void add_case_limit_trns (void); +static void add_filter_trns (void); +static void add_process_if_trns (void); + +static bool internal_procedure (bool (*proc_func) (struct ccase *, void *), + void *aux); +static void update_last_vfm_invocation (void); +static void create_trns_case (struct ccase *, struct dictionary *); +static void open_active_file (void); +static bool write_case (struct write_case_data *wc_data); +static void lag_case (const struct ccase *c); +static void clear_case (struct ccase *c); +static bool close_active_file (void); + +/* Public functions. */ + +/* Returns the last time the data was read. */ +time_t +time_of_last_procedure (void) +{ + if (last_vfm_invocation == 0) + update_last_vfm_invocation (); + return last_vfm_invocation; +} + +/* Reads the data from the input program and writes it to a new + active file. For each case we read from the input program, we + do the following: + + 1. Execute permanent transformations. If these drop the case, + start the next case from step 1. + + 2. Write case to replacement active file. + + 3. Execute temporary transformations. If these drop the case, + start the next case from step 1. + + 4. Pass case to PROC_FUNC, passing AUX as auxiliary data. + + Returns true if successful, false if an I/O error occurred. */ +bool +procedure (bool (*proc_func) (struct ccase *, void *), void *aux) +{ + if (proc_func == NULL + && case_source_is_class (vfm_source, &storage_source_class) + && vfm_sink == NULL + && temporary_trns_chain == NULL + && trns_chain_is_empty (permanent_trns_chain)) + { + expr_free (process_if_expr); + process_if_expr = NULL; + dict_set_case_limit (default_dict, 0); + dict_clear_vectors (default_dict); + + update_last_vfm_invocation (); + return true; + } + else + { + bool ok; + + open_active_file (); + ok = internal_procedure (proc_func, aux); + ok = close_active_file () && ok; + + return ok; + } +} + +/* Callback function for multipass_procedure(). */ +static bool +multipass_callback (struct ccase *c, void *cf_) +{ + struct casefile *cf = cf_; + return casefile_append (cf, c); +} + +/* Procedure that allows multiple passes over the input data. + The entire active file is passed to PROC_FUNC, with the given + AUX as auxiliary data, as a unit. */ +bool +multipass_procedure (bool (*proc_func) (const struct casefile *, void *aux), + void *aux) +{ + if (case_source_is_class (vfm_source, &storage_source_class) + && vfm_sink == NULL + && temporary_trns_chain == NULL + && trns_chain_is_empty (permanent_trns_chain)) + { + proc_func (storage_source_get_casefile (vfm_source), aux); + + expr_free (process_if_expr); + process_if_expr = NULL; + dict_set_case_limit (default_dict, 0); + dict_clear_vectors (default_dict); + + update_last_vfm_invocation (); + return true; + } + else + { + struct casefile *cf; + bool ok; + + assert (proc_func != NULL); + + cf = casefile_create (dict_get_next_value_idx (default_dict)); + + open_active_file (); + ok = internal_procedure (multipass_callback, cf); + ok = proc_func (cf, aux) && ok; + ok = close_active_file () && ok; + + casefile_destroy (cf); + + return ok; + } +} + +/* Executes a procedure, as procedure(), except that the caller + is responsible for calling open_active_file() and + close_active_file(). + Returns true if successful, false if an I/O error occurred. */ +static bool +internal_procedure (bool (*proc_func) (struct ccase *, void *), void *aux) +{ + struct write_case_data wc_data; + bool ok; + + wc_data.proc_func = proc_func; + wc_data.aux = aux; + create_trns_case (&wc_data.trns_case, default_dict); + case_create (&wc_data.sink_case, dict_get_next_value_idx (default_dict)); + wc_data.cases_written = 0; + + update_last_vfm_invocation (); + + ok = (vfm_source == NULL + || vfm_source->class->read (vfm_source, + &wc_data.trns_case, + write_case, &wc_data)); + + case_destroy (&wc_data.sink_case); + case_destroy (&wc_data.trns_case); + + return ok; +} + +/* Updates last_vfm_invocation. */ +static void +update_last_vfm_invocation (void) +{ + last_vfm_invocation = time (NULL); +} + +/* Creates and returns a case, initializing it from the vectors + that say which `value's need to be initialized just once, and + which ones need to be re-initialized before every case. */ +static void +create_trns_case (struct ccase *trns_case, struct dictionary *dict) +{ + size_t var_cnt = dict_get_var_cnt (dict); + size_t i; + + case_create (trns_case, dict_get_next_value_idx (dict)); + for (i = 0; i < var_cnt; i++) + { + struct variable *v = dict_get_var (dict, i); + union value *value = case_data_rw (trns_case, v->fv); + + if (v->type == NUMERIC) + value->f = v->leave ? 0.0 : SYSMIS; + else + memset (value->s, ' ', v->width); + } +} + +/* Makes all preparations for reading from the data source and writing + to the data sink. */ +static void +open_active_file (void) +{ + add_case_limit_trns (); + add_filter_trns (); + add_process_if_trns (); + + /* Finalize transformations. */ + trns_chain_finalize (cur_trns_chain); + + /* Make permanent_dict refer to the dictionary right before + data reaches the sink. */ + if (permanent_dict == NULL) + permanent_dict = default_dict; + + /* Figure out compaction. */ + compactor = (dict_needs_compaction (permanent_dict) + ? dict_make_compactor (permanent_dict) + : NULL); + + /* Prepare sink. */ + if (vfm_sink == NULL) + vfm_sink = create_case_sink (&storage_sink_class, permanent_dict, NULL); + if (vfm_sink->class->open != NULL) + vfm_sink->class->open (vfm_sink); + + /* Allocate memory for lag queue. */ + if (n_lag > 0) + { + int i; + + lag_count = 0; + lag_head = 0; + lag_queue = xnmalloc (n_lag, sizeof *lag_queue); + for (i = 0; i < n_lag; i++) + case_nullify (&lag_queue[i]); + } +} + +/* Transforms trns_case and writes it to the replacement active + file if advisable. Returns true if more cases can be + accepted, false otherwise. Do not call this function again + after it has returned false once. */ +static bool +write_case (struct write_case_data *wc_data) +{ + enum trns_result retval; + size_t case_nr; + + /* Execute permanent transformations. */ + case_nr = wc_data->cases_written + 1; + retval = trns_chain_execute (permanent_trns_chain, + &wc_data->trns_case, &case_nr); + if (retval != TRNS_CONTINUE) + goto done; + + /* Write case to LAG queue. */ + if (n_lag) + lag_case (&wc_data->trns_case); + + /* Write case to replacement active file. */ + wc_data->cases_written++; + if (vfm_sink->class->write != NULL) + { + if (compactor != NULL) + { + dict_compactor_compact (compactor, &wc_data->sink_case, + &wc_data->trns_case); + vfm_sink->class->write (vfm_sink, &wc_data->sink_case); + } + else + vfm_sink->class->write (vfm_sink, &wc_data->trns_case); + } + + /* Execute temporary transformations. */ + if (temporary_trns_chain != NULL) + { + retval = trns_chain_execute (temporary_trns_chain, + &wc_data->trns_case, + &wc_data->cases_written); + if (retval != TRNS_CONTINUE) + goto done; + } + + /* Pass case to procedure. */ + wc_data->cases_analyzed++; + if (wc_data->proc_func != NULL) + if (!wc_data->proc_func (&wc_data->trns_case, wc_data->aux)) + retval = TRNS_ERROR; + + done: + clear_case (&wc_data->trns_case); + return retval != TRNS_ERROR; +} + +/* Add C to the lag queue. */ +static void +lag_case (const struct ccase *c) +{ + if (lag_count < n_lag) + lag_count++; + case_destroy (&lag_queue[lag_head]); + case_clone (&lag_queue[lag_head], c); + if (++lag_head >= n_lag) + lag_head = 0; +} + +/* Clears the variables in C that need to be cleared between + processing cases. */ +static void +clear_case (struct ccase *c) +{ + size_t var_cnt = dict_get_var_cnt (default_dict); + size_t i; + + for (i = 0; i < var_cnt; i++) + { + struct variable *v = dict_get_var (default_dict, i); + if (!v->leave) + { + if (v->type == NUMERIC) + case_data_rw (c, v->fv)->f = SYSMIS; + else + memset (case_data_rw (c, v->fv)->s, ' ', v->width); + } + } +} + +/* Closes the active file. */ +static bool +close_active_file (void) +{ + /* Free memory for lag queue, and turn off lagging. */ + if (n_lag > 0) + { + int i; + + for (i = 0; i < n_lag; i++) + case_destroy (&lag_queue[i]); + free (lag_queue); + n_lag = 0; + } + + /* Dictionary from before TEMPORARY becomes permanent. */ + proc_cancel_temporary_transformations (); + + /* Finish compaction. */ + if (compactor != NULL) + { + dict_compactor_destroy (compactor); + dict_compact_values (default_dict); + } + + /* Free data source. */ + free_case_source (vfm_source); + vfm_source = NULL; + + /* Old data sink becomes new data source. */ + if (vfm_sink->class->make_source != NULL) + vfm_source = vfm_sink->class->make_source (vfm_sink); + free_case_sink (vfm_sink); + vfm_sink = NULL; + + /* Cancel TEMPORARY, PROCESS IF, FILTER, N OF CASES, vectors, + and get rid of all the transformations. */ + dict_clear_vectors (default_dict); + permanent_dict = NULL; + return proc_cancel_all_transformations (); +} + +/* Returns a pointer to the lagged case from N_BEFORE cases before the + current one, or NULL if there haven't been that many cases yet. */ +struct ccase * +lagged_case (int n_before) +{ + assert (n_before >= 1 ); + assert (n_before <= n_lag); + + if (n_before <= lag_count) + { + int index = lag_head - n_before; + if (index < 0) + index += n_lag; + return &lag_queue[index]; + } + else + return NULL; +} + +/* Represents auxiliary data for handling SPLIT FILE. */ +struct split_aux_data + { + size_t case_count; /* Number of cases so far. */ + struct ccase prev_case; /* Data in previous case. */ + + /* Functions to call... */ + void (*begin_func) (void *); /* ...before data. */ + bool (*proc_func) (struct ccase *, void *); /* ...with data. */ + void (*end_func) (void *); /* ...after data. */ + void *func_aux; /* Auxiliary data. */ + }; + +static int equal_splits (const struct ccase *, const struct ccase *); +static bool procedure_with_splits_callback (struct ccase *, void *); +static void dump_splits (struct ccase *); + +/* Like procedure(), but it automatically breaks the case stream + into SPLIT FILE break groups. Before each group of cases with + identical SPLIT FILE variable values, BEGIN_FUNC is called. + Then PROC_FUNC is called with each case in the group. + END_FUNC is called when the group is finished. FUNC_AUX is + passed to each of the functions as auxiliary data. + + If the active file is empty, none of BEGIN_FUNC, PROC_FUNC, + and END_FUNC will be called at all. + + If SPLIT FILE is not in effect, then there is one break group + (if the active file is nonempty), and BEGIN_FUNC and END_FUNC + will be called once. + + Returns true if successful, false if an I/O error occurred. */ +bool +procedure_with_splits (void (*begin_func) (void *aux), + bool (*proc_func) (struct ccase *, void *aux), + void (*end_func) (void *aux), + void *func_aux) +{ + struct split_aux_data split_aux; + bool ok; + + split_aux.case_count = 0; + case_nullify (&split_aux.prev_case); + split_aux.begin_func = begin_func; + split_aux.proc_func = proc_func; + split_aux.end_func = end_func; + split_aux.func_aux = func_aux; + + open_active_file (); + ok = internal_procedure (procedure_with_splits_callback, &split_aux); + if (split_aux.case_count > 0 && end_func != NULL) + end_func (func_aux); + if (!close_active_file ()) + ok = false; + + case_destroy (&split_aux.prev_case); + + return ok; +} + +/* procedure() callback used by procedure_with_splits(). */ +static bool +procedure_with_splits_callback (struct ccase *c, void *split_aux_) +{ + struct split_aux_data *split_aux = split_aux_; + + /* Start a new series if needed. */ + if (split_aux->case_count == 0 + || !equal_splits (c, &split_aux->prev_case)) + { + if (split_aux->case_count > 0 && split_aux->end_func != NULL) + split_aux->end_func (split_aux->func_aux); + + dump_splits (c); + case_destroy (&split_aux->prev_case); + case_clone (&split_aux->prev_case, c); + + if (split_aux->begin_func != NULL) + split_aux->begin_func (split_aux->func_aux); + } + + split_aux->case_count++; + if (split_aux->proc_func != NULL) + return split_aux->proc_func (c, split_aux->func_aux); + else + return true; +} + +/* Compares the SPLIT FILE variables in cases A and B and returns + nonzero only if they differ. */ +static int +equal_splits (const struct ccase *a, const struct ccase *b) +{ + return case_compare (a, b, + dict_get_split_vars (default_dict), + dict_get_split_cnt (default_dict)) == 0; +} + +/* Dumps out the values of all the split variables for the case C. */ +static void +dump_splits (struct ccase *c) +{ + struct variable *const *split; + struct tab_table *t; + size_t split_cnt; + int i; + + split_cnt = dict_get_split_cnt (default_dict); + if (split_cnt == 0) + return; + + t = tab_create (3, split_cnt + 1, 0); + tab_dim (t, tab_natural_dimensions); + tab_vline (t, TAL_GAP, 1, 0, split_cnt); + tab_vline (t, TAL_GAP, 2, 0, split_cnt); + tab_text (t, 0, 0, TAB_NONE, _("Variable")); + tab_text (t, 1, 0, TAB_LEFT, _("Value")); + tab_text (t, 2, 0, TAB_LEFT, _("Label")); + split = dict_get_split_vars (default_dict); + for (i = 0; i < split_cnt; i++) + { + struct variable *v = split[i]; + char temp_buf[80]; + const char *val_lab; + + assert (v->type == NUMERIC || v->type == ALPHA); + tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name); + + data_out (temp_buf, &v->print, case_data (c, v->fv)); + + temp_buf[v->print.w] = 0; + tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf); + + val_lab = val_labs_find (v->val_labs, *case_data (c, v->fv)); + if (val_lab) + tab_text (t, 2, i + 1, TAB_LEFT, val_lab); + } + tab_flags (t, SOMF_NO_TITLE); + tab_submit (t); +} + +/* Represents auxiliary data for handling SPLIT FILE in a + multipass procedure. */ +struct multipass_split_aux_data + { + struct ccase prev_case; /* Data in previous case. */ + struct casefile *casefile; /* Accumulates data for a split. */ + + /* Function to call with the accumulated data. */ + bool (*split_func) (const struct casefile *, void *); + void *func_aux; /* Auxiliary data. */ + }; + +static bool multipass_split_callback (struct ccase *c, void *aux_); +static bool multipass_split_output (struct multipass_split_aux_data *); + +/* Returns true if successful, false if an I/O error occurred. */ +bool +multipass_procedure_with_splits (bool (*split_func) (const struct casefile *, + void *), + void *func_aux) +{ + struct multipass_split_aux_data aux; + bool ok; + + assert (split_func != NULL); + + open_active_file (); + + case_nullify (&aux.prev_case); + aux.casefile = NULL; + aux.split_func = split_func; + aux.func_aux = func_aux; + + ok = internal_procedure (multipass_split_callback, &aux); + if (aux.casefile != NULL) + ok = multipass_split_output (&aux) && ok; + case_destroy (&aux.prev_case); + + if (!close_active_file ()) + ok = false; + + return ok; +} + +/* procedure() callback used by multipass_procedure_with_splits(). */ +static bool +multipass_split_callback (struct ccase *c, void *aux_) +{ + struct multipass_split_aux_data *aux = aux_; + bool ok = true; + + /* Start a new series if needed. */ + if (aux->casefile == NULL || !equal_splits (c, &aux->prev_case)) + { + /* Pass any cases to split_func. */ + if (aux->casefile != NULL) + ok = multipass_split_output (aux); + + /* Start a new casefile. */ + aux->casefile = casefile_create (dict_get_next_value_idx (default_dict)); + + /* Record split values. */ + dump_splits (c); + case_destroy (&aux->prev_case); + case_clone (&aux->prev_case, c); + } + + return casefile_append (aux->casefile, c) && ok; +} + +static bool +multipass_split_output (struct multipass_split_aux_data *aux) +{ + bool ok; + + assert (aux->casefile != NULL); + ok = aux->split_func (aux->casefile, aux->func_aux); + casefile_destroy (aux->casefile); + aux->casefile = NULL; + + return ok; +} + +/* Discards all the current state in preparation for a data-input + command like DATA LIST or GET. */ +void +discard_variables (void) +{ + dict_clear (default_dict); + fh_set_default_handle (NULL); + + n_lag = 0; + + if (vfm_source != NULL) + { + free_case_source (vfm_source); + vfm_source = NULL; + } + + proc_cancel_all_transformations (); + + expr_free (process_if_expr); + process_if_expr = NULL; + + proc_cancel_temporary_transformations (); +} + +/* Returns the current set of permanent transformations, + and clears the permanent transformations. + For use by INPUT PROGRAM. */ +struct trns_chain * +proc_capture_transformations (void) +{ + struct trns_chain *chain; + + assert (temporary_trns_chain == NULL); + chain = permanent_trns_chain; + cur_trns_chain = permanent_trns_chain = trns_chain_create (); + return chain; +} + +/* Adds a transformation that processes a case with PROC and + frees itself with FREE to the current set of transformations. + The functions are passed AUX as auxiliary data. */ +void +add_transformation (trns_proc_func *proc, trns_free_func *free, void *aux) +{ + trns_chain_append (cur_trns_chain, NULL, proc, free, aux); +} + +/* Adds a transformation that processes a case with PROC and + frees itself with FREE to the current set of transformations. + When parsing of the block of transformations is complete, + FINALIZE will be called. + The functions are passed AUX as auxiliary data. */ +void +add_transformation_with_finalizer (trns_finalize_func *finalize, + trns_proc_func *proc, + trns_free_func *free, void *aux) +{ + trns_chain_append (cur_trns_chain, finalize, proc, free, aux); +} + +/* Returns the index of the next transformation. + This value can be returned by a transformation procedure + function to indicate a "jump" to that transformation. */ +size_t +next_transformation (void) +{ + return trns_chain_next (cur_trns_chain); +} + +/* Returns true if the next call to add_transformation() will add + a temporary transformation, false if it will add a permanent + transformation. */ +bool +proc_in_temporary_transformations (void) +{ + return temporary_trns_chain != NULL; +} + +/* Marks the start of temporary transformations. + Further calls to add_transformation() will add temporary + transformations. */ +void +proc_start_temporary_transformations (void) +{ + if (!proc_in_temporary_transformations ()) + { + add_case_limit_trns (); + + permanent_dict = dict_clone (default_dict); + trns_chain_finalize (permanent_trns_chain); + temporary_trns_chain = cur_trns_chain = trns_chain_create (); + } +} + +/* Converts all the temporary transformations, if any, to + permanent transformations. Further transformations will be + permanent. + Returns true if anything changed, false otherwise. */ +bool +proc_make_temporary_transformations_permanent (void) +{ + if (proc_in_temporary_transformations ()) + { + trns_chain_finalize (temporary_trns_chain); + trns_chain_splice (permanent_trns_chain, temporary_trns_chain); + temporary_trns_chain = NULL; + + dict_destroy (permanent_dict); + permanent_dict = NULL; + + return true; + } + else + return false; +} + +/* Cancels all temporary transformations, if any. Further + transformations will be permanent. + Returns true if anything changed, false otherwise. */ +bool +proc_cancel_temporary_transformations (void) +{ + if (proc_in_temporary_transformations ()) + { + dict_destroy (default_dict); + default_dict = permanent_dict; + permanent_dict = NULL; + + trns_chain_destroy (temporary_trns_chain); + temporary_trns_chain = NULL; + + return true; + } + else + return false; +} + +/* Cancels all transformations, if any. + Returns true if successful, false on I/O error. */ +bool +proc_cancel_all_transformations (void) +{ + bool ok; + ok = trns_chain_destroy (permanent_trns_chain); + ok = trns_chain_destroy (temporary_trns_chain) && ok; + permanent_trns_chain = cur_trns_chain = trns_chain_create (); + temporary_trns_chain = NULL; + return ok; +} + +/* Initializes procedure handling. */ +void +proc_init (void) +{ + default_dict = dict_create (); + proc_cancel_all_transformations (); +} + +/* Finishes up procedure handling. */ +void +proc_done (void) +{ + discard_variables (); +} + +/* Sets SINK as the destination for procedure output from the + next procedure. */ +void +proc_set_sink (struct case_sink *sink) +{ + assert (vfm_sink == NULL); + vfm_sink = sink; +} + +/* Sets SOURCE as the source for procedure input for the next + procedure. */ +void +proc_set_source (struct case_source *source) +{ + assert (vfm_source == NULL); + vfm_source = source; +} + +/* Returns true if a source for the next procedure has been + configured, false otherwise. */ +bool +proc_has_source (void) +{ + return vfm_source != NULL; +} + +/* Returns the output from the previous procedure. + For use only immediately after executing a procedure. + The returned casefile is owned by the caller; it will not be + automatically used for the next procedure's input. */ +struct casefile * +proc_capture_output (void) +{ + struct casefile *casefile; + + /* Try to make sure that this function is called immediately + after procedure() or a similar function. */ + assert (vfm_source != NULL); + assert (case_source_is_class (vfm_source, &storage_source_class)); + assert (trns_chain_is_empty (permanent_trns_chain)); + assert (!proc_in_temporary_transformations ()); + + casefile = storage_source_decapsulate (vfm_source); + vfm_source = NULL; + + return casefile; +} + +static trns_proc_func case_limit_trns_proc; +static trns_free_func case_limit_trns_free; + +/* Adds a transformation that limits the number of cases that may + pass through, if default_dict has a case limit. */ +static void +add_case_limit_trns (void) +{ + size_t case_limit = dict_get_case_limit (default_dict); + if (case_limit != 0) + { + size_t *cases_remaining = xmalloc (sizeof *cases_remaining); + *cases_remaining = case_limit; + add_transformation (case_limit_trns_proc, case_limit_trns_free, + cases_remaining); + dict_set_case_limit (default_dict, 0); + } +} + +/* Limits the maximum number of cases processed to + *CASES_REMAINING. */ +static int +case_limit_trns_proc (void *cases_remaining_, + struct ccase *c UNUSED, int case_nr UNUSED) +{ + size_t *cases_remaining = cases_remaining_; + if (*cases_remaining > 0) + { + *cases_remaining--; + return TRNS_CONTINUE; + } + else + return TRNS_DROP_CASE; +} + +/* Frees the data associated with a case limit transformation. */ +static bool +case_limit_trns_free (void *cases_remaining_) +{ + size_t *cases_remaining = cases_remaining_; + free (cases_remaining); + return true; +} + +static trns_proc_func filter_trns_proc; + +/* Adds a temporary transformation to filter data according to + the variable specified on FILTER, if any. */ +static void +add_filter_trns (void) +{ + struct variable *filter_var = dict_get_filter (default_dict); + if (filter_var != NULL) + { + proc_start_temporary_transformations (); + add_transformation (filter_trns_proc, NULL, filter_var); + } +} + +/* FILTER transformation. */ +static int +filter_trns_proc (void *filter_var_, + struct ccase *c UNUSED, int case_nr UNUSED) + +{ + struct variable *filter_var = filter_var_; + double f = case_num (c, filter_var->fv); + return (f != 0.0 && !mv_is_num_missing (&filter_var->miss, f) + ? TRNS_CONTINUE : TRNS_DROP_CASE); +} + +static trns_proc_func process_if_trns_proc; +static trns_free_func process_if_trns_free; + +/* Adds a temporary transformation to filter data according to + the expression specified on PROCESS IF, if any. */ +static void +add_process_if_trns (void) +{ + if (process_if_expr != NULL) + { + proc_start_temporary_transformations (); + add_transformation (process_if_trns_proc, process_if_trns_free, + process_if_expr); + process_if_expr = NULL; + } +} + +/* PROCESS IF transformation. */ +static int +process_if_trns_proc (void *expression_, + struct ccase *c UNUSED, int case_nr UNUSED) + +{ + struct expression *expression = expression_; + return (expr_evaluate_num (expression, c, case_nr) == 1.0 + ? TRNS_CONTINUE : TRNS_DROP_CASE); +} + +/* Frees a PROCESS IF transformation. */ +static bool +process_if_trns_free (void *expression_) +{ + struct expression *expression = expression_; + expr_free (expression); + return true; +} diff --git a/src/data/procedure.h b/src/data/procedure.h new file mode 100644 index 00000000..5a196878 --- /dev/null +++ b/src/data/procedure.h @@ -0,0 +1,83 @@ +/* PSPP - computes sample statistics. + Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Written by Ben Pfaff . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef PROCEDURE_H +#define PROCEDURE_H 1 + +#include +#include +#include + +struct ccase; +struct casefile; +struct case_sink; +struct case_source; + +/* Dictionary produced by permanent and temporary transformations + on data from the source. */ +extern struct dictionary *default_dict; + +/* Transformations. */ + +void add_transformation (trns_proc_func *, trns_free_func *, void *); +void add_transformation_with_finalizer (trns_finalize_func *, + trns_proc_func *, + trns_free_func *, void *); +size_t next_transformation (void); + +void discard_variables (void); + +bool proc_cancel_all_transformations (void); +struct trns_chain *proc_capture_transformations (void); + +void proc_start_temporary_transformations (void); +bool proc_in_temporary_transformations (void); +bool proc_make_temporary_transformations_permanent (void); +bool proc_cancel_temporary_transformations (void); + +/* Procedures. */ + +void proc_init (void); +void proc_done (void); + +void proc_set_source (struct case_source *); +bool proc_has_source (void); + +void proc_set_sink (struct case_sink *); +struct casefile *proc_capture_output (void); + +bool procedure (bool (*proc_func) (struct ccase *, void *aux), void *aux); +bool procedure_with_splits (void (*begin_func) (void *aux), + bool (*proc_func) (struct ccase *, void *aux), + void (*end_func) (void *aux), + void *aux); +bool multipass_procedure (bool (*proc_func) (const struct casefile *, + void *aux), + void *aux); +bool multipass_procedure_with_splits (bool (*) (const struct casefile *, + void *), + void *aux); +time_t time_of_last_procedure (void); + +/* Number of cases to lag. */ +extern int n_lag; + +struct ccase *lagged_case (int n_before); + +#endif /* procedure.h */ diff --git a/src/data/transformations.c b/src/data/transformations.c index e5542b88..675e1c91 100644 --- a/src/data/transformations.c +++ b/src/data/transformations.c @@ -25,7 +25,6 @@ #include #include -#include #include "xalloc.h" diff --git a/src/language/command.c b/src/language/command.c index b5002cae..1e040d6c 100644 --- a/src/language/command.c +++ b/src/language/command.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,6 @@ #include #include #include -#include #if HAVE_SYS_WAIT_H #include diff --git a/src/language/control/do-if.c b/src/language/control/do-if.c index 0c0ead94..47fceee6 100644 --- a/src/language/control/do-if.c +++ b/src/language/control/do-if.c @@ -22,7 +22,7 @@ #include #include "control-stack.h" -#include +#include #include #include #include diff --git a/src/language/control/loop.c b/src/language/control/loop.c index abbc4467..f31486f6 100644 --- a/src/language/control/loop.c +++ b/src/language/control/loop.c @@ -22,7 +22,7 @@ #include "control-stack.h" #include #include -#include +#include #include #include #include diff --git a/src/language/control/repeat.c b/src/language/control/repeat.c index ec37382b..bc4b8295 100644 --- a/src/language/control/repeat.c +++ b/src/language/control/repeat.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/control/temporary.c b/src/language/control/temporary.c index 2424c255..6cfd48ec 100644 --- a/src/language/control/temporary.c +++ b/src/language/control/temporary.c @@ -24,7 +24,7 @@ #include "control-stack.h" #include -#include +#include #include #include #include diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index a778b5d8..89505dbc 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/data-io/data-reader.c b/src/language/data-io/data-reader.c index 8fc7a80a..a8b484d4 100644 --- a/src/language/data-io/data-reader.c +++ b/src/language/data-io/data-reader.c @@ -18,21 +18,24 @@ 02110-1301, USA. */ #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) diff --git a/src/language/data-io/get.c b/src/language/data-io/get.c index b9634b19..0cc628be 100644 --- a/src/language/data-io/get.c +++ b/src/language/data-io/get.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/data-io/inpt-pgm.c b/src/language/data-io/inpt-pgm.c index fbf1d342..51c36981 100644 --- a/src/language/data-io/inpt-pgm.c +++ b/src/language/data-io/inpt-pgm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/data-io/list.q b/src/language/data-io/list.q index a79c51ad..dd9a8ae1 100644 --- a/src/language/data-io/list.q +++ b/src/language/data-io/list.q @@ -18,27 +18,29 @@ 02110-1301, USA. */ #include -#include + #include #include -#include + +#include "intprops.h" +#include "size_max.h" #include -#include -#include #include -#include "intprops.h" +#include +#include +#include +#include #include -#include +#include +#include #include +#include +#include #include #include -#include -#include "size_max.h" #include +#include #include -#include -#include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/data-io/matrix-data.c b/src/language/data-io/matrix-data.c index ff008caa..d5b489c3 100644 --- a/src/language/data-io/matrix-data.c +++ b/src/language/data-io/matrix-data.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/data-io/print.c b/src/language/data-io/print.c index f6633652..63270160 100644 --- a/src/language/data-io/print.c +++ b/src/language/data-io/print.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/apply-dictionary.c b/src/language/dictionary/apply-dictionary.c index 87b71eee..1c9e7ef8 100644 --- a/src/language/dictionary/apply-dictionary.c +++ b/src/language/dictionary/apply-dictionary.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/formats.c b/src/language/dictionary/formats.c index 2d5e1c35..8658634b 100644 --- a/src/language/dictionary/formats.c +++ b/src/language/dictionary/formats.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/missing-values.c b/src/language/dictionary/missing-values.c index 0757fb1d..e37fa987 100644 --- a/src/language/dictionary/missing-values.c +++ b/src/language/dictionary/missing-values.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/modify-variables.c b/src/language/dictionary/modify-variables.c index ad6a48e4..1b0a27b0 100644 --- a/src/language/dictionary/modify-variables.c +++ b/src/language/dictionary/modify-variables.c @@ -31,8 +31,8 @@ #include #include #include +#include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/dictionary/numeric.c b/src/language/dictionary/numeric.c index f946e74a..37934883 100644 --- a/src/language/dictionary/numeric.c +++ b/src/language/dictionary/numeric.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/rename-variables.c b/src/language/dictionary/rename-variables.c index eedc84d4..6165787f 100644 --- a/src/language/dictionary/rename-variables.c +++ b/src/language/dictionary/rename-variables.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/split-file.c b/src/language/dictionary/split-file.c index 149523d3..7e003018 100644 --- a/src/language/dictionary/split-file.c +++ b/src/language/dictionary/split-file.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/sys-file-info.c b/src/language/dictionary/sys-file-info.c index 97bf3df5..13c3275e 100644 --- a/src/language/dictionary/sys-file-info.c +++ b/src/language/dictionary/sys-file-info.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/value-labels.c b/src/language/dictionary/value-labels.c index a9d3d875..89e0160a 100644 --- a/src/language/dictionary/value-labels.c +++ b/src/language/dictionary/value-labels.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/variable-display.c b/src/language/dictionary/variable-display.c index ef43c531..2348b721 100644 --- a/src/language/dictionary/variable-display.c +++ b/src/language/dictionary/variable-display.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/variable-label.c b/src/language/dictionary/variable-label.c index 3692a6c4..7380d3d6 100644 --- a/src/language/dictionary/variable-label.c +++ b/src/language/dictionary/variable-label.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/dictionary/vector.c b/src/language/dictionary/vector.c index 90f245c8..82870d9d 100644 --- a/src/language/dictionary/vector.c +++ b/src/language/dictionary/vector.c @@ -21,7 +21,7 @@ #include -#include +#include #include #include #include diff --git a/src/language/dictionary/weight.c b/src/language/dictionary/weight.c index 121728b6..5d492c4f 100644 --- a/src/language/dictionary/weight.c +++ b/src/language/dictionary/weight.c @@ -21,7 +21,7 @@ #include -#include +#include #include #include #include diff --git a/src/language/expressions/helpers.h b/src/language/expressions/helpers.h index c8355550..f5cfb67b 100644 --- a/src/language/expressions/helpers.h +++ b/src/language/expressions/helpers.h @@ -9,21 +9,22 @@ #include #include #include + +#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) diff --git a/src/language/expressions/parse.c b/src/language/expressions/parse.c index b6c8076c..71543008 100644 --- a/src/language/expressions/parse.c +++ b/src/language/expressions/parse.c @@ -35,7 +35,6 @@ #include #include #include -#include /* Declarations. */ diff --git a/src/language/lexer/variable-parser.c b/src/language/lexer/variable-parser.c index 6475caf4..64792aaa 100644 --- a/src/language/lexer/variable-parser.c +++ b/src/language/lexer/variable-parser.c @@ -25,7 +25,7 @@ #include "lexer.h" #include -#include +#include #include #include #include diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index e51a5a6a..aa289716 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,7 +44,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/stats/autorecode.c b/src/language/stats/autorecode.c index a4177be8..e808359b 100644 --- a/src/language/stats/autorecode.c +++ b/src/language/stats/autorecode.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/stats/correlations.q b/src/language/stats/correlations.q index 68d55635..594a5387 100644 --- a/src/language/stats/correlations.q +++ b/src/language/stats/correlations.q @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 8f1e42b4..55c92d8c 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -30,29 +30,31 @@ */ #include -#include + #include +#include #include #include -#include -#include -#include + #include #include -#include -#include +#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) diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index b7237148..4c5b7ff0 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/stats/examine.q b/src/language/stats/examine.q index 4f8e45de..bf2c3fd1 100644 --- a/src/language/stats/examine.q +++ b/src/language/stats/examine.q @@ -19,33 +19,35 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include + #include #include +#include #include #include -#include -#include -#include + #include +#include #include +#include +#include +#include #include -#include #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) diff --git a/src/language/stats/flip.c b/src/language/stats/flip.c index 02c764b5..3aed8323 100644 --- a/src/language/stats/flip.c +++ b/src/language/stats/flip.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -45,7 +45,6 @@ #include #include #include -#include #include "intprops.h" diff --git a/src/language/stats/frequencies.q b/src/language/stats/frequencies.q index 5de38ad5..db480bce 100644 --- a/src/language/stats/frequencies.q +++ b/src/language/stats/frequencies.q @@ -24,37 +24,38 @@ */ #include -#include + #include #include #include -#include -#include #include -#include #include -#include -#include +#include +#include +#include +#include #include #include -#include -#include +#include #include +#include +#include +#include #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) diff --git a/src/language/stats/means.q b/src/language/stats/means.q index 7fc176f7..a1aa7229 100644 --- a/src/language/stats/means.q +++ b/src/language/stats/means.q @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/stats/oneway.q b/src/language/stats/oneway.q index 2ef2d486..ab221e03 100644 --- a/src/language/stats/oneway.q +++ b/src/language/stats/oneway.q @@ -19,32 +19,33 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include + #include -#include +#include #include #include -#include -#include -#include + #include +#include #include +#include +#include +#include #include -#include #include -#include +#include +#include +#include #include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include - +#include +#include #include "sort-criteria.h" #include "gettext.h" diff --git a/src/language/stats/rank.q b/src/language/stats/rank.q index d3ac8edd..2022aaaf 100644 --- a/src/language/stats/rank.q +++ b/src/language/stats/rank.q @@ -21,8 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA #include #include "sort-criteria.h" + #include -#include +#include #include #include #include diff --git a/src/language/stats/regression.q b/src/language/stats/regression.q index b5dabb15..d79007ac 100644 --- a/src/language/stats/regression.q +++ b/src/language/stats/regression.q @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,6 @@ #include #include #include -#include #include "gettext.h" diff --git a/src/language/stats/sort-cases.c b/src/language/stats/sort-cases.c index 156c5b42..f50b67fe 100644 --- a/src/language/stats/sort-cases.c +++ b/src/language/stats/sort-cases.c @@ -24,7 +24,7 @@ #include #include "sort-criteria.h" -#include +#include #include #include #include diff --git a/src/language/stats/t-test.q b/src/language/stats/t-test.q index 4754b211..6d3f4ba2 100644 --- a/src/language/stats/t-test.q +++ b/src/language/stats/t-test.q @@ -20,31 +20,34 @@ 02110-1301, USA. */ #include + #include -#include +#include #include #include -#include -#include + #include #include +#include +#include +#include +#include #include +#include +#include #include -#include -#include -#include #include -#include -#include #include +#include +#include #include -#include "size_max.h" -#include #include +#include +#include +#include #include -#include -#include -#include + +#include "size_max.h" #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/utilities/set.q b/src/language/utilities/set.q index 2ad52b77..a230c7d5 100644 --- a/src/language/utilities/set.q +++ b/src/language/utilities/set.q @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/utilities/title.c b/src/language/utilities/title.c index d494e35e..9fa1309d 100644 --- a/src/language/utilities/title.c +++ b/src/language/utilities/title.c @@ -18,18 +18,20 @@ 02110-1301, USA. */ #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) diff --git a/src/language/xforms/compute.c b/src/language/xforms/compute.c index 0a399285..0bc6e4d3 100644 --- a/src/language/xforms/compute.c +++ b/src/language/xforms/compute.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index a8a208b3..8673c6de 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index c9cb2039..09eafb6a 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/language/xforms/sample.c b/src/language/xforms/sample.c index 830c981e..41b47f86 100644 --- a/src/language/xforms/sample.c +++ b/src/language/xforms/sample.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/language/xforms/select-if.c b/src/language/xforms/select-if.c index f6be43c2..4666f52d 100644 --- a/src/language/xforms/select-if.c +++ b/src/language/xforms/select-if.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/math/levene.c b/src/math/levene.c index 7a034621..86a32e7a 100644 --- a/src/math/levene.c +++ b/src/math/levene.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include "group.h" diff --git a/src/math/sort.c b/src/math/sort.c index 8ce95538..1d2257b2 100644 --- a/src/math/sort.c +++ b/src/math/sort.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include "gettext.h" #define _(msgid) gettext (msgid) diff --git a/src/procedure.c b/src/procedure.c deleted file mode 100644 index 9b94da01..00000000 --- a/src/procedure.c +++ /dev/null @@ -1,1016 +0,0 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. - Written by Ben Pfaff . - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#include - -#include - -#include -#include -#include -#include - -#include "expressions/public.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gettext.h" -#define _(msgid) gettext (msgid) - -/* - Virtual File Manager (vfm): - - vfm is used to process data files. It uses the model that - data is read from one stream (the data source), processed, - then written to another (the data sink). The data source is - then deleted and the data sink becomes the data source for the - next procedure. */ - -/* Procedure execution data. */ -struct write_case_data - { - /* Function to call for each case. */ - bool (*proc_func) (struct ccase *, void *); /* Function. */ - void *aux; /* Auxiliary data. */ - - struct ccase trns_case; /* Case used for transformations. */ - struct ccase sink_case; /* Case written to sink, if - compaction is necessary. */ - size_t cases_written; /* Cases output so far. */ - size_t cases_analyzed; /* Cases passed to procedure so far. */ - }; - -/* Cases are read from vfm_source, - pass through permanent_trns_chain (which transforms them into - the format described by permanent_dict), - are written to vfm_sink, - pass through temporary_trns_chain (which transforms them into - the format described by default_dict), - and are finally passed to the procedure. */ -static struct case_source *vfm_source; -static struct trns_chain *permanent_trns_chain; -static struct dictionary *permanent_dict; -static struct case_sink *vfm_sink; -static struct trns_chain *temporary_trns_chain; -struct dictionary *default_dict; - -/* The transformation chain that the next transformation will be - added to. */ -static struct trns_chain *cur_trns_chain; - -/* The compactor used to compact a case, if necessary; - otherwise a null pointer. */ -static struct dict_compactor *compactor; - -/* Time at which vfm was last invoked. */ -static time_t last_vfm_invocation; - -/* Lag queue. */ -int n_lag; /* Number of cases to lag. */ -static int lag_count; /* Number of cases in lag_queue so far. */ -static int lag_head; /* Index where next case will be added. */ -static struct ccase *lag_queue; /* Array of n_lag ccase * elements. */ - -static void add_case_limit_trns (void); -static void add_filter_trns (void); -static void add_process_if_trns (void); - -static bool internal_procedure (bool (*proc_func) (struct ccase *, void *), - void *aux); -static void update_last_vfm_invocation (void); -static void create_trns_case (struct ccase *, struct dictionary *); -static void open_active_file (void); -static bool write_case (struct write_case_data *wc_data); -static void lag_case (const struct ccase *c); -static void clear_case (struct ccase *c); -static bool close_active_file (void); - -/* Public functions. */ - -/* Returns the last time the data was read. */ -time_t -time_of_last_procedure (void) -{ - if (last_vfm_invocation == 0) - update_last_vfm_invocation (); - return last_vfm_invocation; -} - -/* Reads the data from the input program and writes it to a new - active file. For each case we read from the input program, we - do the following: - - 1. Execute permanent transformations. If these drop the case, - start the next case from step 1. - - 2. Write case to replacement active file. - - 3. Execute temporary transformations. If these drop the case, - start the next case from step 1. - - 4. Pass case to PROC_FUNC, passing AUX as auxiliary data. - - Returns true if successful, false if an I/O error occurred. */ -bool -procedure (bool (*proc_func) (struct ccase *, void *), void *aux) -{ - if (proc_func == NULL - && case_source_is_class (vfm_source, &storage_source_class) - && vfm_sink == NULL - && temporary_trns_chain == NULL - && trns_chain_is_empty (permanent_trns_chain)) - { - expr_free (process_if_expr); - process_if_expr = NULL; - dict_set_case_limit (default_dict, 0); - dict_clear_vectors (default_dict); - - update_last_vfm_invocation (); - return true; - } - else - { - bool ok; - - open_active_file (); - ok = internal_procedure (proc_func, aux); - ok = close_active_file () && ok; - - return ok; - } -} - -/* Callback function for multipass_procedure(). */ -static bool -multipass_callback (struct ccase *c, void *cf_) -{ - struct casefile *cf = cf_; - return casefile_append (cf, c); -} - -/* Procedure that allows multiple passes over the input data. - The entire active file is passed to PROC_FUNC, with the given - AUX as auxiliary data, as a unit. */ -bool -multipass_procedure (bool (*proc_func) (const struct casefile *, void *aux), - void *aux) -{ - if (case_source_is_class (vfm_source, &storage_source_class) - && vfm_sink == NULL - && temporary_trns_chain == NULL - && trns_chain_is_empty (permanent_trns_chain)) - { - proc_func (storage_source_get_casefile (vfm_source), aux); - - expr_free (process_if_expr); - process_if_expr = NULL; - dict_set_case_limit (default_dict, 0); - dict_clear_vectors (default_dict); - - update_last_vfm_invocation (); - return true; - } - else - { - struct casefile *cf; - bool ok; - - assert (proc_func != NULL); - - cf = casefile_create (dict_get_next_value_idx (default_dict)); - - open_active_file (); - ok = internal_procedure (multipass_callback, cf); - ok = proc_func (cf, aux) && ok; - ok = close_active_file () && ok; - - casefile_destroy (cf); - - return ok; - } -} - -/* Executes a procedure, as procedure(), except that the caller - is responsible for calling open_active_file() and - close_active_file(). - Returns true if successful, false if an I/O error occurred. */ -static bool -internal_procedure (bool (*proc_func) (struct ccase *, void *), void *aux) -{ - struct write_case_data wc_data; - bool ok; - - wc_data.proc_func = proc_func; - wc_data.aux = aux; - create_trns_case (&wc_data.trns_case, default_dict); - case_create (&wc_data.sink_case, dict_get_next_value_idx (default_dict)); - wc_data.cases_written = 0; - - update_last_vfm_invocation (); - - ok = (vfm_source == NULL - || vfm_source->class->read (vfm_source, - &wc_data.trns_case, - write_case, &wc_data)); - - case_destroy (&wc_data.sink_case); - case_destroy (&wc_data.trns_case); - - return ok; -} - -/* Updates last_vfm_invocation. */ -static void -update_last_vfm_invocation (void) -{ - last_vfm_invocation = time (NULL); -} - -/* Creates and returns a case, initializing it from the vectors - that say which `value's need to be initialized just once, and - which ones need to be re-initialized before every case. */ -static void -create_trns_case (struct ccase *trns_case, struct dictionary *dict) -{ - size_t var_cnt = dict_get_var_cnt (dict); - size_t i; - - case_create (trns_case, dict_get_next_value_idx (dict)); - for (i = 0; i < var_cnt; i++) - { - struct variable *v = dict_get_var (dict, i); - union value *value = case_data_rw (trns_case, v->fv); - - if (v->type == NUMERIC) - value->f = v->leave ? 0.0 : SYSMIS; - else - memset (value->s, ' ', v->width); - } -} - -/* Makes all preparations for reading from the data source and writing - to the data sink. */ -static void -open_active_file (void) -{ - add_case_limit_trns (); - add_filter_trns (); - add_process_if_trns (); - - /* Finalize transformations. */ - trns_chain_finalize (cur_trns_chain); - - /* Make permanent_dict refer to the dictionary right before - data reaches the sink. */ - if (permanent_dict == NULL) - permanent_dict = default_dict; - - /* Figure out compaction. */ - compactor = (dict_needs_compaction (permanent_dict) - ? dict_make_compactor (permanent_dict) - : NULL); - - /* Prepare sink. */ - if (vfm_sink == NULL) - vfm_sink = create_case_sink (&storage_sink_class, permanent_dict, NULL); - if (vfm_sink->class->open != NULL) - vfm_sink->class->open (vfm_sink); - - /* Allocate memory for lag queue. */ - if (n_lag > 0) - { - int i; - - lag_count = 0; - lag_head = 0; - lag_queue = xnmalloc (n_lag, sizeof *lag_queue); - for (i = 0; i < n_lag; i++) - case_nullify (&lag_queue[i]); - } -} - -/* Transforms trns_case and writes it to the replacement active - file if advisable. Returns true if more cases can be - accepted, false otherwise. Do not call this function again - after it has returned false once. */ -static bool -write_case (struct write_case_data *wc_data) -{ - enum trns_result retval; - size_t case_nr; - - /* Execute permanent transformations. */ - case_nr = wc_data->cases_written + 1; - retval = trns_chain_execute (permanent_trns_chain, - &wc_data->trns_case, &case_nr); - if (retval != TRNS_CONTINUE) - goto done; - - /* Write case to LAG queue. */ - if (n_lag) - lag_case (&wc_data->trns_case); - - /* Write case to replacement active file. */ - wc_data->cases_written++; - if (vfm_sink->class->write != NULL) - { - if (compactor != NULL) - { - dict_compactor_compact (compactor, &wc_data->sink_case, - &wc_data->trns_case); - vfm_sink->class->write (vfm_sink, &wc_data->sink_case); - } - else - vfm_sink->class->write (vfm_sink, &wc_data->trns_case); - } - - /* Execute temporary transformations. */ - if (temporary_trns_chain != NULL) - { - retval = trns_chain_execute (temporary_trns_chain, - &wc_data->trns_case, - &wc_data->cases_written); - if (retval != TRNS_CONTINUE) - goto done; - } - - /* Pass case to procedure. */ - wc_data->cases_analyzed++; - if (wc_data->proc_func != NULL) - if (!wc_data->proc_func (&wc_data->trns_case, wc_data->aux)) - retval = TRNS_ERROR; - - done: - clear_case (&wc_data->trns_case); - return retval != TRNS_ERROR; -} - -/* Add C to the lag queue. */ -static void -lag_case (const struct ccase *c) -{ - if (lag_count < n_lag) - lag_count++; - case_destroy (&lag_queue[lag_head]); - case_clone (&lag_queue[lag_head], c); - if (++lag_head >= n_lag) - lag_head = 0; -} - -/* Clears the variables in C that need to be cleared between - processing cases. */ -static void -clear_case (struct ccase *c) -{ - size_t var_cnt = dict_get_var_cnt (default_dict); - size_t i; - - for (i = 0; i < var_cnt; i++) - { - struct variable *v = dict_get_var (default_dict, i); - if (!v->leave) - { - if (v->type == NUMERIC) - case_data_rw (c, v->fv)->f = SYSMIS; - else - memset (case_data_rw (c, v->fv)->s, ' ', v->width); - } - } -} - -/* Closes the active file. */ -static bool -close_active_file (void) -{ - /* Free memory for lag queue, and turn off lagging. */ - if (n_lag > 0) - { - int i; - - for (i = 0; i < n_lag; i++) - case_destroy (&lag_queue[i]); - free (lag_queue); - n_lag = 0; - } - - /* Dictionary from before TEMPORARY becomes permanent. */ - proc_cancel_temporary_transformations (); - - /* Finish compaction. */ - if (compactor != NULL) - { - dict_compactor_destroy (compactor); - dict_compact_values (default_dict); - } - - /* Free data source. */ - free_case_source (vfm_source); - vfm_source = NULL; - - /* Old data sink becomes new data source. */ - if (vfm_sink->class->make_source != NULL) - vfm_source = vfm_sink->class->make_source (vfm_sink); - free_case_sink (vfm_sink); - vfm_sink = NULL; - - /* Cancel TEMPORARY, PROCESS IF, FILTER, N OF CASES, vectors, - and get rid of all the transformations. */ - dict_clear_vectors (default_dict); - permanent_dict = NULL; - return proc_cancel_all_transformations (); -} - -/* Returns a pointer to the lagged case from N_BEFORE cases before the - current one, or NULL if there haven't been that many cases yet. */ -struct ccase * -lagged_case (int n_before) -{ - assert (n_before >= 1 ); - assert (n_before <= n_lag); - - if (n_before <= lag_count) - { - int index = lag_head - n_before; - if (index < 0) - index += n_lag; - return &lag_queue[index]; - } - else - return NULL; -} - -/* Represents auxiliary data for handling SPLIT FILE. */ -struct split_aux_data - { - size_t case_count; /* Number of cases so far. */ - struct ccase prev_case; /* Data in previous case. */ - - /* Functions to call... */ - void (*begin_func) (void *); /* ...before data. */ - bool (*proc_func) (struct ccase *, void *); /* ...with data. */ - void (*end_func) (void *); /* ...after data. */ - void *func_aux; /* Auxiliary data. */ - }; - -static int equal_splits (const struct ccase *, const struct ccase *); -static bool procedure_with_splits_callback (struct ccase *, void *); -static void dump_splits (struct ccase *); - -/* Like procedure(), but it automatically breaks the case stream - into SPLIT FILE break groups. Before each group of cases with - identical SPLIT FILE variable values, BEGIN_FUNC is called. - Then PROC_FUNC is called with each case in the group. - END_FUNC is called when the group is finished. FUNC_AUX is - passed to each of the functions as auxiliary data. - - If the active file is empty, none of BEGIN_FUNC, PROC_FUNC, - and END_FUNC will be called at all. - - If SPLIT FILE is not in effect, then there is one break group - (if the active file is nonempty), and BEGIN_FUNC and END_FUNC - will be called once. - - Returns true if successful, false if an I/O error occurred. */ -bool -procedure_with_splits (void (*begin_func) (void *aux), - bool (*proc_func) (struct ccase *, void *aux), - void (*end_func) (void *aux), - void *func_aux) -{ - struct split_aux_data split_aux; - bool ok; - - split_aux.case_count = 0; - case_nullify (&split_aux.prev_case); - split_aux.begin_func = begin_func; - split_aux.proc_func = proc_func; - split_aux.end_func = end_func; - split_aux.func_aux = func_aux; - - open_active_file (); - ok = internal_procedure (procedure_with_splits_callback, &split_aux); - if (split_aux.case_count > 0 && end_func != NULL) - end_func (func_aux); - if (!close_active_file ()) - ok = false; - - case_destroy (&split_aux.prev_case); - - return ok; -} - -/* procedure() callback used by procedure_with_splits(). */ -static bool -procedure_with_splits_callback (struct ccase *c, void *split_aux_) -{ - struct split_aux_data *split_aux = split_aux_; - - /* Start a new series if needed. */ - if (split_aux->case_count == 0 - || !equal_splits (c, &split_aux->prev_case)) - { - if (split_aux->case_count > 0 && split_aux->end_func != NULL) - split_aux->end_func (split_aux->func_aux); - - dump_splits (c); - case_destroy (&split_aux->prev_case); - case_clone (&split_aux->prev_case, c); - - if (split_aux->begin_func != NULL) - split_aux->begin_func (split_aux->func_aux); - } - - split_aux->case_count++; - if (split_aux->proc_func != NULL) - return split_aux->proc_func (c, split_aux->func_aux); - else - return true; -} - -/* Compares the SPLIT FILE variables in cases A and B and returns - nonzero only if they differ. */ -static int -equal_splits (const struct ccase *a, const struct ccase *b) -{ - return case_compare (a, b, - dict_get_split_vars (default_dict), - dict_get_split_cnt (default_dict)) == 0; -} - -/* Dumps out the values of all the split variables for the case C. */ -static void -dump_splits (struct ccase *c) -{ - struct variable *const *split; - struct tab_table *t; - size_t split_cnt; - int i; - - split_cnt = dict_get_split_cnt (default_dict); - if (split_cnt == 0) - return; - - t = tab_create (3, split_cnt + 1, 0); - tab_dim (t, tab_natural_dimensions); - tab_vline (t, TAL_GAP, 1, 0, split_cnt); - tab_vline (t, TAL_GAP, 2, 0, split_cnt); - tab_text (t, 0, 0, TAB_NONE, _("Variable")); - tab_text (t, 1, 0, TAB_LEFT, _("Value")); - tab_text (t, 2, 0, TAB_LEFT, _("Label")); - split = dict_get_split_vars (default_dict); - for (i = 0; i < split_cnt; i++) - { - struct variable *v = split[i]; - char temp_buf[80]; - const char *val_lab; - - assert (v->type == NUMERIC || v->type == ALPHA); - tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name); - - data_out (temp_buf, &v->print, case_data (c, v->fv)); - - temp_buf[v->print.w] = 0; - tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf); - - val_lab = val_labs_find (v->val_labs, *case_data (c, v->fv)); - if (val_lab) - tab_text (t, 2, i + 1, TAB_LEFT, val_lab); - } - tab_flags (t, SOMF_NO_TITLE); - tab_submit (t); -} - -/* Represents auxiliary data for handling SPLIT FILE in a - multipass procedure. */ -struct multipass_split_aux_data - { - struct ccase prev_case; /* Data in previous case. */ - struct casefile *casefile; /* Accumulates data for a split. */ - - /* Function to call with the accumulated data. */ - bool (*split_func) (const struct casefile *, void *); - void *func_aux; /* Auxiliary data. */ - }; - -static bool multipass_split_callback (struct ccase *c, void *aux_); -static bool multipass_split_output (struct multipass_split_aux_data *); - -/* Returns true if successful, false if an I/O error occurred. */ -bool -multipass_procedure_with_splits (bool (*split_func) (const struct casefile *, - void *), - void *func_aux) -{ - struct multipass_split_aux_data aux; - bool ok; - - assert (split_func != NULL); - - open_active_file (); - - case_nullify (&aux.prev_case); - aux.casefile = NULL; - aux.split_func = split_func; - aux.func_aux = func_aux; - - ok = internal_procedure (multipass_split_callback, &aux); - if (aux.casefile != NULL) - ok = multipass_split_output (&aux) && ok; - case_destroy (&aux.prev_case); - - if (!close_active_file ()) - ok = false; - - return ok; -} - -/* procedure() callback used by multipass_procedure_with_splits(). */ -static bool -multipass_split_callback (struct ccase *c, void *aux_) -{ - struct multipass_split_aux_data *aux = aux_; - bool ok = true; - - /* Start a new series if needed. */ - if (aux->casefile == NULL || !equal_splits (c, &aux->prev_case)) - { - /* Pass any cases to split_func. */ - if (aux->casefile != NULL) - ok = multipass_split_output (aux); - - /* Start a new casefile. */ - aux->casefile = casefile_create (dict_get_next_value_idx (default_dict)); - - /* Record split values. */ - dump_splits (c); - case_destroy (&aux->prev_case); - case_clone (&aux->prev_case, c); - } - - return casefile_append (aux->casefile, c) && ok; -} - -static bool -multipass_split_output (struct multipass_split_aux_data *aux) -{ - bool ok; - - assert (aux->casefile != NULL); - ok = aux->split_func (aux->casefile, aux->func_aux); - casefile_destroy (aux->casefile); - aux->casefile = NULL; - - return ok; -} - -/* Discards all the current state in preparation for a data-input - command like DATA LIST or GET. */ -void -discard_variables (void) -{ - dict_clear (default_dict); - fh_set_default_handle (NULL); - - n_lag = 0; - - if (vfm_source != NULL) - { - free_case_source (vfm_source); - vfm_source = NULL; - } - - proc_cancel_all_transformations (); - - expr_free (process_if_expr); - process_if_expr = NULL; - - proc_cancel_temporary_transformations (); -} - -/* Returns the current set of permanent transformations, - and clears the permanent transformations. - For use by INPUT PROGRAM. */ -struct trns_chain * -proc_capture_transformations (void) -{ - struct trns_chain *chain; - - assert (temporary_trns_chain == NULL); - chain = permanent_trns_chain; - cur_trns_chain = permanent_trns_chain = trns_chain_create (); - return chain; -} - -/* Adds a transformation that processes a case with PROC and - frees itself with FREE to the current set of transformations. - The functions are passed AUX as auxiliary data. */ -void -add_transformation (trns_proc_func *proc, trns_free_func *free, void *aux) -{ - trns_chain_append (cur_trns_chain, NULL, proc, free, aux); -} - -/* Adds a transformation that processes a case with PROC and - frees itself with FREE to the current set of transformations. - When parsing of the block of transformations is complete, - FINALIZE will be called. - The functions are passed AUX as auxiliary data. */ -void -add_transformation_with_finalizer (trns_finalize_func *finalize, - trns_proc_func *proc, - trns_free_func *free, void *aux) -{ - trns_chain_append (cur_trns_chain, finalize, proc, free, aux); -} - -/* Returns the index of the next transformation. - This value can be returned by a transformation procedure - function to indicate a "jump" to that transformation. */ -size_t -next_transformation (void) -{ - return trns_chain_next (cur_trns_chain); -} - -/* Returns true if the next call to add_transformation() will add - a temporary transformation, false if it will add a permanent - transformation. */ -bool -proc_in_temporary_transformations (void) -{ - return temporary_trns_chain != NULL; -} - -/* Marks the start of temporary transformations. - Further calls to add_transformation() will add temporary - transformations. */ -void -proc_start_temporary_transformations (void) -{ - if (!proc_in_temporary_transformations ()) - { - add_case_limit_trns (); - - permanent_dict = dict_clone (default_dict); - trns_chain_finalize (permanent_trns_chain); - temporary_trns_chain = cur_trns_chain = trns_chain_create (); - } -} - -/* Converts all the temporary transformations, if any, to - permanent transformations. Further transformations will be - permanent. - Returns true if anything changed, false otherwise. */ -bool -proc_make_temporary_transformations_permanent (void) -{ - if (proc_in_temporary_transformations ()) - { - trns_chain_finalize (temporary_trns_chain); - trns_chain_splice (permanent_trns_chain, temporary_trns_chain); - temporary_trns_chain = NULL; - - dict_destroy (permanent_dict); - permanent_dict = NULL; - - return true; - } - else - return false; -} - -/* Cancels all temporary transformations, if any. Further - transformations will be permanent. - Returns true if anything changed, false otherwise. */ -bool -proc_cancel_temporary_transformations (void) -{ - if (proc_in_temporary_transformations ()) - { - dict_destroy (default_dict); - default_dict = permanent_dict; - permanent_dict = NULL; - - trns_chain_destroy (temporary_trns_chain); - temporary_trns_chain = NULL; - - return true; - } - else - return false; -} - -/* Cancels all transformations, if any. - Returns true if successful, false on I/O error. */ -bool -proc_cancel_all_transformations (void) -{ - bool ok; - ok = trns_chain_destroy (permanent_trns_chain); - ok = trns_chain_destroy (temporary_trns_chain) && ok; - permanent_trns_chain = cur_trns_chain = trns_chain_create (); - temporary_trns_chain = NULL; - return ok; -} - -/* Initializes procedure handling. */ -void -proc_init (void) -{ - default_dict = dict_create (); - proc_cancel_all_transformations (); -} - -/* Finishes up procedure handling. */ -void -proc_done (void) -{ - discard_variables (); -} - -/* Sets SINK as the destination for procedure output from the - next procedure. */ -void -proc_set_sink (struct case_sink *sink) -{ - assert (vfm_sink == NULL); - vfm_sink = sink; -} - -/* Sets SOURCE as the source for procedure input for the next - procedure. */ -void -proc_set_source (struct case_source *source) -{ - assert (vfm_source == NULL); - vfm_source = source; -} - -/* Returns true if a source for the next procedure has been - configured, false otherwise. */ -bool -proc_has_source (void) -{ - return vfm_source != NULL; -} - -/* Returns the output from the previous procedure. - For use only immediately after executing a procedure. - The returned casefile is owned by the caller; it will not be - automatically used for the next procedure's input. */ -struct casefile * -proc_capture_output (void) -{ - struct casefile *casefile; - - /* Try to make sure that this function is called immediately - after procedure() or a similar function. */ - assert (vfm_source != NULL); - assert (case_source_is_class (vfm_source, &storage_source_class)); - assert (trns_chain_is_empty (permanent_trns_chain)); - assert (!proc_in_temporary_transformations ()); - - casefile = storage_source_decapsulate (vfm_source); - vfm_source = NULL; - - return casefile; -} - -static trns_proc_func case_limit_trns_proc; -static trns_free_func case_limit_trns_free; - -/* Adds a transformation that limits the number of cases that may - pass through, if default_dict has a case limit. */ -static void -add_case_limit_trns (void) -{ - size_t case_limit = dict_get_case_limit (default_dict); - if (case_limit != 0) - { - size_t *cases_remaining = xmalloc (sizeof *cases_remaining); - *cases_remaining = case_limit; - add_transformation (case_limit_trns_proc, case_limit_trns_free, - cases_remaining); - dict_set_case_limit (default_dict, 0); - } -} - -/* Limits the maximum number of cases processed to - *CASES_REMAINING. */ -static int -case_limit_trns_proc (void *cases_remaining_, - struct ccase *c UNUSED, int case_nr UNUSED) -{ - size_t *cases_remaining = cases_remaining_; - if (*cases_remaining > 0) - { - *cases_remaining--; - return TRNS_CONTINUE; - } - else - return TRNS_DROP_CASE; -} - -/* Frees the data associated with a case limit transformation. */ -static bool -case_limit_trns_free (void *cases_remaining_) -{ - size_t *cases_remaining = cases_remaining_; - free (cases_remaining); - return true; -} - -static trns_proc_func filter_trns_proc; - -/* Adds a temporary transformation to filter data according to - the variable specified on FILTER, if any. */ -static void -add_filter_trns (void) -{ - struct variable *filter_var = dict_get_filter (default_dict); - if (filter_var != NULL) - { - proc_start_temporary_transformations (); - add_transformation (filter_trns_proc, NULL, filter_var); - } -} - -/* FILTER transformation. */ -static int -filter_trns_proc (void *filter_var_, - struct ccase *c UNUSED, int case_nr UNUSED) - -{ - struct variable *filter_var = filter_var_; - double f = case_num (c, filter_var->fv); - return (f != 0.0 && !mv_is_num_missing (&filter_var->miss, f) - ? TRNS_CONTINUE : TRNS_DROP_CASE); -} - -static trns_proc_func process_if_trns_proc; -static trns_free_func process_if_trns_free; - -/* Adds a temporary transformation to filter data according to - the expression specified on PROCESS IF, if any. */ -static void -add_process_if_trns (void) -{ - if (process_if_expr != NULL) - { - proc_start_temporary_transformations (); - add_transformation (process_if_trns_proc, process_if_trns_free, - process_if_expr); - process_if_expr = NULL; - } -} - -/* PROCESS IF transformation. */ -static int -process_if_trns_proc (void *expression_, - struct ccase *c UNUSED, int case_nr UNUSED) - -{ - struct expression *expression = expression_; - return (expr_evaluate_num (expression, c, case_nr) == 1.0 - ? TRNS_CONTINUE : TRNS_DROP_CASE); -} - -/* Frees a PROCESS IF transformation. */ -static bool -process_if_trns_free (void *expression_) -{ - struct expression *expression = expression_; - expr_free (expression); - return true; -} diff --git a/src/procedure.h b/src/procedure.h deleted file mode 100644 index 5a196878..00000000 --- a/src/procedure.h +++ /dev/null @@ -1,83 +0,0 @@ -/* PSPP - computes sample statistics. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. - Written by Ben Pfaff . - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#ifndef PROCEDURE_H -#define PROCEDURE_H 1 - -#include -#include -#include - -struct ccase; -struct casefile; -struct case_sink; -struct case_source; - -/* Dictionary produced by permanent and temporary transformations - on data from the source. */ -extern struct dictionary *default_dict; - -/* Transformations. */ - -void add_transformation (trns_proc_func *, trns_free_func *, void *); -void add_transformation_with_finalizer (trns_finalize_func *, - trns_proc_func *, - trns_free_func *, void *); -size_t next_transformation (void); - -void discard_variables (void); - -bool proc_cancel_all_transformations (void); -struct trns_chain *proc_capture_transformations (void); - -void proc_start_temporary_transformations (void); -bool proc_in_temporary_transformations (void); -bool proc_make_temporary_transformations_permanent (void); -bool proc_cancel_temporary_transformations (void); - -/* Procedures. */ - -void proc_init (void); -void proc_done (void); - -void proc_set_source (struct case_source *); -bool proc_has_source (void); - -void proc_set_sink (struct case_sink *); -struct casefile *proc_capture_output (void); - -bool procedure (bool (*proc_func) (struct ccase *, void *aux), void *aux); -bool procedure_with_splits (void (*begin_func) (void *aux), - bool (*proc_func) (struct ccase *, void *aux), - void (*end_func) (void *aux), - void *aux); -bool multipass_procedure (bool (*proc_func) (const struct casefile *, - void *aux), - void *aux); -bool multipass_procedure_with_splits (bool (*) (const struct casefile *, - void *), - void *aux); -time_t time_of_last_procedure (void); - -/* Number of cases to lag. */ -extern int n_lag; - -struct ccase *lagged_case (int n_before); - -#endif /* procedure.h */ diff --git a/src/ui/terminal/ChangeLog b/src/ui/terminal/ChangeLog index 330d94ab..f86d6c8c 100644 --- a/src/ui/terminal/ChangeLog +++ b/src/ui/terminal/ChangeLog @@ -1,3 +1,14 @@ +Thu May 4 21:50:59 2006 Ben Pfaff + + Continue reforming procedure execution. In this phase, move + procedure.c and procedure.h from src to src/data. Update + makefiles and #includes accordingly. + + * automake.mk: (src_ui_terminal_pspp_SOURCES) Remove + src/procedure.c and src/procedure.h. + (src_ui_terminal_pspp_LDADD) Move libexpressions.a later in list + to make the link work. + Wed May 3 23:09:37 2006 Ben Pfaff Continue reforming procedure execution. In this phase, get rid of diff --git a/src/ui/terminal/automake.mk b/src/ui/terminal/automake.mk index c1377146..105a6b26 100644 --- a/src/ui/terminal/automake.mk +++ b/src/ui/terminal/automake.mk @@ -14,17 +14,15 @@ src_ui_terminal_libui_a_SOURCES = \ bin_PROGRAMS += src/ui/terminal/pspp -src_ui_terminal_pspp_SOURCES = \ - src/procedure.c \ - src/procedure.h +src_ui_terminal_pspp_SOURCES = src_ui_terminal_pspp_LDADD = \ $(top_builddir)/src/ui/terminal/libui.a \ - $(top_builddir)/src/language/expressions/libexpressions.a \ $(top_builddir)/src/language/liblanguage.a \ $(top_builddir)/src/language/tests/libtests.a \ $(top_builddir)/src/language/utilities/libutilities.a \ $(top_builddir)/src/language/control/libcontrol.a \ + $(top_builddir)/src/language/expressions/libexpressions.a \ $(top_builddir)/src/language/stats/libstats.a \ $(top_builddir)/src/language/xforms/libxforms.a \ $(top_builddir)/src/language/dictionary/libcmddict.a \ diff --git a/src/ui/terminal/main.c b/src/ui/terminal/main.c index 7560dcfe..e19dd0c7 100644 --- a/src/ui/terminal/main.c +++ b/src/ui/terminal/main.c @@ -25,12 +25,12 @@ #include "command-line.h" #include "msg-ui.h" #include "progname.h" -#include "procedure.h" #include "read-line.h" #include #include #include +#include #include #include #include @@ -42,7 +42,6 @@ #include #include #include -#include #if HAVE_FPU_CONTROL_H #include