/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
Code for parsing floating-point numbers adapted from GNU C
library.
#include <math.h>
#include <setjmp.h>
#include "alloc.h"
-#include "bool.h"
+#include <stdbool.h>
#include "case.h"
#include "dictionary.h"
#include "file-handle.h"
#include "format.h"
-#include "getline.h"
+#include "getl.h"
#include "hash.h"
#include "magic.h"
#include "misc.h"
#include "value-labels.h"
#include "var.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
#include "debug-print.h"
+/* portable_to_local[PORTABLE] translates the given portable
+ character into the local character set. */
+static const char portable_to_local[256] =
+ {
+ " "
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
+ "<(+|&[]!$*);^-/|,%_>?`:$@'=\" ~- 0123456789 -() {}\\ "
+ " "
+ };
+
/* Portable file reader. */
struct pfm_reader
{
struct file_handle *fh; /* File handle. */
FILE *file; /* File stream. */
char cc; /* Current character. */
- unsigned char *trans; /* 256-byte character set translation table. */
-
+ 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. */
e.class = ME;
getl_location (&e.where.filename, &e.where.line_number);
- filename = handle_get_filename (r->fh);
+ 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));
struct pfm_reader *volatile r = NULL;
*dict = dict_create ();
- if (!fh_open (fh, "portable file", "rs"))
+ if (!fh_open (fh, FH_REF_FILE, "portable file", "rs"))
goto error;
/* Create and initialize reader. */
if (setjmp (r->bail_out))
goto error;
r->fh = fh;
- r->file = pool_fopen (r->pool, handle_get_filename (r->fh), "rb");
+ r->file = pool_fopen (r->pool, fh_get_filename (r->fh), "rb");
r->weight_index = -1;
r->trans = NULL;
r->var_cnt = 0;
{
msg (ME, _("An error occurred while opening \"%s\" for reading "
"as a portable file: %s."),
- handle_get_filename (r->fh), strerror (errno));
+ fh_get_filename (r->fh), strerror (errno));
err_cond_fail ();
goto error;
}
/* Reads a string and returns a copy of it allocated from R's
pool. */
-static unsigned char *
+static char *
read_pool_string (struct pfm_reader *r)
{
char string[256];
static void
read_header (struct pfm_reader *r)
{
- /* portable_to_local[PORTABLE] translates the given portable
- character into the local character set. */
- static const unsigned char portable_to_local[256] =
- {
- " "
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
- "<(+|&[]!$*);^-/|,%_>?`:$@'=\" ~- 0123456789 -() {}\\ "
- " "
- };
-
- unsigned char *trans;
+ char *trans;
int i;
/* Read and ignore vanity splash strings. */
for (i = 0; i < 8; i++)
if (!match (r, "SPSSPORT"[i]))
{
- msg (SE, _("%s: Not a portable file."), handle_get_filename (r->fh));
+ msg (SE, _("%s: Not a portable file."), fh_get_filename (r->fh));
longjmp (r->bail_out, 1);
}
}
static void
read_version_data (struct pfm_reader *r, struct pfm_read_info *info)
{
- char *date, *time, *product, *subproduct;
+ static char empty_string[] = "";
+ char *date, *time, *product, *author, *subproduct;
int i;
/* Read file. */
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) : (unsigned char *) "";
- subproduct
- = match (r, '3') ? read_pool_string (r) : (unsigned char *) "";
+ product = match (r, '1') ? read_pool_string (r) : empty_string;
+ author = match (r, '2') ? read_pool_string (r) : empty_string;
+ subproduct = match (r, '3') ? read_pool_string (r) : empty_string;
/* Validate file. */
if (strlen (date) != 8)
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);
- r->widths = pool_alloc (r->pool, sizeof *r->widths * 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);
fmt[j] = read_int (r);
if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
- error (r, _("position %d: Invalid variable name `%s'."), name);
+ error (r, _("position %d: Invalid variable name `%s'."), i, name);
str_uppercase (name);
if (width < 0 || width > 255)
convert_format (r, &fmt[3], &v->write, v);
/* Range missing values. */
- if (match (r, 'B'))
- {
- v->miss_type = MISSING_RANGE;
- v->missing[0] = parse_value (r, v);
- v->missing[1] = parse_value (r, v);
- }
+ if (match (r, 'B'))
+ {
+ double x = read_float (r);
+ double y = read_float (r);
+ mv_add_num_range (&v->miss, x, y);
+ }
else if (match (r, 'A'))
- {
- v->miss_type = MISSING_HIGH;
- v->missing[0] = parse_value (r, v);
- }
+ mv_add_num_range (&v->miss, read_float (r), HIGHEST);
else if (match (r, '9'))
- {
- v->miss_type = MISSING_LOW;
- v->missing[0] = parse_value (r, v);
- }
+ mv_add_num_range (&v->miss, LOWEST, read_float (r));
/* Single missing values. */
- while (match (r, '8'))
- {
- static const int map_next[MISSING_COUNT] =
- {
- MISSING_1, MISSING_2, MISSING_3, -1,
- MISSING_RANGE_1, MISSING_LOW_1, MISSING_HIGH_1,
- -1, -1, -1,
- };
-
- static const int map_ofs[MISSING_COUNT] =
- {
- -1, 0, 1, 2, -1, -1, -1, 2, 1, 1,
- };
-
- v->miss_type = map_next[v->miss_type];
- if (v->miss_type == -1)
- error (r, _("Bad missing values for %s."), v->name);
-
- assert (map_ofs[v->miss_type] != -1);
- v->missing[map_ofs[v->miss_type]] = parse_value (r, v);
- }
+ while (match (r, '8'))
+ {
+ union value value = parse_value (r, v);
+ mv_add_value (&v->miss, &value);
+ }
if (match (r, 'C'))
{
int i;
nv = read_int (r);
- v = pool_alloc (r->pool, sizeof *v * nv);
+ v = pool_nalloc (r->pool, nv, sizeof *v);
for (i = 0; i < nv; i++)
{
char name[256];
return true;
}
+
+/* Returns true if FILE is an SPSS portable file,
+ false otherwise. */
+bool
+pfm_detect (FILE *file)
+{
+ unsigned char header[464];
+ char trans[256];
+ int cooked_cnt, raw_cnt;
+ int i;
+
+ cooked_cnt = raw_cnt = 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;
+ }
+
+ memset (trans, 0, 256);
+ 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;
+
+ return true;
+}