From: Ben Pfaff Date: Tue, 17 Feb 2004 06:19:35 +0000 (+0000) Subject: Add an Emacs header line to output files that makes generated .c files X-Git-Tag: sav-api~2586 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f972e0ef93c3a7e00fd5335ea22af2c878f4589;p=pspp 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. FREQUENCIES: Compare by frequency, not bogus a->v.c <=> b->v.c pointer compare. Changed data_out() to store string data directly into a `union value''s s member, not indirectly into c. Renamed some confusingly named member objects in crosstabs.q. --- diff --git a/src/ChangeLog b/src/ChangeLog index e7dba3586b..3df622789a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,75 @@ +Mon Feb 16 22:14:36 2004 Ben Pfaff + + * 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 + + * 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 + + 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 + + * 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 Clean up struct dictionary's value_cnt usage. diff --git a/src/crosstabs.q b/src/crosstabs.q index 11f3832dd7..36c388ac29 100644 --- a/src/crosstabs.q +++ b/src/crosstabs.q @@ -91,7 +91,7 @@ struct table_entry double *data; /* Crosstabulation table for integer mode. */ } u; - union value v[1]; /* Values. */ + union value values[1]; /* Values. */ }; /* A crosstabulation. */ @@ -100,7 +100,7 @@ struct crosstab 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. */ }; @@ -154,6 +154,9 @@ static int calc_integer (struct ccase *, void *); 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); @@ -346,7 +349,7 @@ crs_custom_tables (struct cmd_crosstabs *cmd UNUSED) 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]]; } { @@ -540,13 +543,13 @@ precalc (void *aux UNUSED) 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; @@ -557,8 +560,8 @@ precalc (void *aux UNUSED) 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); @@ -567,10 +570,10 @@ precalc (void *aux UNUSED) } 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; } @@ -609,23 +612,25 @@ calc_general (struct ccase *c, void *aux UNUSED) 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); } } } @@ -672,7 +677,7 @@ calc_integer (struct ccase *c, void *aux UNUSED) 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. */ @@ -691,9 +696,9 @@ calc_integer (struct ccase *c, void *aux UNUSED) } { - 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; } @@ -752,9 +757,9 @@ compare_table_entry (const void *a_, const void *b_, void *foo UNUSED) 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) @@ -762,9 +767,10 @@ compare_table_entry (const void *a_, const void *b_, void *foo UNUSED) } 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; } @@ -774,23 +780,17 @@ compare_table_entry (const void *a_, const void *b_, void *foo UNUSED) 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; } @@ -900,8 +900,8 @@ make_summary_table (void) 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++) @@ -944,7 +944,8 @@ insert_summary (struct tab_table *t, int tab_index, double valid) 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); @@ -1051,7 +1052,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, /* 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); @@ -1062,12 +1063,13 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, 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")); } @@ -1085,11 +1087,12 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, { 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; @@ -1097,9 +1100,9 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, 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); @@ -1288,7 +1291,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, *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.; @@ -1301,7 +1304,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, 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.; @@ -1436,8 +1439,9 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe, 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; @@ -1496,7 +1500,7 @@ delete_missing (void) 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; @@ -1510,7 +1514,7 @@ delete_missing (void) 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; @@ -1540,7 +1544,7 @@ submit (struct tab_table *t) 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); @@ -1629,7 +1633,7 @@ find_pivot_extent_general (struct table_entry **tp, int *cnt, int pivot) 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; } @@ -1663,7 +1667,8 @@ find_pivot_extent_integer (struct table_entry **tp, int *cnt, int pivot) 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; } @@ -1699,18 +1704,19 @@ enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx, { 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); @@ -1737,9 +1743,9 @@ table_value_missing (struct tab_table *table, int c, int r, unsigned char opt, 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 == ' ') @@ -1762,8 +1768,8 @@ display_dimensions (struct tab_table *table, int first_difference, struct table_ 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. */ @@ -1776,7 +1782,7 @@ float_M_suffix (struct tab_table *table, int c, int r, double v) 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--; @@ -1794,7 +1800,7 @@ display_crosstabulation (void) 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")); @@ -1853,8 +1859,8 @@ display_crosstabulation (void) } 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); @@ -1902,7 +1908,7 @@ display_crosstabulation (void) } 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); @@ -1950,7 +1956,7 @@ display_crosstabulation (void) } 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); @@ -2116,24 +2122,24 @@ display_risk (void) 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; } @@ -2248,9 +2254,9 @@ display_directional (void) 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); @@ -2421,7 +2427,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ], } /* 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); @@ -3218,6 +3224,34 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL], 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 diff --git a/src/data-in.h b/src/data-in.h index c569d55c99..450e10d2ed 100644 --- a/src/data-in.h +++ b/src/data-in.h @@ -47,14 +47,4 @@ int data_in (struct data_in *); 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 */ diff --git a/src/data-list.c b/src/data-list.c index f4ed8d874d..a0036d6aa5 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -1186,20 +1186,26 @@ read_from_data_list_list (void) 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); } @@ -1225,7 +1231,7 @@ data_list_source_read (write_case_func *write_case, write_case_data wc_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 = @@ -1254,7 +1260,6 @@ struct repeating_data_trns 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. */ @@ -1262,9 +1267,13 @@ struct repeating_data_trns 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; }; @@ -1273,6 +1282,7 @@ struct repeating_data_trns 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, @@ -1301,6 +1311,7 @@ cmd_repeating_data (void) = 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; @@ -1469,6 +1480,7 @@ cmd_repeating_data (void) 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; @@ -1533,7 +1545,7 @@ cmd_repeating_data (void) 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); @@ -1709,14 +1721,14 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c, /* 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; @@ -1725,25 +1737,21 @@ rpd_parse_record (int beg, int end, int ofs, struct ccase *c, 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; } @@ -1942,6 +1950,16 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c) 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 diff --git a/src/data-out.c b/src/data-out.c index be4471a047..7e3443290e 100644 --- a/src/data-out.c +++ b/src/data-out.c @@ -54,13 +54,25 @@ static convert_func convert_RB, convert_RBHEX, convert_CCx, convert_date; 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; { @@ -69,7 +81,7 @@ data_out (char *s, const struct fmt_spec *fp, const union value *v) { memset (s, ' ', fp->w); s[fp->w - fp->d - 1] = '.'; - return 1; + return; } if ((cat & FCAT_SHIFT_DECIMAL) && v->f != SYSMIS && fp->d) { @@ -78,22 +90,8 @@ 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, - }; - - 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, @@ -397,7 +395,7 @@ convert_Z (char *dst, const struct fmt_spec *fp, const union value *v) 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; } @@ -408,8 +406,8 @@ convert_AHEX (char *dst, const struct fmt_spec *fp, const union value *v) 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; diff --git a/src/expr-evl.c b/src/expr-evl.c index 0699e86b0b..3a6abca6eb 100644 --- a/src/expr-evl.c +++ b/src/expr-evl.c @@ -50,14 +50,6 @@ #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) { @@ -1061,6 +1053,7 @@ 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; } @@ -1292,12 +1285,6 @@ expr_evaluate (struct expression *e, struct ccase *c, union value *v) 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); } diff --git a/src/expr-opt.c b/src/expr-opt.c index e021858e96..40358a77e7 100644 --- a/src/expr-opt.c +++ b/src/expr-opt.c @@ -835,6 +835,7 @@ evaluate_tree (struct nonterm_node * n) 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); } diff --git a/src/format.h b/src/format.h index ad6d2f7ba5..a1a6e5c54e 100644 --- a/src/format.h +++ b/src/format.h @@ -77,6 +77,9 @@ extern const int translate_fmt[40]; 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); @@ -85,7 +88,7 @@ int check_string_specifier (const struct fmt_spec *spec, int min_len); 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); diff --git a/src/frequencies.q b/src/frequencies.q index 850beda2bc..44393a89bb 100644 --- a/src/frequencies.q +++ b/src/frequencies.q @@ -889,9 +889,9 @@ compare_freq_numeric_a (const void *a_, const void *b_, void *foo UNUSED) 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) @@ -911,9 +911,9 @@ compare_freq_alpha_a (const void *a_, const void *b_, void *v_) 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); @@ -927,9 +927,9 @@ compare_freq_numeric_d (const void *a_, const void *b_, void *foo UNUSED) 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) @@ -949,9 +949,9 @@ compare_freq_alpha_d (const void *a_, const void *b_, void *v_) 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); diff --git a/src/list.q b/src/list.q index 5e312f81e9..b0629e0c18 100644 --- a/src/list.q +++ b/src/list.q @@ -669,19 +669,15 @@ list_cases (struct ccase *c, void *aux UNUSED) 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++] = ' '; @@ -706,17 +702,16 @@ list_cases (struct ccase *c, void *aux UNUSED) 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, " %s\n", diff --git a/src/print.c b/src/print.c index 7d5b73b8cc..2fa40ae6e3 100644 --- a/src/print.c +++ b/src/print.c @@ -958,14 +958,7 @@ print_trns_proc (struct trns_header * trns, struct ccase * c) 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; diff --git a/src/q2c.c b/src/q2c.c index c85ea9b37d..20b245986b 100644 --- a/src/q2c.c +++ b/src/q2c.c @@ -1704,7 +1704,7 @@ dump_header (void) 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!"); diff --git a/src/tab.c b/src/tab.c index 862028a8c5..fbb292fdbb 100644 --- a/src/tab.c +++ b/src/tab.c @@ -570,7 +570,6 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt, 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 @@ -591,11 +590,6 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt, 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); } @@ -609,6 +603,7 @@ tab_float (struct tab_table *table, int c, int r, unsigned char opt, char buf[40], *cp; struct fmt_spec f; + union value double_value; assert (table != NULL && w <= 40); @@ -635,7 +630,9 @@ tab_float (struct tab_table *table, int c, int r, unsigned char opt, } #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++; diff --git a/src/var.h b/src/var.h index ea71525213..fc9827d93b 100644 --- a/src/var.h +++ b/src/var.h @@ -26,11 +26,13 @@ /* 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 @@ -54,22 +56,20 @@ union value /* 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); /* Frequency tables. */ diff --git a/src/vars-atr.c b/src/vars-atr.c index 41e4a70197..f90dc1c929 100644 --- a/src/vars-atr.c +++ b/src/vars-atr.c @@ -35,6 +35,17 @@ #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 diff --git a/src/vfm.c b/src/vfm.c index 3d40f6c029..e9c7d20480 100644 --- a/src/vfm.c +++ b/src/vfm.c @@ -1091,12 +1091,7 @@ dump_splits (struct ccase *c) 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);