#include <unistd.h> /* Required by SunOS4. */
#endif
#include "alloc.h"
-#include "approx.h"
#include "do-ifP.h"
#include "error.h"
#include "expr.h"
/* This is used to read from the active file. */
struct case_stream *vfm_source;
-/* `value' indexes to initialize to particular values for certain cases. */
-struct long_vec reinit_sysmis; /* SYSMIS for every case. */
-struct long_vec reinit_blanks; /* Blanks for every case. */
-struct long_vec init_zero; /* Zero for first case only. */
-struct long_vec init_blanks; /* Blanks for first case only. */
-
/* This is used to write to the replacement active file. */
struct case_stream *vfm_sink;
/* Information about the data sink. */
struct stream_info vfm_sink_info;
-/* Filter variable and `value' index. */
-static struct variable *filter_var;
-static int filter_index;
-
-#define FILTERED \
- (filter_index != -1 \
- && (temp_case->data[filter_index].f == 0.0 \
- || temp_case->data[filter_index].f == SYSMIS \
- || is_num_user_missing (temp_case->data[filter_index].f, \
- filter_var)))
-
/* Nonzero if the case needs to have values deleted before being
stored, zero otherwise. */
int compaction_necessary;
static void finish_compaction (void);
static void lag_case (void);
static int procedure_write_case (struct write_case_data *);
+static void clear_temp_case (void);
+static int exclude_this_case (void);
\f
/* Public functions. */
/* Reads all the cases from the active file, transforms them by
the active set of transformations, calls PROCFUNC with CURCASE
- set to the case , and writes them to a new active file.
+ set to the case, and writes them to a new active file.
Divides the active file into zero or more series of one or more
cases each. BEGINFUNC is called before each series. ENDFUNC is
void (*endfunc) (void *),
void *aux)
{
+ static int recursive_call;
+
struct write_case_data procedure_write_data;
struct write_case_data split_file_data;
+ assert (++recursive_call == 1);
+
if (dict_get_split_cnt (default_dict) == 0)
{
/* Normally we just use the data passed by the user. */
open_active_file ();
vfm_source->read (procedure_write_case, &procedure_write_data);
close_active_file (&procedure_write_data);
+
+ assert (--recursive_call == 0);
}
\f
/* Active file processing support. Subtly different semantics from
lag_case ();
/* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
- if (not_canceled
- && !FILTERED
- && (process_if_expr == NULL ||
- expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
+ if (not_canceled && !exclude_this_case ())
not_canceled = data->procfunc (temp_case, data->aux);
case_count++;
done:
- {
- long *lp;
+ clear_temp_case ();
- /* This case is finished. Initialize the variables for the next case. */
- for (lp = reinit_sysmis.vec; *lp != -1;)
- temp_case->data[*lp++].f = SYSMIS;
- for (lp = reinit_blanks.vec; *lp != -1;)
- memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING);
- }
-
return 1;
}
file--it's just a waste of time and space. */
vfm_sink_info.ncases = 0;
- vfm_sink_info.nval = dict_get_value_cnt (default_dict);
- vfm_sink_info.case_size = (sizeof (struct ccase)
- + ((dict_get_value_cnt (default_dict) - 1)
- * sizeof (union value)));
+ vfm_sink_info.nval = dict_get_next_value_idx (default_dict);
+ vfm_sink_info.case_size = dict_get_case_size (default_dict);
if (vfm_sink == NULL)
{
count_values += v->nv;
}
}
- assert (temporary == 2 || count_values <= dict_get_value_cnt (temp_dict));
+ assert (temporary == 2
+ || count_values <= dict_get_next_value_idx (temp_dict));
}
/* Compaction is only necessary if the number of `value's to output
differs from the number already present. */
compaction_nval = count_values;
- compaction_necessary = (temporary == 2
- || count_values != dict_get_value_cnt (temp_dict));
+ if (temporary == 2 || count_values != dict_get_next_value_idx (temp_dict))
+ compaction_necessary = 1;
+ else
+ compaction_necessary = 0;
if (vfm_sink->init)
vfm_sink->init ();
}
#endif
-/* Initializes temp_case from the vectors that say which `value's need
- to be initialized just once, and which ones need to be
+/* 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)
{
- int i;
- long *lp;
-
- /* Just once. */
- for (i = 0; i < init_zero.n; i++)
- temp_case->data[init_zero.vec[i]].f = 0.0;
- for (i = 0; i < init_blanks.n; i++)
- memset (temp_case->data[init_blanks.vec[i]].s, ' ', MAX_SHORT_STRING);
-
- /* These vectors need to be repeatedly accessed, so we add a
- sentinel to (hopefully) improve speed. */
- vec_insert (&reinit_sysmis, -1);
- vec_insert (&reinit_blanks, -1);
-
- for (lp = reinit_sysmis.vec; *lp != -1;)
- temp_case->data[*lp++].f = SYSMIS;
- for (lp = reinit_blanks.vec; *lp != -1;)
- memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING);
-
-#if DEBUGGING
- printf ("vfm: init_zero=");
- for (i = 0; i < init_zero.n; i++)
- printf ("%s%s", i ? "," : "", index_to_varname (init_zero.vec[i]));
- printf (" init_blanks=");
- for (i = 0; i < init_blanks.n; i++)
- printf ("%s%s", i ? "," : "", index_to_varname (init_blanks.vec[i]));
- printf (" reinit_sysmis=");
- for (lp = reinit_sysmis.vec; *lp != -1; lp++)
- printf ("%s%s", lp != reinit_sysmis.vec ? "," : "",
- index_to_varname (*lp));
- printf (" reinit_blanks=");
- for (lp = reinit_blanks.vec; *lp != -1; lp++)
- printf ("%s%s", lp != reinit_blanks.vec ? "," : "",
- index_to_varname (*lp));
- printf ("\n");
-#endif
-}
-
-/* Sets filter_index to an appropriate value. */
-static void
-setup_filter (void)
-{
- filter_var = dict_get_filter (default_dict);
+ size_t var_cnt = dict_get_var_cnt (default_dict);
+ size_t i;
- if (filter_var != NULL)
+ for (i = 0; i < var_cnt; i++)
{
- assert (filter_var->type == NUMERIC);
- filter_index = filter_var->index;
- } else {
- filter_index = -1;
+ 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);
}
}
lag_head = 0;
lag_queue = xmalloc (n_lag * sizeof *lag_queue);
for (i = 0; i < n_lag; i++)
- lag_queue[i] = xmalloc (dict_get_value_cnt (temp_dict)
- * sizeof **lag_queue);
+ lag_queue[i] = xmalloc (dict_get_case_size (temp_dict));
}
/* There is a lot of potential confusion in the vfm and related
make_temp_case ();
vector_initialization ();
discard_ctl_stack ();
- setup_filter ();
setup_lag ();
/* Debug output. */
process_if_expr = NULL;
/* Cancel FILTER if temporary. */
- if (filter_var != NULL && !FILTER_before_TEMPORARY)
+ if (dict_get_filter (default_dict) != NULL && !FILTER_before_TEMPORARY)
dict_set_filter (default_dict, NULL);
/* Cancel transformations. */
cancel_transformations ();
- /* Clear value-initialization vectors. */
- vec_clear (&init_zero);
- vec_clear (&init_blanks);
- vec_clear (&reinit_sysmis);
- vec_clear (&reinit_blanks);
-
/* Turn off case limiter. */
dict_set_case_limit (default_dict, 0);
if (lag_count < n_lag)
lag_count++;
memcpy (lag_queue[lag_head], temp_case,
- sizeof (union value) * dict_get_value_cnt (temp_dict));
+ dict_get_case_size (temp_dict));
if (++lag_head >= n_lag)
lag_head = 0;
}
/* Call the procedure if there is one and FILTER and PROCESS IF
don't prohibit it. */
- if (wc_data->procfunc != NULL
- && !FILTERED
- && (process_if_expr == NULL ||
- expr_evaluate (process_if_expr, temp_case, NULL) == 1.0))
+ if (wc_data->procfunc != NULL && !exclude_this_case ())
wc_data->procfunc (temp_case, wc_data->aux);
case_count++;
done:
debug_putc ('\n', stdout);
-
- {
- long *lp;
- /* This case is finished. Initialize the variables for the next case. */
- for (lp = reinit_sysmis.vec; *lp != -1;)
- temp_case->data[*lp++].f = SYSMIS;
- for (lp = reinit_blanks.vec; *lp != -1;)
- memset (temp_case->data[*lp++].s, ' ', MAX_SHORT_STRING);
- }
+ clear_temp_case ();
/* Return previously determined value. */
return more_cases;
}
+/* Clears the variables in the temporary case that need to be
+ cleared between processing cases. */
+static void
+clear_temp_case (void)
+{
+ /* FIXME? This is linear in the number of variables, but
+ doesn't need to be, so it's an easy optimization target. */
+ 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->init && v->reinit)
+ {
+ if (v->type == NUMERIC)
+ temp_case->data[v->fv].f = SYSMIS;
+ else
+ memset (temp_case->data[v->fv].s, ' ', v->width);
+ }
+ }
+}
+
+/* Returns nonzero if this case should be exclude as specified on
+ FILTER or PROCESS IF, otherwise zero. */
+static int
+exclude_this_case (void)
+{
+ /* FILTER. */
+ struct variable *filter_var = dict_get_filter (default_dict);
+ if (filter_var != NULL)
+ {
+ double f = temp_case->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, NULL) != 1.0)
+ return 1;
+
+ return 0;
+}
+
/* Appends TRNS to t_trns[], the list of all transformations to be
performed on data as it is read from the active file. */
void
assert (v->type == NUMERIC || v->type == ALPHA);
tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name);
- {
- union value val = c->data[v->fv];
- if (v->type == ALPHA)
- val.c = c->data[v->fv].s;
- data_out (temp_buf, &v->print, &val);
- }
+ data_out (temp_buf, &v->print, &c->data[v->fv]);
temp_buf[v->print.w] = 0;
tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf);
switch (v->type)
{
case NUMERIC:
- if (approx_ne (c->data[v->fv].f, prev_case->data[v->fv].f))
+ if (c->data[v->fv].f != prev_case->data[v->fv].f)
goto not_equal;
break;
case ALPHA: