+Wed Mar 3 09:30:09 2004 Ben Pfaff <blp@gnu.org>
+
+ * main.c: (main) sigaction()'s sa_flags member was uninitialized.
+ Just use signal() instead.
+
+Wed Mar 3 09:26:30 2004 Ben Pfaff <blp@gnu.org>
+
+ 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 <blp@gnu.org>
+
+ * 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 <blp@gnu.org>
* frequencies.q: (cleanup_freq_tab) Avoid memory leak by
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);
/* 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));
/* 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);
}
/* 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);
-#ifndef SORT_ALGO_H
-#define SORT_ALGO_H 1
+#ifndef ALGORITHM_H
+#define ALGORITHM_H 1
#include <stddef.h>
algo_compare_func *compare, void *aux);
-#endif /* sort-algo.h */
+#endif /* algorithm.h */
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;
}
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;
/* 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;
/* 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)
{
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]);
}
}
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]);
}
}
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;
/* 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)
{
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]);
}
\f
/* 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 *);
/* 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;
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: "
/* 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;
const struct case_source_class data_list_source_class =
{
"DATA LIST",
+ NULL,
data_list_source_read,
data_list_source_destroy,
};
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 **);
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;
#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);
/* 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;
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
/* 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));
#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;
break;
case OP_CASENUM:
sp++;
- sp->f = vfm_sink_info.ncases + 1;
+ sp->f = case_num;
break;
case OP_SENTINEL:
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 */
const struct case_source_class file_type_source_class =
{
"FILE TYPE",
+ NULL,
file_type_source_read,
file_type_source_destroy,
};
static const struct case_source_class flip_source_class =
{
"FLIP",
+ NULL,
flip_source_read,
flip_source_destroy
};
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 *);
}
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);
const struct case_source_class get_source_class =
{
"GET",
+ NULL,
get_source_read,
get_source_destroy,
};
const struct case_source_class import_source_class =
{
"IMPORT",
+ NULL,
import_source_read,
get_source_destroy,
};
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)
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. */
if (t_trns[i]->proc == end_case_trns_proc)
{
+ cases_written++;
if (!write_case (wc_data))
return;
clear_case (inp);
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:
const struct case_source_class input_program_source_class =
{
"INPUT PROGRAM",
+ NULL,
input_program_source_read,
input_program_source_destroy,
};
}
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);
}
}
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;
{
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 "
}
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");
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);
\f
/* LOOP. */
/* 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;
{
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. */
/* 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;
/* 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;
/* 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;
}
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;
}
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 ())
static const struct case_source_class matrix_data_with_rowtype_source_class =
{
"MATRIX DATA",
+ NULL,
matrix_data_read_with_rowtype,
NULL,
};
matrix_data_without_rowtype_source_class =
{
"MATRIX DATA",
+ NULL,
matrix_data_read_without_rowtype,
NULL,
};
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);
/* 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;
}
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)
}
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;
{
union value v;
- expr_evaluate (t->e, c, &v);
+ expr_evaluate (t->e, c, case_num, &v);
n = v.f;
if (n < 0)
{
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
}
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;
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)
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;
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
/* 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. */
{
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)
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. */
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))
/* 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. */
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;
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,
{
FILE *file;
int file_idx;
- int i;
+ size_t i;
assert (xsrt->run_cnt == 1);
file_idx = xsrt->initial_runs[0].file_idx;
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;
const struct case_source_class sort_source_class =
{
"SORT CASES",
+ NULL, /* FIXME */
sort_source_read,
sort_source_destroy,
};
\f
/* 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 */
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;
};
/* 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'
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);
\f
/* 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);
procedure_write_case, &procedure_write_data);
close_active_file (&procedure_write_data);
+ if (split)
+ free (split_aux.prev_case);
+
assert (--recursive_call == 0);
}
\f
/* 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);
}
{
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:
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++;
void
process_active_file_output_case (void)
{
- vfm_sink_info.ncases++;
vfm_sink->class->write (vfm_sink, temp_case);
}
\f
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
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)
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
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));
}
\f
/* Closes the active file. */
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)
}
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);
/* Clear VECTOR vectors. */
dict_clear_vectors (default_dict);
-
- debug_printf (("vfm: procedure complete\n\n"));
}
\f
/* 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."),
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)
}
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."),
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
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."),
err_failure ();
}
- return create_case_source (&disk_source_class, file);
+ return create_case_source (&disk_source_class, info);
}
/* Disk sink. */
\f
/* 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."),
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,
};
/* 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. */
/* 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. */
};
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;
}
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)
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);
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,
{
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))
const struct case_source_class memory_source_class =
{
"memory",
+ memory_source_count,
memory_source_read,
memory_source_destroy,
};
\f
-#include "debug-print.h"
-
/* Add temp_case to the lag queue. */
static void
lag_case (void)
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:
}
/* 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. */
}
}
-/* 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);
/* 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;
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;
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
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);
}
\f
/* Case compaction. */
const struct case_source_class *class)
{
return source != NULL && source->class == class;
-
}
struct case_sink *
{
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);
#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'