Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
-/* AIX requires this to be the first thing in the file. */
#include <config.h>
-#if __GNUC__
-#define alloca __builtin_alloca
-#else
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else
-#ifdef _AIX
-#pragma alloca
-#else
-#ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-#endif
-#endif
-#endif
-#endif
-
+#include "data-list.h"
#include <assert.h>
#include <ctype.h>
#include <float.h>
int fc, lc; /* Fixed-format: Column numbers in record. */
struct fmt_spec input; /* Input format of this field. */
int fv; /* First value in case. */
- int type; /* 0=numeric, >0=width of alpha field. */
+ int width; /* 0=numeric, >0=width of alpha field. */
};
/* Constants for DATA LIST type. */
lex_match ('=');
if (!lex_force_id ())
return CMD_FAILURE;
- dls.end = find_variable (tokid);
- if (!dls.end)
- dls.end = force_create_variable (&default_dict, tokid, NUMERIC, 0);
+ dls.end = dict_lookup_var (default_dict, tokid);
+ if (!dls.end)
+ dls.end = dict_create_var_assert (default_dict, tokid, 0);
lex_get ();
}
else if (token == T_ID)
else
next = next->next = xmalloc (sizeof *spec);
-#if __CHECKER__
- spec->type = ROUND_UP (spec->type, 8);
-#endif
-
memcpy (next, spec, sizeof *spec);
next->next = NULL;
}
for (i = 0; i < fx.nname; i++)
{
int type;
+ int width;
struct variable *v;
- if (fx.spec.input.type == FMT_A || fx.spec.input.type == FMT_AHEX)
- type = ALPHA;
- else
- type = NUMERIC;
-
- v = create_variable (&default_dict, fx.name[i], type, dividend);
+ if (fx.spec.input.type == FMT_A || fx.spec.input.type == FMT_AHEX)
+ {
+ type = ALPHA;
+ width = dividend;
+ }
+ else
+ {
+ type = NUMERIC;
+ width = 0;
+ }
+
+ v = dict_create_var (default_dict, fx.name[i], width);
if (v)
{
convert_fmt_ItoO (&fx.spec.input, &v->print);
v->write = v->print;
+ if (vfm_source != &input_program_source
+ && vfm_source != &file_type_source)
+ v->init = 0;
}
else
{
- v = find_variable (fx.name[i]);
- assert (v);
+ v = dict_lookup_var_assert (default_dict, fx.name[i]);
if (!vfm_source)
{
msg (SE, _("%s is a duplicate variable name."), fx.name[i]);
fx.spec.fc = fx.fc + dividend * i;
fx.spec.lc = fx.spec.fc + dividend - 1;
fx.spec.fv = v->fv;
- fx.spec.type = v->type == NUMERIC ? 0 : v->width;
+ fx.spec.width = v->width;
append_var_spec (&fx.spec);
}
return 1;
else
{
int type;
+ int width;
struct variable *v;
- type = (formats[f->f.type].cat & FCAT_STRING) ? ALPHA : NUMERIC;
+ if (formats[f->f.type].cat & FCAT_STRING)
+ {
+ type = ALPHA;
+ width = f->f.w;
+ }
+ else
+ {
+ type = NUMERIC;
+ width = 0;
+ }
if (fx.cname >= fx.nname)
{
msg (SE, _("The number of format "
return 0;
}
- fx.spec.v = v = create_variable (&default_dict,
+ fx.spec.v = v = dict_create_var (default_dict,
fx.name[fx.cname++],
- type, f->f.w);
+ width);
if (!v)
{
msg (SE, _("%s is a duplicate variable name."), fx.name[i]);
return 0;
}
+ if (vfm_source != &input_program_source
+ && vfm_source != &file_type_source)
+ v->init = 0;
+
fx.spec.input = f->f;
convert_fmt_ItoO (&fx.spec.input, &v->print);
v->write = v->print;
fx.spec.fc = fx.sc;
fx.spec.lc = fx.sc + f->f.w - 1;
fx.spec.fv = v->fv;
- fx.spec.type = v->type == NUMERIC ? 0 : v->width;
+ fx.spec.width = v->width;
append_var_spec (&fx.spec);
fx.sc += f->f.w;
filename = "";
buf = local_alloc (strlen (filename) + INT_DIGITS + 80);
sprintf (buf, (dls.handle != inline_file
- ? _("Reading %d record%s from file %s.")
- : _("Reading %d record%s from the command file.")),
- dls.nrec, dls.nrec != 1 ? "s" : "", filename);
+ ?
+ ngettext("Reading %d record from file %s.",
+ "Reading %d records from file %s.",dls.nrec)
+ :
+ ngettext("Reading %d record from the command file.",
+ "Reading %d records from the command file.",
+ dls.nrec)),
+ dls.nrec, filename);
}
else
{
char **name;
int nname;
int i;
- int type;
-#if __CHECKER__
- memset (&spec, 0, sizeof spec);
-#endif
lex_get ();
while (token != '.')
{
+ int width;
+
if (!parse_DATA_LIST_vars (&name, &nname, PV_NONE))
return 0;
if (lex_match ('('))
spec.input = in;
if (in.type == FMT_A || in.type == FMT_AHEX)
- type = ALPHA;
+ width = in.w;
else
- type = NUMERIC;
+ width = 0;
for (i = 0; i < nname; i++)
{
struct variable *v;
- spec.v = v = create_variable (&default_dict, name[i], type, in.w);
+ spec.v = v = dict_create_var (default_dict, name[i], width);
if (!v)
{
msg (SE, _("%s is a duplicate variable name."), name[i]);
v->print = v->write = out;
+ if (vfm_source != &input_program_source
+ && vfm_source != &file_type_source)
+ v->init = 0;
+
strcpy (spec.name, name[i]);
spec.fv = v->fv;
- spec.type = type == NUMERIC ? 0 : v->width;
+ spec.width = width;
append_var_spec (&spec);
}
for (i = 0; i < nname; i++)
static int read_from_data_list_fixed (void);
static int read_from_data_list_free (void);
static int read_from_data_list_list (void);
-static int do_reading (int flag);
/* FLAG==0: reads any number of cases into temp_case and calls
write_case() for each one, returns garbage. FLAG!=0: reads one
case into temp_case and returns -2 on eof, -1 otherwise.
Uses dlsp as the relevant parsing description. */
static int
-do_reading (int flag)
+do_reading (int flag, write_case_func *write_case, write_case_data wc_data)
{
int (*func) (void);
else
{
while (func () != -2)
- if (!write_case ())
+ if (!write_case (wc_data))
{
debug_printf ((_("abort in write_case()\n")));
break;
}
fh_close_handle (dlsp->handle);
-#if __CHECKER__
- code = 0; /* prevent error at `return code;' */
-#endif
}
dfm_pop (dlsp->handle);
"or blanks, as appropriate."),
var_spec->name);
for (; var_spec; var_spec = var_spec->next)
- if (!var_spec->type)
+ if (var_spec->width == 0)
temp_case->data[var_spec->fv].f = SYSMIS;
else
- memset (temp_case->data[var_spec->fv].s, ' ', var_spec->type);
+ memset (temp_case->data[var_spec->fv].s, ' ', var_spec->width);
break;
}
return -1;
}
-/* Destroys DATA LIST transformation or input program PGM. */
+/* Destroys SPEC. */
static void
-destroy_dls (struct trns_header *pgm)
+destroy_dls_var_spec (struct dls_var_spec *spec)
{
- struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
- struct dls_var_spec *iter, *next;
+ struct dls_var_spec *next;
- iter = dls->spec;
- while (iter)
+ while (spec != NULL)
{
- next = iter->next;
- free (iter);
- iter = next;
+ next = spec->next;
+ free (spec);
+ spec = next;
}
+}
+
+/* Destroys DATA LIST transformation PGM. */
+static void
+destroy_dls (struct trns_header *pgm)
+{
+ struct data_list_pgm *dls = (struct data_list_pgm *) pgm;
+ destroy_dls_var_spec (dls->spec);
fh_close_handle (dls->handle);
}
/* Note that since this is exclusively an input program, C is
guaranteed to be temp_case. */
static int
-read_one_case (struct trns_header *t, struct ccase *c unused)
+read_one_case (struct trns_header *t, struct ccase *c UNUSED)
{
dlsp = (struct data_list_pgm *) t;
- return do_reading (1);
+ return do_reading (1, NULL, NULL);
}
\f
/* Reads all the records from the data file and passes them to
write_case(). */
static void
-data_list_source_read (void)
+data_list_source_read (write_case_func *write_case, write_case_data wc_data)
{
dlsp = &dls;
- do_reading (0);
+ do_reading (0, write_case, wc_data);
}
/* Destroys the source's internal data. */
static void
data_list_source_destroy_source (void)
{
- destroy_dls ((struct trns_header *) & dls);
+ destroy_dls (&dls.h);
}
struct case_stream data_list_source =
struct trns_header h;
struct dls_var_spec *spec; /* Variable parsing specifications. */
struct file_handle *handle; /* Input file, never NULL. */
- /* Do not reorder preceding fields. */
struct rpd_num_or_var starts_beg; /* STARTS=, before the dash. */
struct rpd_num_or_var starts_end; /* STARTS=, after the dash. */
struct rpd_num_or_var length; /* LENGTH= subcommand. */
struct rpd_num_or_var cont_beg; /* CONTINUED=, before the dash. */
struct rpd_num_or_var cont_end; /* CONTINUED=, after the dash. */
- int id_beg, id_end; /* ID subcommand, beginning & end columns. */
- struct variable *id_var; /* ID subcommand, DATA LIST variable. */
- struct fmt_spec id_spec; /* ID subcommand, input format spec. */
+
+ /* ID subcommand. */
+ int id_beg, id_end; /* Beginning & end columns. */
+ struct variable *id_var; /* DATA LIST variable. */
+ struct fmt_spec id_spec; /* Input format spec. */
+ union value *id_value; /* ID value. */
+
+ write_case_func *write_case;
+ write_case_data wc_data;
};
/* Information about the transformation being parsed. */
static struct repeating_data_trns rpd;
-static int read_one_set_of_repetitions (struct trns_header *, struct ccase *);
+int repeating_data_trns_proc (struct trns_header *, struct ccase *);
+void repeating_data_trns_free (struct trns_header *);
static int parse_num_or_var (struct rpd_num_or_var *, const char *);
static int parse_repeating_data (void);
static void find_variable_input_spec (struct variable *v,
= rpd.cont_end = rpd.starts_beg;
rpd.id_beg = rpd.id_end = 0;
rpd.id_var = NULL;
+ rpd.id_value = NULL;
rpd.spec = NULL;
first = &rpd.spec;
next = NULL;
lex_match ('=');
if (seen & 1)
{
- msg (SE, _("STARTS subcommand given multiple times."));
+ msg (SE, _("%s subcommand given multiple times."),"STARTS");
return CMD_FAILURE;
}
seen |= 1;
lex_match ('=');
if (seen & 2)
{
- msg (SE, _("OCCURS subcommand given multiple times."));
+ msg (SE, _("%s subcommand given multiple times."),"OCCURS");
return CMD_FAILURE;
}
seen |= 2;
lex_match ('=');
if (seen & 4)
{
- msg (SE, _("LENGTH subcommand given multiple times."));
+ msg (SE, _("%s subcommand given multiple times."),"LENGTH");
return CMD_FAILURE;
}
seen |= 4;
lex_match ('=');
if (seen & 8)
{
- msg (SE, _("CONTINUED subcommand given multiple times."));
+ msg (SE, _("%s subcommand given multiple times."),"CONTINUED");
return CMD_FAILURE;
}
seen |= 8;
lex_match ('=');
if (seen & 16)
{
- msg (SE, _("ID subcommand given multiple times."));
+ msg (SE, _("%s subcommand given multiple times."),"ID");
return CMD_FAILURE;
}
seen |= 16;
return CMD_FAILURE;
find_variable_input_spec (rpd.id_var, &rpd.id_spec);
+ rpd.id_value = xmalloc (sizeof *rpd.id_value * rpd.id_var->nv);
}
else if (lex_match_id ("TABLE"))
table = 1;
{
struct repeating_data_trns *new_trns;
- rpd.h.proc = read_one_set_of_repetitions;
- rpd.h.free = destroy_dls;
+ rpd.h.proc = repeating_data_trns_proc;
+ rpd.h.free = repeating_data_trns_free;
new_trns = xmalloc (sizeof *new_trns);
memcpy (new_trns, &rpd, sizeof *new_trns);
/* Handle record ID values. */
if (t->id_beg != 0)
{
- static union value comparator;
- union value v;
+ union value id_temp[MAX_ELEMS_PER_VALUE];
+ /* Parse record ID into V. */
{
struct data_in di;
data_in_finite_line (&di, line, len, t->id_beg, t->id_end);
- di.v = &v;
+ di.v = compare_id ? id_temp : t->id_value;
di.flags = 0;
di.f1 = t->id_beg;
di.format = t->id_spec;
return 0;
}
- if (compare_id == 0)
- comparator = v;
- else if ((t->id_var->type == NUMERIC && comparator.f != v.f)
- || (t->id_var->type == ALPHA
- && strncmp (comparator.s, v.s, t->id_var->width)))
+ if (compare_id
+ && compare_values (id_temp, t->id_value, t->id_var->width) != 0)
{
- char comp_str [64];
- char v_str [64];
+ char expected_str [MAX_FORMATTED_LEN + 1];
+ char actual_str [MAX_FORMATTED_LEN + 1];
- if (!data_out (comp_str, &t->id_var->print, &comparator))
- comp_str[0] = 0;
- if (!data_out (v_str, &t->id_var->print, &v))
- v_str[0] = 0;
-
- comp_str[t->id_var->print.w] = v_str[t->id_var->print.w] = 0;
+ data_out (expected_str, &t->id_var->print, t->id_value);
+ expected_str[t->id_var->print.w] = '\0';
+
+ data_out (actual_str, &t->id_var->print, id_temp);
+ actual_str[t->id_var->print.w] = '\0';
tmsg (SE, RPD_ERR,
- _("Mismatched case ID (%s). Expected value was %s."),
- v_str, comp_str);
+ _("Encountered mismatched record ID \"%s\" expecting \"%s\"."),
+ actual_str, expected_str);
return 0;
}
warned = 1;
tmsg (SW, RPD_ERR,
- _("Variable %s startging in column %d extends "
+ _("Variable %s starting in column %d extends "
"beyond physical record length of %d."),
var_spec->v->name, fc, len);
}
cur += ofs;
- if (!write_case ())
+ if (!t->write_case (t->wc_data))
return 0;
}
}
/* Analogous to read_one_case; reads one set of repetitions of the
elements in the REPEATING DATA structure. Returns -1 on success,
-2 on end of file or on failure. */
-static int
-read_one_set_of_repetitions (struct trns_header *trns, struct ccase *c)
+int
+repeating_data_trns_proc (struct trns_header *trns, struct ccase *c)
{
dfm_push (dlsp->handle);
transformations. */
return -3;
}
+
+void
+repeating_data_trns_free (struct trns_header *rpd_)
+{
+ struct repeating_data_trns *rpd = (struct repeating_data_trns *) rpd_;
+
+ destroy_dls_var_spec (rpd->spec);
+ fh_close_handle (rpd->handle);
+ free (rpd->id_value);
+}
+
+/* This is a kluge. It is only here until I have more time
+ tocome up with something better. It lets
+ repeating_data_trns_proc() know how to write the cases that it
+ composes. */
+void
+repeating_data_set_write_case (struct trns_header *trns,
+ write_case_func *write_case,
+ write_case_data wc_data)
+{
+ struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
+
+ assert (trns->proc == repeating_data_trns_proc);
+ t->write_case = write_case;
+ t->wc_data = wc_data;
+}