X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fpor-file-reader.c;h=a463124274a20c6cd62e1071f15c51cd95edcb3a;hb=b5c82cc9aabe7e641011130240ae1b2e84348e23;hp=3f385223e5afe74f277b6bb4e105a659902a4aec;hpb=77e551d23575da6b89f866612ab39c2b0497c9be;p=pspp-builds.git diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 3f385223..a4631242 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -1,51 +1,54 @@ -/* PSPP - computes sample statistics. - 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 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. +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2006, 2009 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 + 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. 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 -#include "dictionary.h" -#include "file-handle-def.h" -#include "format.h" #include -#include +#include #include #include #include -#include "value-labels.h" -#include "variable.h" + +#include "minmax.h" +#include "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. */ @@ -65,16 +68,19 @@ struct pfm_reader jmp_buf bail_out; /* longjmp() target for error handling. */ struct file_handle *fh; /* File handle. */ + struct fh_lock *lock; /* Read lock for file. */ FILE *file; /* File stream. */ + int line_length; /* Number of characters so far on this line. */ char cc; /* Current character. */ 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. */ - int value_cnt; /* Number of `value's per case. */ + struct caseproto *proto; /* Format of output cases. */ bool ok; /* Set false on I/O error. */ }; +static const struct casereader_class por_file_casereader_class; + static void error (struct pfm_reader *r, const char *msg,...) PRINTF_FORMAT (2, 3) @@ -85,34 +91,91 @@ error (struct pfm_reader *r, const char *msg,...) static void error (struct pfm_reader *r, const char *msg, ...) { - struct error e; - const char *filename; - char *title; + struct msg m; + struct string text; va_list args; - e.class = ME; - e.where.filename = NULL; - e.where.line_number = 0; - filename = fh_get_filename (r->fh); - e.title = title = pool_alloc (r->pool, strlen (filename) + 80); - sprintf (title, _("portable file %s corrupt at offset %ld: "), - filename, ftell (r->file)); - + 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)); va_start (args, msg); - err_vmsg (&e, msg, args); + ds_put_vformat (&text, msg, args); va_end (args); + m.category = MSG_GENERAL; + m.severity = MSG_ERROR; + m.where.file_name = NULL; + m.where.line_number = 0; + m.text = ds_cstr (&text); + + msg_emit (&m); + r->ok = false; longjmp (r->bail_out, 1); } +/* Displays MSG as an warning for the current position in + portable file reader R. */ +static void +warning (struct pfm_reader *r, const char *msg, ...) +{ + struct msg m; + struct string text; + 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)); + va_start (args, msg); + ds_put_vformat (&text, msg, args); + va_end (args); + + m.category = MSG_GENERAL; + m.severity = MSG_WARNING; + m.where.file_name = NULL; + m.where.line_number = 0; + m.text = ds_cstr (&text); + + msg_emit (&m); +} + +/* Close and destroy R. + Returns false if an error was detected on R, true otherwise. */ +static bool +close_reader (struct pfm_reader *r) +{ + bool ok; + if (r == NULL) + return true; + + if (r->file) + { + if (fn_close (fh_get_file_name (r->fh), r->file) == EOF) + { + msg (ME, _("Error closing portable file \"%s\": %s."), + fh_get_file_name (r->fh), strerror (errno)); + r->ok = false; + } + r->file = NULL; + } + + fh_unlock (r->lock); + fh_unref (r->fh); + + ok = r->ok; + pool_destroy (r->pool); + + return ok; +} + /* 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, void *r_) { - if (r != NULL) - pool_destroy (r->pool); + struct pfm_reader *r = r_; + if (!close_reader (r)) + casereader_force_error (reader); } /* Read a single character into cur_char. */ @@ -121,14 +184,33 @@ advance (struct pfm_reader *r) { int c; - while ((c = getc (r->file)) == '\r' || c == '\n') - continue; + /* Read the next character from the file. + Ignore carriage returns entirely. + Mostly ignore new-lines, but if a new-line occurs before the + line has reached 80 bytes in length, then treat the + "missing" bytes as spaces. */ + for (;;) + { + while ((c = getc (r->file)) == '\r') + continue; + if (c != '\n') + break; + + if (r->line_length < 80) + { + c = ' '; + ungetc ('\n', r->file); + break; + } + r->line_length = 0; + } 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; + r->line_length++; } /* Skip a single character if present, and return whether it was @@ -149,12 +231,12 @@ static void read_header (struct pfm_reader *); static void read_version_data (struct pfm_reader *, struct pfm_read_info *); static void read_variables (struct pfm_reader *, struct dictionary *); static void read_value_label (struct pfm_reader *, struct dictionary *); -void dump_dictionary (struct dictionary *); +static void read_documents (struct pfm_reader *, 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) { @@ -162,33 +244,40 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, struct pfm_reader *volatile r = NULL; *dict = dict_create (); - if (!fh_open (fh, FH_REF_FILE, "portable file", "rs")) - goto error; /* Create and initialize reader. */ pool = pool_create (); r = pool_alloc (pool, sizeof *r); r->pool = pool; - if (setjmp (r->bail_out)) - goto error; - r->fh = fh; - r->file = pool_fopen (r->pool, fh_get_filename (r->fh), "rb"); + r->fh = fh_ref (fh); + r->lock = NULL; + r->file = NULL; + r->line_length = 0; 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; - /* Check that file open succeeded, prime reading. */ + /* Lock file. */ + /* 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; + + /* Open file. */ + 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 " "as a portable file: %s."), - fh_get_filename (r->fh), strerror (errno)); + 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); @@ -198,14 +287,20 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, while (match (r, 'D')) read_value_label (r, *dict); + /* Read documents. */ + if (match (r, 'E')) + read_documents (r, *dict); + /* Check that we've made it to the data. */ if (!match (r, 'F')) error (r, _("Data record expected.")); - return r; + 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: - pfm_close_reader (r); + close_reader (r); dict_destroy (*dict); *dict = NULL; return NULL; @@ -214,7 +309,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); @@ -280,7 +375,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 == '-') @@ -324,7 +419,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) @@ -343,7 +438,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; @@ -352,10 +447,32 @@ 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 * -read_pool_string (struct pfm_reader *r) +read_pool_string (struct pfm_reader *r) { char string[256]; read_string (r, string); @@ -372,7 +489,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 @@ -383,7 +500,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; @@ -397,13 +514,13 @@ 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_filename (r->fh)); + msg (SE, _("%s: Not a portable file."), fh_get_file_name (r->fh)); longjmp (r->bail_out, 1); } } @@ -413,13 +530,14 @@ 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. */ 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; @@ -428,18 +546,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 %zu."), strlen (date)); if (strlen (time) != 6) - error (r, _("Bad time string length %d."), strlen (time)); + error (r, _("Bad time string length %zu."), 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; @@ -462,25 +580,56 @@ read_version_data (struct pfm_reader *r, struct pfm_read_info *info) /* Translates a format specification read from portable file R as the three integers INTS into a normal format specifier FORMAT, checking that the format is appropriate for variable V. */ -static void +static struct fmt_spec convert_format (struct pfm_reader *r, const int portable_format[3], - struct fmt_spec *format, struct variable *v) + struct variable *v, bool *report_error) { - format->type = translate_fmt (portable_format[0]); - if (format->type == -1) - error (r, _("%s: Bad format specifier byte (%d)."), - v->name, portable_format[0]); - format->w = portable_format[1]; - format->d = portable_format[2]; - - if (!check_output_specifier (format, false) - || !check_specifier_width (format, v->width, false)) - error (r, _("%s variable %s has invalid format specifier %s."), - v->type == NUMERIC ? _("Numeric") : _("String"), - v->name, fmt_to_string (format)); + struct fmt_spec format; + bool ok; + + if (!fmt_from_io (portable_format[0], &format.type)) + { + if (*report_error) + warning (r, _("%s: Bad format specifier byte (%d). Variable " + "will be assigned a default format."), + var_get_name (v), portable_format[0]); + goto assign_default; + } + + format.w = portable_format[1]; + format.d = portable_format[2]; + + msg_disable (); + ok = (fmt_check_output (&format) + && fmt_check_width_compat (&format, var_get_width (v))); + msg_enable (); + + if (!ok) + { + if (*report_error) + { + char fmt_string[FMT_STRING_LEN_MAX + 1]; + fmt_to_string (&format, fmt_string); + if (var_is_numeric (v)) + warning (r, _("Numeric variable %s has invalid format " + "specifier %s."), + var_get_name (v), fmt_string); + else + warning (r, _("String variable %s with width %d has " + "invalid format specifier %s."), + var_get_name (v), var_get_width (v), fmt_string); + } + goto assign_default; + } + + return format; + +assign_default: + *report_error = false; + 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 @@ -488,14 +637,13 @@ 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) + 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); @@ -503,16 +651,19 @@ 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; char name[256]; int fmt[6]; struct variable *v; + struct missing_values miss; + struct fmt_spec print, write; + bool report_error = true; int j; if (!match (r, '7')) @@ -521,54 +672,78 @@ 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++) fmt[j] = read_int (r); if (!var_is_valid_name (name, false) || *name == '#' || *name == '$') - error (r, _("position %d: Invalid variable name `%s'."), i, name); + error (r, _("Invalid variable name `%s' in position %d."), name, i); 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) - error (r, _("Duplicate variable name %s."), name); + { + int i; + for (i = 1; i < 100000; i++) + { + char try_name[VAR_NAME_LEN + 1]; + sprintf (try_name, "%.*s_%d", VAR_NAME_LEN - 6, 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)); + } - convert_format (r, &fmt[0], &v->print, v); - convert_format (r, &fmt[3], &v->write, v); + print = convert_format (r, &fmt[0], v, &report_error); + write = convert_format (r, &fmt[3], v, &report_error); + var_set_print_format (v, &print); + var_set_write_format (v, &write); /* Range missing values. */ - if (match (r, 'B')) + mv_init (&miss, width); + if (match (r, 'B')) { double x = read_float (r); double y = read_float (r); - mv_add_num_range (&v->miss, x, y); + mv_add_range (&miss, x, y); } else if (match (r, 'A')) - mv_add_num_range (&v->miss, read_float (r), HIGHEST); + mv_add_range (&miss, read_float (r), HIGHEST); else if (match (r, '9')) - mv_add_num_range (&v->miss, LOWEST, read_float (r)); + mv_add_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 (&v->miss, &value); + 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); } - if (match (r, 'C')) + var_set_missing_values (v, &miss); + mv_destroy (&miss); + + if (match (r, 'C')) { char label[256]; read_string (r, label); - v->label = xstrdup (label); + var_set_label (v, label); } } - if (weight_name != NULL) + if (weight_name != NULL) { struct variable *weight_var = dict_lookup_var (dict, weight_name); if (weight_var == NULL) @@ -579,22 +754,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 (vv->type == ALPHA) + 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. */ @@ -621,10 +793,10 @@ read_value_label (struct pfm_reader *r, struct dictionary *dict) if (v[i] == NULL) error (r, _("Unknown variable %s while parsing value labels."), name); - if (v[0]->width != v[i]->width) + if (var_get_type (v[0]) != var_get_type (v[i])) error (r, _("Cannot assign value labels to %s and %s, which " - "have different variable types or widths."), - v[0]->name, v[i]->name); + "have different variable types."), + var_get_name (v[0]), var_get_name (v[i])); } n_labels = read_int (r); @@ -634,103 +806,127 @@ 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's to each variable. */ + /* 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); + + value_destroy (&val, var_get_width (v[0])); + } +} - if (!val_labs_replace (var->val_labs, val, label)) - continue; +/* Reads a set of documents from portable file R into DICT. */ +static void +read_documents (struct pfm_reader *r, struct dictionary *dict) +{ + int line_cnt; + int i; - if (var->type == NUMERIC) - error (r, _("Duplicate label for value %g for variable %s."), - val.f, var->name); - else - error (r, _("Duplicate label for value `%.*s' for variable %s."), - var->width, val.s, var->name); - } + line_cnt = read_int (r); + for (i = 0; i < line_cnt; i++) + { + char line[256]; + read_string (r, line); + dict_add_document_line (dict, line); } } -/* Reads one case from portable file R into C. */ -bool -pfm_read_case (struct pfm_reader *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; + c = case_create (r->proto); setjmp (r->bail_out); if (!r->ok) - return false; - + { + casereader_force_error (reader); + case_unref (c); + return NULL; + } + /* Check for end of file. */ if (r->cc == 'Z') - return false; + { + case_unref (c); + return NULL; + } - idx = 0; - for (i = 0; i < r->var_cnt; i++) + 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 (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 (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; -} -/* 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 c; } /* 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]; - 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); - 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 const struct casereader_class por_file_casereader_class = + { + por_file_casereader_read, + por_file_casereader_destroy, + NULL, + NULL, + };