From: Ben Pfaff Date: Thu, 4 Mar 2004 03:57:16 +0000 (+0000) Subject: Start working to eliminate VFM dependence on static variables. X-Git-Tag: sav-api~2573 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc963dae9be291ea0a7cccf189d13e00d3797cfd;p=pspp Start working to eliminate VFM dependence on static variables. --- diff --git a/src/ChangeLog b/src/ChangeLog index eb405c3516..57862a16cd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,104 @@ +Wed Mar 3 09:30:09 2004 Ben Pfaff + + * main.c: (main) sigaction()'s sa_flags member was uninitialized. + Just use signal() instead. + +Wed Mar 3 09:26:30 2004 Ben Pfaff + + Get rid of vfm_sink_info and vfm_source_info. + + * aggregate.c: (agr_00x_end_func) Don't increment + sfm_sink_info.ncases. + + * sort.c: (do_internal_sort) Get case count from + vfm_source->class->count(). + (struct external_sort) Add `case_size' member. + (do_external_sort) Initialize case_size. + (struct initial_run_state) Add `case_size' member. + (write_initial_runs) Initialize case_size. + (sort_sink_write) Use case_size. + (read_external_sort_output) Use case_size. Get case_cnt from + initial_runs. + + * vfm.c: (struct write_case_data) Add underscores to existing arg + names, all references updated. Renamed `aux' as `func_aux', all + references updated. Added new `aux' member. + (global var vfm_source_info) Removed. + (global var vfm_sink_info) Removed. + (struct procedure_aux_data) New. + (struct split_aux_data) New. + (procedure) Use `aux' fields for procedure_aux_data, + split_aux_data. + (process_active_file_write_case) Pass case_count + 1 to + transformation procedures, exclude_this_case(). + (process_active_file_output_case) Don't increment + vfm_sink_info.ncases. + (prepare_for_writing) Don't initialize vfm_sink_info. Don't try + to send data to disk early. + (make_temp_case) Don't use vfm_sink_info.case_size. + (close_active_file) Don't initialize vfm_source_info. + (struct disk_stream_info) New, to allow for case_cnt and case_size fields. + (disk_sink_create) Initialize and/or update disk_stream_info. + (disk_sink_write) Ditto. + (disk_sink_destroy) Ditto. + (disk_sink_make_source) Ditto. + (disk_source_read) Ditto. + (disk_source_destroy) Ditto. + (global var disk_source_class) Add disk_source_count(). + (disk_source_count) New function. + (struct memory_sink_info) Add `case_cnt', `case_size' members. + (struct memory_source_info) Ditto. + (memory_sink_create) Deal with case_cnt, case_size. + (memory_sink_write) Ditto. + (memory_sink_make_source) Ditto. + (memory_source_read) Ditto. + (memory_source_count) New function. + (memory_source_class) Add memory_source_count(). + (procedure_write_case) Don't use vfm_sink_info.ncases. Do use + proc_aux->cases_written, and pass it to transformation procedures + and exclude_this_case (). + (exclude_this_case) Add case_num parameter. Pass it to + expr_evaluate(). + (SPLIT_FILE_procfunc) Use split_aux->prev_case instead of static + variable. + + * vfm.h: (struct case_source_class) Add `count' member. + + * vfmP.h: (struct stream_info) Removed. + (global variable vfm_source_info) Removed. + (global variable vfm_sink_info) Removed. + +Tue Mar 2 23:38:17 2004 Ben Pfaff + + * var.h: (typedef trns_proc_func) New typedef. + (trns_free_func) New typedef. + (struct trns_header) Change `proc' to type trns_proc_func, `free' + to type trns_free_func. This only changes the actual type of + trns_proc_func, adding a `case_num' parameter. Updated all + implementations to use the typedefs instead. + + * compute.c: (compute_num) Pass case_num to expr_evaluate(). + (compute_num_vec) Ditto. + (compute_str) Ditto. + (compute_str_vec) Ditto. + + * do-if.c: (do_if_trns_proc) Ditto. + + * expr-evl.c: (expr_evaluate) Add new case_num parameter, use for + OP_CASENUM. + + * inpt-pgm.c: (input_program_source_read) Maintain case count, + pass to transformation functions. + (reread_trns_proc) Pass case_num arg to expr_evaluate(). + + * loop.c: (loop_1_trns_proc) Ditto. + (loop_2_trns_proc) Ditto. + (loop_3_trns_proc) Ditto. + + * print.c: (print_space_trns_proc) Ditto. + + * sel-if.c: (select_if_proc) Ditto. + Tue Mar 2 11:36:52 2004 Ben Pfaff * frequencies.q: (cleanup_freq_tab) Avoid memory leak by diff --git a/src/aggregate.c b/src/aggregate.c index 0c274c4b3b..e8568419f6 100644 --- a/src/aggregate.c +++ b/src/aggregate.c @@ -144,10 +144,9 @@ static void free_aggregate_functions (void); static int aggregate_single_case (struct ccase *input, struct ccase *output); static int create_sysfile (void); -static int agr_00x_trns_proc (struct trns_header *, struct ccase *); -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 trns_proc_func agr_00x_trns_proc, agr_10x_trns_proc; +static trns_free_func agr_10x_trns_free; +static void agr_00x_end_func (void *aux); static void agr_10x_end_func (void *); static int agr_11x_func (write_case_data); @@ -1196,7 +1195,8 @@ initialize_aggregate_info (void) /* Aggregate each case as it comes through. Cases which aren't needed are dropped. */ static int -agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c) +agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c, + int case_num UNUSED) { int code = aggregate_single_case (c, compaction_case); debug_printf (("%d ", code)); @@ -1213,7 +1213,6 @@ agr_00x_end_func (void *aux UNUSED) /* Ensure that info for the last break group gets written to the active file. */ dump_aggregate_info (compaction_case); - vfm_sink_info.ncases++; vfm_sink->class->write (vfm_sink, temp_case); } @@ -1253,7 +1252,8 @@ write_case_to_sfm (void) /* Aggregate the current case and output it if we passed a breakpoint. */ static int -agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c) +agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c, + int case_num UNUSED) { int code = aggregate_single_case (c, buf_1xx); diff --git a/src/algorithm.h b/src/algorithm.h index f8f2b84d87..707acf2814 100644 --- a/src/algorithm.h +++ b/src/algorithm.h @@ -1,5 +1,5 @@ -#ifndef SORT_ALGO_H -#define SORT_ALGO_H 1 +#ifndef ALGORITHM_H +#define ALGORITHM_H 1 #include @@ -190,4 +190,4 @@ int is_heap (const void *array, size_t count, size_t size, algo_compare_func *compare, void *aux); -#endif /* sort-algo.h */ +#endif /* algorithm.h */ diff --git a/src/autorecode.c b/src/autorecode.c index 8d15ce63ba..27fe0db2de 100644 --- a/src/autorecode.c +++ b/src/autorecode.c @@ -74,8 +74,8 @@ static struct pool *hash_pool; static int descend; static int print; -static int autorecode_trns_proc (struct trns_header *, struct ccase *); -static void autorecode_trns_free (struct trns_header *); +static trns_proc_func autorecode_trns_proc; +static trns_free_func autorecode_trns_free; 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; @@ -235,7 +235,8 @@ recode (void) } static int -autorecode_trns_proc (struct trns_header * trns, struct ccase * c) +autorecode_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct autorecode_trns *t = (struct autorecode_trns *) trns; int i; diff --git a/src/compute.c b/src/compute.c index aed443853d..60c99ad825 100644 --- a/src/compute.c +++ b/src/compute.c @@ -105,26 +105,28 @@ cmd_compute (void) /* Transformation functions. */ static int -compute_num (struct trns_header *compute_, struct ccase *c) +compute_num (struct trns_header *compute_, struct ccase *c, + int case_num) { struct compute_trns *compute = (struct compute_trns *) compute_; if (compute->test == NULL - || expr_evaluate (compute->test, c, NULL) == 1.0) + || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) { - expr_evaluate (compute->rvalue, c, &c->data[compute->fv]); + expr_evaluate (compute->rvalue, c, case_num, &c->data[compute->fv]); } return -1; } static int -compute_num_vec (struct trns_header *compute_, struct ccase *c) +compute_num_vec (struct trns_header *compute_, struct ccase *c, + int case_num) { struct compute_trns *compute = (struct compute_trns *) compute_; if (compute->test == NULL - || expr_evaluate (compute->test, c, NULL) == 1.0) + || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) { /* Index into the vector. */ union value index; @@ -132,7 +134,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c) /* Rounded index value. */ int rindx; - expr_evaluate (compute->element, c, &index); + expr_evaluate (compute->element, c, case_num, &index); rindx = floor (index.f + EPSILON); if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt) { @@ -145,7 +147,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c) index.f, compute->vector->name); return -1; } - expr_evaluate (compute->rvalue, c, + expr_evaluate (compute->rvalue, c, case_num, &c->data[compute->vector->var[rindx - 1]->fv]); } @@ -153,17 +155,18 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c) } static int -compute_str (struct trns_header *compute_, struct ccase *c) +compute_str (struct trns_header *compute_, struct ccase *c, + int case_num) { struct compute_trns *compute = (struct compute_trns *) compute_; if (compute->test == NULL - || expr_evaluate (compute->test, c, NULL) == 1.0) + || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) { /* Temporary storage for string expression return value. */ union value v; - expr_evaluate (compute->rvalue, c, &v); + expr_evaluate (compute->rvalue, c, case_num, &v); st_bare_pad_len_copy (c->data[compute->fv].s, &v.c[1], compute->width, v.c[0]); } @@ -172,12 +175,13 @@ compute_str (struct trns_header *compute_, struct ccase *c) } static int -compute_str_vec (struct trns_header *compute_, struct ccase *c) +compute_str_vec (struct trns_header *compute_, struct ccase *c, + int case_num) { struct compute_trns *compute = (struct compute_trns *) compute_; if (compute->test == NULL - || expr_evaluate (compute->test, c, NULL) == 1.0) + || expr_evaluate (compute->test, c, case_num, NULL) == 1.0) { /* Temporary storage for string expression return value. */ union value v; @@ -191,7 +195,7 @@ compute_str_vec (struct trns_header *compute_, struct ccase *c) /* Variable reference by indexed vector. */ struct variable *vr; - expr_evaluate (compute->element, c, &index); + expr_evaluate (compute->element, c, case_num, &index); rindx = floor (index.f + EPSILON); if (index.f == SYSMIS || rindx < 1 || rindx > compute->vector->cnt) { @@ -206,7 +210,7 @@ compute_str_vec (struct trns_header *compute_, struct ccase *c) return -1; } - expr_evaluate (compute->rvalue, c, &v); + expr_evaluate (compute->rvalue, c, case_num, &v); vr = compute->vector->var[rindx - 1]; st_bare_pad_len_copy (c->data[vr->fv].s, &v.c[1], vr->width, v.c[0]); } diff --git a/src/count.c b/src/count.c index 3b9a0ac098..4cdf90ecbd 100644 --- a/src/count.c +++ b/src/count.c @@ -128,8 +128,8 @@ static struct cnt_var_info *head; /* Parser. */ -static int count_trns_proc (struct trns_header *, struct ccase *); -static void count_trns_free (struct trns_header *); +static trns_proc_func count_trns_proc; +static trns_free_func count_trns_free; static int parse_numeric_criteria (struct counting *); static int parse_string_criteria (struct counting *); @@ -490,7 +490,8 @@ count_string (struct counting * cnt, struct ccase * c) /* Performs the COUNT transformation T on case C. */ static int -count_trns_proc (struct trns_header * trns, struct ccase * c) +count_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct cnt_var_info *info; struct counting *cnt; diff --git a/src/data-list.c b/src/data-list.c index d0287b6a06..d987a2f746 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -95,8 +95,8 @@ static void dump_fixed_table (const struct dls_var_spec *specs, const struct file_handle *handle, int nrec); static void dump_free_table (const struct data_list_pgm *); static void destroy_dls_var_spec (struct dls_var_spec *); -static void destroy_dls (struct trns_header *); -static int read_one_case (struct trns_header *, struct ccase *); +static trns_free_func destroy_dls; +static trns_proc_func read_one_case; /* Message title for REPEATING DATA. */ #define RPD_ERR "REPEATING DATA: " @@ -1175,7 +1175,8 @@ destroy_dls (struct trns_header *pgm) /* Note that since this is exclusively an input program, C is guaranteed to be temp_case. */ static int -read_one_case (struct trns_header *t, struct ccase *c UNUSED) +read_one_case (struct trns_header *t, struct ccase *c UNUSED, + int case_num UNUSED) { struct data_list_pgm *dls = (struct data_list_pgm *) t; data_list_read_func *read_func; @@ -1250,6 +1251,7 @@ data_list_source_destroy (struct case_source *source) const struct case_source_class data_list_source_class = { "DATA LIST", + NULL, data_list_source_read, data_list_source_destroy, }; @@ -1287,8 +1289,7 @@ struct repeating_data_trns write_case_data wc_data; }; -int repeating_data_trns_proc (struct trns_header *, struct ccase *); -void repeating_data_trns_free (struct trns_header *); +static trns_free_func repeating_data_trns_free; static int parse_num_or_var (struct rpd_num_or_var *, const char *); static int parse_repeating_data (struct dls_var_spec **, struct dls_var_spec **); @@ -1830,7 +1831,8 @@ rpd_parse_record (const struct rpd_parse_info *info) elements in the REPEATING DATA structure. Returns -1 on success, -2 on end of file or on failure. */ int -repeating_data_trns_proc (struct trns_header *trns, struct ccase *c) +repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, + int case_num UNUSED) { struct repeating_data_trns *t = (struct repeating_data_trns *) trns; diff --git a/src/data-list.h b/src/data-list.h index 736d2a5067..494c2ee5a4 100644 --- a/src/data-list.h +++ b/src/data-list.h @@ -26,7 +26,7 @@ #include "var.h" #include "vfm.h" -int repeating_data_trns_proc (struct trns_header *, struct ccase *); +trns_proc_func repeating_data_trns_proc; void repeating_data_set_write_case (struct trns_header *, write_case_func *, write_case_data); diff --git a/src/descript.q b/src/descript.q index 3a3f7da79a..72d5bba4bc 100644 --- a/src/descript.q +++ b/src/descript.q @@ -476,7 +476,8 @@ dump_z_table (void) /* Transformation function to calculate Z-scores. */ static int -descriptives_trns_proc (struct trns_header * trns, struct ccase * c) +descriptives_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct descriptives_trns *t = (struct descriptives_trns *) trns; struct dsc_z_score *z; diff --git a/src/do-if.c b/src/do-if.c index b0014484f0..3397106963 100644 --- a/src/do-if.c +++ b/src/do-if.c @@ -76,9 +76,8 @@ static struct do_if_trns *parse_do_if (void); static void add_ELSE_IF (struct do_if_trns *); -static int goto_trns_proc (struct trns_header *, struct ccase *); -static int do_if_trns_proc (struct trns_header *, struct ccase *); -static void do_if_trns_free (struct trns_header *); +static trns_proc_func goto_trns_proc, do_if_trns_proc; +static trns_free_func do_if_trns_free; /* Parse DO IF. */ int @@ -276,18 +275,20 @@ parse_do_if (void) /* Executes a goto transformation. */ static int -goto_trns_proc (struct trns_header * t, struct ccase * c UNUSED) +goto_trns_proc (struct trns_header * t, struct ccase * c UNUSED, + int case_num UNUSED) { return ((struct goto_trns *) t)->dest; } static int -do_if_trns_proc (struct trns_header * trns, struct ccase * c) +do_if_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct do_if_trns *t = (struct do_if_trns *) trns; union value bool; - expr_evaluate (t->cond, c, &bool); + expr_evaluate (t->cond, c, case_num, &bool); if (bool.f == 1.0) { debug_printf ((_("DO IF %d: true\n"), t->h.index)); diff --git a/src/expr-evl.c b/src/expr-evl.c index a1b540e497..34bbd6ac3d 100644 --- a/src/expr-evl.c +++ b/src/expr-evl.c @@ -51,7 +51,8 @@ #include "vfmP.h" double -expr_evaluate (struct expression *e, struct ccase *c, union value *v) +expr_evaluate (struct expression *e, struct ccase *c, int case_num, + union value *v) { unsigned char *op = e->op; double *dbl = e->num; @@ -1275,7 +1276,7 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v) break; case OP_CASENUM: sp++; - sp->f = vfm_sink_info.ncases + 1; + sp->f = case_num; break; case OP_SENTINEL: diff --git a/src/expr.h b/src/expr.h index 30824966cd..909cf87f17 100644 --- a/src/expr.h +++ b/src/expr.h @@ -38,7 +38,8 @@ struct ccase; union value; struct expression *expr_parse (int flags); -double expr_evaluate (struct expression *, struct ccase *, union value *); +double expr_evaluate (struct expression *, struct ccase *, int case_num, + union value *); void expr_free (struct expression *); #endif /* expr.h */ diff --git a/src/file-type.c b/src/file-type.c index fee9851855..ea0bb332d6 100644 --- a/src/file-type.c +++ b/src/file-type.c @@ -726,6 +726,7 @@ file_type_source_destroy (struct case_source *source) const struct case_source_class file_type_source_class = { "FILE TYPE", + NULL, file_type_source_read, file_type_source_destroy, }; diff --git a/src/flip.c b/src/flip.c index 4ff7045ee2..8ae4ac4ee8 100644 --- a/src/flip.c +++ b/src/flip.c @@ -520,6 +520,7 @@ flip_source_destroy (struct case_source *source) static const struct case_source_class flip_source_class = { "FLIP", + NULL, flip_source_read, flip_source_destroy }; diff --git a/src/get.c b/src/get.c index 8cd3cf783e..be1c09a298 100644 --- a/src/get.c +++ b/src/get.c @@ -56,8 +56,8 @@ struct save_trns static int trim_dictionary (struct dictionary * dict, int *options); 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 *); +static trns_proc_func save_trns_proc; +static trns_free_func save_trns_free; #if DEBUGGING void dump_dict_variables (struct dictionary *); @@ -254,7 +254,7 @@ save_write_case_func (struct ccase * c, void *aux UNUSED) } static int -save_trns_proc (struct trns_header *h, struct ccase * c) +save_trns_proc (struct trns_header *h, struct ccase * c, int case_num UNUSED) { struct save_trns *t = (struct save_trns *) h; do_write_case (t, c); @@ -500,6 +500,7 @@ get_source_read (struct case_source *source, const struct case_source_class get_source_class = { "GET", + NULL, get_source_read, get_source_destroy, }; @@ -1430,6 +1431,7 @@ import_source_read (struct case_source *source, const struct case_source_class import_source_class = { "IMPORT", + NULL, import_source_read, get_source_destroy, }; diff --git a/src/inpt-pgm.c b/src/inpt-pgm.c index 5acf2df414..697d7f5ba5 100644 --- a/src/inpt-pgm.c +++ b/src/inpt-pgm.c @@ -52,10 +52,8 @@ struct input_program_pgm size_t init_cnt; /* Number of elements in inp_init. */ }; -static int end_case_trns_proc (struct trns_header *, struct ccase *); -static int end_file_trns_proc (struct trns_header * t, struct ccase * c); -static int reread_trns_proc (struct trns_header *, struct ccase *); -static void reread_trns_free (struct trns_header *); +static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc; +static trns_free_func reread_trns_free; int cmd_input_program (void) @@ -185,6 +183,12 @@ input_program_source_read (struct case_source *source, cases. */ int end_case = 0; + /* FIXME? This is the number of cases sent out of the input + program, not the number of cases written to the procedure. + The difference should only show up in $CASENUM in COMPUTE. + We should check behavior against SPSS. */ + int cases_written = 0; + assert (inp != NULL); /* Figure end_case. */ @@ -220,6 +224,7 @@ input_program_source_read (struct case_source *source, if (t_trns[i]->proc == end_case_trns_proc) { + cases_written++; if (!write_case (wc_data)) return; clear_case (inp); @@ -227,7 +232,7 @@ input_program_source_read (struct case_source *source, continue; } - code = t_trns[i]->proc (t_trns[i], temp_case); + code = t_trns[i]->proc (t_trns[i], temp_case, cases_written + 1); switch (code) { case -1: @@ -276,6 +281,7 @@ input_program_source_destroy (struct case_source *source) const struct case_source_class input_program_source_class = { "INPUT PROGRAM", + NULL, input_program_source_read, input_program_source_destroy, }; @@ -304,7 +310,8 @@ cmd_end_case (void) } int -end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED) +end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED, + int case_num UNUSED) { assert (0); } @@ -387,7 +394,8 @@ cmd_reread (void) } static int -reread_trns_proc (struct trns_header * pt, struct ccase * c) +reread_trns_proc (struct trns_header * pt, struct ccase * c, + int case_num) { struct reread_trns *t = (struct reread_trns *) pt; @@ -397,7 +405,7 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c) { union value column; - expr_evaluate (t->column, c, &column); + expr_evaluate (t->column, c, case_num, &column); if (!finite (column.f) || column.f < 1) { msg (SE, _("REREAD: Column numbers must be positive finite " @@ -441,7 +449,8 @@ cmd_end_file (void) } static int -end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED) +end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED, + int case_num UNUSED) { #if DEBUGGING printf ("END FILE\n"); diff --git a/src/loop.c b/src/loop.c index e9bb674749..1989a0748a 100644 --- a/src/loop.c +++ b/src/loop.c @@ -140,13 +140,9 @@ static struct loop_3_trns *thr; static int internal_cmd_loop (void); static int internal_cmd_end_loop (void); -static int break_trns_proc (struct trns_header *, struct ccase *); -static int loop_1_trns_proc (struct trns_header *, struct ccase *); -static void loop_1_trns_free (struct trns_header *); -static int loop_2_trns_proc (struct trns_header *, struct ccase *); -static void loop_2_trns_free (struct trns_header *); -static int loop_3_trns_proc (struct trns_header *, struct ccase *); -static void loop_3_trns_free (struct trns_header *); +static trns_proc_func break_trns_proc; +static trns_proc_func loop_1_trns_proc, loop_2_trns_proc, loop_3_trns_proc; +static trns_free_func loop_1_trns_free, loop_2_trns_free, loop_3_trns_free; static void pop_ctl_stack (void); /* LOOP. */ @@ -349,7 +345,8 @@ internal_cmd_end_loop (void) /* Performs transformation 1. */ static int -loop_1_trns_proc (struct trns_header * trns, struct ccase * c) +loop_1_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num) { struct loop_1_trns *one = (struct loop_1_trns *) trns; struct loop_2_trns *two = one->two; @@ -359,12 +356,12 @@ loop_1_trns_proc (struct trns_header * trns, struct ccase * c) { union value t1, t2, t3; - expr_evaluate (one->init, c, &t1); + expr_evaluate (one->init, c, case_num, &t1); if (one->incr) - expr_evaluate (one->incr, c, &t2); + expr_evaluate (one->incr, c, case_num, &t2); else t2.f = 1.0; - expr_evaluate (one->term, c, &t3); + expr_evaluate (one->term, c, case_num, &t3); /* Even if the loop is never entered, force the index variable to assume the initial value. */ @@ -415,7 +412,8 @@ loop_1_trns_free (struct trns_header * trns) /* Performs transformation 2. */ static int -loop_2_trns_proc (struct trns_header * trns, struct ccase * c) +loop_2_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct loop_2_trns *two = (struct loop_2_trns *) trns; @@ -456,7 +454,7 @@ loop_2_trns_proc (struct trns_header * trns, struct ccase * c) /* Conditional clause limiter. */ if ((two->flags & LPC_COND) - && expr_evaluate (two->cond, c, NULL) != 1.0) + && expr_evaluate (two->cond, c, case_num, NULL) != 1.0) return two->loop_term; return -1; @@ -473,13 +471,14 @@ loop_2_trns_free (struct trns_header * trns) /* Performs transformation 3. */ static int -loop_3_trns_proc (struct trns_header * trns, struct ccase * c) +loop_3_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num) { struct loop_3_trns *thr = (struct loop_3_trns *) trns; /* Note that it breaks out of the loop if the expression is true *or missing*. This is conformant. */ - if (thr->cond && expr_evaluate (two->cond, c, NULL) != 0.0) + if (thr->cond && expr_evaluate (two->cond, c, case_num, NULL) != 0.0) return -1; return thr->loop_start; @@ -532,7 +531,8 @@ cmd_break (void) } static int -break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED) +break_trns_proc (struct trns_header * trns, struct ccase * c UNUSED, + int case_num UNUSED) { return ((struct break_trns *) trns)->loop_term; } diff --git a/src/main.c b/src/main.c index c747287c71..d69e661d74 100644 --- a/src/main.c +++ b/src/main.c @@ -60,10 +60,7 @@ int start_interactive; int main (int argc, char **argv) { - struct sigaction bug ; - bug.sa_handler = bug_handler; - - sigaction(SIGSEGV, &bug,0); + signal (SIGSEGV, bug_handler); /* Initialization. */ if (!outp_init ()) diff --git a/src/matrix-data.c b/src/matrix-data.c index 7c3411bcab..1532d1a1c7 100644 --- a/src/matrix-data.c +++ b/src/matrix-data.c @@ -2023,6 +2023,7 @@ wr_read_indeps (struct matrix_data_pgm *mx) static const struct case_source_class matrix_data_with_rowtype_source_class = { "MATRIX DATA", + NULL, matrix_data_read_with_rowtype, NULL, }; @@ -2031,6 +2032,7 @@ static const struct case_source_class matrix_data_without_rowtype_source_class = { "MATRIX DATA", + NULL, matrix_data_read_without_rowtype, NULL, }; diff --git a/src/print.c b/src/print.c index 2fa40ae6e3..9c4b63b20a 100644 --- a/src/print.c +++ b/src/print.c @@ -96,8 +96,8 @@ static struct prt_out_spec *next; static int nrec; static int internal_cmd_print (int flags); -static int print_trns_proc (struct trns_header *, struct ccase *); -static void print_trns_free (struct trns_header *); +static trns_proc_func print_trns_proc; +static trns_free_func print_trns_free; static int parse_specs (void); static void dump_table (void); static void append_var_spec (struct prt_out_spec *spec); @@ -900,7 +900,8 @@ alloc_line (void) /* Performs the transformation inside print_trns T on case C. */ static int -print_trns_proc (struct trns_header * trns, struct ccase * c) +print_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { /* Transformation. */ struct print_trns *t = (struct print_trns *) trns; @@ -1015,8 +1016,8 @@ struct print_space_trns } print_space_trns; -static int print_space_trns_proc (struct trns_header *, struct ccase *); -static void print_space_trns_free (struct trns_header *); +static trns_proc_func print_space_trns_proc; +static trns_free_func print_space_trns_free; int cmd_print_space (void) @@ -1075,7 +1076,8 @@ cmd_print_space (void) } static int -print_space_trns_proc (struct trns_header * trns, struct ccase * c) +print_space_trns_proc (struct trns_header * trns, struct ccase * c, + int case_num UNUSED) { struct print_space_trns *t = (struct print_space_trns *) trns; int n; @@ -1084,7 +1086,7 @@ print_space_trns_proc (struct trns_header * trns, struct ccase * c) { union value v; - expr_evaluate (t->e, c, &v); + expr_evaluate (t->e, c, case_num, &v); n = v.f; if (n < 0) { diff --git a/src/recode.c b/src/recode.c index 543e45ada4..523dcaa644 100644 --- a/src/recode.c +++ b/src/recode.c @@ -104,8 +104,8 @@ struct recode_trns static int parse_dest_spec (struct rcd_var * rcd, union value *v, size_t *max_dst_width); static int parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width); -static int recode_trns_proc (struct trns_header *, struct ccase *); -static void recode_trns_free (struct trns_header *); +static trns_proc_func recode_trns_proc; +static trns_free_func recode_trns_free; static double convert_to_double (char *, int); #if DEBUGGING @@ -772,7 +772,8 @@ find_src_string (struct rcd_var * v, struct ccase * c) } static int -recode_trns_proc (struct trns_header * t, struct ccase * c) +recode_trns_proc (struct trns_header * t, struct ccase * c, + int case_num UNUSED) { struct rcd_var *v; struct coding *cp; diff --git a/src/sample.c b/src/sample.c index 8a5406d142..ce5d18d813 100644 --- a/src/sample.c +++ b/src/sample.c @@ -48,7 +48,7 @@ struct sample_trns unsigned frac; /* TYPE_FRACTION: a fraction of UINT_MAX. */ }; -int sample_trns_proc (struct trns_header *, struct ccase *); +static trns_proc_func sample_trns_proc; int cmd_sample (void) @@ -118,8 +118,9 @@ cmd_sample (void) return lex_end_of_command (); } -int -sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED) +static int +sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED, + int case_num UNUSED) { struct sample_trns *t = (struct sample_trns *) trns; double U; diff --git a/src/sel-if.c b/src/sel-if.c index 07fe318f11..514c44711a 100644 --- a/src/sel-if.c +++ b/src/sel-if.c @@ -33,8 +33,8 @@ struct select_if_trns struct expression *e; /* Test expression. */ }; -static int select_if_proc (struct trns_header *, struct ccase *); -static void select_if_free (struct trns_header *); +static trns_proc_func select_if_proc; +static trns_free_func select_if_free; /* Parses the SELECT IF transformation. */ int @@ -68,9 +68,11 @@ cmd_select_if (void) /* Performs the SELECT IF transformation T on case C. */ static int -select_if_proc (struct trns_header * t, struct ccase * c) +select_if_proc (struct trns_header * t, struct ccase * c, + int case_num) { - return (expr_evaluate (((struct select_if_trns *) t)->e, c, NULL) == 1.0) - 2; + return (expr_evaluate (((struct select_if_trns *) t)->e, c, + case_num, NULL) == 1.0) - 2; } /* Frees SELECT IF transformation T. */ diff --git a/src/sort.c b/src/sort.c index 399823ef76..99d850ad93 100644 --- a/src/sort.c +++ b/src/sort.c @@ -216,11 +216,11 @@ do_internal_sort (struct sort_cases_pgm *scp, int separate) { struct case_list *case_list; struct case_list **case_array; - size_t case_cnt; + int case_cnt; int i; - case_cnt = vfm_source_info.ncases; - if (case_cnt == 0) + case_cnt = vfm_source->class->count (vfm_source); + if (case_cnt <= 0) return isrt; if (case_cnt > set_max_workspace / sizeof *case_array) @@ -327,6 +327,7 @@ struct external_sort size_t run_cnt, run_cap; /* Number of runs, allocated capacity. */ char *temp_dir; /* Temporary file directory name. */ int next_file_idx; /* Lowest unused file index. */ + size_t case_size; /* Number of bytes in case. */ }; /* Prototypes for helper functions. */ @@ -350,6 +351,7 @@ do_external_sort (struct sort_cases_pgm *scp, int separate) xsrt = xmalloc (sizeof *xsrt); xsrt->scp = scp; + xsrt->case_size = sizeof (union value) * compaction_nval; if (!init_external_sort (xsrt)) goto done; if (!write_initial_runs (xsrt, separate)) @@ -614,6 +616,7 @@ struct initial_run_state /* Run currently being output. */ int file_idx; /* Temporary file number. */ size_t case_cnt; /* Number of cases so far. */ + size_t case_size; /* Number of bytes in a case. */ FILE *output_file; /* Output file. */ struct case_list *last_output;/* Record last output. */ @@ -648,6 +651,7 @@ write_initial_runs (struct external_sort *xsrt, int separate) irs->last_output = NULL; irs->file_idx = 0; irs->case_cnt = 0; + irs->case_size = dict_get_case_size (default_dict); irs->okay = 1; if (!allocate_cases (irs)) goto done; @@ -690,7 +694,7 @@ sort_sink_write (struct case_sink *sink, struct ccase *c) assert (irs->record_cnt < irs->record_cap); new_record_run = irs->records + irs->record_cnt++; new_record_run->record = grab_case (irs); - memcpy (new_record_run->record->c.data, c->data, vfm_sink_info.case_size); + memcpy (new_record_run->record->c.data, c->data, irs->case_size); new_record_run->run = irs->file_idx; if (irs->last_output != NULL && compare_record (c->data, irs->last_output->c.data, @@ -1308,7 +1312,7 @@ read_external_sort_output (struct external_sort *xsrt, { FILE *file; int file_idx; - int i; + size_t i; assert (xsrt->run_cnt == 1); file_idx = xsrt->initial_runs[0].file_idx; @@ -1320,10 +1324,10 @@ read_external_sort_output (struct external_sort *xsrt, return; } - for (i = 0; i < vfm_source_info.ncases; i++) + for (i = 0; i < xsrt->initial_runs[0].case_cnt; i++) { if (!read_temp_file (xsrt, file_idx, file, - temp_case, vfm_source_info.case_size)) + temp_case, xsrt->case_size)) { err_failure (); break; @@ -1345,6 +1349,7 @@ sort_source_destroy (struct case_source *source) const struct case_source_class sort_source_class = { "SORT CASES", + NULL, /* FIXME */ sort_source_read, sort_source_destroy, }; diff --git a/src/var.h b/src/var.h index bf2e4d5082..11add5b0da 100644 --- a/src/var.h +++ b/src/var.h @@ -415,17 +415,16 @@ void copy_missing_values (struct variable *dest, const struct variable *src); /* Transformations. */ +struct trns_header; +typedef int trns_proc_func (struct trns_header *, struct ccase *, int); +typedef void trns_free_func (struct trns_header *); + /* Header for all transformations. */ struct trns_header { - /* Index into t_trns[]. */ - int index; - - /* Transformation proc. */ - int (*proc) (struct trns_header *, struct ccase *); - - /* Garbage collector proc. */ - void (*free) (struct trns_header *); + int index; /* Index into t_trns[]. */ + trns_proc_func *proc; /* Transformation proc. */ + trns_free_func *free; /* Garbage collector proc. */ }; /* Array of transformations */ diff --git a/src/vfm.c b/src/vfm.c index 82af200015..a847ea65f2 100644 --- a/src/vfm.c +++ b/src/vfm.c @@ -49,14 +49,16 @@ then deleted and the data sink becomes the data source for the next procedure. */ -#include "debug-print.h" - /* Procedure execution data. */ struct write_case_data { - void (*beginfunc) (void *); - int (*procfunc) (struct ccase *, void *); - void (*endfunc) (void *); + /* Functions to call... */ + void (*begin_func) (void *); /* ...before data. */ + int (*proc_func) (struct ccase *, void *); /* ...with data. */ + void (*end_func) (void *); /* ...after data. */ + void *func_aux; /* Auxiliary data. */ + + /* Extra auxiliary data. */ void *aux; }; @@ -66,18 +68,11 @@ struct case_source *vfm_source; /* The replacement active file, to which cases are written. */ struct case_sink *vfm_sink; -/* Information about the data source. */ -struct stream_info vfm_source_info; - -/* Information about the data sink. */ -struct stream_info vfm_sink_info; - /* Nonzero if the case needs to have values deleted before being stored, zero otherwise. */ int compaction_necessary; -/* Number of values after compaction, or the same as - vfm_sink_info.nval, if compaction is not necessary. */ +/* Number of values after compaction. */ int compaction_nval; /* Temporary case buffer with enough room for `compaction_nval' @@ -104,58 +99,74 @@ static struct ccase **lag_queue; /* Array of n_lag ccase * elements. */ static void open_active_file (void); static void close_active_file (struct write_case_data *); -static int SPLIT_FILE_procfunc (struct ccase *, void *); +static int SPLIT_FILE_proc_func (struct ccase *, void *); static void finish_compaction (void); static void lag_case (void); static int procedure_write_case (struct write_case_data *); static void clear_temp_case (void); -static int exclude_this_case (void); +static int exclude_this_case (int case_num); /* Public functions. */ +struct procedure_aux_data + { + size_t cases_written; /* Number of cases written so far. */ + }; + +struct split_aux_data + { + struct ccase *prev_case; /* Data in previous case. */ + }; + /* Reads all the cases from the active file, transforms them by - the active set of transformations, calls PROCFUNC with CURCASE + the active set of transformations, calls PROC_FUNC 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 + cases each. BEGIN_FUNC is called before each series. END_FUNC is called after each series. - Arbitrary user-specified data AUX is passed to BEGINFUNC, - PROCFUNC, and ENDFUNC as auxiliary data. */ + Arbitrary user-specified data AUX is passed to BEGIN_FUNC, + PROC_FUNC, and END_FUNC as auxiliary data. */ void -procedure (void (*beginfunc) (void *), - int (*procfunc) (struct ccase *curcase, void *), - void (*endfunc) (void *), - void *aux) +procedure (void (*begin_func) (void *), + int (*proc_func) (struct ccase *curcase, void *), + void (*end_func) (void *), + void *func_aux) { static int recursive_call; struct write_case_data procedure_write_data; + struct procedure_aux_data proc_aux; + struct write_case_data split_file_data; + struct split_aux_data split_aux; + int split; assert (++recursive_call == 1); - if (dict_get_split_cnt (default_dict) == 0) - { - /* 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 + proc_aux.cases_written = 0; + + /* Normally we just use the data passed by the user. */ + procedure_write_data.begin_func = begin_func; + procedure_write_data.proc_func = proc_func; + procedure_write_data.end_func = end_func; + procedure_write_data.func_aux = func_aux; + procedure_write_data.aux = &proc_aux; + + /* Under SPLIT FILE, we add a layer of indirection. */ + split = dict_get_split_cnt (default_dict) > 0; + if (split) { - /* 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; + split_file_data = procedure_write_data; + split_file_data.aux = &split_aux; + + split_aux.prev_case = xmalloc (dict_get_case_size (default_dict)); + + procedure_write_data.begin_func = NULL; + procedure_write_data.proc_func = SPLIT_FILE_proc_func; + procedure_write_data.end_func = end_func; + procedure_write_data.func_aux = &split_file_data; } last_vfm_invocation = time (NULL); @@ -166,6 +177,9 @@ procedure (void (*beginfunc) (void *), procedure_write_case, &procedure_write_data); close_active_file (&procedure_write_data); + if (split) + free (split_aux.prev_case); + assert (--recursive_call == 0); } @@ -179,35 +193,32 @@ static int not_canceled; /* Reads all the cases from the active file and passes them one-by-one to CASEFUNC in temp_case. Before any cases are passed, calls - BEGINFUNC. After all the cases have been passed, calls ENDFUNC. - BEGINFUNC, CASEFUNC, and ENDFUNC can write temp_case to the output + BEGIN_FUNC. After all the cases have been passed, calls END_FUNC. + BEGIN_FUNC, CASEFUNC, and END_FUNC can write temp_case to the output file by calling process_active_file_output_case(). process_active_file() ignores TEMPORARY, SPLIT FILE, and N. */ void -process_active_file (void (*beginfunc) (void *), +process_active_file (void (*begin_func) (void *), int (*casefunc) (struct ccase *curcase, void *), - void (*endfunc) (void *), - void *aux) + void (*end_func) (void *), + void *func_aux) { 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; + process_active_write_data.begin_func = begin_func; + process_active_write_data.proc_func = casefunc; + process_active_write_data.end_func = end_func; + process_active_write_data.func_aux = func_aux; not_canceled = 1; open_active_file (); - beginfunc (aux); - - /* There doesn't necessarily need to be an active file. */ + begin_func (func_aux); if (vfm_source != NULL) vfm_source->class->read (vfm_source, process_active_file_write_case, &process_active_write_data); - - endfunc (aux); + end_func (func_aux); close_active_file (&process_active_write_data); } @@ -222,7 +233,8 @@ process_active_file_write_case (struct write_case_data *data) { int code; - code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case); + code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case, + case_count + 1); switch (code) { case -1: @@ -243,8 +255,8 @@ process_active_file_write_case (struct write_case_data *data) lag_case (); /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */ - if (not_canceled && !exclude_this_case ()) - not_canceled = data->procfunc (temp_case, data->aux); + if (not_canceled && !exclude_this_case (case_count + 1)) + not_canceled = data->proc_func (temp_case, data->func_aux); case_count++; @@ -258,7 +270,6 @@ process_active_file_write_case (struct write_case_data *data) void process_active_file_output_case (void) { - vfm_sink_info.ncases++; vfm_sink->class->write (vfm_sink, temp_case); } @@ -285,24 +296,8 @@ prepare_for_writing (void) So, in this case, we shouldn't have to replace the active file--it's just a waste of time and space. */ - vfm_sink_info.ncases = 0; - vfm_sink_info.nval = dict_get_next_value_idx (default_dict); - vfm_sink_info.case_size = dict_get_case_size (default_dict); - if (vfm_sink == NULL) { - if (vfm_sink_info.case_size * vfm_source_info.ncases > set_max_workspace - && !workspace_overflow) - { - msg (MW, _("Workspace overflow predicted. Max workspace is " - "currently set to %d KB (%d cases at %d bytes each). " - "Writing active file to disk."), - set_max_workspace / 1024, set_max_workspace / vfm_sink_info.case_size, - vfm_sink_info.case_size); - - workspace_overflow = 1; - } - if (workspace_overflow) vfm_sink = create_case_sink (&disk_sink_class, NULL); else @@ -350,7 +345,7 @@ arrange_compaction (void) static void make_temp_case (void) { - temp_case = xmalloc (vfm_sink_info.case_size); + temp_case = xmalloc (dict_get_case_size (default_dict)); if (compaction_necessary) compaction_case = xmalloc (sizeof (struct ccase) @@ -422,34 +417,23 @@ setup_lag (void) Here is each nval count, with explanation, as set up by open_active_file(): - vfm_source_info.nval: Number of `value's in the cases returned by - the source stream. This value turns out not to be very useful, but - we maintain it anyway. - - vfm_sink_info.nval: Number of `value's in the cases after all - transformations have been performed. Never less than - vfm_source_info.nval. - temp_dict->nval: Number of `value's in the cases after the - transformations leading up to TEMPORARY have been performed. If - TEMPORARY was not specified, this is equal to vfm_sink_info.nval. - Never less than vfm_sink_info.nval. + transformations leading up to TEMPORARY have been performed. compaction_nval: Number of `value's in the cases after the - transformations leading up to TEMPORARY have been performed and the - case has been compacted by compact_case(), if compaction is - necessary. This the number of `value's in the cases saved by the - sink stream. (However, note that the cases passed to the sink - stream have not yet been compacted. It is the responsibility of - the data sink to call compact_case().) This may be less than, - greater than, or equal to vfm_source_info.nval. `compaction' - becomes the new value of default_dict.nval after the procedure is - completed. - - default_dict.nval: This is often an alias for temp_dict->nval. As - such it can really have no separate existence until the procedure - is complete. For this reason it should *not* be referenced inside - the execution of a procedure. */ + transformations leading up to TEMPORARY have been performed + and the case has been compacted by compact_case(), if + compaction is necessary. This the number of `value's in the + cases saved by the sink stream. (However, note that the cases + passed to the sink stream have not yet been compacted. It is + the responsibility of the data sink to call compact_case().) + `compaction' becomes the new value of default_dict.nval after + the procedure is completed. + + default_dict.nval: This is often an alias for temp_dict->nval. + As such it can really have no separate existence until the + procedure is complete. For this reason it should *not* be + referenced inside the execution of a procedure. */ /* Makes all preparations for reading from the data source and writing to the data sink. */ static void @@ -476,15 +460,6 @@ open_active_file (void) vector_initialization (); discard_ctl_stack (); setup_lag (); - - /* Debug output. */ - debug_printf (("vfm: reading from %s source, writing to %s sink.\n", - vfm_source->name, vfm_sink->name)); - debug_printf (("vfm: vfm_source_info.nval=%d, vfm_sink_info.nval=%d, " - "temp_dict->nval=%d, compaction_nval=%d, " - "default_dict.nval=%d\n", - vfm_source_info.nval, vfm_sink_info.nval, temp_dict->nval, - compaction_nval, default_dict.nval)); } /* Closes the active file. */ @@ -492,8 +467,8 @@ static void close_active_file (struct write_case_data *data) { /* Close the current case group. */ - if (case_count && data->endfunc != NULL) - data->endfunc (data->aux); + if (case_count && data->end_func != NULL) + data->end_func (data->func_aux); /* Stop lagging (catch up?). */ if (n_lag) @@ -528,10 +503,6 @@ close_active_file (struct write_case_data *data) } vfm_source = vfm_sink->class->make_source (vfm_sink); - vfm_source_info.ncases = vfm_sink_info.ncases; - vfm_source_info.nval = compaction_nval; - vfm_source_info.case_size = (sizeof (struct ccase) - + (compaction_nval - 1) * sizeof (union value)); /* Old data sink is gone now. */ free (vfm_sink); @@ -563,18 +534,28 @@ close_active_file (struct write_case_data *data) /* Clear VECTOR vectors. */ dict_clear_vectors (default_dict); - - debug_printf (("vfm: procedure complete\n\n")); } /* Disk case stream. */ +/* Information about disk sink or source. */ +struct disk_stream_info + { + FILE *file; /* Output file. */ + size_t case_cnt; /* Number of cases written so far. */ + size_t case_size; /* Number of bytes in case. */ + }; + /* Initializes the disk sink. */ static void disk_sink_create (struct case_sink *sink) { - sink->aux = tmpfile (); - if (!sink->aux) + struct disk_stream_info *info = xmalloc (sizeof *info); + info->file = tmpfile (); + info->case_cnt = 0; + info->case_size = compaction_nval; + sink->aux = info; + if (info->file == NULL) { msg (ME, _("An error occurred attempting to create a temporary " "file for use as the active file: %s."), @@ -587,7 +568,7 @@ disk_sink_create (struct case_sink *sink) static void disk_sink_write (struct case_sink *sink, struct ccase *c) { - FILE *file = sink->aux; + struct disk_stream_info *info = sink->aux; union value *src_case; if (compaction_necessary) @@ -597,7 +578,9 @@ disk_sink_write (struct case_sink *sink, struct ccase *c) } else src_case = c->data; - if (fwrite (src_case, sizeof *src_case * compaction_nval, 1, file) != 1) + info->case_cnt++; + if (fwrite (src_case, sizeof *src_case * compaction_nval, 1, + info->file) != 1) { msg (ME, _("An error occurred while attempting to write to a " "temporary file used as the active file: %s."), @@ -610,9 +593,9 @@ disk_sink_write (struct case_sink *sink, struct ccase *c) static void disk_sink_destroy (struct case_sink *sink) { - FILE *file = sink->aux; - if (file != NULL) - fclose (file); + struct disk_stream_info *info = sink->aux; + if (info->file != NULL) + fclose (info->file); } /* Closes and destroys the sink and returns a disk source to read @@ -620,11 +603,11 @@ disk_sink_destroy (struct case_sink *sink) static struct case_source * disk_sink_make_source (struct case_sink *sink) { - FILE *file = sink->aux; - + struct disk_stream_info *info = sink->aux; + /* Rewind the file. */ - assert (file != NULL); - if (fseek (file, 0, SEEK_SET) != 0) + assert (info->file != NULL); + if (fseek (info->file, 0, SEEK_SET) != 0) { msg (ME, _("An error occurred while attempting to rewind a " "temporary file used as the active file: %s."), @@ -632,7 +615,7 @@ disk_sink_make_source (struct case_sink *sink) err_failure (); } - return create_case_source (&disk_source_class, file); + return create_case_source (&disk_source_class, info); } /* Disk sink. */ @@ -647,18 +630,28 @@ const struct case_sink_class disk_sink_class = /* Disk source. */ +/* Returns the number of cases that will be read by + disk_source_read(). */ +static int +disk_source_count (const struct case_source *source) +{ + struct disk_stream_info *info = source->aux; + + return info->case_cnt; +} + /* Reads all cases from the disk source and passes them one by one to write_case(). */ static void disk_source_read (struct case_source *source, write_case_func *write_case, write_case_data wc_data) { - FILE *file = source->aux; + struct disk_stream_info *info = source->aux; int i; - for (i = 0; i < vfm_source_info.ncases; i++) + for (i = 0; i < info->case_cnt; i++) { - if (!fread (temp_case, vfm_source_info.case_size, 1, file)) + if (!fread (temp_case, info->case_size, 1, info->file)) { msg (ME, _("An error occurred while attempting to read from " "a temporary file created for the active file: %s."), @@ -676,15 +669,17 @@ disk_source_read (struct case_source *source, static void disk_source_destroy (struct case_source *source) { - FILE *file = source->aux; - if (file != NULL) - fclose (file); + struct disk_stream_info *info = source->aux; + if (info->file != NULL) + fclose (info->file); + free (info); } /* Disk source. */ const struct case_source_class disk_source_class = { "disk", + disk_source_count, disk_source_read, disk_source_destroy, }; @@ -694,6 +689,8 @@ const struct case_source_class disk_source_class = /* Memory sink data. */ struct memory_sink_info { + size_t case_cnt; /* Number of cases. */ + size_t case_size; /* Case size in bytes. */ int max_cases; /* Maximum cases before switching to disk. */ struct case_list *head; /* First case in list. */ struct case_list *tail; /* Last case in list. */ @@ -702,6 +699,8 @@ struct memory_sink_info /* Memory source data. */ struct memory_source_info { + size_t case_cnt; /* Number of cases. */ + size_t case_size; /* Case size in bytes. */ struct case_list *cases; /* List of cases. */ }; @@ -713,7 +712,9 @@ memory_sink_create (struct case_sink *sink) sink->aux = info = xmalloc (sizeof *info); assert (compaction_nval > 0); - info->max_cases = set_max_workspace / (sizeof (union value) * compaction_nval); + info->case_cnt = 0; + info->case_size = compaction_nval * sizeof (union value); + info->max_cases = set_max_workspace / info->case_size; info->head = info->tail = NULL; } @@ -729,8 +730,10 @@ memory_sink_write (struct case_sink *sink, struct ccase *c) new_case = malloc (case_size); /* If we've got memory to spare then add it to the linked list. */ - if (vfm_sink_info.ncases <= info->max_cases && new_case != NULL) + if (info->case_cnt <= info->max_cases && new_case != NULL) { + info->case_cnt++; + /* Append case to linked list. */ new_case->next = NULL; if (info->head != NULL) @@ -852,6 +855,8 @@ memory_sink_make_source (struct case_sink *sink) struct memory_source_info *source_info; source_info = xmalloc (sizeof *source_info); + source_info->case_cnt = sink_info->case_cnt; + source_info->case_size = sink_info->case_size; source_info->cases = sink_info->head; free (sink_info); @@ -868,6 +873,15 @@ const struct case_sink_class memory_sink_class = memory_sink_make_source, }; +/* Returns the number of cases in the source. */ +static int +memory_source_count (const struct case_source *source) +{ + struct memory_source_info *info = source->aux; + + return info->case_cnt; +} + /* Reads the case stream from memory and passes it to write_case(). */ static void memory_source_read (struct case_source *source, @@ -879,7 +893,7 @@ memory_source_read (struct case_source *source, { struct case_list *iter = info->cases; info->cases = iter->next; - memcpy (temp_case, &iter->c, vfm_source_info.case_size); + memcpy (temp_case, &iter->c, info->case_size); free (iter); if (!write_case (wc_data)) @@ -923,12 +937,11 @@ memory_source_set_cases (const struct case_source *source, const struct case_source_class memory_source_class = { "memory", + memory_source_count, memory_source_read, memory_source_destroy, }; -#include "debug-print.h" - /* Add temp_case to the lag queue. */ static void lag_case (void) @@ -965,44 +978,43 @@ lagged_case (int n_before) int procedure_write_case (write_case_data wc_data) { + struct procedure_aux_data *proc_aux = wc_data->aux; + /* Index of current transformation. */ int cur_trns; /* Return value: whether it's reasonable to write any more cases. */ int more_cases = 1; - debug_printf ((_("transform: "))); - cur_trns = f_trns; for (;;) { /* Output the case if this is temp_trns. */ if (cur_trns == temp_trns) { - debug_printf (("REC")); + int case_limit; if (n_lag) lag_case (); - vfm_sink_info.ncases++; vfm_sink->class->write (vfm_sink, temp_case); - if (dict_get_case_limit (default_dict)) - more_cases = (vfm_sink_info.ncases - < dict_get_case_limit (default_dict)); + proc_aux->cases_written++; + case_limit = dict_get_case_limit (default_dict); + if (case_limit != 0 && proc_aux->cases_written >= case_limit) + more_cases = 0; } /* Are we done? */ if (cur_trns >= n_trns) break; - debug_printf (("$%d", cur_trns)); - /* Decide which transformation should come next. */ { int code; - code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case); + code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case, + proc_aux->cases_written + 1); switch (code) { case -1: @@ -1021,19 +1033,18 @@ procedure_write_case (write_case_data wc_data) } /* Call the beginning of group function. */ - if (!case_count && wc_data->beginfunc != NULL) - wc_data->beginfunc (wc_data->aux); + if (!case_count && wc_data->begin_func != NULL) + wc_data->begin_func (wc_data->func_aux); /* Call the procedure if there is one and FILTER and PROCESS IF don't prohibit it. */ - if (wc_data->procfunc != NULL && !exclude_this_case ()) - wc_data->procfunc (temp_case, wc_data->aux); + if (wc_data->proc_func != NULL + && !exclude_this_case (proc_aux->cases_written + 1)) + wc_data->proc_func (temp_case, wc_data->func_aux); case_count++; done: - debug_putc ('\n', stdout); - clear_temp_case (); /* Return previously determined value. */ @@ -1063,10 +1074,11 @@ clear_temp_case (void) } } -/* Returns nonzero if this case should be exclude as specified on - FILTER or PROCESS IF, otherwise zero. */ +/* Returns nonzero if this case (numbered CASE_NUM) should be + exclude as specified on FILTER or PROCESS IF, otherwise + zero. */ static int -exclude_this_case (void) +exclude_this_case (int case_num) { /* FILTER. */ struct variable *filter_var = dict_get_filter (default_dict); @@ -1079,7 +1091,7 @@ exclude_this_case (void) /* PROCESS IF. */ if (process_if_expr != NULL - && expr_evaluate (process_if_expr, temp_case, NULL) != 1.0) + && expr_evaluate (process_if_expr, temp_case, case_num, NULL) != 1.0) return 1; return 0; @@ -1159,14 +1171,14 @@ dump_splits (struct ccase *c) tab_submit (t); } -/* This procfunc is substituted for the user-supplied procfunc when +/* This proc_func is substituted for the user-supplied proc_func when SPLIT FILE is active. This function forms a wrapper around that - procfunc by dividing the input into series. */ + proc_func by dividing the input into series. */ static int -SPLIT_FILE_procfunc (struct ccase *c, void *data_) +SPLIT_FILE_proc_func (struct ccase *c, void *data_) { struct write_case_data *data = data_; - static struct ccase *prev_case; + struct split_aux_data *split_aux = data->aux; struct variable *const *split; size_t split_cnt; size_t i; @@ -1175,16 +1187,13 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_) preserve the values of the case for later comparison. */ if (case_count == 0) { - if (prev_case) - free (prev_case); - prev_case = xmalloc (vfm_sink_info.case_size); - memcpy (prev_case, c, vfm_sink_info.case_size); + memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict)); dump_splits (c); - if (data->beginfunc != NULL) - data->beginfunc (data->aux); + if (data->begin_func != NULL) + data->begin_func (data->func_aux); - return data->procfunc (c, data->aux); + return data->proc_func (c, data->func_aux); } /* Compare the value of each SPLIT FILE variable to the values on @@ -1198,30 +1207,31 @@ SPLIT_FILE_procfunc (struct ccase *c, void *data_) switch (v->type) { case NUMERIC: - if (c->data[v->fv].f != prev_case->data[v->fv].f) + if (c->data[v->fv].f != split_aux->prev_case->data[v->fv].f) goto not_equal; break; case ALPHA: - if (memcmp (c->data[v->fv].s, prev_case->data[v->fv].s, v->width)) + if (memcmp (c->data[v->fv].s, + split_aux->prev_case->data[v->fv].s, v->width)) goto not_equal; break; default: assert (0); } } - return data->procfunc (c, data->aux); + return data->proc_func (c, data->func_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 (data->endfunc != NULL) - data->endfunc (data->aux); + if (data->end_func != NULL) + data->end_func (data->func_aux); dump_splits (c); - if (data->beginfunc != NULL) - data->beginfunc (data->aux); - memcpy (prev_case, c, vfm_sink_info.case_size); - return data->procfunc (c, data->aux); + if (data->begin_func != NULL) + data->begin_func (data->func_aux); + memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict)); + return data->proc_func (c, data->func_aux); } /* Case compaction. */ @@ -1304,7 +1314,6 @@ case_source_is_class (const struct case_source *source, const struct case_source_class *class) { return source != NULL && source->class == class; - } struct case_sink * diff --git a/src/vfm.h b/src/vfm.h index f50b45ee38..186dd6f1d0 100644 --- a/src/vfm.h +++ b/src/vfm.h @@ -46,6 +46,10 @@ struct case_source_class { const char *name; /* Identifying name. */ + /* Returns the exact number of cases that READ will pass to + WRITE_CASE, if known, or -1 otherwise. */ + int (*count) (const struct case_source *); + /* Reads all the cases and calls WRITE_CASE passing the given AUX data for each one. */ void (*read) (struct case_source *, write_case_func *, write_case_data); diff --git a/src/vfmP.h b/src/vfmP.h index eb52f0ed96..d29200ea05 100644 --- a/src/vfmP.h +++ b/src/vfmP.h @@ -22,26 +22,11 @@ #include "var.h" -/* Describes a data stream, either a source or a sink. */ -struct stream_info - { - int case_size; /* Size of one case in bytes. */ - int ncases; /* Number of cases. */ - int nval; /* Number of `value' elements per case. */ - }; - -/* Information about the data source. */ -extern struct stream_info vfm_source_info; - -/* Information about the data sink. */ -extern struct stream_info vfm_sink_info; - /* Nonzero if the case needs to have values deleted before being stored, zero otherwise. */ extern int compaction_necessary; -/* Number of values after compaction, or the same as - vfm_sink_info.nval, if compaction is not necessary. */ +/* Number of values after compaction. */ extern int compaction_nval; /* Temporary case buffer with enough room for `compaction_nval'