X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpor-file-reader.c;h=f9eb28b620d91d58e88573793f80ba0474e90014;hb=5ae0c7d839b1c9ad4e8581197b4e62e0c521f77a;hp=307a5393063f49ec84d7e4fafa4b20d573afbc93;hpb=338fb2a2e84df6427a2fdee6769421f57d5666d8;p=pspp-builds.git diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 307a5393..f9eb28b6 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -1,49 +1,47 @@ -/* PSPP - computes sample statistics. +/* PSPP - a program for statistical analysis. Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc. - Written by Ben Pfaff . - Code for parsing floating-point numbers adapted from GNU C - library. - 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 the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. + 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ + along with this program. If not, see . */ #include #include "por-file-reader.h" -#include -#include -#include -#include + #include #include #include #include -#include +#include #include -#include "case.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include "dictionary.h" -#include "file-handle-def.h" -#include "format.h" -#include "missing-values.h" #include #include +#include #include #include #include -#include "value-labels.h" -#include "variable.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -72,10 +70,12 @@ struct pfm_reader int var_cnt; /* Number of variables. */ int weight_index; /* 0-based index of weight variable, or -1. */ int *widths; /* Variable widths, 0 for numeric. */ - int value_cnt; /* Number of `value's per case. */ + size_t value_cnt; /* Number of `value's per case. */ bool ok; /* Set false on I/O error. */ }; +static struct casereader_class por_file_casereader_class; + static void error (struct pfm_reader *r, const char *msg,...) PRINTF_FORMAT (2, 3) @@ -102,7 +102,7 @@ error (struct pfm_reader *r, const char *msg, ...) m.where.file_name = NULL; m.where.line_number = 0; m.text = ds_cstr (&text); - + msg_emit (&m); r->ok = false; @@ -111,11 +111,11 @@ error (struct pfm_reader *r, const char *msg, ...) } /* Closes portable file reader R, after we're done with it. */ -void -pfm_close_reader (struct pfm_reader *r) +static void +por_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) { - if (r != NULL) - pool_destroy (r->pool); + struct pfm_reader *r = r_; + pool_destroy (r->pool); } /* Read a single character into cur_char. */ @@ -127,10 +127,10 @@ advance (struct pfm_reader *r) while ((c = getc (r->file)) == '\r' || c == '\n') continue; if (c == EOF) - error (r, _("unexpected end of file")); + error (r, _("unexpected end of file")); if (r->trans != NULL) - c = r->trans[c]; + c = r->trans[c]; r->cc = c; } @@ -157,7 +157,7 @@ void dump_dictionary (struct dictionary *); /* Reads the dictionary from file with handle H, and returns it in a dictionary structure. This dictionary may be modified in order to rename, reorder, and delete variables, etc. */ -struct pfm_reader * +struct casereader * pfm_open_reader (struct file_handle *fh, struct dictionary **dict, struct pfm_read_info *info) { @@ -191,7 +191,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, fh_get_file_name (r->fh), strerror (errno)); goto error; } - + /* Read header, version, date info, product id, variables. */ read_header (r); read_version_data (r, info); @@ -205,10 +205,12 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, if (!match (r, 'F')) error (r, _("Data record expected.")); - return r; + r->value_cnt = dict_get_next_value_idx (*dict); + return casereader_create_sequential (NULL, r->value_cnt, CASENUMBER_MAX, + &por_file_casereader_class, r); error: - pfm_close_reader (r); + pool_destroy (r->pool); dict_destroy (*dict); *dict = NULL; return NULL; @@ -217,7 +219,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, /* Returns the value of base-30 digit C, or -1 if C is not a base-30 digit. */ static int -base_30_value (unsigned char c) +base_30_value (unsigned char c) { static const char base_30_digits[] = "0123456789ABCDEFGHIJKLMNOPQRST"; const char *p = strchr (base_30_digits, c); @@ -283,7 +285,7 @@ read_float (struct pfm_reader *r) /* Check that we had some digits. */ if (!got_digit) - error (r, "Number expected."); + error (r, _("Number expected.")); /* Get exponent if any. */ if (r->cc == '+' || r->cc == '-') @@ -327,7 +329,7 @@ read_float (struct pfm_reader *r) return negative ? -num : num; } - + /* Read an integer and return its value. */ static int read_int (struct pfm_reader *r) @@ -346,7 +348,7 @@ read_string (struct pfm_reader *r, char *buf) int n = read_int (r); if (n < 0 || n > 255) error (r, _("Bad string length %d."), n); - + while (n-- > 0) { *buf++ = r->cc; @@ -358,7 +360,7 @@ read_string (struct pfm_reader *r, char *buf) /* Reads a string and returns a copy of it allocated from R's pool. */ static char * -read_pool_string (struct pfm_reader *r) +read_pool_string (struct pfm_reader *r) { char string[256]; read_string (r, string); @@ -375,7 +377,7 @@ read_header (struct pfm_reader *r) /* Read and ignore vanity splash strings. */ for (i = 0; i < 200; i++) advance (r); - + /* Skip the first 64 characters of the translation table. We don't care about these. They are probably all set to '0', marking them as untranslatable, and that would screw @@ -386,7 +388,7 @@ read_header (struct pfm_reader *r) /* Read the rest of the translation table. */ trans = pool_malloc (r->pool, 256); memset (trans, 0, 256); - for (; i < 256; i++) + for (; i < 256; i++) { unsigned char c; @@ -400,11 +402,11 @@ read_header (struct pfm_reader *r) /* Set up the translation table, then read the first translated character. */ r->trans = trans; - advance (r); + advance (r); /* Skip and verify signature. */ - for (i = 0; i < 8; i++) - if (!match (r, "SPSSPORT"[i])) + for (i = 0; i < 8; i++) + if (!match (r, "SPSSPORT"[i])) { msg (SE, _("%s: Not a portable file."), fh_get_file_name (r->fh)); longjmp (r->bail_out, 1); @@ -422,7 +424,7 @@ read_version_data (struct pfm_reader *r, struct pfm_read_info *info) /* Read file. */ if (!match (r, 'A')) - error (r, "Unrecognized version code `%c'.", r->cc); + error (r, _("Unrecognized version code `%c'."), r->cc); date = read_pool_string (r); time = read_pool_string (r); product = match (r, '1') ? read_pool_string (r) : empty_string; @@ -431,18 +433,18 @@ read_version_data (struct pfm_reader *r, struct pfm_read_info *info) /* Validate file. */ if (strlen (date) != 8) - error (r, _("Bad date string length %d."), strlen (date)); + error (r, _("Bad date string length %d."), (int) strlen (date)); if (strlen (time) != 6) - error (r, _("Bad time string length %d."), strlen (time)); + error (r, _("Bad time string length %d."), (int) strlen (time)); /* Save file info. */ - if (info != NULL) + if (info != NULL) { /* Date. */ - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1}; - info->creation_date[map[i]] = date[i]; + info->creation_date[map[i]] = date[i]; } info->creation_date[2] = info->creation_date[5] = ' '; info->creation_date[10] = 0; @@ -503,10 +505,10 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) { char *weight_name = NULL; int i; - + if (!match (r, '4')) error (r, _("Expected variable count record.")); - + r->var_cnt = read_int (r); if (r->var_cnt <= 0 || r->var_cnt == NOT_INT) error (r, _("Invalid number of variables %d."), r->var_cnt); @@ -518,10 +520,10 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) if (match (r, '6')) { weight_name = read_pool_string (r); - if (strlen (weight_name) > SHORT_NAME_LEN) + if (strlen (weight_name) > SHORT_NAME_LEN) error (r, _("Weight variable name (%s) truncated."), weight_name); } - + for (i = 0; i < r->var_cnt; i++) { int width; @@ -549,7 +551,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) str_uppercase (name); if (width < 0 || width > 255) - error (r, "Bad width %d for variable %s.", width, name); + error (r, _("Bad width %d for variable %s."), width, name); v = dict_create_var (dict, name, width); if (v == NULL) @@ -562,7 +564,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) /* Range missing values. */ mv_init (&miss, var_get_width (v)); - if (match (r, 'B')) + if (match (r, 'B')) { double x = read_float (r); double y = read_float (r); @@ -574,15 +576,15 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) mv_add_num_range (&miss, LOWEST, read_float (r)); /* Single missing values. */ - while (match (r, '8')) + while (match (r, '8')) { union value value = parse_value (r, v); - mv_add_value (&miss, &value); + mv_add_value (&miss, &value); } var_set_missing_values (v, &miss); - if (match (r, 'C')) + if (match (r, 'C')) { char label[256]; read_string (r, label); @@ -590,7 +592,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict) } } - if (weight_name != NULL) + if (weight_name != NULL) { struct variable *weight_var = dict_lookup_var (dict, weight_name); if (weight_var == NULL) @@ -606,12 +608,12 @@ static union value parse_value (struct pfm_reader *r, struct variable *vv) { union value v; - - if (var_is_alpha (vv)) + + if (var_is_alpha (vv)) { char string[256]; read_string (r, string); - buf_copy_str_rpad (v.s, 8, string); + buf_copy_str_rpad (v.s, 8, string); } else v.f = read_float (r); @@ -678,25 +680,34 @@ read_value_label (struct pfm_reader *r, struct dictionary *dict) } /* Reads one case from portable file R into C. */ -bool -pfm_read_case (struct pfm_reader *r, struct ccase *c) +static bool +por_file_casereader_read (struct casereader *reader, void *r_, struct ccase *c) { + struct pfm_reader *r = r_; size_t i; size_t idx; + case_create (c, casereader_get_value_cnt (reader)); setjmp (r->bail_out); if (!r->ok) - return false; - + { + casereader_force_error (reader); + case_destroy (c); + return false; + } + /* Check for end of file. */ if (r->cc == 'Z') - return false; + { + case_destroy (c); + return false; + } idx = 0; - for (i = 0; i < r->var_cnt; i++) + for (i = 0; i < r->var_cnt; i++) { int width = r->widths[i]; - + if (width == 0) { case_data_rw_idx (c, idx)->f = read_float (r); @@ -710,22 +721,14 @@ pfm_read_case (struct pfm_reader *r, struct ccase *c) idx += DIV_RND_UP (width, MAX_SHORT_STRING); } } - - return true; -} -/* Returns true if an I/O error has occurred on READER, false - otherwise. */ -bool -pfm_read_error (const struct pfm_reader *reader) -{ - return !reader->ok; + return true; } /* Returns true if FILE is an SPSS portable file, false otherwise. */ bool -pfm_detect (FILE *file) +pfm_detect (FILE *file) { unsigned char header[464]; char trans[256]; @@ -738,21 +741,29 @@ pfm_detect (FILE *file) int c = getc (file); if (c == EOF || raw_cnt++ > 512) return false; - else if (c != '\n' && c != '\r') + else if (c != '\n' && c != '\r') header[cooked_cnt++] = c; } memset (trans, 0, 256); - for (i = 64; i < 256; i++) + for (i = 64; i < 256; i++) { unsigned char c = header[i + 200]; if (trans[c] == 0) trans[c] = portable_to_local[i]; } - for (i = 0; i < 8; i++) - if (trans[header[i + 456]] != "SPSSPORT"[i]) - return false; + for (i = 0; i < 8; i++) + if (trans[header[i + 456]] != "SPSSPORT"[i]) + return false; return true; } + +static struct casereader_class por_file_casereader_class = + { + por_file_casereader_read, + por_file_casereader_destroy, + NULL, + NULL, + };