X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdata-io%2Fdata-list.c;h=641740fc6c29c66f97e583d21df58de39b298aea;hb=77555681fa75d9b790bf8ba5f8e2aafa853cc183;hp=39bd743efb3e3dec479b7c6c47a20aebe3cb7652;hpb=a37754c18dee3d5941e5fe041b2c1fa1a3370157;p=pspp-builds.git diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c index 39bd743e..641740fc 100644 --- a/src/language/data-io/data-list.c +++ b/src/language/data-io/data-list.c @@ -99,12 +99,15 @@ struct data_list_pgm struct variable *end; /* Variable specified on END subcommand. */ int record_cnt; /* Number of records. */ struct string delims; /* Field delimiters. */ + int skip_records; /* Records to skip before first case. */ }; static const struct case_source_class data_list_source_class; -static bool parse_fixed (struct pool *tmp_pool, struct data_list_pgm *); -static bool parse_free (struct pool *tmp_pool, struct data_list_pgm *); +static bool parse_fixed (struct lexer *, struct dictionary *dict, + struct pool *tmp_pool, struct data_list_pgm *); +static bool parse_free (struct lexer *, struct dictionary *dict, + struct pool *tmp_pool, struct data_list_pgm *); static void dump_fixed_table (const struct ll_list *, const struct file_handle *, int record_cnt); static void dump_free_table (const struct data_list_pgm *, @@ -114,8 +117,9 @@ static trns_free_func data_list_trns_free; static trns_proc_func data_list_trns_proc; int -cmd_data_list (void) +cmd_data_list (struct lexer *lexer, struct dataset *ds) { + struct dictionary *dict = dataset_dict (ds); struct data_list_pgm *dls; int table = -1; /* Print table if nonzero, -1=undecided. */ struct file_handle *fh = fh_inline_file (); @@ -123,7 +127,7 @@ cmd_data_list (void) bool ok; if (!in_input_program ()) - discard_variables (); + discard_variables (ds); dls = pool_create_container (struct data_list_pgm, pool); ll_init (&dls->specs); @@ -131,31 +135,40 @@ cmd_data_list (void) dls->type = -1; dls->end = NULL; dls->record_cnt = 0; + dls->skip_records = 0; ds_init_empty (&dls->delims); ds_register_pool (&dls->delims, dls->pool); tmp_pool = pool_create_subpool (dls->pool); - while (token != '/') + while (lex_token (lexer) != '/') { - if (lex_match_id ("FILE")) + if (lex_match_id (lexer, "FILE")) { - lex_match ('='); - fh = fh_parse (FH_REF_FILE | FH_REF_INLINE); + lex_match (lexer, '='); + fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE); if (fh == NULL) goto error; } - else if (lex_match_id ("RECORDS")) + else if (lex_match_id (lexer, "RECORDS")) { - lex_match ('='); - lex_match ('('); - if (!lex_force_int ()) + lex_match (lexer, '='); + lex_match (lexer, '('); + if (!lex_force_int (lexer)) goto error; - dls->record_cnt = lex_integer (); - lex_get (); - lex_match (')'); + dls->record_cnt = lex_integer (lexer); + lex_get (lexer); + lex_match (lexer, ')'); } - else if (lex_match_id ("END")) + else if (lex_match_id (lexer, "SKIP")) + { + lex_match (lexer, '='); + if (!lex_force_int (lexer)) + goto error; + dls->skip_records = lex_integer (lexer); + lex_get (lexer); + } + else if (lex_match_id (lexer, "END")) { if (dls->end) { @@ -163,32 +176,32 @@ cmd_data_list (void) goto error; } - lex_match ('='); - if (!lex_force_id ()) + lex_match (lexer, '='); + if (!lex_force_id (lexer)) goto error; - dls->end = dict_lookup_var (default_dict, tokid); + dls->end = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)); if (!dls->end) - dls->end = dict_create_var_assert (default_dict, tokid, 0); - lex_get (); + dls->end = dict_create_var_assert (dataset_dict (ds), lex_tokid (lexer), 0); + lex_get (lexer); } - else if (token == T_ID) + else if (lex_token (lexer) == T_ID) { - if (lex_match_id ("NOTABLE")) + if (lex_match_id (lexer, "NOTABLE")) table = 0; - else if (lex_match_id ("TABLE")) + else if (lex_match_id (lexer, "TABLE")) table = 1; else { int type; - if (lex_match_id ("FIXED")) + if (lex_match_id (lexer, "FIXED")) type = DLS_FIXED; - else if (lex_match_id ("FREE")) + else if (lex_match_id (lexer, "FREE")) type = DLS_FREE; - else if (lex_match_id ("LIST")) + else if (lex_match_id (lexer, "LIST")) type = DLS_LIST; else { - lex_error (NULL); + lex_error (lexer, NULL); goto error; } @@ -201,35 +214,35 @@ cmd_data_list (void) dls->type = type; if ((dls->type == DLS_FREE || dls->type == DLS_LIST) - && lex_match ('(')) + && lex_match (lexer, '(')) { - while (!lex_match (')')) + while (!lex_match (lexer, ')')) { int delim; - if (lex_match_id ("TAB")) + if (lex_match_id (lexer, "TAB")) delim = '\t'; - else if (token == T_STRING && ds_length (&tokstr) == 1) + else if (lex_token (lexer) == T_STRING && ds_length (lex_tokstr (lexer)) == 1) { - delim = ds_first (&tokstr); - lex_get (); + delim = ds_first (lex_tokstr (lexer)); + lex_get (lexer); } else { - lex_error (NULL); + lex_error (lexer, NULL); goto error; } ds_put_char (&dls->delims, delim); - lex_match (','); + lex_match (lexer, ','); } } } } else { - lex_error (NULL); + lex_error (lexer, NULL); goto error; } } @@ -242,11 +255,11 @@ cmd_data_list (void) if (table == -1) table = dls->type != DLS_FREE; - ok = (dls->type == DLS_FIXED ? parse_fixed : parse_free) (tmp_pool, dls); + ok = (dls->type == DLS_FIXED ? parse_fixed : parse_free) (lexer, dict, tmp_pool, dls); if (!ok) goto error; - if (lex_end_of_command () != CMD_SUCCESS) + if (lex_end_of_command (lexer) != CMD_SUCCESS) goto error; if (table) @@ -257,14 +270,14 @@ cmd_data_list (void) dump_free_table (dls, fh); } - dls->reader = dfm_open_reader (fh); + dls->reader = dfm_open_reader (fh, lexer); if (dls->reader == NULL) goto error; if (in_input_program ()) - add_transformation (data_list_trns_proc, data_list_trns_free, dls); + add_transformation (ds, data_list_trns_proc, data_list_trns_free, dls); else - proc_set_source (create_case_source (&data_list_source_class, dls)); + proc_set_source (ds, create_case_source (&data_list_source_class, dls)); pool_destroy (tmp_pool); @@ -282,13 +295,14 @@ cmd_data_list (void) needed once parsing is complete. Returns true only if successful. */ static bool -parse_fixed (struct pool *tmp_pool, struct data_list_pgm *dls) +parse_fixed (struct lexer *lexer, struct dictionary *dict, + struct pool *tmp_pool, struct data_list_pgm *dls) { int last_nonempty_record; int record = 0; int column = 1; - while (token != '.') + while (lex_token (lexer) != '.') { char **names; size_t name_cnt, name_idx; @@ -296,9 +310,11 @@ parse_fixed (struct pool *tmp_pool, struct data_list_pgm *dls) size_t format_cnt; /* Parse everything. */ - if (!parse_record_placement (&record, &column) - || !parse_DATA_LIST_vars_pool (tmp_pool, &names, &name_cnt, PV_NONE) - || !parse_var_placements (tmp_pool, name_cnt, &formats, &format_cnt)) + if (!parse_record_placement (lexer, &record, &column) + || !parse_DATA_LIST_vars_pool (lexer, tmp_pool, + &names, &name_cnt, PV_NONE) + || !parse_var_placements (lexer, tmp_pool, name_cnt, true, + &formats, &format_cnt)) return false; /* Create variables and var specs. */ @@ -314,15 +330,13 @@ parse_fixed (struct pool *tmp_pool, struct data_list_pgm *dls) name = names[name_idx++]; /* Create variable. */ - width = get_format_var_width (f); - v = dict_create_var (default_dict, name, width); + width = fmt_var_width (f); + v = dict_create_var (dict, name, width); if (v != NULL) { /* Success. */ - struct fmt_spec output; - convert_fmt_ItoO (f, &output); - v->print = output; - v->write = output; + struct fmt_spec output = fmt_for_output_from_input (f); + var_set_both_formats (v, &output); } else { @@ -337,15 +351,15 @@ parse_fixed (struct pool *tmp_pool, struct data_list_pgm *dls) return false; } - v = dict_lookup_var_assert (default_dict, name); - if ((width != 0) != (v->width != 0)) + v = dict_lookup_var_assert (dict, name); + if ((width != 0) != (var_get_width (v) != 0)) { msg (SE, _("There is already a variable %s of a " "different type."), name); return false; } - if (width != 0 && width != v->width) + if (width != 0 && width != var_get_width (v)) { msg (SE, _("There is already a string variable %s of a " "different width."), name); @@ -359,7 +373,7 @@ parse_fixed (struct pool *tmp_pool, struct data_list_pgm *dls) spec->fv = v->fv; spec->record = record; spec->first_column = column; - strcpy (spec->name, v->name); + strcpy (spec->name, var_get_name (v)); ll_push_tail (&dls->specs, &spec->ll); column += f->w; @@ -411,11 +425,13 @@ dump_fixed_table (const struct ll_list *specs, row = 1; ll_for_each (spec, struct dls_var_spec, ll, specs) { + char fmt_string[FMT_STRING_LEN_MAX + 1]; tab_text (t, 0, row, TAB_LEFT, spec->name); tab_text (t, 1, row, TAT_PRINTF, "%d", spec->record); tab_text (t, 2, row, TAT_PRINTF, "%3d-%3d", spec->first_column, spec->first_column + spec->input.w - 1); - tab_text (t, 3, row, TAB_LEFT | TAB_FIX, fmt_to_string (&spec->input)); + tab_text (t, 3, row, TAB_LEFT | TAB_FIX, + fmt_to_string (&spec->input, fmt_string)); row++; } @@ -431,31 +447,39 @@ dump_fixed_table (const struct ll_list *specs, them to DLS. Uses TMP_POOL for data that is not needed once parsing is complete. Returns true only if successful. */ static bool -parse_free (struct pool *tmp_pool, struct data_list_pgm *dls) +parse_free (struct lexer *lexer, struct dictionary *dict, struct pool *tmp_pool, + struct data_list_pgm *dls) { - lex_get (); - while (token != '.') + lex_get (lexer); + while (lex_token (lexer) != '.') { struct fmt_spec input, output; char **name; size_t name_cnt; size_t i; - if (!parse_DATA_LIST_vars_pool (tmp_pool, &name, &name_cnt, PV_NONE)) + if (!parse_DATA_LIST_vars_pool (lexer, tmp_pool, + &name, &name_cnt, PV_NONE)) return 0; - if (lex_match ('(')) + if (lex_match (lexer, '(')) { - if (!parse_format_specifier (&input) - || !check_input_specifier (&input, 1) - || !lex_force_match (')')) + if (!parse_format_specifier (lexer, &input) + || !fmt_check_input (&input) + || !lex_force_match (lexer, ')')) return NULL; - convert_fmt_ItoO (&input, &output); + + /* As a special case, N format is treated as F format + for free-field input. */ + if (input.type == FMT_N) + input.type = FMT_F; + + output = fmt_for_output_from_input (&input); } else { - lex_match ('*'); - input = make_input_format (FMT_F, 8, 0); + lex_match (lexer, '*'); + input = fmt_for_input (FMT_F, 8, 0); output = *get_format (); } @@ -464,19 +488,18 @@ parse_free (struct pool *tmp_pool, struct data_list_pgm *dls) struct dls_var_spec *spec; struct variable *v; - v = dict_create_var (default_dict, name[i], - get_format_var_width (&input)); + v = dict_create_var (dict, name[i], fmt_var_width (&input)); if (v == NULL) { msg (SE, _("%s is a duplicate variable name."), name[i]); return 0; } - v->print = v->write = output; + var_set_both_formats (v, &output); spec = pool_alloc (dls->pool, sizeof *spec); spec->input = input; spec->fv = v->fv; - strcpy (spec->name, v->name); + strcpy (spec->name, var_get_name (v)); ll_push_tail (&dls->specs, &spec->ll); } } @@ -505,12 +528,13 @@ dump_free_table (const struct data_list_pgm *dls, tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, spec_cnt); tab_hline (t, TAL_2, 0, 1, 1); tab_dim (t, tab_natural_dimensions); - row = 1; ll_for_each (spec, struct dls_var_spec, ll, &dls->specs) { + char str[FMT_STRING_LEN_MAX + 1]; tab_text (t, 0, row, TAB_LEFT, spec->name); - tab_text (t, 1, row, TAB_LEFT | TAB_FIX, fmt_to_string (&spec->input)); + tab_text (t, 1, row, TAB_LEFT | TAB_FIX, + fmt_to_string (&spec->input, str)); row++; } @@ -653,19 +677,9 @@ read_from_data_list_fixed (const struct data_list_pgm *dls, struct ccase *c) line = dfm_get_record (dls->reader); ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs) - { - struct data_in di; - - data_in_finite_line (&di, ss_data (line), ss_length (line), - spec->first_column, - spec->first_column + spec->input.w - 1); - di.v = case_data_rw (c, spec->fv); - di.flags = DI_IMPLIED_DECIMALS; - di.f1 = spec->first_column; - di.format = spec->input; - - data_in (&di); - } + data_in (ss_substr (line, spec->first_column - 1, spec->input.w), + spec->input.type, spec->input.d, spec->first_column, + case_data_rw (c, spec->fv), fmt_var_width (&spec->input)); dfm_forward_record (dls->reader); } @@ -684,7 +698,6 @@ read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c) ll_for_each (spec, struct dls_var_spec, ll, &dls->specs) { struct substring field; - struct data_in di; /* Cut out a field and read in a new record if necessary. */ while (!cut_field (dls, &field)) @@ -700,13 +713,9 @@ read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c) } } - di.s = ss_data (field); - di.e = ss_end (field); - di.v = case_data_rw (c, spec->fv); - di.flags = 0; - di.f1 = dfm_get_column (dls->reader, ss_data (field)); - di.format = spec->input; - data_in (&di); + data_in (field, spec->input.type, 0, + dfm_get_column (dls->reader, ss_data (field)), + case_data_rw (c, spec->fv), fmt_var_width (&spec->input)); } return true; } @@ -725,7 +734,6 @@ read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c) ll_for_each (spec, struct dls_var_spec, ll, &dls->specs) { struct substring field; - struct data_in di; if (!cut_field (dls, &field)) { @@ -736,7 +744,7 @@ read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c) spec->name); ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs) { - int width = get_format_var_width (&spec->input); + int width = fmt_var_width (&spec->input); if (width == 0) case_data_rw (c, spec->fv)->f = SYSMIS; else @@ -745,13 +753,9 @@ read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c) break; } - di.s = ss_data (field); - di.e = ss_end (field); - di.v = case_data_rw (c, spec->fv); - di.flags = 0; - di.f1 = dfm_get_column (dls->reader, ss_data (field)); - di.format = spec->input; - data_in (&di); + data_in (field, spec->input.type, 0, + dfm_get_column (dls->reader, ss_data (field)), + case_data_rw (c, spec->fv), fmt_var_width (&spec->input)); } dfm_forward_record (dls->reader); @@ -771,7 +775,7 @@ data_list_trns_free (void *dls_) /* Handle DATA LIST transformation DLS, parsing data into C. */ static int -data_list_trns_proc (void *dls_, struct ccase *c, casenum_t case_num UNUSED) +data_list_trns_proc (void *dls_, struct ccase *c, casenumber case_num UNUSED) { struct data_list_pgm *dls = dls_; int retval; @@ -813,6 +817,16 @@ data_list_source_read (struct case_source *source, { struct data_list_pgm *dls = source->aux; + /* Skip the requested number of records before reading the + first case. */ + while (dls->skip_records > 0) + { + if (dfm_eof (dls->reader)) + return false; + dfm_forward_record (dls->reader); + dls->skip_records--; + } + for (;;) { bool ok;