b73a2bda6fdc076e243ca171ecb69412d4e33a74
[pspp-builds.git] / src / language / data-io / get.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21
22 #include <stdlib.h>
23
24 #include <data/any-reader.h>
25 #include <data/any-writer.h>
26 #include <data/case-sink.h>
27 #include <data/case-source.h>
28 #include <data/case.h>
29 #include <data/dictionary.h>
30 #include <data/por-file-writer.h>
31 #include <data/settings.h>
32 #include <data/storage-stream.h>
33 #include <data/sys-file-writer.h>
34 #include <data/value-labels.h>
35 #include <data/variable.h>
36 #include <language/command.h>
37 #include <language/data-io/file-handle.h>
38 #include <language/lexer/lexer.h>
39 #include <libpspp/alloc.h>
40 #include <libpspp/compiler.h>
41 #include <libpspp/hash.h>
42 #include <libpspp/message.h>
43 #include <libpspp/message.h>
44 #include <libpspp/misc.h>
45 #include <libpspp/str.h>
46 #include <procedure.h>
47
48 #include "gettext.h"
49 #define _(msgid) gettext (msgid)
50
51 /* Rearranging and reducing a dictionary. */
52 static void start_case_map (struct dictionary *);
53 static struct case_map *finish_case_map (struct dictionary *);
54 static void map_case (const struct case_map *,
55                       const struct ccase *, struct ccase *);
56 static void destroy_case_map (struct case_map *);
57
58 static bool parse_dict_trim (struct dictionary *);
59 \f
60 /* Reading system and portable files. */
61
62 /* Type of command. */
63 enum reader_command 
64   {
65     GET_CMD,
66     IMPORT_CMD
67   };
68
69 /* Case reader input program. */
70 struct case_reader_pgm 
71   {
72     struct any_reader *reader;  /* File reader. */
73     struct case_map *map;       /* Map from file dict to active file dict. */
74     struct ccase bounce;        /* Bounce buffer. */
75   };
76
77 static const struct case_source_class case_reader_source_class;
78
79 static void case_reader_pgm_free (struct case_reader_pgm *);
80
81 /* Parses a GET or IMPORT command. */
82 static int
83 parse_read_command (enum reader_command type)
84 {
85   struct case_reader_pgm *pgm = NULL;
86   struct file_handle *fh = NULL;
87   struct dictionary *dict = NULL;
88
89   for (;;)
90     {
91       lex_match ('/');
92
93       if (lex_match_id ("FILE") || token == T_STRING)
94         {
95           lex_match ('=');
96
97           fh = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
98           if (fh == NULL)
99             goto error;
100         }
101       else if (type == IMPORT_CMD && lex_match_id ("TYPE"))
102         {
103           lex_match ('=');
104
105           if (lex_match_id ("COMM"))
106             type = PFM_COMM;
107           else if (lex_match_id ("TAPE"))
108             type = PFM_TAPE;
109           else
110             {
111               lex_error (_("expecting COMM or TAPE"));
112               goto error;
113             }
114         }
115       else
116         break; 
117     }
118   
119   if (fh == NULL) 
120     {
121       lex_sbc_missing ("FILE");
122       goto error;
123     }
124               
125   discard_variables ();
126
127   pgm = xmalloc (sizeof *pgm);
128   pgm->reader = any_reader_open (fh, &dict);
129   pgm->map = NULL;
130   case_nullify (&pgm->bounce);
131   if (pgm->reader == NULL)
132     goto error;
133
134   case_create (&pgm->bounce, dict_get_next_value_idx (dict));
135   
136   start_case_map (dict);
137
138   while (token != '.')
139     {
140       lex_match ('/');
141       if (!parse_dict_trim (dict))
142         goto error;
143     }
144
145   pgm->map = finish_case_map (dict);
146   
147   dict_destroy (default_dict);
148   default_dict = dict;
149
150   vfm_source = create_case_source (&case_reader_source_class, pgm);
151
152   return CMD_SUCCESS;
153
154  error:
155   case_reader_pgm_free (pgm);
156   if (dict != NULL)
157     dict_destroy (dict);
158   return CMD_CASCADING_FAILURE;
159 }
160
161 /* Frees a struct case_reader_pgm. */
162 static void
163 case_reader_pgm_free (struct case_reader_pgm *pgm) 
164 {
165   if (pgm != NULL) 
166     {
167       any_reader_close (pgm->reader);
168       destroy_case_map (pgm->map);
169       case_destroy (&pgm->bounce);
170       free (pgm);
171     }
172 }
173
174 /* Clears internal state related to case reader input procedure. */
175 static void
176 case_reader_source_destroy (struct case_source *source)
177 {
178   struct case_reader_pgm *pgm = source->aux;
179   case_reader_pgm_free (pgm);
180 }
181
182 /* Reads all the cases from the data file into C and passes them
183    to WRITE_CASE one by one, passing WC_DATA.
184    Returns true if successful, false if an I/O error occurred. */
185 static bool
186 case_reader_source_read (struct case_source *source,
187                          struct ccase *c,
188                          write_case_func *write_case, write_case_data wc_data)
189 {
190   struct case_reader_pgm *pgm = source->aux;
191   bool ok = true;
192
193   do
194     {
195       bool got_case;
196       if (pgm->map == NULL)
197         got_case = any_reader_read (pgm->reader, c);
198       else
199         {
200           got_case = any_reader_read (pgm->reader, &pgm->bounce);
201           if (got_case)
202             map_case (pgm->map, &pgm->bounce, c);
203         }
204       if (!got_case)
205         break;
206
207       ok = write_case (wc_data);
208     }
209   while (ok);
210
211   return ok && !any_reader_error (pgm->reader);
212 }
213
214 static const struct case_source_class case_reader_source_class =
215   {
216     "case reader",
217     NULL,
218     case_reader_source_read,
219     case_reader_source_destroy,
220   };
221 \f
222 /* GET. */
223 int
224 cmd_get (void) 
225 {
226   return parse_read_command (GET_CMD);
227 }
228
229 /* IMPORT. */
230 int
231 cmd_import (void) 
232 {
233   return parse_read_command (IMPORT_CMD);
234 }
235 \f
236 /* Writing system and portable files. */ 
237
238 /* Type of output file. */
239 enum writer_type
240   {
241     SYSFILE_WRITER,     /* System file. */
242     PORFILE_WRITER      /* Portable file. */
243   };
244
245 /* Type of a command. */
246 enum command_type 
247   {
248     XFORM_CMD,          /* Transformation. */
249     PROC_CMD            /* Procedure. */
250   };
251
252 /* File writer plus a case map. */
253 struct case_writer
254   {
255     struct any_writer *writer;  /* File writer. */
256     struct case_map *map;       /* Map to output file dictionary
257                                    (null pointer for identity mapping). */
258     struct ccase bounce;        /* Bounce buffer for mapping (if needed). */
259   };
260
261 /* Destroys AW. */
262 static bool
263 case_writer_destroy (struct case_writer *aw)
264 {
265   bool ok = true;
266   if (aw != NULL) 
267     {
268       ok = any_writer_close (aw->writer);
269       destroy_case_map (aw->map);
270       case_destroy (&aw->bounce);
271       free (aw);
272     }
273   return ok;
274 }
275
276 /* Parses SAVE or XSAVE or EXPORT or XEXPORT command.
277    WRITER_TYPE identifies the type of file to write,
278    and COMMAND_TYPE identifies the type of command.
279
280    On success, returns a writer.
281    For procedures only, sets *RETAIN_UNSELECTED to true if cases
282    that would otherwise be excluded by FILTER or USE should be
283    included.
284
285    On failure, returns a null pointer. */
286 static struct case_writer *
287 parse_write_command (enum writer_type writer_type,
288                      enum command_type command_type,
289                      bool *retain_unselected)
290 {
291   /* Common data. */
292   struct file_handle *handle; /* Output file. */
293   struct dictionary *dict;    /* Dictionary for output file. */
294   struct case_writer *aw;      /* Writer. */  
295
296   /* Common options. */
297   bool print_map;             /* Print map?  TODO. */
298   bool print_short_names;     /* Print long-to-short name map.  TODO. */
299   struct sfm_write_options sysfile_opts;
300   struct pfm_write_options porfile_opts;
301
302   assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER);
303   assert (command_type == XFORM_CMD || command_type == PROC_CMD);
304   assert ((retain_unselected != NULL) == (command_type == PROC_CMD));
305
306   if (command_type == PROC_CMD)
307     *retain_unselected = true;
308
309   handle = NULL;
310   dict = dict_clone (default_dict);
311   aw = xmalloc (sizeof *aw);
312   aw->writer = NULL;
313   aw->map = NULL;
314   case_nullify (&aw->bounce);
315   print_map = false;
316   print_short_names = false;
317   sysfile_opts = sfm_writer_default_options ();
318   porfile_opts = pfm_writer_default_options ();
319
320   start_case_map (dict);
321   dict_delete_scratch_vars (dict);
322
323   lex_match ('/');
324   for (;;)
325     {
326       if (lex_match_id ("OUTFILE"))
327         {
328           if (handle != NULL) 
329             {
330               lex_sbc_only_once ("OUTFILE");
331               goto error; 
332             }
333           
334           lex_match ('=');
335       
336           handle = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
337           if (handle == NULL)
338             goto error;
339         }
340       else if (lex_match_id ("NAMES"))
341         print_short_names = true;
342       else if (lex_match_id ("PERMISSIONS")) 
343         {
344           bool cw;
345           
346           lex_match ('=');
347           if (lex_match_id ("READONLY"))
348             cw = false;
349           else if (lex_match_id ("WRITEABLE"))
350             cw = true;
351           else
352             {
353               lex_error (_("expecting %s or %s"), "READONLY", "WRITEABLE");
354               goto error;
355             }
356           sysfile_opts.create_writeable = porfile_opts.create_writeable = cw;
357         }
358       else if (command_type == PROC_CMD && lex_match_id ("UNSELECTED")) 
359         {
360           lex_match ('=');
361           if (lex_match_id ("RETAIN"))
362             *retain_unselected = true;
363           else if (lex_match_id ("DELETE"))
364             *retain_unselected = false;
365           else
366             {
367               lex_error (_("expecting %s or %s"), "RETAIN", "DELETE");
368               goto error;
369             }
370         }
371       else if (writer_type == SYSFILE_WRITER && lex_match_id ("COMPRESSED"))
372         sysfile_opts.compress = true;
373       else if (writer_type == SYSFILE_WRITER && lex_match_id ("UNCOMPRESSED"))
374         sysfile_opts.compress = false;
375       else if (writer_type == SYSFILE_WRITER && lex_match_id ("VERSION"))
376         {
377           lex_match ('=');
378           if (!lex_force_int ())
379             goto error;
380           sysfile_opts.version = lex_integer ();
381           lex_get ();
382         }
383       else if (writer_type == PORFILE_WRITER && lex_match_id ("TYPE")) 
384         {
385           lex_match ('=');
386           if (lex_match_id ("COMMUNICATIONS"))
387             porfile_opts.type = PFM_COMM;
388           else if (lex_match_id ("TAPE"))
389             porfile_opts.type = PFM_TAPE;
390           else
391             {
392               lex_error (_("expecting %s or %s"), "COMM", "TAPE");
393               goto error;
394             }
395         }
396       else if (writer_type == PORFILE_WRITER && lex_match_id ("DIGITS")) 
397         {
398           lex_match ('=');
399           if (!lex_force_int ())
400             goto error;
401           porfile_opts.digits = lex_integer ();
402           lex_get ();
403         }
404       else if (!parse_dict_trim (dict))
405         goto error;
406       
407       if (!lex_match ('/'))
408         break;
409     }
410   if (lex_end_of_command () != CMD_SUCCESS)
411     goto error;
412
413   if (handle == NULL) 
414     {
415       lex_sbc_missing ("OUTFILE");
416       goto error;
417     }
418
419   dict_compact_values (dict);
420   aw->map = finish_case_map (dict);
421   if (aw->map != NULL)
422     case_create (&aw->bounce, dict_get_next_value_idx (dict));
423
424   if (fh_get_referent (handle) == FH_REF_FILE) 
425     {
426       switch (writer_type) 
427         {
428         case SYSFILE_WRITER:
429           aw->writer = any_writer_from_sfm_writer (
430             sfm_open_writer (handle, dict, sysfile_opts));
431           break;
432         case PORFILE_WRITER:
433           aw->writer = any_writer_from_pfm_writer (
434             pfm_open_writer (handle, dict, porfile_opts));
435           break;
436         }
437     }
438   else
439     aw->writer = any_writer_open (handle, dict);
440   dict_destroy (dict);
441   
442   return aw;
443
444  error:
445   case_writer_destroy (aw);
446   dict_destroy (dict);
447   return NULL;
448 }
449
450 /* Writes case C to writer AW. */
451 static bool
452 case_writer_write_case (struct case_writer *aw, struct ccase *c) 
453 {
454   if (aw->map != NULL) 
455     {
456       map_case (aw->map, c, &aw->bounce);
457       c = &aw->bounce; 
458     }
459   return any_writer_write (aw->writer, c);
460 }
461 \f
462 /* SAVE and EXPORT. */
463
464 static bool output_proc (struct ccase *, void *);
465
466 /* Parses and performs the SAVE or EXPORT procedure. */
467 static int
468 parse_output_proc (enum writer_type writer_type)
469 {
470   bool retain_unselected;
471   struct variable *saved_filter_variable;
472   struct case_writer *aw;
473   bool ok;
474
475   aw = parse_write_command (writer_type, PROC_CMD, &retain_unselected);
476   if (aw == NULL) 
477     return CMD_CASCADING_FAILURE;
478
479   saved_filter_variable = dict_get_filter (default_dict);
480   if (retain_unselected) 
481     dict_set_filter (default_dict, NULL);
482   ok = procedure (output_proc, aw);
483   dict_set_filter (default_dict, saved_filter_variable);
484
485   case_writer_destroy (aw);
486   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
487 }
488
489 /* Writes case C to file. */
490 static bool
491 output_proc (struct ccase *c, void *aw_) 
492 {
493   struct case_writer *aw = aw_;
494   return case_writer_write_case (aw, c);
495 }
496
497 int
498 cmd_save (void) 
499 {
500   return parse_output_proc (SYSFILE_WRITER);
501 }
502
503 int
504 cmd_export (void) 
505 {
506   return parse_output_proc (PORFILE_WRITER);
507 }
508 \f
509 /* XSAVE and XEXPORT. */
510
511 /* Transformation. */
512 struct output_trns 
513   {
514     struct case_writer *aw;      /* Writer. */
515   };
516
517 static trns_proc_func output_trns_proc;
518 static trns_free_func output_trns_free;
519
520 /* Parses the XSAVE or XEXPORT transformation command. */
521 static int
522 parse_output_trns (enum writer_type writer_type) 
523 {
524   struct output_trns *t = xmalloc (sizeof *t);
525   t->aw = parse_write_command (writer_type, XFORM_CMD, NULL);
526   if (t->aw == NULL) 
527     {
528       free (t);
529       return CMD_CASCADING_FAILURE;
530     }
531
532   add_transformation (output_trns_proc, output_trns_free, t);
533   return CMD_SUCCESS;
534 }
535
536 /* Writes case C to the system file specified on XSAVE or XEXPORT. */
537 static int
538 output_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
539 {
540   struct output_trns *t = trns_;
541   case_writer_write_case (t->aw, c);
542   return TRNS_CONTINUE;
543 }
544
545 /* Frees an XSAVE or XEXPORT transformation.
546    Returns true if successful, false if an I/O error occurred. */
547 static bool
548 output_trns_free (void *trns_)
549 {
550   struct output_trns *t = trns_;
551   bool ok = true;
552
553   if (t != NULL)
554     {
555       ok = case_writer_destroy (t->aw);
556       free (t);
557     }
558   return ok;
559 }
560
561 /* XSAVE command. */
562 int
563 cmd_xsave (void) 
564 {
565   return parse_output_trns (SYSFILE_WRITER);
566 }
567
568 /* XEXPORT command. */
569 int
570 cmd_xexport (void) 
571 {
572   return parse_output_trns (PORFILE_WRITER);
573 }
574 \f
575 static bool rename_variables (struct dictionary *dict);
576 static bool drop_variables (struct dictionary *dict);
577 static bool keep_variables (struct dictionary *dict);
578
579 /* Commands that read and write system files share a great deal
580    of common syntactic structure for rearranging and dropping
581    variables.  This function parses this syntax and modifies DICT
582    appropriately.  Returns true on success, false on failure. */
583 static bool
584 parse_dict_trim (struct dictionary *dict)
585 {
586   if (lex_match_id ("MAP")) 
587     {
588       /* FIXME. */
589       return true;
590     }
591   else if (lex_match_id ("DROP"))
592     return drop_variables (dict);
593   else if (lex_match_id ("KEEP"))
594     return keep_variables (dict);
595   else if (lex_match_id ("RENAME"))
596     return rename_variables (dict);
597   else
598     {
599       lex_error (_("expecting a valid subcommand"));
600       return false;
601     }
602 }
603
604 /* Parses and performs the RENAME subcommand of GET and SAVE. */
605 static bool
606 rename_variables (struct dictionary *dict)
607 {
608   size_t i;
609
610   int success = 0;
611
612   struct variable **v;
613   char **new_names;
614   size_t nv, nn;
615   char *err_name;
616
617   int group;
618
619   lex_match ('=');
620   if (token != '(')
621     {
622       struct variable *v;
623
624       v = parse_dict_variable (dict);
625       if (v == NULL)
626         return 0;
627       if (!lex_force_match ('=')
628           || !lex_force_id ())
629         return 0;
630       if (dict_lookup_var (dict, tokid) != NULL)
631         {
632           msg (SE, _("Cannot rename %s as %s because there already exists "
633                      "a variable named %s.  To rename variables with "
634                      "overlapping names, use a single RENAME subcommand "
635                      "such as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, "
636                      "\"/RENAME (A B C=B C A)\"."), v->name, tokid, tokid);
637           return 0;
638         }
639       
640       dict_rename_var (dict, v, tokid);
641       lex_get ();
642       return 1;
643     }
644
645   nv = nn = 0;
646   v = NULL;
647   new_names = 0;
648   group = 1;
649   while (lex_match ('('))
650     {
651       size_t old_nv = nv;
652
653       if (!parse_variables (dict, &v, &nv, PV_NO_DUPLICATE | PV_APPEND))
654         goto done;
655       if (!lex_match ('='))
656         {
657           msg (SE, _("`=' expected after variable list."));
658           goto done;
659         }
660       if (!parse_DATA_LIST_vars (&new_names, &nn, PV_APPEND | PV_NO_SCRATCH))
661         goto done;
662       if (nn != nv)
663         {
664           msg (SE, _("Number of variables on left side of `=' (%d) does not "
665                      "match number of variables on right side (%d), in "
666                      "parenthesized group %d of RENAME subcommand."),
667                (unsigned) (nv - old_nv), (unsigned) (nn - old_nv), group);
668           goto done;
669         }
670       if (!lex_force_match (')'))
671         goto done;
672       group++;
673     }
674
675   if (!dict_rename_vars (dict, v, new_names, nv, &err_name)) 
676     {
677       msg (SE, _("Requested renaming duplicates variable name %s."), err_name);
678       goto done;
679     }
680   success = 1;
681
682  done:
683   for (i = 0; i < nn; i++)
684     free (new_names[i]);
685   free (new_names);
686   free (v);
687
688   return success;
689 }
690
691 /* Parses and performs the DROP subcommand of GET and SAVE.
692    Returns true if successful, false on failure.*/
693 static bool
694 drop_variables (struct dictionary *dict)
695 {
696   struct variable **v;
697   size_t nv;
698
699   lex_match ('=');
700   if (!parse_variables (dict, &v, &nv, PV_NONE))
701     return false;
702   dict_delete_vars (dict, v, nv);
703   free (v);
704
705   if (dict_get_var_cnt (dict) == 0)
706     {
707       msg (SE, _("Cannot DROP all variables from dictionary."));
708       return false;
709     }
710   return true;
711 }
712
713 /* Parses and performs the KEEP subcommand of GET and SAVE.
714    Returns true if successful, false on failure.*/
715 static bool
716 keep_variables (struct dictionary *dict)
717 {
718   struct variable **v;
719   size_t nv;
720   size_t i;
721
722   lex_match ('=');
723   if (!parse_variables (dict, &v, &nv, PV_NONE))
724     return false;
725
726   /* Move the specified variables to the beginning. */
727   dict_reorder_vars (dict, v, nv);
728           
729   /* Delete the remaining variables. */
730   v = xnrealloc (v, dict_get_var_cnt (dict) - nv, sizeof *v);
731   for (i = nv; i < dict_get_var_cnt (dict); i++)
732     v[i - nv] = dict_get_var (dict, i);
733   dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);
734   free (v);
735
736   return true;
737 }
738 \f
739 /* MATCH FILES. */
740
741 /* File types. */
742 enum
743   {
744     MTF_FILE,                   /* Specified on FILE= subcommand. */
745     MTF_TABLE                   /* Specified on TABLE= subcommand. */
746   };
747
748 /* One of the files on MATCH FILES. */
749 struct mtf_file
750   {
751     struct mtf_file *next, *prev; /* Next, previous in the list of files. */
752     struct mtf_file *next_min;  /* Next in the chain of minimums. */
753     
754     int type;                   /* One of MTF_*. */
755     struct variable **by;       /* List of BY variables for this file. */
756     struct file_handle *handle; /* File handle. */
757     struct any_reader *reader;  /* File reader. */
758     struct dictionary *dict;    /* Dictionary from system file. */
759
760     /* IN subcommand. */
761     char *in_name;              /* Variable name. */
762     struct variable *in_var;    /* Variable (in master dictionary). */
763
764     struct ccase input;         /* Input record. */
765   };
766
767 /* MATCH FILES procedure. */
768 struct mtf_proc 
769   {
770     struct mtf_file *head;      /* First file mentioned on FILE or TABLE. */
771     struct mtf_file *tail;      /* Last file mentioned on FILE or TABLE. */
772
773     bool ok;                    /* False if I/O error occurs. */
774
775     size_t by_cnt;              /* Number of variables on BY subcommand. */
776
777     /* Names of FIRST, LAST variables. */
778     char first[LONG_NAME_LEN + 1], last[LONG_NAME_LEN + 1];
779     
780     struct dictionary *dict;    /* Dictionary of output file. */
781     struct case_sink *sink;     /* Sink to receive output. */
782     struct ccase mtf_case;      /* Case used for output. */
783
784     unsigned seq_num;           /* Have we initialized this variable? */
785     unsigned *seq_nums;         /* Sequence numbers for each var in dict. */
786   };
787
788 static bool mtf_free (struct mtf_proc *);
789 static bool mtf_close_file (struct mtf_file *);
790 static int mtf_merge_dictionary (struct dictionary *const, struct mtf_file *);
791 static bool mtf_delete_file_in_place (struct mtf_proc *, struct mtf_file **);
792
793 static bool mtf_read_nonactive_records (void *);
794 static bool mtf_processing_finish (void *);
795 static bool mtf_processing (struct ccase *, void *);
796
797 static char *var_type_description (struct variable *);
798
799 static void set_master (struct variable *, struct variable *master);
800 static struct variable *get_master (struct variable *);
801
802 /* Parse and execute the MATCH FILES command. */
803 int
804 cmd_match_files (void)
805 {
806   struct mtf_proc mtf;
807   struct mtf_file *first_table = NULL;
808   struct mtf_file *iter;
809   
810   bool used_active_file = false;
811   bool saw_table = false;
812   bool saw_in = false;
813
814   bool ok;
815   
816   mtf.head = mtf.tail = NULL;
817   mtf.by_cnt = 0;
818   mtf.first[0] = '\0';
819   mtf.last[0] = '\0';
820   mtf.dict = dict_create ();
821   mtf.sink = NULL;
822   case_nullify (&mtf.mtf_case);
823   mtf.seq_num = 0;
824   mtf.seq_nums = NULL;
825   dict_set_case_limit (mtf.dict, dict_get_case_limit (default_dict));
826
827   lex_match ('/');
828   while (token == T_ID
829          && (lex_id_match ("FILE", tokid) || lex_id_match ("TABLE", tokid)))
830     {
831       struct mtf_file *file = xmalloc (sizeof *file);
832
833       if (lex_match_id ("FILE"))
834         file->type = MTF_FILE;
835       else if (lex_match_id ("TABLE"))
836         {
837           file->type = MTF_TABLE;
838           saw_table = true;
839         }
840       else
841         assert (0);
842       lex_match ('=');
843
844       file->by = NULL;
845       file->handle = NULL;
846       file->reader = NULL;
847       file->dict = NULL;
848       file->in_name = NULL;
849       file->in_var = NULL;
850       case_nullify (&file->input);
851
852       /* FILEs go first, then TABLEs. */
853       if (file->type == MTF_TABLE || first_table == NULL)
854         {
855           file->next = NULL;
856           file->prev = mtf.tail;
857           if (mtf.tail)
858             mtf.tail->next = file;
859           mtf.tail = file;
860           if (mtf.head == NULL)
861             mtf.head = file;
862           if (file->type == MTF_TABLE && first_table == NULL)
863             first_table = file;
864         }
865       else 
866         {
867           assert (file->type == MTF_FILE);
868           file->next = first_table;
869           file->prev = first_table->prev;
870           if (first_table->prev)
871             first_table->prev->next = file;
872           else
873             mtf.head = file;
874           first_table->prev = file;
875         }
876
877       if (lex_match ('*'))
878         {
879           file->handle = NULL;
880           file->reader = NULL;
881               
882           if (used_active_file)
883             {
884               msg (SE, _("The active file may not be specified more "
885                          "than once."));
886               goto error;
887             }
888           used_active_file = true;
889
890           if (vfm_source == NULL)
891             {
892               msg (SE, _("Cannot specify the active file since no active "
893                          "file has been defined."));
894               goto error;
895             }
896
897           if (temporary != 0)
898             {
899               msg (SE,
900                    _("MATCH FILES may not be used after TEMPORARY when "
901                      "the active file is an input source.  "
902                      "Temporary transformations will be made permanent."));
903               cancel_temporary (); 
904             }
905
906           file->dict = default_dict;
907         }
908       else
909         {
910           file->handle = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
911           if (file->handle == NULL)
912             goto error;
913
914           file->reader = any_reader_open (file->handle, &file->dict);
915           if (file->reader == NULL)
916             goto error;
917
918           case_create (&file->input, dict_get_next_value_idx (file->dict));
919         }
920
921       while (lex_match ('/'))
922         if (lex_match_id ("RENAME")) 
923           {
924             if (!rename_variables (file->dict))
925               goto error; 
926           }
927         else if (lex_match_id ("IN"))
928           {
929             lex_match ('=');
930             if (token != T_ID)
931               {
932                 lex_error (NULL);
933                 goto error;
934               }
935
936             if (file->in_name != NULL)
937               {
938                 msg (SE, _("Multiple IN subcommands for a single FILE or "
939                            "TABLE."));
940                 goto error;
941               }
942             file->in_name = xstrdup (tokid);
943             lex_get ();
944             saw_in = true;
945           }
946
947       mtf_merge_dictionary (mtf.dict, file);
948     }
949   
950   while (token != '.')
951     {
952       if (lex_match (T_BY))
953         {
954           struct variable **by;
955           
956           if (mtf.by_cnt)
957             {
958               msg (SE, _("BY may appear at most once."));
959               goto error;
960             }
961               
962           lex_match ('=');
963           if (!parse_variables (mtf.dict, &by, &mtf.by_cnt,
964                                 PV_NO_DUPLICATE | PV_NO_SCRATCH))
965             goto error;
966
967           for (iter = mtf.head; iter != NULL; iter = iter->next)
968             {
969               size_t i;
970           
971               iter->by = xnmalloc (mtf.by_cnt, sizeof *iter->by);
972
973               for (i = 0; i < mtf.by_cnt; i++)
974                 {
975                   iter->by[i] = dict_lookup_var (iter->dict, by[i]->name);
976                   if (iter->by[i] == NULL)
977                     {
978                       msg (SE, _("File %s lacks BY variable %s."),
979                            iter->handle ? fh_get_name (iter->handle) : "*",
980                            by[i]->name);
981                       free (by);
982                       goto error;
983                     }
984                 }
985             }
986           free (by);
987         }
988       else if (lex_match_id ("FIRST")) 
989         {
990           if (mtf.first[0] != '\0')
991             {
992               msg (SE, _("FIRST may appear at most once."));
993               goto error;
994             }
995               
996           lex_match ('=');
997           if (!lex_force_id ())
998             goto error;
999           strcpy (mtf.first, tokid);
1000           lex_get ();
1001         }
1002       else if (lex_match_id ("LAST")) 
1003         {
1004           if (mtf.last[0] != '\0')
1005             {
1006               msg (SE, _("LAST may appear at most once."));
1007               goto error;
1008             }
1009               
1010           lex_match ('=');
1011           if (!lex_force_id ())
1012             goto error;
1013           strcpy (mtf.last, tokid);
1014           lex_get ();
1015         }
1016       else if (lex_match_id ("MAP"))
1017         {
1018           /* FIXME. */
1019         }
1020       else if (lex_match_id ("DROP")) 
1021         {
1022           if (!drop_variables (mtf.dict))
1023             goto error;
1024         }
1025       else if (lex_match_id ("KEEP")) 
1026         {
1027           if (!keep_variables (mtf.dict))
1028             goto error;
1029         }
1030       else
1031         {
1032           lex_error (NULL);
1033           goto error;
1034         }
1035
1036       if (!lex_match ('/') && token != '.') 
1037         {
1038           lex_end_of_command ();
1039           goto error;
1040         }
1041     }
1042
1043   if (mtf.by_cnt == 0)
1044     {
1045       if (saw_table)
1046         {
1047           msg (SE, _("BY is required when TABLE is specified."));
1048           goto error;
1049         }
1050       if (saw_in)
1051         {
1052           msg (SE, _("BY is required when IN is specified."));
1053           goto error;
1054         }
1055     }
1056
1057   /* Set up mapping from each file's variables to master
1058      variables. */
1059   for (iter = mtf.head; iter != NULL; iter = iter->next)
1060     {
1061       struct dictionary *d = iter->dict;
1062       int i;
1063
1064       for (i = 0; i < dict_get_var_cnt (d); i++)
1065         {
1066           struct variable *v = dict_get_var (d, i);
1067           struct variable *mv = dict_lookup_var (mtf.dict, v->name);
1068           if (mv != NULL)
1069             set_master (v, mv);
1070         }
1071     }
1072
1073   /* Add IN variables to master dictionary. */
1074   for (iter = mtf.head; iter != NULL; iter = iter->next) 
1075     if (iter->in_name != NULL)
1076       {
1077         iter->in_var = dict_create_var (mtf.dict, iter->in_name, 0);
1078         if (iter->in_var == NULL)
1079           {
1080             msg (SE, _("IN variable name %s duplicates an "
1081                        "existing variable name."),
1082                  iter->in_var->name);
1083             goto error;
1084           }
1085         iter->in_var->print = iter->in_var->write
1086           = make_output_format (FMT_F, 1, 0);
1087       }
1088     
1089   /* MATCH FILES performs an n-way merge on all its input files.
1090      Abstract algorithm:
1091
1092      1. Read one input record from every input FILE.
1093
1094      2. If no FILEs are left, stop.  Otherwise, proceed to step 3.
1095
1096      3. Find the FILE input record(s) that have minimum BY
1097      values.  Store all the values from these input records into
1098      the output record.
1099
1100      4. For every TABLE, read another record as long as the BY values
1101      on the TABLE's input record are less than the FILEs' BY values.
1102      If an exact match is found, store all the values from the TABLE
1103      input record into the output record.
1104
1105      5. Write the output record.
1106
1107      6. Read another record from each input file FILE and TABLE that
1108      we stored values from above.  If we come to the end of one of the
1109      input files, remove it from the list of input files.
1110
1111      7. Repeat from step 2.
1112
1113      Unfortunately, this algorithm can't be implemented in a
1114      straightforward way because there's no function to read a
1115      record from the active file.  Instead, it has to be written
1116      as a state machine.
1117
1118      FIXME: For merging large numbers of files (more than 10?) a
1119      better algorithm would use a heap for finding minimum
1120      values. */
1121
1122   if (!used_active_file)
1123     discard_variables ();
1124
1125   dict_compact_values (mtf.dict);
1126   mtf.sink = create_case_sink (&storage_sink_class, mtf.dict, NULL);
1127   if (mtf.sink->class->open != NULL)
1128     mtf.sink->class->open (mtf.sink);
1129
1130   mtf.seq_nums = xcalloc (dict_get_var_cnt (mtf.dict), sizeof *mtf.seq_nums);
1131   case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));
1132
1133   if (!mtf_read_nonactive_records (&mtf))
1134     goto error;
1135
1136   if (used_active_file) 
1137     ok = procedure (mtf_processing, &mtf) && mtf_processing_finish (&mtf);
1138   else
1139     ok = mtf_processing_finish (&mtf);
1140
1141   free_case_source (vfm_source);
1142   vfm_source = NULL;
1143
1144   dict_destroy (default_dict);
1145   default_dict = mtf.dict;
1146   mtf.dict = NULL;
1147   vfm_source = mtf.sink->class->make_source (mtf.sink);
1148   free_case_sink (mtf.sink);
1149   
1150   if (!mtf_free (&mtf))
1151     ok = false;
1152   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
1153   
1154  error:
1155   mtf_free (&mtf);
1156   return CMD_CASCADING_FAILURE;
1157 }
1158
1159 /* Repeats 2...7 an arbitrary number of times. */
1160 static bool
1161 mtf_processing_finish (void *mtf_)
1162 {
1163   struct mtf_proc *mtf = mtf_;
1164   struct mtf_file *iter;
1165
1166   /* Find the active file and delete it. */
1167   for (iter = mtf->head; iter; iter = iter->next)
1168     if (iter->handle == NULL)
1169       {
1170         if (!mtf_delete_file_in_place (mtf, &iter))
1171           abort ();
1172         break;
1173       }
1174   
1175   while (mtf->head && mtf->head->type == MTF_FILE)
1176     if (!mtf_processing (NULL, mtf))
1177       return false;
1178
1179   return true;
1180 }
1181
1182 /* Return a string in a static buffer describing V's variable type and
1183    width. */
1184 static char *
1185 var_type_description (struct variable *v)
1186 {
1187   static char buf[2][32];
1188   static int x = 0;
1189   char *s;
1190
1191   x ^= 1;
1192   s = buf[x];
1193
1194   if (v->type == NUMERIC)
1195     strcpy (s, "numeric");
1196   else
1197     {
1198       assert (v->type == ALPHA);
1199       sprintf (s, "string with width %d", v->width);
1200     }
1201   return s;
1202 }
1203
1204 /* Closes FILE and frees its associated data.
1205    Returns true if successful, false if an I/O error
1206    occurred on FILE. */
1207 static bool
1208 mtf_close_file (struct mtf_file *file)
1209 {
1210   bool ok = file->reader == NULL || !any_reader_error (file->reader);
1211   free (file->by);
1212   any_reader_close (file->reader);
1213   if (file->handle != NULL)
1214     dict_destroy (file->dict);
1215   case_destroy (&file->input);
1216   free (file->in_name);
1217   free (file);
1218   return ok;
1219 }
1220
1221 /* Free all the data for the MATCH FILES procedure.
1222    Returns true if successful, false if an I/O error
1223    occurred. */
1224 static bool
1225 mtf_free (struct mtf_proc *mtf)
1226 {
1227   struct mtf_file *iter, *next;
1228   bool ok = true;
1229
1230   for (iter = mtf->head; iter; iter = next)
1231     {
1232       next = iter->next;
1233       assert (iter->dict != mtf->dict);
1234       if (!mtf_close_file (iter))
1235         ok = false;
1236     }
1237   
1238   if (mtf->dict)
1239     dict_destroy (mtf->dict);
1240   case_destroy (&mtf->mtf_case);
1241   free (mtf->seq_nums);
1242
1243   return ok;
1244 }
1245
1246 /* Remove *FILE from the mtf_file chain.  Make *FILE point to the next
1247    file in the chain, or to NULL if was the last in the chain.
1248    Returns true if successful, false if an I/O error occurred. */
1249 static bool
1250 mtf_delete_file_in_place (struct mtf_proc *mtf, struct mtf_file **file)
1251 {
1252   struct mtf_file *f = *file;
1253   int i;
1254
1255   if (f->prev)
1256     f->prev->next = f->next;
1257   if (f->next)
1258     f->next->prev = f->prev;
1259   if (f == mtf->head)
1260     mtf->head = f->next;
1261   if (f == mtf->tail)
1262     mtf->tail = f->prev;
1263   *file = f->next;
1264
1265   if (f->in_var != NULL)
1266     case_data_rw (&mtf->mtf_case, f->in_var->fv)->f = 0.;
1267   for (i = 0; i < dict_get_var_cnt (f->dict); i++)
1268     {
1269       struct variable *v = dict_get_var (f->dict, i);
1270       struct variable *mv = get_master (v);
1271       if (mv != NULL) 
1272         {
1273           union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1274           
1275           if (v->type == NUMERIC)
1276             out->f = SYSMIS;
1277           else
1278             memset (out->s, ' ', v->width);
1279         } 
1280     }
1281
1282   return mtf_close_file (f);
1283 }
1284
1285 /* Read a record from every input file except the active file.
1286    Returns true if successful, false if an I/O error occurred. */
1287 static bool
1288 mtf_read_nonactive_records (void *mtf_)
1289 {
1290   struct mtf_proc *mtf = mtf_;
1291   struct mtf_file *iter, *next;
1292   bool ok = true;
1293
1294   for (iter = mtf->head; ok && iter != NULL; iter = next)
1295     {
1296       next = iter->next;
1297       if (iter->handle && !any_reader_read (iter->reader, &iter->input)) 
1298         if (!mtf_delete_file_in_place (mtf, &iter))
1299           ok = false;
1300     }
1301   return ok;
1302 }
1303
1304 /* Compare the BY variables for files A and B; return -1 if A < B, 0
1305    if A == B, 1 if A > B. */
1306 static inline int
1307 mtf_compare_BY_values (struct mtf_proc *mtf,
1308                        struct mtf_file *a, struct mtf_file *b,
1309                        struct ccase *c)
1310 {
1311   struct ccase *ca = case_is_null (&a->input) ? c : &a->input;
1312   struct ccase *cb = case_is_null (&b->input) ? c : &b->input;
1313   assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
1314   return case_compare_2dict (ca, cb, a->by, b->by, mtf->by_cnt);
1315 }
1316
1317 /* Perform one iteration of steps 3...7 above.
1318    Returns true if successful, false if an I/O error occurred. */
1319 static bool
1320 mtf_processing (struct ccase *c, void *mtf_)
1321 {
1322   struct mtf_proc *mtf = mtf_;
1323
1324   /* Do we need another record from the active file? */
1325   bool read_active_file;
1326
1327   assert (mtf->head != NULL);
1328   if (mtf->head->type == MTF_TABLE)
1329     return true;
1330   
1331   do
1332     {
1333       struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
1334       struct mtf_file *max_head, *max_tail; /* Files with non-minimum BYs. */
1335       struct mtf_file *iter, *next;
1336
1337       read_active_file = false;
1338       
1339       /* 3. Find the FILE input record(s) that have minimum BY
1340          values.  Store all the values from these input records into
1341          the output record. */
1342       min_head = min_tail = mtf->head;
1343       max_head = max_tail = NULL;
1344       for (iter = mtf->head->next; iter && iter->type == MTF_FILE;
1345            iter = iter->next) 
1346         {
1347           int cmp = mtf_compare_BY_values (mtf, min_head, iter, c);
1348           if (cmp < 0) 
1349             {
1350               if (max_head)
1351                 max_tail = max_tail->next_min = iter;
1352               else
1353                 max_head = max_tail = iter;
1354             }
1355           else if (cmp == 0) 
1356             min_tail = min_tail->next_min = iter;
1357           else /* cmp > 0 */
1358             {
1359               if (max_head)
1360                 {
1361                   max_tail->next_min = min_head;
1362                   max_tail = min_tail;
1363                 }
1364               else
1365                 {
1366                   max_head = min_head;
1367                   max_tail = min_tail;
1368                 }
1369               min_head = min_tail = iter;
1370             }
1371         }
1372       
1373       /* 4. For every TABLE, read another record as long as the BY
1374          values on the TABLE's input record are less than the FILEs'
1375          BY values.  If an exact match is found, store all the values
1376          from the TABLE input record into the output record. */
1377       for (; iter != NULL; iter = next)
1378         {
1379           assert (iter->type == MTF_TABLE);
1380       
1381           next = iter->next;
1382           for (;;) 
1383             {
1384               int cmp = mtf_compare_BY_values (mtf, min_head, iter, c);
1385               if (cmp < 0) 
1386                 {
1387                   if (max_head)
1388                     max_tail = max_tail->next_min = iter;
1389                   else
1390                     max_head = max_tail = iter;
1391                 }
1392               else if (cmp == 0)
1393                 min_tail = min_tail->next_min = iter;
1394               else /* cmp > 0 */
1395                 {
1396                   if (iter->handle == NULL)
1397                     return true;
1398                   if (any_reader_read (iter->reader, &iter->input))
1399                     continue;
1400                   if (!mtf_delete_file_in_place (mtf, &iter))
1401                     return false;
1402                 }
1403               break;
1404             }
1405         }
1406
1407       /* Next sequence number. */
1408       mtf->seq_num++;
1409
1410       /* Store data to all the records we are using. */
1411       if (min_tail)
1412         min_tail->next_min = NULL;
1413       for (iter = min_head; iter; iter = iter->next_min)
1414         {
1415           int i;
1416
1417           for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1418             {
1419               struct variable *v = dict_get_var (iter->dict, i);
1420               struct variable *mv = get_master (v);
1421           
1422               if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
1423                 {
1424                   struct ccase *record
1425                     = case_is_null (&iter->input) ? c : &iter->input;
1426                   union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1427
1428                   mtf->seq_nums[mv->index] = mtf->seq_num;
1429                   if (v->type == NUMERIC)
1430                     out->f = case_num (record, v->fv);
1431                   else
1432                     memcpy (out->s, case_str (record, v->fv), v->width);
1433                 } 
1434             }
1435           if (iter->in_var != NULL)
1436             case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 1.;
1437
1438           if (iter->type == MTF_FILE && iter->handle == NULL)
1439             read_active_file = true;
1440         }
1441
1442       /* Store missing values to all the records we're not
1443          using. */
1444       if (max_tail)
1445         max_tail->next_min = NULL;
1446       for (iter = max_head; iter; iter = iter->next_min)
1447         {
1448           int i;
1449
1450           for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1451             {
1452               struct variable *v = dict_get_var (iter->dict, i);
1453               struct variable *mv = get_master (v);
1454
1455               if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
1456                 {
1457                   union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1458                   mtf->seq_nums[mv->index] = mtf->seq_num;
1459
1460                   if (v->type == NUMERIC)
1461                     out->f = SYSMIS;
1462                   else
1463                     memset (out->s, ' ', v->width);
1464                 }
1465             }
1466           if (iter->in_var != NULL)
1467             case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 0.;
1468         }
1469
1470       /* 5. Write the output record. */
1471       mtf->sink->class->write (mtf->sink, &mtf->mtf_case);
1472
1473       /* 6. Read another record from each input file FILE and TABLE
1474          that we stored values from above.  If we come to the end of
1475          one of the input files, remove it from the list of input
1476          files. */
1477       for (iter = min_head; iter && iter->type == MTF_FILE; iter = next)
1478         {
1479           next = iter->next_min;
1480           if (iter->reader != NULL
1481               && !any_reader_read (iter->reader, &iter->input))
1482             if (!mtf_delete_file_in_place (mtf, &iter))
1483               return false;
1484         }
1485     }
1486   while (!read_active_file
1487          && mtf->head != NULL && mtf->head->type == MTF_FILE);
1488
1489   return true;
1490 }
1491
1492 /* Merge the dictionary for file F into master dictionary M. */
1493 static int
1494 mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f)
1495 {
1496   struct dictionary *d = f->dict;
1497   const char *d_docs, *m_docs;
1498   int i;
1499
1500   if (dict_get_label (m) == NULL)
1501     dict_set_label (m, dict_get_label (d));
1502
1503   d_docs = dict_get_documents (d);
1504   m_docs = dict_get_documents (m);
1505   if (d_docs != NULL) 
1506     {
1507       if (m_docs == NULL)
1508         dict_set_documents (m, d_docs);
1509       else
1510         {
1511           char *new_docs;
1512           size_t new_len;
1513
1514           new_len = strlen (m_docs) + strlen (d_docs);
1515           new_docs = xmalloc (new_len + 1);
1516           strcpy (new_docs, m_docs);
1517           strcat (new_docs, d_docs);
1518           dict_set_documents (m, new_docs);
1519           free (new_docs);
1520         }
1521     }
1522   
1523   for (i = 0; i < dict_get_var_cnt (d); i++)
1524     {
1525       struct variable *dv = dict_get_var (d, i);
1526       struct variable *mv = dict_lookup_var (m, dv->name);
1527
1528       if (dict_class_from_id (dv->name) == DC_SCRATCH)
1529         continue;
1530
1531       if (mv != NULL)
1532         {
1533           if (mv->width != dv->width) 
1534             {
1535               msg (SE, _("Variable %s in file %s (%s) has different "
1536                          "type or width from the same variable in "
1537                          "earlier file (%s)."),
1538                    dv->name, fh_get_name (f->handle),
1539                    var_type_description (dv), var_type_description (mv));
1540               return 0;
1541             }
1542         
1543           if (dv->width == mv->width)
1544             {
1545               if (val_labs_count (dv->val_labs)
1546                   && !val_labs_count (mv->val_labs))
1547                 mv->val_labs = val_labs_copy (dv->val_labs);
1548               if (!mv_is_empty (&dv->miss) && mv_is_empty (&mv->miss))
1549                 mv_copy (&mv->miss, &dv->miss);
1550             }
1551
1552           if (dv->label && !mv->label)
1553             mv->label = xstrdup (dv->label);
1554         }
1555       else
1556         mv = dict_clone_var_assert (m, dv, dv->name);
1557     }
1558
1559   return 1;
1560 }
1561
1562 /* Marks V's master variable as MASTER. */
1563 static void
1564 set_master (struct variable *v, struct variable *master) 
1565 {
1566   var_attach_aux (v, master, NULL);
1567 }
1568
1569 /* Returns the master variable corresponding to V,
1570    as set with set_master(). */
1571 static struct variable *
1572 get_master (struct variable *v) 
1573 {
1574   return v->aux;
1575 }
1576 \f
1577
1578 \f
1579 /* Case map.
1580
1581    A case map copies data from a case that corresponds for one
1582    dictionary to a case that corresponds to a second dictionary
1583    derived from the first by, optionally, deleting, reordering,
1584    or renaming variables.  (No new variables may be created.)
1585    */
1586
1587 /* A case map. */
1588 struct case_map
1589   {
1590     size_t value_cnt;   /* Number of values in map. */
1591     int *map;           /* For each destination index, the
1592                            corresponding source index. */
1593   };
1594
1595 /* Prepares dictionary D for producing a case map.  Afterward,
1596    the caller may delete, reorder, or rename variables within D
1597    at will before using finish_case_map() to produce the case
1598    map.
1599
1600    Uses D's aux members, which must otherwise not be in use. */
1601 static void
1602 start_case_map (struct dictionary *d) 
1603 {
1604   size_t var_cnt = dict_get_var_cnt (d);
1605   size_t i;
1606   
1607   for (i = 0; i < var_cnt; i++)
1608     {
1609       struct variable *v = dict_get_var (d, i);
1610       int *src_fv = xmalloc (sizeof *src_fv);
1611       *src_fv = v->fv;
1612       var_attach_aux (v, src_fv, var_dtor_free);
1613     }
1614 }
1615
1616 /* Produces a case map from dictionary D, which must have been
1617    previously prepared with start_case_map().
1618
1619    Does not retain any reference to D, and clears the aux members
1620    set up by start_case_map().
1621
1622    Returns the new case map, or a null pointer if no mapping is
1623    required (that is, no data has changed position). */
1624 static struct case_map *
1625 finish_case_map (struct dictionary *d) 
1626 {
1627   struct case_map *map;
1628   size_t var_cnt = dict_get_var_cnt (d);
1629   size_t i;
1630   int identity_map;
1631
1632   map = xmalloc (sizeof *map);
1633   map->value_cnt = dict_get_next_value_idx (d);
1634   map->map = xnmalloc (map->value_cnt, sizeof *map->map);
1635   for (i = 0; i < map->value_cnt; i++)
1636     map->map[i] = -1;
1637
1638   identity_map = 1;
1639   for (i = 0; i < var_cnt; i++) 
1640     {
1641       struct variable *v = dict_get_var (d, i);
1642       int *src_fv = (int *) var_detach_aux (v);
1643       size_t idx;
1644
1645       if (v->fv != *src_fv)
1646         identity_map = 0;
1647       
1648       for (idx = 0; idx < v->nv; idx++)
1649         {
1650           int src_idx = *src_fv + idx;
1651           int dst_idx = v->fv + idx;
1652           
1653           assert (map->map[dst_idx] == -1);
1654           map->map[dst_idx] = src_idx;
1655         }
1656       free (src_fv);
1657     }
1658
1659   if (identity_map) 
1660     {
1661       destroy_case_map (map);
1662       return NULL;
1663     }
1664
1665   while (map->value_cnt > 0 && map->map[map->value_cnt - 1] == -1)
1666     map->value_cnt--;
1667
1668   return map;
1669 }
1670
1671 /* Maps from SRC to DST, applying case map MAP. */
1672 static void
1673 map_case (const struct case_map *map,
1674           const struct ccase *src, struct ccase *dst) 
1675 {
1676   size_t dst_idx;
1677
1678   assert (map != NULL);
1679   assert (src != NULL);
1680   assert (dst != NULL);
1681   assert (src != dst);
1682
1683   for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++)
1684     {
1685       int src_idx = map->map[dst_idx];
1686       if (src_idx != -1)
1687         *case_data_rw (dst, dst_idx) = *case_data (src, src_idx);
1688     }
1689 }
1690
1691 /* Destroys case map MAP. */
1692 static void
1693 destroy_case_map (struct case_map *map) 
1694 {
1695   if (map != NULL) 
1696     {
1697       free (map->map);
1698       free (map);
1699     }
1700 }