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