Break get.c up into multiple files in a logical fashion.
[pspp-builds.git] / src / language / data-io / match-files.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2008 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 <stdlib.h>
20
21 #include <data/any-reader.h>
22 #include <data/case.h>
23 #include <data/casereader.h>
24 #include <data/casewriter.h>
25 #include <data/format.h>
26 #include <data/dictionary.h>
27 #include <data/procedure.h>
28 #include <data/variable.h>
29 #include <language/command.h>
30 #include <language/data-io/file-handle.h>
31 #include <language/data-io/trim.h>
32 #include <language/lexer/lexer.h>
33 #include <language/lexer/variable-parser.h>
34 #include <libpspp/assertion.h>
35 #include <libpspp/message.h>
36 #include <libpspp/taint.h>
37
38 #include "xalloc.h"
39
40 #include "gettext.h"
41 #define _(msgid) gettext (msgid)
42
43 /* File types. */
44 enum mtf_type
45   {
46     MTF_FILE,                   /* Specified on FILE= subcommand. */
47     MTF_TABLE                   /* Specified on TABLE= subcommand. */
48   };
49
50 /* One of the FILEs or TABLEs on MATCH FILES. */
51 struct mtf_file
52   {
53     struct ll ll;               /* In list of all files and tables. */
54
55     enum mtf_type type;
56     int sequence;
57
58     const struct variable **by; /* List of BY variables for this file. */
59     struct mtf_variable *vars;  /* Variables to copy to output. */
60     size_t var_cnt;             /* Number of other variables. */
61
62     struct file_handle *handle; /* Input file handle. */
63     struct dictionary *dict;    /* Input file dictionary. */
64     struct casereader *reader;  /* Input reader. */
65     struct ccase input;         /* Input record (null at end of file). */
66
67     /* IN subcommand. */
68     char *in_name;              /* Variable name. */
69     struct variable *in_var;    /* Variable (in master dictionary). */
70   };
71
72 struct mtf_variable
73   {
74     struct variable *in_var;
75     struct variable *out_var;
76   };
77
78 /* MATCH FILES procedure. */
79 struct mtf_proc
80   {
81     struct ll_list files;       /* List of "struct mtf_file"s. */
82     int nonempty_files;         /* FILEs that are not at end-of-file. */
83
84     bool ok;                    /* False if I/O error occurs. */
85
86     struct dictionary *dict;    /* Dictionary of output file. */
87     struct casewriter *output;  /* MATCH FILES output. */
88
89     size_t by_cnt;              /* Number of variables on BY subcommand. */
90
91     /* FIRST, LAST.
92        Only if "first" or "last" is nonnull are the remaining
93        members used. */
94     struct variable *first;     /* Variable specified on FIRST (if any). */
95     struct variable *last;      /* Variable specified on LAST (if any). */
96     struct ccase buffered_case; /* Case ready for output except that we don't
97                                    know the value for the LAST variable yet. */
98     struct ccase prev_BY_case;  /* Case with values of last set of BY vars. */
99     const struct variable **prev_BY;  /* Last set of BY variables. */
100   };
101
102 static void mtf_free (struct mtf_proc *);
103
104 static bool mtf_close_all_files (struct mtf_proc *);
105 static bool mtf_merge_dictionary (struct dictionary *const, struct mtf_file *);
106 static bool mtf_read_record (struct mtf_proc *mtf, struct mtf_file *);
107
108 static void mtf_process_case (struct mtf_proc *);
109
110 static bool create_flag_var (const char *subcommand_name, const char *var_name,
111                              struct dictionary *, struct variable **);
112 static char *var_type_description (struct variable *);
113
114 /* Parse and execute the MATCH FILES command. */
115 int
116 cmd_match_files (struct lexer *lexer, struct dataset *ds)
117 {
118   struct mtf_proc mtf;
119   struct ll *first_table;
120   struct mtf_file *file, *next;
121
122   bool saw_in = false;
123   struct casereader *active_file = NULL;
124
125   char first_name[VAR_NAME_LEN + 1] = "";
126   char last_name[VAR_NAME_LEN + 1] = "";
127
128   struct taint *taint = NULL;
129
130   size_t i;
131
132   ll_init (&mtf.files);
133   mtf.nonempty_files = 0;
134   first_table = ll_null (&mtf.files);
135   mtf.dict = dict_create ();
136   mtf.output = NULL;
137   mtf.by_cnt = 0;
138   mtf.first = mtf.last = NULL;
139   case_nullify (&mtf.buffered_case);
140   case_nullify (&mtf.prev_BY_case);
141   mtf.prev_BY = NULL;
142
143   dict_set_case_limit (mtf.dict, dict_get_case_limit (dataset_dict (ds)));
144
145   lex_match (lexer, '/');
146   while (lex_token (lexer) == T_ID
147          && (lex_id_match (ss_cstr ("FILE"), ss_cstr (lex_tokid (lexer)))
148              || lex_id_match (ss_cstr ("TABLE"), ss_cstr (lex_tokid (lexer)))))
149     {
150       struct mtf_file *file = xmalloc (sizeof *file);
151       file->by = NULL;
152       file->handle = NULL;
153       file->reader = NULL;
154       file->dict = NULL;
155       file->in_name = NULL;
156       file->in_var = NULL;
157       file->var_cnt = 0;
158       file->vars = NULL;
159       case_nullify (&file->input);
160
161       if (lex_match_id (lexer, "FILE"))
162         {
163           file->type = MTF_FILE;
164           ll_insert (first_table, &file->ll);
165           mtf.nonempty_files++;
166         }
167       else if (lex_match_id (lexer, "TABLE"))
168         {
169           file->type = MTF_TABLE;
170           ll_push_tail (&mtf.files, &file->ll);
171           if (first_table == ll_null (&mtf.files))
172             first_table = &file->ll;
173         }
174       else
175         NOT_REACHED ();
176       lex_match (lexer, '=');
177
178       if (lex_match (lexer, '*'))
179         {
180           if (!proc_has_active_file (ds))
181             {
182               msg (SE, _("Cannot specify the active file since no active "
183                          "file has been defined."));
184               goto error;
185             }
186
187           if (proc_make_temporary_transformations_permanent (ds))
188             msg (SE,
189                  _("MATCH FILES may not be used after TEMPORARY when "
190                    "the active file is an input source.  "
191                    "Temporary transformations will be made permanent."));
192
193           file->dict = dict_clone (dataset_dict (ds));
194         }
195       else
196         {
197           file->handle = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
198           if (file->handle == NULL)
199             goto error;
200
201           file->reader = any_reader_open (file->handle, &file->dict);
202           if (file->reader == NULL)
203             goto error;
204         }
205
206       while (lex_match (lexer, '/'))
207         if (lex_match_id (lexer, "RENAME"))
208           {
209             if (!parse_dict_rename (lexer, file->dict))
210               goto error;
211           }
212         else if (lex_match_id (lexer, "IN"))
213           {
214             lex_match (lexer, '=');
215             if (lex_token (lexer) != T_ID)
216               {
217                 lex_error (lexer, NULL);
218                 goto error;
219               }
220
221             if (file->in_name != NULL)
222               {
223                 msg (SE, _("Multiple IN subcommands for a single FILE or "
224                            "TABLE."));
225                 goto error;
226               }
227             file->in_name = xstrdup (lex_tokid (lexer));
228             lex_get (lexer);
229             saw_in = true;
230           }
231
232       mtf_merge_dictionary (mtf.dict, file);
233     }
234
235   while (lex_token (lexer) != '.')
236     {
237       if (lex_match (lexer, T_BY))
238         {
239           struct mtf_file *file;
240           struct variable **by;
241           bool ok;
242
243           if (mtf.by_cnt)
244             {
245               lex_sbc_only_once ("BY");
246               goto error;
247             }
248
249           lex_match (lexer, '=');
250           if (!parse_variables (lexer, mtf.dict, &by, &mtf.by_cnt,
251                                 PV_NO_DUPLICATE | PV_NO_SCRATCH))
252             goto error;
253
254           ok = true;
255           ll_for_each (file, struct mtf_file, ll, &mtf.files)
256             {
257               size_t i;
258
259               file->by = xnmalloc (mtf.by_cnt, sizeof *file->by);
260               for (i = 0; i < mtf.by_cnt; i++)
261                 {
262                   const char *var_name = var_get_name (by[i]);
263                   file->by[i] = dict_lookup_var (file->dict, var_name);
264                   if (file->by[i] == NULL)
265                     {
266                       if (file->handle != NULL)
267                         msg (SE, _("File %s lacks BY variable %s."),
268                              fh_get_name (file->handle), var_name);
269                       else
270                         msg (SE, _("Active file lacks BY variable %s."),
271                              var_name);
272                       ok = false;
273                     }
274                 }
275             }
276           free (by);
277
278           if (!ok)
279             goto error;
280         }
281       else if (lex_match_id (lexer, "FIRST"))
282         {
283           if (first_name[0] != '\0')
284             {
285               lex_sbc_only_once ("FIRST");
286               goto error;
287             }
288
289           lex_match (lexer, '=');
290           if (!lex_force_id (lexer))
291             goto error;
292           strcpy (first_name, lex_tokid (lexer));
293           lex_get (lexer);
294         }
295       else if (lex_match_id (lexer, "LAST"))
296         {
297           if (last_name[0] != '\0')
298             {
299               lex_sbc_only_once ("LAST");
300               goto error;
301             }
302
303           lex_match (lexer, '=');
304           if (!lex_force_id (lexer))
305             goto error;
306           strcpy (last_name, lex_tokid (lexer));
307           lex_get (lexer);
308         }
309       else if (lex_match_id (lexer, "MAP"))
310         {
311           /* FIXME. */
312         }
313       else if (lex_match_id (lexer, "DROP"))
314         {
315           if (!parse_dict_drop (lexer, mtf.dict))
316             goto error;
317         }
318       else if (lex_match_id (lexer, "KEEP"))
319         {
320           if (!parse_dict_keep (lexer, mtf.dict))
321             goto error;
322         }
323       else
324         {
325           lex_error (lexer, NULL);
326           goto error;
327         }
328
329       if (!lex_match (lexer, '/') && lex_token (lexer) != '.')
330         {
331           lex_end_of_command (lexer);
332           goto error;
333         }
334     }
335
336   if (mtf.by_cnt == 0)
337     {
338       if (first_table != ll_null (&mtf.files))
339         {
340           msg (SE, _("BY is required when TABLE is specified."));
341           goto error;
342         }
343       if (saw_in)
344         {
345           msg (SE, _("BY is required when IN is specified."));
346           goto error;
347         }
348     }
349
350   /* Set up mapping from each file's variables to master
351      variables. */
352   ll_for_each (file, struct mtf_file, ll, &mtf.files)
353     {
354       size_t in_var_cnt = dict_get_var_cnt (file->dict);
355
356       file->vars = xnmalloc (in_var_cnt, sizeof *file->vars);
357       file->var_cnt = 0;
358       for (i = 0; i < in_var_cnt; i++)
359         {
360           struct variable *in_var = dict_get_var (file->dict, i);
361           struct variable *out_var = dict_lookup_var (mtf.dict,
362                                                       var_get_name (in_var));
363
364           if (out_var != NULL)
365             {
366               struct mtf_variable *mv = &file->vars[file->var_cnt++];
367               mv->in_var = in_var;
368               mv->out_var = out_var;
369             }
370         }
371     }
372
373   /* Add IN, FIRST, and LAST variables to master dictionary. */
374   ll_for_each (file, struct mtf_file, ll, &mtf.files)
375     if (!create_flag_var ("IN", file->in_name, mtf.dict, &file->in_var))
376       goto error;
377   if (!create_flag_var ("FIRST", first_name, mtf.dict, &mtf.first)
378       || !create_flag_var ("LAST", last_name, mtf.dict, &mtf.last))
379     goto error;
380
381   dict_delete_scratch_vars (mtf.dict);
382   dict_compact_values (mtf.dict);
383   mtf.output = autopaging_writer_create (dict_get_next_value_idx (mtf.dict));
384   taint = taint_clone (casewriter_get_taint (mtf.output));
385
386   ll_for_each (file, struct mtf_file, ll, &mtf.files)
387     {
388       if (file->reader == NULL)
389         {
390           if (active_file == NULL)
391             {
392               proc_discard_output (ds);
393               file->reader = active_file = proc_open (ds);
394             }
395           else
396             file->reader = casereader_clone (active_file);
397         }
398       taint_propagate (casereader_get_taint (file->reader), taint);
399     }
400
401   ll_for_each_safe (file, next, struct mtf_file, ll, &mtf.files)
402     mtf_read_record (&mtf, file);
403   while (mtf.nonempty_files > 0)
404     mtf_process_case (&mtf);
405   if ((mtf.first != NULL || mtf.last != NULL) && mtf.prev_BY != NULL)
406     {
407       if (mtf.last != NULL)
408         case_data_rw (&mtf.buffered_case, mtf.last)->f = 1.0;
409       casewriter_write (mtf.output, &mtf.buffered_case);
410       case_nullify (&mtf.buffered_case);
411     }
412   mtf_close_all_files (&mtf);
413   if (active_file != NULL)
414     proc_commit (ds);
415
416   proc_set_active_file (ds, casewriter_make_reader (mtf.output), mtf.dict);
417   mtf.dict = NULL;
418   mtf.output = NULL;
419
420   mtf_free (&mtf);
421
422   return taint_destroy (taint) ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
423
424  error:
425   if (active_file != NULL)
426     proc_commit (ds);
427   mtf_free (&mtf);
428   taint_destroy (taint);
429   return CMD_CASCADING_FAILURE;
430 }
431
432 /* If VAR_NAME is a nonnull pointer to a non-empty string,
433    attempts to create a variable named VAR_NAME, with format
434    F1.0, in DICT, and stores a pointer to the variable in *VAR.
435    Returns true if successful, false if the variable name is a
436    duplicate (in which case a message saying that the variable
437    specified on the given SUBCOMMAND is a duplicate is emitted).
438    Also returns true, without doing anything, if VAR_NAME is null
439    or empty. */
440 static bool
441 create_flag_var (const char *subcommand, const char *var_name,
442                  struct dictionary *dict, struct variable **var)
443 {
444   if (var_name != NULL && var_name[0] != '\0')
445     {
446       struct fmt_spec format = fmt_for_output (FMT_F, 1, 0);
447       *var = dict_create_var (dict, var_name, 0);
448       if (*var == NULL)
449         {
450           msg (SE, _("Variable name %s specified on %s subcommand "
451                      "duplicates an existing variable name."),
452                subcommand, var_name);
453           return false;
454         }
455       var_set_both_formats (*var, &format);
456     }
457   else
458     *var = NULL;
459   return true;
460 }
461
462 /* Return a string in an allocated buffer describing V's variable
463    type and width. */
464 static char *
465 var_type_description (struct variable *v)
466 {
467   if (var_is_numeric (v))
468     return xstrdup ("numeric");
469   else
470     return xasprintf ("string with width %d", var_get_width (v));
471 }
472
473 /* Closes all the files in MTF and frees their associated data.
474    Returns true if successful, false if an I/O error occurred on
475    any of the files. */
476 static bool
477 mtf_close_all_files (struct mtf_proc *mtf)
478 {
479   struct mtf_file *file;
480   bool ok = true;
481
482   ll_for_each_preremove (file, struct mtf_file, ll, &mtf->files)
483     {
484       fh_unref (file->handle);
485       casereader_destroy (file->reader);
486       free (file->by);
487       dict_destroy (file->dict);
488       free (file->in_name);
489       case_destroy (&file->input);
490       free (file->vars);
491       free (file);
492     }
493
494   return ok;
495 }
496
497 /* Frees all the data for the MATCH FILES procedure. */
498 static void
499 mtf_free (struct mtf_proc *mtf)
500 {
501   mtf_close_all_files (mtf);
502   dict_destroy (mtf->dict);
503   casewriter_destroy (mtf->output);
504   case_destroy (&mtf->buffered_case);
505   case_destroy (&mtf->prev_BY_case);
506 }
507
508 /* Reads the next record into FILE, if possible, and update MTF's
509    nonempty_files count if not. */
510 static bool
511 mtf_read_record (struct mtf_proc *mtf, struct mtf_file *file)
512 {
513   case_destroy (&file->input);
514   if (!casereader_read (file->reader, &file->input))
515     {
516       mtf->nonempty_files--;
517       return false;
518     }
519   else
520     return true;
521 }
522
523 /* Compare the BY variables for files A and B; return -1 if A <
524    B, 0 if A == B, 1 if A > B.  (If there are no BY variables,
525    then all records are equal.) */
526 static inline int
527 mtf_compare_BY_values (struct mtf_proc *mtf,
528                        struct mtf_file *a, struct mtf_file *b)
529 {
530   return case_compare_2dict (&a->input, &b->input, a->by, b->by, mtf->by_cnt);
531 }
532
533 /* Processes input files and write one case to the output file. */
534 static void
535 mtf_process_case (struct mtf_proc *mtf)
536 {
537   struct ccase c;
538   struct mtf_file *min;
539   struct mtf_file *file;
540   int min_sequence;
541   size_t i;
542
543   /* Find the set of one or more FILEs whose BY values are
544      minimal, as well as the set of zero or more TABLEs whose BY
545      values equal those of the minimum FILEs.
546
547      After each iteration of the loop, this invariant holds: the
548      FILEs with minimum BY values thus far have "sequence"
549      members equal to min_sequence, and "min" points to one of
550      the mtf_files whose case has those minimum BY values, and
551      similarly for TABLEs. */
552   min_sequence = 0;
553   min = NULL;
554   ll_for_each (file, struct mtf_file, ll, &mtf->files)
555     if (case_is_null (&file->input))
556       file->sequence = -1;
557     else if (file->type == MTF_FILE)
558       {
559         int cmp = min != NULL ? mtf_compare_BY_values (mtf, min, file) : 1;
560         if (cmp <= 0)
561           file->sequence = cmp < 0 ? -1 : min_sequence;
562         else
563           {
564             file->sequence = ++min_sequence;
565             min = file;
566           }
567       }
568     else
569       {
570         int cmp;
571         assert (min != NULL);
572         do
573           {
574             cmp = mtf_compare_BY_values (mtf, min, file);
575           }
576         while (cmp > 0 && mtf_read_record (mtf, file));
577         file->sequence = cmp == 0 ? min_sequence : -1;
578       }
579
580   /* Form the output case from the input cases. */
581   case_create (&c, dict_get_next_value_idx (mtf->dict));
582   for (i = 0; i < dict_get_var_cnt (mtf->dict); i++)
583     {
584       struct variable *v = dict_get_var (mtf->dict, i);
585       value_set_missing (case_data_rw (&c, v), var_get_width (v));
586     }
587   ll_for_each_reverse (file, struct mtf_file, ll, &mtf->files)
588     {
589       bool include_file = file->sequence == min_sequence;
590       if (include_file)
591         for (i = 0; i < file->var_cnt; i++)
592           {
593             const struct mtf_variable *mv = &file->vars[i];
594             const union value *in = case_data (&file->input, mv->in_var);
595             union value *out = case_data_rw (&c, mv->out_var);
596             value_copy (out, in, var_get_width (mv->in_var));
597           }
598       if (file->in_var != NULL)
599         case_data_rw (&c, file->in_var)->f = include_file;
600     }
601
602   /* Write the output case. */
603   if (mtf->first == NULL && mtf->last == NULL)
604     {
605       /* With no FIRST or LAST variables, it's trivial. */
606       casewriter_write (mtf->output, &c);
607     }
608   else
609     {
610       /* It's harder with LAST, because we can't know whether
611          this case is the last in a group until we've prepared
612          the *next* case also.  Thus, we buffer the previous
613          output case until the next one is ready.
614
615          We also have to save a copy of one of the previous input
616          cases, so that we can compare the BY variables.  We
617          can't compare the BY variables between the current
618          output case and the saved one because the BY variables
619          might not be in the output (the user is allowed to drop
620          them). */
621       bool new_BY;
622       if (mtf->prev_BY != NULL)
623         {
624           new_BY = case_compare_2dict (&min->input, &mtf->prev_BY_case,
625                                        min->by, mtf->prev_BY,
626                                        mtf->by_cnt);
627           if (mtf->last != NULL)
628             case_data_rw (&mtf->buffered_case, mtf->last)->f = new_BY;
629           casewriter_write (mtf->output, &mtf->buffered_case);
630         }
631       else
632         new_BY = true;
633
634       case_move (&mtf->buffered_case, &c);
635       if (mtf->first != NULL)
636         case_data_rw (&mtf->buffered_case, mtf->first)->f = new_BY;
637
638       if (new_BY)
639         {
640           mtf->prev_BY = min->by;
641           case_destroy (&mtf->prev_BY_case);
642           case_clone (&mtf->prev_BY_case, &min->input);
643         }
644     }
645
646   /* Read another record from each input file FILE with minimum
647      values. */
648   ll_for_each (file, struct mtf_file, ll, &mtf->files)
649     if (file->type == MTF_FILE)
650       {
651         if (file->sequence == min_sequence)
652           mtf_read_record (mtf, file);
653       }
654     else
655       break;
656 }
657
658 /* Merge the dictionary for file F into master dictionary M. */
659 static bool
660 mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f)
661 {
662   struct dictionary *d = f->dict;
663   const char *d_docs, *m_docs;
664   int i;
665
666   if (dict_get_label (m) == NULL)
667     dict_set_label (m, dict_get_label (d));
668
669   d_docs = dict_get_documents (d);
670   m_docs = dict_get_documents (m);
671   if (d_docs != NULL)
672     {
673       if (m_docs == NULL)
674         dict_set_documents (m, d_docs);
675       else
676         {
677           char *new_docs = xasprintf ("%s%s", m_docs, d_docs);
678           dict_set_documents (m, new_docs);
679           free (new_docs);
680         }
681     }
682
683   for (i = 0; i < dict_get_var_cnt (d); i++)
684     {
685       struct variable *dv = dict_get_var (d, i);
686       struct variable *mv = dict_lookup_var (m, var_get_name (dv));
687
688       if (dict_class_from_id (var_get_name (dv)) == DC_SCRATCH)
689         continue;
690
691       if (mv != NULL)
692         {
693           if (var_get_width (mv) != var_get_width (dv))
694             {
695               char *dv_description = var_type_description (dv);
696               char *mv_description = var_type_description (mv);
697               msg (SE, _("Variable %s in file %s (%s) has different "
698                          "type or width from the same variable in "
699                          "earlier file (%s)."),
700                    var_get_name (dv), fh_get_name (f->handle),
701                    dv_description, mv_description);
702               free (dv_description);
703               free (mv_description);
704               return false;
705             }
706
707           if (var_get_width (dv) == var_get_width (mv))
708             {
709               if (var_has_value_labels (dv) && !var_has_value_labels (mv))
710                 var_set_value_labels (mv, var_get_value_labels (dv));
711               if (var_has_missing_values (dv) && !var_has_missing_values (mv))
712                 var_set_missing_values (mv, var_get_missing_values (dv));
713             }
714
715           if (var_get_label (dv) && !var_get_label (mv))
716             var_set_label (mv, var_get_label (dv));
717         }
718       else
719         mv = dict_clone_var_assert (m, dv, var_get_name (dv));
720     }
721
722   return true;
723 }