X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fget.c;h=deda2d57b6c6fd29de6e72a70d49575360178912;hb=92fb12eb06716d14c05b781f5d9dcde956d77c30;hp=44e5af4ad2403acc60a3289da1169c090d545538;hpb=0790746952bc8609c5f1edf476d70dc9a49d3915;p=pspp diff --git a/src/get.c b/src/get.c index 44e5af4ad2..deda2d57b6 100644 --- a/src/get.c +++ b/src/get.c @@ -1,5 +1,5 @@ /* 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 . This program is free software; you can redistribute it and/or @@ -21,6 +21,8 @@ #include "error.h" #include #include "alloc.h" +#include "any-reader.h" +#include "any-writer.h" #include "case.h" #include "command.h" #include "dictionary.h" @@ -29,10 +31,8 @@ #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" @@ -40,6 +40,9 @@ #include "vfm.h" #include "vfmP.h" +#include "gettext.h" +#define _(msgid) gettext (msgid) + #include "debug-print.h" /* Rearranging and reducing a dictionary. */ @@ -49,111 +52,147 @@ static void map_case (const struct case_map *, const struct ccase *, struct ccase *); static void destroy_case_map (struct case_map *); -/* Operation type. */ -enum operation +static bool parse_dict_trim (struct dictionary *); + +/* 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); - -/* 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); } @@ -164,194 +203,362 @@ get_source_read (struct case_source *source, 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, }; -/* 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); +} + +/* 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); +} + +/* 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); } + +/* 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); +} + static bool rename_variables (struct dictionary *dict); static bool drop_variables (struct dictionary *dict); static bool keep_variables (struct dictionary *dict); @@ -359,78 +566,39 @@ 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; @@ -467,7 +635,7 @@ rename_variables (struct dictionary *dict) 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; @@ -481,9 +649,9 @@ rename_variables (struct dictionary *dict) 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 (')')) @@ -498,7 +666,7 @@ rename_variables (struct dictionary *dict) } success = 1; -done: + done: for (i = 0; i < nn; i++) free (new_names[i]); free (new_names); @@ -513,7 +681,7 @@ static bool drop_variables (struct dictionary *dict) { struct variable **v; - int nv; + size_t nv; lex_match ('='); if (!parse_variables (dict, &v, &nv, PV_NONE)) @@ -535,8 +703,8 @@ static bool 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)) @@ -546,7 +714,7 @@ keep_variables (struct dictionary *dict) 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); @@ -555,91 +723,6 @@ keep_variables (struct dictionary *dict) return true; } -/* 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); - } -} - /* MATCH FILES. */ #include "debug-print.h" @@ -654,14 +737,13 @@ enum /* 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. */ @@ -811,11 +893,11 @@ cmd_match_files (void) } 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; @@ -870,9 +952,9 @@ cmd_match_files (void) 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++) { @@ -880,7 +962,7 @@ cmd_match_files (void) 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; @@ -983,7 +1065,7 @@ cmd_match_files (void) { msg (SE, _("IN variable name %s duplicates an " "existing variable name."), - iter->in_var); + iter->in_var->name); goto error; } iter->in_var->print = iter->in_var->write @@ -1051,7 +1133,7 @@ cmd_match_files (void) mtf_free (&mtf); return CMD_SUCCESS; -error: + error: mtf_free (&mtf); return CMD_FAILURE; } @@ -1103,7 +1185,7 @@ static void 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); @@ -1177,7 +1259,7 @@ mtf_read_nonactive_records (void *mtf_) 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); } } @@ -1275,7 +1357,7 @@ mtf_processing (struct ccase *c, void *mtf_) { 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); } @@ -1357,7 +1439,7 @@ mtf_processing (struct ccase *c, void *mtf_) { 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); } } @@ -1413,7 +1495,7 @@ mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f) 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; } @@ -1423,9 +1505,8 @@ mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f) 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) @@ -1453,147 +1534,6 @@ get_master (struct variable *v) return v->aux; } -/* 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, - }; /* Case map. @@ -1617,7 +1557,7 @@ struct 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) { @@ -1651,7 +1591,7 @@ finish_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;