+Mon Feb 16 22:14:36 2004 Ben Pfaff <blp@gnu.org>
+
+ * q2c.c: (dump_header) Add an Emacs header line to output files
+ that makes generated .c files read-only by default, to make it
+ difficult to accidentally change generated files.
+
+Mon Feb 16 22:12:07 2004 Ben Pfaff <blp@gnu.org>
+
+ * frequencies.q: (compare_freq_numeric_a) Compare by frequency,
+ not bogus a->v.c <=> b->v.c pointer compare.
+ (compare_freq_alpha_a) Ditto.
+ (compare_freq_numeric_d) Ditto.
+ (compare_freq_alpha_d) Ditto.
+
+Mon Feb 16 22:00:53 2004 Ben Pfaff <blp@gnu.org>
+
+ Changed data_out() to store string data directly into a `union
+ value''s s member, not indirectly into c.
+
+ * crosstabs.q: (output_pivot_table) Use format_short() instead of
+ data_out().
+ (table_value_missing) Ditto.
+ (float_M_suffix) Ditto.
+ (format_short) New function.
+
+ * data-in.h: (data_in_finite_line) Remove inline definition.
+
+ * data-list.c: (destroy_dls_var_spec) New function.
+ (destroy_dls) Rewrite in terms of destroy_dls_var_spec().
+ (data_list_source_destroy_source) Avoid cast.
+ (struct repeating_data_trns) New field `id_value'. Update
+ comments.
+ (cmd_repeating_data) Initialize id_value. Use new
+ repeating_data_trns_free() for freeing REPEATING DATA
+ transformations.
+ (rpd_parse_record) Rewrite support for record ID to be less bogus.
+ (repeating_data_trns_free) New function.
+
+ * data-out.c: (data_out) Change return type to `void' by replacing
+ error returns by writing a message into the output buffer.
+ (convert_A) Read from v->s instead of v->c.
+ (convert_AHEX) Ditto.
+
+ * expr-evl.c: Update comment.
+ (expr_evaluate) Add assertion in OP_STRING case.
+
+ * format.h: (macro MAX_FORMATTED_LEN) New macro.
+
+ * list.q: (list_cases) Update for new data_out() semantics.
+
+ * print.c: (print_trns_proc) Ditto.
+
+ * tab.c: (tab_value) Ditto.
+ (tab_float) Avoid stupid cast.
+
+ * var.h: Update comments.
+ (macro MAX_STRING) New macro.
+ (macro MAX_ELEMS_PER_VALUE) New macro.
+
+ * vars-atr.c: (compare_values) New function.
+
+ * vfm.c: (dump_splits) Update for new data_out() semantics.
+
+Mon Feb 16 21:45:47 2004 Ben Pfaff <blp@gnu.org>
+
+ * crosstabs.q: (struct table_entry) Rename v[] to values[]. All
+ references updated.
+ (struct crosstab) Rename v[] to vars[]. All references updated.
+ (hash_table_entry) Replace the hash algorithm and fix a bug at the
+ same time, which caused the hash value to depend only on a single
+ value, not all of the variables' values.
+
Mon Feb 16 12:49:53 2004 Ben Pfaff <blp@gnu.org>
Clean up struct dictionary's value_cnt usage.
double *data; /* Crosstabulation table for integer mode. */
}
u;
- union value v[1]; /* Values. */
+ union value values[1]; /* Values. */
};
/* A crosstabulation. */
int nvar; /* Number of variables. */
double missing; /* Missing cases count. */
int ofs; /* Integer mode: Offset into sorted_tab[]. */
- struct variable *v[2]; /* At least two variables; sorted by
+ struct variable *vars[2]; /* At least two variables; sorted by
larger indices first. */
};
static void postcalc (void *);
static void submit (struct tab_table *);
+static void format_short (char *s, const struct fmt_spec *fp,
+ const union value *v);
+
#if DEBUGGING
static void debug_print (void);
static void print_table_entries (struct table_entry **tab);
int i;
for (i = 0; i < n_by; i++)
- x->v[i] = by[i][by_iter[i]];
+ x->vars[i] = by[i][by_iter[i]];
}
{
x->ofs = n_sorted_tab;
for (j = 2; j < x->nvar; j++)
- count *= x->v[j - 2]->p.crs.count;
+ count *= x->vars[j - 2]->p.crs.count;
sorted_tab = xrealloc (sorted_tab,
sizeof *sorted_tab * (n_sorted_tab + count));
v = local_alloc (sizeof *v * x->nvar);
for (j = 2; j < x->nvar; j++)
- v[j] = x->v[j]->p.crs.min;
+ v[j] = x->vars[j]->p.crs.min;
for (j = 0; j < count; j++)
{
struct table_entry *te;
te->table = i;
{
- const int mat_size = (x->v[0]->p.crs.count
- * x->v[1]->p.crs.count);
+ const int mat_size = (x->vars[0]->p.crs.count
+ * x->vars[1]->p.crs.count);
int m;
te->u.data = xmalloc (sizeof *te->u.data * mat_size);
}
for (k = 2; k < x->nvar; k++)
- te->v[k].f = v[k];
+ te->values[k].f = v[k];
for (k = 2; k < x->nvar; k++)
- if (++v[k] >= x->v[k]->p.crs.max)
- v[k] = x->v[k]->p.crs.min;
+ if (++v[k] >= x->vars[k]->p.crs.max)
+ v[k] = x->vars[k]->p.crs.min;
else
break;
}
for (j = 0; j < x->nvar; j++)
{
if ((cmd.miss == CRS_TABLE
- && is_missing (&c->data[x->v[j]->fv], x->v[j]))
+ && is_missing (&c->data[x->vars[j]->fv], x->vars[j]))
|| (cmd.miss == CRS_INCLUDE
- && is_system_missing (&c->data[x->v[j]->fv], x->v[j])))
+ && is_system_missing (&c->data[x->vars[j]->fv],
+ x->vars[j])))
{
x->missing += weight;
goto next_crosstab;
}
- if (x->v[j]->type == NUMERIC)
- te->v[j].f = c->data[x->v[j]->fv].f;
+ if (x->vars[j]->type == NUMERIC)
+ te->values[j].f = c->data[x->vars[j]->fv].f;
else
{
- memcpy (te->v[j].s, c->data[x->v[j]->fv].s, x->v[j]->width);
+ memcpy (te->values[j].s, c->data[x->vars[j]->fv].s,
+ x->vars[j]->width);
/* Necessary in order to simplify comparisons. */
- memset (&te->v[j].s[x->v[j]->width], 0,
- sizeof (union value) - x->v[j]->width);
+ memset (&te->values[j].s[x->vars[j]->width], 0,
+ sizeof (union value) - x->vars[j]->width);
}
}
}
ofs = x->ofs;
for (i = 0; i < x->nvar; i++)
{
- struct variable *const v = x->v[i];
+ struct variable *const v = x->vars[i];
double value = c->data[v->fv].f;
/* Note that the first test also rules out SYSMIS. */
}
{
- const int row = c->data[x->v[ROW_VAR]->fv].f - x->v[ROW_VAR]->p.crs.min;
- const int col = c->data[x->v[COL_VAR]->fv].f - x->v[COL_VAR]->p.crs.min;
- const int col_dim = x->v[COL_VAR]->p.crs.count;
+ const int row = c->data[x->vars[ROW_VAR]->fv].f - x->vars[ROW_VAR]->p.crs.min;
+ const int col = c->data[x->vars[COL_VAR]->fv].f - x->vars[COL_VAR]->p.crs.min;
+ const int col_dim = x->vars[COL_VAR]->p.crs.count;
sorted_tab[ofs]->u.data[col + row * col_dim] += weight;
}
int i;
for (i = x->nvar - 1; i >= 0; i--)
- if (x->v[i]->type == NUMERIC)
+ if (x->vars[i]->type == NUMERIC)
{
- const double diffnum = a->v[i].f - b->v[i].f;
+ const double diffnum = a->values[i].f - b->values[i].f;
if (diffnum < 0)
return -1;
else if (diffnum > 0)
}
else
{
- assert (x->v[i]->type == ALPHA);
+ assert (x->vars[i]->type == ALPHA);
{
- const int diffstr = strncmp (a->v[i].s, b->v[i].s, x->v[i]->width);
+ const int diffstr = strncmp (a->values[i].s, b->values[i].s,
+ x->vars[i]->width);
if (diffstr)
return diffstr;
}
return 0;
}
-/* Calculate a hash value from table_entry PA. */
+/* Calculate a hash value from table_entry A. */
static unsigned
-hash_table_entry (const void *pa, void *foo UNUSED)
+hash_table_entry (const void *a_, void *foo UNUSED)
{
- const struct table_entry *a = pa;
- unsigned long hash = a->table;
+ const struct table_entry *a = a_;
+ unsigned long hash;
int i;
- /* Hash formula from _SPSS Statistical Algorithms_. */
+ hash = a->table;
for (i = 0; i < xtab[a->table]->nvar; i++)
- {
- hash = (hash << 3) | (hash >> (CHAR_BIT * SIZEOF_LONG - 3));
- hash ^= a->v[i].hash[0];
-#if SIZEOF_DOUBLE / SIZEOF_LONG > 1
- hash ^= a->v[i].hash[1];
-#endif
- }
+ hash ^= hsh_hash_bytes (&a->values[i], sizeof a->values[i]);
return hash;
}
else
{
const struct crosstab *const x = xtab[(*pb)->table];
- const int n_cols = x->v[COL_VAR]->p.crs.count;
- const int n_rows = x->v[ROW_VAR]->p.crs.count;
+ const int n_cols = x->vars[COL_VAR]->p.crs.count;
+ const int n_rows = x->vars[ROW_VAR]->p.crs.count;
const int count = n_cols * n_rows;
for (valid = 0.; pb < pe; pb++)
if (i > 0)
cp = stpcpy (cp, " * ");
- cp = stpcpy (cp, x->v[i]->label ? x->v[i]->label : x->v[i]->name);
+ cp = stpcpy (cp,
+ x->vars[i]->label ? x->vars[i]->label : x->vars[i]->name);
}
tab_text (t, 0, 0, TAB_LEFT, buf);
/* First header line. */
tab_joint_text (table, nvar - 1, 0, (nvar - 1) + (n_cols - 1), 0,
- TAB_CENTER | TAT_TITLE, x->v[COL_VAR]->name);
+ TAB_CENTER | TAT_TITLE, x->vars[COL_VAR]->name);
tab_hline (table, TAL_1, nvar - 1, nvar + n_cols - 2, 1);
for (i = 2; i < nvar; i++)
tab_joint_text (table, nvar - i - 1, 0, nvar - i - 1, 1,
TAB_RIGHT | TAT_TITLE,
- x->v[i]->label ? x->v[i]->label : x->v[i]->name);
+ (x->vars[i]->label
+ ? x->vars[i]->label : x->vars[i]->name));
tab_text (table, nvar - 2, 1, TAB_RIGHT | TAT_TITLE,
- x->v[ROW_VAR]->name);
+ x->vars[ROW_VAR]->name);
for (i = 0; i < n_cols; i++)
table_value_missing (table, nvar + i - 1, 1, TAB_RIGHT, &cols[i],
- x->v[COL_VAR]);
+ x->vars[COL_VAR]);
tab_text (table, nvar + n_cols - 1, 1, TAB_CENTER, _("Total"));
}
{
if (i)
cp = stpcpy (cp, " by ");
- cp = stpcpy (cp, x->v[i]->name);
+ cp = stpcpy (cp, x->vars[i]->name);
}
else
{
- cp = spprintf (cp, "%s by %s for", x->v[0]->name, x->v[1]->name);
+ cp = spprintf (cp, "%s by %s for",
+ x->vars[0]->name, x->vars[1]->name);
for (i = 2; i < nvar; i++)
{
char buf[64], *bufp;
if (i > 2)
*cp++ = ',';
*cp++ = ' ';
- cp = stpcpy (cp, x->v[i]->name);
+ cp = stpcpy (cp, x->vars[i]->name);
*cp++ = '=';
- data_out (buf, &x->v[i]->print, &(*pb)->v[i]);
+ format_short (buf, &x->vars[i]->print, &(*pb)->values[i]);
for (bufp = buf; isspace ((unsigned char) *bufp); bufp++)
;
cp = stpcpy (cp, bufp);
*cp = 0.;
for (p = &tb[0]; p < te; p++)
{
- for (; memcmp (cur_col, &(*p)->v[COL_VAR], sizeof *cur_col);
+ for (; memcmp (cur_col, &(*p)->values[COL_VAR], sizeof *cur_col);
cur_row = rows)
{
*++cp = 0.;
mp = &mat[cur_col - cols];
}
- for (; memcmp (cur_row, &(*p)->v[ROW_VAR], sizeof *cur_row);
+ for (; memcmp (cur_row, &(*p)->values[ROW_VAR], sizeof *cur_row);
cur_row++)
{
*mp = 0.;
for (; ; first_difference--)
{
assert (first_difference >= 2);
- if (memcmp (&cmp->v[first_difference],
- &(*tb)->v[first_difference], sizeof *cmp->v))
+ if (memcmp (&cmp->values[first_difference],
+ &(*tb)->values[first_difference],
+ sizeof *cmp->values))
break;
}
cmp = *tb;
int r;
for (r = 0; r < n_rows; r++)
- if (is_num_user_missing (rows[r].f, x->v[ROW_VAR]))
+ if (is_num_user_missing (rows[r].f, x->vars[ROW_VAR]))
{
int c;
int c;
for (c = 0; c < n_cols; c++)
- if (is_num_user_missing (cols[c].f, x->v[COL_VAR]))
+ if (is_num_user_missing (cols[c].f, x->vars[COL_VAR]))
{
int r;
if (t != table)
for (i = 2; i < nvar; i++)
tab_text (t, nvar - i - 1, 0, TAB_RIGHT | TAT_TITLE,
- x->v[i]->label ? x->v[i]->label : x->v[i]->name);
+ x->vars[i]->label ? x->vars[i]->label : x->vars[i]->name);
tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
tab_box (t, -1, -1, -1, TAL_1, tab_l (t), tab_t (t) - 1, tab_nc (t) - 1,
tab_nr (t) - 1);
if (pivot)
continue;
- if (memcmp (&(*tp)->v[2], &fp->v[2], sizeof (union value) * (x->nvar - 2)))
+ if (memcmp (&(*tp)->values[2], &fp->values[2], sizeof (union value) * (x->nvar - 2)))
break;
}
if (pivot)
continue;
- if (memcmp (&(*tp)->v[2], &fp->v[2], sizeof (union value) * (x->nvar - 2)))
+ if (memcmp (&(*tp)->values[2], &fp->values[2],
+ sizeof (union value) * (x->nvar - 2)))
break;
}
{
if (mode == GENERAL)
{
- int width = xtab[(*entries)->table]->v[var_idx]->width;
+ int width = xtab[(*entries)->table]->vars[var_idx]->width;
int i;
*values = xmalloc (sizeof **values * entry_cnt);
for (i = 0; i < entry_cnt; i++)
- (*values)[i] = entries[i]->v[var_idx];
+ (*values)[i] = entries[i]->values[var_idx];
*value_cnt = sort_unique (*values, entry_cnt, sizeof **values,
compare_value, &width);
}
else
{
- struct crosstab_proc *crs = &xtab[(*entries)->table]->v[var_idx]->p.crs;
+ struct crosstab_proc *crs
+ = &xtab[(*entries)->table]->vars[var_idx]->p.crs;
int i;
assert (mode == INTEGER);
return;
}
- s.length = var->print.w;
- s.string = tab_alloc (table, s.length + 1);
- data_out (s.string, &var->print, v);
+ s.string = tab_alloc (table, var->print.w);
+ format_short (s.string, &var->print, v);
+ s.length = strlen (s.string);
if (cmd.miss == CRS_REPORT && is_num_user_missing (v->f, var))
s.string[s.length++] = 'M';
while (s.length && *s.string == ' ')
for (; first_difference >= 2; first_difference--)
table_value_missing (table, nvar - first_difference - 1, 0,
- TAB_RIGHT, &tb->v[first_difference],
- x->v[first_difference]);
+ TAB_RIGHT, &tb->values[first_difference],
+ x->vars[first_difference]);
}
/* Put value V into cell (C,R) of TABLE, suffixed with letter M. */
s.length = 9;
s.string = tab_alloc (table, 9);
s.string[8] = 'M';
- data_out (s.string, &f, (union value *) &v);
+ format_short (s.string, &f, (union value *) &v);
while (*s.string == ' ')
{
s.length--;
for (r = 0; r < n_rows; r++)
table_value_missing (table, nvar - 2, r * num_cells,
- TAB_RIGHT, &rows[r], x->v[ROW_VAR]);
+ TAB_RIGHT, &rows[r], x->vars[ROW_VAR]);
}
tab_text (table, nvar - 2, n_rows * num_cells,
TAB_LEFT, _("Total"));
}
if (cmd.miss == CRS_REPORT
- && (is_num_user_missing (cols[c].f, x->v[COL_VAR])
- || is_num_user_missing (rows[r].f, x->v[ROW_VAR])))
+ && (is_num_user_missing (cols[c].f, x->vars[COL_VAR])
+ || is_num_user_missing (rows[r].f, x->vars[ROW_VAR])))
float_M_suffix (table, c, i, v);
else if (v != 0.)
tab_float (table, c, i, TAB_RIGHT, v, 8, 0);
}
if (cmd.miss == CRS_REPORT
- && is_num_user_missing (rows[r].f, x->v[ROW_VAR]))
+ && is_num_user_missing (rows[r].f, x->vars[ROW_VAR]))
float_M_suffix (table, n_cols, 0, v);
else if (v != 0.)
tab_float (table, n_cols, 0, TAB_RIGHT, v, 8, 0);
}
if (cmd.miss == CRS_REPORT && c < n_cols
- && is_num_user_missing (cols[c].f, x->v[COL_VAR]))
+ && is_num_user_missing (cols[c].f, x->vars[COL_VAR]))
float_M_suffix (table, c, j, v);
else if (v != 0.)
tab_float (table, c, j, TAB_RIGHT, v, 8, 0);
switch (i)
{
case 0:
- if (x->v[COL_VAR]->type == NUMERIC)
+ if (x->vars[COL_VAR]->type == NUMERIC)
sprintf (buf, _("Odds Ratio for %s (%g / %g)"),
- x->v[COL_VAR]->name, c[0].f, c[1].f);
+ x->vars[COL_VAR]->name, c[0].f, c[1].f);
else
sprintf (buf, _("Odds Ratio for %s (%.*s / %.*s)"),
- x->v[COL_VAR]->name,
- x->v[COL_VAR]->width, c[0].s,
- x->v[COL_VAR]->width, c[1].s);
+ x->vars[COL_VAR]->name,
+ x->vars[COL_VAR]->width, c[0].s,
+ x->vars[COL_VAR]->width, c[1].s);
break;
case 1:
case 2:
- if (x->v[ROW_VAR]->type == NUMERIC)
+ if (x->vars[ROW_VAR]->type == NUMERIC)
sprintf (buf, _("For cohort %s = %g"),
- x->v[ROW_VAR]->name, rows[i - 1].f);
+ x->vars[ROW_VAR]->name, rows[i - 1].f);
else
sprintf (buf, _("For cohort %s = %.*s"),
- x->v[ROW_VAR]->name,
- x->v[ROW_VAR]->width, rows[i - 1].s);
+ x->vars[ROW_VAR]->name,
+ x->vars[ROW_VAR]->width, rows[i - 1].s);
break;
}
if (k == 0)
string = NULL;
else if (k == 1)
- string = x->v[0]->name;
+ string = x->vars[0]->name;
else
- string = x->v[1]->name;
+ string = x->vars[1]->name;
tab_text (direct, j, 0, TAB_LEFT | TAT_PRINTF,
gettext (stats_names[j][k]), string);
}
/* Calculate Mantel-Haenszel. */
- if (x->v[ROW_VAR]->type == NUMERIC && x->v[COL_VAR]->type == NUMERIC)
+ if (x->vars[ROW_VAR]->type == NUMERIC && x->vars[COL_VAR]->type == NUMERIC)
{
double r, ase_0, ase_1;
calc_r ((double *) rows, (double *) cols, &r, &ase_0, &ase_1);
return 1;
}
+/* A wrapper around data_out() that limits string output to short
+ string width and null terminates the result. */
+static void
+format_short (char *s, const struct fmt_spec *fp, const union value *v)
+{
+ struct fmt_spec fmt_subst;
+
+ /* Limit to short string width. */
+ if (formats[fp->type].cat & FCAT_STRING)
+ {
+ fmt_subst = *fp;
+
+ assert (fmt_subst.type == FMT_A || fmt_subst.type == FMT_AHEX);
+ if (fmt_subst.type == FMT_A)
+ fmt_subst.w = min (8, fmt_subst.w);
+ else
+ fmt_subst.w = min (16, fmt_subst.w);
+
+ fp = &fmt_subst;
+ }
+
+ /* Format. */
+ data_out (s, fp, v);
+
+ /* Null terminate. */
+ s[fp->w] = '\0';
+}
+
/*
Local Variables:
mode: c
void data_in_finite_line (struct data_in *di, const char *line, size_t len,
int fc, int lc);
-#if __GNUC__ >= 2
-extern inline void
-data_in_finite_line (struct data_in *di, const char *line, size_t len,
- int fc, int lc)
-{
- di->s = line + ((size_t) fc <= len ? fc - 1 : len);
- di->e = line + ((size_t) lc <= len ? lc : len);
-}
-#endif /* GNU C */
-
#endif /* data-in.h */
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);
}
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;
};
static struct repeating_data_trns rpd;
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;
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 = repeating_data_trns_proc;
- rpd.h.free = destroy_dls;
+ 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;
}
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
static convert_func convert_time, convert_WKDAY, convert_MONTH;
static convert_func try_F;
-/* Converts binary value V into printable form in string S according
- to format specification FP. The string as written has exactly
- FP->W characters. It is not null-terminated. Returns 1 on
- success, 0 on failure. */
-int
+/* Converts binary value V into printable form in the exactly
+ FP->W character in buffer S according to format specification
+ FP. No null terminator is appended to the buffer. */
+void
data_out (char *s, const struct fmt_spec *fp, const union value *v)
{
+ static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
+ {
+ convert_F, convert_N, convert_E, convert_F_plus,
+ convert_F_plus, convert_F_plus, convert_F_plus,
+ convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
+ convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
+ convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
+ convert_date, convert_date, convert_date, convert_date, convert_date,
+ convert_date, convert_date, convert_date, convert_date,
+ convert_time, convert_time,
+ convert_WKDAY, convert_MONTH,
+ };
+
union value tmp_val;
{
{
memset (s, ' ', fp->w);
s[fp->w - fp->d - 1] = '.';
- return 1;
+ return;
}
if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d)
{
}
}
- {
- static convert_func *const handlers[FMT_NUMBER_OF_FORMATS] =
- {
- convert_F, convert_N, convert_E, convert_F_plus,
- convert_F_plus, convert_F_plus, convert_F_plus,
- convert_Z, convert_A, convert_AHEX, convert_IB, convert_P, convert_PIB,
- convert_PIBHEX, convert_PK, convert_RB, convert_RBHEX,
- convert_CCx, convert_CCx, convert_CCx, convert_CCx, convert_CCx,
- convert_date, convert_date, convert_date, convert_date, convert_date,
- convert_date, convert_date, convert_date, convert_date,
- convert_time, convert_time,
- convert_WKDAY, convert_MONTH,
- };
-
- return handlers[fp->type] (s, fp, v);
- }
+ if (!handlers[fp->type] (s, fp, v))
+ strncpy (s, "ERROR", fp->w);
}
/* Converts V into S in F format with width W and D decimal places,
static int
convert_A (char *dst, const struct fmt_spec *fp, const union value *v)
{
- memcpy (dst, v->c, fp->w);
+ memcpy (dst, v->s, fp->w);
return 1;
}
for (i = 0; i < fp->w / 2; i++)
{
- ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->c[i]) >> 4);
- ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->c[i]) & 0xf);
+ ((unsigned char *) dst)[i * 2] = MAKE_HEXIT ((v->s[i]) >> 4);
+ ((unsigned char *) dst)[i * 2 + 1] = MAKE_HEXIT ((v->s[i]) & 0xf);
}
return 1;
#include "vfm.h"
#include "vfmP.h"
-/* FIXME: This could be even more efficient if we caught SYSMIS when
- it first reared its ugly head, then threw it into an entirely new
- switch that handled SYSMIS aggressively like all the code does now.
- But I've spent a couple of weeks on the expression code, and that's
- enough to make anyone sick. For that matter, it could be more
- efficient if I hand-coded it in assembly for a dozen processors,
- but I'm not going to do that either. */
-
double
expr_evaluate (struct expression *e, struct ccase *c, union value *v)
{
dest = pool_alloc (e->pool, f.w + 1);
dest[0] = f.w;
+ assert ((formats[f.type].cat & FCAT_STRING) == 0);
data_out (&dest[1], &f, sp);
sp->c = dest;
}
goto finished;
default:
-#if GLOBAL_DEBUGGING
- printf (_("evaluate_expression(): not implemented: %s\n"),
- ops[op[-1]].name);
-#else
- printf (_("evaluate_expression(): not implemented: %d\n"), op[-1]);
-#endif
assert (0);
}
f.d = (int) n->arg[3];
v.f = n0;
+ assert ((formats[f.type].cat & FCAT_STRING) == 0);
data_out (strbuf, &f, &v);
n = repl_str_con (n, strbuf, f.w);
}
union value;
+/* Maximum length of formatted value, in character. */
+#define MAX_FORMATTED_LEN 256
+
int parse_format_specifier (struct fmt_spec *input, int allow_xt);
int parse_format_specifier_name (const char **cp, int allow_xt);
int check_input_specifier (const struct fmt_spec *spec);
void convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output);
int parse_string_as_format (const char *s, int len, const struct fmt_spec *fp,
int fc, union value *v);
-int data_out (char *s, const struct fmt_spec *fp, const union value *v);
+void data_out (char *s, const struct fmt_spec *fp, const union value *v);
char *fmt_to_string (const struct fmt_spec *);
void num_to_string (double v, char *s, int w, int d);
const struct freq *a = a_;
const struct freq *b = b_;
- if (a->v.c > b->v.c)
+ if (a->c > b->c)
return 1;
- else if (a->v.c < b->v.c)
+ else if (a->c < b->c)
return -1;
if (a->v.f > b->v.f)
const struct freq *b = b_;
const struct variable *v = v_;
- if (a->v.c > b->v.c)
+ if (a->c > b->c)
return 1;
- else if (a->v.c < b->v.c)
+ else if (a->c < b->c)
return -1;
else
return memcmp (a->v.s, b->v.s, v->width);
const struct freq *a = a_;
const struct freq *b = b_;
- if (a->v.c > b->v.c)
+ if (a->c > b->c)
return -1;
- else if (a->v.c < b->v.c)
+ else if (a->c < b->c)
return 1;
if (a->v.f > b->v.f)
const struct freq *b = b_;
const struct variable *v = v_;
- if (a->v.c > b->v.c)
+ if (a->c > b->c)
return -1;
- else if (a->v.c < b->v.c)
+ else if (a->c < b->c)
return 1;
else
return memcmp (a->v.s, b->v.s, v->width);
memset(&line_buf[x], ' ', width - v->print.w);
x += width - v->print.w;
}
-
- {
- union value value;
-
- if (formats[v->print.type].cat & FCAT_STRING)
- value.c = c->data[v->fv].s;
- else if (v->fv == -1)
- value.f = case_num;
- else
- value.f = c->data[v->fv].f;
-
- data_out (&line_buf[x], &v->print, &value);
- }
+
+ if ((formats[v->print.type].cat & FCAT_STRING) || v->fv != -1)
+ data_out (&line_buf[x], &v->print, &c->data[v->fv]);
+ else
+ {
+ union value case_num_value;
+ case_num_value.f = case_num;
+ data_out (&line_buf[x], &v->print, &case_num_value);
+ }
x += v->print.w;
line_buf[x++] = ' ';
for (column = 0; column < cmd.n_variables; column++)
{
struct variable *v = cmd.v_variables[column];
- union value value;
char buf[41];
- if (formats[v->print.type].cat & FCAT_STRING)
- value.c = c->data[v->fv].s;
- else if (v->fv == -1)
- value.f = case_num;
- else
- value.f = c->data[v->fv].f;
-
- data_out (buf, &v->print, &value);
+ if ((formats[v->print.type].cat & FCAT_STRING) || v->fv != -1)
+ data_out (buf, &v->print, &c->data[v->fv]);
+ else
+ {
+ union value case_num_value;
+ case_num_value.f = case_num;
+ data_out (buf, &v->print, &case_num_value);
+ }
buf[v->print.w] = 0;
fprintf (x->file.file, " <TD ALIGN=RIGHT>%s</TD>\n",
break;
case PRT_VAR:
- if (i->u.v.v->type == NUMERIC)
- data_out (&buf[i->fc], &i->u.v.f, &c->data[i->u.v.v->fv]);
- else
- {
- union value t;
- t.c = c->data[i->u.v.v->fv].s;
- data_out (&buf[i->fc], &i->u.v.f, &t);
- }
+ data_out (&buf[i->fc], &i->u.v.f, &c->data[i->u.v.v->fv]);
len = i->fc + i->u.v.f.w;
break;
loctime = localtime (&curtime);
timep = asctime (loctime);
timep[strlen (timep) - 1] = 0;
- dump (0, "/* %s", ofn);
+ dump (0, "/* %s\t\t-*- mode: c; buffer-read-only: t -*-", ofn);
dump (0, nullstr);
dump (0, " Generated by q2c from %s on %s.", ifn, timep);
dump (0, " Do not modify!");
const union value *v, const struct fmt_spec *f)
{
char *contents;
- union value temp_val;
assert (table != NULL && v != NULL && f != NULL);
#if GLOBAL_DEBUGGING
ls_init (&table->cc[c + r * table->cf], contents, f->w);
table->ct[c + r * table->cf] = opt;
- if (formats[f->type].cat & FCAT_STRING)
- {
- temp_val.c = (char *) v->s;
- v = &temp_val;
- }
data_out (contents, f, v);
}
char buf[40], *cp;
struct fmt_spec f;
+ union value double_value;
assert (table != NULL && w <= 40);
}
#endif
- data_out (buf, &f, (union value *) &val);
+ double_value.f = val;
+ data_out (buf, &f, &double_value);
+
cp = buf;
while (isspace ((unsigned char) *cp) && cp < &buf[w])
cp++;
/* Values. */
-/* Definition of the max length of a short string value, generally
- eight characters. */
+/* Max length of a short string value, generally 8 chars. */
#define MAX_SHORT_STRING ((SIZEOF_DOUBLE)>=8 ? ((SIZEOF_DOUBLE)+1)/2*2 : 8)
#define MIN_LONG_STRING (MAX_SHORT_STRING+1)
+/* Max string length. */
+#define MAX_STRING 255
+
/* FYI: It is a bad situation if sizeof(flt64) < MAX_SHORT_STRING:
then short string missing values can be truncated in system files
because there's only room for as many characters as can fit in a
/* A short-string value. */
unsigned char s[MAX_SHORT_STRING];
- /* This member is used by data-in.c to return a string result,
- since it may need to return a long string. As currently
- implemented, it's a pointer to a static internal buffer in
- data-in.c.
-
- Also used by evaluate_expression() to return a string result.
- As currently implemented, it's a pointer to a dynamic buffer in
- the appropriate expression.
+ /* Used by evaluate_expression() to return a string result.
+ As currently implemented, it's a pointer to a dynamic
+ buffer in the appropriate expression.
Also used by the AGGREGATE procedure in handling string
values. */
unsigned char *c;
-
- /* Sometimes we insert value's in a hash table. */
- unsigned long hash[SIZEOF_DOUBLE / SIZEOF_LONG];
};
+
+/* Maximum number of `union value's in a single number or string
+ value. */
+#define MAX_ELEMS_PER_VALUE (MAX_STRING / sizeof (union value) + 1)
+
+int compare_values (union value *a, union value *b, int width);
\f
/* Frequency tables. */
#include "debug-print.h"
+/* Compares A and B, which both have the given WIDTH, and returns
+ a strcmp()-type result. */
+int
+compare_values (union value *a, union value *b, int width)
+{
+ if (width == 0)
+ return a->f < b->f ? -1 : a->f > b->f;
+ else
+ return memcmp (a->s, b->s, width);
+}
+
/* Discards all the current state in preparation for a data-input
command like DATA LIST or GET. */
void
assert (v->type == NUMERIC || v->type == ALPHA);
tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name);
- {
- union value val = c->data[v->fv];
- if (v->type == ALPHA)
- val.c = c->data[v->fv].s;
- data_out (temp_buf, &v->print, &val);
- }
+ data_out (temp_buf, &v->print, &c->data[v->fv]);
temp_buf[v->print.w] = 0;
tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf);