You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include <config.h>
#include "vfm.h"
#include "alloc.h"
#include "case.h"
#include "casefile.h"
+#include "command.h"
#include "dictionary.h"
-#include "do-ifP.h"
+#include "ctl-stack.h"
#include "error.h"
#include "expressions/public.h"
#include "misc.h"
#include "var.h"
#include "value-labels.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
/*
Virtual File Manager (vfm):
static int compaction_necessary;
/* Time at which vfm was last invoked. */
-time_t last_vfm_invocation;
+static time_t last_vfm_invocation;
/* Lag queue. */
int n_lag; /* Number of cases to lag. */
static void internal_procedure (int (*proc_func) (struct ccase *, void *),
void *aux);
+static void update_last_vfm_invocation (void);
static void create_trns_case (struct ccase *, struct dictionary *);
static void open_active_file (void);
static int write_case (struct write_case_data *wc_data);
static int execute_transformations (struct ccase *c,
- struct trns_header **trns,
+ struct transformation *trns,
int first_idx, int last_idx,
int case_num);
static int filter_case (const struct ccase *c, int case_num);
static void lag_case (const struct ccase *c);
-static void compact_case (struct ccase *dest, const struct ccase *src);
static void clear_case (struct ccase *c);
static void close_active_file (void);
\f
/* Public functions. */
+/* Returns the last time the data was read. */
+time_t
+vfm_last_invocation (void)
+{
+ if (last_vfm_invocation == 0)
+ update_last_vfm_invocation ();
+ return last_vfm_invocation;
+}
+
/* Reads the data from the input program and writes it to a new
active file. For each case we read from the input program, we
do the following
&& n_trns == 0)
{
/* Nothing to do. */
+ update_last_vfm_invocation ();
return;
}
case_create (&wc_data.sink_case, dict_get_next_value_idx (default_dict));
wc_data.cases_written = 0;
- last_vfm_invocation = time (NULL);
+ update_last_vfm_invocation ();
if (vfm_source != NULL)
vfm_source->class->read (vfm_source,
assert (--recursive_call == 0);
}
+/* Updates last_vfm_invocation. */
+static void
+update_last_vfm_invocation (void)
+{
+ last_vfm_invocation = time (NULL);
+}
+
/* 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. */
lag_count = 0;
lag_head = 0;
- lag_queue = xmalloc (n_lag * sizeof *lag_queue);
+ lag_queue = xnmalloc (n_lag, sizeof *lag_queue);
for (i = 0; i < n_lag; i++)
case_nullify (&lag_queue[i]);
}
/* Close any unclosed DO IF or LOOP constructs. */
- discard_ctl_stack ();
+ ctl_stack_clear ();
}
/* Transforms trns_case and writes it to the replacement active
{
if (compaction_necessary)
{
- compact_case (&wc_data->sink_case, &wc_data->trns_case);
+ dict_compact_case (temp_dict, &wc_data->sink_case,
+ &wc_data->trns_case);
vfm_sink->class->write (vfm_sink, &wc_data->sink_case);
}
else
transformations, nonzero otherwise. */
static int
execute_transformations (struct ccase *c,
- struct trns_header **trns,
+ struct transformation *trns,
int first_idx, int last_idx,
int case_num)
{
for (idx = first_idx; idx != last_idx; )
{
- int retval = trns[idx]->proc (trns[idx], c, case_num);
+ struct transformation *t = &trns[idx];
+ int retval = t->proc (t->private, c, case_num);
switch (retval)
{
case -1:
if (filter_var != NULL)
{
double f = case_num (c, filter_var->fv);
- if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var))
+ if (f == 0.0 || mv_is_num_missing (&filter_var->miss, f))
return 1;
}
lag_head = 0;
}
-/* Copies case SRC to case DEST, compacting it in the process. */
-static void
-compact_case (struct ccase *dest, const struct ccase *src)
-{
- int i;
- int nval = 0;
- size_t var_cnt;
-
- assert (compaction_necessary);
-
- /* Copy all the variables except scratch variables from SRC to
- DEST. */
- /* FIXME: this should be temp_dict not default_dict I guess. */
- var_cnt = dict_get_var_cnt (default_dict);
- for (i = 0; i < var_cnt; i++)
- {
- struct variable *v = dict_get_var (default_dict, i);
-
- if (dict_class_from_id (v->name) == DC_SCRATCH)
- continue;
-
- if (v->type == NUMERIC)
- {
- case_data_rw (dest, nval)->f = case_num (src, v->fv);
- nval++;
- }
- else
- {
- int w = DIV_RND_UP (v->width, sizeof (union value));
-
- memcpy (case_data_rw (dest, nval), case_str (src, v->fv),
- w * sizeof (union value));
- nval += w;
- }
- }
-}
-
/* Clears the variables in C that need to be cleared between
processing cases. */
static void
dict_compact_values (default_dict);
/* Free data source. */
- if (vfm_source != NULL)
- {
- free_case_source (vfm_source);
- vfm_source = NULL;
- }
+ free_case_source (vfm_source);
+ vfm_source = NULL;
/* Old data sink becomes new data source. */
if (vfm_sink->class->make_source != NULL)
storage_sink_make_source (struct case_sink *sink)
{
struct case_source *source
- = create_case_source (&storage_source_class, sink->dict, sink->aux);
+ = create_case_source (&storage_source_class, sink->aux);
sink->aux = NULL;
return source;
}
}
struct case_source *
-storage_source_create (struct casefile *cf, const struct dictionary *dict)
+storage_source_create (struct casefile *cf)
{
struct storage_stream_info *info;
info = xmalloc (sizeof *info);
info->casefile = cf;
- return create_case_source (&storage_source_class, dict, info);
+ return create_case_source (&storage_source_class, info);
}
\f
/* Null sink. Used by a few procedures that keep track of output
struct ccase *
lagged_case (int n_before)
{
- assert (n_before >= 1 && n_before <= n_lag);
+ assert (n_before >= 1 );
+ assert (n_before <= n_lag);
+
if (n_before <= lag_count)
{
int index = lag_head - n_before;
/* Appends TRNS to t_trns[], the list of all transformations to be
performed on data as it is read from the active file. */
void
-add_transformation (struct trns_header * trns)
+add_transformation (trns_proc_func *proc, trns_free_func *free, void *private)
{
+ struct transformation *trns;
if (n_trns >= m_trns)
- {
- m_trns += 16;
- t_trns = xrealloc (t_trns, sizeof *t_trns * m_trns);
- }
- t_trns[n_trns] = trns;
- trns->index = n_trns++;
+ t_trns = x2nrealloc (t_trns, &m_trns, sizeof *t_trns);
+ trns = &t_trns[n_trns++];
+ trns->proc = proc;
+ trns->free = free;
+ trns->private = private;
+}
+
+/* Returns the index number that the next transformation added by
+ add_transformation() will receive. A trns_proc_func that
+ returns this index causes control flow to jump to it. */
+size_t
+next_transformation (void)
+{
+ return n_trns;
}
/* Cancels all active transformations, including any transformations
void
cancel_transformations (void)
{
- int i;
+ size_t i;
for (i = 0; i < n_trns; i++)
{
- if (t_trns[i]->free)
- t_trns[i]->free (t_trns[i]);
- free (t_trns[i]);
+ struct transformation *t = &t_trns[i];
+ if (t->free != NULL)
+ t->free (t->private);
}
n_trns = f_trns = 0;
free (t_trns);
- t_trns=NULL;
+ t_trns = NULL;
m_trns = 0;
}
\f
and based on dictionary DICT. */
struct case_source *
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;
}
return source != NULL && source->class == class;
}
-/* Creates a case sink with class CLASS and auxiliary data
- AUX. */
+/* Creates a case sink to accept cases from the given DICT with
+ class CLASS and auxiliary data AUX. */
struct case_sink *
create_case_sink (const struct case_sink_class *class,
const struct dictionary *dict,
{
struct case_sink *sink = xmalloc (sizeof *sink);
sink->class = class;
- sink->dict = dict;
- sink->idx_to_fv = dict_get_compacted_idx_to_fv (dict);
sink->value_cnt = dict_get_compacted_value_cnt (dict);
sink->aux = aux;
return sink;
{
if (sink->class->destroy != NULL)
sink->class->destroy (sink);
- free (sink->idx_to_fv);
free (sink);
}
}
split_aux.end_func = end_func;
split_aux.func_aux = func_aux;
- procedure (procedure_with_splits_callback, &split_aux);
-
+ open_active_file ();
+ internal_procedure (procedure_with_splits_callback, &split_aux);
if (split_aux.case_count > 0 && end_func != NULL)
end_func (func_aux);
+ close_active_file ();
+
case_destroy (&split_aux.prev_case);
}
static int
equal_splits (const struct ccase *a, const struct ccase *b)
{
- struct variable *const *split;
- size_t split_cnt;
- size_t i;
-
- split = dict_get_split_vars (default_dict);
- split_cnt = dict_get_split_cnt (default_dict);
- for (i = 0; i < split_cnt; i++)
- {
- struct variable *v = split[i];
-
- switch (v->type)
- {
- case NUMERIC:
- if (case_num (a, v->fv) != case_num (b, v->fv))
- return 0;
- break;
- case ALPHA:
- if (memcmp (case_str (a, v->fv), case_str (b, v->fv), v->width))
- return 0;
- break;
- default:
- assert (0);
- }
- }
-
- return 1;
+ return case_compare (a, b,
+ dict_get_split_vars (default_dict),
+ dict_get_split_cnt (default_dict)) == 0;
}
/* Dumps out the values of all the split variables for the case C. */
casefile_destroy (aux->casefile);
aux->casefile = NULL;
}
+
+
+/* Discards all the current state in preparation for a data-input
+ command like DATA LIST or GET. */
+void
+discard_variables (void)
+{
+ dict_clear (default_dict);
+ default_handle = NULL;
+
+ n_lag = 0;
+
+ if (vfm_source != NULL)
+ {
+ free_case_source (vfm_source);
+ vfm_source = NULL;
+ }
+
+ cancel_transformations ();
+
+ ctl_stack_clear ();
+
+ expr_free (process_if_expr);
+ process_if_expr = NULL;
+
+ cancel_temporary ();
+
+ pgm_state = STATE_INIT;
+}