Implemented the ENCODING subcommand to DATA LIST.
[pspp-builds.git] / src / language / data-io / data-list.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2009 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/data-in.h>
27 #include <data/casereader.h>
28 #include <data/dictionary.h>
29 #include <data/format.h>
30 #include <data/procedure.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/message.h>
46 #include <libpspp/misc.h>
47 #include <libpspp/pool.h>
48 #include <libpspp/str.h>
49
50 #include "xsize.h"
51 #include "xalloc.h"
52
53 #include "gettext.h"
54 #define _(msgid) gettext (msgid)
55 \f
56 /* DATA LIST transformation data. */
57 struct data_list_trns
58   {
59     struct data_parser *parser; /* Parser. */
60     struct dfm_reader *reader;  /* Data file reader. */
61     struct variable *end;       /* Variable specified on END subcommand. */
62   };
63
64 static bool parse_fixed (struct lexer *, struct dictionary *,
65                          struct pool *, struct data_parser *);
66 static bool parse_free (struct lexer *, struct dictionary *,
67                         struct pool *, struct data_parser *);
68
69 static trns_free_func data_list_trns_free;
70 static trns_proc_func data_list_trns_proc;
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   struct string encoding = DS_EMPTY_INITIALIZER;
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 () ? dataset_dict (ds) : dict_create ();
89   parser = data_parser_create ();
90   reader = NULL;
91
92   table = -1;                /* Print table if nonzero, -1=undecided. */
93   has_type = false;
94
95   while (lex_token (lexer) != '/')
96     {
97       if (lex_match_id (lexer, "FILE"))
98         {
99           lex_match (lexer, '=');
100           fh_unref (fh);
101           fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE);
102           if (fh == NULL)
103             goto error;
104         }
105       else if (lex_match_id (lexer, "ENCODING"))
106         {
107           lex_match (lexer, '=');
108           if (!lex_force_string (lexer))
109             goto error;
110
111           ds_init_string (&encoding, lex_tokstr (lexer));
112
113           lex_get (lexer);
114         }
115       else if (lex_match_id (lexer, "RECORDS"))
116         {
117           lex_match (lexer, '=');
118           lex_match (lexer, '(');
119           if (!lex_force_int (lexer))
120             goto error;
121           data_parser_set_records (parser, lex_integer (lexer));
122           lex_get (lexer);
123           lex_match (lexer, ')');
124         }
125       else if (lex_match_id (lexer, "SKIP"))
126         {
127           lex_match (lexer, '=');
128           if (!lex_force_int (lexer))
129             goto error;
130           data_parser_set_skip (parser, lex_integer (lexer));
131           lex_get (lexer);
132         }
133       else if (lex_match_id (lexer, "END"))
134         {
135           if (!in_input_program ())
136             {
137               msg (SE, _("The END subcommand may only be used within "
138                          "INPUT PROGRAM."));
139               goto error;
140             }
141           if (end)
142             {
143               msg (SE, _("The END subcommand may only be specified once."));
144               goto error;
145             }
146
147           lex_match (lexer, '=');
148           if (!lex_force_id (lexer))
149             goto error;
150           end = dict_lookup_var (dict, lex_tokid (lexer));
151           if (!end)
152             end = dict_create_var_assert (dict, lex_tokid (lexer), 0);
153           lex_get (lexer);
154         }
155       else if (lex_match_id (lexer, "NOTABLE"))
156         table = 0;
157       else if (lex_match_id (lexer, "TABLE"))
158         table = 1;
159       else if (lex_token (lexer) == T_ID)
160         {
161           if (lex_match_id (lexer, "FIXED"))
162             data_parser_set_type (parser, DP_FIXED);
163           else if (lex_match_id (lexer, "FREE"))
164             {
165               data_parser_set_type (parser, DP_DELIMITED);
166               data_parser_set_span (parser, true);
167             }
168           else if (lex_match_id (lexer, "LIST"))
169             {
170               data_parser_set_type (parser, DP_DELIMITED);
171               data_parser_set_span (parser, false);
172             }
173           else
174             {
175               lex_error (lexer, NULL);
176               goto error;
177             }
178
179           if (has_type)
180             {
181               msg (SE, _("Only one of FIXED, FREE, or LIST may "
182                          "be specified."));
183               goto error;
184             }
185           has_type = true;
186
187           if (data_parser_get_type (parser) == DP_DELIMITED)
188             {
189               if (lex_match (lexer, '('))
190                 {
191                   struct string delims = DS_EMPTY_INITIALIZER;
192
193                   while (!lex_match (lexer, ')'))
194                     {
195                       int delim;
196
197                       if (lex_match_id (lexer, "TAB"))
198                         delim = '\t';
199                       else if (lex_token (lexer) == T_STRING
200                                && ds_length (lex_tokstr (lexer)) == 1)
201                         {
202                           delim = ds_first (lex_tokstr (lexer));
203                           lex_get (lexer);
204                         }
205                       else
206                         {
207                           lex_error (lexer, NULL);
208                           ds_destroy (&delims);
209                           goto error;
210                         }
211                       ds_put_char (&delims, delim);
212
213                       lex_match (lexer, ',');
214                     }
215
216                   data_parser_set_empty_line_has_field (parser, true);
217                   data_parser_set_quotes (parser, ss_empty ());
218                   data_parser_set_soft_delimiters (parser, ss_empty ());
219                   data_parser_set_hard_delimiters (parser, ds_ss (&delims));
220                   ds_destroy (&delims);
221                 }
222               else
223                 {
224                   data_parser_set_empty_line_has_field (parser, false);
225                   data_parser_set_quotes (parser, ss_cstr ("'\""));
226                   data_parser_set_soft_delimiters (parser,
227                                                    ss_cstr (CC_SPACES));
228                   data_parser_set_hard_delimiters (parser, ss_cstr (","));
229                 }
230             }
231         }
232       else
233         {
234           lex_error (lexer, NULL);
235           goto error;
236         }
237     }
238   type = data_parser_get_type (parser);
239
240   if (! ds_is_empty (&encoding))
241     {
242       if ( NULL == fh)
243         msg (MW, _("Encoding should not be specified for inline data. It will be ignored."));
244       else
245         dict_set_encoding (dict, ds_cstr (&encoding));
246     }
247
248   if (fh == NULL)
249     fh = fh_inline_file ();
250   fh_set_default_handle (fh);
251
252   if (type != DP_FIXED && end != NULL)
253     {
254       msg (SE, _("The END subcommand may be used only with DATA LIST FIXED."));
255       goto error;
256     }
257
258   tmp_pool = pool_create ();
259   if (type == DP_FIXED)
260     ok = parse_fixed (lexer, dict, tmp_pool, parser);
261   else
262     ok = parse_free (lexer, dict, tmp_pool, parser);
263   pool_destroy (tmp_pool);
264   if (!ok)
265     goto error;
266
267   if (!data_parser_any_fields (parser))
268     {
269       msg (SE, _("At least one variable must be specified."));
270       goto error;
271     }
272
273   if (lex_end_of_command (lexer) != CMD_SUCCESS)
274     goto error;
275
276   if (table == -1)
277     table = type == DP_FIXED || !data_parser_get_span (parser);
278   if (table)
279     data_parser_output_description (parser, fh);
280
281   reader = dfm_open_reader (fh, lexer);
282   if (reader == NULL)
283     goto error;
284
285   if (in_input_program ())
286     {
287       struct data_list_trns *trns = xmalloc (sizeof *trns);
288       trns->parser = parser;
289       trns->reader = reader;
290       trns->end = end;
291       add_transformation (ds, data_list_trns_proc, data_list_trns_free, trns);
292     }
293   else
294     data_parser_make_active_file (parser, ds, reader, dict);
295
296   fh_unref (fh);
297
298   return CMD_SUCCESS;
299
300  error:
301   data_parser_destroy (parser);
302   if (!in_input_program ())
303     dict_destroy (dict);
304   fh_unref (fh);
305   return CMD_CASCADING_FAILURE;
306 }
307 \f
308 /* Fixed-format parsing. */
309
310 /* Parses all the variable specifications for DATA LIST FIXED,
311    storing them into DLS.  Uses TMP_POOL for temporary storage;
312    the caller may destroy it.  Returns true only if
313    successful. */
314 static bool
315 parse_fixed (struct lexer *lexer, struct dictionary *dict,
316              struct pool *tmp_pool, struct data_parser *parser)
317 {
318   int max_records = data_parser_get_records (parser);
319   int record = 0;
320   int column = 1;
321
322   while (lex_token (lexer) != '.')
323     {
324       char **names;
325       size_t name_cnt, name_idx;
326       struct fmt_spec *formats, *f;
327       size_t format_cnt;
328
329       /* Parse everything. */
330       if (!parse_record_placement (lexer, &record, &column)
331           || !parse_DATA_LIST_vars_pool (lexer, tmp_pool,
332                                          &names, &name_cnt, PV_NONE)
333           || !parse_var_placements (lexer, tmp_pool, name_cnt, true,
334                                     &formats, &format_cnt))
335         return false;
336
337       /* Create variables and var specs. */
338       name_idx = 0;
339       for (f = formats; f < &formats[format_cnt]; f++)
340         if (!execute_placement_format (f, &record, &column))
341           {
342             char *name;
343             int width;
344             struct variable *v;
345
346             name = names[name_idx++];
347
348             /* Create variable. */
349             width = fmt_var_width (f);
350             v = dict_create_var (dict, name, width);
351             if (v != NULL)
352               {
353                 /* Success. */
354                 struct fmt_spec output = fmt_for_output_from_input (f);
355                 var_set_both_formats (v, &output);
356               }
357             else
358               {
359                 /* Failure.
360                    This can be acceptable if we're in INPUT
361                    PROGRAM, but only if the existing variable has
362                    the same width as the one we would have
363                    created. */
364                 if (!in_input_program ())
365                   {
366                     msg (SE, _("%s is a duplicate variable name."), name);
367                     return false;
368                   }
369
370                 v = dict_lookup_var_assert (dict, name);
371                 if ((width != 0) != (var_get_width (v) != 0))
372                   {
373                     msg (SE, _("There is already a variable %s of a "
374                                "different type."),
375                          name);
376                     return false;
377                   }
378                 if (width != 0 && width != var_get_width (v))
379                   {
380                     msg (SE, _("There is already a string variable %s of a "
381                                "different width."), name);
382                     return false;
383                   }
384               }
385
386             if (max_records && record > max_records)
387               {
388                 msg (SE, _("Cannot place variable %s on record %d when "
389                            "RECORDS=%d is specified."),
390                      var_get_name (v), record,
391                      data_parser_get_records (parser));
392               }
393
394             data_parser_add_fixed_field (parser, f,
395                                          var_get_case_index (v),
396                                          var_get_name (v), record, column);
397
398             column += f->w;
399           }
400       assert (name_idx == name_cnt);
401     }
402
403   return true;
404 }
405 \f
406 /* Free-format parsing. */
407
408 /* Parses variable specifications for DATA LIST FREE and adds
409    them to DLS.  Uses TMP_POOL for temporary storage; the caller
410    may destroy it.  Returns true only if successful. */
411 static bool
412 parse_free (struct lexer *lexer, struct dictionary *dict,
413             struct pool *tmp_pool, struct data_parser *parser)
414 {
415   lex_get (lexer);
416   while (lex_token (lexer) != '.')
417     {
418       struct fmt_spec input, output;
419       char **name;
420       size_t name_cnt;
421       size_t i;
422
423       if (!parse_DATA_LIST_vars_pool (lexer, tmp_pool,
424                                       &name, &name_cnt, PV_NONE))
425         return false;
426
427       if (lex_match (lexer, '('))
428         {
429           if (!parse_format_specifier (lexer, &input)
430               || !fmt_check_input (&input)
431               || !lex_force_match (lexer, ')'))
432             return NULL;
433
434           /* As a special case, N format is treated as F format
435              for free-field input. */
436           if (input.type == FMT_N)
437             input.type = FMT_F;
438
439           output = fmt_for_output_from_input (&input);
440         }
441       else
442         {
443           lex_match (lexer, '*');
444           input = fmt_for_input (FMT_F, 8, 0);
445           output = *settings_get_format ();
446         }
447
448       for (i = 0; i < name_cnt; i++)
449         {
450           struct variable *v;
451
452           v = dict_create_var (dict, name[i], fmt_var_width (&input));
453           if (v == NULL)
454             {
455               msg (SE, _("%s is a duplicate variable name."), name[i]);
456               return false;
457             }
458           var_set_both_formats (v, &output);
459
460           data_parser_add_delimited_field (parser,
461                                            &input, var_get_case_index (v),
462                                            var_get_name (v));
463         }
464     }
465
466   return true;
467 }
468 \f
469 /* Input procedure. */
470
471 /* Destroys DATA LIST transformation TRNS.
472    Returns true if successful, false if an I/O error occurred. */
473 static bool
474 data_list_trns_free (void *trns_)
475 {
476   struct data_list_trns *trns = trns_;
477   data_parser_destroy (trns->parser);
478   dfm_close_reader (trns->reader);
479   free (trns);
480   return true;
481 }
482
483 /* Handle DATA LIST transformation TRNS, parsing data into *C. */
484 static int
485 data_list_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
486 {
487   struct data_list_trns *trns = trns_;
488   int retval;
489
490   *c = case_unshare (*c);
491   if (data_parser_parse (trns->parser, trns->reader, *c))
492     retval = TRNS_CONTINUE;
493   else if (dfm_reader_error (trns->reader) || dfm_eof (trns->reader) > 1)
494     {
495       /* An I/O error, or encountering end of file for a second
496          time, should be escalated into a more serious error. */
497       retval = TRNS_ERROR;
498     }
499   else
500     retval = TRNS_END_FILE;
501
502   /* If there was an END subcommand handle it. */
503   if (trns->end != NULL)
504     {
505       double *end = &case_data_rw (*c, trns->end)->f;
506       if (retval == TRNS_END_FILE)
507         {
508           *end = 1.0;
509           retval = TRNS_CONTINUE;
510         }
511       else
512         *end = 0.0;
513     }
514
515   return retval;
516 }
517 \f