/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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
#include <ctype.h>
#include <errno.h>
+#include <getopt.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
-#include <data/val-type.h>
-#include <libpspp/compiler.h>
-#include <libpspp/float-format.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/misc.h>
+#include "data/val-type.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/misc.h"
-#include "error.h"
-#include "minmax.h"
-#include "progname.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
+#include "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/progname.h"
+#include "gl/version-etc.h"
+#include "gl/xalloc.h"
#define ID_MAX_LEN 64
size_t size, size_t count);
static void read_unknown_extension (struct sfm_reader *,
size_t size, size_t count);
-static void read_compressed_data (struct sfm_reader *);
+static void read_compressed_data (struct sfm_reader *, int max_cases);
static struct text_record *open_text_record (
struct sfm_reader *, size_t size);
static const char *text_parse_counted_string (struct text_record *);
static size_t text_pos (const struct text_record *);
-static void usage (int exit_code);
+static void usage (void);
static void sys_warn (struct sfm_reader *, const char *, ...)
PRINTF_FORMAT (2, 3);
static void sys_error (struct sfm_reader *, const char *, ...)
int
main (int argc, char *argv[])
{
+ int max_cases = 0;
struct sfm_reader r;
int i;
set_program_name (argv[0]);
- if (argc < 2)
- usage (EXIT_FAILURE);
- for (i = 1; i < argc; i++)
+ for (;;)
+ {
+ static const struct option long_options[] =
+ {
+ { "data", optional_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 },
+ };
+
+ int c;
+
+ c = getopt_long (argc, argv, "d::hv", long_options, NULL);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 'd':
+ max_cases = optarg ? atoi (optarg) : INT_MAX;
+ break;
+
+ case 'v':
+ version_etc (stdout, "pspp-dump-sav", PACKAGE_NAME, PACKAGE_VERSION,
+ "Ben Pfaff", "John Darrington", NULL_SENTINEL);
+ exit (EXIT_SUCCESS);
+
+ case 'h':
+ usage ();
+ exit (EXIT_SUCCESS);
+
+ default:
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ if (optind == argc)
+ error (1, 0, "at least one non-option argument is required; "
+ "use --help for help");
+
+ for (i = optind; i < argc; i++)
{
int rec_type;
r.var_widths = 0;
r.compressed = false;
- if (argc > 2)
+ if (argc - optind > 1)
printf ("Reading \"%s\":\n", r.file_name);
read_header (&r);
break;
case 4:
- sys_error (&r, _("Misplaced type 4 record."));
+ sys_error (&r, "Misplaced type 4 record.");
case 6:
read_document_record (&r);
break;
default:
- sys_error (&r, _("Unrecognized record type %d."), rec_type);
+ sys_error (&r, "Unrecognized record type %d.", rec_type);
}
}
printf ("%08llx: end-of-dictionary record "
(long long int) ftello (r.file),
(long long int) ftello (r.file) + 4);
- if (r.compressed)
- read_compressed_data (&r);
+ if (r.compressed && max_cases > 0)
+ read_compressed_data (&r, max_cases);
fclose (r.file);
}
char eye_catcher[61];
uint8_t raw_layout_code[4];
int32_t layout_code;
- int32_t nominal_case_size;
int32_t compressed;
int32_t weight_index;
int32_t ncases;
read_string (r, eye_catcher, sizeof eye_catcher);
if (strcmp ("$FL2", rec_type) != 0)
- sys_error (r, _("This is not an SPSS system file."));
+ sys_error (r, "This is not an SPSS system file.");
/* Identify integer format. */
read_bytes (r, raw_layout_code, sizeof raw_layout_code);
&r->integer_format))
|| (r->integer_format != INTEGER_MSB_FIRST
&& r->integer_format != INTEGER_LSB_FIRST))
- sys_error (r, _("This is not an SPSS system file."));
+ sys_error (r, "This is not an SPSS system file.");
layout_code = integer_get (r->integer_format,
raw_layout_code, sizeof raw_layout_code);
- nominal_case_size = read_int (r);
+ read_int (r); /* Nominal case size (not actually useful). */
compressed = read_int (r);
weight_index = read_int (r);
ncases = read_int (r);
read_bytes (r, raw_bias, sizeof raw_bias);
if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
{
- sys_warn (r, _("Compression bias is not the usual "
- "value of 100, or system file uses unrecognized "
- "floating-point format."));
+ sys_warn (r, "Compression bias is not the usual value of 100, or system "
+ "file uses unrecognized floating-point format.");
if (r->integer_format == INTEGER_MSB_FIRST)
r->float_format = FLOAT_IEEE_DOUBLE_BE;
else
/* Get variable label, if any. */
if (has_variable_label != 0 && has_variable_label != 1)
- sys_error (r, _("Variable label indicator field is not 0 or 1."));
+ sys_error (r, "Variable label indicator field is not 0 or 1.");
if (has_variable_label == 1)
{
long long int offset = ftello (r->file);
{
if (missing_value_code < -3 || missing_value_code > 3
|| missing_value_code == -1)
- sys_error (r, _("Numeric missing value indicator field is not "
- "-3, -2, 0, 1, 2, or 3."));
+ sys_error (r, "Numeric missing value indicator field is not "
+ "-3, -2, 0, 1, 2, or 3.");
if (missing_value_code < 0)
{
double low = read_float (r);
else if (width > 0)
{
if (missing_value_code < 1 || missing_value_code > 3)
- sys_error (r, _("String missing value indicator field is not "
- "0, 1, 2, or 3."));
+ sys_error (r, "String missing value indicator field is not "
+ "0, 1, 2, or 3.");
for (i = 0; i < missing_value_code; i++)
{
char string[9];
double value;
value = float_get_double (r->float_format, raw_value);
- for (n_printable = 0; n_printable < sizeof raw_value; n_printable++)
+ for (n_printable = 0; n_printable < 8; n_printable++)
if (!isprint (raw_value[n_printable]))
break;
/* Read record type of type 4 record. */
if (read_int (r) != 4)
- sys_error (r, _("Variable index record (type 4) does not immediately "
- "follow value label record (type 3) as it should."));
+ sys_error (r, "Variable index record (type 4) does not immediately "
+ "follow value label record (type 3) as it should.");
/* Read number of variables associated with value label from type 4
record. */
return;
default:
- sys_warn (r, _("Unrecognized record type 7, subtype %d."), subtype);
+ sys_warn (r, "Unrecognized record type 7, subtype %d.", subtype);
read_unknown_extension (r, size, count);
return;
}
printf ("%08llx: machine integer info\n", offset);
if (size != 4 || count != 8)
- sys_error (r, _("Bad size (%zu) or count (%zu) field on record type 7, "
- "subtype 3."),
- size, count);
+ sys_error (r, "Bad size (%zu) or count (%zu) field on record type 7, "
+ "subtype 3.", size, count);
printf ("\tVersion: %d.%d.%d\n",
version_major, version_minor, version_revision);
printf ("%08llx: machine float info\n", offset);
if (size != 8 || count != 3)
- sys_error (r, _("Bad size (%zu) or count (%zu) on extension 4."),
+ sys_error (r, "Bad size (%zu) or count (%zu) on extension 4.",
size, count);
- printf ("\tsysmis: %g\n", sysmis);
+ printf ("\tsysmis: %g (%a)\n", sysmis, sysmis);
if (sysmis != SYSMIS)
- sys_warn (r, _("File specifies unexpected value %g as %s."),
- sysmis, "SYSMIS");
+ sys_warn (r, "File specifies unexpected value %g (%a) as %s.",
+ sysmis, sysmis, "SYSMIS");
- printf ("\thighest: %g\n", highest);
+ printf ("\thighest: %g (%a)\n", highest, highest);
if (highest != HIGHEST)
- sys_warn (r, _("File specifies unexpected value %g as %s."),
- highest, "HIGHEST");
+ sys_warn (r, "File specifies unexpected value %g (%a) as %s.",
+ highest, highest, "HIGHEST");
- printf ("\tlowest: %g\n", lowest);
- if (lowest != LOWEST)
- sys_warn (r, _("File specifies unexpected value %g as %s."),
- lowest, "LOWEST");
+ printf ("\tlowest: %g (%a)\n", lowest, lowest);
+ if (lowest != LOWEST && lowest != SYSMIS)
+ sys_warn (r, "File specifies unexpected value %g (%a) as %s.",
+ lowest, lowest, "LOWEST");
}
/* Read record type 7, subtype 7. */
if (!text_match (text, ' '))
{
- sys_warn (r, _("Missing space following `%c' at offset %zu "
- "in MRSETS record"), 'E', text_pos (text));
+ sys_warn (r, "Missing space following `%c' at offset %zu "
+ "in MRSETS record", 'E', text_pos (text));
break;
}
if (!strcmp (number, "11"))
label_from_var_label = true;
else if (strcmp (number, "1"))
- sys_warn (r, _("Unexpected label source value `%s' "
- "following `E' at offset %zu in MRSETS record"),
+ sys_warn (r, "Unexpected label source value `%s' "
+ "following `E' at offset %zu in MRSETS record",
number, text_pos (text));
}
(long long int) ftello (r->file));
if (size != 4)
{
- sys_warn (r, _("Bad size %zu on extension 11."), size);
+ sys_warn (r, "Bad size %zu on extension 11.", size);
skip_bytes (r, size * count);
return;
}
includes_width = false;
else
{
- sys_warn (r, _("Extension 11 has bad count %zu (for %zu variables)."),
+ sys_warn (r, "Extension 11 has bad count %zu (for %zu variables.",
count, n_vars);
skip_bytes (r, size * count);
return;
const char *value = text_tokenize (text, '\n');
if (value == NULL)
{
- sys_warn (r, _("%s: Error parsing attribute value %s[%d]"),
+ sys_warn (r, "%s: Error parsing attribute value %s[%d]",
variable, key, index);
return false;
}
if (strlen (value) < 2
|| value[0] != '\'' || value[strlen (value) - 1] != '\'')
- sys_warn (r, _("%s: Attribute value %s[%d] is not quoted: %s"),
+ sys_warn (r, "%s: Attribute value %s[%d] is not quoted: %s",
variable, key, index, value);
else
printf ("\t%s: %s[%d] = \"%.*s\"\n",
if (size != 8)
{
- sys_warn (r, _("Bad size %zu for extended number of cases."), size);
+ sys_warn (r, "Bad size %zu for extended number of cases.", size);
skip_bytes (r, size * count);
return;
}
if (count != 2)
{
- sys_warn (r, _("Bad count %zu for extended number of cases."), size);
+ sys_warn (r, "Bad count %zu for extended number of cases.", size);
skip_bytes (r, size * count);
return;
}
/* Read variable name. */
var_name_len = read_int (r);
if (var_name_len > ID_MAX_LEN)
- sys_error (r, _("Variable name length in long string value label "
- "record (%d) exceeds %d-byte limit."),
+ sys_error (r, "Variable name length in long string value label "
+ "record (%d) exceeds %d-byte limit.",
var_name_len, ID_MAX_LEN);
read_string (r, var_name, var_name_len + 1);
buffer = xmalloc (count);
read_bytes (r, buffer, count);
if (memchr (buffer, 0, count) == 0)
- for (i = 0; i < count; i++)
- {
- unsigned char c = buffer[i];
-
- if (c == '\\')
- printf ("\\\\");
- else if (c == '\n' || isprint (c))
- putchar (c);
- else
- printf ("\\%02x", c);
- }
+ {
+ for (i = 0; i < count; i++)
+ {
+ unsigned char c = buffer[i];
+
+ if (c == '\\')
+ printf ("\\\\");
+ else if (c == '\n' || isprint (c))
+ putchar (c);
+ else
+ printf ("\\%02x", c);
+ }
+ putchar ('\n');
+ }
else
hex_dump (0, buffer, count);
free (buffer);
}
static void
-read_compressed_data (struct sfm_reader *r)
+read_compressed_data (struct sfm_reader *r, int max_cases)
{
enum { N_OPCODES = 8 };
uint8_t opcodes[N_OPCODES];
opcode_idx = N_OPCODES;
opcode_ofs = 0;
case_num = 0;
- for (case_num = 0; ; case_num++)
+ for (case_num = 0; case_num < max_cases; case_num++)
{
printf ("%08llx: case %d's uncompressible data begins\n",
(long long int) ftello (r->file), case_num);
}
\f
static void
-usage (int exit_code)
+usage (void)
{
- printf ("usage: %s SYSFILE...\n"
- "where each SYSFILE is the name of a system file\n",
- program_name);
- exit (exit_code);
+ printf ("\
+%s, a utility for dissecting system files.\n\
+Usage: %s [OPTION]... SYSFILE...\n\
+where each SYSFILE is the name of a system file.\n\
+\n\
+Options:\n\
+ --data[=MAXCASES] print (up to MAXCASES cases of) compressed data\n\
+ --help display this help and exit\n\
+ --version output version information and exit\n",
+ program_name, program_name);
}
/* Displays a corruption message. */
if (bytes_read == byte_cnt)
return true;
else if (ferror (r->file))
- sys_error (r, _("System error: %s."), strerror (errno));
+ sys_error (r, "System error: %s.", strerror (errno));
else if (!eof_is_ok || bytes_read != 0)
- sys_error (r, _("Unexpected end of file."));
+ sys_error (r, "Unexpected end of file.");
else
return false;
}