X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fpspp-dump-sav.c;h=36cb285380f564c93edbc19be87d4f6383ba43bb;hb=refs%2Fheads%2Fctables7;hp=ceabd1d57d4b3df973bfdf6129addc1777e1e675;hpb=e2da62d735c597afeef2e0e9b36e5a4a83d7da94;p=pspp diff --git a/utilities/pspp-dump-sav.c b/utilities/pspp-dump-sav.c index ceabd1d57d..36cb285380 100644 --- a/utilities/pspp-dump-sav.c +++ b/utilities/pspp-dump-sav.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. + Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include "gl/progname.h" #include "gl/version-etc.h" #include "gl/xalloc.h" +#include "gl/xsize.h" #define ID_MAX_LEN 64 @@ -98,7 +100,7 @@ static void read_simple_compressed_data (struct sfm_reader *, int max_cases); static void read_zlib_compressed_data (struct sfm_reader *); static struct text_record *open_text_record ( - struct sfm_reader *, size_t size); + struct sfm_reader *, size_t size, size_t count); static void close_text_record (struct text_record *); static bool read_variable_to_value_pair (struct text_record *, char **key, char **value); @@ -192,7 +194,7 @@ main (int argc, char *argv[]) if (argc - optind > 1) printf ("Reading \"%s\":\n", r.file_name); - + read_header (&r); while ((rec_type = read_int (&r)) != 999) { @@ -234,9 +236,11 @@ main (int argc, char *argv[]) else if (r.compression == COMP_ZLIB) read_zlib_compressed_data (&r); + free (r.var_widths); + fclose (r.file); } - + return 0; } @@ -332,7 +336,7 @@ read_header (struct sfm_reader *r) : ""); printf ("\t%17s: %"PRId32"\n", "Weight index", weight_index); printf ("\t%17s: %"PRId32"\n", "Number of cases", ncases); - printf ("\t%17s: %g\n", "Compression bias", r->bias); + printf ("\t%17s: %.*g\n", "Compression bias", DBL_DIG + 1, r->bias); printf ("\t%17s: %s\n", "Creation date", creation_date); printf ("\t%17s: %s\n", "Creation time", creation_time); printf ("\t%17s: \"%s\"\n", "File label", file_label); @@ -378,6 +382,8 @@ format_name (int format) case 37: return "CCE"; case 38: return "EDATE"; case 39: return "SDATE"; + case 40: return "MTIME"; + case 41: return "YMDHMS"; default: return "invalid"; } } @@ -397,7 +403,7 @@ read_variable_record (struct sfm_reader *r) char name[9]; printf ("%08llx: variable record #%d\n", - (long long int) ftello (r->file), r->n_variable_records++); + (long long int) ftello (r->file), ++r->n_variable_records); width = read_int (r); has_variable_label = read_int (r); @@ -443,18 +449,14 @@ read_variable_record (struct sfm_reader *r) if (has_variable_label == 1) { long long int offset = ftello (r->file); - size_t len, read_len; - char label[255 + 1]; + enum { MAX_LABEL_LEN = 65536 }; - len = read_int (r); - - /* Read up to 255 bytes of label. */ - read_len = MIN (sizeof label - 1, len); + size_t len = read_int (r); + size_t read_len = MIN (MAX_LABEL_LEN, len); + char *label = xmalloc (read_len + 1); read_string (r, label, read_len + 1); printf("\t%08llx Variable label: \"%s\"\n", offset, label); - - /* Skip unread label bytes. */ - skip_bytes (r, len - read_len); + free (label); /* Skip label padding up to multiple of 4 bytes. */ skip_bytes (r, ROUND_UP (len, 4) - len); @@ -476,11 +478,11 @@ read_variable_record (struct sfm_reader *r) { double low = read_float (r); double high = read_float (r); - printf (" %g...%g", low, high); + printf (" %.*g...%.*g", DBL_DIG + 1, low, DBL_DIG + 1, high); missing_value_code = -missing_value_code - 2; } for (i = 0; i < missing_value_code; i++) - printf (" %g", read_float (r)); + printf (" %.*g", DBL_DIG + 1, read_float (r)); } else if (width > 0) { @@ -509,7 +511,7 @@ print_untyped_value (struct sfm_reader *r, char raw_value[8]) if (!isprint (raw_value[n_printable])) break; - printf ("%g/\"%.*s\"", value, n_printable, raw_value); + printf ("%.*g/\"%.*s\"", DBL_DIG + 1, value, n_printable, raw_value); } /* Reads value labels from sysfile R and inserts them into the @@ -517,14 +519,14 @@ print_untyped_value (struct sfm_reader *r, char raw_value[8]) static void read_value_label_record (struct sfm_reader *r) { - int label_cnt, var_cnt; + int n_labels, n_vars; int i; printf ("%08llx: value labels record\n", (long long int) ftello (r->file)); /* Read number of labels. */ - label_cnt = read_int (r); - for (i = 0; i < label_cnt; i++) + n_labels = read_int (r); + for (i = 0; i < n_labels; i++) { char raw_value[8]; unsigned char label_len; @@ -557,8 +559,8 @@ read_value_label_record (struct sfm_reader *r) /* Read number of variables associated with value label from type 4 record. */ printf ("\t%08llx: apply to variables", (long long int) ftello (r->file)); - var_cnt = read_int (r); - for (i = 0; i < var_cnt; i++) + n_vars = read_int (r); + for (i = 0; i < n_vars; i++) printf (" #%d", read_int (r)); putchar ('\n'); } @@ -605,12 +607,6 @@ read_extension_record (struct sfm_reader *r) read_machine_float_info (r, size, count); return; - case 5: - /* Variable sets information. We don't use these yet. - They only apply to GUIs; see VARSETS on the APPLY - DICTIONARY command in SPSS documentation. */ - break; - case 6: /* DATE variable information. We don't use it yet, but we should. */ @@ -718,20 +714,20 @@ read_machine_float_info (struct sfm_reader *r, size_t size, size_t count) sys_error (r, "Bad size (%zu) or count (%zu) on extension 4.", size, count); - printf ("\tsysmis: %g (%a)\n", sysmis, sysmis); + printf ("\tsysmis: %.*g (%a)\n", DBL_DIG + 1, sysmis, sysmis); if (sysmis != SYSMIS) - sys_warn (r, "File specifies unexpected value %g (%a) as %s.", - sysmis, sysmis, "SYSMIS"); + sys_warn (r, "File specifies unexpected value %.*g (%a) as %s.", + DBL_DIG + 1, sysmis, sysmis, "SYSMIS"); - printf ("\thighest: %g (%a)\n", highest, highest); + printf ("\thighest: %.*g (%a)\n", DBL_DIG + 1, highest, highest); if (highest != HIGHEST) - sys_warn (r, "File specifies unexpected value %g (%a) as %s.", - highest, highest, "HIGHEST"); + sys_warn (r, "File specifies unexpected value %.*g (%a) as %s.", + DBL_DIG + 1, highest, highest, "HIGHEST"); - printf ("\tlowest: %g (%a)\n", lowest, lowest); + printf ("\tlowest: %.*g (%a)\n", DBL_DIG + 1, lowest, lowest); if (lowest != LOWEST && lowest != SYSMIS) - sys_warn (r, "File specifies unexpected value %g (%a) as %s.", - lowest, lowest, "LOWEST"); + sys_warn (r, "File specifies unexpected value %.*g (%a) as %s.", + DBL_DIG + 1, lowest, lowest, "LOWEST"); } static void @@ -742,7 +738,7 @@ read_extra_product_info (struct sfm_reader *r, const char *s; printf ("%08llx: extra product info\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); + text = open_text_record (r, size, count); s = text_get_all (text); print_string (s, strlen (s)); close_text_record (text); @@ -756,7 +752,7 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) printf ("%08llx: multiple response sets\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); + text = open_text_record (r, size, count); for (;;) { const char *name; @@ -767,6 +763,9 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) const char *label; const char *variables; + while (text_match (text, '\n')) + continue; + name = text_tokenize (text, '='); if (name == NULL) break; @@ -801,7 +800,11 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) } number = text_tokenize (text, ' '); - if (!strcmp (number, "11")) + if (!number) + sys_warn (r, "Missing label source value " + "following `E' at offset %zu in MRSETS record", + text_pos (text)); + else if (!strcmp (number, "11")) label_from_var_label = true; else if (strcmp (number, "1")) sys_warn (r, "Unexpected label source value `%s' " @@ -828,12 +831,6 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) break; variables = text_tokenize (text, '\n'); - if (variables == NULL) - { - sys_warn (r, "missing variable names following label " - "at offset %zu in mrsets record", text_pos (text)); - break; - } printf ("\t\"%s\": multiple %s set", name, type == MRSET_MC ? "category" : "dichotomy"); @@ -845,7 +842,10 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) printf (", label \"%s\"", label); if (label_from_var_label) printf (", label from variable label"); - printf(", variables \"%s\"\n", variables); + if (variables != NULL) + printf(", variables \"%s\"\n", variables); + else + printf(", no variables\n"); } close_text_record (text); } @@ -912,7 +912,7 @@ read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count) printf ("%08llx: long variable names (short => long)\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); + text = open_text_record (r, size, count); while (read_variable_to_value_pair (text, &var, &long_name)) printf ("\t%s => %s\n", var, long_name); close_text_record (text); @@ -929,7 +929,7 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count) printf ("%08llx: very long strings (variable => length)\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); + text = open_text_record (r, size, count); while (read_variable_to_value_pair (text, &var, &length_s)) printf ("\t%s => %d\n", var, atoi (length_s)); close_text_record (text); @@ -942,17 +942,17 @@ read_attributes (struct sfm_reader *r, struct text_record *text, const char *key; int index; - for (;;) + for (;;) { key = text_tokenize (text, '('); if (key == NULL) return true; - + for (index = 1; ; index++) { /* Parse the value. */ const char *value = text_tokenize (text, '\n'); - if (value == NULL) + if (value == NULL) { sys_warn (r, "%s: Error parsing attribute value %s[%d]", variable, key, index); @@ -972,7 +972,7 @@ read_attributes (struct sfm_reader *r, struct text_record *text, } if (text_match (text, '/')) - return true; + return true; } } @@ -1002,12 +1002,12 @@ read_ncases64 (struct sfm_reader *r, size_t size, size_t count) } static void -read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count) +read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count) { struct text_record *text; - + printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); + text = open_text_record (r, size, count); read_attributes (r, text, "datafile"); close_text_record (text); } @@ -1020,6 +1020,8 @@ read_character_encoding (struct sfm_reader *r, size_t size, size_t count) read_string (r, encoding, count + 1); printf ("%08llx: Character Encoding: %s\n", posn, encoding); + + free (encoding); } static void @@ -1194,17 +1196,17 @@ read_unknown_extension (struct sfm_reader *r, size_t size, size_t count) } static void -read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) +read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) { struct text_record *text; - + printf ("%08llx: variable attributes\n", (long long int) ftello (r->file)); - text = open_text_record (r, size * count); - for (;;) + text = open_text_record (r, size, count); + for (;;) { const char *variable = text_tokenize (text, ':'); if (variable == NULL || !read_attributes (r, text, variable)) - break; + break; } close_text_record (text); } @@ -1229,7 +1231,7 @@ read_simple_compressed_data (struct sfm_reader *r, int max_cases) { printf ("%08llx: case %d's uncompressible data begins\n", (long long int) ftello (r->file), case_num); - for (i = 0; i < r->n_var_widths; ) + for (i = 0; i < r->n_var_widths;) { int width = r->var_widths[i]; char raw_value[8]; @@ -1254,7 +1256,7 @@ read_simple_compressed_data (struct sfm_reader *r, int max_cases) switch (opcode) { default: - printf ("%g", opcode - r->bias); + printf ("%.*g", DBL_DIG + 1, opcode - r->bias); if (width != 0) printf (", but this is a string variable (width=%d)", width); printf ("\n"); @@ -1392,18 +1394,23 @@ struct text_record size_t pos; /* Current position in buffer. */ }; -/* Reads SIZE bytes into a text record for R, +/* Reads SIZE * COUNT bytes into a text record for R, and returns the new text record. */ static struct text_record * -open_text_record (struct sfm_reader *r, size_t size) +open_text_record (struct sfm_reader *r, size_t size, size_t count) { struct text_record *text = xmalloc (sizeof *text); - char *buffer = xmalloc (size + 1); - read_bytes (r, buffer, size); - buffer[size] = '\0'; + + if (size_overflow_p (xsum (1, xtimes (size, count)))) + sys_error (r, "Extension record too large."); + + size_t n_bytes = size * count; + char *buffer = xmalloc (n_bytes + 1); + read_bytes (r, buffer, n_bytes); + buffer[n_bytes] = '\0'; text->reader = r; text->buffer = buffer; - text->size = size; + text->size = n_bytes; text->pos = 0; return text; } @@ -1433,9 +1440,9 @@ text_tokenize (struct text_record *text, int delimiter) } static bool -text_match (struct text_record *text, int c) +text_match (struct text_record *text, int c) { - if (text->pos < text->size && text->buffer[text->pos] == c) + if (text->pos < text->size && text->buffer[text->pos] == c) { text->pos++; return true; @@ -1583,10 +1590,10 @@ sys_error (struct sfm_reader *r, const char *format, ...) too. */ static inline bool read_bytes_internal (struct sfm_reader *r, bool eof_is_ok, - void *buf, size_t byte_cnt) + void *buf, size_t n_bytes) { - size_t bytes_read = fread (buf, 1, byte_cnt, r->file); - if (bytes_read == byte_cnt) + size_t bytes_read = fread (buf, 1, n_bytes, r->file); + if (bytes_read == n_bytes) return true; else if (ferror (r->file)) sys_error (r, "System error: %s.", strerror (errno)); @@ -1599,9 +1606,9 @@ read_bytes_internal (struct sfm_reader *r, bool eof_is_ok, /* Reads BYTE_CNT into BUF. Aborts upon I/O error or if end-of-file is encountered. */ static void -read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) +read_bytes (struct sfm_reader *r, void *buf, size_t n_bytes) { - read_bytes_internal (r, false, buf, byte_cnt); + read_bytes_internal (r, false, buf, n_bytes); } /* Reads BYTE_CNT bytes into BUF. @@ -1609,9 +1616,9 @@ read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) Returns false if an immediate end-of-file is encountered. Aborts if an I/O error or a partial read occurs. */ static bool -try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) +try_read_bytes (struct sfm_reader *r, void *buf, size_t n_bytes) { - return read_bytes_internal (r, true, buf, byte_cnt); + return read_bytes_internal (r, true, buf, n_bytes); } /* Reads a 32-bit signed integer from R and returns its value in