#include <setjmp.h>
#include <stdlib.h>
-#include <libpspp/alloc.h>
#include <libpspp/assertion.h>
#include <libpspp/message.h>
#include <libpspp/compiler.h>
-#include <libpspp/magic.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
#include <libpspp/str.h>
#include "inttostr.h"
#include "minmax.h"
#include "unlocked-io.h"
+#include "xalloc.h"
#include "xsize.h"
#include "gettext.h"
/* File state. */
struct file_handle *fh; /* File handle. */
+ struct fh_lock *lock; /* Mutual exclusion for file handle. */
FILE *file; /* File stream. */
bool error; /* I/O or corruption error? */
size_t value_cnt; /* Number of "union value"s in struct case. */
int claimed_oct_cnt;
int rec_type;
- if (!fh_open (fh, FH_REF_FILE, "system file", "rs"))
- return NULL;
-
*dict = dict_create ();
/* Create and initialize reader. */
r = pool_create_container (struct sfm_reader, pool);
- r->fh = fh;
- r->file = fn_open (fh_get_file_name (fh), "rb");
+ r->fh = fh_ref (fh);
+ r->lock = NULL;
+ r->file = NULL;
r->error = false;
r->oct_cnt = 0;
r->has_long_var_names = false;
r->opcode_idx = sizeof r->opcodes;
+ /* 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_("system file"), FH_ACC_READ, false);
+ if (r->lock == NULL)
+ goto error;
+
+ r->file = fn_open (fh_get_file_name (fh), "rb");
+ if (r->file == NULL)
+ {
+ msg (ME, _("Error opening \"%s\" for reading as a system file: %s."),
+ fh_get_file_name (r->fh), strerror (errno));
+ goto error;
+ }
+
/* Initialize info. */
if (info == NULL)
info = &local_info;
memset (info, 0, sizeof *info);
if (setjmp (r->bail_out))
- {
- close_reader (r);
- dict_destroy (*dict);
- *dict = NULL;
- return NULL;
- }
+ goto error;
- if (r->file == NULL)
- {
- msg (ME, _("Error opening \"%s\" for reading as a system file: %s."),
- fh_get_file_name (r->fh), strerror (errno));
- longjmp (r->bail_out, 1);
- }
/* Read header. */
read_header (r, *dict, &weight_idx, &claimed_oct_cnt, info);
(NULL, r->value_cnt,
r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
&sys_file_casereader_class, r);
+
+error:
+ close_reader (r);
+ dict_destroy (*dict);
+ *dict = NULL;
+ return NULL;
}
/* Closes a system file after we're done with it.
r->file = NULL;
}
- if (r->fh != NULL)
- fh_close (r->fh, "system file", "rs");
+ fh_unlock (r->lock);
+ fh_unref (r->fh);
error = r->error;
pool_destroy (r->pool);
len = read_int (r);
if (len >= sizeof label)
- sys_error (r, _("Variable %s has label of invalid length %u."),
- name, (unsigned int) len);
+ sys_error (r, _("Variable %s has label of invalid length %zu."),
+ name, len);
read_string (r, label, len + 1);
var_set_label (var, label);
bool ok;
if (!fmt_from_io (raw_type, &f.type))
- sys_error (r, _("Unknown variable format %d."), (int) raw_type);
+ sys_error (r, _("Unknown variable format %"PRIu8"."), raw_type);
f.w = w;
f.d = d;
int expected_integer_format;
if (size != 4 || count != 8)
- sys_error (r, _("Bad size (%u) or count (%u) field on record type 7, "
+ sys_error (r, _("Bad size (%zu) or count (%zu) field on record type 7, "
"subtype 3."),
- (unsigned int) size, (unsigned int) count);
+ size, count);
/* Save version info. */
info->version_major = version_major;
double lowest = read_float (r);
if (size != 8 || count != 3)
- sys_error (r, _("Bad size (%u) or count (%u) on extension 4."),
- (unsigned int) size, (unsigned int) count);
+ sys_error (r, _("Bad size (%zu) or count (%zu) on extension 4."),
+ size, count);
if (sysmis != SYSMIS)
sys_warn (r, _("File specifies unexpected value %g as SYSMIS."), sysmis);
int i;
if (count % 3 || n_vars != dict_get_var_cnt (dict))
- sys_error (r, _("Bad size (%u) or count (%u) on extension 11."),
- (unsigned int) size, (unsigned int) count);
+ sys_error (r, _("Bad size (%zu) or count (%zu) on extension 11."),
+ size, count);
for (i = 0; i < n_vars; ++i)
{
if (0 == measure && var_is_alpha (v))
measure = 1;
+ /* Older versions (SPSS 9.0) sometimes set the display width
+ to zero. This causes confusion especially in the GUI */
+ if (0 == width)
+ width = 8;
+
if (measure < 1 || measure > 3 || align < 0 || align > 2)
{
if (!warned)
var_set_short_name (var, i, short_names[i]);
free (short_names[i]);
}
+ free (short_names);
}
close_variable_to_value_map (r, map);
r->has_long_var_names = true;
var_cnt = read_int (r);
if (var_cnt < 1 || var_cnt > dict_get_var_cnt (dict))
sys_error (r, _("Number of variables associated with a value label (%d) "
- "is not between 1 and the number of variables (%u)."),
- var_cnt, (unsigned int) dict_get_var_cnt (dict));
+ "is not between 1 and the number of variables (%zu)."),
+ var_cnt, dict_get_var_cnt (dict));
/* Read the list of variables. */
var = pool_nalloc (subpool, var_cnt, sizeof *var);