1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009, 2010, 2011, 2012, 2013, 2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "language/data-io/data-parser.h"
24 #include "data/casereader-provider.h"
25 #include "data/data-in.h"
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/format.h"
29 #include "data/file-handle-def.h"
30 #include "data/settings.h"
31 #include "language/data-io/data-reader.h"
32 #include "libpspp/intern.h"
33 #include "libpspp/message.h"
34 #include "libpspp/str.h"
35 #include "libpspp/string-array.h"
36 #include "output/pivot-table.h"
38 #include "gl/xalloc.h"
41 #define N_(msgid) msgid
42 #define _(msgid) gettext (msgid)
44 /* Data parser for textual data like that read by DATA LIST. */
47 enum data_parser_type type; /* Type of data to parse. */
48 int skip_records; /* Records to skip before first real data. */
50 struct field *fields; /* Fields to parse. */
51 size_t n_fields; /* Number of fields. */
52 size_t field_allocated; /* Number of fields spaced allocated for. */
54 /* DP_DELIMITED parsers only. */
55 bool span; /* May cases span multiple records? */
56 bool empty_line_has_field; /* Does an empty line have an (empty) field? */
57 bool warn_missing_fields; /* Should missing fields be considered errors? */
58 struct substring quotes; /* Characters that can quote separators. */
59 bool quote_escape; /* Doubled quote acts as escape? */
60 struct substring soft_seps; /* Two soft separators act like just one. */
61 struct substring hard_seps; /* Two hard separators yield empty fields. */
62 struct string any_sep; /* Concatenation of soft_seps and hard_seps. */
64 /* DP_FIXED parsers only. */
65 int records_per_case; /* Number of records in each case. */
68 /* How to parse one variable. */
71 struct fmt_spec format; /* Input format of this field. */
72 int case_idx; /* First value in case. */
73 char *name; /* Var name for error messages and tables. */
76 int record; /* Record number (1-based). */
77 int first_column; /* First column in record (1-based). */
80 static void set_any_sep (struct data_parser *parser);
82 /* Creates and returns a new data parser. */
84 data_parser_create (void)
86 struct data_parser *parser = xmalloc (sizeof *parser);
88 parser->type = DP_FIXED;
89 parser->skip_records = 0;
91 parser->fields = NULL;
93 parser->field_allocated = 0;
96 parser->empty_line_has_field = false;
97 parser->warn_missing_fields = true;
98 ss_alloc_substring (&parser->quotes, ss_cstr ("\"'"));
99 parser->quote_escape = false;
100 ss_alloc_substring (&parser->soft_seps, ss_cstr (CC_SPACES));
101 ss_alloc_substring (&parser->hard_seps, ss_cstr (","));
102 ds_init_empty (&parser->any_sep);
103 set_any_sep (parser);
105 parser->records_per_case = 0;
110 /* Destroys PARSER. */
112 data_parser_destroy (struct data_parser *parser)
118 for (i = 0; i < parser->n_fields; i++)
119 free (parser->fields[i].name);
120 free (parser->fields);
121 ss_dealloc (&parser->quotes);
122 ss_dealloc (&parser->soft_seps);
123 ss_dealloc (&parser->hard_seps);
124 ds_destroy (&parser->any_sep);
129 /* Returns the type of PARSER (either DP_DELIMITED or DP_FIXED). */
130 enum data_parser_type
131 data_parser_get_type (const struct data_parser *parser)
136 /* Sets the type of PARSER to TYPE (either DP_DELIMITED or
139 data_parser_set_type (struct data_parser *parser, enum data_parser_type type)
141 assert (parser->n_fields == 0);
142 assert (type == DP_FIXED || type == DP_DELIMITED);
146 /* Configures PARSER to skip the specified number of
147 INITIAL_RECORDS_TO_SKIP before parsing any data. By default,
148 no records are skipped. */
150 data_parser_set_skip (struct data_parser *parser, int initial_records_to_skip)
152 assert (initial_records_to_skip >= 0);
153 parser->skip_records = initial_records_to_skip;
156 /* Returns true if PARSER is configured to allow cases to span
159 data_parser_get_span (const struct data_parser *parser)
164 /* If MAY_CASES_SPAN_RECORDS is true, configures PARSER to allow
165 a single case to span multiple records and multiple cases to
166 occupy a single record. If MAY_CASES_SPAN_RECORDS is false,
167 configures PARSER to require each record to contain exactly
170 This setting affects parsing of DP_DELIMITED files only. */
172 data_parser_set_span (struct data_parser *parser, bool may_cases_span_records)
174 parser->span = may_cases_span_records;
177 /* If EMPTY_LINE_HAS_FIELD is true, configures PARSER to parse an
178 empty line as an empty field and to treat a hard delimiter
179 followed by end-of-line as an empty field. If
180 EMPTY_LINE_HAS_FIELD is false, PARSER will skip empty lines
181 and hard delimiters at the end of lines without emitting empty
184 This setting affects parsing of DP_DELIMITED files only. */
186 data_parser_set_empty_line_has_field (struct data_parser *parser,
187 bool empty_line_has_field)
189 parser->empty_line_has_field = empty_line_has_field;
193 /* If WARN_MISSING_FIELDS is true, configures PARSER to emit a warning
194 and cause an error condition when a missing field is encountered.
195 If WARN_MISSING_FIELDS is false, PARSER will silently fill such
196 fields with the system missing value.
198 This setting affects parsing of DP_DELIMITED files only. */
200 data_parser_set_warn_missing_fields (struct data_parser *parser,
201 bool warn_missing_fields)
203 parser->warn_missing_fields = warn_missing_fields;
207 /* Sets the characters that may be used for quoting field
208 contents to QUOTES. If QUOTES is empty, quoting will be
211 The caller retains ownership of QUOTES.
213 This setting affects parsing of DP_DELIMITED files only. */
215 data_parser_set_quotes (struct data_parser *parser, struct substring quotes)
217 ss_dealloc (&parser->quotes);
218 ss_alloc_substring (&parser->quotes, quotes);
221 /* If ESCAPE is false (the default setting), a character used for
222 quoting cannot itself be embedded within a quoted field. If
223 ESCAPE is true, then a quote character can be embedded within
224 a quoted field by doubling it.
226 This setting affects parsing of DP_DELIMITED files only, and
227 only when at least one quote character has been set (with
228 data_parser_set_quotes). */
230 data_parser_set_quote_escape (struct data_parser *parser, bool escape)
232 parser->quote_escape = escape;
235 /* Sets PARSER's soft delimiters to DELIMITERS. Soft delimiters
236 separate fields, but consecutive soft delimiters do not yield
237 empty fields. (Ordinarily, only white space characters are
238 appropriate soft delimiters.)
240 The caller retains ownership of DELIMITERS.
242 This setting affects parsing of DP_DELIMITED files only. */
244 data_parser_set_soft_delimiters (struct data_parser *parser,
245 struct substring delimiters)
247 ss_dealloc (&parser->soft_seps);
248 ss_alloc_substring (&parser->soft_seps, delimiters);
249 set_any_sep (parser);
252 /* Sets PARSER's hard delimiters to DELIMITERS. Hard delimiters
253 separate fields. A consecutive pair of hard delimiters yield
256 The caller retains ownership of DELIMITERS.
258 This setting affects parsing of DP_DELIMITED files only. */
260 data_parser_set_hard_delimiters (struct data_parser *parser,
261 struct substring delimiters)
263 ss_dealloc (&parser->hard_seps);
264 ss_alloc_substring (&parser->hard_seps, delimiters);
265 set_any_sep (parser);
268 /* Returns the number of records per case. */
270 data_parser_get_records (const struct data_parser *parser)
272 return parser->records_per_case;
275 /* Sets the number of records per case to RECORDS_PER_CASE.
277 This setting affects parsing of DP_FIXED files only. */
279 data_parser_set_records (struct data_parser *parser, int records_per_case)
281 assert (records_per_case >= 0);
282 assert (records_per_case >= parser->records_per_case);
283 parser->records_per_case = records_per_case;
287 add_field (struct data_parser *p, const struct fmt_spec *format, int case_idx,
288 const char *name, int record, int first_column)
292 if (p->n_fields == p->field_allocated)
293 p->fields = x2nrealloc (p->fields, &p->field_allocated, sizeof *p->fields);
294 field = &p->fields[p->n_fields++];
295 field->format = *format;
296 field->case_idx = case_idx;
297 field->name = xstrdup (name);
298 field->record = record;
299 field->first_column = first_column;
302 /* Adds a delimited field to the field parsed by PARSER, which
303 must be configured as a DP_DELIMITED parser. The field is
304 parsed as input format FORMAT. Its data will be stored into case
305 index CASE_INDEX. Errors in input data will be reported
306 against variable NAME. */
308 data_parser_add_delimited_field (struct data_parser *parser,
309 const struct fmt_spec *format, int case_idx,
312 assert (parser->type == DP_DELIMITED);
313 add_field (parser, format, case_idx, name, 0, 0);
316 /* Adds a fixed field to the field parsed by PARSER, which
317 must be configured as a DP_FIXED parser. The field is
318 parsed as input format FORMAT. Its data will be stored into case
319 index CASE_INDEX. Errors in input data will be reported
320 against variable NAME. The field will be drawn from the
321 FORMAT->w columns in 1-based RECORD starting at 1-based
324 RECORD must be at least as great as that of any field already
325 added; that is, fields must be added in increasing order of
326 record number. If RECORD is greater than the current number
327 of records per case, the number of records per case are
328 increased as needed. */
330 data_parser_add_fixed_field (struct data_parser *parser,
331 const struct fmt_spec *format, int case_idx,
333 int record, int first_column)
335 assert (parser->type == DP_FIXED);
336 assert (parser->n_fields == 0
337 || record >= parser->fields[parser->n_fields - 1].record);
338 if (record > parser->records_per_case)
339 parser->records_per_case = record;
340 add_field (parser, format, case_idx, name, record, first_column);
343 /* Returns true if any fields have been added to PARSER, false
346 data_parser_any_fields (const struct data_parser *parser)
348 return parser->n_fields > 0;
352 set_any_sep (struct data_parser *parser)
354 ds_assign_substring (&parser->any_sep, parser->soft_seps);
355 ds_put_substring (&parser->any_sep, parser->hard_seps);
358 static bool parse_delimited_span (const struct data_parser *,
360 struct dictionary *, struct ccase *);
361 static bool parse_delimited_no_span (const struct data_parser *,
363 struct dictionary *, struct ccase *);
364 static bool parse_fixed (const struct data_parser *, struct dfm_reader *,
365 struct dictionary *, struct ccase *);
367 /* Reads a case from DFM into C, which matches dictionary DICT, parsing it with
368 PARSER. Returns true if successful, false at end of file or on I/O error.
370 Case C must not be shared. */
372 data_parser_parse (struct data_parser *parser, struct dfm_reader *reader,
373 struct dictionary *dict, struct ccase *c)
377 assert (!case_is_shared (c));
378 assert (data_parser_any_fields (parser));
380 /* Skip the requested number of records before reading the
382 for (; parser->skip_records > 0; parser->skip_records--)
384 if (dfm_eof (reader))
386 dfm_forward_record (reader);
390 if (parser->type == DP_DELIMITED)
393 retval = parse_delimited_span (parser, reader, dict, c);
395 retval = parse_delimited_no_span (parser, reader, dict, c);
398 retval = parse_fixed (parser, reader, dict, c);
404 cut_field__ (const struct data_parser *parser, const struct substring *line,
405 struct substring *p, size_t *n_columns,
406 struct string *tmp, struct substring *field)
408 bool quoted = ss_find_byte (parser->quotes, ss_first (*p)) != SIZE_MAX;
412 int quote = ss_get_byte (p);
413 if (!ss_get_until (p, quote, field))
414 msg (DW, _("Quoted string extends beyond end of line."));
415 if (parser->quote_escape && ss_first (*p) == quote)
417 ds_assign_substring (tmp, *field);
418 while (ss_match_byte (p, quote))
421 ds_put_byte (tmp, quote);
422 if (!ss_get_until (p, quote, &ss))
423 msg (DW, _("Quoted string extends beyond end of line."));
424 ds_put_substring (tmp, ss);
426 *field = ds_ss (tmp);
428 *n_columns = ss_length (*line) - ss_length (*p);
433 ss_get_bytes (p, ss_cspan (*p, ds_ss (&parser->any_sep)), field);
434 *n_columns = ss_length (*field);
437 /* Skip trailing soft separator and a single hard separator if present. */
438 size_t length_before_separators = ss_length (*p);
439 ss_ltrim (p, parser->soft_seps);
440 if (!ss_is_empty (*p)
441 && ss_find_byte (parser->hard_seps, ss_first (*p)) != SIZE_MAX)
444 ss_ltrim (p, parser->soft_seps);
447 if (!ss_is_empty (*p) && quoted && length_before_separators == ss_length (*p))
448 msg (DW, _("Missing delimiter following quoted string."));
451 /* Extracts a delimited field from the current position in the
452 current record according to PARSER, reading data from READER.
454 *FIELD is set to the field content. The caller must not or
455 destroy this constant string.
457 Sets *FIRST_COLUMN to the 1-based column number of the start of
458 the extracted field, and *LAST_COLUMN to the end of the extracted
461 Returns true on success, false on failure. */
463 cut_field (const struct data_parser *parser, struct dfm_reader *reader,
464 int *first_column, int *last_column, struct string *tmp,
465 struct substring *field)
467 struct substring line, p;
469 if (dfm_eof (reader))
471 if (ss_is_empty (parser->hard_seps))
472 dfm_expand_tabs (reader);
473 line = p = dfm_get_record (reader);
475 /* Skip leading soft separators. */
476 ss_ltrim (&p, parser->soft_seps);
478 /* Handle empty or completely consumed lines. */
481 if (!parser->empty_line_has_field || dfm_columns_past_end (reader) > 0)
486 *first_column = dfm_column_start (reader);
487 *last_column = *first_column + 1;
488 dfm_forward_columns (reader, 1);
494 cut_field__ (parser, &line, &p, &n_columns, tmp, field);
495 *first_column = dfm_column_start (reader);
496 *last_column = *first_column + n_columns;
499 dfm_forward_columns (reader, 1);
500 dfm_forward_columns (reader, ss_length (line) - ss_length (p));
506 parse_error (const struct dfm_reader *reader, const struct field *field,
507 int first_column, int last_column, char *error)
509 int line_number = dfm_get_line_number (reader);
510 struct msg_location *location = xmalloc (sizeof *location);
511 *location = (struct msg_location) {
512 .file_name = intern_new (dfm_get_file_name (reader)),
513 .start = { .line = line_number, .column = first_column },
514 .end = { .line = line_number, .column = last_column - 1 },
516 struct msg *m = xmalloc (sizeof *m);
518 .category = MSG_C_DATA,
519 .severity = MSG_S_WARNING,
520 .location = location,
521 .text = xasprintf (_("Data for variable %s is not valid as format %s: %s"),
522 field->name, fmt_name (field->format.type), error),
529 /* Reads a case from READER into C, which matches DICT, parsing it according to
530 fixed-format syntax rules in PARSER. Returns true if successful, false at
531 end of file or on I/O error. */
533 parse_fixed (const struct data_parser *parser, struct dfm_reader *reader,
534 struct dictionary *dict, struct ccase *c)
536 const char *input_encoding = dfm_reader_get_encoding (reader);
537 const char *output_encoding = dict_get_encoding (dict);
541 if (dfm_eof (reader))
545 for (row = 1; row <= parser->records_per_case; row++)
547 struct substring line;
549 if (dfm_eof (reader))
551 msg (DW, _("Partial case of %d of %d records discarded."),
552 row - 1, parser->records_per_case);
555 dfm_expand_tabs (reader);
556 line = dfm_get_record (reader);
558 for (; f < &parser->fields[parser->n_fields] && f->record == row; f++)
560 struct substring s = ss_substr (line, f->first_column - 1,
562 union value *value = case_data_rw_idx (c, f->case_idx);
563 char *error = data_in (s, input_encoding, f->format.type,
564 settings_get_fmt_settings (),
565 value, fmt_var_width (&f->format),
569 data_in_imply_decimals (s, input_encoding, f->format.type,
570 f->format.d, settings_get_fmt_settings (),
573 parse_error (reader, f, f->first_column,
574 f->first_column + f->format.w, error);
577 dfm_forward_record (reader);
583 /* Splits the data line in LINE into individual text fields and returns the
584 number of fields. If SA is nonnull, appends each field to SA; the caller
585 retains ownership of SA and its contents. */
587 data_parser_split (const struct data_parser *parser,
588 struct substring line, struct string_array *sa)
592 struct string tmp = DS_EMPTY_INITIALIZER;
595 struct substring p = line;
596 ss_ltrim (&p, parser->soft_seps);
604 struct substring field;
607 cut_field__ (parser, &line, &p, &n_columns, &tmp, &field);
611 string_array_append_nocopy (sa, ss_xstrdup (field));
617 /* Reads a case from READER into C, which matches dictionary DICT, parsing it
618 according to free-format syntax rules in PARSER. Returns true if
619 successful, false at end of file or on I/O error. */
621 parse_delimited_span (const struct data_parser *parser,
622 struct dfm_reader *reader,
623 struct dictionary *dict, struct ccase *c)
625 const char *output_encoding = dict_get_encoding (dict);
626 struct string tmp = DS_EMPTY_INITIALIZER;
629 for (f = parser->fields; f < &parser->fields[parser->n_fields]; f++)
632 int first_column, last_column;
635 /* Cut out a field and read in a new record if necessary. */
636 while (!cut_field (parser, reader,
637 &first_column, &last_column, &tmp, &s))
639 if (!dfm_eof (reader))
640 dfm_forward_record (reader);
641 if (dfm_eof (reader))
643 if (f > parser->fields)
644 msg (DW, _("Partial case discarded. The first variable "
645 "missing was %s."), f->name);
651 const char *input_encoding = dfm_reader_get_encoding (reader);
652 error = data_in (s, input_encoding, f->format.type,
653 settings_get_fmt_settings (),
654 case_data_rw_idx (c, f->case_idx),
655 fmt_var_width (&f->format), output_encoding);
657 parse_error (reader, f, first_column, last_column, error);
663 /* Reads a case from READER into C, which matches dictionary DICT, parsing it
664 according to delimited syntax rules with one case per record in PARSER.
665 Returns true if successful, false at end of file or on I/O error. */
667 parse_delimited_no_span (const struct data_parser *parser,
668 struct dfm_reader *reader,
669 struct dictionary *dict, struct ccase *c)
671 const char *output_encoding = dict_get_encoding (dict);
672 struct string tmp = DS_EMPTY_INITIALIZER;
674 struct field *f, *end;
676 if (dfm_eof (reader))
679 end = &parser->fields[parser->n_fields];
680 for (f = parser->fields; f < end; f++)
682 int first_column, last_column;
685 if (!cut_field (parser, reader, &first_column, &last_column, &tmp, &s))
687 if (f < end - 1 && settings_get_undefined () && parser->warn_missing_fields)
688 msg (DW, _("Missing value(s) for all variables from %s onward. "
689 "These will be filled with the system-missing value "
690 "or blanks, as appropriate."),
693 value_set_missing (case_data_rw_idx (c, f->case_idx),
694 fmt_var_width (&f->format));
698 const char *input_encoding = dfm_reader_get_encoding (reader);
699 error = data_in (s, input_encoding, f->format.type,
700 settings_get_fmt_settings (),
701 case_data_rw_idx (c, f->case_idx),
702 fmt_var_width (&f->format), output_encoding);
704 parse_error (reader, f, first_column, last_column, error);
707 s = dfm_get_record (reader);
708 ss_ltrim (&s, parser->soft_seps);
709 if (!ss_is_empty (s))
710 msg (DW, _("Record ends in data not part of any field."));
713 dfm_forward_record (reader);
718 /* Displays a table giving information on fixed-format variable
719 parsing on DATA LIST. */
721 dump_fixed_table (const struct data_parser *parser,
722 const struct file_handle *fh)
724 /* XXX This should not be preformatted. */
725 char *title = xasprintf (ngettext ("Reading %d record from %s.",
726 "Reading %d records from %s.",
727 parser->records_per_case),
728 parser->records_per_case, fh_get_name (fh));
729 struct pivot_table *table = pivot_table_create__ (
730 pivot_value_new_user_text (title, -1), "Fixed Data Records");
733 pivot_dimension_create (
734 table, PIVOT_AXIS_COLUMN, N_("Attributes"),
735 N_("Record"), N_("Columns"), N_("Format"));
737 struct pivot_dimension *variables = pivot_dimension_create (
738 table, PIVOT_AXIS_ROW, N_("Variable"));
739 variables->root->show_label = true;
740 for (size_t i = 0; i < parser->n_fields; i++)
742 struct field *f = &parser->fields[i];
744 /* XXX It would be better to have the actual variable here. */
745 int variable_idx = pivot_category_create_leaf (
746 variables->root, pivot_value_new_user_text (f->name, -1));
748 pivot_table_put2 (table, 0, variable_idx,
749 pivot_value_new_integer (f->record));
751 int first_column = f->first_column;
752 int last_column = f->first_column + f->format.w - 1;
753 char *columns = xasprintf ("%d-%d", first_column, last_column);
754 pivot_table_put2 (table, 1, variable_idx,
755 pivot_value_new_user_text (columns, -1));
758 char str[FMT_STRING_LEN_MAX + 1];
759 pivot_table_put2 (table, 2, variable_idx,
760 pivot_value_new_user_text (
761 fmt_to_string (&f->format, str), -1));
765 pivot_table_submit (table);
768 /* Displays a table giving information on free-format variable parsing
771 dump_delimited_table (const struct data_parser *parser,
772 const struct file_handle *fh)
774 struct pivot_table *table = pivot_table_create__ (
775 pivot_value_new_text_format (N_("Reading free-form data from %s."),
777 "Free-Form Data Records");
779 pivot_dimension_create (
780 table, PIVOT_AXIS_COLUMN, N_("Attributes"), N_("Format"));
782 struct pivot_dimension *variables = pivot_dimension_create (
783 table, PIVOT_AXIS_ROW, N_("Variable"));
784 variables->root->show_label = true;
785 for (size_t i = 0; i < parser->n_fields; i++)
787 struct field *f = &parser->fields[i];
789 /* XXX It would be better to have the actual variable here. */
790 int variable_idx = pivot_category_create_leaf (
791 variables->root, pivot_value_new_user_text (f->name, -1));
793 char str[FMT_STRING_LEN_MAX + 1];
794 pivot_table_put2 (table, 0, variable_idx,
795 pivot_value_new_user_text (
796 fmt_to_string (&f->format, str), -1));
799 pivot_table_submit (table);
802 /* Displays a table giving information on how PARSER will read
805 data_parser_output_description (struct data_parser *parser,
806 const struct file_handle *fh)
808 if (parser->type == DP_FIXED)
809 dump_fixed_table (parser, fh);
811 dump_delimited_table (parser, fh);
814 /* Data parser input program. */
815 struct data_parser_casereader
817 struct data_parser *parser; /* Parser. */
818 struct dictionary *dict; /* Dictionary. */
819 struct dfm_reader *reader; /* Data file reader. */
820 struct caseproto *proto; /* Format of cases. */
823 static const struct casereader_class data_parser_casereader_class;
825 /* Replaces DS's active dataset by an input program that reads data
826 from READER according to the rules in PARSER, using DICT as
827 the underlying dictionary. Ownership of PARSER and READER is
828 transferred to the input program, and ownership of DICT is
829 transferred to the dataset. */
831 data_parser_make_active_file (struct data_parser *parser, struct dataset *ds,
832 struct dfm_reader *reader,
833 struct dictionary *dict,
834 struct casereader* (*func)(struct casereader *,
835 const struct dictionary *,
839 struct data_parser_casereader *r;
840 struct casereader *casereader0;
841 struct casereader *casereader1;
843 r = xmalloc (sizeof *r);
845 r->dict = dict_ref (dict);
847 r->proto = caseproto_ref (dict_get_proto (dict));
848 casereader0 = casereader_create_sequential (NULL, r->proto,
850 &data_parser_casereader_class, r);
853 casereader1 = func (casereader0, dict, ud);
855 casereader1 = casereader0;
857 dataset_set_dict (ds, dict);
858 dataset_set_source (ds, casereader1);
862 static struct ccase *
863 data_parser_casereader_read (struct casereader *reader UNUSED, void *r_)
865 struct data_parser_casereader *r = r_;
866 struct ccase *c = case_create (r->proto);
867 if (data_parser_parse (r->parser, r->reader, r->dict, c))
877 data_parser_casereader_destroy (struct casereader *reader, void *r_)
879 struct data_parser_casereader *r = r_;
880 if (dfm_reader_error (r->reader))
881 casereader_force_error (reader);
882 dfm_close_reader (r->reader);
883 caseproto_unref (r->proto);
884 dict_unref (r->dict);
885 data_parser_destroy (r->parser);
889 static const struct casereader_class data_parser_casereader_class =
891 data_parser_casereader_read,
892 data_parser_casereader_destroy,