/* PSPP - computes sample statistics.
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 <config.h>
#include "por-file-reader.h"
-#include "message.h"
+#include <libpspp/message.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <setjmp.h>
-#include "alloc.h"
+#include <libpspp/alloc.h>
#include <stdbool.h>
#include "case.h"
+#include <libpspp/compiler.h>
#include "dictionary.h"
#include "file-handle-def.h"
#include "format.h"
-#include "hash.h"
-#include "magic.h"
-#include "misc.h"
-#include "pool.h"
-#include "str.h"
+#include "missing-values.h"
+#include <libpspp/hash.h>
+#include <libpspp/magic.h>
+#include <libpspp/misc.h>
+#include <libpspp/pool.h>
+#include <libpspp/str.h>
#include "value-labels.h"
#include "variable.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] =
static void
error (struct pfm_reader *r, const char *msg,...)
- PRINTF_FORMAT (2, 3);
+ PRINTF_FORMAT (2, 3)
+ NO_RETURN;
/* Displays MSG as an error message and aborts reading the
portable file via longjmp(). */
static void
error (struct pfm_reader *r, const char *msg, ...)
{
- struct error e;
- const char *filename;
- char *title;
+ struct msg m;
+ struct string text;
va_list args;
- e.class = ME;
- e.where.filename = NULL;
- e.where.line_number = 0;
- 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));
-
+ ds_init_empty (&text);
+ ds_put_format (&text, _("portable file %s corrupt at offset %ld: "),
+ fh_get_file_name (r->fh), ftell (r->file));
va_start (args, msg);
- err_vmsg (&e, msg, args);
+ ds_put_vformat (&text, msg, args);
va_end (args);
+ m.category = MSG_GENERAL;
+ m.severity = MSG_ERROR;
+ m.where.file_name = NULL;
+ m.where.line_number = 0;
+ m.text = ds_cstr (&text);
+
+ msg_emit (&m);
+
r->ok = false;
longjmp (r->bail_out, 1);
if (setjmp (r->bail_out))
goto error;
r->fh = fh;
- r->file = pool_fopen (r->pool, fh_get_filename (r->fh), "rb");
+ r->file = pool_fopen (r->pool, fh_get_file_name (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."),
- fh_get_filename (r->fh), strerror (errno));
+ fh_get_file_name (r->fh), strerror (errno));
goto error;
}
/* Check that we had some digits. */
if (!got_digit)
- error (r, "Number expected.");
+ error (r, _("Number expected."));
/* Get exponent if any. */
if (r->cc == '+' || r->cc == '-')
for (i = 0; i < 8; i++)
if (!match (r, "SPSSPORT"[i]))
{
- msg (SE, _("%s: Not a portable file."), fh_get_filename (r->fh));
+ msg (SE, _("%s: Not a portable file."), fh_get_file_name (r->fh));
longjmp (r->bail_out, 1);
}
}
/* Read file. */
if (!match (r, 'A'))
- error (r, "Unrecognized version code `%c'.", r->cc);
+ 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) : empty_string;
/* Validate file. */
if (strlen (date) != 8)
- error (r, _("Bad date string length %d."), strlen (date));
+ error (r, _("Bad date string length %d."), (int) strlen (date));
if (strlen (time) != 6)
- error (r, _("Bad time string length %d."), strlen (time));
+ error (r, _("Bad time string length %d."), (int) strlen (time));
/* Save file info. */
if (info != NULL)
/* Translates a format specification read from portable file R as
the three integers INTS into a normal format specifier FORMAT,
checking that the format is appropriate for variable V. */
-static void
+static struct fmt_spec
convert_format (struct pfm_reader *r, const int portable_format[3],
- struct fmt_spec *format, struct variable *v)
+ struct variable *v)
{
- format->type = translate_fmt (portable_format[0]);
- if (format->type == -1)
+ struct fmt_spec format;
+ bool ok;
+
+ if (!fmt_from_io (portable_format[0], &format.type))
error (r, _("%s: Bad format specifier byte (%d)."),
- v->name, portable_format[0]);
- format->w = portable_format[1];
- format->d = portable_format[2];
-
- if (!check_output_specifier (format, false)
- || !check_specifier_width (format, v->width, false))
- error (r, _("%s variable %s has invalid format specifier %s."),
- v->type == NUMERIC ? _("Numeric") : _("String"),
- v->name, fmt_to_string (format));
+ var_get_name (v), portable_format[0]);
+ format.w = portable_format[1];
+ format.d = portable_format[2];
+
+ msg_disable ();
+ ok = (fmt_check_output (&format)
+ && fmt_check_width_compat (&format, var_get_width (v)));
+ msg_enable ();
+
+ if (!ok)
+ {
+ char fmt_string[FMT_STRING_LEN_MAX + 1];
+ error (r, _("%s variable %s has invalid format specifier %s."),
+ var_is_numeric (v) ? _("Numeric") : _("String"),
+ var_get_name (v), fmt_to_string (&format, fmt_string));
+ format = fmt_default_for_width (var_get_width (v));
+ }
+
+ return format;
}
static union value parse_value (struct pfm_reader *, struct variable *);
char name[256];
int fmt[6];
struct variable *v;
+ struct missing_values miss;
+ struct fmt_spec print, write;
int j;
if (!match (r, '7'))
str_uppercase (name);
if (width < 0 || width > 255)
- error (r, "Bad width %d for variable %s.", width, name);
+ error (r, _("Bad width %d for variable %s."), width, name);
v = dict_create_var (dict, name, width);
if (v == NULL)
error (r, _("Duplicate variable name %s."), name);
- convert_format (r, &fmt[0], &v->print, v);
- convert_format (r, &fmt[3], &v->write, v);
+ print = convert_format (r, &fmt[0], v);
+ write = convert_format (r, &fmt[3], v);
+ var_set_print_format (v, &print);
+ var_set_write_format (v, &write);
/* Range missing values. */
+ mv_init (&miss, var_get_width (v));
if (match (r, 'B'))
{
double x = read_float (r);
double y = read_float (r);
- mv_add_num_range (&v->miss, x, y);
+ mv_add_num_range (&miss, x, y);
}
else if (match (r, 'A'))
- mv_add_num_range (&v->miss, read_float (r), HIGHEST);
+ mv_add_num_range (&miss, read_float (r), HIGHEST);
else if (match (r, '9'))
- mv_add_num_range (&v->miss, LOWEST, read_float (r));
+ mv_add_num_range (&miss, LOWEST, read_float (r));
/* Single missing values. */
while (match (r, '8'))
{
union value value = parse_value (r, v);
- mv_add_value (&v->miss, &value);
+ mv_add_value (&miss, &value);
}
+ var_set_missing_values (v, &miss);
+
if (match (r, 'C'))
{
char label[256];
read_string (r, label);
- v->label = xstrdup (label);
+ var_set_label (v, label);
}
}
{
union value v;
- if (vv->type == ALPHA)
+ if (var_is_alpha (vv))
{
char string[256];
read_string (r, string);
if (v[i] == NULL)
error (r, _("Unknown variable %s while parsing value labels."), name);
- if (v[0]->width != v[i]->width)
+ if (var_get_width (v[0]) != var_get_width (v[i]))
error (r, _("Cannot assign value labels to %s and %s, which "
"have different variable types or widths."),
- v[0]->name, v[i]->name);
+ var_get_name (v[0]), var_get_name (v[i]));
}
n_labels = read_int (r);
{
struct variable *var = v[j];
- if (!val_labs_replace (var->val_labs, val, label))
+ if (!var_add_value_label (var, &val, label))
continue;
- if (var->type == NUMERIC)
+ if (var_is_numeric (var))
error (r, _("Duplicate label for value %g for variable %s."),
- val.f, var->name);
+ val.f, var_get_name (var));
else
error (r, _("Duplicate label for value `%.*s' for variable %s."),
- var->width, val.s, var->name);
+ var_get_width (var), val.s, var_get_name (var));
}
}
}
if (width == 0)
{
- case_data_rw (c, idx)->f = read_float (r);
+ case_data_rw_idx (c, idx)->f = read_float (r);
idx++;
}
else
{
char string[256];
read_string (r, string);
- buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
+ buf_copy_str_rpad (case_data_rw_idx (c, idx)->s, width, string);
idx += DIV_RND_UP (width, MAX_SHORT_STRING);
}
}