546e33f21e86424278256c4709ec7ef779597250
[pspp] / src / language / data-io / data-list.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <float.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "data/case.h"
26 #include "data/casereader.h"
27 #include "data/data-in.h"
28 #include "data/dataset.h"
29 #include "data/dictionary.h"
30 #include "data/format.h"
31 #include "data/settings.h"
32 #include "data/transformations.h"
33 #include "data/variable.h"
34 #include "language/command.h"
35 #include "language/data-io/data-parser.h"
36 #include "language/data-io/data-reader.h"
37 #include "language/data-io/file-handle.h"
38 #include "language/data-io/inpt-pgm.h"
39 #include "language/data-io/placement-parser.h"
40 #include "language/lexer/format-parser.h"
41 #include "language/lexer/lexer.h"
42 #include "language/lexer/variable-parser.h"
43 #include "libpspp/assertion.h"
44 #include "libpspp/compiler.h"
45 #include "libpspp/i18n.h"
46 #include "libpspp/message.h"
47 #include "libpspp/misc.h"
48 #include "libpspp/pool.h"
49 #include "libpspp/str.h"
50
51 #include "gl/xsize.h"
52 #include "gl/xalloc.h"
53
54 #include "gettext.h"
55 #define _(msgid) gettext (msgid)
56 \f
57 /* DATA LIST transformation data. */
58 struct data_list_trns
59   {
60     struct data_parser *parser; /* Parser. */
61     struct dictionary *dict;    /* Dictionary. */
62     struct dfm_reader *reader;  /* Data file reader. */
63     struct variable *end;       /* Variable specified on END subcommand. */
64   };
65
66 static bool parse_fixed (struct lexer *, struct dictionary *,
67                          struct pool *, struct data_parser *);
68 static bool parse_free (struct lexer *, struct dictionary *,
69                         struct pool *, struct data_parser *);
70
71 static const struct trns_class data_list_trns_class;
72
73 int
74 cmd_data_list (struct lexer *lexer, struct dataset *ds)
75 {
76   struct dictionary *dict;
77   struct data_parser *parser;
78   struct dfm_reader *reader;
79   struct variable *end = NULL;
80   struct file_handle *fh = NULL;
81   char *encoding = NULL;
82
83   int table;
84   enum data_parser_type type;
85   bool has_type;
86   struct pool *tmp_pool;
87   bool ok;
88
89   dict = (in_input_program ()
90           ? dataset_dict (ds)
91           : dict_create (get_default_encoding ()));
92   parser = data_parser_create ();
93   reader = NULL;
94
95   table = -1;                /* Print table if nonzero, -1=undecided. */
96   has_type = false;
97
98   while (lex_token (lexer) != T_SLASH)
99     {
100       if (lex_match_id (lexer, "FILE"))
101         {
102           lex_match (lexer, T_EQUALS);
103           fh_unref (fh);
104           fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE, NULL);
105           if (fh == NULL)
106             goto error;
107         }
108       else if (lex_match_id (lexer, "ENCODING"))
109         {
110           lex_match (lexer, T_EQUALS);
111           if (!lex_force_string (lexer))
112             goto error;
113
114           free (encoding);
115           encoding = ss_xstrdup (lex_tokss (lexer));
116
117           lex_get (lexer);
118         }
119       else if (lex_match_id (lexer, "RECORDS"))
120         {
121           if (data_parser_get_records (parser) > 0)
122             {
123               lex_sbc_only_once (lexer, "RECORDS");
124               goto error;
125             }
126           lex_match (lexer, T_EQUALS);
127           lex_match (lexer, T_LPAREN);
128           if (!lex_force_int_range (lexer, "RECORDS", 0, INT_MAX))
129             goto error;
130           data_parser_set_records (parser, lex_integer (lexer));
131           lex_get (lexer);
132           lex_match (lexer, T_RPAREN);
133         }
134       else if (lex_match_id (lexer, "SKIP"))
135         {
136           lex_match (lexer, T_EQUALS);
137           if (!lex_force_int_range (lexer, "SKIP", 0, INT_MAX))
138             goto error;
139           data_parser_set_skip (parser, lex_integer (lexer));
140           lex_get (lexer);
141         }
142       else if (lex_match_id (lexer, "END"))
143         {
144           if (!in_input_program ())
145             {
146               lex_next_error (lexer, -1, -1,
147                               _("The %s subcommand may only be used within %s."),
148                               "END", "INPUT PROGRAM");
149               goto error;
150             }
151           if (end)
152             {
153               lex_sbc_only_once (lexer, "END");
154               goto error;
155             }
156
157           lex_match (lexer, T_EQUALS);
158           if (!lex_force_id (lexer))
159             goto error;
160           end = dict_lookup_var (dict, lex_tokcstr (lexer));
161           if (!end)
162             end = dict_create_var_assert (dict, lex_tokcstr (lexer), 0);
163           lex_get (lexer);
164         }
165       else if (lex_match_id (lexer, "NOTABLE"))
166         table = 0;
167       else if (lex_match_id (lexer, "TABLE"))
168         table = 1;
169       else if (lex_token (lexer) == T_ID)
170         {
171           if (lex_match_id (lexer, "FIXED"))
172             data_parser_set_type (parser, DP_FIXED);
173           else if (lex_match_id (lexer, "FREE"))
174             {
175               data_parser_set_type (parser, DP_DELIMITED);
176               data_parser_set_span (parser, true);
177             }
178           else if (lex_match_id (lexer, "LIST"))
179             {
180               data_parser_set_type (parser, DP_DELIMITED);
181               data_parser_set_span (parser, false);
182             }
183           else
184             {
185               lex_error (lexer, NULL);
186               goto error;
187             }
188
189           if (has_type)
190             {
191               lex_next_error (lexer, -1, -1,
192                               _("Only one of FIXED, FREE, or LIST may "
193                                 "be specified."));
194               goto error;
195             }
196           has_type = true;
197
198           if (data_parser_get_type (parser) == DP_DELIMITED)
199             {
200               if (lex_match (lexer, T_LPAREN))
201                 {
202                   struct string delims = DS_EMPTY_INITIALIZER;
203
204                   while (!lex_match (lexer, T_RPAREN))
205                     {
206                       int delim;
207
208                       if (lex_match_id (lexer, "TAB"))
209                         delim = '\t';
210                       else if (lex_is_string (lexer)
211                                && ss_length (lex_tokss (lexer)) == 1)
212                         {
213                           delim = ss_first (lex_tokss (lexer));
214                           lex_get (lexer);
215                         }
216                       else
217                         {
218                           /* XXX should support multibyte UTF-8 characters */
219                           lex_error (lexer, NULL);
220                           ds_destroy (&delims);
221                           goto error;
222                         }
223                       ds_put_byte (&delims, delim);
224
225                       lex_match (lexer, T_COMMA);
226                     }
227
228                   data_parser_set_empty_line_has_field (parser, true);
229                   data_parser_set_quotes (parser, ss_empty ());
230                   data_parser_set_soft_delimiters (parser, ss_empty ());
231                   data_parser_set_hard_delimiters (parser, ds_ss (&delims));
232                   ds_destroy (&delims);
233                 }
234               else
235                 {
236                   data_parser_set_empty_line_has_field (parser, false);
237                   data_parser_set_quotes (parser, ss_cstr ("'\""));
238                   data_parser_set_soft_delimiters (parser,
239                                                    ss_cstr (CC_SPACES));
240                   const char decimal = settings_get_fmt_settings ()->decimal;
241                   data_parser_set_hard_delimiters (parser,
242                                                    ss_buffer (",", (decimal == '.') ? 1 : 0));
243                 }
244             }
245         }
246       else
247         {
248           lex_error (lexer, NULL);
249           goto error;
250         }
251     }
252   type = data_parser_get_type (parser);
253
254   if (encoding && NULL == fh)
255     msg (MW, _("Encoding should not be specified for inline data. It will be "
256                "ignored."));
257
258   if (fh == NULL)
259     fh = fh_inline_file ();
260   fh_set_default_handle (fh);
261
262   if (type != DP_FIXED && end != NULL)
263     {
264       msg (SE, _("The %s subcommand may be used only with %s."), "END", "DATA LIST FIXED");
265       goto error;
266     }
267
268   tmp_pool = pool_create ();
269   if (type == DP_FIXED)
270     ok = parse_fixed (lexer, dict, tmp_pool, parser);
271   else
272     ok = parse_free (lexer, dict, tmp_pool, parser);
273   pool_destroy (tmp_pool);
274   if (!ok)
275     goto error;
276
277   if (!data_parser_any_fields (parser))
278     {
279       msg (SE, _("At least one variable must be specified."));
280       goto error;
281     }
282
283   if (lex_end_of_command (lexer) != CMD_SUCCESS)
284     goto error;
285
286   if (table == -1)
287     table = type == DP_FIXED || !data_parser_get_span (parser);
288   if (table)
289     data_parser_output_description (parser, fh);
290
291   reader = dfm_open_reader (fh, lexer, encoding);
292   if (reader == NULL)
293     goto error;
294
295   if (in_input_program ())
296     {
297       struct data_list_trns *trns = xmalloc (sizeof *trns);
298       trns->parser = parser;
299       trns->dict = dict_ref (dict);
300       trns->reader = reader;
301       trns->end = end;
302       add_transformation (ds, &data_list_trns_class, trns);
303     }
304   else
305     data_parser_make_active_file (parser, ds, reader, dict, NULL, NULL);
306
307   fh_unref (fh);
308   free (encoding);
309
310   data_list_seen ();
311
312   return CMD_SUCCESS;
313
314  error:
315   data_parser_destroy (parser);
316   if (!in_input_program ())
317     dict_unref (dict);
318   fh_unref (fh);
319   free (encoding);
320   return CMD_CASCADING_FAILURE;
321 }
322 \f
323 /* Fixed-format parsing. */
324
325 /* Parses all the variable specifications for DATA LIST FIXED,
326    storing them into DLS.  Uses TMP_POOL for temporary storage;
327    the caller may destroy it.  Returns true only if
328    successful. */
329 static bool
330 parse_fixed (struct lexer *lexer, struct dictionary *dict,
331              struct pool *tmp_pool, struct data_parser *parser)
332 {
333   int max_records = data_parser_get_records (parser);
334   int record = 0;
335   int column = 1;
336
337   while (lex_token (lexer) != T_ENDCMD)
338     {
339       char **names;
340       size_t n_names, name_idx;
341       struct fmt_spec *formats, *f;
342       size_t n_formats;
343
344       /* Parse everything. */
345       if (!parse_record_placement (lexer, &record, &column)
346           || !parse_DATA_LIST_vars_pool (lexer, dict, tmp_pool,
347                                          &names, &n_names, PV_NONE)
348           || !parse_var_placements (lexer, tmp_pool, n_names, FMT_FOR_INPUT,
349                                     &formats, &n_formats))
350         return false;
351
352       /* Create variables and var specs. */
353       name_idx = 0;
354       for (f = formats; f < &formats[n_formats]; f++)
355         if (!execute_placement_format (f, &record, &column))
356           {
357             char *name;
358             int width;
359             struct variable *v;
360
361             name = names[name_idx++];
362
363             /* Create variable. */
364             width = fmt_var_width (f);
365             v = dict_create_var (dict, name, width);
366             if (v != NULL)
367               {
368                 /* Success. */
369                 struct fmt_spec output = fmt_for_output_from_input (
370                   f, settings_get_fmt_settings ());
371                 var_set_both_formats (v, &output);
372               }
373             else
374               {
375                 /* Failure.
376                    This can be acceptable if we're in INPUT
377                    PROGRAM, but only if the existing variable has
378                    the same width as the one we would have
379                    created. */
380                 if (!in_input_program ())
381                   {
382                     msg (SE, _("%s is a duplicate variable name."), name);
383                     return false;
384                   }
385
386                 v = dict_lookup_var_assert (dict, name);
387                 if ((width != 0) != (var_get_width (v) != 0))
388                   {
389                     msg (SE, _("There is already a variable %s of a "
390                                "different type."),
391                          name);
392                     return false;
393                   }
394                 if (width != 0 && width != var_get_width (v))
395                   {
396                     msg (SE, _("There is already a string variable %s of a "
397                                "different width."), name);
398                     return false;
399                   }
400               }
401
402             if (max_records && record > max_records)
403               {
404                 msg (SE, _("Cannot place variable %s on record %d when "
405                            "RECORDS=%d is specified."),
406                      var_get_name (v), record,
407                      data_parser_get_records (parser));
408               }
409
410             data_parser_add_fixed_field (parser, f,
411                                          var_get_case_index (v),
412                                          var_get_name (v), record, column);
413
414             column += f->w;
415           }
416       assert (name_idx == n_names);
417     }
418
419   return true;
420 }
421 \f
422 /* Free-format parsing. */
423
424 /* Parses variable specifications for DATA LIST FREE and adds
425    them to DLS.  Uses TMP_POOL for temporary storage; the caller
426    may destroy it.  Returns true only if successful. */
427 static bool
428 parse_free (struct lexer *lexer, struct dictionary *dict,
429             struct pool *tmp_pool, struct data_parser *parser)
430 {
431   lex_get (lexer);
432   while (lex_token (lexer) != T_ENDCMD)
433     {
434       struct fmt_spec input, output;
435       char **name;
436       size_t n_names;
437       size_t i;
438
439       if (!parse_DATA_LIST_vars_pool (lexer, dict, tmp_pool,
440                                       &name, &n_names, PV_NONE))
441         return false;
442
443       if (lex_match (lexer, T_LPAREN))
444         {
445           char type[FMT_TYPE_LEN_MAX + 1];
446
447           if (!parse_abstract_format_specifier (lexer, type, &input.w,
448                                                 &input.d))
449             return NULL;
450           if (!fmt_from_name (type, &input.type))
451             {
452               lex_next_error (lexer, -1, -1,
453                               _("Unknown format type `%s'."), type);
454               return NULL;
455             }
456
457           /* If no width was included, use the minimum width for the type.
458              This isn't quite right, because DATETIME by itself seems to become
459              DATETIME20 (see bug #30690), whereas this will become
460              DATETIME17.  The correct behavior is not documented. */
461           if (input.w == 0)
462             {
463               input.w = fmt_min_input_width (input.type);
464               input.d = 0;
465             }
466
467           if (!fmt_check_input (&input) || !lex_force_match (lexer, T_RPAREN))
468             return NULL;
469
470           /* As a special case, N format is treated as F format
471              for free-field input. */
472           if (input.type == FMT_N)
473             input.type = FMT_F;
474
475           output = fmt_for_output_from_input (&input,
476                                               settings_get_fmt_settings ());
477         }
478       else
479         {
480           lex_match (lexer, T_ASTERISK);
481           input = fmt_for_input (FMT_F, 8, 0);
482           output = *settings_get_format ();
483         }
484
485       for (i = 0; i < n_names; i++)
486         {
487           struct variable *v;
488
489           v = dict_create_var (dict, name[i], fmt_var_width (&input));
490           if (v == NULL)
491             {
492               msg (SE, _("%s is a duplicate variable name."), name[i]);
493               return false;
494             }
495           var_set_both_formats (v, &output);
496
497           data_parser_add_delimited_field (parser,
498                                            &input, var_get_case_index (v),
499                                            var_get_name (v));
500         }
501     }
502
503   return true;
504 }
505 \f
506 /* Input procedure. */
507
508 /* Destroys DATA LIST transformation TRNS.
509    Returns true if successful, false if an I/O error occurred. */
510 static bool
511 data_list_trns_free (void *trns_)
512 {
513   struct data_list_trns *trns = trns_;
514   data_parser_destroy (trns->parser);
515   dfm_close_reader (trns->reader);
516   dict_unref (trns->dict);
517   free (trns);
518   return true;
519 }
520
521 /* Handle DATA LIST transformation TRNS, parsing data into *C. */
522 static enum trns_result
523 data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
524 {
525   struct data_list_trns *trns = trns_;
526   enum trns_result retval;
527
528   *c = case_unshare (*c);
529   if (data_parser_parse (trns->parser, trns->reader, trns->dict, *c))
530     retval = TRNS_CONTINUE;
531   else if (dfm_reader_error (trns->reader) || dfm_eof (trns->reader) > 1)
532     {
533       /* An I/O error, or encountering end of file for a second
534          time, should be escalated into a more serious error. */
535       retval = TRNS_ERROR;
536     }
537   else
538     retval = TRNS_END_FILE;
539
540   /* If there was an END subcommand handle it. */
541   if (trns->end != NULL)
542     {
543       double *end = case_num_rw (*c, trns->end);
544       if (retval == TRNS_END_FILE)
545         {
546           *end = 1.0;
547           retval = TRNS_CONTINUE;
548         }
549       else
550         *end = 0.0;
551     }
552
553   return retval;
554 }
555
556 static const struct trns_class data_list_trns_class = {
557   .name = "DATA LIST",
558   .execute = data_list_trns_proc,
559   .destroy = data_list_trns_free,
560 };