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