/* Variables. */
struct subcase by_vars; /* BY variables in this input file. */
struct subcase src, dst; /* Data to copy to output; where to put it. */
+ const struct missing_values **mv; /* Each variable's missing values. */
/* Input files. */
struct file_handle *handle; /* Input file handle. */
subcase_init_empty (&file->by_vars);
subcase_init_empty (&file->src);
subcase_init_empty (&file->dst);
+ file->mv = NULL;
file->handle = NULL;
file->dict = NULL;
file->reader = NULL;
size_t src_var_cnt = dict_get_var_cnt (file->dict);
size_t j;
+ file->mv = xnmalloc (src_var_cnt, sizeof *file->mv);
for (j = 0; j < src_var_cnt; j++)
{
struct variable *src_var = dict_get_var (file->dict, j);
var_get_name (src_var));
if (dst_var != NULL)
{
+ size_t n = subcase_get_n_fields (&file->src);
+ file->mv[n] = var_get_missing_values (src_var);
subcase_add_var (&file->src, src_var, SC_ASCEND);
subcase_add_var (&file->dst, dst_var, SC_ASCEND);
}
subcase_destroy (&file->by_vars);
subcase_destroy (&file->src);
subcase_destroy (&file->dst);
+ free (file->mv);
fh_unref (file->handle);
dict_destroy (file->dict);
casereader_destroy (file->reader);
static bool scan_table (struct comb_file *, union value by[]);
static struct ccase *create_output_case (const struct comb_proc *);
static void apply_case (const struct comb_file *, struct ccase *);
+static void apply_nonmissing_case (const struct comb_file *, struct ccase *);
static void advance_file (struct comb_file *, union value by[]);
static void output_case (struct comb_proc *, struct ccase *, union value by[]);
static void output_buffered_case (struct comb_proc *);
{
while (file->is_minimal)
{
- apply_case (file, output);
+ apply_nonmissing_case (file, output);
advance_file (file, by);
}
}
return output;
}
+static void
+mark_file_used (const struct comb_file *file, struct ccase *output)
+{
+ if (file->in_var != NULL)
+ case_data_rw (output, file->in_var)->f = true;
+}
+
/* Copies the data from FILE's case into output case OUTPUT.
If FILE has an IN variable, then it is set to 1 in OUTPUT. */
static void
apply_case (const struct comb_file *file, struct ccase *output)
{
subcase_copy (&file->src, file->data, &file->dst, output);
- if (file->in_var != NULL)
- case_data_rw (output, file->in_var)->f = true;
+ mark_file_used (file, output);
+}
+
+/* Copies the data from FILE's case into output case OUTPUT,
+ skipping values that are missing or all spaces.
+
+ If FILE has an IN variable, then it is set to 1 in OUTPUT. */
+static void
+apply_nonmissing_case (const struct comb_file *file, struct ccase *output)
+{
+ size_t i;
+
+ for (i = 0; i < subcase_get_n_fields (&file->src); i++)
+ {
+ const struct subcase_field *src_field = &file->src.fields[i];
+ const struct subcase_field *dst_field = &file->dst.fields[i];
+ const union value *src_value
+ = case_data_idx (file->data, src_field->case_index);
+ int width = src_field->width;
+
+ if (!mv_is_value_missing (file->mv[i], src_value, MV_ANY)
+ && !(width > 0 && value_is_spaces (src_value, width)))
+ value_copy (case_data_rw_idx (output, dst_field->case_index),
+ src_value, width);
+ }
+ mark_file_used (file, output);
}
/* Advances FILE to its next case. If BY is nonnull, then FILE's is_minimal