From 37597beca4a11edba50b847932fdfeca3a648fa2 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 10 Mar 2004 07:40:03 +0000 Subject: [PATCH] Eliminate temp_case, and a few other cleanups. --- TODO | 4 +- doc/ChangeLog | 4 + doc/pspp.texi | 5 + src/ChangeLog | 140 ++++++++++++++++++++++++ src/aggregate.c | 69 ++++++------ src/compute.c | 17 ++- src/data-list.c | 135 ++++++++++++----------- src/expr-evl.c | 2 +- src/expr.h | 2 +- src/file-type.c | 13 ++- src/flip.c | 273 +++++++++++++++++++++------------------------- src/format.c | 108 ++++++++++++------ src/format.h | 4 +- src/frequencies.q | 6 +- src/get.c | 104 ++++++++++-------- src/glob.c | 2 - src/inpt-pgm.c | 88 ++++++++------- src/loop.c | 61 +++++------ src/matrix-data.c | 55 ++++++---- src/pfm-read.c | 6 +- src/postscript.c | 4 +- src/print.c | 2 + src/recode.c | 1 + src/sample.c | 1 + src/sfm-read.c | 6 +- src/sort.c | 157 ++++++++++++++++---------- src/sort.h | 6 +- src/vars-prs.c | 54 +++++++-- src/vfm.c | 248 +++++++++++++++++++++-------------------- src/vfm.h | 33 +++--- src/weight.c | 7 -- 31 files changed, 959 insertions(+), 658 deletions(-) diff --git a/TODO b/TODO index 9eba3496..a4c5c7c2 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,10 @@ -Time-stamp: <2004-02-24 19:22:15 blp> +Time-stamp: <2004-03-05 15:22:29 blp> TODO ---- +In debug mode hash table code should verify that collisions are reasonably low. + Use posix_fadvise(POSIX_FADV_SEQUENTIAL) where available. random.c should not know about set_seed. diff --git a/doc/ChangeLog b/doc/ChangeLog index b9cf67aa..dbf6547f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +Tue Mar 9 22:34:17 2004 Ben Pfaff + + * Updated. + Wed Feb 18 18:15:48 2004 Ben Pfaff * Improve CROSSTABS description diff --git a/doc/pspp.texi b/doc/pspp.texi index aceaf8a5..564e36ec 100644 --- a/doc/pspp.texi +++ b/doc/pspp.texi @@ -5806,6 +5806,11 @@ columns that the identifier will occupy, followed by an equals sign (@samp{=}) and the identifier variable name. The variable must already have been declared with @cmd{NUMERIC} or another command. +@cmd{REPEATING DATA} should be the last command given within an +@cmd{INPUT PROGRAM}. It should not be enclosed within a @cmd{LOOP} +structure (@pxref{LOOP}). Use @cmd{DATA LIST} before, not after, +@cmd{REPEATING DATA}. + @node WRITE, , REPEATING DATA, Data Input and Output @section WRITE @vindex WRITE diff --git a/src/ChangeLog b/src/ChangeLog index 0dcff3dc..5e7f0c1a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,143 @@ +Tue Mar 9 23:10:41 2004 Ben Pfaff + + * format.c: (global array translate_fmt[]) Removed. + (translate_fmt) New function as replacement. + (parse_format_specifier_name) Rewrite. + + * pfm-read.c: (convert_format) Use translate_fmt() instead of + translate_fmt[]. + + * sfm-read.c: (parse_format_spec) Ditto. + + * postscript.c: (text) Fix handling of fonts with missing + ligatures. + + * sort.c: (struct external_sort) Add temp_name member. + (destroy_external_sort) Free temp_dir, temp_name members. + (init_external_sort) Allocate temp_name. + (get_temp_file_name) Change prototype. + (open_temp_file) Deal with change to get_temp_file_name(). + (close_temp_file) Ditto. + (remove_temp_file) Ditto. + (write_temp_file) Ditto. + (read_temp_file) Ditto. + (sort_sink_destroy) Removed. + (sort_sink_class) Change destroy member to null. + +Tue Mar 9 22:36:34 2004 Ben Pfaff + + Eliminate temp_case. + + * aggregate.c: (cmd_aggregate) No need to save/restore temp_case + anymore. Use agr_11x_finish(). + (aggregate_single_case) Make first param const. + (accumulate_aggregate_info) Ditto. + (agr_00x_end_func) Use compaction_case, not temp_case. + (agr_11x_func) Break into agr_11x_read(), agr_11x_finish(). + + * data-list.c: (struct data_list_pgm) Add `case_size' member. + (cmd_data_list) Initialize case_size. + (read_from_data_list_fixed) Add struct ccase * param, use instead + of temp_case. + (read_from_data_list_free) Ditto. + (read_from_data_list_list) Ditto. + (read_one_case) Rename data_list_trns_proc(), all references + updated. Add argument in calling above functions. Use c + argument instead of temp_case. + (destroy_dls) Rename data_list_trns_free(), all references + updated. + + * expr-evl.c: (expr_evaluate) Make second parameter const. + + * file-type.c: (struct file_type_pgm) Add `case_size' member. + (cmd_end_file_type) Initialize `case_size'. + (file_type_source_read) Add struct ccase * parameter. Use instead + of temp_case. + + * flip.c: Rewritten. + + * get.c: (struct get_pgm) New structure to keep track of + case_size. + (cmd_get) Initialize case_size. + (cmd_import) Ditto. + (get_source) Deal with struct get_pgm. + (get_source_read) Add struct ccase * parameter, use instead of + temp_case. + (import_source_read) Ditto. + + * get.c: Use a null pointer instead of temp_case to represent the + "current case" in a struct mtf_file's input member. + (mtf_processing_finish) Pass null to mtf_processing(), not + temp_case. + (mtf_read_nonactive_records) Don't set iter->input to temp_case. + (mtf_compare_BY_values) Add extra arg, use instead of null input + members. + (mtf_processing) Use c parameter instead of temp_case. Pass + compaction_case to process_active_file_output_case(). + + * glob.c: (global variable temp_case) Removed. + + * inpt-pgm.c: (struct input_program_pgm) Add `case_size' member. + (cmd_input_program) Initialize case_size. Set + vfm_source->value_cnt. + (init_case) Add struct ccase * parameter, use instead of + temp_case. + (clear_case) Ditto. + (input_program_source_read) Ditto. + + * matrix-data.c: (matrix_data_read_without_rowtype) Ditto. + (dump_cell_content) Ditto. + (nr_output_data) Ditto. + (read_matrices_without_rowtype) Ditto. + (matrix_data_read_with_rowtype) Ditto. + (wr_read_splits) Ditto. + (wr_output_data) Ditto. + + * sort.h: (struct sort_cases_pgm) New member `case_size'. + + * sort.c: (sort_cases) Initialize scp->case_size. + (struct external_sort) Remove `case_size' member. + (write_initial_runs) Only call vfm_sink->class_destroy if + non-null. + (struct sort_source_aux) New structure. + (sort_source_read_helper) New function. + (sort_source_read) Use sort_source_read_helper(). + (read_sort_output) Change interface to be more reasonable. + (read_internal_sort_output) Ditto. + (read_external_sort_output) Ditto. + + * vars-prs.c: (dict_class_to_name) Pass return value through + gettext. + + * vfm.c: (struct procedure_aux_data) Add `trns_case' member. + (procedure) Initialize trns_case. + (procedure) Pass trns_case to vfm_source->class->read(). + Free trns_case. + (process_active_file) Start using struct procedure_aux_data. + (process_active_file_write_case) Pass trns_case to + transformations, lag_case(), clear_case(). + (process_active_file_output_case) Add struct ccase * parameter. + (create_trns_case) New function. + (make_temp_case) Removed. + (vector_initialization) Removed. + (close_active_file) Only call make_source if non-null, otherwise + set vfm_source to null pointer. Don't free temp_case. + (disk_source_read) Add struct ccase * parameter, use instead of + temp_case. + (memory_source_read) Ditto. + (lag_case) Add const struct ccase * member. + (procedure_write_case) Use trns_case instead of temp_case. + (clear_case) Add struct ccase * member, use instead of temp_case. + (exclude_this_case) Ditto. + (create_case_source) Add struct dictionary * parameter, use to + initialize source->value_cnt. + + * vfm.h: (struct case_source) Add `value_cnt' member. + (struct case_source_class) Add struct ccase * parameter to `read' + member function pointer. + (struct case_sink_class) Make struct ccase * parameter const in + `write' member function pointer. + Wed Mar 3 20:44:37 2004 Ben Pfaff Fix a lot of "possibly uninitialized variable" warnings. Some of diff --git a/src/aggregate.c b/src/aggregate.c index 880a713a..4d00a34a 100644 --- a/src/aggregate.c +++ b/src/aggregate.c @@ -141,14 +141,16 @@ static void initialize_aggregate_info (void); /* Prototypes. */ static int parse_aggregate_functions (void); static void free_aggregate_functions (void); -static int aggregate_single_case (struct ccase *input, struct ccase *output); +static int aggregate_single_case (const struct ccase *input, + struct ccase *output); static int create_sysfile (void); 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); +static read_sort_output_func agr_11x_read; +static void agr_11x_finish (void); #if DEBUGGING static void debug_print (int flags); @@ -367,20 +369,14 @@ cmd_aggregate (void) } case 6: - case 7: + case 7: sort_cases (sort, 1); if (!create_sysfile ()) goto lossage; - read_sort_output (sort, agr_11x_func, NULL); - - { - struct ccase *save_temp_case = temp_case; - temp_case = NULL; - agr_11x_func (NULL); - temp_case = save_temp_case; - } - + read_sort_output (sort, agr_11x_read, NULL); + agr_11x_finish (); + break; default: @@ -762,7 +758,7 @@ free_aggregate_functions (void) /* Execution. */ -static void accumulate_aggregate_info (struct ccase *input); +static void accumulate_aggregate_info (const struct ccase *input); static void dump_aggregate_info (struct ccase *output); /* Processes a single case INPUT for aggregation. If output is @@ -772,7 +768,7 @@ static void dump_aggregate_info (struct ccase *output); /* The code in this function has an eerie similarity to vfm.c:SPLIT_FILE_procfunc()... */ static int -aggregate_single_case (struct ccase *input, struct ccase *output) +aggregate_single_case (const struct ccase *input, struct ccase *output) { /* The first case always begins a new break group. We also need to preserve the values of the case for later comparison. */ @@ -877,7 +873,7 @@ not_equal: /* Accumulates aggregation data from the case INPUT. */ static void -accumulate_aggregate_info (struct ccase *input) +accumulate_aggregate_info (const struct ccase *input) { struct agr_var *iter; double weight; @@ -887,7 +883,7 @@ accumulate_aggregate_info (struct ccase *input) for (iter = agr_first; iter; iter = iter->next) if (iter->src) { - union value *v = &input->data[iter->src->fv]; + const union value *v = &input->data[iter->src->fv]; if ((!iter->include_missing && is_missing (v, iter->src)) || (iter->include_missing && iter->src->type == NUMERIC @@ -1214,7 +1210,7 @@ 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->class->write (vfm_sink, temp_case); + vfm_sink->class->write (vfm_sink, compaction_case); } /* Transform the aggregate case buf_1xx, in internal format, to system @@ -1280,31 +1276,30 @@ agr_10x_end_func (void *aux UNUSED) write_case_to_sfm (); } -/* When called with temp_case non-NULL (the normal case), runs the - case through the aggregater and outputs it to the system file if - appropriate. If temp_case is NULL, finishes up writing the last - case if necessary. */ +/* Runs case C through the aggregater and outputs it to the + system file if appropriate. */ static int -agr_11x_func (write_case_data wc_data UNUSED) +agr_11x_read (const struct ccase *c, void *aux UNUSED) { - if (temp_case != NULL) - { - int code = aggregate_single_case (temp_case, buf_1xx); + int code = aggregate_single_case (c, buf_1xx); - assert (code == -2 || code == -1); - if (code == -1) - write_case_to_sfm (); - } - else + assert (code == -2 || code == -1); + if (code == -1) + write_case_to_sfm (); + + return 1; +} + +/* Finishes up writing the last case if necessary. */ +static void +agr_11x_finish (void) +{ + if (case_count) { - if (case_count) - { - dump_aggregate_info (buf_1xx); - write_case_to_sfm (); - } - fh_close_handle (outfile); + dump_aggregate_info (buf_1xx); + write_case_to_sfm (); } - return 1; + fh_close_handle (outfile); } /* Debugging. */ diff --git a/src/compute.c b/src/compute.c index 60c99ad8..9c20e0ee 100644 --- a/src/compute.c +++ b/src/compute.c @@ -104,6 +104,7 @@ cmd_compute (void) /* Transformation functions. */ +/* Handle COMPUTE or IF with numeric target variable. */ static int compute_num (struct trns_header *compute_, struct ccase *c, int case_num) @@ -119,6 +120,8 @@ compute_num (struct trns_header *compute_, struct ccase *c, return -1; } +/* Handle COMPUTE or IF with numeric vector element target + variable. */ static int compute_num_vec (struct trns_header *compute_, struct ccase *c, int case_num) @@ -154,6 +157,7 @@ compute_num_vec (struct trns_header *compute_, struct ccase *c, return -1; } +/* Handle COMPUTE or IF with string target variable. */ static int compute_str (struct trns_header *compute_, struct ccase *c, int case_num) @@ -174,6 +178,8 @@ compute_str (struct trns_header *compute_, struct ccase *c, return -1; } +/* Handle COMPUTE or IF with string vector element target + variable. */ static int compute_str_vec (struct trns_header *compute_, struct ccase *c, int case_num) @@ -317,6 +323,7 @@ compute_trns_free (struct trns_header *compute_) expr_free (compute->rvalue); } +/* COMPUTE or IF target variable or vector element. */ struct lvalue { char var_name[9]; /* Destination variable name, or "". */ @@ -324,6 +331,8 @@ struct lvalue struct expression *element; /* Destination vector element, or NULL. */ }; +/* Parses the target variable or vector elector into a new + `struct lvalue', which is returned. */ static struct lvalue * lvalue_parse (void) { @@ -371,6 +380,8 @@ lvalue_parse (void) return NULL; } +/* Returns the type (NUMERIC or ALPHA) of the target variable or + vector in LVALUE. */ static int lvalue_get_type (const struct lvalue *lvalue) { @@ -387,12 +398,15 @@ lvalue_get_type (const struct lvalue *lvalue) return lvalue->vector->var[0]->type; } +/* Returns nonzero if LVALUE has a vector as its target. */ static int lvalue_is_vector (const struct lvalue *lvalue) { return lvalue->vector != NULL; } +/* Finalizes making LVALUE the target of COMPUTE, by creating the + target variable if necessary and setting fields in COMPUTE. */ static void lvalue_finalize (struct lvalue *lvalue, struct compute_trns *compute) @@ -407,8 +421,6 @@ lvalue_finalize (struct lvalue *lvalue, compute->fv = compute->variable->fv; compute->width = compute->variable->width; - - /* Goofy behavior, but compatible: Turn off LEAVE. */ if (dict_class_from_id (compute->variable->name) != DC_SCRATCH) compute->variable->reinit = 1; @@ -423,6 +435,7 @@ lvalue_finalize (struct lvalue *lvalue, lvalue_destroy (lvalue); } +/* Destroys LVALUE. */ static void lvalue_destroy (struct lvalue *lvalue) { diff --git a/src/data-list.c b/src/data-list.c index 11b7f9c7..de50b437 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -79,14 +79,15 @@ enum struct data_list_pgm { struct trns_header h; + struct dls_var_spec *first, *last; /* Variable parsing specifications. */ struct file_handle *handle; /* Input file, never NULL. */ - /* Do not reorder preceding fields. */ int type; /* A DLS_* constant. */ struct variable *end; /* Variable specified on END subcommand. */ int eof; /* End of file encountered. */ int nrec; /* Number of records. */ + size_t case_size; /* Case size in bytes. */ }; static int parse_fixed (struct data_list_pgm *); @@ -95,8 +96,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 trns_free_func destroy_dls; -static trns_proc_func read_one_case; +static trns_free_func data_list_trns_free; +static trns_proc_func data_list_trns_proc; /* Message title for REPEATING DATA. */ #define RPD_ERR "REPEATING DATA: " @@ -207,6 +208,7 @@ cmd_data_list (void) } } + dls->case_size = dict_get_case_size (default_dict); default_handle = dls->handle; if (dls->type == -1) @@ -239,15 +241,16 @@ cmd_data_list (void) { struct data_list_pgm *new_pgm; - dls->h.proc = read_one_case; - dls->h.free = destroy_dls; + dls->h.proc = data_list_trns_proc; + dls->h.free = data_list_trns_free; new_pgm = xmalloc (sizeof *new_pgm); memcpy (new_pgm, &dls, sizeof *new_pgm); add_transformation (&new_pgm->h); } else - vfm_source = create_case_source (&data_list_source_class, dls); + vfm_source = create_case_source (&data_list_source_class, + default_dict, dls); return CMD_SUCCESS; @@ -257,6 +260,8 @@ cmd_data_list (void) return CMD_FAILURE; } +/* Adds SPEC to the linked list with head at FIRST and tail at + LAST. */ static void append_var_spec (struct dls_var_spec **first, struct dls_var_spec **last, struct dls_var_spec *spec) @@ -281,9 +286,7 @@ struct fmt_list struct fmt_list *down; }; -/* Used as "local" variables among the fixed-format parsing funcs. If - it were guaranteed that PSPP were going to be compiled by gcc, - I'd make all these functions a single set of nested functions. */ +/* State of parsing DATA LIST. */ struct fixed_parsing_state { char **name; /* Variable names. */ @@ -301,6 +304,8 @@ static int fixed_parse_fortran (struct fixed_parsing_state *, struct dls_var_spec **, struct dls_var_spec **); +/* Parses all the variable specifications for DATA LIST FIXED, + storing them into DLS. Returns nonzero if successful. */ static int parse_fixed (struct data_list_pgm *dls) { @@ -384,6 +389,9 @@ fail: return 0; } +/* Parses a variable specification in the form 1-10 (A) based on + FX and adds specifications to the linked list with head at + FIRST and tail at LAST. */ static int fixed_parse_compatible (struct fixed_parsing_state *fx, struct dls_var_spec **first, struct dls_var_spec **last) @@ -558,7 +566,8 @@ fixed_parse_compatible (struct fixed_parsing_state *fx, return 1; } -/* Destroy a format list and, optionally, all its sublists. */ +/* Destroy format list F and, if RECURSE is nonzero, all its + sublists. */ static void destroy_fmt_list (struct fmt_list *f, int recurse) { @@ -574,9 +583,10 @@ destroy_fmt_list (struct fmt_list *f, int recurse) } /* Takes a hierarchically structured fmt_list F as constructed by - fixed_parse_fortran(), and flattens it into a linear list of - dls_var_spec's. NAME_IDX is used to take values from the list - of names in FX; it should initially point to a value of 0. */ + fixed_parse_fortran(), and flattens it, adding the variable + specifications to the linked list with head FIRST and tail + LAST. NAME_IDX is used to take values from the list of names + in FX; it should initially point to a value of 0. */ static int dump_fmt_list (struct fixed_parsing_state *fx, struct fmt_list *f, struct dls_var_spec **first, struct dls_var_spec **last, @@ -646,10 +656,10 @@ dump_fmt_list (struct fixed_parsing_state *fx, struct fmt_list *f, return 1; } -/* Recursively parses a FORTRAN-like format specification. LEVEL - is the level of recursion, starting from 0. Returns the - parsed specification if successful, or a null pointer on - failure. */ +/* Recursively parses a FORTRAN-like format specification into + the linked list with head FIRST and tail TAIL. LEVEL is the + level of recursion, starting from 0. Returns the parsed + specification if successful, or a null pointer on failure. */ static struct fmt_list * fixed_parse_fortran_internal (struct fixed_parsing_state *fx, struct dls_var_spec **first, @@ -707,8 +717,9 @@ fail: return NULL; } -/* Parses a FORTRAN-like format specification. Returns nonzero - if successful. */ +/* Parses a FORTRAN-like format specification into the linked + list with head FIRST and tail LAST. Returns nonzero if + successful. */ static int fixed_parse_fortran (struct fixed_parsing_state *fx, struct dls_var_spec **first, struct dls_var_spec **last) @@ -792,6 +803,9 @@ dump_fixed_table (const struct dls_var_spec *specs, /* Free-format parsing. */ +/* Parses variable specifications for DATA LIST FREE and adds + them to the linked list with head FIRST and tail LAST. + Returns nonzero only if successful. */ static int parse_free (struct dls_var_spec **first, struct dls_var_spec **last) { @@ -976,7 +990,7 @@ cut_field (const struct data_list_pgm *dls, char **ret_cp, int *ret_len) } } -typedef int data_list_read_func (const struct data_list_pgm *); +typedef int data_list_read_func (const struct data_list_pgm *, struct ccase *); static data_list_read_func read_from_data_list_fixed; static data_list_read_func read_from_data_list_free; static data_list_read_func read_from_data_list_list; @@ -990,26 +1004,24 @@ get_data_list_read_func (const struct data_list_pgm *dls) { case DLS_FIXED: return read_from_data_list_fixed; - break; case DLS_FREE: return read_from_data_list_free; - break; case DLS_LIST: return read_from_data_list_list; - break; default: assert (0); } } -/* Reads a case from the data file and parses it according to - fixed-format syntax rules. Returns -1 on success, -2 at end - of file. */ +/* Reads a case from the data file into C, parsing it according + to fixed-format syntax rules in DLS. Returns -1 on success, + -2 at end of file. */ static int -read_from_data_list_fixed (const struct data_list_pgm *dls) +read_from_data_list_fixed (const struct data_list_pgm *dls, + struct ccase *c) { struct dls_var_spec *var_spec = dls->first; int i; @@ -1034,7 +1046,7 @@ read_from_data_list_fixed (const struct data_list_pgm *dls) struct data_in di; data_in_finite_line (&di, line, len, var_spec->fc, var_spec->lc); - di.v = &temp_case->data[var_spec->fv]; + di.v = &c->data[var_spec->fv]; di.flags = 0; di.f1 = var_spec->fc; di.format = var_spec->input; @@ -1048,11 +1060,12 @@ read_from_data_list_fixed (const struct data_list_pgm *dls) return -1; } -/* Reads a case from the data file and parses it according to - free-format syntax rules. Returns -1 on success, -2 at end of - file. */ +/* Reads a case from the data file into C, parsing it according + to free-format syntax rules in DLS. Returns -1 on success, + -2 at end of file. */ static int -read_from_data_list_free (const struct data_list_pgm *dls) +read_from_data_list_free (const struct data_list_pgm *dls, + struct ccase *c) { struct dls_var_spec *var_spec; char *field; @@ -1085,7 +1098,7 @@ read_from_data_list_free (const struct data_list_pgm *dls) di.s = field; di.e = field + len; - di.v = &temp_case->data[var_spec->fv]; + di.v = &c->data[var_spec->fv]; di.flags = 0; di.f1 = column; di.format = var_spec->input; @@ -1099,7 +1112,8 @@ read_from_data_list_free (const struct data_list_pgm *dls) list-format syntax rules. Returns -1 on success, -2 at end of file. */ static int -read_from_data_list_list (const struct data_list_pgm *dls) +read_from_data_list_list (const struct data_list_pgm *dls, + struct ccase *c) { struct dls_var_spec *var_spec; char *field; @@ -1124,9 +1138,9 @@ read_from_data_list_list (const struct data_list_pgm *dls) { int width = get_format_var_width (&var_spec->input); if (width == 0) - temp_case->data[var_spec->fv].f = SYSMIS; + c->data[var_spec->fv].f = SYSMIS; else - memset (temp_case->data[var_spec->fv].s, ' ', width); + memset (c->data[var_spec->fv].s, ' ', width); } break; } @@ -1136,7 +1150,7 @@ read_from_data_list_list (const struct data_list_pgm *dls) di.s = field; di.e = field + len; - di.v = &temp_case->data[var_spec->fv]; + di.v = &c->data[var_spec->fv]; di.flags = 0; di.f1 = column; di.format = var_spec->input; @@ -1164,7 +1178,7 @@ destroy_dls_var_spec (struct dls_var_spec *spec) /* Destroys DATA LIST transformation PGM. */ static void -destroy_dls (struct trns_header *pgm) +data_list_trns_free (struct trns_header *pgm) { struct data_list_pgm *dls = (struct data_list_pgm *) pgm; destroy_dls_var_spec (dls->first); @@ -1172,11 +1186,10 @@ destroy_dls (struct trns_header *pgm) free (pgm); } -/* Note that since this is exclusively an input program, C is - guaranteed to be temp_case. */ +/* Handle DATA LIST transformation T, parsing data into C. */ static int -read_one_case (struct trns_header *t, struct ccase *c UNUSED, - int case_num UNUSED) +data_list_trns_proc (struct trns_header *t, struct ccase *c, + int case_num UNUSED) { struct data_list_pgm *dls = (struct data_list_pgm *) t; data_list_read_func *read_func; @@ -1185,7 +1198,7 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED, dfm_push (dls->handle); read_func = get_data_list_read_func (dls); - retval = read_func (dls); + retval = read_func (dls, c); /* Handle end of file. */ if (retval == -2) @@ -1211,11 +1224,11 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED, { if (retval == -2) { - temp_case->data[dls->end->fv].f = 1.0; + c->data[dls->end->fv].f = 1.0; retval = -1; } else - temp_case->data[dls->end->fv].f = 0.0; + c->data[dls->end->fv].f = 0.0; } dfm_pop (dls->handle); @@ -1227,13 +1240,14 @@ read_one_case (struct trns_header *t, struct ccase *c UNUSED, write_case(). */ static void data_list_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { struct data_list_pgm *dls = source->aux; data_list_read_func *read_func = get_data_list_read_func (dls); dfm_push (dls->handle); - while (read_func (dls) != -2) + while (read_func (dls, c) != -2) if (!write_case (wc_data)) break; dfm_pop (dls->handle); @@ -1245,7 +1259,7 @@ data_list_source_read (struct case_source *source, static void data_list_source_destroy (struct case_source *source) { - destroy_dls (source->aux); + data_list_trns_free (source->aux); } const struct case_source_class data_list_source_class = @@ -1568,10 +1582,9 @@ cmd_repeating_data (void) return CMD_FAILURE; } -/* Because of the way that DATA LIST is structured, it's not trivial - to determine what input format is associated with a given variable. - This function finds the input format specification for variable V - and puts it in SPEC. */ +/* Finds the input format specification for variable V and puts + it in SPEC. Because of the way that DATA LIST is structured, + this is nontrivial. */ static void find_variable_input_spec (struct variable *v, struct fmt_spec *spec) { @@ -1581,7 +1594,7 @@ find_variable_input_spec (struct variable *v, struct fmt_spec *spec) { struct data_list_pgm *pgm = (struct data_list_pgm *) t_trns[i]; - if (pgm->h.proc == read_one_case) + if (pgm->h.proc == data_list_trns_proc) { struct dls_var_spec *iter; @@ -1634,8 +1647,9 @@ parse_num_or_var (struct rpd_num_or_var *value, const char *message) return 1; } -/* Parses data specifications for repeating data groups. Taken from - parse_fixed(). Returns nonzero only if successful. */ +/* Parses data specifications for repeating data groups, adding + them to the linked list with head FIRST and tail LAST. + Returns nonzero only if successful. */ static int parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last) { @@ -1827,9 +1841,9 @@ rpd_parse_record (const struct rpd_parse_info *info) return occurrences; } -/* Analogous to read_one_case; reads one set of repetitions of the - elements in the REPEATING DATA structure. Returns -1 on success, - -2 on end of file or on failure. */ +/* Reads one set of repetitions of the elements in the REPEATING + DATA structure. Returns -1 on success, -2 on end of file or + on failure. */ int repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, int case_num UNUSED) @@ -1983,6 +1997,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, return -3; } +/* Frees a REPEATING DATA transformation. */ void repeating_data_trns_free (struct trns_header *rpd_) { @@ -1993,10 +2008,8 @@ repeating_data_trns_free (struct trns_header *rpd_) free (rpd->id_value); } -/* This is a kluge. It is only here until I have more time - tocome up with something better. It lets - repeating_data_trns_proc() know how to write the cases that it - composes. */ +/* Lets repeating_data_trns_proc() know how to write the cases + that it composes. Not elegant. */ void repeating_data_set_write_case (struct trns_header *trns, write_case_func *write_case, diff --git a/src/expr-evl.c b/src/expr-evl.c index 34bbd6ac..62a9f6b2 100644 --- a/src/expr-evl.c +++ b/src/expr-evl.c @@ -51,7 +51,7 @@ #include "vfmP.h" double -expr_evaluate (struct expression *e, struct ccase *c, int case_num, +expr_evaluate (struct expression *e, const struct ccase *c, int case_num, union value *v) { unsigned char *op = e->op; diff --git a/src/expr.h b/src/expr.h index 909cf87f..5a1da2ae 100644 --- a/src/expr.h +++ b/src/expr.h @@ -38,7 +38,7 @@ struct ccase; union value; struct expression *expr_parse (int flags); -double expr_evaluate (struct expression *, struct ccase *, int case_num, +double expr_evaluate (struct expression *, const struct ccase *, int case_num, union value *); void expr_free (struct expression *); diff --git a/src/file-type.c b/src/file-type.c index ea0bb332..e5e3d81e 100644 --- a/src/file-type.c +++ b/src/file-type.c @@ -86,6 +86,7 @@ struct file_type_pgm DATA LIST. */ struct record_type *recs_head; /* List of record types. */ struct record_type *recs_tail; /* Last in list of record types. */ + size_t case_size; /* Case size in bytes. */ }; static int parse_col_spec (struct col_spec *, const char *); @@ -271,10 +272,10 @@ cmd_file_type (void) default_handle = fty->handle; - vfm_source = create_case_source (&file_type_source_class, fty); create_col_var (&fty->record); if (fty->case_sbc.name[0]) create_col_var (&fty->case_sbc); + vfm_source = create_case_source (&file_type_source_class, default_dict, fty); return CMD_SUCCESS; @@ -579,6 +580,7 @@ cmd_end_file_type (void) return CMD_FAILURE; } fty = vfm_source->aux; + fty->case_size = dict_get_case_size (default_dict); lex_match_id ("TYPE"); @@ -616,10 +618,11 @@ cmd_end_file_type (void) static void read_from_file_type_grouped(void); static void read_from_file_type_nested(void); */ -/* Reads any number of cases into temp_case and calls write_case() for - each one. Compare data-list.c:read_from_data_list. */ +/* Reads any number of cases into case C and calls write_case() + for each one. Compare data-list.c:read_from_data_list. */ static void file_type_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case UNUSED, write_case_data wc_data UNUSED) { @@ -644,7 +647,7 @@ file_type_source_read (struct case_source *source, { struct data_in di; - v.c = temp_case->data[fty->record.v->fv].s; + v.c = c->data[fty->record.v->fv].s; data_in_finite_line (&di, line, len, fty->record.fc, fty->record.fc + fty->record.nc); @@ -677,7 +680,7 @@ file_type_source_read (struct case_source *source, di.format = format; data_in (&di); - memcpy (&temp_case->data[fty->record.v->fv].f, &v.f, sizeof v.f); + memcpy (&c->data[fty->record.v->fv].f, &v.f, sizeof v.f); for (iter = fty->recs_head; iter; iter = iter->next) { if (iter->flags & RCT_OTHER) diff --git a/src/flip.c b/src/flip.c index 8ae4ac4e..7bf59104 100644 --- a/src/flip.c +++ b/src/flip.c @@ -17,8 +17,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* FIXME: does this work with long string variables? */ - #include #include #include @@ -47,18 +45,25 @@ struct varname struct flip_pgm { struct variable **var; /* Variables to transpose. */ - int var_cnt; /* Number of variables. */ - struct variable *newnames; /* Variable containing new variable names. */ - struct varname *new_names_head, *new_names_tail; - /* New variable names. */ - int case_count; /* Number of cases. */ + int var_cnt; /* Number of elements in `var'. */ + int case_cnt; /* Pre-flip case count. */ + size_t case_size; /* Post-flip bytes per case. */ + + struct variable *new_names; /* Variable containing new variable names. */ + struct varname *new_names_head; /* First new variable. */ + struct varname *new_names_tail; /* Last new variable. */ + FILE *file; /* Temporary file containing data. */ }; -static void destroy_flip_pgm (struct flip_pgm *flip); +static void destroy_flip_pgm (struct flip_pgm *); static struct case_sink *flip_sink_create (struct flip_pgm *); +static struct case_source *flip_source_create (struct flip_pgm *); +static void flip_file (struct flip_pgm *); +static int build_dictionary (struct flip_pgm *); + static const struct case_source_class flip_source_class; -static int build_dictionary (struct flip_pgm *flip); +static const struct case_sink_class flip_sink_class; /* Parses and executes FLIP. */ int @@ -69,9 +74,11 @@ cmd_flip (void) flip = xmalloc (sizeof *flip); flip->var = NULL; flip->var_cnt = 0; - flip->newnames = NULL; - flip->new_names_head = flip->new_names_tail = NULL; - flip->case_count = 0; + flip->case_cnt = 0; + flip->new_names = NULL; + flip->new_names_head = NULL; + flip->new_names_tail = NULL; + flip->file = NULL; lex_match_id ("FLIP"); lex_match ('/'); @@ -89,19 +96,19 @@ cmd_flip (void) if (lex_match_id ("NEWNAMES")) { lex_match ('='); - flip->newnames = parse_variable (); - if (!flip->newnames) + flip->new_names = parse_variable (); + if (!flip->new_names) goto error; } else - flip->newnames = dict_lookup_var (default_dict, "CASE_LBL"); + flip->new_names = dict_lookup_var (default_dict, "CASE_LBL"); - if (flip->newnames) + if (flip->new_names) { int i; for (i = 0; i < flip->var_cnt; i++) - if (flip->var[i] == flip->newnames) + if (flip->var[i] == flip->new_names) { memmove (&flip->var[i], &flip->var[i + 1], sizeof *flip->var * (flip->var_cnt - i - 1)); flip->var_cnt--; @@ -109,18 +116,27 @@ cmd_flip (void) } } - flip->case_count = 0; + /* Read the active file into a flip_sink. */ + flip->case_cnt = 0; temp_trns = temporary = 0; vfm_sink = flip_sink_create (flip); flip->new_names_tail = NULL; procedure (NULL, NULL, NULL, NULL); + /* Flip the data we read. */ + flip_file (flip); + + /* Flip the dictionary. */ dict_clear (default_dict); if (!build_dictionary (flip)) { discard_variables (); goto error; } + flip->case_size = dict_get_case_size (default_dict); + + /* Set up flipped data for reading. */ + vfm_source = flip_source_create (flip); return lex_end_of_command (); @@ -129,6 +145,7 @@ cmd_flip (void) return CMD_FAILURE; } +/* Destroys FLIP. */ static void destroy_flip_pgm (struct flip_pgm *flip) { @@ -140,6 +157,8 @@ destroy_flip_pgm (struct flip_pgm *flip) next = iter->next; free (iter); } + if (flip->file != NULL) + fclose (flip->file); free (flip); } @@ -202,13 +221,13 @@ build_dictionary (struct flip_pgm *flip) { int i; - if (flip->case_count > 99999) + if (flip->case_cnt > 99999) { msg (SE, _("Cannot create more than 99999 variable names.")); return 0; } - for (i = 0; i < flip->case_count; i++) + for (i = 0; i < flip->case_cnt; i++) { struct variable *v; char s[9]; @@ -233,77 +252,52 @@ build_dictionary (struct flip_pgm *flip) struct flip_sink_info { struct flip_pgm *flip; /* FLIP program. */ - int internal; /* Internal or external flip. */ - char *old_names; /* Old variable names. */ - unsigned long case_cnt; /* Number of cases. */ - FILE *file; /* Temporary file. */ - }; - -/* Source: Cases after transposition. */ -struct flip_source_info - { - struct flip_pgm *flip; /* FLIP program. */ - char *old_names; /* Old variable names. */ - unsigned long case_cnt; /* Number of cases. */ - FILE *file; /* Temporary file. */ + union value *output_buf; /* Case output buffer. */ }; -static const struct case_sink_class flip_sink_class; - -static FILE *flip_file (struct flip_sink_info *info); - -/* Creates a flip sink based on FLIP, of which it takes - ownership. */ +/* Creates a flip sink based on FLIP. */ static struct case_sink * flip_sink_create (struct flip_pgm *flip) { struct flip_sink_info *info = xmalloc (sizeof *info); + int i; info->flip = flip; - info->case_cnt = 0; - - { - size_t n = flip->var_cnt; - char *p; - int i; - - for (i = 0; i < flip->var_cnt; i++) - n += strlen (flip->var[i]->name); - p = info->old_names = xmalloc (n); - for (i = 0; i < flip->var_cnt; i++) - p = stpcpy (p, flip->var[i]->name) + 1; - } + info->output_buf = xmalloc (sizeof *info->output_buf * flip->var_cnt); - return create_case_sink (&flip_sink_class, info); -} + flip->file = tmpfile (); + if (!flip->file) + msg (FE, _("Could not create temporary file for FLIP.")); -/* Open the FLIP sink. */ -static void -flip_sink_open (struct case_sink *sink) -{ - struct flip_sink_info *info = sink->aux; + /* Write variable names as first case. */ + for (i = 0; i < flip->var_cnt; i++) + st_bare_pad_copy (info->output_buf[i].s, flip->var[i]->name, 8); + if (fwrite (info->output_buf, sizeof *info->output_buf, + flip->var_cnt, flip->file) != (size_t) flip->var_cnt) + msg (FE, _("Error writing FLIP file: %s."), strerror (errno)); - info->file = tmpfile (); - if (!info->file) - msg (FE, _("Could not create temporary file for FLIP.")); + flip->case_cnt = 1; + + return create_case_sink (&flip_sink_class, info); } /* Writes case C to the FLIP sink. */ static void -flip_sink_write (struct case_sink *sink, struct ccase *c) +flip_sink_write (struct case_sink *sink, const struct ccase *c) { struct flip_sink_info *info = sink->aux; struct flip_pgm *flip = info->flip; + int i; - info->case_cnt++; + flip->case_cnt++; - if (flip->newnames) + if (flip->new_names != NULL) { struct varname *v = xmalloc (sizeof (struct varname)); v->next = NULL; - if (flip->newnames->type == NUMERIC) + if (flip->new_names->type == NUMERIC) { - double f = c->data[flip->newnames->fv].f; + double f = c->data[flip->new_names->fv].f; if (f == SYSMIS) strcpy (v->name, "VSYSMIS"); @@ -321,8 +315,8 @@ flip_sink_write (struct case_sink *sink, struct ccase *c) } else { - int width = min (flip->newnames->width, 8); - memcpy (v->name, c->data[flip->newnames->fv].s, width); + int width = min (flip->new_names->width, 8); + memcpy (v->name, c->data[flip->new_names->fv].s, width); v->name[width] = 0; } @@ -332,65 +326,23 @@ flip_sink_write (struct case_sink *sink, struct ccase *c) flip->new_names_tail->next = v; flip->new_names_tail = v; } - else - flip->case_count++; - /* Write to external file. */ - { - double *d = local_alloc (sizeof *d * flip->var_cnt); - int i; - - for (i = 0; i < flip->var_cnt; i++) - if (flip->var[i]->type == NUMERIC) - d[i] = c->data[flip->var[i]->fv].f; - else - d[i] = SYSMIS; + for (i = 0; i < flip->var_cnt; i++) + if (flip->var[i]->type == NUMERIC) + info->output_buf[i].f = c->data[flip->var[i]->fv].f; + else + info->output_buf[i].f = SYSMIS; - if (fwrite (d, sizeof *d, flip->var_cnt, info->file) != (size_t) flip->var_cnt) - msg (FE, _("Error writing FLIP file: %s."), - strerror (errno)); - - local_free (d); - } + if (fwrite (info->output_buf, sizeof *info->output_buf, + flip->var_cnt, flip->file) != (size_t) flip->var_cnt) + msg (FE, _("Error writing FLIP file: %s."), strerror (errno)); } -/* Destroy sink's internal data. */ +/* Transposes the external file into a new file. */ static void -flip_sink_destroy (struct case_sink *sink) +flip_file (struct flip_pgm *flip) { - struct flip_sink_info *info = sink->aux; - - free (info->old_names); - destroy_flip_pgm (info->flip); - free (info); -} - -/* Convert the FLIP sink into a source. */ -static struct case_source * -flip_sink_make_source (struct case_sink *sink) -{ - struct flip_sink_info *sink_info = sink->aux; - struct flip_source_info *source_info; - - source_info = xmalloc (sizeof *source_info); - source_info->flip = sink_info->flip; - source_info->old_names = sink_info->old_names; - source_info->case_cnt = sink_info->case_cnt; - source_info->file = flip_file (sink_info); - fclose (sink_info->file); - - free (sink_info); - - return create_case_source (&flip_source_class, source_info); -} - -/* Transposes the external file into a new file and returns a - pointer to the transposed file. */ -static FILE * -flip_file (struct flip_sink_info *info) -{ - struct flip_pgm *flip = info->flip; size_t case_bytes; size_t case_capacity; size_t case_idx; @@ -400,8 +352,8 @@ flip_file (struct flip_sink_info *info) /* Allocate memory for many cases. */ case_bytes = flip->var_cnt * sizeof *input_buf; case_capacity = set_max_workspace / case_bytes; - if (case_capacity > info->case_cnt) - case_capacity = info->case_cnt; + if (case_capacity > flip->case_cnt * 2) + case_capacity = flip->case_cnt * 2; if (case_capacity < 2) case_capacity = 2; for (;;) @@ -424,7 +376,7 @@ flip_file (struct flip_sink_info *info) case_capacity /= 2; output_buf = input_buf + flip->var_cnt * case_capacity; - input_file = info->file; + input_file = flip->file; if (fseek (input_file, 0, SEEK_SET) != 0) msg (FE, _("Error rewinding FLIP file: %s."), strerror (errno)); @@ -432,9 +384,9 @@ flip_file (struct flip_sink_info *info) if (output_file == NULL) msg (FE, _("Error creating FLIP source file.")); - for (case_idx = 0; case_idx < info->case_cnt; ) + for (case_idx = 0; case_idx < flip->case_cnt; ) { - unsigned long read_cases = min (info->case_cnt - case_idx, + unsigned long read_cases = min (flip->case_cnt - case_idx, case_capacity); int i; @@ -449,7 +401,7 @@ flip_file (struct flip_sink_info *info) output_buf[j] = input_buf[i + j * flip->var_cnt]; if (fseek (output_file, - sizeof *input_buf * (case_idx + i * info->case_cnt), + sizeof *input_buf * (case_idx + i * flip->case_cnt), SEEK_SET) != 0) msg (FE, _("Error seeking FLIP source file: %s."), strerror (errno)); @@ -463,58 +415,79 @@ flip_file (struct flip_sink_info *info) case_idx += read_cases; } + fclose (input_file); + free (input_buf); + if (fseek (output_file, 0, SEEK_SET) != 0) msg (FE, _("Error rewind FLIP source file: %s."), strerror (errno)); + flip->file = output_file; +} - free (input_buf); - return output_file; +/* Destroy sink's internal data. */ +static void +flip_sink_destroy (struct case_sink *sink) +{ + struct flip_sink_info *info = sink->aux; + + free (info->output_buf); + free (info); } /* FLIP sink class. */ static const struct case_sink_class flip_sink_class = { "FLIP", - flip_sink_open, + NULL, flip_sink_write, flip_sink_destroy, - flip_sink_make_source, + NULL, }; -/* Reads the FLIP stream and passes it to WRITE_CASE(). */ +/* Creates and returns a FLIP source based on PGM, + which should have already been used as a sink. */ +static struct case_source * +flip_source_create (struct flip_pgm *pgm) +{ + return create_case_source (&flip_source_class, default_dict, pgm); +} + +/* Reads the FLIP stream. Copies each case into C and calls + WRITE_CASE passing WC_DATA. */ static void flip_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { - struct flip_source_info *info = source->aux; - struct flip_pgm *flip = info->flip; + struct flip_pgm *flip = source->aux; int i; - char *p = info->old_names; - + for (i = 0; i < flip->var_cnt; i++) { - st_bare_pad_copy (temp_case->data[0].s, p, 8); - p = strchr (p, 0) + 1; - - if (fread (&temp_case->data[1], sizeof (double), info->case_cnt, - info->file) != info->case_cnt) - msg (FE, _("Error reading FLIP source file: %s."), - strerror (errno)); + if (fread (c->data, sizeof *c->data, flip->case_cnt, + flip->file) != flip->case_cnt) + { + if (ferror (flip->file)) + msg (SE, _("Error reading FLIP temporary file: %s."), + strerror (errno)); + else if (feof (flip->file)) + msg (SE, _("Unexpected end of file reading FLIP temporary file.")); + else + assert (0); + break; + } if (!write_case (wc_data)) - return; + break; } } -/* Destroy source's internal data. */ +/* Destroy internal data in SOURCE. */ static void flip_source_destroy (struct case_source *source) { - struct flip_source_info *info = source->aux; + struct flip_pgm *flip = source->aux; - destroy_flip_pgm (info->flip); - free (info->old_names); - fclose (info->file); - free (info); + destroy_flip_pgm (flip); } static const struct case_source_class flip_source_class = diff --git a/src/format.c b/src/format.c index 33a81ff3..37e691a4 100644 --- a/src/format.c +++ b/src/format.c @@ -36,50 +36,58 @@ struct fmt_desc formats[FMT_NUMBER_OF_FORMATS + 1] = {"", -1, -1, -1, -1, -1, 0000, -1, -1}, }; -const int translate_fmt[40] = - { - -1, FMT_A, FMT_AHEX, FMT_COMMA, FMT_DOLLAR, FMT_F, FMT_IB, - FMT_PIBHEX, FMT_P, FMT_PIB, FMT_PK, FMT_RB, FMT_RBHEX, -1, - -1, FMT_Z, FMT_N, FMT_E, -1, -1, FMT_DATE, FMT_TIME, - FMT_DATETIME, FMT_ADATE, FMT_JDATE, FMT_DTIME, FMT_WKDAY, - FMT_MONTH, FMT_MOYR, FMT_QYR, FMT_WKYR, FMT_PCT, FMT_DOT, - FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE, FMT_EDATE, - FMT_SDATE, - }; - +/* Parses the alphabetic prefix of the current token as a format + specifier name. Returns the corresponding format specifier + type if successful, or -1 on failure. If ALLOW_XT is zero, + then X and T format specifiers are not allowed. If CP is + nonzero, then *CP is set to the first non-alphabetic character + in the current token on success or to a null pointer on + failure. */ int parse_format_specifier_name (const char **cp, int allow_xt) { - struct fmt_desc *f; - char *ep; - int x; + char *sp, *ep; + int idx; - ep = ds_value (&tokstr); + sp = ep = ds_value (&tokstr); while (isalpha ((unsigned char) *ep)) ep++; - x = *ep; - *ep = 0; - - for (f = formats; f->name[0]; f++) - if (!strcmp (f->name, ds_value (&tokstr))) - { - int indx = f - formats; - *ep = x; - if (cp) - *cp = ep; + if (sp != ep) + { + /* Find format. */ + for (idx = 0; idx < FMT_NUMBER_OF_FORMATS; idx++) + if (strlen (formats[idx].name) == ep - sp + && memcmp (formats[idx].name, sp, ep - sp)) + break; - if (!allow_xt && (indx == FMT_T || indx == FMT_X)) - { - msg (SE, _("X and T format specifiers not allowed here.")); - return -1; - } - return indx; - } + /* Check format. */ + if (idx < FMT_NUMBER_OF_FORMATS) + { + if (!allow_xt && (idx == FMT_T || idx == FMT_X)) + { + msg (SE, _("X and T format specifiers not allowed here.")); + idx = -1; + } + } + else + { + /* No match. */ + msg (SE, _("%.*s is not a valid data format."), + (int) (ep - sp), ds_value (&tokstr)); + idx = -1; + } + } + else + { + lex_error ("expecting data format"); + idx = -1; + } + + if (cp != NULL) + *cp = ep; - msg (SE, _("%s is not a valid data format."), ds_value (&tokstr)); - *ep = x; - return -1; + return idx; } /* Converts F to its string representation (for instance, "F8.2") and @@ -96,6 +104,9 @@ fmt_to_string (const struct fmt_spec *f) return buf; } +/* Checks whether SPEC is valid as an input format and returns + nonzero if so. Otherwise, emits an error message and returns + zero. */ int check_input_specifier (const struct fmt_spec *spec) { @@ -135,6 +146,9 @@ check_input_specifier (const struct fmt_spec *spec) return 1; } +/* Checks whether SPEC is valid as an output format and returns + nonzero if so. Otherwise, emits an error message and returns + zero. */ int check_output_specifier (const struct fmt_spec *spec) { @@ -196,6 +210,8 @@ check_string_specifier (const struct fmt_spec *f, int min_len) return 1; } +/* Converts input format specifier INPUT into output format + specifier OUTPUT. */ void convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output) { @@ -288,6 +304,12 @@ convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output) } } +/* Parses a format specifier from the token stream and returns + nonzero only if successful. Emits an error message on + failure. Allows X and T format specifiers only if ALLOW_XT is + nonzero. The caller should call check_input_specifier() or + check_output_specifier() on the parsed format as + necessary. */ int parse_format_specifier (struct fmt_spec *input, int allow_xt) { @@ -340,6 +362,9 @@ parse_format_specifier (struct fmt_spec *input, int allow_xt) return 1; } +/* Returns the width corresponding to the format specifier. The + return value is the value of the `width' member of a `struct + variable' for such an input format. */ int get_format_var_width (const struct fmt_spec *spec) { @@ -350,3 +375,16 @@ get_format_var_width (const struct fmt_spec *spec) else return 0; } + +/* Returns the PSPP format corresponding to the given SPSS + format. */ +int +translate_fmt (int spss) +{ + int type; + + for (type = 0; type < FMT_NUMBER_OF_FORMATS; type++) + if (formats[type].spss == spss) + return type; + return -1; +} diff --git a/src/format.h b/src/format.h index 7f4b5442..375b639f 100644 --- a/src/format.h +++ b/src/format.h @@ -71,9 +71,6 @@ struct fmt_spec /* Descriptions of all the display formats above. */ extern struct fmt_desc formats[]; -/* Translates SPSS formats to PSPP formats. */ -extern const int translate_fmt[40]; - union value; /* Maximum length of formatted value, in character. */ @@ -88,6 +85,7 @@ void convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output); int get_format_var_width (const struct fmt_spec *); int parse_string_as_format (const char *s, int len, const struct fmt_spec *fp, int fc, union value *v); +int translate_fmt (int spss); void data_out (char *s, const struct fmt_spec *fp, const union value *v); char *fmt_to_string (const struct fmt_spec *); void num_to_string (double v, char *s, int w, int d); diff --git a/src/frequencies.q b/src/frequencies.q index d9f8660f..66faf5ef 100644 --- a/src/frequencies.q +++ b/src/frequencies.q @@ -518,6 +518,8 @@ get_freq_comparator (int frq_sort, int var_type) return 0; } +/* Returns nonzero iff the value in struct freq F is non-missing + for variable V. */ static int not_missing (const void *f_, void *v_) { @@ -527,8 +529,9 @@ not_missing (const void *f_, void *v_) return !is_missing (&f->v, v); } +/* Summarizes the frequency table data for variable V. */ static void -postprocess_freq_tab (struct variable * v) +postprocess_freq_tab (struct variable *v) { hsh_compare_func *compare; struct freq_tab *ft; @@ -575,6 +578,7 @@ postprocess_freq_tab (struct variable * v) } } +/* Frees the frequency table for variable V. */ static void cleanup_freq_tab (struct variable *v) { diff --git a/src/get.c b/src/get.c index be1c09a2..e0ecc55d 100644 --- a/src/get.c +++ b/src/get.c @@ -38,6 +38,13 @@ #include "debug-print.h" +/* GET or IMPORT input program. */ +struct get_pgm + { + struct file_handle *handle; /* File to GET or IMPORT from. */ + size_t case_size; /* Case size in bytes. */ + }; + /* XSAVE transformation (and related SAVE, EXPORT procedures). */ struct save_trns { @@ -69,6 +76,7 @@ cmd_get (void) { struct file_handle *handle; struct dictionary *dict; + struct get_pgm *pgm; int options = GTSV_OPT_NONE; lex_match_id ("GET"); @@ -114,7 +122,10 @@ cmd_get (void) dict_destroy (default_dict); default_dict = dict; - vfm_source = create_case_source (&get_source_class, handle); + pgm = xmalloc (sizeof *pgm); + pgm->handle = handle; + pgm->case_size = dict_get_case_size (default_dict); + vfm_source = create_case_source (&get_source_class, default_dict, pgm); return CMD_SUCCESS; } @@ -246,21 +257,24 @@ do_write_case (struct save_trns *t, struct ccase *c) sfm_write_case (t->f, t->case_buf, p - t->case_buf); } +/* Writes case C to the system file specified on SAVE. */ static int -save_write_case_func (struct ccase * c, void *aux UNUSED) +save_write_case_func (struct ccase *c, void *aux UNUSED) { do_write_case (aux, c); return 1; } +/* Writes case C to the system file specified on XSAVE. */ static int -save_trns_proc (struct trns_header *h, struct ccase * c, int case_num UNUSED) +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); return -1; } +/* Frees a SAVE transformation. */ static void save_trns_free (struct trns_header *pt) { @@ -477,22 +491,24 @@ dump_dict_variables (struct dictionary * dict) static void get_source_destroy (struct case_source *source) { - struct file_handle *handle = source->aux; + struct get_pgm *pgm = source->aux; /* It is not necessary to destroy the dictionary because if we get to this point then the dictionary is default_dict. */ - fh_close_handle (handle); + fh_close_handle (pgm->handle); + free (pgm); } -/* Reads all the cases from the data file and passes them to - write_case(). */ +/* Reads all the cases from the data file into C and passes them + to WRITE_CASE one by one, passing WC_DATA. */ static void get_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { - struct file_handle *handle = source->aux; + struct get_pgm *pgm = source->aux; - while (sfm_read_case (handle, temp_case->data, default_dict) + while (sfm_read_case (pgm->handle, c->data, default_dict) && write_case (wc_data)) ; } @@ -848,10 +864,7 @@ cmd_match_files (void) FIXME: For merging large numbers of files (more than 10?) a better algorithm would use a heap for finding minimum - values, or replacement selection, as described by Knuth in - _Art of Computer Programming, Vol. 3_. The SORT CASES - procedure does this, and perhaps some of its code could be - adapted. */ + values. */ if (!(seen & 2)) discard_variables (); @@ -894,7 +907,7 @@ mtf_processing_finish (void *aux UNUSED) } while (mtf_head && mtf_head->type == MTF_FILE) - if (!mtf_processing (temp_case, NULL)) + if (!mtf_processing (NULL, NULL)) break; } @@ -1006,20 +1019,22 @@ mtf_read_nonactive_records (void *aux UNUSED) iter = iter->next; } else - { - iter->input = temp_case->data; - iter = iter->next; - } + iter = iter->next; } } /* Compare the BY variables for files A and B; return -1 if A < B, 0 if A == B, 1 if A > B. */ static inline int -mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b) +mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b, + struct ccase *c) { + union value *a_input, *b_input; int i; - + + assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1); + a_input = a->input != NULL ? a->input : c->data; + b_input = b->input != NULL ? b->input : c->data; for (i = 0; i < mtf_n_by; i++) { assert (a->by[i]->type == b->by[i]->type); @@ -1027,8 +1042,8 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b) if (a->by[i]->type == NUMERIC) { - double af = a->input[a->by[i]->fv].f; - double bf = b->input[b->by[i]->fv].f; + double af = a_input[a->by[i]->fv].f; + double bf = b_input[b->by[i]->fv].f; if (af < bf) return -1; @@ -1040,8 +1055,8 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b) int result; assert (a->by[i]->type == ALPHA); - result = memcmp (a->input[a->by[i]->fv].s, - b->input[b->by[i]->fv].s, + result = memcmp (a_input[a->by[i]->fv].s, + b_input[b->by[i]->fv].s, a->by[i]->width); if (result < 0) return -1; @@ -1054,7 +1069,7 @@ mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b) /* Perform one iteration of steps 3...7 above. */ static int -mtf_processing (struct ccase *c UNUSED, void *aux UNUSED) +mtf_processing (struct ccase *c, void *aux UNUSED) { /* List of files with minimum BY values. */ struct mtf_file *min_head, *min_tail; @@ -1084,7 +1099,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED) max_head = max_tail = NULL; for (iter = mtf_head->next; iter && iter->type == MTF_FILE; iter = iter->next) - switch (mtf_compare_BY_values (min_head, iter)) + switch (mtf_compare_BY_values (min_head, iter, c)) { case -1: if (max_head) @@ -1129,7 +1144,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED) advance = 0; again: - switch (mtf_compare_BY_values (min_head, iter)) + switch (mtf_compare_BY_values (min_head, iter, c)) { case -1: if (max_head) @@ -1170,26 +1185,20 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED) for (i = 0; i < dict_get_var_cnt (iter->dict); i++) { struct variable *v = dict_get_var (iter->dict, i); + union value *record; if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num) continue; mtf_seq_nums[v->p.mtf.master->index] = mtf_seq_num; -#if 0 - printf ("%s/%s: dest-fv=%d, src-fv=%d\n", - fh_handle_name (iter->handle), - v->name, - v->p.mtf.master->fv, v->fv); -#endif + record = iter->input != NULL ? iter->input : c->data; + + assert (v->type == NUMERIC || v->type == ALPHA); if (v->type == NUMERIC) - compaction_case->data[v->p.mtf.master->fv].f - = iter->input[v->fv].f; + compaction_case->data[v->p.mtf.master->fv].f = record[v->fv].f; else - { - assert (v->type == ALPHA); - memcpy (compaction_case->data[v->p.mtf.master->fv].s, - iter->input[v->fv].s, v->width); - } + memcpy (compaction_case->data[v->p.mtf.master->fv].s, + record[v->fv].s, v->width); } } @@ -1226,7 +1235,7 @@ mtf_processing (struct ccase *c UNUSED, void *aux UNUSED) } /* 6. Write the output record. */ - process_active_file_output_case (); + process_active_file_output_case (compaction_case); /* 7. Read another record from each input file FILE and TABLE that we stored values from above. If we come to the end of @@ -1338,6 +1347,7 @@ cmd_import (void) { struct file_handle *handle = NULL; struct dictionary *dict; + struct get_pgm *pgm; int options = GTSV_OPT_NONE; int type; @@ -1411,7 +1421,10 @@ cmd_import (void) dict_destroy (default_dict); default_dict = dict; - vfm_source = create_case_source (&import_source_class, handle); + pgm = xmalloc (sizeof *pgm); + pgm->handle = handle; + pgm->case_size = dict_get_case_size (default_dict); + vfm_source = create_case_source (&import_source_class, default_dict, pgm); return CMD_SUCCESS; } @@ -1420,10 +1433,12 @@ cmd_import (void) write_case(). */ static void import_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { - struct file_handle *handle = source->aux; - while (pfm_read_case (handle, temp_case->data, default_dict)) + struct get_pgm *pgm = source->aux; + + while (pfm_read_case (pgm->handle, c->data, default_dict)) if (!write_case (wc_data)) break; } @@ -1503,6 +1518,7 @@ cmd_export (void) return CMD_SUCCESS; } +/* Writes case C to the EXPORT file. */ static int export_write_case_func (struct ccase *c, void *aux) { diff --git a/src/glob.c b/src/glob.c index 5bf5600f..60da1fff 100644 --- a/src/glob.c +++ b/src/glob.c @@ -100,8 +100,6 @@ extern void stifle_history (); struct dictionary *default_dict; struct expression *process_if_expr; -struct ccase *temp_case; - struct trns_header **t_trns; int n_trns; int m_trns; diff --git a/src/inpt-pgm.c b/src/inpt-pgm.c index 697d7f5b..dc08f346 100644 --- a/src/inpt-pgm.c +++ b/src/inpt-pgm.c @@ -50,6 +50,7 @@ struct input_program_pgm { enum value_init_type *init; /* How to initialize each `union value'. */ size_t init_cnt; /* Number of elements in inp_init. */ + size_t case_size; /* Size of case in bytes. */ }; static trns_proc_func end_case_trns_proc, reread_trns_proc, end_file_trns_proc; @@ -62,7 +63,10 @@ cmd_input_program (void) lex_match_id ("PROGRAM"); discard_variables (); - vfm_source = create_case_source (&input_program_source_class, NULL); + /* FIXME: we shouldn't do this here, but I'm afraid that other + code will check the class of vfm_source. */ + vfm_source = create_case_source (&input_program_source_class, + default_dict, NULL); return lex_end_of_command (); } @@ -91,7 +95,7 @@ cmd_end_input_program (void) ordinary transformations. */ f_trns = n_trns; - /* Figure out how to initialize temp_case. */ + /* Figure out how to initialize each input case. */ inp = xmalloc (sizeof *inp); inp->init_cnt = dict_get_next_value_idx (default_dict); inp->init = xmalloc (inp->init_cnt * sizeof *inp->init); @@ -111,16 +115,20 @@ cmd_end_input_program (void) } for (i = 0; i < inp->init_cnt; i++) assert (inp->init[i] != -1); + inp->case_size = dict_get_case_size (default_dict); /* Put inp into vfm_source for later use. */ vfm_source->aux = inp; + /* FIXME: we should use create_case_source() here. */ + vfm_source->value_cnt = dict_get_next_value_idx (default_dict); + return lex_end_of_command (); } -/* Initializes temp_case. Called before the first case is read. */ +/* Initializes case C. Called before the first case is read. */ static void -init_case (struct input_program_pgm *inp) +init_case (const struct input_program_pgm *inp, struct ccase *c) { size_t i; @@ -128,23 +136,23 @@ init_case (struct input_program_pgm *inp) switch (inp->init[i]) { case INP_NUMERIC | INP_INIT_ONCE: - temp_case->data[i].f = 0.0; + c->data[i].f = 0.0; break; case INP_NUMERIC | INP_REINIT: - temp_case->data[i].f = SYSMIS; + c->data[i].f = SYSMIS; break; case INP_STRING | INP_INIT_ONCE: case INP_STRING | INP_REINIT: - memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s); + memset (c->data[i].s, ' ', sizeof c->data[i].s); break; default: assert (0); } } -/* Clears temp_case. Called between reading successive records. */ +/* Clears case C. Called between reading successive records. */ static void -clear_case (struct input_program_pgm *inp) +clear_case (const struct input_program_pgm *inp, struct ccase *c) { size_t i; @@ -154,12 +162,12 @@ clear_case (struct input_program_pgm *inp) case INP_NUMERIC | INP_INIT_ONCE: break; case INP_NUMERIC | INP_REINIT: - temp_case->data[i].f = SYSMIS; + c->data[i].f = SYSMIS; break; case INP_STRING | INP_INIT_ONCE: break; case INP_STRING | INP_REINIT: - memset (temp_case->data[i].s, ' ', sizeof temp_case->data[i].s); + memset (c->data[i].s, ' ', sizeof c->data[i].s); break; default: assert (0); @@ -172,6 +180,7 @@ clear_case (struct input_program_pgm *inp) return value is the index of the transformation to go to next. */ static void input_program_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { @@ -190,56 +199,43 @@ input_program_source_read (struct case_source *source, int cases_written = 0; assert (inp != NULL); - + /* Figure end_case. */ for (i = 0; i < f_trns; i++) if (t_trns[i]->proc == end_case_trns_proc) end_case = 1; - /* FIXME: This code should not be necessary. It is an ugly - kluge. */ + /* FIXME: This is an ugly kluge. */ for (i = 0; i < f_trns; i++) if (t_trns[i]->proc == repeating_data_trns_proc) repeating_data_set_write_case (t_trns[i], write_case, wc_data); - init_case (inp); + init_case (inp, c); for (;;) { - /* Index of current transformation. */ - int i; - - /* Return value of last-called transformation. */ - int code; - - debug_printf (("input-program: ")); - /* Perform transformations on `blank' case. */ - for (i = 0; i < f_trns;) + for (i = 0; i < f_trns; ) { -#if DEBUGGING - printf ("/%d", i); - if (t_trns[i]->proc == end_case_trns_proc) - printf ("\n"); -#endif + int code; /* Return value of last-called transformation. */ if (t_trns[i]->proc == end_case_trns_proc) { cases_written++; if (!write_case (wc_data)) - return; - clear_case (inp); + goto done; + clear_case (inp, c); i++; continue; } - code = t_trns[i]->proc (t_trns[i], temp_case, cases_written + 1); + code = t_trns[i]->proc (t_trns[i], c, cases_written + 1); switch (code) { case -1: i++; break; case -2: - return; + goto done; case -3: goto next_case; default: @@ -248,22 +244,22 @@ input_program_source_read (struct case_source *source, } } -#if DEBUGGING - if (!end_case) - printf ("\n"); -#endif - /* Write the case if appropriate. */ - if (!end_case) - if (!write_case (wc_data)) - return; + if (!end_case) + { + cases_written++; + if (!write_case (wc_data)) + break; + } /* Blank out the case for the next iteration. */ next_case: - clear_case (inp); + clear_case (inp, c); } + done: ; } +/* Destroys an INPUT PROGRAM source. */ static void input_program_source_destroy (struct case_source *source) { @@ -309,6 +305,8 @@ cmd_end_case (void) return lex_end_of_command (); } +/* Should never be called, because this is handled in + input_program_source_read(). */ int end_case_trns_proc (struct trns_header *t UNUSED, struct ccase * c UNUSED, int case_num UNUSED) @@ -393,6 +391,7 @@ cmd_reread (void) return CMD_SUCCESS; } +/* Executes a REREAD transformation. */ static int reread_trns_proc (struct trns_header * pt, struct ccase * c, int case_num) @@ -418,6 +417,7 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c, return -1; } +/* Frees a REREAD transformation. */ static void reread_trns_free (struct trns_header * t) { @@ -448,12 +448,10 @@ cmd_end_file (void) return lex_end_of_command (); } +/* Executes an END FILE transformation. */ static int end_file_trns_proc (struct trns_header * t UNUSED, struct ccase * c UNUSED, int case_num UNUSED) { -#if DEBUGGING - printf ("END FILE\n"); -#endif return -2; } diff --git a/src/loop.c b/src/loop.c index 1989a074..b0c836bc 100644 --- a/src/loop.c +++ b/src/loop.c @@ -32,7 +32,6 @@ #include "debug-print.h" -/* *INDENT-OFF* */ /* LOOP strategy: Each loop causes 3 different transformations to be output. The @@ -43,42 +42,40 @@ transformation to -1. This ensures that the pass number is set to -1 every time the loop is encountered, before the first iteration. - The second transformation increments the pass number. If there is - no indexing or test clause on either LOOP or END LOOP, then the - pass number is checked against MXLOOPS and control may pass out of - the loop; otherwise the indexing or test clause(s) on LOOP are - checked, and again control may pass out of the loop. + The second transformation increments the pass number. If + there is no indexing or test clause on either LOOP or END + LOOP, then the pass number is checked against MXLOOPS and + control may pass out of the loop. Otherwise the indexing or + test clause(s) on LOOP are checked, and again control may pass + out of the loop. - After the second transformation the body of the loop is executed. + After the second transformation the body of the loop is + executed. The last transformation checks the test clause if present and - either jumps back up to the second transformation or terminates the - loop. - - Flow of control: (The characters ^V<> represents arrows.) - - 1. LOOP (sets pass # to -1) - V - V - >>2. LOOP (increment pass number) - ^ (test optional indexing clause) - ^ (test optional IF clause) - ^ if we need another trip if we're done with the loop>>V - ^ V V - ^ V V - ^ *. execute loop body V - ^ . V - ^ . (any number of transformations) V - ^ . V - ^ V - ^ 3. END LOOP (test optional IF clause) V - ^<<<>V - V - V - *. transformations after loop body<<<<<<<<<<<<<<<<<<<<<<<<<<< + either jumps back up to the second transformation or + terminates the loop. + Flow of control: + + 1. LOOP. Sets pass number to -1 and continues to next + transformation. + + 2. LOOP. Increments pass number. Tests optional indexing + clause and optional IF clause. If we're done with the + loop, we jump to the transformation just after LOOP + transformation 3. + + Otherwise, we continue through the transformations in the + loop body. + + 3. END LOOP. We test the optional IF clause. If we need to + make another pass through the loop, we jump to LOOP + transformation 2. + + Otherwise, we continue with the transformation jump after + the loop. */ -/* *INDENT-ON* */ /* Types of limits on loop execution. */ enum diff --git a/src/matrix-data.c b/src/matrix-data.c index b47112a1..98fcd4ff 100644 --- a/src/matrix-data.c +++ b/src/matrix-data.c @@ -126,7 +126,7 @@ struct matrix_data_pgm int contents[EOC * 3 + 1]; /* Contents. */ int n_contents; /* Number of entries. */ - + /* Continuous variables. */ int n_continuous; /* Number of continuous variables. */ int first_continuous; /* Index into default_dict.var of first continuous variable. */ @@ -786,6 +786,7 @@ enum matrix_token_type MSTR /* String. */ }; +/* A MATRIX DATA parsing token. */ struct matrix_token { enum matrix_token_type type; @@ -1009,9 +1010,10 @@ static double *split_values; static int nr_read_splits (struct matrix_data_pgm *, int compare); static int nr_read_factors (struct matrix_data_pgm *, int cell); -static void nr_output_data (struct matrix_data_pgm *, +static void nr_output_data (struct matrix_data_pgm *, struct ccase *, write_case_func *, write_case_data); static void matrix_data_read_without_rowtype (struct case_source *source, + struct ccase *, write_case_func *, write_case_data); @@ -1028,7 +1030,7 @@ read_matrices_without_rowtype (struct matrix_data_pgm *mx) max_cell_index = 0; vfm_source = create_case_source (&matrix_data_without_rowtype_source_class, - mx); + default_dict, mx); procedure (NULL, NULL, NULL, NULL); @@ -1201,6 +1203,7 @@ nr_read_data_lines (struct matrix_data_pgm *mx, writes them to the output file. Returns success. */ static void matrix_data_read_without_rowtype (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { @@ -1287,7 +1290,7 @@ matrix_data_read_without_rowtype (struct case_source *source, } } - nr_output_data (mx, write_case, wc_data); + nr_output_data (mx, c, write_case, wc_data); if (dict_get_split_cnt (default_dict) == 0 || !another_token (mx->data_file)) @@ -1405,16 +1408,17 @@ nr_read_factors (struct matrix_data_pgm *mx, int cell) CP to the active file. */ static void dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { int type = content_type[content]; { - st_bare_pad_copy (temp_case->data[mx->rowtype_->fv].s, + st_bare_pad_copy (c->data[mx->rowtype_->fv].s, content_names[content], 8); if (type != 1) - memset (&temp_case->data[mx->varname_->fv].s, ' ', 8); + memset (&c->data[mx->varname_->fv].s, ' ', 8); } { @@ -1428,11 +1432,11 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp, for (j = 0; j < mx->n_continuous; j++) { int fv = dict_get_var (default_dict, mx->first_continuous + j)->fv; - temp_case->data[fv].f = *cp; + c->data[fv].f = *cp; cp++; } if (type == 1) - st_bare_pad_copy (temp_case->data[mx->varname_->fv].s, + st_bare_pad_copy (c->data[mx->varname_->fv].s, dict_get_var (default_dict, mx->first_continuous + i)->name, 8); @@ -1443,7 +1447,7 @@ dump_cell_content (struct matrix_data_pgm *mx, int content, double *cp, /* Finally dump out everything from nr_data[] to the output file. */ static void -nr_output_data (struct matrix_data_pgm *mx, +nr_output_data (struct matrix_data_pgm *mx, struct ccase *c, write_case_func *write_case, write_case_data wc_data) { { @@ -1454,7 +1458,7 @@ nr_output_data (struct matrix_data_pgm *mx, split_cnt = dict_get_split_cnt (default_dict); split = dict_get_split_vars (default_dict); for (i = 0; i < split_cnt; i++) - temp_case->data[split[i]->fv].f = split_values[i]; + c->data[split[i]->fv].f = split_values[i]; } if (mx->n_factors) @@ -1468,7 +1472,7 @@ nr_output_data (struct matrix_data_pgm *mx, for (factor = 0; factor < mx->n_factors; factor++) { - temp_case->data[mx->factors[factor]->fv].f + c->data[mx->factors[factor]->fv].f = nr_factor_values[factor + cell * mx->n_factors]; debug_printf (("f:%s ", mx->factors[factor]->name)); } @@ -1484,7 +1488,7 @@ nr_output_data (struct matrix_data_pgm *mx, && nr_data[content][cell] != NULL); dump_cell_content (mx, content, nr_data[content][cell], - write_case, wc_data); + c, write_case, wc_data); } } } @@ -1497,13 +1501,13 @@ nr_output_data (struct matrix_data_pgm *mx, int factor; for (factor = 0; factor < mx->n_factors; factor++) - temp_case->data[mx->factors[factor]->fv].f = SYSMIS; + c->data[mx->factors[factor]->fv].f = SYSMIS; } for (content = 0; content <= PROX; content++) if (!mx->is_per_factor[content] && nr_data[content] != NULL) dump_cell_content (mx, content, nr_data[content][0], - write_case, wc_data); + c, write_case, wc_data); } } @@ -1528,12 +1532,15 @@ struct factor_data *wr_data; struct factor_data *wr_current; static int wr_read_splits (struct matrix_data_pgm *, + struct ccase *, write_case_func *, write_case_data); -static int wr_output_data (struct matrix_data_pgm *, write_case_func *, write_case_data); +static int wr_output_data (struct matrix_data_pgm *, + struct ccase *, write_case_func *, write_case_data); static int wr_read_rowtype (const struct matrix_token *, struct file_handle *); static int wr_read_factors (struct matrix_data_pgm *); static int wr_read_indeps (struct matrix_data_pgm *); static void matrix_data_read_with_rowtype (struct case_source *, + struct ccase *, write_case_func *, write_case_data); @@ -1546,7 +1553,8 @@ read_matrices_with_rowtype (struct matrix_data_pgm *mx) split_values = NULL; mx->cells = 0; - vfm_source = create_case_source (&matrix_data_with_rowtype_source_class, mx); + vfm_source = create_case_source (&matrix_data_with_rowtype_source_class, + default_dict, mx); procedure (NULL, NULL, NULL, NULL); @@ -1557,6 +1565,7 @@ read_matrices_with_rowtype (struct matrix_data_pgm *mx) /* Read from the data file and write it to the active file. */ static void matrix_data_read_with_rowtype (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { @@ -1564,7 +1573,7 @@ matrix_data_read_with_rowtype (struct case_source *source, do { - if (!wr_read_splits (mx, write_case, wc_data)) + if (!wr_read_splits (mx, c, write_case, wc_data)) return; if (!wr_read_factors (mx)) @@ -1575,13 +1584,14 @@ matrix_data_read_with_rowtype (struct case_source *source, } while (another_token (mx->data_file)); - wr_output_data (mx, write_case, wc_data); + wr_output_data (mx, c, write_case, wc_data); } /* Read the split file variables. If they differ from the previous set of split variables then output the data. Returns success. */ static int wr_read_splits (struct matrix_data_pgm *mx, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { int compare; @@ -1617,7 +1627,7 @@ wr_read_splits (struct matrix_data_pgm *mx, if (compare && split_values[i] != token.number && !different) { - if (!wr_output_data (mx, write_case, wc_data)) + if (!wr_output_data (mx, c, write_case, wc_data)) return 0; different = 1; mx->cells = 0; @@ -1669,6 +1679,7 @@ compare_factors (const void *a_, const void *b_, void *mx_) file. */ static int wr_output_data (struct matrix_data_pgm *mx, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { { @@ -1679,7 +1690,7 @@ wr_output_data (struct matrix_data_pgm *mx, split_cnt = dict_get_split_cnt (default_dict); split = dict_get_split_vars (default_dict); for (i = 0; i < split_cnt; i++) - temp_case->data[split[i]->fv].f = split_values[i]; + c->data[split[i]->fv].f = split_values[i]; } /* Sort the wr_data list. */ @@ -1714,7 +1725,7 @@ wr_output_data (struct matrix_data_pgm *mx, for (factor = 0; factor < mx->n_factors; factor++) { - temp_case->data[mx->factors[factor]->fv].f + c->data[mx->factors[factor]->fv].f = iter->factors[factor]; debug_printf (("f:%s ", factors[factor]->name)); } @@ -1749,7 +1760,7 @@ wr_output_data (struct matrix_data_pgm *mx, fill_matrix (mx, content, iter->data[content]); dump_cell_content (mx, content, iter->data[content], - write_case, wc_data); + c, write_case, wc_data); } } } diff --git a/src/pfm-read.c b/src/pfm-read.c index b587fbca..8f19f1ba 100644 --- a/src/pfm-read.c +++ b/src/pfm-read.c @@ -617,11 +617,9 @@ static int convert_format (struct file_handle *h, int fmt[3], struct fmt_spec *v, struct variable *vv) { - if (fmt[0] < 0 - || (size_t) fmt[0] >= sizeof translate_fmt / sizeof *translate_fmt) + v->type = translate_fmt (fmt[0]); + if (v->type == -1) lose ((h, _("%s: Bad format specifier byte (%d)."), vv->name, fmt[0])); - - v->type = translate_fmt[fmt[0]]; v->w = fmt[1]; v->d = fmt[2]; diff --git a/src/postscript.c b/src/postscript.c index b911f8cc..196e7120 100644 --- a/src/postscript.c +++ b/src/postscript.c @@ -2575,7 +2575,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw) char_name = local_char_name; if (ext->current->font->ligatures && *cp == 'f') { - int lig; + int lig = 0; char_name = NULL; if (cp < end - 1) @@ -2604,7 +2604,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw) } if ((lig & ext->current->font->ligatures) == 0) { - local_char_name[0] = *cp++; /* 'f' */ + local_char_name[0] = *cp; /* 'f' */ char_name = local_char_name; } } diff --git a/src/print.c b/src/print.c index 95dae157..17c0eab2 100644 --- a/src/print.c +++ b/src/print.c @@ -17,6 +17,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* FIXME: seems like a lot of code duplication with data-list.c. */ + #include #include #include diff --git a/src/recode.c b/src/recode.c index 53a8e23a..ee164b9c 100644 --- a/src/recode.c +++ b/src/recode.c @@ -34,6 +34,7 @@ /* Definitions. */ +/* Type of source value for RECODE. */ enum { RCD_END, /* sentinel value */ diff --git a/src/sample.c b/src/sample.c index ce5d18d8..3f887935 100644 --- a/src/sample.c +++ b/src/sample.c @@ -118,6 +118,7 @@ cmd_sample (void) return lex_end_of_command (); } +/* Executes a SAMPLE transformation. */ static int sample_trns_proc (struct trns_header * trns, struct ccase *c UNUSED, int case_num UNUSED) diff --git a/src/sfm-read.c b/src/sfm-read.c index c14e11ac..03b6d5ab 100644 --- a/src/sfm-read.c +++ b/src/sfm-read.c @@ -895,12 +895,10 @@ lossage: static int parse_format_spec (struct file_handle *h, int32 s, struct fmt_spec *v, struct variable *vv) { - if ((size_t) ((s >> 16) & 0xff) - >= sizeof translate_fmt / sizeof *translate_fmt) + v->type = translate_fmt ((s >> 16) & 0xff); + if (v->type == -1) lose ((ME, _("%s: Bad format specifier byte (%d)."), h->fn, (s >> 16) & 0xff)); - - v->type = translate_fmt[(s >> 16) & 0xff]; v->w = (s >> 8) & 0xff; v->d = s & 0xff; diff --git a/src/sort.c b/src/sort.c index 99d850ad..b00c492f 100644 --- a/src/sort.c +++ b/src/sort.c @@ -141,6 +141,7 @@ parse_sort (void) return NULL; } +/* Destroys a SORT CASES program. */ void destroy_sort_cases_pgm (struct sort_cases_pgm *scp) { @@ -169,6 +170,8 @@ destroy_sort_cases_pgm (struct sort_cases_pgm *scp) int sort_cases (struct sort_cases_pgm *scp, int separate) { + scp->case_size = sizeof (union value) * compaction_nval; + /* Not sure this is necessary but it's good to be safe. */ if (separate && case_source_is_class (vfm_source, &sort_source_class)) procedure (NULL, NULL, NULL, NULL); @@ -192,6 +195,7 @@ sort_cases (struct sort_cases_pgm *scp, int separate) return 0; } +/* Results of an internal sort. */ struct internal_sort { struct case_list **results; @@ -261,6 +265,7 @@ do_internal_sort (struct sort_cases_pgm *scp, int separate) return NULL; } +/* Destroys an internal sort result. */ static void destroy_internal_sort (struct internal_sort *isrt) { @@ -320,18 +325,19 @@ compare_initial_runs (const void *a_, const void *b_, void *aux UNUSED) return a->case_cnt > b->case_cnt ? -1 : a->case_cnt case_cnt; } +/* Results of an external sort. */ struct external_sort { struct sort_cases_pgm *scp; /* SORT CASES info. */ struct initial_run *initial_runs; /* Array of initial runs. */ size_t run_cnt, run_cap; /* Number of runs, allocated capacity. */ char *temp_dir; /* Temporary file directory name. */ + char *temp_name; /* Name of a temporary file. */ int next_file_idx; /* Lowest unused file index. */ - size_t case_size; /* Number of bytes in case. */ }; /* Prototypes for helper functions. */ -static void sort_sink_write (struct case_sink *, struct ccase *); +static void sort_sink_write (struct case_sink *, const struct ccase *); static int write_initial_runs (struct external_sort *, int separate); static int init_external_sort (struct external_sort *); static int merge (struct external_sort *); @@ -351,7 +357,6 @@ 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)) @@ -386,6 +391,8 @@ destroy_external_sort (struct external_sort *xsrt) for (i = 0; i < xsrt->run_cnt; i++) remove_temp_file (xsrt, xsrt->initial_runs[i].file_idx); rmdir_temp_dir (xsrt); + free (xsrt->temp_dir); + free (xsrt->temp_name); free (xsrt->initial_runs); free (xsrt); } @@ -467,13 +474,16 @@ init_external_sort (struct external_sort *xsrt) /* Temporary directory. */ xsrt->temp_dir = make_temp_dir (); + xsrt->temp_name = NULL; if (xsrt->temp_dir == NULL) return 0; + xsrt->temp_name = xmalloc (strlen (xsrt->temp_dir) + 64); return 1; } - +/* Returns nonzero if we should return an error even though the + operation succeeded. Useful for testing. */ static int simulate_error (void) { @@ -502,22 +512,26 @@ rmdir_temp_dir (struct external_sort *xsrt) } } -#define TEMP_FILE_NAME_SIZE (L_tmpnam + 32) -static void -get_temp_file_name (struct external_sort *xsrt, int file_idx, - char filename[TEMP_FILE_NAME_SIZE]) +/* Returns the name of temporary file number FILE_IDX for XSRT. + The name is written into a static buffer, so be careful. */ +static char * +get_temp_file_name (struct external_sort *xsrt, int file_idx) { assert (xsrt->temp_dir != NULL); - sprintf (filename, "%s%c%04d", xsrt->temp_dir, DIR_SEPARATOR, file_idx); + sprintf (xsrt->temp_name, "%s%c%04d", + xsrt->temp_dir, DIR_SEPARATOR, file_idx); + return xsrt->temp_name; } +/* Opens temporary file numbered FILE_IDX for XSRT with mode MODE + and returns the FILE *. */ static FILE * open_temp_file (struct external_sort *xsrt, int file_idx, const char *mode) { - char temp_file[TEMP_FILE_NAME_SIZE]; + char *temp_file; FILE *file; - get_temp_file_name (xsrt, file_idx, temp_file); + temp_file = get_temp_file_name (xsrt, file_idx); file = fopen (temp_file, mode); if (simulate_error () || file == NULL) @@ -528,13 +542,14 @@ open_temp_file (struct external_sort *xsrt, int file_idx, const char *mode) return file; } +/* Closes FILE, which is the temporary file numbered FILE_IDX + under XSRT. Returns nonzero only if successful. */ static int close_temp_file (struct external_sort *xsrt, int file_idx, FILE *file) { if (file != NULL) { - char temp_file[TEMP_FILE_NAME_SIZE]; - get_temp_file_name (xsrt, file_idx, temp_file); + char *temp_file = get_temp_file_name (xsrt, file_idx); if (simulate_error () || fclose (file) == EOF) { msg (SE, _("%s: Error closing temporary file: %s."), @@ -545,19 +560,21 @@ close_temp_file (struct external_sort *xsrt, int file_idx, FILE *file) return 1; } +/* Delete temporary file numbered FILE_IDX for XSRT. */ static void remove_temp_file (struct external_sort *xsrt, int file_idx) { if (file_idx != -1) { - char temp_file[TEMP_FILE_NAME_SIZE]; - get_temp_file_name (xsrt, file_idx, temp_file); + char *temp_file = get_temp_file_name (xsrt, file_idx); if (simulate_error () || remove (temp_file) != 0) msg (SE, _("%s: Error removing temporary file: %s."), temp_file, strerror (errno)); } } +/* Writes SIZE bytes from buffer DATA into FILE, which is + temporary file numbered FILE_IDX from XSRT. */ static int write_temp_file (struct external_sort *xsrt, int file_idx, FILE *file, const void *data, size_t size) @@ -566,14 +583,15 @@ write_temp_file (struct external_sort *xsrt, int file_idx, return 1; else { - char temp_file[TEMP_FILE_NAME_SIZE]; - get_temp_file_name (xsrt, file_idx, temp_file); + char *temp_file = get_temp_file_name (xsrt, file_idx); msg (SE, _("%s: Error writing temporary file: %s."), temp_file, strerror (errno)); return 0; } } +/* Reads SIZE bytes into buffer DATA into FILE, which is + temporary file numbered FILE_IDX from XSRT. */ static int read_temp_file (struct external_sort *xsrt, int file_idx, FILE *file, void *data, size_t size) @@ -582,8 +600,7 @@ read_temp_file (struct external_sort *xsrt, int file_idx, return 1; else { - char temp_file[TEMP_FILE_NAME_SIZE]; - get_temp_file_name (xsrt, file_idx, temp_file); + char *temp_file = get_temp_file_name (xsrt, file_idx); if (ferror (file)) msg (SE, _("%s: Error reading temporary file: %s."), temp_file, strerror (errno)); @@ -603,6 +620,7 @@ struct record_run struct case_list *record; /* Case data. */ }; +/* Represents a set of initial runs during an external sort. */ struct initial_run_state { struct external_sort *xsrt; @@ -635,6 +653,8 @@ static int compare_record_run (const struct record_run *, struct sort_cases_pgm *); static int compare_record_run_minheap (const void *, const void *, void *); +/* Writes initial runs for XSRT, sending them to a separate file + if SEPARATE is nonzero. */ static int write_initial_runs (struct external_sort *xsrt, int separate) { @@ -659,7 +679,7 @@ write_initial_runs (struct external_sort *xsrt, int separate) /* Create case sink. */ if (!separate) { - if (vfm_sink) + if (vfm_sink != NULL && vfm_sink->class->destroy != NULL) vfm_sink->class->destroy (vfm_sink); vfm_sink = create_case_sink (&sort_sink_class, irs); xsrt->scp->ref_cnt++; @@ -682,7 +702,7 @@ write_initial_runs (struct external_sort *xsrt, int separate) /* Add a single case to an initial run. */ static void -sort_sink_write (struct case_sink *sink, struct ccase *c) +sort_sink_write (struct case_sink *sink, const struct ccase *c) { struct initial_run_state *irs = sink->aux; struct record_run *new_record_run; @@ -708,6 +728,7 @@ sort_sink_write (struct case_sink *sink, struct ccase *c) output_record (irs); } +/* Destroys the initial run state represented by IRS. */ static void destroy_initial_run_state (struct initial_run_state *irs) { @@ -821,6 +842,8 @@ compare_record (const union value *a, const union value *b, return 0; } +/* Compares record-run tuples A and B on run number first, then + on the current record according to SCP. */ static int compare_record_run (const struct record_run *a, const struct record_run *b, @@ -832,6 +855,9 @@ compare_record_run (const struct record_run *a, return compare_record (a->record->c.data, b->record->c.data, scp); } +/* Compares record-run tuples A and B on run number first, then + on the current record according to SCP, but in descending + order. */ static int compare_record_run_minheap (const void *a, const void *b, void *scp) { @@ -879,6 +905,7 @@ end_run (struct initial_run_state *irs) irs->output_file = NULL; } +/* Writes a record to the current initial run. */ static void output_record (struct initial_run_state *irs) { @@ -927,6 +954,8 @@ output_record (struct initial_run_state *irs) irs->last_output = record_run->record; } +/* Gets a case from the free list in IRS. It is an error to call + this function if the free list is empty. */ static struct case_list * grab_case (struct initial_run_state *irs) { @@ -940,6 +969,7 @@ grab_case (struct initial_run_state *irs) return c; } +/* Returns C to the free list in IRS. */ static void release_case (struct initial_run_state *irs, struct case_list *c) { @@ -952,6 +982,7 @@ release_case (struct initial_run_state *irs, struct case_list *c) /* Merging. */ +/* State of merging initial runs. */ struct merge_state { struct external_sort *xsrt; /* External sort state. */ @@ -1228,18 +1259,13 @@ fill_run_buffer (struct merge_state *mrg, struct run *run) return 1; } -static void -sort_sink_destroy (struct case_sink *sink UNUSED) -{ - assert (0); -} - static struct case_source * sort_sink_make_source (struct case_sink *sink) { struct initial_run_state *irs = sink->aux; - return create_case_source (&sort_source_class, irs->xsrt->scp); + return create_case_source (&sort_source_class, default_dict, + irs->xsrt->scp); } const struct case_sink_class sort_sink_class = @@ -1247,72 +1273,90 @@ const struct case_sink_class sort_sink_class = "SORT CASES", NULL, sort_sink_write, - sort_sink_destroy, + NULL, sort_sink_make_source, }; +struct sort_source_aux + { + struct sort_cases_pgm *scp; + struct ccase *dst; + write_case_func *write_case; + write_case_data wc_data; + }; + +/* Passes C to the write_case function. */ +static int +sort_source_read_helper (const struct ccase *src, void *aux_) +{ + struct sort_source_aux *aux = aux_; + + memcpy (aux->dst, src, aux->scp->case_size); + return aux->write_case (aux->wc_data); +} + /* Reads all the records from the source stream and passes them to write_case(). */ static void sort_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { struct sort_cases_pgm *scp = source->aux; + struct sort_source_aux aux; + + aux.scp = scp; + aux.dst = c; + aux.write_case = write_case; + aux.wc_data = wc_data; - read_sort_output (scp, write_case, wc_data); + read_sort_output (scp, sort_source_read_helper, &aux); } -void read_internal_sort_output (struct internal_sort *isrt, - write_case_func *write_case, - write_case_data wc_data); -void read_external_sort_output (struct external_sort *xsrt, - write_case_func *write_case, - write_case_data wc_data); +static void read_internal_sort_output (struct internal_sort *isrt, + read_sort_output_func *, void *aux); +static void read_external_sort_output (struct external_sort *xsrt, + read_sort_output_func *, void *aux); /* Reads all the records from the output stream and passes them to the function provided, which must have an interface identical to write_case(). */ void read_sort_output (struct sort_cases_pgm *scp, - write_case_func *write_case, write_case_data wc_data) + read_sort_output_func *output_func, void *aux) { assert ((scp->isrt != NULL) + (scp->xsrt != NULL) <= 1); if (scp->isrt != NULL) - read_internal_sort_output (scp->isrt, write_case, wc_data); + read_internal_sort_output (scp->isrt, output_func, aux); else if (scp->xsrt != NULL) - read_external_sort_output (scp->xsrt, write_case, wc_data); + read_external_sort_output (scp->xsrt, output_func, aux); else { /* No results. Probably an external sort that failed. */ } } -void +static void read_internal_sort_output (struct internal_sort *isrt, - write_case_func *write_case, - write_case_data wc_data) + read_sort_output_func *output_func, + void *aux) { - struct ccase *save_temp_case = temp_case; struct case_list **p; - for (p = isrt->results; *p; p++) - { - temp_case = &(*p)->c; - write_case (wc_data); - } + for (p = isrt->results; *p; p++) + if (!output_func (&(*p)->c, aux)) + break; free (isrt->results); - - temp_case = save_temp_case; } -void +static void read_external_sort_output (struct external_sort *xsrt, - write_case_func *write_case, - write_case_data wc_data) + read_sort_output_func *output_func, void *aux) { FILE *file; int file_idx; size_t i; + struct ccase *c; assert (xsrt->run_cnt == 1); file_idx = xsrt->initial_runs[0].file_idx; @@ -1324,18 +1368,19 @@ read_external_sort_output (struct external_sort *xsrt, return; } + c = xmalloc (xsrt->scp->case_size); for (i = 0; i < xsrt->initial_runs[0].case_cnt; i++) { - if (!read_temp_file (xsrt, file_idx, file, - temp_case, xsrt->case_size)) + if (!read_temp_file (xsrt, file_idx, file, c, xsrt->scp->case_size)) { err_failure (); break; } - if (!write_case (wc_data)) + if (!output_func (c, aux)) break; } + free (c); } static void diff --git a/src/sort.h b/src/sort.h index 928a5170..4f8659e6 100644 --- a/src/sort.h +++ b/src/sort.h @@ -40,13 +40,17 @@ struct sort_cases_pgm struct internal_sort *isrt; /* Internal sort output. */ struct external_sort *xsrt; /* External sort output. */ + size_t case_size; /* Number of bytes in case. */ }; /* SORT CASES programmatic interface. */ + +typedef int read_sort_output_func (const struct ccase *, void *aux); + struct sort_cases_pgm *parse_sort (void); int sort_cases (struct sort_cases_pgm *, int separate); void read_sort_output (struct sort_cases_pgm *, - write_case_func *, write_case_data); + read_sort_output_func, void *aux); void destroy_sort_cases_pgm (struct sort_cases_pgm *); #endif /* !sort_h */ diff --git a/src/vars-prs.c b/src/vars-prs.c index 66fec9ae..8b15fd7b 100644 --- a/src/vars-prs.c +++ b/src/vars-prs.c @@ -30,6 +30,9 @@ #include "misc.h" #include "str.h" +/* Parses a name as a variable within VS and returns the variable + if successful. On failure emits an error message and returns + a null pointer. */ static struct variable * parse_vs_variable (struct var_set *vs) { @@ -49,6 +52,9 @@ parse_vs_variable (struct var_set *vs) return vp; } +/* Parses a variable name in dictionary D and returns the + variable if successful. On failure emits an error message and + returns a null pointer. */ struct variable * parse_dict_variable (struct dictionary *d) { @@ -58,13 +64,17 @@ parse_dict_variable (struct dictionary *d) return var; } +/* Parses a variable name in default_dict and returns the + variable if successful. On failure emits an error message and + returns a null pointer. */ struct variable * parse_variable (void) { return parse_dict_variable (default_dict); } - +/* Returns the dictionary class corresponding to a variable named + NAME. */ enum dict_class dict_class_from_id (const char *name) { @@ -81,22 +91,26 @@ dict_class_from_id (const char *name) } } +/* Returns the name of dictionary class DICT_CLASS. */ const char * dict_class_to_name (enum dict_class dict_class) { switch (dict_class) { case DC_ORDINARY: - return "ordinary"; + return _("ordinary"); case DC_SYSTEM: - return "system"; + return _("system"); case DC_SCRATCH: - return "scratch"; + return _("scratch"); default: assert (0); } } +/* Parses a set of variables from dictionary D given options + OPTS. Resulting list of variables stored in *VAR and the + number of variables into *CNT. */ int parse_variables (struct dictionary *d, struct variable ***var, int *cnt, int opts) @@ -297,6 +311,9 @@ fail: return 0; } +/* Extracts a numeric suffix from variable name S, copying it + into string R. Sets *D to the length of R and *N to its + value. */ static int extract_num (char *s, char *r, int *n, int *d) { @@ -502,6 +519,7 @@ fail: return 0; } +/* A set of variables. */ struct var_set { size_t (*get_cnt) (struct var_set *); @@ -511,6 +529,7 @@ struct var_set void *aux; }; +/* Returns the number of variables in VS. */ size_t var_set_get_cnt (struct var_set *vs) { @@ -519,6 +538,8 @@ var_set_get_cnt (struct var_set *vs) return vs->get_cnt (vs); } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ struct variable * var_set_get_var (struct var_set *vs, size_t idx) { @@ -528,6 +549,8 @@ var_set_get_var (struct var_set *vs, size_t idx) return vs->get_var (vs, idx); } +/* Returns the variable in VS named NAME, or a null pointer if VS + contains no variable with that name. */ struct variable * var_set_lookup_var (struct var_set *vs, const char *name) { @@ -538,6 +561,7 @@ var_set_lookup_var (struct var_set *vs, const char *name) return vs->lookup_var (vs, name); } +/* Destroys VS. */ void var_set_destroy (struct var_set *vs) { @@ -545,6 +569,7 @@ var_set_destroy (struct var_set *vs) vs->destroy (vs); } +/* Returns the number of variables in VS. */ static size_t dict_var_set_get_cnt (struct var_set *vs) { @@ -553,6 +578,8 @@ dict_var_set_get_cnt (struct var_set *vs) return dict_get_var_cnt (d); } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ static struct variable * dict_var_set_get_var (struct var_set *vs, size_t idx) { @@ -561,6 +588,8 @@ dict_var_set_get_var (struct var_set *vs, size_t idx) return dict_get_var (d, idx); } +/* Returns the variable in VS named NAME, or a null pointer if VS + contains no variable with that name. */ static struct variable * dict_var_set_lookup_var (struct var_set *vs, const char *name) { @@ -569,12 +598,14 @@ dict_var_set_lookup_var (struct var_set *vs, const char *name) return dict_lookup_var (d, name); } +/* Destroys VS. */ static void dict_var_set_destroy (struct var_set *vs) { free (vs); } +/* Returns a variable set based on D. */ struct var_set * var_set_create_from_dict (struct dictionary *d) { @@ -587,13 +618,15 @@ var_set_create_from_dict (struct dictionary *d) return vs; } +/* A variable set based on an array. */ struct array_var_set { - struct variable **var; - size_t var_cnt; - struct hsh_table *name_tab; + struct variable **var; /* Array of variables. */ + size_t var_cnt; /* Number of elements in var. */ + struct hsh_table *name_tab; /* Hash from variable names to variables. */ }; +/* Returns the number of variables in VS. */ static size_t array_var_set_get_cnt (struct var_set *vs) { @@ -602,6 +635,8 @@ array_var_set_get_cnt (struct var_set *vs) return avs->var_cnt; } +/* Return variable with index IDX in VS. + IDX must be less than the number of variables in VS. */ static struct variable * array_var_set_get_var (struct var_set *vs, size_t idx) { @@ -610,6 +645,8 @@ array_var_set_get_var (struct var_set *vs, size_t idx) return avs->var[idx]; } +/* Returns the variable in VS named NAME, or a null pointer if VS + contains no variable with that name. */ static struct variable * array_var_set_lookup_var (struct var_set *vs, const char *name) { @@ -621,6 +658,7 @@ array_var_set_lookup_var (struct var_set *vs, const char *name) return hsh_find (avs->name_tab, &v); } +/* Destroys VS. */ static void array_var_set_destroy (struct var_set *vs) { @@ -631,6 +669,8 @@ array_var_set_destroy (struct var_set *vs) free (vs); } +/* Returns a variable set based on the VAR_CNT variables in + VAR. */ struct var_set * var_set_create_from_array (struct variable **var, size_t var_cnt) { diff --git a/src/vfm.c b/src/vfm.c index a847ea65..07bfaad3 100644 --- a/src/vfm.c +++ b/src/vfm.c @@ -97,30 +97,34 @@ static int lag_count; /* Number of cases in lag_queue so far. */ static int lag_head; /* Index where next case will be added. */ static struct ccase **lag_queue; /* Array of n_lag ccase * elements. */ +static struct ccase *create_trns_case (struct dictionary *dict); static void open_active_file (void); static void close_active_file (struct write_case_data *); 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 (int case_num); +static void lag_case (const struct ccase *); +static write_case_func procedure_write_case; +static void clear_case (struct ccase *); +static int exclude_this_case (const struct ccase *, int case_num); /* Public functions. */ +/* Auxiliary data for executing a procedure. */ struct procedure_aux_data { + struct ccase *trns_case; /* Case used for transformations. */ size_t cases_written; /* Number of cases written so far. */ }; +/* Auxiliary data for SPLIT FILE. */ 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 PROC_FUNC with CURCASE - set to the case, and writes them to a new active file. + the active set of transformations, passes each of them to + PROC_FUNC, and writes them to a new active file. Divides the active file into zero or more series of one or more cases each. BEGIN_FUNC is called before each series. END_FUNC is @@ -130,7 +134,7 @@ struct split_aux_data PROC_FUNC, and END_FUNC as auxiliary data. */ void procedure (void (*begin_func) (void *), - int (*proc_func) (struct ccase *curcase, void *), + int (*proc_func) (struct ccase *, void *), void (*end_func) (void *), void *func_aux) { @@ -146,6 +150,7 @@ procedure (void (*begin_func) (void *), assert (++recursive_call == 1); proc_aux.cases_written = 0; + proc_aux.trns_case = create_trns_case (default_dict); /* Normally we just use the data passed by the user. */ procedure_write_data.begin_func = begin_func; @@ -174,66 +179,75 @@ procedure (void (*begin_func) (void *), open_active_file (); if (vfm_source != NULL) vfm_source->class->read (vfm_source, + proc_aux.trns_case, procedure_write_case, &procedure_write_data); close_active_file (&procedure_write_data); if (split) free (split_aux.prev_case); + free (proc_aux.trns_case); + assert (--recursive_call == 0); } /* Active file processing support. Subtly different semantics from procedure(). */ -static int process_active_file_write_case (struct write_case_data *data); +static write_case_func process_active_file_write_case; -/* The casefunc might want us to stop calling it. */ +/* The case_func might want us to stop calling it. */ 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 - 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(). +/* Reads all the cases from the active file and passes them + one-by-one to CASE_FUNC. Before any cases are passed, calls + BEGIN_FUNC. After all the cases have been passed, calls + END_FUNC. BEGIN_FUNC, CASE_FUNC, and END_FUNC can write 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 (*begin_func) (void *), - int (*casefunc) (struct ccase *curcase, void *), + int (*case_func) (struct ccase *, void *), void (*end_func) (void *), void *func_aux) { + struct procedure_aux_data proc_aux; struct write_case_data process_active_write_data; + proc_aux.cases_written = 0; + proc_aux.trns_case = create_trns_case (default_dict); + process_active_write_data.begin_func = begin_func; - process_active_write_data.proc_func = casefunc; + process_active_write_data.proc_func = case_func; process_active_write_data.end_func = end_func; process_active_write_data.func_aux = func_aux; + process_active_write_data.aux = &proc_aux; not_canceled = 1; open_active_file (); begin_func (func_aux); if (vfm_source != NULL) - vfm_source->class->read (vfm_source, process_active_file_write_case, + vfm_source->class->read (vfm_source, proc_aux.trns_case, + process_active_file_write_case, &process_active_write_data); end_func (func_aux); close_active_file (&process_active_write_data); } -/* Pass the current case to casefunc. */ +/* Pass the current case to case_func. */ static int -process_active_file_write_case (struct write_case_data *data) +process_active_file_write_case (struct write_case_data *wc_data) { - /* Index of current transformation. */ - int cur_trns; + struct procedure_aux_data *proc_aux = wc_data->aux; + int cur_trns; /* Index of current transformation. */ - for (cur_trns = f_trns ; cur_trns != temp_trns; ) + for (cur_trns = f_trns; cur_trns != temp_trns; ) { int code; - code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case, + code = t_trns[cur_trns]->proc (t_trns[cur_trns], proc_aux->trns_case, case_count + 1); switch (code) { @@ -252,25 +266,52 @@ process_active_file_write_case (struct write_case_data *data) } if (n_lag) - lag_case (); + lag_case (proc_aux->trns_case); /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */ - if (not_canceled && !exclude_this_case (case_count + 1)) - not_canceled = data->proc_func (temp_case, data->func_aux); + if (not_canceled && !exclude_this_case (proc_aux->trns_case, case_count + 1)) + not_canceled = wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux); case_count++; done: - clear_temp_case (); + clear_case (proc_aux->trns_case); return 1; } -/* Write temp_case to the active file. */ +/* Write the given case to the active file. */ void -process_active_file_output_case (void) +process_active_file_output_case (const struct ccase *c) { - vfm_sink->class->write (vfm_sink, temp_case); + vfm_sink->class->write (vfm_sink, c); +} + +/* Creates and returns a case, initializing it from the vectors + that say which `value's need to be initialized just once, and + which ones need to be re-initialized before every case. */ +static struct ccase * +create_trns_case (struct dictionary *dict) +{ + struct ccase *c = xmalloc (dict_get_case_size (dict)); + size_t var_cnt = dict_get_var_cnt (dict); + size_t i; + + for (i = 0; i < var_cnt; i++) + { + struct variable *v = dict_get_var (dict, i); + + if (v->type == NUMERIC) + { + if (v->reinit) + c->data[v->fv].f = 0.0; + else + c->data[v->fv].f = SYSMIS; + } + else + memset (c->data[v->fv].s, ' ', v->width); + } + return c; } /* Opening the active file. */ @@ -282,20 +323,6 @@ process_active_file_output_case (void) static void prepare_for_writing (void) { - /* FIXME: If ALL the conditions listed below hold true, then the - replacement active file is guaranteed to be identical to the - original active file: - - 1. TEMPORARY was the first transformation, OR, there were no - transformations at all. - - 2. Input is not coming from an input program. - - 3. Compaction is not necessary. - - So, in this case, we shouldn't have to replace the active - file--it's just a waste of time and space. */ - if (vfm_sink == NULL) { if (workspace_overflow) @@ -339,17 +366,11 @@ arrange_compaction (void) if (vfm_sink->class->open != NULL) vfm_sink->class->open (vfm_sink); -} - -/* Prepares the temporary case and compaction case. */ -static void -make_temp_case (void) -{ - temp_case = xmalloc (dict_get_case_size (default_dict)); if (compaction_necessary) compaction_case = xmalloc (sizeof (struct ccase) + sizeof (union value) * (compaction_nval - 1)); + } #if DEBUGGING @@ -371,31 +392,6 @@ index_to_varname (int ccase_index) } #endif -/* Initializes temp_case from the vectors that say which `value's - need to be initialized just once, and which ones need to be - re-initialized before every case. */ -static void -vector_initialization (void) -{ - size_t var_cnt = dict_get_var_cnt (default_dict); - size_t i; - - for (i = 0; i < var_cnt; i++) - { - struct variable *v = dict_get_var (default_dict, i); - - if (v->type == NUMERIC) - { - if (v->reinit) - temp_case->data[v->fv].f = 0.0; - else - temp_case->data[v->fv].f = SYSMIS; - } - else - memset (temp_case->data[v->fv].s, ' ', v->width); - } -} - /* Sets all the lag-related variables based on value of n_lag. */ static void setup_lag (void) @@ -456,8 +452,6 @@ open_active_file (void) /* The rest. */ prepare_for_writing (); arrange_compaction (); - make_temp_case (); - vector_initialization (); discard_ctl_stack (); setup_lag (); } @@ -502,7 +496,10 @@ close_active_file (struct write_case_data *data) free (vfm_source); } - vfm_source = vfm_sink->class->make_source (vfm_sink); + if (vfm_sink->class->make_source != NULL) + vfm_source = vfm_sink->class->make_source (vfm_sink); + else + vfm_source = NULL; /* Old data sink is gone now. */ free (vfm_sink); @@ -512,9 +509,6 @@ close_active_file (struct write_case_data *data) cancel_temporary (); /* Free temporary cases. */ - free (temp_case); - temp_case = NULL; - free (compaction_case); compaction_case = NULL; @@ -564,12 +558,12 @@ disk_sink_create (struct case_sink *sink) } } -/* Writes temp_case to the disk sink. */ +/* Writes case C to the disk sink. */ static void -disk_sink_write (struct case_sink *sink, struct ccase *c) +disk_sink_write (struct case_sink *sink, const struct ccase *c) { struct disk_stream_info *info = sink->aux; - union value *src_case; + const union value *src_case; if (compaction_necessary) { @@ -615,7 +609,7 @@ disk_sink_make_source (struct case_sink *sink) err_failure (); } - return create_case_source (&disk_source_class, info); + return create_case_source (&disk_source_class, default_dict, info); } /* Disk sink. */ @@ -644,6 +638,7 @@ disk_source_count (const struct case_source *source) write_case(). */ static void disk_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { struct disk_stream_info *info = source->aux; @@ -651,17 +646,17 @@ disk_source_read (struct case_source *source, for (i = 0; i < info->case_cnt; i++) { - if (!fread (temp_case, info->case_size, 1, info->file)) + if (!fread (c, 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."), strerror (errno)); err_failure (); - return; + break; } if (!write_case (wc_data)) - return; + break; } } @@ -704,6 +699,7 @@ struct memory_source_info struct case_list *cases; /* List of cases. */ }; +/* Creates the SINK memory sink. */ static void memory_sink_create (struct case_sink *sink) { @@ -718,8 +714,9 @@ memory_sink_create (struct case_sink *sink) info->head = info->tail = NULL; } +/* Writes case C to memory sink SINK. */ static void -memory_sink_write (struct case_sink *sink, struct ccase *c) +memory_sink_write (struct case_sink *sink, const struct ccase *c) { struct memory_sink_info *info = sink->aux; size_t case_size; @@ -861,7 +858,8 @@ memory_sink_make_source (struct case_sink *sink) free (sink_info); - return create_case_source (&memory_source_class, source_info); + return create_case_source (&memory_source_class, + default_dict, source_info); } const struct case_sink_class memory_sink_class = @@ -885,6 +883,7 @@ memory_source_count (const struct case_source *source) /* Reads the case stream from memory and passes it to write_case(). */ static void memory_source_read (struct case_source *source, + struct ccase *c, write_case_func *write_case, write_case_data wc_data) { struct memory_source_info *info = source->aux; @@ -892,12 +891,12 @@ memory_source_read (struct case_source *source, while (info->cases != NULL) { struct case_list *iter = info->cases; + memcpy (c, &iter->c, info->case_size); + if (!write_case (wc_data)) + break; + info->cases = iter->next; - memcpy (temp_case, &iter->c, info->case_size); free (iter); - - if (!write_case (wc_data)) - return; } } @@ -916,6 +915,7 @@ memory_source_destroy (struct case_source *source) free (info); } +/* Returns the list of cases in memory source SOURCE. */ struct case_list * memory_source_get_cases (const struct case_source *source) { @@ -924,6 +924,7 @@ memory_source_get_cases (const struct case_source *source) return info->cases; } +/* Sets the list of cases in memory source SOURCE to CASES. */ void memory_source_set_cases (const struct case_source *source, struct case_list *cases) @@ -942,14 +943,13 @@ const struct case_source_class memory_source_class = memory_source_destroy, }; -/* Add temp_case to the lag queue. */ +/* Add C to the lag queue. */ static void -lag_case (void) +lag_case (const struct ccase *c) { if (lag_count < n_lag) lag_count++; - memcpy (lag_queue[lag_head], temp_case, - dict_get_case_size (temp_dict)); + memcpy (lag_queue[lag_head], c, dict_get_case_size (temp_dict)); if (++lag_head >= n_lag) lag_head = 0; } @@ -971,10 +971,10 @@ lagged_case (int n_before) } } -/* Transforms temp_case and writes it to the replacement active file - if advisable. Returns nonzero if more cases can be accepted, zero - otherwise. Do not call this function again after it has returned - zero once. */ +/* Transforms trns_case and writes it to the replacement active + file if advisable. Returns nonzero if more cases can be + accepted, zero otherwise. Do not call this function again + after it has returned zero once. */ int procedure_write_case (write_case_data wc_data) { @@ -995,9 +995,9 @@ procedure_write_case (write_case_data wc_data) int case_limit; if (n_lag) - lag_case (); + lag_case (proc_aux->trns_case); - vfm_sink->class->write (vfm_sink, temp_case); + vfm_sink->class->write (vfm_sink, proc_aux->trns_case); proc_aux->cases_written++; case_limit = dict_get_case_limit (default_dict); @@ -1013,7 +1013,7 @@ procedure_write_case (write_case_data wc_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], proc_aux->trns_case, proc_aux->cases_written + 1); switch (code) { @@ -1039,22 +1039,22 @@ procedure_write_case (write_case_data wc_data) /* Call the procedure if there is one and FILTER and PROCESS IF don't prohibit it. */ if (wc_data->proc_func != NULL - && !exclude_this_case (proc_aux->cases_written + 1)) - wc_data->proc_func (temp_case, wc_data->func_aux); + && !exclude_this_case (proc_aux->trns_case, proc_aux->cases_written + 1)) + wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux); case_count++; done: - clear_temp_case (); + clear_case (proc_aux->trns_case); /* Return previously determined value. */ return more_cases; } -/* Clears the variables in the temporary case that need to be - cleared between processing cases. */ +/* Clears the variables in C that need to be cleared between + processing cases. */ static void -clear_temp_case (void) +clear_case (struct ccase *c) { /* FIXME? This is linear in the number of variables, but doesn't need to be, so it's an easy optimization target. */ @@ -1067,31 +1067,31 @@ clear_temp_case (void) if (v->init && v->reinit) { if (v->type == NUMERIC) - temp_case->data[v->fv].f = SYSMIS; + c->data[v->fv].f = SYSMIS; else - memset (temp_case->data[v->fv].s, ' ', v->width); + memset (c->data[v->fv].s, ' ', v->width); } } } -/* Returns nonzero if this case (numbered CASE_NUM) should be +/* Returns nonzero if case C with case number CASE_NUM should be exclude as specified on FILTER or PROCESS IF, otherwise zero. */ static int -exclude_this_case (int case_num) +exclude_this_case (const struct ccase *c, int case_num) { /* FILTER. */ struct variable *filter_var = dict_get_filter (default_dict); if (filter_var != NULL) { - double f = temp_case->data[filter_var->fv].f; + double f = c->data[filter_var->fv].f; if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var)) return 1; } /* PROCESS IF. */ if (process_if_expr != NULL - && expr_evaluate (process_if_expr, temp_case, case_num, NULL) != 1.0) + && expr_evaluate (process_if_expr, c, case_num, NULL) != 1.0) return 1; return 0; @@ -1293,15 +1293,21 @@ finish_compaction (void) dict_compact_values (default_dict); } +/* Creates a case source with class CLASS and auxiliary data AUX + and based on dictionary DICT. */ struct case_source * -create_case_source (const struct case_source_class *class, void *aux) +create_case_source (const struct case_source_class *class, + const struct dictionary *dict, + void *aux) { struct case_source *source = xmalloc (sizeof *source); source->class = class; + source->value_cnt = dict_get_next_value_idx (dict); source->aux = aux; return source; } +/* Returns nonzero if a case source is "complex". */ int case_source_is_complex (const struct case_source *source) { @@ -1309,6 +1315,7 @@ case_source_is_complex (const struct case_source *source) || source->class == &file_type_source_class); } +/* Returns nonzero if CLASS is the class of SOURCE. */ int case_source_is_class (const struct case_source *source, const struct case_source_class *class) @@ -1316,6 +1323,8 @@ case_source_is_class (const struct case_source *source, return source != NULL && source->class == class; } +/* Creates a case sink with class CLASS and auxiliary data + AUX. */ struct case_sink * create_case_sink (const struct case_sink_class *class, void *aux) { @@ -1324,4 +1333,3 @@ create_case_sink (const struct case_sink_class *class, void *aux) sink->aux = aux; return sink; } - diff --git a/src/vfm.h b/src/vfm.h index 186dd6f1..06425b2c 100644 --- a/src/vfm.h +++ b/src/vfm.h @@ -25,9 +25,7 @@ /* This is the time at which vfm was last invoked. */ extern time_t last_vfm_invocation; -/* This is the case that is to be filled in by input programs. */ -extern struct ccase *temp_case; - +struct ccase; typedef struct write_case_data *write_case_data; typedef int write_case_func (write_case_data); @@ -38,7 +36,8 @@ extern struct case_source *vfm_source; struct case_source { const struct case_source_class *class; /* Class. */ - void *aux; /* Auxiliary data. */ + size_t value_cnt; /* Number of `union value's in case. */ + void *aux; /* Auxiliary data. */ }; /* A case source class. */ @@ -50,9 +49,11 @@ struct case_source_class 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); + /* Reads the cases one by one into C and for each one calls + WRITE_CASE passing the given AUX data. */ + void (*read) (struct case_source *, + struct ccase *c, + write_case_func *write_case, write_case_data aux); /* Destroys the source. */ void (*destroy) (struct case_source *); @@ -67,7 +68,9 @@ extern const struct case_source_class get_source_class; extern const struct case_source_class import_source_class; extern const struct case_source_class sort_source_class; +struct dictionary; struct case_source *create_case_source (const struct case_source_class *, + const struct dictionary *, void *); int case_source_is_complex (const struct case_source *); int case_source_is_class (const struct case_source *, @@ -95,7 +98,7 @@ struct case_sink_class void (*open) (struct case_sink *); /* Writes a case to the sink. */ - void (*write) (struct case_sink *, struct ccase *); + void (*write) (struct case_sink *, const struct ccase *); /* Closes and destroys the sink. */ void (*destroy) (struct case_sink *); @@ -115,18 +118,18 @@ struct case_sink *create_case_sink (const struct case_sink_class *, void *); /* Number of cases to lag. */ extern int n_lag; -void procedure (void (*beginfunc) (void *aux), - int (*procfunc) (struct ccase *curcase, void *aux), - void (*endfunc) (void *aux), +void procedure (void (*begin_func) (void *aux), + int (*proc_func) (struct ccase *, void *aux), + void (*end_func) (void *aux), void *aux); struct ccase *lagged_case (int n_before); void compact_case (struct ccase *dest, const struct ccase *src); void write_active_file_to_disk (void); -void process_active_file (void (*beginfunc) (void *), - int (*casefunc) (struct ccase *curcase, void *), - void (*endfunc) (void *), +void process_active_file (void (*begin_func) (void *), + int (*casefunc) (struct ccase *, void *), + void (*end_func) (void *), void *aux); -void process_active_file_output_case (void); +void process_active_file_output_case (const struct ccase *); #endif /* !vfm_h */ diff --git a/src/weight.c b/src/weight.c index 642a2b73..fd19f8c8 100644 --- a/src/weight.c +++ b/src/weight.c @@ -26,13 +26,6 @@ #include "str.h" #include "var.h" -/* Notes: - - If the weighting variable is deleted somehow (for instance by - end-of-scope of TEMPORARY), weighting must be canceled. - - Scratch vars may not be used for weighting. */ - /* WEIGHT transformation. */ struct weight_trns { -- 2.30.2