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