X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata-list.c;h=bab5d215e9fe8ea0ed7f2c5560dd254350b277cd;hb=1f053e35b27208cad9bec322c67ba4ef022c1dc1;hp=62734de1d191f3b5eb3649c0e403b9ee1e92ee1e;hpb=965d82cdc50d81c07b736a0f92c680fdb010c976;p=pspp-builds.git diff --git a/src/data-list.c b/src/data-list.c index 62734de1..bab5d215 100644 --- a/src/data-list.c +++ b/src/data-list.c @@ -14,8 +14,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ #include #include "data-list.h" @@ -25,10 +25,12 @@ #include #include #include "alloc.h" +#include "case.h" #include "command.h" #include "data-in.h" #include "debug-print.h" -#include "dfm.h" +#include "dfm-read.h" +#include "dictionary.h" #include "error.h" #include "file-handle.h" #include "format.h" @@ -63,7 +65,7 @@ struct dls_var_spec int fc, lc; /* Column numbers in record. */ /* Free format only. */ - char name[9]; /* Name of variable. */ + char name[LONG_NAME_LEN + 1]; /* Name of variable. */ }; /* Constants for DATA LIST type. */ @@ -81,21 +83,23 @@ struct data_list_pgm struct trns_header h; struct dls_var_spec *first, *last; /* Variable parsing specifications. */ - struct file_handle *handle; /* Input file, never NULL. */ + struct dfm_reader *reader; /* Data file reader. */ int type; /* A DLS_* constant. */ struct variable *end; /* Variable specified on END subcommand. */ int eof; /* End of file encountered. */ - int nrec; /* Number of records. */ + int rec_cnt; /* Number of records. */ size_t case_size; /* Case size in bytes. */ - int delim; /* Specified delimeter */ + char *delims; /* Delimiters if any; not null-terminated. */ + size_t delim_cnt; /* Number of delimiter, or 0 for spaces. */ }; static int parse_fixed (struct data_list_pgm *); static int parse_free (struct dls_var_spec **, struct dls_var_spec **); -static void dump_fixed_table (const struct dls_var_spec *specs, - const struct file_handle *handle, int nrec); -static void dump_free_table (const struct data_list_pgm *); +static void dump_fixed_table (const struct dls_var_spec *, + const struct file_handle *, int rec_cnt); +static void dump_free_table (const struct data_list_pgm *, + const struct file_handle *); static void destroy_dls_var_spec (struct dls_var_spec *); static trns_free_func data_list_trns_free; static trns_proc_func data_list_trns_proc; @@ -106,22 +110,21 @@ static trns_proc_func data_list_trns_proc; int cmd_data_list (void) { - /* DATA LIST program under construction. */ - struct data_list_pgm *dls; - - /* 0=print no table, 1=print table. (TABLE subcommand.) */ - int table = -1; + struct data_list_pgm *dls; /* DATA LIST program under construction. */ + int table = -1; /* Print table if nonzero, -1=undecided. */ + struct file_handle *fh = NULL; /* File handle of source, NULL=inline file. */ if (!case_source_is_complex (vfm_source)) discard_variables (); dls = xmalloc (sizeof *dls); - dls->handle = default_handle; + dls->reader = NULL; dls->type = -1; dls->end = NULL; dls->eof = 0; - dls->nrec = 0; - dls->delim=0; + dls->rec_cnt = 0; + dls->delims = NULL; + dls->delim_cnt = 0; dls->first = dls->last = NULL; while (token != '/') @@ -129,11 +132,11 @@ cmd_data_list (void) if (lex_match_id ("FILE")) { lex_match ('='); - dls->handle = fh_parse_file_handle (); - if (!dls->handle) + fh = fh_parse (); + if (fh == NULL) goto error; if (case_source_is_class (vfm_source, &file_type_source_class) - && dls->handle != default_handle) + && fh != default_handle) { msg (SE, _("DATA LIST may not use a different file from " "that specified on its surrounding FILE TYPE.")); @@ -146,7 +149,7 @@ cmd_data_list (void) lex_match ('('); if (!lex_force_int ()) goto error; - dls->nrec = lex_integer (); + dls->rec_cnt = lex_integer (); lex_get (); lex_match (')'); } @@ -168,45 +171,61 @@ cmd_data_list (void) } else if (token == T_ID) { - /* Must match DLS_* constants. */ - static const char *id[] = {"FIXED", "FREE", "LIST", "NOTABLE", - "TABLE", NULL}; - const char **p; - int index; - - for (p = id; *p; p++) - if (lex_id_match (*p, tokid)) - break; - if (*p == NULL) - { - lex_error (NULL); - goto error; - } - - lex_get (); + if (lex_match_id ("NOTABLE")) + table = 0; + else if (lex_match_id ("TABLE")) + table = 1; + else + { + int type; + if (lex_match_id ("FIXED")) + type = DLS_FIXED; + else if (lex_match_id ("FREE")) + type = DLS_FREE; + else if (lex_match_id ("LIST")) + type = DLS_LIST; + else + { + lex_error (NULL); + goto error; + } - index = p - id; - if (index < 3) - { if (dls->type != -1) { msg (SE, _("Only one of FIXED, FREE, or LIST may " - "be specified.")); + "be specified.")); goto error; } - - dls->type = index; - } - else - table = index - 3; - } - else if (token=='(') { - lex_get(); - if (lex_match_id ("TAB")) { - dls->delim='\t'; + dls->type = type; + + if ((dls->type == DLS_FREE || dls->type == DLS_LIST) + && lex_match ('(')) + { + while (!lex_match (')')) + { + int delim; + + if (lex_match_id ("TAB")) + delim = '\t'; + else if (token == T_STRING && tokstr.length == 1) + { + delim = tokstr.string[0]; + lex_get(); + } + else + { + lex_error (NULL); + goto error; + } + + dls->delims = xrealloc (dls->delims, dls->delim_cnt + 1); + dls->delims[dls->delim_cnt++] = delim; + + lex_match (','); + } + } + } } - lex_get(); - } else { lex_error (NULL); @@ -215,7 +234,7 @@ cmd_data_list (void) } dls->case_size = dict_get_case_size (default_dict); - default_handle = dls->handle; + default_handle = fh; if (dls->type == -1) dls->type = DLS_FIXED; @@ -233,38 +252,34 @@ cmd_data_list (void) if (!parse_fixed (dls)) goto error; if (table) - dump_fixed_table (dls->first, dls->handle, dls->nrec); + dump_fixed_table (dls->first, fh, dls->rec_cnt); } else { if (!parse_free (&dls->first, &dls->last)) goto error; if (table) - dump_free_table (dls); + dump_free_table (dls, fh); } - if (!dfm_open_for_reading (dls->handle)) + dls->reader = dfm_open_reader (fh); + if (dls->reader == NULL) goto error; if (vfm_source != NULL) { - struct data_list_pgm *new_pgm; - dls->h.proc = data_list_trns_proc; dls->h.free = data_list_trns_free; - - new_pgm = xmalloc (sizeof *new_pgm); - memcpy (new_pgm, &dls, sizeof *new_pgm); - add_transformation (&new_pgm->h); + add_transformation (&dls->h); } else - vfm_source = create_case_source (&data_list_source_class, - default_dict, dls); + vfm_source = create_case_source (&data_list_source_class, dls); return CMD_SUCCESS; error: destroy_dls_var_spec (dls->first); + free (dls->delims); free (dls); return CMD_FAILURE; } @@ -329,7 +344,7 @@ parse_fixed (struct data_list_pgm *dls) while (lex_match ('/')) { fx.recno++; - if (lex_integer_p ()) + if (lex_is_integer ()) { if (lex_integer () < fx.recno) { @@ -350,7 +365,7 @@ parse_fixed (struct data_list_pgm *dls) if (!parse_DATA_LIST_vars (&fx.name, &fx.name_cnt, PV_NONE)) return 0; - if (token == T_NUM) + if (lex_is_number ()) { if (!fixed_parse_compatible (&fx, &dls->first, &dls->last)) goto fail; @@ -363,7 +378,7 @@ parse_fixed (struct data_list_pgm *dls) else { msg (SE, _("SPSS-like or FORTRAN-like format " - "specification expected after variable names.")); + "specification expected after variable names.")); goto fail; } @@ -376,20 +391,15 @@ parse_fixed (struct data_list_pgm *dls) msg (SE, _("At least one variable must be specified.")); return 0; } - if (dls->nrec && dls->last->rec > dls->nrec) + if (dls->rec_cnt && dls->last->rec > dls->rec_cnt) { msg (SE, _("Variables are specified on records that " "should not exist according to RECORDS subcommand.")); return 0; } - else if (!dls->nrec) - dls->nrec = dls->last->rec; - if (token != '.') - { - lex_error (_("expecting end of command")); - return 0; - } - return 1; + else if (!dls->rec_cnt) + dls->rec_cnt = dls->last->rec; + return lex_end_of_command () == CMD_SUCCESS; fail: for (i = 0; i < fx.name_cnt; i++) @@ -480,7 +490,7 @@ fixed_parse_compatible (struct fixed_parsing_state *fx, else input.type = FMT_F; - if (lex_integer_p ()) + if (lex_is_integer ()) { if (lex_integer () < 1) { @@ -514,7 +524,7 @@ fixed_parse_compatible (struct fixed_parsing_state *fx, input.type = FMT_F; input.d = 0; } - if (!check_input_specifier (&input)) + if (!check_input_specifier (&input, 1)) return 0; /* Start column for next specification. */ @@ -692,7 +702,7 @@ fixed_parse_fortran_internal (struct fixed_parsing_state *fx, tail = new; /* Parse count. */ - if (lex_integer_p ()) + if (lex_is_integer ()) { new->count = lex_integer (); lex_get (); @@ -710,8 +720,8 @@ fixed_parse_fortran_internal (struct fixed_parsing_state *fx, } else if (lex_match ('/')) new->f.type = FMT_NEWREC; - else if (!parse_format_specifier (&new->f, 1) - || !check_input_specifier (&new->f)) + else if (!parse_format_specifier (&new->f, FMTP_ALLOW_XT) + || !check_input_specifier (&new->f, 1)) goto fail; lex_match (','); @@ -761,12 +771,10 @@ fixed_parse_fortran (struct fixed_parsing_state *fx, ending column. */ static void dump_fixed_table (const struct dls_var_spec *specs, - const struct file_handle *handle, int nrec) + const struct file_handle *fh, int rec_cnt) { const struct dls_var_spec *spec; struct tab_table *t; - char *buf; - const char *filename; int i; for (i = 0, spec = specs; spec; spec = spec->next) @@ -792,21 +800,16 @@ dump_fixed_table (const struct dls_var_spec *specs, fmt_to_string (&spec->input)); } - filename = handle_get_filename (handle); - if (filename == NULL) - filename = ""; - buf = local_alloc (strlen (filename) + INT_DIGITS + 80); - sprintf (buf, (handle != inline_file - ? ngettext ("Reading %d record from file %s.", - "Reading %d records from file %s.", nrec) - : ngettext ("Reading %d record from the command file.", - "Reading %d records from the command file.", - nrec)), - nrec, filename); - - tab_title (t, 0, buf); + if (fh != NULL) + tab_title (t, 1, ngettext ("Reading %d record from file %s.", + "Reading %d records from file %s.", rec_cnt), + rec_cnt, handle_get_filename (fh)); + else + tab_title (t, 1, ngettext ("Reading %d record from the command file.", + "Reading %d records from the command file.", + rec_cnt), + rec_cnt); tab_submit (t); - local_free (buf); } /* Free-format parsing. */ @@ -828,10 +831,11 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) if (!parse_DATA_LIST_vars (&name, &name_cnt, PV_NONE)) return 0; + if (lex_match ('(')) { if (!parse_format_specifier (&input, 0) - || !check_input_specifier (&input) + || !check_input_specifier (&input, 1) || !lex_force_match (')')) { for (i = 0; i < name_cnt; i++) @@ -844,10 +848,8 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) else { lex_match ('*'); - input.type = FMT_F; - input.w = 8; - input.d = 0; - output = get_format(); + input = make_input_format (FMT_F, 8, 0); + output = get_format (); } if (input.type == FMT_A || input.type == FMT_AHEX) @@ -860,6 +862,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) struct variable *v; v = dict_create_var (default_dict, name[i], width); + if (!v) { msg (SE, _("%s is a duplicate variable name."), name[i]); @@ -874,7 +877,7 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) spec->input = input; spec->v = v; spec->fv = v->fv; - strcpy (spec->name, name[i]); + str_copy_trunc (spec->name, sizeof spec->name, v->name); append_var_spec (first, last, spec); } for (i = 0; i < name_cnt; i++) @@ -882,15 +885,14 @@ parse_free (struct dls_var_spec **first, struct dls_var_spec **last) free (name); } - if (token != '.') - lex_error (_("expecting end of command")); - return 1; + return lex_end_of_command () == CMD_SUCCESS; } /* Displays a table giving information on free-format variable parsing on DATA LIST. */ static void -dump_free_table (const struct data_list_pgm *dls) +dump_free_table (const struct data_list_pgm *dls, + const struct file_handle *fh) { struct tab_table *t; int i; @@ -919,109 +921,123 @@ dump_free_table (const struct data_list_pgm *dls) tab_text (t, 1, i, TAB_LEFT | TAT_FIX, fmt_to_string (&spec->input)); } } - - { - const char *filename; - - filename = handle_get_filename (dls->handle); - if (filename == NULL) - filename = ""; - tab_title (t, 1, - (dls->handle != inline_file - ? _("Reading free-form data from file %s.") - : _("Reading free-form data from the command file.")), - filename); - } + + if (fh != NULL) + tab_title (t, 1, _("Reading free-form data from file %s."), + handle_get_filename (fh)); + else + tab_title (t, 1, _("Reading free-form data from the command file.")); tab_submit (t); } /* Input procedure. */ -/* Extracts a field from the current position in the current record. - Fields can be unquoted or quoted with single- or double-quote - characters. *RET_LEN is set to the field length, *RET_CP is set to - the field itself. After parsing the field, sets the current - position in the record to just past the field. Returns 0 on - failure or a 1-based column number indicating the beginning of the - field on success. */ +/* Extracts a field from the current position in the current + record. Fields can be unquoted or quoted with single- or + double-quote characters. *FIELD is set to the field content. + After parsing the field, sets the current position in the + record to just past the field and any trailing delimiter. + END_BLANK is used internally; it should be initialized by the + caller to 0 and left alone afterward. Returns 0 on failure or + a 1-based column number indicating the beginning of the field + on success. */ static int -cut_field (const struct data_list_pgm *dls, char **ret_cp, int *ret_len) +cut_field (const struct data_list_pgm *dls, struct fixed_string *field, + int *end_blank) { - char *cp, *ep; - int len; + struct fixed_string line; + char *cp; + size_t column_start; - cp = dfm_get_record (dls->handle, &len); - if (!cp) + if (dfm_eof (dls->reader)) return 0; + if (dls->delim_cnt == 0) + dfm_expand_tabs (dls->reader); + dfm_get_record (dls->reader, &line); - ep = cp + len; - if (dls->delim != 0) { - if (*cp==dls->delim) { - cp++; - } - } else { - - /* Skip leading whitespace and commas. */ - while ((isspace ((unsigned char) *cp) || *cp == ',') && cp < ep) - cp++; - } - if (cp >= ep) - return 0; - - /* Three types of fields: quoted with ', quoted with ", unquoted. */ - /* Quoting does not escape the effects of delimiters for explicitly */ - /* specified delims */ - /* (consistency with SPSS doco: */ - /* For data with explicitly specified value delimiters (for example, */ - /* DATA LIST FREE (","): */ - /* - Multiple delimiters without any intervening space can be used */ - /* to specify missing data. */ - /* - The specified delimiters cannot occur within a data value, even */ - /* if you enclose the value in quotation marks or apostrophes. */ - if (dls->delim==0 && (*cp == '\'' || *cp == '"')) + cp = ls_c_str (&line); + if (dls->delim_cnt == 0) { - int quote = *cp; - - *ret_cp = ++cp; - while (cp < ep && *cp != quote) - cp++; - if (dls->delim!=0) { - while(cpdelim) { - cp++; + /* Skip leading whitespace. */ + while (cp < ls_end (&line) && isspace ((unsigned char) *cp)) + cp++; + if (cp >= ls_end (&line)) + return 0; + + /* Handle actual data, whether quoted or unquoted. */ + if (*cp == '\'' || *cp == '"') + { + int quote = *cp; + + field->string = ++cp; + while (cp < ls_end (&line) && *cp != quote) + cp++; + field->length = cp - field->string; + if (cp < ls_end (&line)) + cp++; + else + msg (SW, _("Quoted string missing terminating `%c'."), quote); } - } - *ret_len = cp - *ret_cp; - if (cp < ep) - cp++; else - msg (SW, _("Scope of string exceeds line.")); + { + field->string = cp; + while (cp < ls_end (&line) + && !isspace ((unsigned char) *cp) && *cp != ',') + cp++; + field->length = cp - field->string; + } + + /* Skip trailing whitespace and a single comma if present. */ + while (cp < ls_end (&line) && isspace ((unsigned char) *cp)) + cp++; + if (cp < ls_end (&line) && *cp == ',') + cp++; } - else + else { - *ret_cp = cp; - if (dls->delim!=0) { - while(cpdelim) { - cp++; + if (cp >= ls_end (&line)) + { + int column = dfm_column_start (dls->reader); + /* A blank line or a line that ends in \t has a + trailing blank field. */ + if (column == 1 || (column > 1 && cp[-1] == '\t')) + { + if (*end_blank == 0) + { + *end_blank = 1; + field->string = ls_end (&line); + field->length = 0; + dfm_forward_record (dls->reader); + return column; + } + else + { + *end_blank = 0; + return 0; + } + } + else + return 0; + } + else + { + field->string = cp; + while (cp < ls_end (&line) + && memchr (dls->delims, *cp, dls->delim_cnt) == NULL) + cp++; + field->length = cp - field->string; + if (cp < ls_end (&line)) + cp++; } - } else { - - while (cp < ep && !isspace ((unsigned char) *cp) && *cp != ',') - cp++; - } - *ret_len = cp - *ret_cp; } - - { - int beginning_column; - - dfm_set_record (dls->handle, *ret_cp); - beginning_column = dfm_get_cur_col (dls->handle) + 1; + + dfm_forward_columns (dls->reader, field->string - line.string); + column_start = dfm_column_start (dls->reader); - dfm_set_record (dls->handle, cp); + dfm_forward_columns (dls->reader, cp - field->string); - return beginning_column; - } + return column_start; } typedef int data_list_read_func (const struct data_list_pgm *, struct ccase *); @@ -1061,35 +1077,37 @@ read_from_data_list_fixed (const struct data_list_pgm *dls, struct dls_var_spec *var_spec = dls->first; int i; - if (!dfm_get_record (dls->handle, NULL)) + if (dfm_eof (dls->reader)) return -2; - for (i = 1; i <= dls->nrec; i++) + for (i = 1; i <= dls->rec_cnt; i++) { - int len; - char *line = dfm_get_record (dls->handle, &len); + struct fixed_string line; - if (!line) + if (dfm_eof (dls->reader)) { /* Note that this can't occur on the first record. */ msg (SW, _("Partial case of %d of %d records discarded."), - i - 1, dls->nrec); + i - 1, dls->rec_cnt); return -2; } + dfm_expand_tabs (dls->reader); + dfm_get_record (dls->reader, &line); for (; var_spec && i == var_spec->rec; var_spec = var_spec->next) { struct data_in di; - data_in_finite_line (&di, line, len, var_spec->fc, var_spec->lc); - di.v = &c->data[var_spec->fv]; - di.flags = 0; + data_in_finite_line (&di, ls_c_str (&line), ls_length (&line), + var_spec->fc, var_spec->lc); + di.v = case_data_rw (c, var_spec->fv); + di.flags = DI_IMPLIED_DECIMALS; di.f1 = var_spec->fc; di.format = var_spec->input; data_in (&di); } - dfm_fwd_record (dls->handle); + dfm_forward_record (dls->reader); } return -1; @@ -1103,27 +1121,27 @@ read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c) { struct dls_var_spec *var_spec; - char *field; - int len; + int end_blank = 0; for (var_spec = dls->first; var_spec; var_spec = var_spec->next) { + struct fixed_string field; int column; /* Cut out a field and read in a new record if necessary. */ for (;;) { - column = cut_field (dls, &field, &len); + column = cut_field (dls, &field, &end_blank); if (column != 0) break; - if (dfm_get_record (dls->handle, NULL)) - dfm_fwd_record (dls->handle); - if (!dfm_get_record (dls->handle, NULL)) + if (!dfm_eof (dls->reader)) + dfm_forward_record (dls->reader); + if (dfm_eof (dls->reader)) { if (var_spec != dls->first) msg (SW, _("Partial case discarded. The first variable " - "missing was %s."), var_spec->name); + "missing was %s."), var_spec->name); return -2; } } @@ -1131,9 +1149,9 @@ read_from_data_list_free (const struct data_list_pgm *dls, { struct data_in di; - di.s = field; - di.e = field + len; - di.v = &c->data[var_spec->fv]; + di.s = ls_c_str (&field); + di.e = ls_end (&field); + di.v = case_data_rw (c, var_spec->fv); di.flags = 0; di.f1 = column; di.format = var_spec->input; @@ -1151,31 +1169,32 @@ read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c) { struct dls_var_spec *var_spec; - char *field; - int len; + int end_blank = 0; - if (!dfm_get_record (dls->handle, NULL)) + if (dfm_eof (dls->reader)) return -2; for (var_spec = dls->first; var_spec; var_spec = var_spec->next) { + struct fixed_string field; + int column; + /* Cut out a field and check for end-of-line. */ - int column = cut_field (dls, &field, &len); - + column = cut_field (dls, &field, &end_blank); if (column == 0) { - if (get_undefined() ) + if (get_undefined ()) msg (SW, _("Missing value(s) for all variables from %s onward. " - "These will be filled with the system-missing value " - "or blanks, as appropriate."), + "These will be filled with the system-missing value " + "or blanks, as appropriate."), var_spec->name); - for (; var_spec; var_spec = var_spec->next) + for (; var_spec; var_spec = var_spec->next) { int width = get_format_var_width (&var_spec->input); if (width == 0) - c->data[var_spec->fv].f = SYSMIS; + case_data_rw (c, var_spec->fv)->f = SYSMIS; else - memset (c->data[var_spec->fv].s, ' ', width); + memset (case_data_rw (c, var_spec->fv)->s, ' ', width); } break; } @@ -1183,9 +1202,9 @@ read_from_data_list_list (const struct data_list_pgm *dls, { struct data_in di; - di.s = field; - di.e = field + len; - di.v = &c->data[var_spec->fv]; + di.s = ls_c_str (&field); + di.e = ls_end (&field); + di.v = case_data_rw (c, var_spec->fv); di.flags = 0; di.f1 = column; di.format = var_spec->input; @@ -1193,7 +1212,7 @@ read_from_data_list_list (const struct data_list_pgm *dls, } } - dfm_fwd_record (dls->handle); + dfm_forward_record (dls->reader); return -1; } @@ -1216,9 +1235,9 @@ static void data_list_trns_free (struct trns_header *pgm) { struct data_list_pgm *dls = (struct data_list_pgm *) pgm; + free (dls->delims); destroy_dls_var_spec (dls->first); - fh_close_handle (dls->handle); - free (pgm); + dfm_close_reader (dls->reader); } /* Handle DATA LIST transformation T, parsing data into C. */ @@ -1230,7 +1249,7 @@ data_list_trns_proc (struct trns_header *t, struct ccase *c, data_list_read_func *read_func; int retval; - dfm_push (dls->handle); + dfm_push (dls->reader); read_func = get_data_list_read_func (dls); retval = read_func (dls, c); @@ -1244,7 +1263,7 @@ data_list_trns_proc (struct trns_header *t, struct ccase *c, { msg (SE, _("Attempt to read past end of file.")); err_failure (); - dfm_pop (dls->handle); + dfm_pop (dls->reader); return -2; } @@ -1259,14 +1278,14 @@ data_list_trns_proc (struct trns_header *t, struct ccase *c, { if (retval == -2) { - c->data[dls->end->fv].f = 1.0; + case_data_rw (c, dls->end->fv)->f = 1.0; retval = -1; } else - c->data[dls->end->fv].f = 0.0; + case_data_rw (c, dls->end->fv)->f = 0.0; } - dfm_pop (dls->handle); + dfm_pop (dls->reader); return retval; } @@ -1281,13 +1300,11 @@ data_list_source_read (struct case_source *source, struct data_list_pgm *dls = source->aux; data_list_read_func *read_func = get_data_list_read_func (dls); - dfm_push (dls->handle); + dfm_push (dls->reader); while (read_func (dls, c) != -2) if (!write_case (wc_data)) break; - dfm_pop (dls->handle); - - fh_close_handle (dls->handle); + dfm_pop (dls->reader); } /* Destroys the source's internal data. */ @@ -1295,6 +1312,7 @@ static void data_list_source_destroy (struct case_source *source) { data_list_trns_free (source->aux); + free (source->aux); } const struct case_source_class data_list_source_class = @@ -1319,7 +1337,7 @@ struct repeating_data_trns { struct trns_header h; struct dls_var_spec *first, *last; /* Variable parsing specifications. */ - struct file_handle *handle; /* Input file, never NULL. */ + struct dfm_reader *reader; /* Input file, never NULL. */ struct rpd_num_or_var starts_beg; /* STARTS=, before the dash. */ struct rpd_num_or_var starts_end; /* STARTS=, after the dash. */ @@ -1350,17 +1368,18 @@ int cmd_repeating_data (void) { struct repeating_data_trns *rpd; - - /* 0=print no table, 1=print table. (TABLE subcommand.) */ - int table = 1; - - /* Bits are set when a particular subcommand has been seen. */ - unsigned seen = 0; + int table = 1; /* Print table? */ + bool saw_starts = false; /* Saw STARTS subcommand? */ + bool saw_occurs = false; /* Saw OCCURS subcommand? */ + bool saw_length = false; /* Saw LENGTH subcommand? */ + bool saw_continued = false; /* Saw CONTINUED subcommand? */ + bool saw_id = false; /* Saw ID subcommand? */ + struct file_handle *const fh = default_handle; assert (case_source_is_complex (vfm_source)); rpd = xmalloc (sizeof *rpd); - rpd->handle = default_handle; + rpd->reader = dfm_open_reader (default_handle); rpd->first = rpd->last = NULL; rpd->starts_beg.num = 0; rpd->starts_beg.var = NULL; @@ -1376,11 +1395,12 @@ cmd_repeating_data (void) { if (lex_match_id ("FILE")) { + struct file_handle *file; lex_match ('='); - rpd->handle = fh_parse_file_handle (); - if (!rpd->handle) + file = fh_parse (); + if (file == NULL) goto error; - if (rpd->handle != default_handle) + if (file != fh) { msg (SE, _("REPEATING DATA must use the same file as its " "corresponding DATA LIST or FILE TYPE.")); @@ -1390,13 +1410,13 @@ cmd_repeating_data (void) else if (lex_match_id ("STARTS")) { lex_match ('='); - if (seen & 1) + if (saw_starts) { msg (SE, _("%s subcommand given multiple times."),"STARTS"); goto error; } - seen |= 1; - + saw_starts = true; + if (!parse_num_or_var (&rpd->starts_beg, "STARTS beginning column")) goto error; @@ -1406,11 +1426,10 @@ cmd_repeating_data (void) if (!parse_num_or_var (&rpd->starts_end, "STARTS ending column")) goto error; } else { - /* Otherwise, rpd->starts_end is left uninitialized. - This is okay. We will initialize it later from the - record length of the file. We can't do this now - because we can't be sure that the user has specified - the file handle yet. */ + /* Otherwise, rpd->starts_end is uninitialized. We + will initialize it later from the record length + of the file. We can't do so now because the + file handle may not be specified yet. */ } if (rpd->starts_beg.num != 0 && rpd->starts_end.num != 0 @@ -1425,12 +1444,12 @@ cmd_repeating_data (void) else if (lex_match_id ("OCCURS")) { lex_match ('='); - if (seen & 2) + if (saw_occurs) { msg (SE, _("%s subcommand given multiple times."),"OCCURS"); goto error; } - seen |= 2; + saw_occurs |= 2; if (!parse_num_or_var (&rpd->occurs, "OCCURS")) goto error; @@ -1438,12 +1457,12 @@ cmd_repeating_data (void) else if (lex_match_id ("LENGTH")) { lex_match ('='); - if (seen & 4) + if (saw_length & 4) { msg (SE, _("%s subcommand given multiple times."),"LENGTH"); goto error; } - seen |= 4; + saw_length |= 4; if (!parse_num_or_var (&rpd->length, "LENGTH")) goto error; @@ -1451,16 +1470,17 @@ cmd_repeating_data (void) else if (lex_match_id ("CONTINUED")) { lex_match ('='); - if (seen & 8) + if (saw_continued & 8) { msg (SE, _("%s subcommand given multiple times."),"CONTINUED"); goto error; } - seen |= 8; + saw_continued |= 8; if (!lex_match ('/')) { - if (!parse_num_or_var (&rpd->cont_beg, "CONTINUED beginning column")) + if (!parse_num_or_var (&rpd->cont_beg, + "CONTINUED beginning column")) goto error; lex_negative_to_dash (); @@ -1484,12 +1504,12 @@ cmd_repeating_data (void) else if (lex_match_id ("ID")) { lex_match ('='); - if (seen & 16) + if (saw_id & 16) { msg (SE, _("%s subcommand given multiple times."),"ID"); goto error; } - seen |= 16; + saw_id |= 16; if (!lex_force_int ()) goto error; @@ -1553,58 +1573,71 @@ cmd_repeating_data (void) } /* Comes here when DATA specification encountered. */ - if ((seen & (1 | 2)) != (1 | 2)) + if (!saw_starts || !saw_occurs) { - if ((seen & 1) == 0) + if (!saw_starts) msg (SE, _("Missing required specification STARTS.")); - if ((seen & 2) == 0) + if (!saw_occurs) msg (SE, _("Missing required specification OCCURS.")); goto error; } /* Enforce ID restriction. */ - if ((seen & 16) && !(seen & 8)) + if (saw_id && !saw_continued) { msg (SE, _("ID specified without CONTINUED.")); goto error; } - /* Calculate starts_end, cont_end if necessary. */ - if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL) - rpd->starts_end.num = handle_get_record_width (rpd->handle); - if (rpd->cont_end.num == 0 && rpd->starts_end.var == NULL) - rpd->cont_end.num = handle_get_record_width (rpd->handle); - - /* Calculate length if possible. */ - if ((seen & 4) == 0) + /* Calculate and check starts_end, cont_end if necessary. */ + if (rpd->starts_end.num == 0 && rpd->starts_end.var == NULL) { - struct dls_var_spec *iter; - - for (iter = rpd->first; iter; iter = iter->next) - { - if (iter->lc > rpd->length.num) - rpd->length.num = iter->lc; - } - assert (rpd->length.num != 0); + rpd->starts_end.num = fh != NULL ? handle_get_record_width (fh) : 80; + if (rpd->starts_beg.num != 0 + && rpd->starts_beg.num > rpd->starts_end.num) + { + msg (SE, _("STARTS beginning column (%d) exceeds " + "default STARTS ending column taken from file's " + "record width (%d)."), + rpd->starts_beg.num, rpd->starts_end.num); + goto error; + } + } + if (rpd->cont_end.num == 0 && rpd->cont_end.var == NULL) + { + rpd->cont_end.num = fh != NULL ? handle_get_record_width (fh) : 80; + if (rpd->cont_beg.num != 0 + && rpd->cont_beg.num > rpd->cont_end.num) + { + msg (SE, _("CONTINUED beginning column (%d) exceeds " + "default CONTINUED ending column taken from file's " + "record width (%d)."), + rpd->cont_beg.num, rpd->cont_end.num); + goto error; + } } lex_match ('='); if (!parse_repeating_data (&rpd->first, &rpd->last)) goto error; + /* Calculate length if necessary. */ + if (!saw_length) + { + struct dls_var_spec *iter; + + for (iter = rpd->first; iter; iter = iter->next) + if (iter->lc > rpd->length.num) + rpd->length.num = iter->lc; + assert (rpd->length.num != 0); + } + if (table) - dump_fixed_table (rpd->first, rpd->handle, rpd->last->rec); - - { - struct repeating_data_trns *new_trns; + dump_fixed_table (rpd->first, fh, rpd->last->rec); - 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); - add_transformation ((struct trns_header *) new_trns); - } + rpd->h.proc = repeating_data_trns_proc; + rpd->h.free = repeating_data_trns_free; + add_transformation (&rpd->h); return lex_end_of_command (); @@ -1661,7 +1694,7 @@ parse_num_or_var (struct rpd_num_or_var *value, const char *message) return 0; } } - else if (lex_integer_p ()) + else if (lex_is_integer ()) { value->num = lex_integer (); @@ -1696,7 +1729,7 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last) if (!parse_DATA_LIST_vars (&fx.name, &fx.name_cnt, PV_NONE)) return 0; - if (token == T_NUM) + if (lex_is_number ()) { if (!fixed_parse_compatible (&fx, first, last)) goto fail; @@ -1709,7 +1742,7 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last) else { msg (SE, _("SPSS-like or FORTRAN-like format " - "specification expected after variable names.")); + "specification expected after variable names.")); goto fail; } @@ -1717,11 +1750,6 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last) free (fx.name[i]); free (fx.name); } - if (token != '.') - { - lex_error (_("expecting end of command")); - return 0; - } return 1; @@ -1739,21 +1767,13 @@ parse_repeating_data (struct dls_var_spec **first, struct dls_var_spec **last) static int realize_value (struct rpd_num_or_var *n, struct ccase *c) { - if (n->num > 0) - return n->num; - - assert (n->num == 0); if (n->var != NULL) { - double v = c->data[n->var->fv].f; - - if (v == SYSMIS || v <= INT_MIN || v >= INT_MAX) - return -1; - else - return v; + double v = case_num (c, n->var->fv); + return v != SYSMIS && v >= INT_MIN && v <= INT_MAX ? v : -1; } else - return 0; + return n->num; } /* Parameter record passed to rpd_parse_record(). */ @@ -1852,7 +1872,7 @@ rpd_parse_record (const struct rpd_parse_info *info) struct data_in di; data_in_finite_line (&di, info->line, info->len, fc, lc); - di.v = &info->c->data[var_spec->fv]; + di.v = case_data_rw (info->c, var_spec->fv); di.flags = 0; di.f1 = fc + 1; di.format = var_spec->input; @@ -1882,15 +1902,14 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, { struct repeating_data_trns *t = (struct repeating_data_trns *) trns; - char *line; /* Current record. */ - int len; /* Length of current record. */ + struct fixed_string line; /* Current record. */ int starts_beg; /* Starting column. */ int starts_end; /* Ending column. */ int occurs; /* Number of repetitions. */ int length; /* Length of each occurrence. */ - int cont_beg; /* Starting column for continuation lines. */ - int cont_end; /* Ending column for continuation lines. */ + int cont_beg; /* Starting column for continuation lines. */ + int cont_end; /* Ending column for continuation lines. */ int occurs_left; /* Number of occurrences remaining. */ @@ -1898,14 +1917,15 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, int skip_first_record = 0; - dfm_push (t->handle); + dfm_push (t->reader); /* Read the current record. */ - dfm_bkwd_record (t->handle, 1); - line = dfm_get_record (t->handle, &len); - if (line == NULL) + dfm_reread_record (t->reader, 1); + dfm_expand_tabs (t->reader); + if (dfm_eof (t->reader)) return -2; - dfm_fwd_record (t->handle); + dfm_get_record (t->reader, &line); + dfm_forward_record (t->reader); /* Calculate occurs, length. */ occurs_left = occurs = realize_value (&t->occurs, c); @@ -1959,8 +1979,8 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, { struct rpd_parse_info info; info.trns = t; - info.line = line; - info.len = len; + info.line = ls_c_str (&line); + info.len = ls_length (&line); info.beg = starts_beg; info.end = starts_end; info.ofs = length; @@ -1995,8 +2015,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, assert (occurs_left >= 0); /* Read in another record. */ - line = dfm_get_record (t->handle, &len); - if (line == NULL) + if (dfm_eof (t->reader)) { tmsg (SE, RPD_ERR, _("Unexpected end of file with %d repetitions " @@ -2004,12 +2023,14 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, occurs_left, occurs); return -2; } - dfm_fwd_record (t->handle); + dfm_expand_tabs (t->reader); + dfm_get_record (t->reader, &line); + dfm_forward_record (t->reader); /* Parse this record. */ info.trns = t; - info.line = line; - info.len = len; + info.line = ls_c_str (&line); + info.len = ls_length (&line); info.beg = cont_beg; info.end = cont_end; info.ofs = length; @@ -2022,7 +2043,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c, occurs_left -= code; } - dfm_pop (t->handle); + dfm_pop (t->reader); /* FIXME: This is a kluge until we've implemented multiplexing of transformations. */ @@ -2036,7 +2057,7 @@ repeating_data_trns_free (struct trns_header *rpd_) struct repeating_data_trns *rpd = (struct repeating_data_trns *) rpd_; destroy_dls_var_spec (rpd->first); - fh_close_handle (rpd->handle); + dfm_close_reader (rpd->reader); free (rpd->id_value); }