X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpc%2B-file-reader.c;h=c7c9e3b7f8b062b75d3e57c0ed5be2a262e34fe5;hb=771599745cfe2a306dc45f2f299b9bfbfa19601b;hp=a127323c682d4d57b3be3f9c79a316af1eda92ab;hpb=63c7521729b947ace9e192dff9330813ecfb5812;p=pspp diff --git a/src/data/pc+-file-reader.c b/src/data/pc+-file-reader.c index a127323c68..c7c9e3b7f8 100644 --- a/src/data/pc+-file-reader.c +++ b/src/data/pc+-file-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-2000, 2006-2007, 2009-2014 Free Software Foundation, Inc. + Copyright (C) 1997-2000, 2006-2007, 2009-2016 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 @@ -73,6 +73,7 @@ struct pcp_main_header char creation_date[9]; /* "[m]m/dd/yy". */ char creation_time[9]; /* "[H]H:MM:SS". */ char file_label[65]; /* File label. */ + unsigned int weight_index; /* Index of weighting variable, 0 if none. */ }; struct pcp_var_record @@ -85,6 +86,8 @@ struct pcp_var_record uint8_t missing[8]; char *label; + bool weight; + struct pcp_value_label *val_labs; size_t n_val_labs; @@ -206,7 +209,7 @@ pcp_open (struct file_handle *fh) goto error; /* Open file. */ - r->file = fn_open (fh_get_file_name (fh), "rb"); + r->file = fn_open (fh, "rb"); if (r->file == NULL) { msg (ME, _("Error opening `%s' for reading as an SPSS/PC+ " @@ -218,13 +221,13 @@ pcp_open (struct file_handle *fh) /* Fetch file size. */ if (fstat (fileno (r->file), &s)) { - pcp_error (ME, 0, _("%s: stat failed (%s)."), + pcp_error (r, 0, _("%s: stat failed (%s)."), fh_get_file_name (r->fh), strerror (errno)); goto error; } if (s.st_size > UINT_MAX) { - pcp_error (ME, 0, _("%s: file too large."), fh_get_file_name (r->fh)); + pcp_error (r, 0, _("%s: file too large."), fh_get_file_name (r->fh)); goto error; } r->file_size = s.st_size; @@ -458,7 +461,7 @@ pcp_decode (struct any_reader *r_, const char *encoding, error: pcp_close (&r->any_reader); - dict_destroy (dict); + dict_unref (dict); *dictp = NULL; return NULL; } @@ -475,7 +478,7 @@ pcp_close (struct any_reader *r_) if (r->file) { - if (fn_close (fh_get_file_name (r->fh), r->file) == EOF) + if (fn_close (r->fh, r->file) == EOF) { msg (ME, _("Error closing system file `%s': %s."), fh_get_file_name (r->fh), strerror (errno)); @@ -502,18 +505,20 @@ pcp_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) pcp_close (&r->any_reader); } -/* Returns true if FILE is an SPSS/PC+ system file, - false otherwise. */ +/* Detects whether FILE is an SPSS/PC+ system file. Returns 1 if so, 0 if + not, and a negative errno value if there is an error reading FILE. */ static int pcp_detect (FILE *file) { static const char signature[4] = "SPSS"; char buf[sizeof signature]; - if (fseek (file, 0x104, SEEK_SET) - || (fread (buf, sizeof buf, 1, file) != 1 && !feof (file))) + if (fseek (file, 0x104, SEEK_SET)) return -errno; + if (fread (buf, sizeof buf, 1, file) != 1) + return ferror (file) ? -errno : 0; + return !memcmp (buf, signature, sizeof buf); } @@ -524,8 +529,8 @@ static bool read_main_header (struct pcp_reader *r, struct pcp_main_header *header) { unsigned int base_ofs = r->directory.main.ofs; + unsigned int zero0, zero1, zero2, zero3; size_t min_values, min_data_size; - unsigned int zero0, zero1, zero2; unsigned int one0, one1; unsigned int compressed; unsigned int n_cases1; @@ -551,9 +556,11 @@ read_main_header (struct pcp_reader *r, struct pcp_main_header *header) || !read_uint16 (r, &one1) || !read_uint16 (r, &compressed) || !read_uint16 (r, &header->nominal_case_size) - || !read_uint32 (r, &r->n_cases) + || !read_uint16 (r, &r->n_cases) + || !read_uint16 (r, &header->weight_index) || !read_uint16 (r, &zero2) - || !read_uint32 (r, &n_cases1) + || !read_uint16 (r, &n_cases1) + || !read_uint16 (r, &zero3) || !read_string (r, header->creation_date, sizeof header->creation_date) || !read_string (r, header->creation_time, sizeof header->creation_time) || !read_string (r, header->file_label, sizeof header->file_label)) @@ -565,10 +572,11 @@ read_main_header (struct pcp_reader *r, struct pcp_main_header *header) pcp_warn (r, base_ofs, _("Record 0 specifies unexpected system missing " "value %g (%a)."), d, d); } - if (one0 != 1 || one1 != 1 || zero0 != 0 || zero1 != 0 || zero2 != 0) + if (one0 != 1 || one1 != 1 + || zero0 != 0 || zero1 != 0 || zero2 != 0 || zero3 != 0) pcp_warn (r, base_ofs, _("Record 0 reserved fields have unexpected values " - "(%u,%u,%u,%u,%u)."), - one0, one1, zero0, zero1, zero2); + "(%u,%u,%u,%u,%u,%u)."), + one0, one1, zero0, zero1, zero2, zero3); if (n_cases1 != r->n_cases) pcp_warn (r, base_ofs, _("Record 0 case counts differ (%u versus %u)."), r->n_cases, n_cases1); @@ -633,8 +641,9 @@ read_value_labels (struct pcp_reader *r, struct pcp_var_record *var, uint8_t len; if (var->n_val_labs >= allocated_val_labs) - var->val_labs = x2nrealloc (var->val_labs, &allocated_val_labs, - sizeof *var->val_labs); + var->val_labs = pool_2nrealloc (r->pool, var->val_labs, + &allocated_val_labs, + sizeof *var->val_labs); vl = &var->val_labs[var->n_val_labs]; if (!read_bytes (r, vl->value, sizeof vl->value) @@ -701,6 +710,7 @@ static bool read_variables_record (struct pcp_reader *r) { unsigned int i; + bool weighted; if (!pcp_seek (r, r->directory.variables.ofs)) return false; @@ -713,6 +723,7 @@ read_variables_record (struct pcp_reader *r) r->vars = pool_calloc (r->pool, r->header.nominal_case_size, sizeof *r->vars); + weighted = false; for (i = 0; i < r->header.nominal_case_size; i++) { struct pcp_var_record *var = &r->vars[r->n_vars++]; @@ -730,6 +741,10 @@ read_variables_record (struct pcp_reader *r) || !read_bytes (r, var->missing, sizeof var->missing)) return false; + var->weight = r->header.weight_index && i == r->header.weight_index - 1; + if (var->weight) + weighted = true; + raw_type = format >> 16; if (!fmt_from_io (raw_type, &var->format.type)) { @@ -768,6 +783,9 @@ read_variables_record (struct pcp_reader *r) } } + if (r->header.weight_index && !weighted) + pcp_warn (r, -1, _("Invalid weight index %u."), r->header.weight_index); + return true; } @@ -823,14 +841,12 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict, for (rec = var_recs; rec < &var_recs[n_var_recs]; rec++) { struct variable *var; - bool weight; char *name; size_t i; name = recode_string_pool ("UTF-8", dict_encoding, rec->name, -1, r->pool); name[strcspn (name, " ")] = '\0'; - weight = !strcmp (name, "$WEIGHT") && rec->width == 0; /* Transform $DATE => DATE_, $WEIGHT => WEIGHT_, $CASENUM => CASENUM_. */ if (name[0] == '$') @@ -852,8 +868,14 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict, var = rec->var = dict_create_var_assert (dict, new_name, rec->width); free (new_name); } - if (weight) - dict_set_weight (dict, var); + if (rec->weight) + { + if (!rec->width) + dict_set_weight (dict, var); + else + pcp_warn (r, rec->pos, + _("Cannot weight by string variable `%s'."), name); + } /* Set the short name the same as the long name. */ var_set_short_name (var, 0, name); @@ -878,8 +900,7 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict, if (var_is_numeric (var)) value.f = parse_float (rec->val_labs[i].value); else - memcpy (value_str_rw (&value, rec->width), - rec->val_labs[i].value, rec->width); + memcpy (value.s, rec->val_labs[i].value, rec->width); utf8_label = recode_string ("UTF-8", dict_encoding, rec->val_labs[i].label, -1); @@ -945,8 +966,7 @@ pcp_file_casereader_read (struct casereader *reader, void *r_) if (var->width == 0) retval = read_case_number (r, &v->f); else - retval = read_case_string (r, value_str_rw (v, var->width), - var->width); + retval = read_case_string (r, v->s, var->width); if (retval != 1) { @@ -1130,9 +1150,7 @@ static void pcp_msg (struct pcp_reader *r, off_t offset, int class, const char *format, va_list args) { - struct msg m; struct string text; - ds_init_empty (&text); if (offset >= 0) ds_put_format (&text, _("`%s' near offset 0x%llx: "), @@ -1141,15 +1159,11 @@ pcp_msg (struct pcp_reader *r, off_t offset, ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh)); ds_put_vformat (&text, format, args); - m.category = msg_class_to_category (class); - m.severity = msg_class_to_severity (class); - m.file_name = NULL; - m.first_line = 0; - m.last_line = 0; - m.first_column = 0; - m.last_column = 0; - m.text = ds_cstr (&text); - + struct msg m = { + .category = msg_class_to_category (class), + .severity = msg_class_to_severity (class), + .text = ds_cstr (&text), + }; msg_emit (&m); }