/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
#include "error.h"
#include <stdlib.h>
#include "alloc.h"
+#include "any-reader.h"
+#include "any-writer.h"
#include "case.h"
#include "command.h"
#include "dictionary.h"
#include "hash.h"
#include "lexer.h"
#include "misc.h"
-#include "pfm-read.h"
#include "pfm-write.h"
#include "settings.h"
-#include "sfm-read.h"
#include "sfm-write.h"
#include "str.h"
#include "value-labels.h"
#include "vfm.h"
#include "vfmP.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
#include "debug-print.h"
/* Rearranging and reducing a dictionary. */
const struct ccase *, struct ccase *);
static void destroy_case_map (struct case_map *);
-/* Operation type. */
-enum operation
+static bool parse_dict_trim (struct dictionary *);
+\f
+/* Reading system and portable files. */
+
+/* Type of command. */
+enum reader_command
{
- OP_READ, /* GET or IMPORT. */
- OP_SAVE, /* SAVE or XSAVE. */
- OP_EXPORT /* EXPORT. */
+ GET_CMD,
+ IMPORT_CMD
};
-static bool trim_dictionary (struct dictionary *,
- enum operation, int *compress);
-\f
-/* GET input program. */
-struct get_pgm
+/* Case reader input program. */
+struct case_reader_pgm
{
- struct sfm_reader *reader; /* System file reader. */
- struct case_map *map; /* Map from system file to active file dict. */
+ struct any_reader *reader; /* File reader. */
+ struct case_map *map; /* Map from file dict to active file dict. */
struct ccase bounce; /* Bounce buffer. */
};
-static void get_pgm_free (struct get_pgm *);
+static const struct case_source_class case_reader_source_class;
-/* Parses the GET command. */
-int
-cmd_get (void)
+static void case_reader_pgm_free (struct case_reader_pgm *);
+
+/* Parses a GET or IMPORT command. */
+static int
+parse_read_command (enum reader_command type)
{
- struct get_pgm *pgm = NULL;
- struct file_handle *fh;
+ struct case_reader_pgm *pgm = NULL;
+ struct file_handle *fh = NULL;
struct dictionary *dict = NULL;
- pgm = xmalloc (sizeof *pgm);
- pgm->reader = NULL;
- pgm->map = NULL;
- case_nullify (&pgm->bounce);
+ for (;;)
+ {
+ lex_match ('/');
- discard_variables ();
+ if (lex_match_id ("FILE") || token == T_STRING)
+ {
+ lex_match ('=');
- lex_match ('/');
- if (lex_match_id ("FILE"))
- lex_match ('=');
- fh = fh_parse ();
- if (fh == NULL)
- goto error;
+ fh = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
+ if (fh == NULL)
+ goto error;
+ }
+ else if (type == IMPORT_CMD && lex_match_id ("TYPE"))
+ {
+ lex_match ('=');
+
+ if (lex_match_id ("COMM"))
+ type = PFM_COMM;
+ else if (lex_match_id ("TAPE"))
+ type = PFM_TAPE;
+ else
+ {
+ lex_error (_("expecting COMM or TAPE"));
+ goto error;
+ }
+ }
+ else
+ break;
+ }
+
+ if (fh == NULL)
+ {
+ lex_sbc_missing ("FILE");
+ goto error;
+ }
+
+ discard_variables ();
- pgm->reader = sfm_open_reader (fh, &dict, NULL);
+ pgm = xmalloc (sizeof *pgm);
+ pgm->reader = any_reader_open (fh, &dict);
+ pgm->map = NULL;
+ case_nullify (&pgm->bounce);
if (pgm->reader == NULL)
goto error;
- case_create (&pgm->bounce, dict_get_next_value_idx (dict));
+ case_create (&pgm->bounce, dict_get_next_value_idx (dict));
+
start_case_map (dict);
- if (!trim_dictionary (dict, OP_READ, NULL))
- goto error;
- pgm->map = finish_case_map (dict);
+ while (token != '.')
+ {
+ lex_match ('/');
+ if (!parse_dict_trim (dict))
+ goto error;
+ }
+
+ pgm->map = finish_case_map (dict);
+
dict_destroy (default_dict);
default_dict = dict;
- vfm_source = create_case_source (&get_source_class, pgm);
+ vfm_source = create_case_source (&case_reader_source_class, pgm);
return CMD_SUCCESS;
error:
- get_pgm_free (pgm);
+ case_reader_pgm_free (pgm);
if (dict != NULL)
dict_destroy (dict);
return CMD_FAILURE;
}
-/* Frees a struct get_pgm. */
+/* Frees a struct case_reader_pgm. */
static void
-get_pgm_free (struct get_pgm *pgm)
+case_reader_pgm_free (struct case_reader_pgm *pgm)
{
if (pgm != NULL)
{
- sfm_close_reader (pgm->reader);
+ any_reader_close (pgm->reader);
destroy_case_map (pgm->map);
case_destroy (&pgm->bounce);
free (pgm);
}
}
-/* Clears internal state related to GET input procedure. */
+/* Clears internal state related to case reader input procedure. */
static void
-get_source_destroy (struct case_source *source)
+case_reader_source_destroy (struct case_source *source)
{
- struct get_pgm *pgm = source->aux;
- get_pgm_free (pgm);
+ struct case_reader_pgm *pgm = source->aux;
+ case_reader_pgm_free (pgm);
}
/* 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)
+case_reader_source_read (struct case_source *source,
+ struct ccase *c,
+ write_case_func *write_case, write_case_data wc_data)
{
- struct get_pgm *pgm = source->aux;
+ struct case_reader_pgm *pgm = source->aux;
int ok;
do
{
if (pgm->map == NULL)
- ok = sfm_read_case (pgm->reader, c);
+ ok = any_reader_read (pgm->reader, c);
else
{
- ok = sfm_read_case (pgm->reader, &pgm->bounce);
+ ok = any_reader_read (pgm->reader, &pgm->bounce);
if (ok)
map_case (pgm->map, &pgm->bounce, c);
}
while (ok);
}
-const struct case_source_class get_source_class =
+static const struct case_source_class case_reader_source_class =
{
- "GET",
+ "case reader",
NULL,
- get_source_read,
- get_source_destroy,
+ case_reader_source_read,
+ case_reader_source_destroy,
};
\f
-/* XSAVE transformation and SAVE procedure. */
-struct save_trns
+/* GET. */
+int
+cmd_get (void)
+{
+ return parse_read_command (GET_CMD);
+}
+
+/* IMPORT. */
+int
+cmd_import (void)
+{
+ return parse_read_command (IMPORT_CMD);
+}
+\f
+/* Writing system and portable files. */
+
+/* Type of output file. */
+enum writer_type
{
- struct trns_header h;
- struct sfm_writer *writer; /* System file writer. */
- struct case_map *map; /* Map from active file to system file dict. */
- struct ccase bounce; /* Bounce buffer. */
+ SYSFILE_WRITER, /* System file. */
+ PORFILE_WRITER /* Portable file. */
+ };
+
+/* Type of a command. */
+enum command_type
+ {
+ XFORM_CMD, /* Transformation. */
+ PROC_CMD /* Procedure. */
};
-static int save_write_case_func (struct ccase *, void *);
-static trns_proc_func save_trns_proc;
-static trns_free_func save_trns_free;
+/* File writer plus a case map. */
+struct case_writer
+ {
+ struct any_writer *writer; /* File writer. */
+ struct case_map *map; /* Map to output file dictionary
+ (null pointer for identity mapping). */
+ struct ccase bounce; /* Bounce buffer for mapping (if needed). */
+ };
-/* Parses the SAVE or XSAVE command
- and returns the parsed transformation. */
-static struct save_trns *
-cmd_save_internal (void)
+/* Destroys AW. */
+static void
+case_writer_destroy (struct case_writer *aw)
{
- struct file_handle *fh = NULL;
- struct dictionary *dict = NULL;
- struct save_trns *t = NULL;
- int compress = get_scompression ();
- const int default_version = 3;
- int version = default_version;
- short no_name_table = 0;
-
- t = xmalloc (sizeof *t);
- t->h.proc = save_trns_proc;
- t->h.free = save_trns_free;
- t->writer = NULL;
- t->map = NULL;
- case_nullify (&t->bounce);
-
+ if (aw != NULL)
+ {
+ any_writer_close (aw->writer);
+ destroy_case_map (aw->map);
+ case_destroy (&aw->bounce);
+ free (aw);
+ }
+}
+
+/* Parses SAVE or XSAVE or EXPORT or XEXPORT command.
+ WRITER_TYPE identifies the type of file to write,
+ and COMMAND_TYPE identifies the type of command.
+
+ On success, returns a writer.
+ For procedures only, sets *RETAIN_UNSELECTED to true if cases
+ that would otherwise be excluded by FILTER or USE should be
+ included.
+
+ On failure, returns a null pointer. */
+static struct case_writer *
+parse_write_command (enum writer_type writer_type,
+ enum command_type command_type,
+ bool *retain_unselected)
+{
+ /* Common data. */
+ struct file_handle *handle; /* Output file. */
+ struct dictionary *dict; /* Dictionary for output file. */
+ struct case_writer *aw; /* Writer. */
+
+ /* Common options. */
+ bool print_map; /* Print map? TODO. */
+ bool print_short_names; /* Print long-to-short name map. TODO. */
+ struct sfm_write_options sysfile_opts;
+ struct pfm_write_options porfile_opts;
+
+ assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER);
+ assert (command_type == XFORM_CMD || command_type == PROC_CMD);
+ assert ((retain_unselected != NULL) == (command_type == PROC_CMD));
+
+ if (command_type == PROC_CMD)
+ *retain_unselected = true;
+
+ handle = NULL;
+ dict = dict_clone (default_dict);
+ aw = xmalloc (sizeof *aw);
+ aw->writer = NULL;
+ aw->map = NULL;
+ case_nullify (&aw->bounce);
+ print_map = false;
+ print_short_names = false;
+ sysfile_opts = sfm_writer_default_options ();
+ porfile_opts = pfm_writer_default_options ();
- /* Read most of the subcommands. */
+ start_case_map (dict);
+ dict_delete_scratch_vars (dict);
+
+ lex_match ('/');
for (;;)
{
- if (lex_match_id ("VERSION"))
+ if (lex_match_id ("OUTFILE"))
{
+ if (handle != NULL)
+ {
+ lex_sbc_only_once ("OUTFILE");
+ goto error;
+ }
+
lex_match ('=');
- if (lex_force_int ())
- {
- version = lex_integer ();
- lex_get ();
-
- if (lex_match_id ("X"))
- no_name_table = 1;
- }
+
+ handle = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
+ if (handle == NULL)
+ goto error;
}
- else if (lex_match_id ("OUTFILE"))
+ else if (lex_match_id ("NAMES"))
+ print_short_names = true;
+ else if (lex_match_id ("PERMISSIONS"))
+ {
+ bool cw;
+
+ lex_match ('=');
+ if (lex_match_id ("READONLY"))
+ cw = false;
+ else if (lex_match_id ("WRITEABLE"))
+ cw = true;
+ else
+ {
+ lex_error (_("expecting %s or %s"), "READONLY", "WRITEABLE");
+ goto error;
+ }
+ sysfile_opts.create_writeable = porfile_opts.create_writeable = cw;
+ }
+ else if (command_type == PROC_CMD && lex_match_id ("UNSELECTED"))
+ {
+ lex_match ('=');
+ if (lex_match_id ("RETAIN"))
+ *retain_unselected = true;
+ else if (lex_match_id ("DELETE"))
+ *retain_unselected = false;
+ else
+ {
+ lex_error (_("expecting %s or %s"), "RETAIN", "DELETE");
+ goto error;
+ }
+ }
+ else if (writer_type == SYSFILE_WRITER && lex_match_id ("COMPRESSED"))
+ sysfile_opts.compress = true;
+ else if (writer_type == SYSFILE_WRITER && lex_match_id ("UNCOMPRESSED"))
+ sysfile_opts.compress = false;
+ else if (writer_type == SYSFILE_WRITER && lex_match_id ("VERSION"))
{
lex_match ('=');
-
- fh = fh_parse ();
- if (fh == NULL)
- goto error;
-
+ if (!lex_force_int ())
+ goto error;
+ sysfile_opts.version = lex_integer ();
+ lex_get ();
}
- if ( ! lex_match('/') )
+ else if (writer_type == PORFILE_WRITER && lex_match_id ("TYPE"))
+ {
+ lex_match ('=');
+ if (lex_match_id ("COMMUNICATIONS"))
+ porfile_opts.type = PFM_COMM;
+ else if (lex_match_id ("TAPE"))
+ porfile_opts.type = PFM_TAPE;
+ else
+ {
+ lex_error (_("expecting %s or %s"), "COMM", "TAPE");
+ goto error;
+ }
+ }
+ else if (writer_type == PORFILE_WRITER && lex_match_id ("DIGITS"))
+ {
+ lex_match ('=');
+ if (!lex_force_int ())
+ goto error;
+ porfile_opts.digits = lex_integer ();
+ lex_get ();
+ }
+ else if (!parse_dict_trim (dict))
+ goto error;
+
+ if (!lex_match ('/'))
break;
-
}
+ if (lex_end_of_command () != CMD_SUCCESS)
+ goto error;
- if (token != '.')
+ if (handle == NULL)
{
- lex_error (_("expecting end of command"));
+ lex_sbc_missing ("OUTFILE");
goto error;
}
- if ( fh == NULL )
- {
- msg ( ME, _("The required %s subcommand was not present"), "OUTFILE");
- goto error;
- }
+ dict_compact_values (dict);
+ aw->map = finish_case_map (dict);
+ if (aw->map != NULL)
+ case_create (&aw->bounce, dict_get_next_value_idx (dict));
- if ( version != default_version )
+ if (fh_get_referent (handle) == FH_REF_FILE)
{
- msg (MW, _("Unsupported sysfile version: %d. Using version %d instead."),
- version, default_version);
-
- version = default_version;
+ switch (writer_type)
+ {
+ case SYSFILE_WRITER:
+ aw->writer = any_writer_from_sfm_writer (
+ sfm_open_writer (handle, dict, sysfile_opts));
+ break;
+ case PORFILE_WRITER:
+ aw->writer = any_writer_from_pfm_writer (
+ pfm_open_writer (handle, dict, porfile_opts));
+ break;
+ }
}
-
- dict = dict_clone (default_dict);
- start_case_map (dict);
- if (!trim_dictionary (dict, OP_SAVE, &compress))
- goto error;
- t->map = finish_case_map (dict);
- if (t->map != NULL)
- case_create (&t->bounce, dict_get_next_value_idx (dict));
-
- t->writer = sfm_open_writer (fh, dict, compress, no_name_table);
- if (t->writer == NULL)
- goto error;
-
+ else
+ aw->writer = any_writer_open (handle, dict);
dict_destroy (dict);
-
- return t;
+
+ return aw;
error:
- assert (t != NULL);
+ case_writer_destroy (aw);
dict_destroy (dict);
- save_trns_free (&t->h);
return NULL;
}
-/* Parses and performs the SAVE procedure. */
-int
-cmd_save (void)
+/* Writes case C to writer AW. */
+static void
+case_writer_write_case (struct case_writer *aw, struct ccase *c)
{
- struct save_trns *t = cmd_save_internal ();
- if (t != NULL)
+ if (aw->map != NULL)
{
- procedure (save_write_case_func, t);
- save_trns_free (&t->h);
- free(t);
- return CMD_SUCCESS;
+ map_case (aw->map, c, &aw->bounce);
+ c = &aw->bounce;
}
- else
+ any_writer_write (aw->writer, c);
+}
+\f
+/* SAVE and EXPORT. */
+
+static int output_proc (struct ccase *, void *);
+
+/* Parses and performs the SAVE or EXPORT procedure. */
+static int
+parse_output_proc (enum writer_type writer_type)
+{
+ bool retain_unselected;
+ struct variable *saved_filter_variable;
+ struct case_writer *aw;
+
+ aw = parse_write_command (writer_type, PROC_CMD, &retain_unselected);
+ if (aw == NULL)
return CMD_FAILURE;
+
+ saved_filter_variable = dict_get_filter (default_dict);
+ if (retain_unselected)
+ dict_set_filter (default_dict, NULL);
+ procedure (output_proc, aw);
+ dict_set_filter (default_dict, saved_filter_variable);
+
+ case_writer_destroy (aw);
+ return CMD_SUCCESS;
+}
+
+/* Writes case C to file. */
+static int
+output_proc (struct ccase *c, void *aw_)
+{
+ struct case_writer *aw = aw_;
+ case_writer_write_case (aw, c);
+ return 0;
}
-/* Parses the XSAVE transformation command. */
int
-cmd_xsave (void)
+cmd_save (void)
{
- struct save_trns *t = cmd_save_internal ();
- if (t != NULL)
- {
- add_transformation (&t->h);
- return CMD_SUCCESS;
- }
- else
- return CMD_FAILURE;
+ return parse_output_proc (SYSFILE_WRITER);
}
-/* Writes the given C to the file specified by T. */
-static void
-do_write_case (struct save_trns *t, struct ccase *c)
+int
+cmd_export (void)
{
- if (t->map == NULL)
- sfm_write_case (t->writer, c);
- else
- {
- map_case (t->map, c, &t->bounce);
- sfm_write_case (t->writer, &t->bounce);
- }
+ return parse_output_proc (PORFILE_WRITER);
}
+\f
+/* XSAVE and XEXPORT. */
-/* Writes case C to the system file specified on SAVE. */
+/* Transformation. */
+struct output_trns
+ {
+ struct case_writer *aw; /* Writer. */
+ };
+
+static trns_proc_func output_trns_proc;
+static trns_free_func output_trns_free;
+
+/* Parses the XSAVE or XEXPORT transformation command. */
static int
-save_write_case_func (struct ccase *c, void *aux UNUSED)
+parse_output_trns (enum writer_type writer_type)
{
- do_write_case (aux, c);
- return 1;
+ struct output_trns *t = xmalloc (sizeof *t);
+ t->aw = parse_write_command (writer_type, XFORM_CMD, NULL);
+ if (t->aw == NULL)
+ {
+ free (t);
+ return CMD_FAILURE;
+ }
+
+ add_transformation (output_trns_proc, output_trns_free, t);
+ return CMD_SUCCESS;
}
-/* Writes case C to the system file specified on XSAVE. */
+/* Writes case C to the system file specified on XSAVE or XEXPORT. */
static int
-save_trns_proc (struct trns_header *h, struct ccase *c, int case_num UNUSED)
+output_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
{
- struct save_trns *t = (struct save_trns *) h;
- do_write_case (t, c);
+ struct output_trns *t = trns_;
+ case_writer_write_case (t->aw, c);
return -1;
}
-/* Frees a SAVE transformation. */
+/* Frees an XSAVE or XEXPORT transformation. */
static void
-save_trns_free (struct trns_header *t_)
+output_trns_free (void *trns_)
{
- struct save_trns *t = (struct save_trns *) t_;
+ struct output_trns *t = trns_;
- if (t != NULL)
+ if (t != NULL)
{
- sfm_close_writer (t->writer);
- destroy_case_map (t->map);
- case_destroy (&t->bounce);
+ case_writer_destroy (t->aw);
+ free (t);
}
}
+/* XSAVE command. */
+int
+cmd_xsave (void)
+{
+ return parse_output_trns (SYSFILE_WRITER);
+}
+
+/* XEXPORT command. */
+int
+cmd_xexport (void)
+{
+ return parse_output_trns (PORFILE_WRITER);
+}
+\f
static bool rename_variables (struct dictionary *dict);
static bool drop_variables (struct dictionary *dict);
static bool keep_variables (struct dictionary *dict);
/* Commands that read and write system files share a great deal
of common syntactic structure for rearranging and dropping
variables. This function parses this syntax and modifies DICT
- appropriately.
-
- OP is the operation being performed. For operations that
- write a system file, *COMPRESS is set to 1 if the system file
- should be compressed, 0 otherwise.
-
- Returns true on success, false on failure. */
+ appropriately. Returns true on success, false on failure. */
static bool
-trim_dictionary (struct dictionary *dict, enum operation op, int *compress)
+parse_dict_trim (struct dictionary *dict)
{
- assert ((compress != NULL) == (op == OP_SAVE));
- if (get_scompression())
- *compress = 1;
-
- if (op == OP_SAVE || op == OP_EXPORT)
+ if (lex_match_id ("MAP"))
{
- /* Delete all the scratch variables. */
- struct variable **v;
- size_t nv;
- size_t i;
-
- v = xmalloc (sizeof *v * dict_get_var_cnt (dict));
- nv = 0;
- for (i = 0; i < dict_get_var_cnt (dict); i++)
- 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);
+ /* FIXME. */
+ return true;
}
-
- while (lex_match ('/'))
+ else if (lex_match_id ("DROP"))
+ return drop_variables (dict);
+ else if (lex_match_id ("KEEP"))
+ return keep_variables (dict);
+ else if (lex_match_id ("RENAME"))
+ return rename_variables (dict);
+ else
{
- bool ok = true;
-
- if (op == OP_SAVE && lex_match_id ("COMPRESSED"))
- *compress = 1;
- else if (op == OP_SAVE && lex_match_id ("UNCOMPRESSED"))
- *compress = 0;
- else if (lex_match_id ("DROP"))
- ok = drop_variables (dict);
- else if (lex_match_id ("KEEP"))
- ok = keep_variables (dict);
- else if (lex_match_id ("RENAME"))
- ok = rename_variables (dict);
- else
- {
- lex_error (_("expecting a valid subcommand"));
- ok = false;
- }
-
- if (!ok)
- return false;
+ lex_error (_("expecting a valid subcommand"));
+ return false;
}
-
- if (!lex_end_of_command ())
- return false;
-
- dict_compact_values (dict);
- return true;
}
/* Parses and performs the RENAME subcommand of GET and SAVE. */
static bool
rename_variables (struct dictionary *dict)
{
- int i;
+ size_t i;
int success = 0;
struct variable **v;
char **new_names;
- int nv, nn;
+ size_t nv, nn;
char *err_name;
int group;
group = 1;
while (lex_match ('('))
{
- int old_nv = nv;
+ size_t old_nv = nv;
if (!parse_variables (dict, &v, &nv, PV_NO_DUPLICATE | PV_APPEND))
goto done;
if (nn != nv)
{
msg (SE, _("Number of variables on left side of `=' (%d) does not "
- "match number of variables on right side (%d), in "
- "parenthesized group %d of RENAME subcommand."),
- nv - old_nv, nn - old_nv, group);
+ "match number of variables on right side (%d), in "
+ "parenthesized group %d of RENAME subcommand."),
+ (unsigned) (nv - old_nv), (unsigned) (nn - old_nv), group);
goto done;
}
if (!lex_force_match (')'))
}
success = 1;
-done:
+ done:
for (i = 0; i < nn; i++)
free (new_names[i]);
free (new_names);
drop_variables (struct dictionary *dict)
{
struct variable **v;
- int nv;
+ size_t nv;
lex_match ('=');
if (!parse_variables (dict, &v, &nv, PV_NONE))
keep_variables (struct dictionary *dict)
{
struct variable **v;
- int nv;
- int i;
+ size_t nv;
+ size_t i;
lex_match ('=');
if (!parse_variables (dict, &v, &nv, PV_NONE))
dict_reorder_vars (dict, v, nv);
/* Delete the remaining variables. */
- v = xrealloc (v, (dict_get_var_cnt (dict) - nv) * sizeof *v);
+ v = xnrealloc (v, dict_get_var_cnt (dict) - nv, sizeof *v);
for (i = nv; i < dict_get_var_cnt (dict); i++)
v[i - nv] = dict_get_var (dict, i);
dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);
return true;
}
\f
-/* EXPORT procedure. */
-struct export_proc
- {
- struct pfm_writer *writer; /* System file writer. */
- struct case_map *map; /* Map from active file to system file dict. */
- struct ccase bounce; /* Bounce buffer. */
- };
-
-static int export_write_case_func (struct ccase *, void *);
-static void export_proc_free (struct export_proc *);
-
-/* Parses the EXPORT command. */
-/* FIXME: same as cmd_save_internal(). */
-int
-cmd_export (void)
-{
- struct file_handle *fh;
- struct dictionary *dict;
- struct export_proc *proc;
-
- proc = xmalloc (sizeof *proc);
- proc->writer = NULL;
- proc->map = NULL;
- case_nullify (&proc->bounce);
-
- lex_match ('/');
- if (lex_match_id ("OUTFILE"))
- lex_match ('=');
- fh = fh_parse ();
- if (fh == NULL)
- return CMD_FAILURE;
-
- dict = dict_clone (default_dict);
- start_case_map (dict);
- if (!trim_dictionary (dict, OP_EXPORT, NULL))
- goto error;
- proc->map = finish_case_map (dict);
- if (proc->map != NULL)
- case_create (&proc->bounce, dict_get_next_value_idx (dict));
-
- proc->writer = pfm_open_writer (fh, dict);
- if (proc->writer == NULL)
- goto error;
-
- dict_destroy (dict);
-
- procedure (export_write_case_func, proc);
- export_proc_free (proc);
- free (proc);
-
- return CMD_SUCCESS;
-
- error:
- dict_destroy (dict);
- export_proc_free (proc);
- free (proc);
- return CMD_FAILURE;
-}
-
-/* Writes case C to the EXPORT file. */
-static int
-export_write_case_func (struct ccase *c, void *aux)
-{
- struct export_proc *proc = aux;
- if (proc->map == NULL)
- pfm_write_case (proc->writer, c);
- else
- {
- map_case (proc->map, c, &proc->bounce);
- pfm_write_case (proc->writer, &proc->bounce);
- }
- return 1;
-}
-
-static void
-export_proc_free (struct export_proc *proc)
-{
- if (proc != NULL)
- {
- pfm_close_writer (proc->writer);
- destroy_case_map (proc->map);
- case_destroy (&proc->bounce);
- }
-}
-\f
/* MATCH FILES. */
#include "debug-print.h"
/* One of the files on MATCH FILES. */
struct mtf_file
{
- struct mtf_file *next, *prev;
- /* Next, previous in the list of files. */
+ struct mtf_file *next, *prev; /* Next, previous in the list of files. */
struct mtf_file *next_min; /* Next in the chain of minimums. */
int type; /* One of MTF_*. */
struct variable **by; /* List of BY variables for this file. */
struct file_handle *handle; /* File handle. */
- struct sfm_reader *reader; /* System file reader. */
+ struct any_reader *reader; /* File reader. */
struct dictionary *dict; /* Dictionary from system file. */
/* IN subcommand. */
}
else
{
- file->handle = fh_parse ();
+ file->handle = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
if (file->handle == NULL)
goto error;
- file->reader = sfm_open_reader (file->handle, &file->dict, NULL);
+ file->reader = any_reader_open (file->handle, &file->dict);
if (file->reader == NULL)
goto error;
for (iter = mtf.head; iter != NULL; iter = iter->next)
{
- int i;
+ size_t i;
- iter->by = xmalloc (sizeof *iter->by * mtf.by_cnt);
+ iter->by = xnmalloc (mtf.by_cnt, sizeof *iter->by);
for (i = 0; i < mtf.by_cnt; i++)
{
if (iter->by[i] == NULL)
{
msg (SE, _("File %s lacks BY variable %s."),
- iter->handle ? handle_get_name (iter->handle) : "*",
+ iter->handle ? fh_get_name (iter->handle) : "*",
by[i]->name);
free (by);
goto error;
mtf_free (&mtf);
return CMD_SUCCESS;
-error:
+ error:
mtf_free (&mtf);
return CMD_FAILURE;
}
mtf_free_file (struct mtf_file *file)
{
free (file->by);
- sfm_close_reader (file->reader);
+ any_reader_close (file->reader);
if (file->dict != default_dict)
dict_destroy (file->dict);
case_destroy (&file->input);
for (iter = mtf->head; iter != NULL; iter = next)
{
next = iter->next;
- if (iter->handle && !sfm_read_case (iter->reader, &iter->input))
+ if (iter->handle && !any_reader_read (iter->reader, &iter->input))
mtf_delete_file_in_place (mtf, &iter);
}
}
{
if (iter->handle == NULL)
return 1;
- if (sfm_read_case (iter->reader, &iter->input))
+ if (any_reader_read (iter->reader, &iter->input))
continue;
mtf_delete_file_in_place (mtf, &iter);
}
{
next = iter->next_min;
if (iter->reader != NULL
- && !sfm_read_case (iter->reader, &iter->input))
+ && !any_reader_read (iter->reader, &iter->input))
mtf_delete_file_in_place (mtf, &iter);
}
}
msg (SE, _("Variable %s in file %s (%s) has different "
"type or width from the same variable in "
"earlier file (%s)."),
- dv->name, handle_get_name (f->handle),
+ dv->name, fh_get_name (f->handle),
var_type_description (dv), var_type_description (mv));
return 0;
}
if (val_labs_count (dv->val_labs)
&& !val_labs_count (mv->val_labs))
mv->val_labs = val_labs_copy (dv->val_labs);
- if (dv->miss_type != MISSING_NONE
- && mv->miss_type == MISSING_NONE)
- copy_missing_values (mv, dv);
+ if (!mv_is_empty (&dv->miss) && mv_is_empty (&mv->miss))
+ mv_copy (&mv->miss, &dv->miss);
}
if (dv->label && !mv->label)
return v->aux;
}
\f
-/* IMPORT command. */
-
-/* IMPORT input program. */
-struct import_pgm
- {
- struct pfm_reader *reader; /* Portable file reader. */
- struct case_map *map; /* Map from system file to active file dict. */
- struct ccase bounce; /* Bounce buffer. */
- };
-
-static void import_pgm_free (struct import_pgm *);
-
-/* Parses the IMPORT command. */
-int
-cmd_import (void)
-{
- struct import_pgm *pgm = NULL;
- struct file_handle *fh = NULL;
- struct dictionary *dict = NULL;
- int type;
-
- pgm = xmalloc (sizeof *pgm);
- pgm->reader = NULL;
- pgm->map = NULL;
- case_nullify (&pgm->bounce);
-
- for (;;)
- {
- lex_match ('/');
-
- if (lex_match_id ("FILE") || token == T_STRING)
- {
- lex_match ('=');
-
- fh = fh_parse ();
- if (fh == NULL)
- return CMD_FAILURE;
- }
- else if (lex_match_id ("TYPE"))
- {
- lex_match ('=');
-
- if (lex_match_id ("COMM"))
- type = PFM_COMM;
- else if (lex_match_id ("TAPE"))
- type = PFM_TAPE;
- else
- {
- lex_error (_("expecting COMM or TAPE"));
- return CMD_FAILURE;
- }
- }
- else break;
- }
- if (!lex_match ('/') && token != '.')
- {
- lex_error (NULL);
- return CMD_FAILURE;
- }
-
- discard_variables ();
-
- pgm->reader = pfm_open_reader (fh, &dict, NULL);
- if (pgm->reader == NULL)
- return CMD_FAILURE;
- case_create (&pgm->bounce, dict_get_next_value_idx (dict));
-
- start_case_map (dict);
- if (!trim_dictionary (dict, OP_READ, NULL))
- goto error;
- pgm->map = finish_case_map (dict);
-
- dict_destroy (default_dict);
- default_dict = dict;
-
- vfm_source = create_case_source (&import_source_class, pgm);
-
- return CMD_SUCCESS;
-
- error:
- import_pgm_free (pgm);
- if (dict != NULL)
- dict_destroy (dict);
- return CMD_FAILURE;
-}
-
-/* Frees a struct import_pgm. */
-static void
-import_pgm_free (struct import_pgm *pgm)
-{
- if (pgm != NULL)
- {
- pfm_close_reader (pgm->reader);
- destroy_case_map (pgm->map);
- case_destroy (&pgm->bounce);
- free (pgm);
- }
-}
-
-/* Clears internal state related to IMPORT input procedure. */
-static void
-import_source_destroy (struct case_source *source)
-{
- struct import_pgm *pgm = source->aux;
- import_pgm_free (pgm);
-}
-
-/* Reads all the cases from the data file into C and passes them
- to WRITE_CASE one by one, passing WC_DATA. */
-static void
-import_source_read (struct case_source *source,
- struct ccase *c,
- write_case_func *write_case, write_case_data wc_data)
-{
- struct import_pgm *pgm = source->aux;
- int ok;
-
- do
- {
- if (pgm->map == NULL)
- ok = pfm_read_case (pgm->reader, c);
- else
- {
- ok = pfm_read_case (pgm->reader, &pgm->bounce);
- if (ok)
- map_case (pgm->map, &pgm->bounce, c);
- }
-
- if (ok)
- ok = write_case (wc_data);
- }
- while (ok);
-}
-
-const struct case_source_class import_source_class =
- {
- "IMPORT",
- NULL,
- import_source_read,
- import_source_destroy,
- };
\f
/* Case map.
at will before using finish_case_map() to produce the case
map.
- Uses D's aux members, which may not otherwise be in use. */
+ Uses D's aux members, which must otherwise not be in use. */
static void
start_case_map (struct dictionary *d)
{
map = xmalloc (sizeof *map);
map->value_cnt = dict_get_next_value_idx (d);
- map->map = xmalloc (sizeof *map->map * map->value_cnt);
+ map->map = xnmalloc (map->value_cnt, sizeof *map->map);
for (i = 0; i < map->value_cnt; i++)
map->map[i] = -1;