- Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010 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
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 <data/value-labels.h>
#include <data/variable.h>
#include <libpspp/compiler.h>
#include <data/value-labels.h>
#include <data/variable.h>
#include <libpspp/compiler.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
/* portable_to_local[PORTABLE] translates the given portable
character into the local character set. */
/* portable_to_local[PORTABLE] translates the given portable
character into the local character set. */
jmp_buf bail_out; /* longjmp() target for error handling. */
struct file_handle *fh; /* File handle. */
jmp_buf bail_out; /* longjmp() target for error handling. */
struct file_handle *fh; /* File handle. */
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. */
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. */
- ds_put_format (&text, _("portable file %s corrupt at offset 0x%lx: "),
- fh_get_file_name (r->fh), ftell (r->file));
+ ds_put_format (&text, _("portable file %s corrupt at offset 0x%llx: "),
+ fh_get_file_name (r->fh), (long long int) ftello (r->file));
- ds_put_format (&text, _("reading portable file %s at offset 0x%lx: "),
- fh_get_file_name (r->fh), ftell (r->file));
+ ds_put_format (&text, _("reading portable file %s at offset 0x%llx: "),
+ fh_get_file_name (r->fh), (long long int) ftello (r->file));
/* Create and initialize reader. */
pool = pool_create ();
r = pool_alloc (pool, sizeof *r);
r->pool = pool;
/* Create and initialize reader. */
pool = pool_create ();
r = pool_alloc (pool, sizeof *r);
r->pool = pool;
- /* Check that file open succeeded. */
+ /* 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");
"as a portable file: %s."),
fh_get_file_name (r->fh), strerror (errno));
goto error;
"as a portable file: %s."),
fh_get_file_name (r->fh), strerror (errno));
goto error;
- r->value_cnt = dict_get_next_value_idx (*dict);
- return casereader_create_sequential (NULL, r->value_cnt, CASENUMBER_MAX,
+ r->proto = caseproto_ref_pool (dict_get_proto (*dict), r->pool);
+ return casereader_create_sequential (NULL, r->proto, CASENUMBER_MAX,
+
+/* 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;
+}
+
+
+
- static char empty_string[] = "";
- char *date, *time, *product, *author, *subproduct;
+ static const char empty_string[] = "";
+ char *date, *time;
+ const char *product, *author, *subproduct;
r->var_cnt = read_int (r);
if (r->var_cnt <= 0)
error (r, _("Invalid number of variables %d."), r->var_cnt);
r->var_cnt = read_int (r);
if (r->var_cnt <= 0)
error (r, _("Invalid number of variables %d."), r->var_cnt);
- char try_name[LONG_NAME_LEN + 1];
- sprintf (try_name, "%.*s_%d", LONG_NAME_LEN - 6, name, i);
+ char try_name[VAR_NAME_LEN + 1];
+ sprintf (try_name, "%.*s_%d", VAR_NAME_LEN - 6, name, i);
var_set_write_format (v, &write);
/* Range missing values. */
var_set_write_format (v, &write);
/* Range missing values. */
- union value value = parse_value (r, v);
+ int mv_width = MIN (width, 8);
+ union value value;
+
+ parse_value (r, mv_width, &value);
+ value_resize (&value, mv_width, width);
-/* 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)
- 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, ' ');
- if (!var_is_long_string (var))
- var_replace_value_label (var, &val, label);
- }
+ value_destroy (&val, var_get_width (v[0]));
-/* Reads one case from portable file R into C. */
-static bool
-por_file_casereader_read (struct casereader *reader, void *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_)
- char string[256];
- read_string (r, string);
- buf_copy_str_rpad (case_data_rw_idx (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, ' ');
- 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++;
+ }
{
por_file_casereader_read,
por_file_casereader_destroy,
{
por_file_casereader_read,
por_file_casereader_destroy,