02111-1307, USA. */
#include <config.h>
-#include <assert.h>
+#include "error.h"
#include <stdlib.h>
#include "alloc.h"
+#include "case.h"
#include "command.h"
#include "error.h"
#include "file-handle.h"
#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
{
static int trim_dictionary (struct dictionary * dict, int *options);
static int save_write_case_func (struct ccase *, void *);
-static int save_trns_proc (struct trns_header *, struct ccase *);
-static void save_trns_free (struct trns_header *);
-
-#if DEBUGGING
-void dump_dict_variables (struct dictionary *);
-#endif
+static trns_proc_func save_trns_proc;
+static trns_free_func save_trns_free;
/* Parses the GET command. */
int
{
struct file_handle *handle;
struct dictionary *dict;
+ struct get_pgm *pgm;
int options = GTSV_OPT_NONE;
- lex_match_id ("GET");
discard_variables ();
lex_match ('/');
if (dict == NULL)
return CMD_FAILURE;
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
if (0 == trim_dictionary (dict, &options))
{
fh_close_handle (handle);
return CMD_FAILURE;
}
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
dict_compact_values (dict);
-#if DEBUGGING
- printf (_("GET translation table from file to memory:\n"));
- for (i = 0; i < dict->nvar; i++)
- {
- struct variable *v = dict->var[i];
-
- printf (_(" %8s from %3d,%3d to %3d,%3d\n"), v->name,
- v->get.fv, v->get.nv, v->fv, v->nv);
- }
-#endif
-
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;
}
int i;
- lex_match_id ("SAVE");
-
lex_match ('/');
if (lex_match_id ("OUTFILE"))
lex_match ('=');
return CMD_FAILURE;
dict = dict_clone (default_dict);
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
for (i = 0; i < dict_get_var_cnt (dict); i++)
dict_get_var (dict, i)->aux = dict_get_var (default_dict, i);
if (0 == trim_dictionary (dict, &options))
return CMD_FAILURE;
}
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
-
/* Write dictionary. */
inf.h = handle;
inf.dict = dict;
if (save_cmd == CMD_SAVE)
{
- procedure (NULL, save_write_case_func, NULL, t);
+ procedure (save_write_case_func, t);
save_trns_free (&t->h);
}
else
struct variable *v = t->var[i];
if (v->type == NUMERIC)
{
- double src = c->data[v->fv].f;
+ double src = case_num (c, v->fv);
if (src == SYSMIS)
*p++ = -FLT64_MAX;
else
}
else
{
- memcpy (p, c->data[v->fv].s, v->width);
+ memcpy (p, case_str (c, v->fv), v->width);
memset (&((char *) p)[v->width], ' ',
REM_RND_UP (v->width, sizeof *p));
p += DIV_RND_UP (v->width, sizeof *p);
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)
+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)
{
static int
trim_dictionary (struct dictionary *dict, int *options)
{
- if (set_scompression)
+ if (get_scompression())
*options |= GTSV_OPT_COMPRESSED;
if (*options & GTSV_OPT_SAVE)
v = xmalloc (sizeof *v * dict_get_var_cnt (dict));
nv = 0;
for (i = 0; i < dict_get_var_cnt (dict); i++)
- if (dict_get_var (dict, i)->name[0] == '#')
+ if (dict_class_from_id (dict_get_var (dict, i)->name) == DC_SCRATCH)
v[nv++] = dict_get_var (dict, i);
dict_delete_vars (dict, v, nv);
free (v);
return success;
}
-
-#if DEBUGGING
-void
-dump_dict_variables (struct dictionary * dict)
-{
- int i;
-
- printf (_("\nVariables in dictionary:\n"));
- for (i = 0; i < dict->nvar; i++)
- printf ("%s, ", dict->var[i]->name);
- printf ("\n");
-}
-#endif
\f
/* Clears internal state related to GET input procedure. */
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, default_dict)
&& write_case (wc_data))
;
}
const struct case_source_class get_source_class =
{
"GET",
+ NULL,
get_source_read,
get_source_destroy,
};
struct dictionary *dict; /* Dictionary from system file. */
char in[9]; /* Name of the variable from IN=. */
char first[9], last[9]; /* Name of the variables from FIRST=, LAST=. */
- union value *input; /* Input record. */
+ struct ccase input; /* Input record. */
};
-/* All the files mentioned on FILE or TABLE. */
-static struct mtf_file *mtf_head, *mtf_tail;
-
-/* Variables on the BY subcommand. */
-static struct variable **mtf_by;
-static int mtf_n_by;
-
-/* Master dictionary. */
-static struct dictionary *mtf_master;
+/* MATCH FILES procedure. */
+struct mtf_proc
+ {
+ struct mtf_file *head; /* First file mentioned on FILE or TABLE. */
+ struct mtf_file *tail; /* Last file mentioned on FILE or TABLE. */
+
+ struct variable **by; /* Variables on the BY subcommand. */
+ size_t by_cnt; /* Number of variables on BY subcommand. */
-/* Used to determine whether we've already initialized this
- variable. */
-static unsigned mtf_seq_num;
+ struct dictionary *dict; /* Dictionary of output file. */
+ struct case_sink *sink; /* Sink to receive output. */
+ struct ccase *mtf_case; /* Case used for output. */
-/* Sequence numbers for each variable in mtf_master. */
-static unsigned *mtf_seq_nums;
+ unsigned seq_num; /* Have we initialized this variable? */
+ unsigned *seq_nums; /* Sequence numbers for each var in dict. */
+ };
-static void mtf_free (void);
-static void mtf_free_file (struct mtf_file *file);
-static int mtf_merge_dictionary (struct mtf_file *f);
-static void mtf_delete_file_in_place (struct mtf_file **file);
+static void mtf_free (struct mtf_proc *);
+static void mtf_free_file (struct mtf_file *);
+static int mtf_merge_dictionary (struct dictionary *const, struct mtf_file *);
+static void mtf_delete_file_in_place (struct mtf_proc *, struct mtf_file **);
static void mtf_read_nonactive_records (void *);
static void mtf_processing_finish (void *);
int
cmd_match_files (void)
{
+ struct mtf_proc mtf;
struct mtf_file *first_table = NULL;
int seen = 0;
- lex_match_id ("MATCH");
- lex_match_id ("FILES");
-
- mtf_head = mtf_tail = NULL;
- mtf_by = NULL;
- mtf_n_by = 0;
- mtf_master = dict_create ();
- mtf_seq_num = 0;
- mtf_seq_nums = NULL;
- dict_set_case_limit (mtf_master, dict_get_case_limit (default_dict));
+ mtf.head = mtf.tail = NULL;
+ mtf.by = NULL;
+ mtf.by_cnt = 0;
+ mtf.dict = dict_create ();
+ mtf.sink = NULL;
+ mtf.mtf_case = NULL;
+ mtf.seq_num = 0;
+ mtf.seq_nums = NULL;
+ dict_set_case_limit (mtf.dict, dict_get_case_limit (default_dict));
do
{
seen |= 1;
lex_match ('=');
- if (!parse_variables (mtf_master, &mtf_by, &mtf_n_by,
+ if (!parse_variables (mtf.dict, &mtf.by, &mtf.by_cnt,
PV_NO_DUPLICATE | PV_NO_SCRATCH))
goto lossage;
}
file->in[0] = file->first[0] = file->last[0] = '\0';
file->dict = NULL;
file->by = NULL;
- file->input = NULL;
+ case_nullify (&file->input);
if (lex_match_id ("FILE"))
file->type = MTF_FILE;
if (file->type == MTF_TABLE || first_table == NULL)
{
file->next = NULL;
- file->prev = mtf_tail;
- if (mtf_tail)
- mtf_tail->next = file;
- mtf_tail = file;
- if (mtf_head == NULL)
- mtf_head = file;
+ file->prev = mtf.tail;
+ if (mtf.tail)
+ mtf.tail->next = file;
+ mtf.tail = file;
+ if (mtf.head == NULL)
+ mtf.head = file;
if (file->type == MTF_TABLE && first_table == NULL)
first_table = file;
}
if (first_table->prev)
first_table->prev->next = file;
else
- mtf_head = file;
+ mtf.head = file;
first_table->prev = file;
}
"file has been defined."));
goto lossage;
}
+
+ if (temporary != 0)
+ {
+ msg (SE,
+ _("MATCH FILES may not be used after TEMPORARY when "
+ "the active file is an input source. "
+ "Temporary transformations will be made permanent."));
+ cancel_temporary ();
+ }
}
else
{
file->dict = sfm_read_dictionary (file->handle, NULL);
if (!file->dict)
goto lossage;
+ case_create (&file->input, dict_get_next_value_idx (file->dict));
}
else
file->dict = default_dict;
- if (!mtf_merge_dictionary (file))
+ if (!mtf_merge_dictionary (mtf.dict, file))
goto lossage;
}
else if (lex_id_match ("IN", tokid)
const char *sbc;
char *name;
- if (mtf_tail == NULL)
+ if (mtf.tail == NULL)
{
msg (SE, _("IN, FIRST, and LAST subcommands may not occur "
"before the first FILE or TABLE."));
if (lex_match_id ("IN"))
{
- name = mtf_tail->in;
+ name = mtf.tail->in;
sbc = "IN";
}
else if (lex_match_id ("FIRST"))
{
- name = mtf_tail->first;
+ name = mtf.tail->first;
sbc = "FIRST";
}
else if (lex_match_id ("LAST"))
{
- name = mtf_tail->last;
+ name = mtf.tail->last;
sbc = "LAST";
}
- else
- assert (0);
+ else
+ {
+ assert (0);
+ abort ();
+ }
lex_match ('=');
if (token != T_ID)
strcpy (name, tokid);
lex_get ();
- if (!dict_create_var (mtf_master, name, 0))
+ if (!dict_create_var (mtf.dict, name, 0))
{
msg (SE, _("Duplicate variable name %s while creating %s "
"variable."),
{
int options = GTSV_OPT_MATCH_FILES;
- if (mtf_tail == NULL)
+ if (mtf.tail == NULL)
{
msg (SE, _("RENAME, KEEP, and DROP subcommands may not occur "
"before the first FILE or TABLE."));
goto lossage;
}
- if (!trim_dictionary (mtf_tail->dict, &options))
+ if (!trim_dictionary (mtf.tail->dict, &options))
goto lossage;
}
else if (lex_match_id ("MAP"))
{
struct mtf_file *iter;
- for (iter = mtf_head; iter; iter = iter->next)
+ for (iter = mtf.head; iter; iter = iter->next)
{
int i;
- iter->by = xmalloc (sizeof *iter->by * mtf_n_by);
+ iter->by = xmalloc (sizeof *iter->by * mtf.by_cnt);
- for (i = 0; i < mtf_n_by; i++)
+ for (i = 0; i < mtf.by_cnt; i++)
{
- iter->by[i] = dict_lookup_var (iter->dict, mtf_by[i]->name);
+ iter->by[i] = dict_lookup_var (iter->dict, mtf.by[i]->name);
if (iter->by[i] == NULL)
{
msg (SE, _("File %s lacks BY variable %s."),
- iter->handle ? fh_handle_name (iter->handle) : "*",
- mtf_by[i]->name);
+ iter->handle ? handle_get_name (iter->handle) : "*",
+ mtf.by[i]->name);
goto lossage;
}
}
}
}
-#if DEBUGGING
- {
- /* From sfm-read.c. */
- extern void dump_dictionary (struct dictionary *);
-
- dump_dictionary (mtf_master);
- }
-#endif
-
/* MATCH FILES performs an n-way merge on all its input files.
Abstract algorithm:
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 ();
- temporary = 2;
- temp_dict = mtf_master;
- temp_trns = n_trns;
+ mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);
- mtf_seq_nums = xmalloc (dict_get_var_cnt (mtf_master)
- * sizeof *mtf_seq_nums);
- memset (mtf_seq_nums, 0,
- dict_get_var_cnt (mtf_master) * sizeof *mtf_seq_nums);
+ mtf.seq_nums = xmalloc (dict_get_var_cnt (mtf.dict)
+ * sizeof *mtf.seq_nums);
+ memset (mtf.seq_nums, 0,
+ dict_get_var_cnt (mtf.dict) * sizeof *mtf.seq_nums);
+ mtf.mtf_case = xmalloc (dict_get_case_size (mtf.dict));
- process_active_file (mtf_read_nonactive_records, mtf_processing,
- mtf_processing_finish, NULL);
- mtf_master = NULL;
+ mtf_read_nonactive_records (NULL);
+ if (seen & 2)
+ procedure (mtf_processing, NULL);
+ mtf_processing_finish (NULL);
+
+ dict_destroy (default_dict);
+ default_dict = mtf.dict;
+ mtf.dict = NULL;
+ vfm_source = mtf.sink->class->make_source (mtf.sink);
+ free_case_sink (mtf.sink);
- mtf_free ();
+ mtf_free (&mtf);
return CMD_SUCCESS;
lossage:
- mtf_free ();
+ mtf_free (&mtf);
return CMD_FAILURE;
}
/* Repeats 2...8 an arbitrary number of times. */
static void
-mtf_processing_finish (void *aux UNUSED)
+mtf_processing_finish (void *mtf_)
{
+ struct mtf_proc *mtf = mtf_;
+ struct mtf_file *iter;
+
/* Find the active file and delete it. */
- {
- struct mtf_file *iter;
-
- for (iter = mtf_head; iter; iter = iter->next)
- if (iter->handle == NULL)
- {
- mtf_delete_file_in_place (&iter);
- break;
- }
- }
+ for (iter = mtf->head; iter; iter = iter->next)
+ if (iter->handle == NULL)
+ {
+ mtf_delete_file_in_place (mtf, &iter);
+ break;
+ }
- while (mtf_head && mtf_head->type == MTF_FILE)
- if (!mtf_processing (temp_case, NULL))
+ while (mtf->head && mtf->head->type == MTF_FILE)
+ if (!mtf_processing (NULL, mtf))
break;
}
dict_destroy (file->dict);
free (file->by);
if (file->handle)
- free (file->input);
+ case_destroy (&file->input);
free (file);
}
/* Free all the data for the MATCH FILES procedure. */
static void
-mtf_free (void)
+mtf_free (struct mtf_proc *mtf)
{
struct mtf_file *iter, *next;
- for (iter = mtf_head; iter; iter = next)
+ for (iter = mtf->head; iter; iter = next)
{
next = iter->next;
mtf_free_file (iter);
}
- free (mtf_by);
- if (mtf_master)
- dict_destroy (mtf_master);
- free (mtf_seq_nums);
+ free (mtf->by);
+ if (mtf->dict)
+ dict_destroy (mtf->dict);
+ free (mtf->seq_nums);
}
/* Remove *FILE from the mtf_file chain. Make *FILE point to the next
file in the chain, or to NULL if was the last in the chain. */
static void
-mtf_delete_file_in_place (struct mtf_file **file)
+mtf_delete_file_in_place (struct mtf_proc *mtf, struct mtf_file **file)
{
struct mtf_file *f = *file;
f->prev->next = f->next;
if (f->next)
f->next->prev = f->prev;
- if (f == mtf_head)
- mtf_head = f->next;
- if (f == mtf_tail)
- mtf_tail = f->prev;
+ if (f == mtf->head)
+ mtf->head = f->next;
+ if (f == mtf->tail)
+ mtf->tail = f->prev;
*file = f->next;
{
for (i = 0; i < dict_get_var_cnt (f->dict); i++)
{
struct variable *v = dict_get_var (f->dict, i);
+ union value *out = case_data_rw (mtf->mtf_case, v->p.mtf.master->fv);
if (v->type == NUMERIC)
- compaction_case->data[v->p.mtf.master->fv].f = SYSMIS;
+ out->f = SYSMIS;
else
- memset (compaction_case->data[v->p.mtf.master->fv].s, ' ',
- v->width);
+ memset (out->s, ' ', v->width);
}
}
-
+
mtf_free_file (f);
}
/* Read a record from every input file except the active file. */
static void
-mtf_read_nonactive_records (void *aux UNUSED)
+mtf_read_nonactive_records (void *mtf_ UNUSED)
{
+ struct mtf_proc *mtf = mtf_;
struct mtf_file *iter;
- for (iter = mtf_head; iter; )
+ for (iter = mtf->head; iter; )
{
if (iter->handle)
{
- assert (iter->input == NULL);
- iter->input = xmalloc (dict_get_case_size (iter->dict));
-
- if (!sfm_read_case (iter->handle, iter->input, iter->dict))
- mtf_delete_file_in_place (&iter);
+ if (!sfm_read_case (iter->handle, &iter->input, iter->dict))
+ mtf_delete_file_in_place (mtf, &iter);
else
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_proc *mtf,
+ struct mtf_file *a, struct mtf_file *b,
+ struct ccase *c)
{
+ struct ccase *a_input, *b_input;
int i;
-
- for (i = 0; i < mtf_n_by; i++)
+
+ assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
+ a_input = case_is_null (&a->input) ? c : &a->input;
+ b_input = case_is_null (&b->input) ? c : &b->input;
+ for (i = 0; i < mtf->by_cnt; i++)
{
assert (a->by[i]->type == b->by[i]->type);
assert (a->by[i]->width == b->by[i]->width);
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 = case_num (a_input, a->by[i]->fv);
+ double bf = case_num (b_input, b->by[i]->fv);
if (af < bf)
return -1;
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 (case_str (a_input, a->by[i]->fv),
+ case_str (b_input, b->by[i]->fv),
a->by[i]->width);
if (result < 0)
return -1;
/* 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 *mtf_ UNUSED)
{
- /* List of files with minimum BY values. */
- struct mtf_file *min_head, *min_tail;
-
- /* List of files with non-minimum BY values. */
- struct mtf_file *max_head, *max_tail;
-
- /* Iterator. */
- struct mtf_file *iter;
+ struct mtf_proc *mtf = mtf_;
+ struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
+ struct mtf_file *max_head, *max_tail; /* Files with non-minimum BY values. */
+ struct mtf_file *iter; /* Iterator. */
for (;;)
{
return because that would cause a record to be skipped. */
int advance = 1;
- if (mtf_head->type == MTF_TABLE)
+ if (mtf->head->type == MTF_TABLE)
return 0;
/* 3. Find the FILE input record with minimum BY values. Store
4. Find all the FILE input records with BY values identical
to the minimums. Store all the values from these input
records into the output record. */
- min_head = min_tail = mtf_head;
+ min_head = min_tail = mtf->head;
max_head = max_tail = NULL;
- for (iter = mtf_head->next; iter && iter->type == MTF_FILE;
+ 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 (mtf, min_head, iter, c))
{
case -1:
if (max_head)
advance = 0;
again:
- switch (mtf_compare_BY_values (min_head, iter))
+ switch (mtf_compare_BY_values (mtf, min_head, iter, c))
{
case -1:
if (max_head)
case 1:
if (iter->handle == NULL)
return 1;
- if (sfm_read_case (iter->handle, iter->input, iter->dict))
+ if (sfm_read_case (iter->handle, &iter->input, iter->dict))
goto again;
- mtf_delete_file_in_place (&iter);
+ mtf_delete_file_in_place (mtf, &iter);
break;
default:
}
/* Next sequence number. */
- mtf_seq_num++;
+ mtf->seq_num++;
/* Store data to all the records we are using. */
if (min_tail)
for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
{
struct variable *v = dict_get_var (iter->dict, i);
+ struct ccase *record;
+ union value *out;
- if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num)
+ 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
+ mtf->seq_nums[v->p.mtf.master->index] = mtf->seq_num;
+
+ record = case_is_null (&iter->input) ? c : &iter->input;
+
+ assert (v->type == NUMERIC || v->type == ALPHA);
+ out = case_data_rw (mtf->mtf_case, v->p.mtf.master->fv);
if (v->type == NUMERIC)
- compaction_case->data[v->p.mtf.master->fv].f
- = iter->input[v->fv].f;
+ out->f = case_num (record, v->fv);
else
- {
- assert (v->type == ALPHA);
- memcpy (compaction_case->data[v->p.mtf.master->fv].s,
- iter->input[v->fv].s, v->width);
- }
+ memcpy (out->s, case_str (record, v->fv), v->width);
}
}
for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
{
struct variable *v = dict_get_var (iter->dict, i);
+ union value *out;
- if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num)
+ 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\n",
- fh_handle_name (iter->handle),
- v->name,
- v->p.mtf.master->fv);
-#endif
+ mtf->seq_nums[v->p.mtf.master->index] = mtf->seq_num;
+
+ out = case_data_rw (mtf->mtf_case, v->p.mtf.master->fv);
if (v->type == NUMERIC)
- compaction_case->data[v->p.mtf.master->fv].f = SYSMIS;
+ out->f = SYSMIS;
else
- memset (compaction_case->data[v->p.mtf.master->fv].s, ' ',
- v->width);
+ memset (out->s, ' ', v->width);
}
if (iter->handle == NULL)
}
/* 6. Write the output record. */
- process_active_file_output_case ();
+ mtf->sink->class->write (mtf->sink, mtf->mtf_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
if (iter->handle)
{
- assert (iter->input != NULL);
-
- if (!sfm_read_case (iter->handle, iter->input, iter->dict))
- mtf_delete_file_in_place (&iter);
+ if (!sfm_read_case (iter->handle, &iter->input, iter->dict))
+ mtf_delete_file_in_place (mtf, &iter);
}
iter = next;
break;
}
- return (mtf_head && mtf_head->type != MTF_TABLE);
+ return (mtf->head && mtf->head->type != MTF_TABLE);
}
/* Merge the dictionary for file F into the master dictionary
- mtf_master. */
+ mtf_dict. */
static int
-mtf_merge_dictionary (struct mtf_file *f)
+mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f)
{
- struct dictionary *const m = mtf_master;
struct dictionary *d = f->dict;
const char *d_docs, *m_docs;
msg (SE, _("Variable %s in file %s (%s) has different "
"type or width from the same variable in "
"earlier file (%s)."),
- dv->name, fh_handle_name (f->handle),
+ dv->name, handle_get_name (f->handle),
var_type_description (dv), var_type_description (mv));
return 0;
}
{
struct file_handle *handle = NULL;
struct dictionary *dict;
+ struct get_pgm *pgm;
int options = GTSV_OPT_NONE;
int type;
- lex_match_id ("IMPORT");
-
for (;;)
{
lex_match ('/');
if (dict == NULL)
return CMD_FAILURE;
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
if (0 == trim_dictionary (dict, &options))
{
fh_close_handle (handle);
return CMD_FAILURE;
}
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
dict_compact_values (dict);
-#if DEBUGGING
- printf (_("IMPORT translation table from file to memory:\n"));
- for (i = 0; i < dict->nvar; i++)
- {
- struct variable *v = dict->var[i];
-
- printf (_(" %8s from %3d,%3d to %3d,%3d\n"), v->name,
- v->get.fv, v->get.nv, v->fv, v->nv);
- }
-#endif
-
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;
}
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, default_dict))
if (!write_case (wc_data))
break;
}
const struct case_source_class import_source_class =
{
"IMPORT",
+ NULL,
import_source_read,
get_source_destroy,
};
int i;
- lex_match_id ("EXPORT");
-
lex_match ('/');
if (lex_match_id ("OUTFILE"))
lex_match ('=');
return CMD_FAILURE;
dict = dict_clone (default_dict);
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
for (i = 0; i < dict_get_var_cnt (dict); i++)
dict_get_var (dict, i)->aux = dict_get_var (default_dict, i);
if (0 == trim_dictionary (dict, &options))
return CMD_FAILURE;
}
-#if DEBUGGING
- dump_dict_variables (dict);
-#endif
-
/* Write dictionary. */
if (!pfm_write_dictionary (handle, dict))
{
t->case_buf = xmalloc (sizeof *t->case_buf * t->nvar);
dict_destroy (dict);
- procedure (NULL, export_write_case_func, NULL, t);
+ procedure (export_write_case_func, t);
save_trns_free (&t->h);
return CMD_SUCCESS;
}
+/* Writes case C to the EXPORT file. */
static int
export_write_case_func (struct ccase *c, void *aux)
{
struct variable *v = t->var[i];
if (v->type == NUMERIC)
- *p++ = c->data[v->fv];
+ (*p++).f = case_num (c, v->fv);
else
- (*p++).c = c->data[v->fv].s;
+ (*p++).c = (char *) case_str (c, v->fv);
}
pfm_write_case (t->f, (union value *) t->case_buf);