X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fdata-io%2Fdata-list.c;h=75db52af6548f61baa214f9250856778565fb53b;hb=2c7d1b0285e21571b1e50def87e33095f095ce4e;hp=9594ead0759b888427a184e5c75322e55cac1eb7;hpb=5862de297bb487c81660beb3796d5c612eeb12b7;p=pspp
diff --git a/src/language/data-io/data-list.c b/src/language/data-io/data-list.c
index 9594ead075..75db52af65 100644
--- a/src/language/data-io/data-list.c
+++ b/src/language/data-io/data-list.c
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
+/* PSPP - a program for statistical analysis.
Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
#include
@@ -23,10 +21,10 @@
#include
#include
-#include
#include
-#include
#include
+#include
+#include
#include
#include
#include
@@ -75,7 +73,7 @@ struct dls_var_spec
};
static struct dls_var_spec *
-ll_to_dls_var_spec (struct ll *ll)
+ll_to_dls_var_spec (struct ll *ll)
{
return ll_data (ll, struct dls_var_spec, ll);
}
@@ -99,13 +97,14 @@ struct data_list_pgm
int record_cnt; /* Number of records. */
struct string delims; /* Field delimiters. */
int skip_records; /* Records to skip before first case. */
+ size_t value_cnt; /* Number of `union value's in case. */
};
-static const struct case_source_class data_list_source_class;
+static const struct casereader_class data_list_casereader_class;
-static bool parse_fixed (struct lexer *, struct dictionary *dict,
+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,
+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);
@@ -118,15 +117,14 @@ static trns_proc_func data_list_trns_proc;
int
cmd_data_list (struct lexer *lexer, struct dataset *ds)
{
- struct dictionary *dict = dataset_dict (ds);
+ struct dictionary *dict;
struct data_list_pgm *dls;
int table = -1; /* Print table if nonzero, -1=undecided. */
struct file_handle *fh = fh_inline_file ();
struct pool *tmp_pool;
bool ok;
- if (!in_input_program ())
- discard_variables (ds);
+ dict = in_input_program () ? dataset_dict (ds) : dict_create ();
dls = pool_create_container (struct data_list_pgm, pool);
ll_init (&dls->specs);
@@ -174,13 +172,13 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
msg (SE, _("The END subcommand may only be specified once."));
goto error;
}
-
+
lex_match (lexer, '=');
if (!lex_force_id (lexer))
goto error;
- dls->end = dict_lookup_var (dataset_dict (ds), lex_tokid (lexer));
- if (!dls->end)
- dls->end = dict_create_var_assert (dataset_dict (ds), lex_tokid (lexer), 0);
+ dls->end = dict_lookup_var (dict, lex_tokid (lexer));
+ if (!dls->end)
+ dls->end = dict_create_var_assert (dict, lex_tokid (lexer), 0);
lex_get (lexer);
}
else if (lex_token (lexer) == T_ID)
@@ -189,7 +187,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
table = 0;
else if (lex_match_id (lexer, "TABLE"))
table = 1;
- else
+ else
{
int type;
if (lex_match_id (lexer, "FIXED"))
@@ -198,7 +196,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
type = DLS_FREE;
else if (lex_match_id (lexer, "LIST"))
type = DLS_LIST;
- else
+ else
{
lex_error (lexer, NULL);
goto error;
@@ -213,7 +211,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
dls->type = type;
if ((dls->type == DLS_FREE || dls->type == DLS_LIST)
- && lex_match (lexer, '('))
+ && lex_match (lexer, '('))
{
while (!lex_match (lexer, ')'))
{
@@ -226,7 +224,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
delim = ds_first (lex_tokstr (lexer));
lex_get (lexer);
}
- else
+ else
{
lex_error (lexer, NULL);
goto error;
@@ -251,6 +249,12 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
if (dls->type == -1)
dls->type = DLS_FIXED;
+ if (dls->type != DLS_FIXED && dls->end != NULL)
+ {
+ msg (SE, _("The END keyword may be used only with DATA LIST FIXED."));
+ goto error;
+ }
+
if (table == -1)
table = dls->type != DLS_FREE;
@@ -273,10 +277,19 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
if (dls->reader == NULL)
goto error;
+ dls->value_cnt = dict_get_next_value_idx (dict);
+
if (in_input_program ())
add_transformation (ds, data_list_trns_proc, data_list_trns_free, dls);
- else
- proc_set_source (ds, create_case_source (&data_list_source_class, dls));
+ else
+ {
+ struct casereader *reader;
+ reader = casereader_create_sequential (NULL,
+ dict_get_next_value_idx (dict),
+ -1, &data_list_casereader_class,
+ dls);
+ proc_set_active_file (ds, reader, dict);
+ }
pool_destroy (tmp_pool);
@@ -294,7 +307,7 @@ cmd_data_list (struct lexer *lexer, struct dataset *ds)
needed once parsing is complete. Returns true only if
successful. */
static bool
-parse_fixed (struct lexer *lexer, struct dictionary *dict,
+parse_fixed (struct lexer *lexer, struct dictionary *dict,
struct pool *tmp_pool, struct data_list_pgm *dls)
{
int last_nonempty_record;
@@ -310,7 +323,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
/* Parse everything. */
if (!parse_record_placement (lexer, &record, &column)
- || !parse_DATA_LIST_vars_pool (lexer, tmp_pool,
+ || !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))
@@ -325,7 +338,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
int width;
struct variable *v;
struct dls_var_spec *spec;
-
+
name = names[name_idx++];
/* Create variable. */
@@ -343,7 +356,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
This can be acceptable if we're in INPUT
PROGRAM, but only if the existing variable has
the same width as the one we would have
- created. */
+ created. */
if (!in_input_program ())
{
msg (SE, _("%s is a duplicate variable name."), name);
@@ -379,7 +392,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
}
assert (name_idx == name_cnt);
}
- if (ll_is_empty (&dls->specs))
+ if (ll_is_empty (&dls->specs))
{
msg (SE, _("At least one variable must be specified."));
return false;
@@ -392,7 +405,7 @@ parse_fixed (struct lexer *lexer, struct dictionary *dict,
"should not exist according to RECORDS subcommand."));
return false;
}
- else if (!dls->record_cnt)
+ else if (!dls->record_cnt)
dls->record_cnt = last_nonempty_record;
return true;
@@ -446,7 +459,7 @@ 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 lexer *lexer, struct dictionary *dict, struct pool *tmp_pool,
+parse_free (struct lexer *lexer, struct dictionary *dict, struct pool *tmp_pool,
struct data_list_pgm *dls)
{
lex_get (lexer);
@@ -457,7 +470,7 @@ parse_free (struct lexer *lexer, struct dictionary *dict, struct pool *tmp_pool,
size_t name_cnt;
size_t i;
- if (!parse_DATA_LIST_vars_pool (lexer, tmp_pool,
+ if (!parse_DATA_LIST_vars_pool (lexer, tmp_pool,
&name, &name_cnt, PV_NONE))
return 0;
@@ -465,14 +478,14 @@ parse_free (struct lexer *lexer, struct dictionary *dict, struct pool *tmp_pool,
{
if (!parse_format_specifier (lexer, &input)
|| !fmt_check_input (&input)
- || !lex_force_match (lexer, ')'))
+ || !lex_force_match (lexer, ')'))
return NULL;
/* 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
@@ -518,7 +531,7 @@ dump_free_table (const struct data_list_pgm *dls,
int row;
spec_cnt = ll_count (&dls->specs);
-
+
t = tab_create (2, spec_cnt + 1, 0);
tab_columns (t, TAB_COL_DOWN, 1);
tab_headers (t, 0, 0, 1, 0);
@@ -538,11 +551,11 @@ dump_free_table (const struct data_list_pgm *dls,
}
tab_title (t, _("Reading free-form data from %s."), fh_get_name (fh));
-
+
tab_submit (t);
}
-/* Input procedure. */
+/* Input procedure. */
/* Extracts a field from the current position in the current
record. Fields can be unquoted or quoted with single- or
@@ -550,7 +563,7 @@ dump_free_table (const struct data_list_pgm *dls,
*FIELD is set to the field content. The caller must not
or destroy this constant string.
-
+
After parsing the field, sets the current position in the
record to just past the field and any trailing delimiter.
Returns 0 on failure or a 1-based column number indicating the
@@ -566,15 +579,15 @@ cut_field (const struct data_list_pgm *dls, struct substring *field)
dfm_expand_tabs (dls->reader);
line = p = dfm_get_record (dls->reader);
- if (ds_is_empty (&dls->delims))
+ if (ds_is_empty (&dls->delims))
{
bool missing_quote = false;
-
+
/* Skip leading whitespace. */
ss_ltrim (&p, ss_cstr (CC_SPACES));
if (ss_is_empty (p))
return false;
-
+
/* Handle actual data, whether quoted or unquoted. */
if (ss_match_char (&p, '\''))
missing_quote = !ss_get_until (&p, '\'', field);
@@ -591,7 +604,7 @@ cut_field (const struct data_list_pgm *dls, struct substring *field)
dfm_forward_columns (dls->reader, ss_length (line) - ss_length (p));
}
- else
+ else
{
if (!ss_is_empty (p))
ss_get_chars (&p, ss_cspan (p, ds_ss (&dls->delims)), field);
@@ -601,11 +614,11 @@ cut_field (const struct data_list_pgm *dls, struct substring *field)
trailing blank field. */
*field = p;
}
- else
+ else
return false;
/* Advance past the field.
-
+
Also advance past a trailing delimiter, regardless of
whether one actually existed. If we "skip" a delimiter
that was not actually there, then we will return
@@ -625,7 +638,7 @@ static bool read_from_data_list_list (const struct data_list_pgm *,
/* Reads a case from DLS into C.
Returns true if successful, false at end of file or on I/O error. */
static bool
-read_from_data_list (const struct data_list_pgm *dls, struct ccase *c)
+read_from_data_list (const struct data_list_pgm *dls, struct ccase *c)
{
bool retval;
@@ -650,7 +663,7 @@ read_from_data_list (const struct data_list_pgm *dls, struct ccase *c)
}
/* Reads a case from the data file into C, parsing it according
- to fixed-format syntax rules in DLS.
+ to fixed-format syntax rules in DLS.
Returns true if successful, false at end of file or on I/O error. */
static bool
read_from_data_list_fixed (const struct data_list_pgm *dls, struct ccase *c)
@@ -658,8 +671,8 @@ read_from_data_list_fixed (const struct data_list_pgm *dls, struct ccase *c)
struct dls_var_spec *spec;
int row;
- if (dfm_eof (dls->reader))
- return false;
+ if (dfm_eof (dls->reader))
+ return false;
spec = ll_to_dls_var_spec (ll_head (&dls->specs));
for (row = 1; row <= dls->record_cnt; row++)
@@ -671,14 +684,20 @@ read_from_data_list_fixed (const struct data_list_pgm *dls, struct ccase *c)
msg (SW, _("Partial case of %d of %d records discarded."),
row - 1, dls->record_cnt);
return false;
- }
+ }
dfm_expand_tabs (dls->reader);
line = dfm_get_record (dls->reader);
- ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs)
- data_in (ss_substr (line, spec->first_column - 1, spec->input.w),
- spec->input.type, spec->input.d, spec->first_column,
- case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
+ ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs)
+ {
+ if (row < spec->record)
+ break;
+
+ data_in (ss_substr (line, spec->first_column - 1, spec->input.w),
+ spec->input.type, spec->input.d, spec->first_column,
+ case_data_rw_idx (c, spec->fv),
+ fmt_var_width (&spec->input));
+ }
dfm_forward_record (dls->reader);
}
@@ -687,7 +706,7 @@ read_from_data_list_fixed (const struct data_list_pgm *dls, struct ccase *c)
}
/* Reads a case from the data file into C, parsing it according
- to free-format syntax rules in DLS.
+ to free-format syntax rules in DLS.
Returns true if successful, false at end of file or on I/O error. */
static bool
read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c)
@@ -697,11 +716,11 @@ 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;
-
+
/* Cut out a field and read in a new record if necessary. */
while (!cut_field (dls, &field))
{
- if (!dfm_eof (dls->reader))
+ if (!dfm_eof (dls->reader))
dfm_forward_record (dls->reader);
if (dfm_eof (dls->reader))
{
@@ -711,7 +730,7 @@ read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c)
return false;
}
}
-
+
data_in (field, spec->input.type, 0,
dfm_get_column (dls->reader, ss_data (field)),
case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
@@ -720,7 +739,7 @@ read_from_data_list_free (const struct data_list_pgm *dls, struct ccase *c)
}
/* Reads a case from the data file and parses it according to
- list-format syntax rules.
+ list-format syntax rules.
Returns true if successful, false at end of file or on I/O error. */
static bool
read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c)
@@ -747,11 +766,11 @@ read_from_data_list_list (const struct data_list_pgm *dls, struct ccase *c)
if (width == 0)
case_data_rw_idx (c, spec->fv)->f = SYSMIS;
else
- memset (case_data_rw_idx (c, spec->fv)->s, ' ', width);
+ memset (case_data_rw_idx (c, spec->fv)->s, ' ', width);
}
break;
}
-
+
data_in (field, spec->input.type, 0,
dfm_get_column (dls->reader, ss_data (field)),
case_data_rw_idx (c, spec->fv), fmt_var_width (&spec->input));
@@ -781,7 +800,7 @@ data_list_trns_proc (void *dls_, struct ccase *c, casenumber case_num UNUSED)
if (read_from_data_list (dls, c))
retval = TRNS_CONTINUE;
- else if (dfm_reader_error (dls->reader) || dfm_eof (dls->reader) > 1)
+ else if (dfm_reader_error (dls->reader) || dfm_eof (dls->reader) > 1)
{
/* An I/O error, or encountering end of file for a second
time, should be escalated into a more serious error. */
@@ -789,15 +808,15 @@ data_list_trns_proc (void *dls_, struct ccase *c, casenumber case_num UNUSED)
}
else
retval = TRNS_END_FILE;
-
+
/* If there was an END subcommand handle it. */
- if (dls->end != NULL)
+ if (dls->end != NULL)
{
double *end = &case_data_rw (c, dls->end)->f;
- if (retval == TRNS_DROP_CASE)
+ if (retval == TRNS_END_FILE)
{
*end = 1.0;
- retval = TRNS_END_FILE;
+ retval = TRNS_CONTINUE;
}
else
*end = 0.0;
@@ -810,39 +829,43 @@ data_list_trns_proc (void *dls_, struct ccase *c, casenumber case_num UNUSED)
Returns true if successful, false at end of file or if an
I/O error occurred. */
static bool
-data_list_source_read (struct case_source *source, struct ccase *c)
+data_list_casereader_read (struct casereader *reader UNUSED, void *dls_,
+ struct ccase *c)
{
- struct data_list_pgm *dls = source->aux;
+ struct data_list_pgm *dls = dls_;
+ bool ok;
/* Skip the requested number of records before reading the
first case. */
- while (dls->skip_records > 0)
+ while (dls->skip_records > 0)
{
if (dfm_eof (dls->reader))
return false;
dfm_forward_record (dls->reader);
dls->skip_records--;
}
-
- return read_from_data_list (dls, c);
+
+ case_create (c, dls->value_cnt);
+ ok = read_from_data_list (dls, c);
+ if (!ok)
+ case_destroy (c);
+ return ok;
}
-/* Destroys the source.
- Returns true if successful read, false if an I/O occurred
- during destruction or previously. */
-static bool
-data_list_source_destroy (struct case_source *source)
+/* Destroys the casereader. */
+static void
+data_list_casereader_destroy (struct casereader *reader UNUSED, void *dls_)
{
- struct data_list_pgm *dls = source->aux;
- bool ok = !dfm_reader_error (dls->reader);
+ struct data_list_pgm *dls = dls_;
+ if (dfm_reader_error (dls->reader))
+ casereader_force_error (reader);
data_list_trns_free (dls);
- return ok;
}
-static const struct case_source_class data_list_source_class =
+static const struct casereader_class data_list_casereader_class =
{
- "DATA LIST",
+ data_list_casereader_read,
+ data_list_casereader_destroy,
+ NULL,
NULL,
- data_list_source_read,
- data_list_source_destroy,
};