X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpor-file-reader.c;h=3f8ee3c9fee47601c651850ba2ce6e3195028da0;hb=81579d9e9f994fb2908f50af41c3eb033d216e58;hp=668a8429d5839d9f8fb810009ef50d24d25eb169;hpb=707848060e414fe93458834446dd7cdbf800667f;p=pspp-builds.git diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 668a8429..3f8ee3c9 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,7 +15,8 @@ along with this program. If not, see . */ #include -#include "por-file-reader.h" + +#include "data/por-file-reader.h" #include #include @@ -26,26 +27,29 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xalloc.h" +#include "data/casereader-provider.h" +#include "data/casereader.h" +#include "data/dictionary.h" +#include "data/file-handle-def.h" +#include "data/file-name.h" +#include "data/format.h" +#include "data/missing-values.h" +#include "data/short-names.h" +#include "data/value-labels.h" +#include "data/variable.h" +#include "libpspp/compiler.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" + +#include "gl/intprops.h" +#include "gl/minmax.h" +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) +#define N_(msgid) (msgid) /* portable_to_local[PORTABLE] translates the given portable character into the local character set. */ @@ -72,12 +76,11 @@ struct pfm_reader char *trans; /* 256-byte character set translation table. */ int var_cnt; /* Number of variables. */ int weight_index; /* 0-based index of weight variable, or -1. */ - int *widths; /* Variable widths, 0 for numeric. */ - size_t value_cnt; /* Number of `value's per case. */ + struct caseproto *proto; /* Format of output cases. */ bool ok; /* Set false on I/O error. */ }; -static struct casereader_class por_file_casereader_class; +static const struct casereader_class por_file_casereader_class; static void error (struct pfm_reader *r, const char *msg,...) @@ -94,16 +97,18 @@ error (struct pfm_reader *r, const char *msg, ...) va_list args; ds_init_empty (&text); - ds_put_format (&text, _("portable file %s corrupt at offset 0x%lx: "), - fh_get_file_name (r->fh), ftell (r->file)); + ds_put_format (&text, _("portable file %s corrupt at offset 0x%llx: "), + fh_get_file_name (r->fh), (long long int) ftello (r->file)); va_start (args, msg); ds_put_vformat (&text, msg, args); va_end (args); - m.category = MSG_GENERAL; - m.severity = MSG_ERROR; + m.category = MSG_C_GENERAL; + m.severity = MSG_S_ERROR; m.where.file_name = NULL; m.where.line_number = 0; + m.where.first_column = 0; + m.where.last_column = 0; m.text = ds_cstr (&text); msg_emit (&m); @@ -123,16 +128,18 @@ warning (struct pfm_reader *r, const char *msg, ...) va_list args; ds_init_empty (&text); - ds_put_format (&text, _("reading portable file %s at offset 0x%lx: "), - fh_get_file_name (r->fh), ftell (r->file)); + ds_put_format (&text, _("reading portable file %s at offset 0x%llx: "), + fh_get_file_name (r->fh), (long long int) ftello (r->file)); va_start (args, msg); ds_put_vformat (&text, msg, args); va_end (args); - m.category = MSG_GENERAL; - m.severity = MSG_WARNING; + m.category = MSG_C_GENERAL; + m.severity = MSG_S_WARNING; m.where.file_name = NULL; m.where.line_number = 0; + m.where.first_column = 0; + m.where.last_column = 0; m.text = ds_cstr (&text); msg_emit (&m); @@ -151,7 +158,7 @@ close_reader (struct pfm_reader *r) { if (fn_close (fh_get_file_name (r->fh), r->file) == EOF) { - msg (ME, _("Error closing portable file \"%s\": %s."), + msg (ME, _("Error closing portable file `%s': %s."), fh_get_file_name (r->fh), strerror (errno)); r->ok = false; } @@ -254,14 +261,15 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, r->weight_index = -1; r->trans = NULL; r->var_cnt = 0; - r->widths = NULL; - r->value_cnt = 0; + r->proto = NULL; r->ok = true; if (setjmp (r->bail_out)) goto error; /* Lock file. */ - r->lock = fh_lock (fh, FH_REF_FILE, "portable file", FH_ACC_READ, false); + /* TRANSLATORS: this fragment will be interpolated into + messages in fh_lock() that identify types of files. */ + r->lock = fh_lock (fh, FH_REF_FILE, N_("portable file"), FH_ACC_READ, false); if (r->lock == NULL) goto error; @@ -269,7 +277,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, r->file = fn_open (fh_get_file_name (r->fh), "rb"); if (r->file == NULL) { - msg (ME, _("An error occurred while opening \"%s\" for reading " + msg (ME, _("An error occurred while opening `%s' for reading " "as a portable file: %s."), fh_get_file_name (r->fh), strerror (errno)); goto error; @@ -292,8 +300,8 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, if (!match (r, 'F')) error (r, _("Data record expected.")); - r->value_cnt = dict_get_next_value_idx (*dict); - return casereader_create_sequential (NULL, r->value_cnt, CASENUMBER_MAX, + r->proto = caseproto_ref_pool (dict_get_proto (*dict), r->pool); + return casereader_create_sequential (NULL, r->proto, CASENUMBER_MAX, &por_file_casereader_class, r); error: @@ -444,6 +452,28 @@ read_string (struct pfm_reader *r, char *buf) *buf = '\0'; } + +/* Reads a string into BUF, which must have room for 256 + characters. + Returns the number of bytes read. +*/ +static size_t +read_bytes (struct pfm_reader *r, uint8_t *buf) +{ + int n = read_int (r); + if (n < 0 || n > 255) + error (r, _("Bad string length %d."), n); + + while (n-- > 0) + { + *buf++ = r->cc; + advance (r); + } + return n; +} + + + /* Reads a string and returns a copy of it allocated from R's pool. */ static char * @@ -505,8 +535,9 @@ read_header (struct pfm_reader *r) static void read_version_data (struct pfm_reader *r, struct pfm_read_info *info) { - static char empty_string[] = ""; - char *date, *time, *product, *author, *subproduct; + static const char empty_string[] = ""; + char *date, *time; + const char *product, *author, *subproduct; int i; /* Read file. */ @@ -603,7 +634,7 @@ assign_default: return fmt_default_for_width (var_get_width (v)); } -static union value parse_value (struct pfm_reader *, struct variable *); +static void parse_value (struct pfm_reader *, int width, union value *); /* Read information on all the variables. */ static void @@ -618,7 +649,6 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) r->var_cnt = read_int (r); if (r->var_cnt <= 0) error (r, _("Invalid number of variables %d."), r->var_cnt); - r->widths = pool_nalloc (r->pool, r->var_cnt, sizeof *r->widths); /* Purpose of this value is unknown. It is typically 161. */ read_int (r); @@ -647,7 +677,6 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) width = read_int (r); if (width < 0) error (r, _("Invalid variable width %d."), width); - r->widths[i] = width; read_string (r, name); for (j = 0; j < 6; j++) @@ -663,17 +692,15 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) v = dict_create_var (dict, name, width); if (v == NULL) { - int i; - for (i = 1; i < 100000; i++) + unsigned long int i; + for (i = 1; ; i++) { - char try_name[LONG_NAME_LEN + 1]; - sprintf (try_name, "%.*s_%d", LONG_NAME_LEN - 6, name, i); + char try_name[8 + 1 + INT_STRLEN_BOUND (i) + 1]; + sprintf (try_name, "%s_%lu", name, i); v = dict_create_var (dict, try_name, width); if (v != NULL) break; } - if (v == NULL) - error (r, _("Duplicate variable name %s in position %d."), name, i); warning (r, _("Duplicate variable name %s in position %d renamed " "to %s."), name, i, var_get_name (v)); } @@ -684,26 +711,32 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) var_set_write_format (v, &write); /* Range missing values. */ - mv_init (&miss, var_get_width (v)); + mv_init (&miss, width); if (match (r, 'B')) { double x = read_float (r); double y = read_float (r); - mv_add_num_range (&miss, x, y); + mv_add_range (&miss, x, y); } else if (match (r, 'A')) - mv_add_num_range (&miss, read_float (r), HIGHEST); + mv_add_range (&miss, read_float (r), HIGHEST); else if (match (r, '9')) - mv_add_num_range (&miss, LOWEST, read_float (r)); + mv_add_range (&miss, LOWEST, read_float (r)); /* Single missing values. */ while (match (r, '8')) { - union value value = parse_value (r, v); + int mv_width = MIN (width, 8); + union value value; + + parse_value (r, mv_width, &value); + value_resize (&value, mv_width, width); mv_add_value (&miss, &value); + value_destroy (&value, width); } var_set_missing_values (v, &miss); + mv_destroy (&miss); if (match (r, 'C')) { @@ -724,22 +757,19 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) } } -/* Parse a value for variable VV into value V. */ -static union value -parse_value (struct pfm_reader *r, struct variable *vv) +/* Parse a value of with WIDTH into value V. */ +static void +parse_value (struct pfm_reader *r, int width, union value *v) { - union value v; - - if (var_is_alpha (vv)) + value_init (v, width); + if (width > 0) { - char string[256]; - read_string (r, string); - buf_copy_str_rpad (v.s, 8, string); + uint8_t buf[256]; + size_t n_bytes = read_bytes (r, buf); + value_copy_buf_rpad (v, width, buf, n_bytes, ' '); } else - v.f = read_float (r); - - return v; + v->f = read_float (r); } /* Parse a value label record and return success. */ @@ -779,17 +809,14 @@ read_value_label (struct pfm_reader *r, struct dictionary *dict) char label[256]; int j; - val = parse_value (r, v[0]); + parse_value (r, var_get_width (v[0]), &val); read_string (r, label); /* Assign the value label to each variable. */ for (j = 0; j < nv; j++) - { - struct variable *var = v[j]; + var_replace_value_label (v[j], &val, label); - if (!var_is_long_string (var)) - var_replace_value_label (var, &val, label); - } + value_destroy (&val, var_get_width (v[0])); } } @@ -809,50 +836,46 @@ read_documents (struct pfm_reader *r, struct dictionary *dict) } } -/* Reads one case from portable file R into C. */ -static bool -por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c) +/* Reads and returns one case from portable file R. Returns a + null pointer on failure. */ +static struct ccase * +por_file_casereader_read (struct casereader *reader, void *r_) { struct pfm_reader *r = r_; + struct ccase *volatile c; size_t i; - size_t idx; - case_create (c, casereader_get_value_cnt (reader)); + c = case_create (r->proto); setjmp (r->bail_out); if (!r->ok) { casereader_force_error (reader); - case_destroy (c); - return false; + case_unref (c); + return NULL; } /* Check for end of file. */ if (r->cc == 'Z') { - case_destroy (c); - return false; + case_unref (c); + return NULL; } - idx = 0; for (i = 0; i < r->var_cnt; i++) { - int width = r->widths[i]; + int width = caseproto_get_width (r->proto, i); if (width == 0) - { - case_data_rw_idx (c, idx)->f = read_float (r); - idx++; - } + case_data_rw_idx (c, i)->f = read_float (r); else { - char string[256]; - read_string (r, string); - buf_copy_str_rpad (case_data_rw_idx (c, idx)->s, width, string); - idx += DIV_RND_UP (width, MAX_SHORT_STRING); + uint8_t buf[256]; + size_t n_bytes = read_bytes (r, buf); + u8_buf_copy_rpad (case_str_rw_idx (c, i), width, buf, n_bytes, ' '); } } - return true; + return c; } /* Returns true if FILE is an SPSS portable file, @@ -862,17 +885,30 @@ pfm_detect (FILE *file) { unsigned char header[464]; char trans[256]; - int cooked_cnt, raw_cnt; + int cooked_cnt, raw_cnt, line_len; int i; cooked_cnt = raw_cnt = 0; + line_len = 0; while (cooked_cnt < sizeof header) { int c = getc (file); if (c == EOF || raw_cnt++ > 512) return false; - else if (c != '\n' && c != '\r') - header[cooked_cnt++] = c; + else if (c == '\n') + { + while (line_len < 80 && cooked_cnt < sizeof header) + { + header[cooked_cnt++] = ' '; + line_len++; + } + line_len = 0; + } + else if (c != '\r') + { + header[cooked_cnt++] = c; + line_len++; + } } memset (trans, 0, 256); @@ -890,7 +926,7 @@ pfm_detect (FILE *file) return true; } -static struct casereader_class por_file_casereader_class = +static const struct casereader_class por_file_casereader_class = { por_file_casereader_read, por_file_casereader_destroy,