clean-ups of vfm interface.
+Thu Feb 12 23:35:15 2004 Ben Pfaff <blp@gnu.org>
+
+ Add auxiliary argument to procedure() interface. Associated small
+ clean-ups of vfm interface.
+
+ * Updated every caller of procedure() and process_active_file() to
+ reflect modified interface. Simple, ordinary changes not listed
+ otherwise below.
+
+ * Updated every function that implements struct case_stream's
+ `read' function to take a write_case_func and a write_case_data.
+ Also updated every caller of write_case() to instead call them
+ through these arguments. In some cases this meant that the extra
+ args had to be threaded through a couple of extra levels. This
+ wasn't difficult or interesting so the details won't be given.
+
+ * data-list.c: (struct repeating_data_trns) Add members
+ `write_case', `wc_data' as kluge.
+ (read_one_set_of_repetitions) Rename repeating_data_trns_proc and
+ make non-static.
+ (repeating_data_set_write_case) New function.
+
+ * data-list.h: New file to declare repeating_data_trns_proc() and
+ repeating_data_set_write_case().
+
+ * inpt-pgm.c: (input_program_source_read) Call
+ repeating_data_set_write_case() for all the REPEATING DATA
+ transformations, so that they know where to send their cases.
+ It's a big kluge. Also kluge in END CASE.
+ (end_case_trns_proc) Never called anymore, but we still need it,
+ so just assert(0).
+
+ * sort.c: (read_sort_output) Update to match struct case_stream
+ `read' member.
+
+ * vfm.c: (struct write_case_data) New structure.
+ (proc_func) Removed.
+ (virt_proc_func) Removed.
+ (begin_func) Removed.
+ (virt_begin_func) Removed.
+ (end_func) Removed.
+ (write_case) Removed.
+ (procedure) Added an auxiliary parameter to each function pointer
+ argument's prototype. Added an auxiliary data parameter.
+ Rewrote.
+ (process_active_file) Ditto.
+ (process_active_file_write_case) Pass aux data along.
+ (close_active_file) Ditto.
+ (procedure_write_case) Ditto.
+ (SPLIT_FILE_procfunc) Ditto.
+
+ * vfm.h: (typedef write_case_data) New.
+ (typedef write_case_func) New.
+ (struct case_stream) Add parameters to `read' member prototype.
+
Thu Feb 12 19:24:53 WST 2004 John Darrington <john@darrington.wattle.id.au>
* t-test.q: Added calculations for independent samples. (But no Levene
static int create_sysfile (void);
static int agr_00x_trns_proc (struct trns_header *, struct ccase *);
-static void agr_00x_end_func (void);
+static void agr_00x_end_func (void *);
static int agr_10x_trns_proc (struct trns_header *, struct ccase *);
static void agr_10x_trns_free (struct trns_header *);
-static void agr_10x_end_func (void);
-static int agr_11x_func (void);
+static void agr_10x_end_func (void *);
+static int agr_11x_func (write_case_data);
#if DEBUGGING
static void debug_print (int flags);
agr_dict = NULL;
- procedure (NULL, NULL, agr_00x_end_func);
+ procedure (NULL, NULL, agr_00x_end_func, NULL);
break;
}
t->free = agr_10x_trns_free;
add_transformation (t);
- procedure (NULL, NULL, agr_10x_end_func);
+ procedure (NULL, NULL, agr_10x_end_func, NULL);
}
break;
if (!create_sysfile ())
goto lossage;
- read_sort_output (agr_11x_func);
+ read_sort_output (agr_11x_func, NULL);
{
struct ccase *save_temp_case = temp_case;
temp_case = NULL;
- agr_11x_func ();
+ agr_11x_func (NULL);
temp_case = save_temp_case;
}
the cases have been output; very little has been cleaned up at this
point. */
static void
-agr_00x_end_func (void)
+agr_00x_end_func (void *aux UNUSED)
{
/* Ensure that info for the last break group gets written to the
active file. */
/* Ensure that info for the last break group gets written to the
system file. */
static void
-agr_10x_end_func (void)
+agr_10x_end_func (void *aux UNUSED)
{
dump_aggregate_info (buf_1xx);
write_case_to_sfm ();
appropriate. If temp_case is NULL, finishes up writing the last
case if necessary. */
static int
-agr_11x_func (void)
+agr_11x_func (write_case_data wc_data UNUSED)
{
if (temp_case != NULL)
{
static int autorecode_trns_proc (struct trns_header *, struct ccase *);
static void autorecode_trns_free (struct trns_header *);
-static int autorecode_proc_func (struct ccase *);
+static int autorecode_proc_func (struct ccase *, void *);
static hsh_compare_func compare_alpha_value, compare_numeric_value;
static hsh_hash_func hash_alpha_value, hash_numeric_value;
static void recode (void);
h_trans[i] = hsh_create (10, compare_numeric_value,
hash_numeric_value, NULL, NULL);
- procedure (NULL, autorecode_proc_func, NULL);
+ procedure (NULL, autorecode_proc_func, NULL, NULL);
for (i = 0; i < nv_dest; i++)
{
}
static int
-autorecode_proc_func (struct ccase * c)
+autorecode_proc_func (struct ccase *c, void *aux UNUSED)
{
int i;
cmd_execute (void)
{
lex_match_id ("EXECUTE");
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
return lex_end_of_command ();
}
static struct pool *pl_col; /* For column data. */
static int internal_cmd_crosstabs (void);
-static void precalc (void);
-static int calc_general (struct ccase *);
-static int calc_integer (struct ccase *);
-static void postcalc (void);
+static void precalc (void *);
+static int calc_general (struct ccase *, void *);
+static int calc_integer (struct ccase *, void *);
+static void postcalc (void *);
static void submit (struct tab_table *);
#if DEBUGGING
else
write = CRS_WR_NONE;
- procedure (precalc, mode == GENERAL ? calc_general : calc_integer, postcalc);
+ procedure (precalc, mode == GENERAL ? calc_general : calc_integer, postcalc,
+ NULL);
return CMD_SUCCESS;
}
/* Set up the crosstabulation tables for processing. */
static void
-precalc (void)
+precalc (void *aux UNUSED)
{
if (mode == GENERAL)
{
/* Form crosstabulations for general mode. */
static int
-calc_general (struct ccase *c)
+calc_general (struct ccase *c, void *aux UNUSED)
{
/* Case weight. */
double weight = dict_get_case_weight (default_dict, c);
}
static int
-calc_integer (struct ccase *c)
+calc_integer (struct ccase *c, void *aux UNUSED)
{
/* Case weight. */
double weight = dict_get_case_weight (default_dict, c);
static void make_summary_table (void);
static void
-postcalc (void)
+postcalc (void *aux UNUSED)
{
if (mode == GENERAL)
{
02111-1307, USA. */
#include <config.h>
+#include "data-list.h"
#include <assert.h>
#include <ctype.h>
#include <float.h>
static int read_from_data_list_fixed (void);
static int read_from_data_list_free (void);
static int read_from_data_list_list (void);
-static int do_reading (int flag);
/* FLAG==0: reads any number of cases into temp_case and calls
write_case() for each one, returns garbage. FLAG!=0: reads one
case into temp_case and returns -2 on eof, -1 otherwise.
Uses dlsp as the relevant parsing description. */
static int
-do_reading (int flag)
+do_reading (int flag, write_case_func *write_case, write_case_data wc_data)
{
int (*func) (void);
else
{
while (func () != -2)
- if (!write_case ())
+ if (!write_case (wc_data))
{
debug_printf ((_("abort in write_case()\n")));
break;
read_one_case (struct trns_header *t, struct ccase *c UNUSED)
{
dlsp = (struct data_list_pgm *) t;
- return do_reading (1);
+ return do_reading (1, NULL, NULL);
}
\f
/* Reads all the records from the data file and passes them to
write_case(). */
static void
-data_list_source_read (void)
+data_list_source_read (write_case_func *write_case, write_case_data wc_data)
{
dlsp = &dls;
- do_reading (0);
+ do_reading (0, write_case, wc_data);
}
/* Destroys the source's internal data. */
int id_beg, id_end; /* ID subcommand, beginning & end columns. */
struct variable *id_var; /* ID subcommand, DATA LIST variable. */
struct fmt_spec id_spec; /* ID subcommand, input format spec. */
+ write_case_func *write_case;
+ write_case_data wc_data;
};
/* Information about the transformation being parsed. */
static struct repeating_data_trns rpd;
-static int read_one_set_of_repetitions (struct trns_header *, struct ccase *);
+int repeating_data_trns_proc (struct trns_header *, struct ccase *);
static int parse_num_or_var (struct rpd_num_or_var *, const char *);
static int parse_repeating_data (void);
static void find_variable_input_spec (struct variable *v,
{
struct repeating_data_trns *new_trns;
- rpd.h.proc = read_one_set_of_repetitions;
+ rpd.h.proc = repeating_data_trns_proc;
rpd.h.free = destroy_dls;
new_trns = xmalloc (sizeof *new_trns);
cur += ofs;
- if (!write_case ())
+ if (!t->write_case (t->wc_data))
return 0;
}
}
/* Analogous to read_one_case; reads one set of repetitions of the
elements in the REPEATING DATA structure. Returns -1 on success,
-2 on end of file or on failure. */
-static int
-read_one_set_of_repetitions (struct trns_header *trns, struct ccase *c)
+int
+repeating_data_trns_proc (struct trns_header *trns, struct ccase *c)
{
dfm_push (dlsp->handle);
transformations. */
return -3;
}
+
+/* This is a kluge. It is only here until I have more time
+ tocome up with something better. It lets
+ repeating_data_trns_proc() know how to write the cases that it
+ composes. */
+void
+repeating_data_set_write_case (struct trns_header *trns,
+ write_case_func *write_case,
+ write_case_data wc_data)
+{
+ struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+
+ assert (trns->proc == repeating_data_trns_proc);
+ t->write_case = write_case;
+ t->wc_data = wc_data;
+}
--- /dev/null
+/* PSPP - computes sample statistics.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#ifndef INCLUDED_DATA_LIST_H
+#define INCLUDED_DATA_LIST_H
+
+/* FIXME: This header is a kluge and should go away when we come
+ up with a less-klugy solution. */
+
+#include "var.h"
+#include "vfm.h"
+
+int repeating_data_trns_proc (struct trns_header *, struct ccase *);
+void repeating_data_set_write_case (struct trns_header *,
+ write_case_func *, write_case_data);
+
+#endif /* data-list.h */
static void run_z_pass (void);
/* Procedure execution functions. */
-static int calc (struct ccase *);
-static void precalc (void);
-static void postcalc (void);
+static int calc (struct ccase *, void *);
+static void precalc (void *);
+static void postcalc (void *);
static void display (void);
\f
/* Parser and outline. */
/* Data pass! */
bad_weight = 0;
- procedure (precalc, calc, postcalc);
+ procedure (precalc, calc, postcalc, NULL);
if (bad_weight)
msg (SW, _("At least one case in the data file had a weight value "
/* Statistical calculation. */
static void
-precalc (void)
+precalc (void *aux UNUSED)
{
int i;
}
static int
-calc (struct ccase * c)
+calc (struct ccase * c, void *aux UNUSED)
{
int i;
}
static void
-postcalc (void)
+postcalc (void *aux UNUSED)
{
int i;
/* We don't actually read from the inline file. The input procedure
is what reads from it. */
getl_prompt = GETL_PRPT_DATA;
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
ext = inline_file->ext;
/* Reads any number of cases into temp_case and calls write_case() for
each one. Compare data-list.c:read_from_data_list. */
static void
-file_type_source_read (void)
+file_type_source_read (write_case_func *write_case UNUSED,
+ write_case_data wc_data UNUSED)
{
char *line;
int len;
temp_trns = temporary = 0;
vfm_sink = &flip_stream;
new_names_tail = NULL;
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
dict_clear (default_dict);
if (!build_dictionary ())
/* Reads the FLIP stream and passes it to write_case(). */
static void
-flip_stream_read (void)
+flip_stream_read (write_case_func *write_case, write_case_data wc_data)
{
if (src || (src == NULL && src_file == NULL))
{
for (iter = src, j = 1; iter; iter = iter->next, j++)
temp_case->data[j].f = iter->v[i];
- if (!write_case ())
+ if (!write_case (wc_data))
return;
}
}
msg (FE, _("Error reading FLIP source file: %s."),
strerror (errno));
- if (!write_case ())
+ if (!write_case (wc_data))
return;
}
}
static void determine_charts (void);
-static void precalc (void);
-static int calc (struct ccase *);
-static void postcalc (void);
+static void precalc (void *);
+static int calc (struct ccase *, void *);
+static void postcalc (void *);
static void postprocess_freq_tab (struct variable *);
static void dump_full (struct variable *);
cmd.sort = FRQ_AVALUE;
/* Do it! */
- procedure (precalc, calc, postcalc);
+ procedure (precalc, calc, postcalc, NULL);
return CMD_SUCCESS;
}
/* Add data from case C to the frequency table. */
static int
-calc (struct ccase *c)
+calc (struct ccase *c, void *aux UNUSED)
{
double weight;
int i;
/* Prepares each variable that is the target of FREQUENCIES by setting
up its hash table. */
static void
-precalc (void)
+precalc (void *aux UNUSED)
{
int i;
/* Finishes up with the variables after frequencies have been
calculated. Displays statistics, percentiles, ... */
static void
-postcalc (void)
+postcalc (void *aux UNUSED)
{
int i;
static struct save_trns *trns;
static int trim_dictionary (struct dictionary * dict, int *options);
-static int save_write_case_func (struct ccase *);
+static int save_write_case_func (struct ccase *, void *);
static int save_trns_proc (struct trns_header *, struct ccase *);
static void save_trns_free (struct trns_header *);
if (xsave == 0)
/* SAVE. */
{
- procedure (NULL, save_write_case_func, NULL);
+ procedure (NULL, save_write_case_func, NULL, NULL);
save_trns_free (&t->h);
}
else
}
static int
-save_write_case_func (struct ccase * c)
+save_write_case_func (struct ccase * c, void *aux UNUSED)
{
save_trns_proc (&trns->h, c);
return 1;
/* Reads all the cases from the data file and passes them to
write_case(). */
static void
-get_source_read (void)
+get_source_read (write_case_func *write_case, write_case_data wc_data)
{
while (sfm_read_case (get_file, temp_case->data, default_dict)
- && write_case ())
+ && write_case (wc_data))
;
get_source_destroy_source ();
}
static int mtf_merge_dictionary (struct mtf_file *f);
static void mtf_delete_file_in_place (struct mtf_file **file);
-static void mtf_read_nonactive_records (void);
-static void mtf_processing_finish (void);
-static int mtf_processing (struct ccase *);
+static void mtf_read_nonactive_records (void *);
+static void mtf_processing_finish (void *);
+static int mtf_processing (struct ccase *, void *);
static char *var_type_description (struct variable *);
dict_get_var_cnt (mtf_master) * sizeof *mtf_seq_nums);
process_active_file (mtf_read_nonactive_records, mtf_processing,
- mtf_processing_finish);
+ mtf_processing_finish, NULL);
mtf_master = NULL;
mtf_free ();
/* Repeats 2...8 an arbitrary number of times. */
static void
-mtf_processing_finish (void)
+mtf_processing_finish (void *aux UNUSED)
{
/* Find the active file and delete it. */
{
}
while (mtf_head && mtf_head->type == MTF_FILE)
- if (!mtf_processing (temp_case))
+ if (!mtf_processing (temp_case, NULL))
break;
}
/* Read a record from every input file except the active file. */
static void
-mtf_read_nonactive_records (void)
+mtf_read_nonactive_records (void *aux UNUSED)
{
struct mtf_file *iter;
/* Perform one iteration of steps 3...7 above. */
static int
-mtf_processing (struct ccase *c UNUSED)
+mtf_processing (struct ccase *c UNUSED, void *aux UNUSED)
{
/* List of files with minimum BY values. */
struct mtf_file *min_head, *min_tail;
/* Reads all the cases from the data file and passes them to
write_case(). */
static void
-import_source_read (void)
+import_source_read (write_case_func *write_case, write_case_data wc_data)
{
while (pfm_read_case (get_file, temp_case->data, default_dict)
- && write_case ())
+ && write_case (wc_data))
;
get_source_destroy_source ();
}
"IMPORT",
};
\f
-static int export_write_case_func (struct ccase *c);
+static int export_write_case_func (struct ccase *c, void *);
/* Parses the EXPORT command. */
/* FIXME: same as cmd_save_internal(). */
t->case_buf = xmalloc (sizeof *t->case_buf * t->nvar);
dict_destroy (dict);
- procedure (NULL, export_write_case_func, NULL);
+ procedure (NULL, export_write_case_func, NULL, NULL);
save_trns_free (&t->h);
return CMD_SUCCESS;
}
static int
-export_write_case_func (struct ccase *c)
+export_write_case_func (struct ccase *c, void *aux UNUSED)
{
union value *p = (union value *) trns->case_buf;
int i;
#include <stdlib.h>
#include "alloc.h"
#include "command.h"
+#include "data-list.h"
#include "dfm.h"
#include "error.h"
#include "expr.h"
file. -1 means go on to the next transformation. Otherwise the
return value is the index of the transformation to go to next. */
static void
-input_program_source_read (void)
+input_program_source_read (write_case_func *write_case,
+ write_case_data wc_data)
{
int i;
if (t_trns[i]->proc == end_case_trns_proc)
end_case = 1;
+ /* FIXME: This code should not be necessary. It 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], write_case, wc_data);
+
init_case ();
for (;;)
{
if (t_trns[i]->proc == end_case_trns_proc)
printf ("\n");
#endif
+
+ if (t_trns[i]->proc == end_case_trns_proc)
+ {
+ if (!write_case (wc_data))
+ return;
+ clear_case ();
+ i++;
+ continue;
+ }
+
code = t_trns[i]->proc (t_trns[i], temp_case);
switch (code)
{
/* Write the case if appropriate. */
if (!end_case)
- if (!write_case ())
+ if (!write_case (wc_data))
return;
/* Blank out the case for the next iteration. */
int
end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED)
{
-#if DEBUGGING
- printf ("END CASE\n");
-#endif
- if (!write_case ())
- return -2;
- clear_case ();
- return -1;
+ assert (0);
}
/* REREAD transformation. */
static void write_line (struct outp_driver *d, char *s);
/* Other functions. */
-static int list_cases (struct ccase *);
+static int list_cases (struct ccase *, void *);
static void determine_layout (void);
static void clean_up (void);
static void write_header (struct outp_driver *);
-static void write_all_headers (void);
+static void write_all_headers (void *);
/* Returns the number of text lines that can fit on the remainder of
the page. */
determine_layout ();
case_num = 0;
- procedure (write_all_headers, list_cases, NULL);
+ procedure (write_all_headers, list_cases, NULL, NULL);
free (line_buf);
clean_up ();
/* Writes headers to all devices. This is done at the beginning of
each SPLIT FILE group. */
static void
-write_all_headers (void)
+write_all_headers (void *aux UNUSED)
{
struct outp_driver *d;
}
static int
-list_cases (struct ccase *c)
+list_cases (struct ccase *c, void *aux UNUSED)
{
struct outp_driver *d;
static int nr_read_splits (int compare);
static int nr_read_factors (int cell);
-static void nr_output_data (void);
-static int matrix_data_read_without_rowtype (void);
+static void nr_output_data (write_case_func *, write_case_data);
+static void matrix_data_read_without_rowtype (write_case_func *,
+ write_case_data);
/* Read from the data file and write it to the active file. */
static void
nr_factor_values = xmalloc (sizeof *nr_factor_values * n_factors * cells);
max_cell_index = 0;
- matrix_data_source.read = (void (*)(void)) matrix_data_read_without_rowtype;
+ matrix_data_source.read = matrix_data_read_without_rowtype;
vfm_source = &matrix_data_source;
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
free (split_values);
free (nr_factor_values);
/* When ROWTYPE_ does not appear in the data, reads the matrices and
writes them to the output file. Returns success. */
-static int
-matrix_data_read_without_rowtype (void)
+static void
+matrix_data_read_without_rowtype (write_case_func *write_case,
+ write_case_data wc_data)
{
{
int *cp;
int *bp, *ep, *np;
if (!nr_read_splits (0))
- return 0;
+ return;
for (bp = contents; *bp != EOC; bp = np)
{
for (cp = bp; cp < ep; cp++)
if (!nr_read_data_lines (per_factor, i, *cp, cp != bp))
- return 0;
+ return;
}
}
}
- nr_output_data ();
+ nr_output_data (write_case, wc_data);
if (dict_get_split_cnt (default_dict) == 0 || !another_token ())
- return 1;
+ return;
}
}
/* Write the contents of a cell having content type CONTENT and data
CP to the active file. */
static void
-dump_cell_content (int content, double *cp)
+dump_cell_content (int content, double *cp,
+ write_case_func *write_case, write_case_data wc_data)
{
int type = content_type[content];
dict_get_var (default_dict,
first_continuous + i)->name,
8);
- write_case ();
+ write_case (wc_data);
}
}
}
/* Finally dump out everything from nr_data[] to the output file. */
static void
-nr_output_data (void)
+nr_output_data (write_case_func *write_case, write_case_data wc_data)
{
{
struct variable *const *split;
assert (nr_data[content] != NULL
&& nr_data[content][cell] != NULL);
- dump_cell_content (content, nr_data[content][cell]);
+ dump_cell_content (content, nr_data[content][cell],
+ write_case, wc_data);
}
}
}
for (content = 0; content <= PROX; content++)
if (!is_per_factor[content] && nr_data[content] != NULL)
- dump_cell_content (content, nr_data[content][0]);
+ dump_cell_content (content, nr_data[content][0],
+ write_case, wc_data);
}
}
\f
/* Current factor. */
struct factor_data *wr_current;
-static int wr_read_splits (void);
-static int wr_output_data (void);
+static int wr_read_splits (write_case_func *, write_case_data);
+static int wr_output_data (write_case_func *, write_case_data);
static int wr_read_rowtype (void);
static int wr_read_factors (void);
static int wr_read_indeps (void);
-static int matrix_data_read_with_rowtype (void);
+static void matrix_data_read_with_rowtype (write_case_func *,
+ write_case_data);
/* When ROWTYPE_ appears in the data, reads the matrices and writes
them to the output file. */
split_values = NULL;
cells = 0;
- matrix_data_source.read = (void (*)(void)) matrix_data_read_with_rowtype;
+ matrix_data_source.read = matrix_data_read_with_rowtype;
vfm_source = &matrix_data_source;
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
free (split_values);
fh_close_handle (data_file);
}
/* Read from the data file and write it to the active file. */
-static int
-matrix_data_read_with_rowtype (void)
+static void
+matrix_data_read_with_rowtype (write_case_func *write_case,
+ write_case_data wc_data)
{
do
{
- if (!wr_read_splits ())
- return 0;
+ if (!wr_read_splits (write_case, wc_data))
+ return;
if (!wr_read_factors ())
- return 0;
+ return;
if (!wr_read_indeps ())
- return 0;
+ return;
}
while (another_token ());
- wr_output_data ();
- return 1;
+ wr_output_data (write_case, wc_data);
}
/* Read the split file variables. If they differ from the previous
set of split variables then output the data. Returns success. */
static int
-wr_read_splits (void)
+wr_read_splits (write_case_func *write_case, write_case_data wc_data)
{
int compare;
size_t split_cnt;
if (compare && split_values[i] != mtokval && !different)
{
- if (!wr_output_data ())
+ if (!wr_output_data (write_case, wc_data))
return 0;
different = 1;
cells = 0;
/* Write out the data for the current split file to the active
file. */
static int
-wr_output_data (void)
+wr_output_data (write_case_func *write_case, write_case_data wc_data)
{
{
struct variable *const *split;
fill_matrix (content, iter->data[content]);
- dump_cell_content (content, iter->data[content]);
+ dump_cell_content (content, iter->data[content],
+ write_case, wc_data);
}
}
}
if (already_encountered & (1 | 4))
{
/* Read the data. */
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
}
if (!rearrange_dict (default_dict, &vm))
static int do_internal_sort (int separate);
static int do_external_sort (int separate);
int parse_sort_variables (void);
-void read_sort_output (int (*write_case) (void));
+void read_sort_output (write_case_func *write_case, write_case_data wc_data);
/* Performs the SORT CASES procedures. */
int
/* Not sure this is necessary but it's good to be safe. */
if (separate && vfm_source == &sort_stream)
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
/* SORT CASES cancels PROCESS IF. */
expr_free (process_if_expr);
if (vfm_source != &vfm_disk_stream)
{
if (vfm_source != &vfm_memory_stream)
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
if (vfm_source == &vfm_memory_stream)
{
struct case_list **case_tab = malloc (sizeof *case_tab
vfm_sink->destroy_sink ();
vfm_sink = &sort_stream;
}
- procedure (NULL, NULL, NULL);
+ procedure (NULL, NULL, NULL, NULL);
/* Final iterations of steps R4, R5, R6, R7, R2, R3, ... */
for (;;)
/* Reads all the records from the source stream and passes them
to write_case(). */
static void
-sort_stream_read (void)
+sort_stream_read (write_case_func *write_case, write_case_data wc_data)
{
- read_sort_output (write_case);
+ read_sort_output (write_case, wc_data);
}
/* Reads all the records from the output stream and passes them to the
function provided, which must have an interface identical to
write_case(). */
void
-read_sort_output (int (*write_case) (void))
+read_sort_output (write_case_func *write_case, write_case_data wc_data)
{
int i;
FILE *f;
for (p = separate_case_tab; *p; p++)
{
temp_case = &(*p)->c;
- write_case ();
+ write_case (wc_data);
}
free (separate_case_tab);
break;
}
- if (!write_case ())
+ if (!write_case (wc_data))
break;
}
#if !sort_h
#define sort_h 1
+#include "vfm.h"
+
/* SORT CASES programmatic interface. */
int sort_cases (int separate);
-void read_sort_output (int (*write_case)(void));
+void read_sort_output (write_case_func *, write_case_data);
/* Variables to sort. */
extern struct variable **v_sort;
};
-static int common_calc (struct ccase *);
-static void common_precalc (void);
-static void common_postcalc (void);
+static int common_calc (struct ccase *, void *);
+static void common_precalc (void *);
+static void common_postcalc (void *);
-static int one_sample_calc (struct ccase *);
-static void one_sample_precalc (void);
-static void one_sample_postcalc (void);
+static int one_sample_calc (struct ccase *, void *);
+static void one_sample_precalc (void *);
+static void one_sample_postcalc (void *);
-static int paired_calc (struct ccase *);
-static void paired_precalc (void);
-static void paired_postcalc (void);
+static int paired_calc (struct ccase *, void *);
+static void paired_precalc (void *);
+static void paired_postcalc (void *);
-static void group_precalc (void);
-static int group_calc (struct ccase *);
-static void group_postcalc (void);
+static void group_precalc (void *);
+static int group_calc (struct ccase *, void *);
+static void group_postcalc (void *);
static int compare_var_name (const void *a_, const void *b_, void *v_ UNUSED);
}
- procedure(common_precalc,common_calc,common_postcalc);
+ procedure(common_precalc,common_calc,common_postcalc, NULL);
switch(mode)
{
case T_1_SAMPLE:
- procedure(one_sample_precalc,one_sample_calc,one_sample_postcalc);
+ procedure(one_sample_precalc,one_sample_calc,one_sample_postcalc, NULL);
break;
case T_PAIRED:
- procedure(paired_precalc,paired_calc,paired_postcalc);
+ procedure(paired_precalc,paired_calc,paired_postcalc, NULL);
break;
case T_IND_SAMPLES:
- procedure(group_precalc,group_calc,group_postcalc);
+ procedure(group_precalc,group_calc,group_postcalc, NULL);
break;
}
/* Per case calculations common to all variants of the T test */
static int
-common_calc (struct ccase *c)
+common_calc (struct ccase *c, void *aux UNUSED)
{
int i;
/* Pre calculations common to all variants of the T test */
static void
-common_precalc (void)
+common_precalc (void *aux UNUSED)
{
int i=0;
/* Post calculations common to all variants of the T test */
void
-common_postcalc (void)
+common_postcalc (void *aux UNUSED)
{
int i=0;
/* Per case calculations for one sample t test */
static int
-one_sample_calc (struct ccase *c)
+one_sample_calc (struct ccase *c, void *aux UNUSED)
{
int i;
/* Pre calculations for one sample t test */
static void
-one_sample_precalc (void)
+one_sample_precalc (void *aux UNUSED)
{
int i=0;
/* Post calculations for one sample t test */
static void
-one_sample_postcalc (void)
+one_sample_postcalc (void *aux UNUSED)
{
int i=0;
static void
-paired_precalc (void)
+paired_precalc (void *aux UNUSED)
{
int i;
}
static int
-paired_calc (struct ccase *c)
+paired_calc (struct ccase *c, void *aux UNUSED)
{
int i;
}
static void
-paired_postcalc (void)
+paired_postcalc (void *aux UNUSED)
{
int i;
static void
-group_precalc (void)
+group_precalc (void *aux UNUSED)
{
int i;
int j;
}
static int
-group_calc (struct ccase *c)
+group_calc (struct ccase *c, void *aux UNUSED)
{
int i;
union value *gv = &c->data[groups->fv];
}
static void
-group_postcalc (void)
+group_postcalc (void *aux UNUSED)
{
int i;
int j;
#include "debug-print.h"
+/* Procedure execution data. */
+struct write_case_data
+ {
+ void (*beginfunc) (void *);
+ int (*procfunc) (struct ccase *, void *);
+ void (*endfunc) (void *);
+ void *aux;
+ };
+
/* This is used to read from the active file. */
struct case_stream *vfm_source;
/* Time at which vfm was last invoked. */
time_t last_vfm_invocation;
-/* Functions called during procedure processing. */
-static int (*proc_func) (struct ccase *); /* Called for each case. */
-static int (*virt_proc_func) (struct ccase *); /* From SPLIT_FILE_procfunc. */
-static void (*begin_func) (void); /* Called at beginning of a series. */
-static void (*virt_begin_func) (void); /* Called by SPLIT_FILE_procfunc. */
-static void (*end_func) (void); /* Called after end of a series. */
-int (*write_case) (void);
-
/* Number of cases passed to proc_func(). */
static int case_count;
static struct ccase **lag_queue; /* Array of n_lag ccase * elements. */
static void open_active_file (void);
-static void close_active_file (void);
-static int SPLIT_FILE_procfunc (struct ccase *);
+static void close_active_file (struct write_case_data *);
+static int SPLIT_FILE_procfunc (struct ccase *, void *);
static void finish_compaction (void);
static void lag_case (void);
-static int procedure_write_case (void);
+static int procedure_write_case (struct write_case_data *);
\f
/* Public functions. */
-/* Reads all the cases from the active file, transforms them by the
- active set of transformations, calls PROCFUNC with CURCASE set to
- the case and CASENUM set to the case number, and writes them to a
- new active file.
+/* Reads all the cases from the active file, transforms them by
+ the active set of transformations, calls PROCFUNC with CURCASE
+ set to the case , and writes them to a new active file.
Divides the active file into zero or more series of one or more
cases each. BEGINFUNC is called before each series. ENDFUNC is
- called after each series. */
+ called after each series.
+
+ Arbitrary user-specified data AUX is passed to BEGINFUNC,
+ PROCFUNC, and ENDFUNC as auxiliary data. */
void
-procedure (void (*beginfunc) (void),
- int (*procfunc) (struct ccase *curcase),
- void (*endfunc) (void))
+procedure (void (*beginfunc) (void *),
+ int (*procfunc) (struct ccase *curcase, void *),
+ void (*endfunc) (void *),
+ void *aux)
{
- end_func = endfunc;
- write_case = procedure_write_case;
+ struct write_case_data procedure_write_data;
+ struct write_case_data split_file_data;
- if (dict_get_split_cnt (default_dict) != 0 && procfunc != NULL)
+ if (dict_get_split_cnt (default_dict) == 0)
{
- virt_proc_func = procfunc;
- proc_func = SPLIT_FILE_procfunc;
-
- virt_begin_func = beginfunc;
- begin_func = NULL;
- } else {
- begin_func = beginfunc;
- proc_func = procfunc;
+ /* Normally we just use the data passed by the user. */
+ procedure_write_data.beginfunc = beginfunc;
+ procedure_write_data.procfunc = procfunc;
+ procedure_write_data.endfunc = endfunc;
+ procedure_write_data.aux = aux;
+ }
+ else
+ {
+ /* Under SPLIT FILE, we add a layer of indirection. */
+ procedure_write_data.beginfunc = NULL;
+ procedure_write_data.procfunc = SPLIT_FILE_procfunc;
+ procedure_write_data.endfunc = endfunc;
+ procedure_write_data.aux = &split_file_data;
+
+ split_file_data.beginfunc = beginfunc;
+ split_file_data.procfunc = procfunc;
+ split_file_data.endfunc = endfunc;
+ split_file_data.aux = aux;
}
last_vfm_invocation = time (NULL);
open_active_file ();
- vfm_source->read ();
- close_active_file ();
+ vfm_source->read (procedure_write_case, &procedure_write_data);
+ close_active_file (&procedure_write_data);
}
\f
/* Active file processing support. Subtly different semantics from
procedure(). */
-static int process_active_file_write_case (void);
+static int process_active_file_write_case (struct write_case_data *data);
/* The casefunc might want us to stop calling it. */
static int not_canceled;
process_active_file() ignores TEMPORARY, SPLIT FILE, and N. */
void
-process_active_file (void (*beginfunc) (void),
- int (*casefunc) (struct ccase *curcase),
- void (*endfunc) (void))
+process_active_file (void (*beginfunc) (void *),
+ int (*casefunc) (struct ccase *curcase, void *),
+ void (*endfunc) (void *),
+ void *aux)
{
- proc_func = casefunc;
- write_case = process_active_file_write_case;
+ struct write_case_data process_active_write_data;
+
+ process_active_write_data.beginfunc = beginfunc;
+ process_active_write_data.procfunc = casefunc;
+ process_active_write_data.endfunc = endfunc;
+ process_active_write_data.aux = aux;
+
not_canceled = 1;
open_active_file ();
- beginfunc ();
+ beginfunc (aux);
/* There doesn't necessarily need to be an active file. */
if (vfm_source)
- vfm_source->read ();
+ vfm_source->read (process_active_file_write_case,
+ &process_active_write_data);
- endfunc ();
- close_active_file ();
+ endfunc (aux);
+ close_active_file (&process_active_write_data);
}
/* Pass the current case to casefunc. */
static int
-process_active_file_write_case (void)
+process_active_file_write_case (struct write_case_data *data)
{
/* Index of current transformation. */
int cur_trns;
&& !FILTERED
&& (process_if_expr == NULL ||
expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
- not_canceled = proc_func (temp_case);
+ not_canceled = data->procfunc (temp_case, data->aux);
case_count++;
\f
/* Closes the active file. */
static void
-close_active_file (void)
+close_active_file (struct write_case_data *data)
{
/* Close the current case group. */
- if (case_count && end_func != NULL)
- end_func ();
+ if (case_count && data->endfunc != NULL)
+ data->endfunc (data->aux);
/* Stop lagging (catch up?). */
if (n_lag)
/* Reads all cases from the disk source and passes them one by one to
write_case(). */
static void
-disk_stream_read (void)
+disk_stream_read (write_case_func *write_case, write_case_data wc_data)
{
int i;
return;
}
- if (!write_case ())
+ if (!write_case (wc_data))
return;
}
}
/* Reads the case stream from memory and passes it to write_case(). */
static void
-memory_stream_read (void)
+memory_stream_read (write_case_func *write_case, write_case_data wc_data)
{
while (memory_source_cases != NULL)
{
free (current);
}
- if (!write_case ())
+ if (!write_case (wc_data))
return;
}
}
otherwise. Do not call this function again after it has returned
zero once. */
int
-procedure_write_case (void)
+procedure_write_case (write_case_data wc_data)
{
/* Index of current transformation. */
int cur_trns;
}
/* Call the beginning of group function. */
- if (!case_count && begin_func != NULL)
- begin_func ();
+ if (!case_count && wc_data->beginfunc != NULL)
+ wc_data->beginfunc (wc_data->aux);
/* Call the procedure if there is one and FILTER and PROCESS IF
don't prohibit it. */
- if (proc_func != NULL
+ if (wc_data->procfunc != NULL
&& !FILTERED
&& (process_if_expr == NULL ||
expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
- proc_func (temp_case);
+ wc_data->procfunc (temp_case, wc_data->aux);
case_count++;
SPLIT FILE is active. This function forms a wrapper around that
procfunc by dividing the input into series. */
static int
-SPLIT_FILE_procfunc (struct ccase *c)
+SPLIT_FILE_procfunc (struct ccase *c, void *data_)
{
+ struct write_case_data *data = data_;
static struct ccase *prev_case;
struct variable *const *split;
size_t split_cnt;
memcpy (prev_case, c, vfm_sink_info.case_size);
dump_splits (c);
- if (virt_begin_func != NULL)
- virt_begin_func ();
+ if (data->beginfunc != NULL)
+ data->beginfunc (data->aux);
- return virt_proc_func (c);
+ return data->procfunc (c, data->aux);
}
/* Compare the value of each SPLIT FILE variable to the values on
assert (0);
}
}
- return virt_proc_func (c);
+ return data->procfunc (c, data->aux);
not_equal:
/* The values of the SPLIT FILE variable are different from the
values on the previous case. That means that it's time to begin
a new series. */
- if (end_func != NULL)
- end_func ();
+ if (data->endfunc != NULL)
+ data->endfunc (data->aux);
dump_splits (c);
- if (virt_begin_func != NULL)
- virt_begin_func ();
+ if (data->beginfunc != NULL)
+ data->beginfunc (data->aux);
memcpy (prev_case, c, vfm_sink_info.case_size);
- return virt_proc_func (c);
+ return data->procfunc (c, data->aux);
}
\f
/* Case compaction. */
extern struct long_vec init_zero; /* Zero for first case only. */
extern struct long_vec init_blanks; /* Blanks for first case only. */
+typedef struct write_case_data *write_case_data;
+typedef int write_case_func (write_case_data);
+
/* A case stream: either a source or a sink, depending on context. */
struct case_stream
{
/* Initializes sink. */
void (*init) (void);
- /* Reads all the cases and passes them to WRITE_CASE. */
- void (*read) (void);
+ /* Reads all the cases and calls WRITE_CASE passing the given
+ AUX data for each one. */
+ void (*read) (write_case_func *, write_case_data);
/* Writes a single case, temp_case. */
void (*write) (void);
/* Number of cases to lag. */
extern int n_lag;
-extern int (*write_case) (void);
-
-void procedure (void (*beginfunc) (void),
- int (*procfunc) (struct ccase *curcase),
- void (*endfunc) (void));
+void procedure (void (*beginfunc) (void *aux),
+ int (*procfunc) (struct ccase *curcase, void *aux),
+ void (*endfunc) (void *aux),
+ void *aux);
struct ccase *lagged_case (int n_before);
void compact_case (struct ccase *dest, const struct ccase *src);
void page_to_disk (void);
-void process_active_file (void (*beginfunc) (void),
- int (*casefunc) (struct ccase *curcase),
- void (*endfunc) (void));
+void process_active_file (void (*beginfunc) (void *),
+ int (*casefunc) (struct ccase *curcase, void *),
+ void (*endfunc) (void *),
+ void *aux);
void process_active_file_output_case (void);
#endif /* !vfm_h */