Move var_set and variable parsing declarations into new header.
[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   dict_destroy (dict);
444   
445   return aw;
446
447  error:
448   case_writer_destroy (aw);
449   dict_destroy (dict);
450   return NULL;
451 }
452
453 /* Writes case C to writer AW. */
454 static bool
455 case_writer_write_case (struct case_writer *aw, const struct ccase *c) 
456 {
457   if (aw->map != NULL) 
458     {
459       map_case (aw->map, c, &aw->bounce);
460       c = &aw->bounce; 
461     }
462   return any_writer_write (aw->writer, c);
463 }
464 \f
465 /* SAVE and EXPORT. */
466
467 static bool output_proc (const struct ccase *, void *);
468
469 /* Parses and performs the SAVE or EXPORT procedure. */
470 static int
471 parse_output_proc (enum writer_type writer_type)
472 {
473   bool retain_unselected;
474   struct variable *saved_filter_variable;
475   struct case_writer *aw;
476   bool ok;
477
478   aw = parse_write_command (writer_type, PROC_CMD, &retain_unselected);
479   if (aw == NULL) 
480     return CMD_CASCADING_FAILURE;
481
482   saved_filter_variable = dict_get_filter (default_dict);
483   if (retain_unselected) 
484     dict_set_filter (default_dict, NULL);
485   ok = procedure (output_proc, aw);
486   dict_set_filter (default_dict, saved_filter_variable);
487
488   case_writer_destroy (aw);
489   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
490 }
491
492 /* Writes case C to file. */
493 static bool
494 output_proc (const struct ccase *c, void *aw_) 
495 {
496   struct case_writer *aw = aw_;
497   return case_writer_write_case (aw, c);
498 }
499
500 int
501 cmd_save (void) 
502 {
503   return parse_output_proc (SYSFILE_WRITER);
504 }
505
506 int
507 cmd_export (void) 
508 {
509   return parse_output_proc (PORFILE_WRITER);
510 }
511 \f
512 /* XSAVE and XEXPORT. */
513
514 /* Transformation. */
515 struct output_trns 
516   {
517     struct case_writer *aw;      /* Writer. */
518   };
519
520 static trns_proc_func output_trns_proc;
521 static trns_free_func output_trns_free;
522
523 /* Parses the XSAVE or XEXPORT transformation command. */
524 static int
525 parse_output_trns (enum writer_type writer_type) 
526 {
527   struct output_trns *t = xmalloc (sizeof *t);
528   t->aw = parse_write_command (writer_type, XFORM_CMD, NULL);
529   if (t->aw == NULL) 
530     {
531       free (t);
532       return CMD_CASCADING_FAILURE;
533     }
534
535   add_transformation (output_trns_proc, output_trns_free, t);
536   return CMD_SUCCESS;
537 }
538
539 /* Writes case C to the system file specified on XSAVE or XEXPORT. */
540 static int
541 output_trns_proc (void *trns_, struct ccase *c, int case_num UNUSED)
542 {
543   struct output_trns *t = trns_;
544   case_writer_write_case (t->aw, c);
545   return TRNS_CONTINUE;
546 }
547
548 /* Frees an XSAVE or XEXPORT transformation.
549    Returns true if successful, false if an I/O error occurred. */
550 static bool
551 output_trns_free (void *trns_)
552 {
553   struct output_trns *t = trns_;
554   bool ok = true;
555
556   if (t != NULL)
557     {
558       ok = case_writer_destroy (t->aw);
559       free (t);
560     }
561   return ok;
562 }
563
564 /* XSAVE command. */
565 int
566 cmd_xsave (void) 
567 {
568   return parse_output_trns (SYSFILE_WRITER);
569 }
570
571 /* XEXPORT command. */
572 int
573 cmd_xexport (void) 
574 {
575   return parse_output_trns (PORFILE_WRITER);
576 }
577 \f
578 static bool rename_variables (struct dictionary *dict);
579 static bool drop_variables (struct dictionary *dict);
580 static bool keep_variables (struct dictionary *dict);
581
582 /* Commands that read and write system files share a great deal
583    of common syntactic structure for rearranging and dropping
584    variables.  This function parses this syntax and modifies DICT
585    appropriately.  Returns true on success, false on failure. */
586 static bool
587 parse_dict_trim (struct dictionary *dict)
588 {
589   if (lex_match_id ("MAP")) 
590     {
591       /* FIXME. */
592       return true;
593     }
594   else if (lex_match_id ("DROP"))
595     return drop_variables (dict);
596   else if (lex_match_id ("KEEP"))
597     return keep_variables (dict);
598   else if (lex_match_id ("RENAME"))
599     return rename_variables (dict);
600   else
601     {
602       lex_error (_("expecting a valid subcommand"));
603       return false;
604     }
605 }
606
607 /* Parses and performs the RENAME subcommand of GET and SAVE. */
608 static bool
609 rename_variables (struct dictionary *dict)
610 {
611   size_t i;
612
613   int success = 0;
614
615   struct variable **v;
616   char **new_names;
617   size_t nv, nn;
618   char *err_name;
619
620   int group;
621
622   lex_match ('=');
623   if (token != '(')
624     {
625       struct variable *v;
626
627       v = parse_dict_variable (dict);
628       if (v == NULL)
629         return 0;
630       if (!lex_force_match ('=')
631           || !lex_force_id ())
632         return 0;
633       if (dict_lookup_var (dict, tokid) != NULL)
634         {
635           msg (SE, _("Cannot rename %s as %s because there already exists "
636                      "a variable named %s.  To rename variables with "
637                      "overlapping names, use a single RENAME subcommand "
638                      "such as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, "
639                      "\"/RENAME (A B C=B C A)\"."), v->name, tokid, tokid);
640           return 0;
641         }
642       
643       dict_rename_var (dict, v, tokid);
644       lex_get ();
645       return 1;
646     }
647
648   nv = nn = 0;
649   v = NULL;
650   new_names = 0;
651   group = 1;
652   while (lex_match ('('))
653     {
654       size_t old_nv = nv;
655
656       if (!parse_variables (dict, &v, &nv, PV_NO_DUPLICATE | PV_APPEND))
657         goto done;
658       if (!lex_match ('='))
659         {
660           msg (SE, _("`=' expected after variable list."));
661           goto done;
662         }
663       if (!parse_DATA_LIST_vars (&new_names, &nn, PV_APPEND | PV_NO_SCRATCH))
664         goto done;
665       if (nn != nv)
666         {
667           msg (SE, _("Number of variables on left side of `=' (%d) does not "
668                      "match number of variables on right side (%d), in "
669                      "parenthesized group %d of RENAME subcommand."),
670                (unsigned) (nv - old_nv), (unsigned) (nn - old_nv), group);
671           goto done;
672         }
673       if (!lex_force_match (')'))
674         goto done;
675       group++;
676     }
677
678   if (!dict_rename_vars (dict, v, new_names, nv, &err_name)) 
679     {
680       msg (SE, _("Requested renaming duplicates variable name %s."), err_name);
681       goto done;
682     }
683   success = 1;
684
685  done:
686   for (i = 0; i < nn; i++)
687     free (new_names[i]);
688   free (new_names);
689   free (v);
690
691   return success;
692 }
693
694 /* Parses and performs the DROP subcommand of GET and SAVE.
695    Returns true if successful, false on failure.*/
696 static bool
697 drop_variables (struct dictionary *dict)
698 {
699   struct variable **v;
700   size_t nv;
701
702   lex_match ('=');
703   if (!parse_variables (dict, &v, &nv, PV_NONE))
704     return false;
705   dict_delete_vars (dict, v, nv);
706   free (v);
707
708   if (dict_get_var_cnt (dict) == 0)
709     {
710       msg (SE, _("Cannot DROP all variables from dictionary."));
711       return false;
712     }
713   return true;
714 }
715
716 /* Parses and performs the KEEP subcommand of GET and SAVE.
717    Returns true if successful, false on failure.*/
718 static bool
719 keep_variables (struct dictionary *dict)
720 {
721   struct variable **v;
722   size_t nv;
723   size_t i;
724
725   lex_match ('=');
726   if (!parse_variables (dict, &v, &nv, PV_NONE))
727     return false;
728
729   /* Move the specified variables to the beginning. */
730   dict_reorder_vars (dict, v, nv);
731           
732   /* Delete the remaining variables. */
733   v = xnrealloc (v, dict_get_var_cnt (dict) - nv, sizeof *v);
734   for (i = nv; i < dict_get_var_cnt (dict); i++)
735     v[i - nv] = dict_get_var (dict, i);
736   dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);
737   free (v);
738
739   return true;
740 }
741 \f
742 /* MATCH FILES. */
743
744 /* File types. */
745 enum
746   {
747     MTF_FILE,                   /* Specified on FILE= subcommand. */
748     MTF_TABLE                   /* Specified on TABLE= subcommand. */
749   };
750
751 /* One of the files on MATCH FILES. */
752 struct mtf_file
753   {
754     struct mtf_file *next, *prev; /* Next, previous in the list of files. */
755     struct mtf_file *next_min;  /* Next in the chain of minimums. */
756     
757     int type;                   /* One of MTF_*. */
758     struct variable **by;       /* List of BY variables for this file. */
759     struct file_handle *handle; /* File handle. */
760     struct any_reader *reader;  /* File reader. */
761     struct dictionary *dict;    /* Dictionary from system file. */
762
763     /* IN subcommand. */
764     char *in_name;              /* Variable name. */
765     struct variable *in_var;    /* Variable (in master dictionary). */
766
767     struct ccase input;         /* Input record. */
768   };
769
770 /* MATCH FILES procedure. */
771 struct mtf_proc 
772   {
773     struct mtf_file *head;      /* First file mentioned on FILE or TABLE. */
774     struct mtf_file *tail;      /* Last file mentioned on FILE or TABLE. */
775
776     bool ok;                    /* False if I/O error occurs. */
777
778     size_t by_cnt;              /* Number of variables on BY subcommand. */
779
780     /* Names of FIRST, LAST variables. */
781     char first[LONG_NAME_LEN + 1], last[LONG_NAME_LEN + 1];
782     
783     struct dictionary *dict;    /* Dictionary of output file. */
784     struct casefile *output;    /* MATCH FILES output. */
785     struct ccase mtf_case;      /* Case used for output. */
786
787     unsigned seq_num;           /* Have we initialized this variable? */
788     unsigned *seq_nums;         /* Sequence numbers for each var in dict. */
789   };
790
791 static bool mtf_free (struct mtf_proc *);
792 static bool mtf_close_file (struct mtf_file *);
793 static int mtf_merge_dictionary (struct dictionary *const, struct mtf_file *);
794 static bool mtf_delete_file_in_place (struct mtf_proc *, struct mtf_file **);
795
796 static bool mtf_read_nonactive_records (void *);
797 static bool mtf_processing_finish (void *);
798 static bool mtf_processing (const struct ccase *, void *);
799
800 static char *var_type_description (struct variable *);
801
802 static void set_master (struct variable *, struct variable *master);
803 static struct variable *get_master (struct variable *);
804
805 /* Parse and execute the MATCH FILES command. */
806 int
807 cmd_match_files (void)
808 {
809   struct mtf_proc mtf;
810   struct mtf_file *first_table = NULL;
811   struct mtf_file *iter;
812   
813   bool used_active_file = false;
814   bool saw_table = false;
815   bool saw_in = false;
816
817   bool ok;
818   
819   mtf.head = mtf.tail = NULL;
820   mtf.by_cnt = 0;
821   mtf.first[0] = '\0';
822   mtf.last[0] = '\0';
823   mtf.dict = dict_create ();
824   mtf.output = NULL;
825   case_nullify (&mtf.mtf_case);
826   mtf.seq_num = 0;
827   mtf.seq_nums = NULL;
828   dict_set_case_limit (mtf.dict, dict_get_case_limit (default_dict));
829
830   lex_match ('/');
831   while (token == T_ID
832          && (lex_id_match ("FILE", tokid) || lex_id_match ("TABLE", tokid)))
833     {
834       struct mtf_file *file = xmalloc (sizeof *file);
835
836       if (lex_match_id ("FILE"))
837         file->type = MTF_FILE;
838       else if (lex_match_id ("TABLE"))
839         {
840           file->type = MTF_TABLE;
841           saw_table = true;
842         }
843       else
844         assert (0);
845       lex_match ('=');
846
847       file->by = NULL;
848       file->handle = NULL;
849       file->reader = NULL;
850       file->dict = NULL;
851       file->in_name = NULL;
852       file->in_var = NULL;
853       case_nullify (&file->input);
854
855       /* FILEs go first, then TABLEs. */
856       if (file->type == MTF_TABLE || first_table == NULL)
857         {
858           file->next = NULL;
859           file->prev = mtf.tail;
860           if (mtf.tail)
861             mtf.tail->next = file;
862           mtf.tail = file;
863           if (mtf.head == NULL)
864             mtf.head = file;
865           if (file->type == MTF_TABLE && first_table == NULL)
866             first_table = file;
867         }
868       else 
869         {
870           assert (file->type == MTF_FILE);
871           file->next = first_table;
872           file->prev = first_table->prev;
873           if (first_table->prev)
874             first_table->prev->next = file;
875           else
876             mtf.head = file;
877           first_table->prev = file;
878         }
879
880       if (lex_match ('*'))
881         {
882           file->handle = NULL;
883           file->reader = NULL;
884               
885           if (used_active_file)
886             {
887               msg (SE, _("The active file may not be specified more "
888                          "than once."));
889               goto error;
890             }
891           used_active_file = true;
892
893           if (!proc_has_source ())
894             {
895               msg (SE, _("Cannot specify the active file since no active "
896                          "file has been defined."));
897               goto error;
898             }
899
900           if (proc_make_temporary_transformations_permanent ())
901             msg (SE,
902                  _("MATCH FILES may not be used after TEMPORARY when "
903                    "the active file is an input source.  "
904                    "Temporary transformations will be made permanent."));
905
906           file->dict = default_dict;
907         }
908       else
909         {
910           file->handle = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
911           if (file->handle == NULL)
912             goto error;
913
914           file->reader = any_reader_open (file->handle, &file->dict);
915           if (file->reader == NULL)
916             goto error;
917
918           case_create (&file->input, dict_get_next_value_idx (file->dict));
919         }
920
921       while (lex_match ('/'))
922         if (lex_match_id ("RENAME")) 
923           {
924             if (!rename_variables (file->dict))
925               goto error; 
926           }
927         else if (lex_match_id ("IN"))
928           {
929             lex_match ('=');
930             if (token != T_ID)
931               {
932                 lex_error (NULL);
933                 goto error;
934               }
935
936             if (file->in_name != NULL)
937               {
938                 msg (SE, _("Multiple IN subcommands for a single FILE or "
939                            "TABLE."));
940                 goto error;
941               }
942             file->in_name = xstrdup (tokid);
943             lex_get ();
944             saw_in = true;
945           }
946
947       mtf_merge_dictionary (mtf.dict, file);
948     }
949   
950   while (token != '.')
951     {
952       if (lex_match (T_BY))
953         {
954           struct variable **by;
955           
956           if (mtf.by_cnt)
957             {
958               msg (SE, _("BY may appear at most once."));
959               goto error;
960             }
961               
962           lex_match ('=');
963           if (!parse_variables (mtf.dict, &by, &mtf.by_cnt,
964                                 PV_NO_DUPLICATE | PV_NO_SCRATCH))
965             goto error;
966
967           for (iter = mtf.head; iter != NULL; iter = iter->next)
968             {
969               size_t i;
970           
971               iter->by = xnmalloc (mtf.by_cnt, sizeof *iter->by);
972
973               for (i = 0; i < mtf.by_cnt; i++)
974                 {
975                   iter->by[i] = dict_lookup_var (iter->dict, by[i]->name);
976                   if (iter->by[i] == NULL)
977                     {
978                       msg (SE, _("File %s lacks BY variable %s."),
979                            iter->handle ? fh_get_name (iter->handle) : "*",
980                            by[i]->name);
981                       free (by);
982                       goto error;
983                     }
984                 }
985             }
986           free (by);
987         }
988       else if (lex_match_id ("FIRST")) 
989         {
990           if (mtf.first[0] != '\0')
991             {
992               msg (SE, _("FIRST may appear at most once."));
993               goto error;
994             }
995               
996           lex_match ('=');
997           if (!lex_force_id ())
998             goto error;
999           strcpy (mtf.first, tokid);
1000           lex_get ();
1001         }
1002       else if (lex_match_id ("LAST")) 
1003         {
1004           if (mtf.last[0] != '\0')
1005             {
1006               msg (SE, _("LAST may appear at most once."));
1007               goto error;
1008             }
1009               
1010           lex_match ('=');
1011           if (!lex_force_id ())
1012             goto error;
1013           strcpy (mtf.last, tokid);
1014           lex_get ();
1015         }
1016       else if (lex_match_id ("MAP"))
1017         {
1018           /* FIXME. */
1019         }
1020       else if (lex_match_id ("DROP")) 
1021         {
1022           if (!drop_variables (mtf.dict))
1023             goto error;
1024         }
1025       else if (lex_match_id ("KEEP")) 
1026         {
1027           if (!keep_variables (mtf.dict))
1028             goto error;
1029         }
1030       else
1031         {
1032           lex_error (NULL);
1033           goto error;
1034         }
1035
1036       if (!lex_match ('/') && token != '.') 
1037         {
1038           lex_end_of_command ();
1039           goto error;
1040         }
1041     }
1042
1043   if (mtf.by_cnt == 0)
1044     {
1045       if (saw_table)
1046         {
1047           msg (SE, _("BY is required when TABLE is specified."));
1048           goto error;
1049         }
1050       if (saw_in)
1051         {
1052           msg (SE, _("BY is required when IN is specified."));
1053           goto error;
1054         }
1055     }
1056
1057   /* Set up mapping from each file's variables to master
1058      variables. */
1059   for (iter = mtf.head; iter != NULL; iter = iter->next)
1060     {
1061       struct dictionary *d = iter->dict;
1062       int i;
1063
1064       for (i = 0; i < dict_get_var_cnt (d); i++)
1065         {
1066           struct variable *v = dict_get_var (d, i);
1067           struct variable *mv = dict_lookup_var (mtf.dict, v->name);
1068           if (mv != NULL)
1069             set_master (v, mv);
1070         }
1071     }
1072
1073   /* Add IN variables to master dictionary. */
1074   for (iter = mtf.head; iter != NULL; iter = iter->next) 
1075     if (iter->in_name != NULL)
1076       {
1077         iter->in_var = dict_create_var (mtf.dict, iter->in_name, 0);
1078         if (iter->in_var == NULL)
1079           {
1080             msg (SE, _("IN variable name %s duplicates an "
1081                        "existing variable name."),
1082                  iter->in_var->name);
1083             goto error;
1084           }
1085         iter->in_var->print = iter->in_var->write
1086           = make_output_format (FMT_F, 1, 0);
1087       }
1088     
1089   /* MATCH FILES performs an n-way merge on all its input files.
1090      Abstract algorithm:
1091
1092      1. Read one input record from every input FILE.
1093
1094      2. If no FILEs are left, stop.  Otherwise, proceed to step 3.
1095
1096      3. Find the FILE input record(s) that have minimum BY
1097      values.  Store all the values from these input records into
1098      the output record.
1099
1100      4. For every TABLE, read another record as long as the BY values
1101      on the TABLE's input record are less than the FILEs' BY values.
1102      If an exact match is found, store all the values from the TABLE
1103      input record into the output record.
1104
1105      5. Write the output record.
1106
1107      6. Read another record from each input file FILE and TABLE that
1108      we stored values from above.  If we come to the end of one of the
1109      input files, remove it from the list of input files.
1110
1111      7. Repeat from step 2.
1112
1113      Unfortunately, this algorithm can't be implemented in a
1114      straightforward way because there's no function to read a
1115      record from the active file.  Instead, it has to be written
1116      as a state machine.
1117
1118      FIXME: For merging large numbers of files (more than 10?) a
1119      better algorithm would use a heap for finding minimum
1120      values. */
1121
1122   if (!used_active_file)
1123     discard_variables ();
1124
1125   dict_compact_values (mtf.dict);
1126   mtf.output = casefile_create (dict_get_next_value_idx (mtf.dict));
1127   mtf.seq_nums = xcalloc (dict_get_var_cnt (mtf.dict), sizeof *mtf.seq_nums);
1128   case_create (&mtf.mtf_case, dict_get_next_value_idx (mtf.dict));
1129
1130   if (!mtf_read_nonactive_records (&mtf))
1131     goto error;
1132
1133   if (used_active_file) 
1134     {
1135       proc_set_sink (create_case_sink (&null_sink_class, default_dict, NULL));
1136       ok = procedure (mtf_processing, &mtf) && mtf_processing_finish (&mtf); 
1137     }
1138   else
1139     ok = mtf_processing_finish (&mtf);
1140
1141   discard_variables ();
1142
1143   dict_destroy (default_dict);
1144   default_dict = mtf.dict;
1145   mtf.dict = NULL;
1146   proc_set_source (storage_source_create (mtf.output));
1147   mtf.output = NULL;
1148   
1149   if (!mtf_free (&mtf))
1150     ok = false;
1151   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
1152   
1153  error:
1154   mtf_free (&mtf);
1155   return CMD_CASCADING_FAILURE;
1156 }
1157
1158 /* Repeats 2...7 an arbitrary number of times. */
1159 static bool
1160 mtf_processing_finish (void *mtf_)
1161 {
1162   struct mtf_proc *mtf = mtf_;
1163   struct mtf_file *iter;
1164
1165   /* Find the active file and delete it. */
1166   for (iter = mtf->head; iter; iter = iter->next)
1167     if (iter->handle == NULL)
1168       {
1169         if (!mtf_delete_file_in_place (mtf, &iter))
1170           abort ();
1171         break;
1172       }
1173   
1174   while (mtf->head && mtf->head->type == MTF_FILE)
1175     if (!mtf_processing (NULL, mtf))
1176       return false;
1177
1178   return true;
1179 }
1180
1181 /* Return a string in a static buffer describing V's variable type and
1182    width. */
1183 static char *
1184 var_type_description (struct variable *v)
1185 {
1186   static char buf[2][32];
1187   static int x = 0;
1188   char *s;
1189
1190   x ^= 1;
1191   s = buf[x];
1192
1193   if (v->type == NUMERIC)
1194     strcpy (s, "numeric");
1195   else
1196     {
1197       assert (v->type == ALPHA);
1198       sprintf (s, "string with width %d", v->width);
1199     }
1200   return s;
1201 }
1202
1203 /* Closes FILE and frees its associated data.
1204    Returns true if successful, false if an I/O error
1205    occurred on FILE. */
1206 static bool
1207 mtf_close_file (struct mtf_file *file)
1208 {
1209   bool ok = file->reader == NULL || !any_reader_error (file->reader);
1210   free (file->by);
1211   any_reader_close (file->reader);
1212   if (file->handle != NULL)
1213     dict_destroy (file->dict);
1214   case_destroy (&file->input);
1215   free (file->in_name);
1216   free (file);
1217   return ok;
1218 }
1219
1220 /* Free all the data for the MATCH FILES procedure.
1221    Returns true if successful, false if an I/O error
1222    occurred. */
1223 static bool
1224 mtf_free (struct mtf_proc *mtf)
1225 {
1226   struct mtf_file *iter, *next;
1227   bool ok = true;
1228
1229   for (iter = mtf->head; iter; iter = next)
1230     {
1231       next = iter->next;
1232       assert (iter->dict != mtf->dict);
1233       if (!mtf_close_file (iter))
1234         ok = false;
1235     }
1236   
1237   if (mtf->dict)
1238     dict_destroy (mtf->dict);
1239   case_destroy (&mtf->mtf_case);
1240   free (mtf->seq_nums);
1241
1242   return ok;
1243 }
1244
1245 /* Remove *FILE from the mtf_file chain.  Make *FILE point to the next
1246    file in the chain, or to NULL if was the last in the chain.
1247    Returns true if successful, false if an I/O error occurred. */
1248 static bool
1249 mtf_delete_file_in_place (struct mtf_proc *mtf, struct mtf_file **file)
1250 {
1251   struct mtf_file *f = *file;
1252   int i;
1253
1254   if (f->prev)
1255     f->prev->next = f->next;
1256   if (f->next)
1257     f->next->prev = f->prev;
1258   if (f == mtf->head)
1259     mtf->head = f->next;
1260   if (f == mtf->tail)
1261     mtf->tail = f->prev;
1262   *file = f->next;
1263
1264   if (f->in_var != NULL)
1265     case_data_rw (&mtf->mtf_case, f->in_var->fv)->f = 0.;
1266   for (i = 0; i < dict_get_var_cnt (f->dict); i++)
1267     {
1268       struct variable *v = dict_get_var (f->dict, i);
1269       struct variable *mv = get_master (v);
1270       if (mv != NULL) 
1271         {
1272           union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1273           
1274           if (v->type == NUMERIC)
1275             out->f = SYSMIS;
1276           else
1277             memset (out->s, ' ', v->width);
1278         } 
1279     }
1280
1281   return mtf_close_file (f);
1282 }
1283
1284 /* Read a record from every input file except the active file.
1285    Returns true if successful, false if an I/O error occurred. */
1286 static bool
1287 mtf_read_nonactive_records (void *mtf_)
1288 {
1289   struct mtf_proc *mtf = mtf_;
1290   struct mtf_file *iter, *next;
1291   bool ok = true;
1292
1293   for (iter = mtf->head; ok && iter != NULL; iter = next)
1294     {
1295       next = iter->next;
1296       if (iter->handle && !any_reader_read (iter->reader, &iter->input)) 
1297         if (!mtf_delete_file_in_place (mtf, &iter))
1298           ok = false;
1299     }
1300   return ok;
1301 }
1302
1303 /* Compare the BY variables for files A and B; return -1 if A < B, 0
1304    if A == B, 1 if A > B. */
1305 static inline int
1306 mtf_compare_BY_values (struct mtf_proc *mtf,
1307                        struct mtf_file *a, struct mtf_file *b,
1308                        const struct ccase *c)
1309 {
1310   const struct ccase *ca = case_is_null (&a->input) ? c : &a->input;
1311   const struct ccase *cb = case_is_null (&b->input) ? c : &b->input;
1312   assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
1313   return case_compare_2dict (ca, cb, a->by, b->by, mtf->by_cnt);
1314 }
1315
1316 /* Perform one iteration of steps 3...7 above.
1317    Returns true if successful, false if an I/O error occurred. */
1318 static bool
1319 mtf_processing (const struct ccase *c, void *mtf_)
1320 {
1321   struct mtf_proc *mtf = mtf_;
1322
1323   /* Do we need another record from the active file? */
1324   bool read_active_file;
1325
1326   assert (mtf->head != NULL);
1327   if (mtf->head->type == MTF_TABLE)
1328     return true;
1329   
1330   do
1331     {
1332       struct mtf_file *min_head, *min_tail; /* Files with minimum BY values. */
1333       struct mtf_file *max_head, *max_tail; /* Files with non-minimum BYs. */
1334       struct mtf_file *iter, *next;
1335
1336       read_active_file = false;
1337       
1338       /* 3. Find the FILE input record(s) that have minimum BY
1339          values.  Store all the values from these input records into
1340          the output record. */
1341       min_head = min_tail = mtf->head;
1342       max_head = max_tail = NULL;
1343       for (iter = mtf->head->next; iter && iter->type == MTF_FILE;
1344            iter = iter->next) 
1345         {
1346           int cmp = mtf_compare_BY_values (mtf, min_head, iter, c);
1347           if (cmp < 0) 
1348             {
1349               if (max_head)
1350                 max_tail = max_tail->next_min = iter;
1351               else
1352                 max_head = max_tail = iter;
1353             }
1354           else if (cmp == 0) 
1355             min_tail = min_tail->next_min = iter;
1356           else /* cmp > 0 */
1357             {
1358               if (max_head)
1359                 {
1360                   max_tail->next_min = min_head;
1361                   max_tail = min_tail;
1362                 }
1363               else
1364                 {
1365                   max_head = min_head;
1366                   max_tail = min_tail;
1367                 }
1368               min_head = min_tail = iter;
1369             }
1370         }
1371       
1372       /* 4. For every TABLE, read another record as long as the BY
1373          values on the TABLE's input record are less than the FILEs'
1374          BY values.  If an exact match is found, store all the values
1375          from the TABLE input record into the output record. */
1376       for (; iter != NULL; iter = next)
1377         {
1378           assert (iter->type == MTF_TABLE);
1379       
1380           next = iter->next;
1381           for (;;) 
1382             {
1383               int cmp = mtf_compare_BY_values (mtf, min_head, iter, c);
1384               if (cmp < 0) 
1385                 {
1386                   if (max_head)
1387                     max_tail = max_tail->next_min = iter;
1388                   else
1389                     max_head = max_tail = iter;
1390                 }
1391               else if (cmp == 0)
1392                 min_tail = min_tail->next_min = iter;
1393               else /* cmp > 0 */
1394                 {
1395                   if (iter->handle == NULL)
1396                     return true;
1397                   if (any_reader_read (iter->reader, &iter->input))
1398                     continue;
1399                   if (!mtf_delete_file_in_place (mtf, &iter))
1400                     return false;
1401                 }
1402               break;
1403             }
1404         }
1405
1406       /* Next sequence number. */
1407       mtf->seq_num++;
1408
1409       /* Store data to all the records we are using. */
1410       if (min_tail)
1411         min_tail->next_min = NULL;
1412       for (iter = min_head; iter; iter = iter->next_min)
1413         {
1414           int i;
1415
1416           for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1417             {
1418               struct variable *v = dict_get_var (iter->dict, i);
1419               struct variable *mv = get_master (v);
1420           
1421               if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
1422                 {
1423                   const struct ccase *record
1424                     = case_is_null (&iter->input) ? c : &iter->input;
1425                   union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1426
1427                   mtf->seq_nums[mv->index] = mtf->seq_num;
1428                   if (v->type == NUMERIC)
1429                     out->f = case_num (record, v->fv);
1430                   else
1431                     memcpy (out->s, case_str (record, v->fv), v->width);
1432                 } 
1433             }
1434           if (iter->in_var != NULL)
1435             case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 1.;
1436
1437           if (iter->type == MTF_FILE && iter->handle == NULL)
1438             read_active_file = true;
1439         }
1440
1441       /* Store missing values to all the records we're not
1442          using. */
1443       if (max_tail)
1444         max_tail->next_min = NULL;
1445       for (iter = max_head; iter; iter = iter->next_min)
1446         {
1447           int i;
1448
1449           for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1450             {
1451               struct variable *v = dict_get_var (iter->dict, i);
1452               struct variable *mv = get_master (v);
1453
1454               if (mv != NULL && mtf->seq_nums[mv->index] != mtf->seq_num) 
1455                 {
1456                   union value *out = case_data_rw (&mtf->mtf_case, mv->fv);
1457                   mtf->seq_nums[mv->index] = mtf->seq_num;
1458
1459                   if (v->type == NUMERIC)
1460                     out->f = SYSMIS;
1461                   else
1462                     memset (out->s, ' ', v->width);
1463                 }
1464             }
1465           if (iter->in_var != NULL)
1466             case_data_rw (&mtf->mtf_case, iter->in_var->fv)->f = 0.;
1467         }
1468
1469       /* 5. Write the output record. */
1470       casefile_append (mtf->output, &mtf->mtf_case);
1471
1472       /* 6. Read another record from each input file FILE and TABLE
1473          that we stored values from above.  If we come to the end of
1474          one of the input files, remove it from the list of input
1475          files. */
1476       for (iter = min_head; iter && iter->type == MTF_FILE; iter = next)
1477         {
1478           next = iter->next_min;
1479           if (iter->reader != NULL
1480               && !any_reader_read (iter->reader, &iter->input))
1481             if (!mtf_delete_file_in_place (mtf, &iter))
1482               return false;
1483         }
1484     }
1485   while (!read_active_file
1486          && mtf->head != NULL && mtf->head->type == MTF_FILE);
1487
1488   return true;
1489 }
1490
1491 /* Merge the dictionary for file F into master dictionary M. */
1492 static int
1493 mtf_merge_dictionary (struct dictionary *const m, struct mtf_file *f)
1494 {
1495   struct dictionary *d = f->dict;
1496   const char *d_docs, *m_docs;
1497   int i;
1498
1499   if (dict_get_label (m) == NULL)
1500     dict_set_label (m, dict_get_label (d));
1501
1502   d_docs = dict_get_documents (d);
1503   m_docs = dict_get_documents (m);
1504   if (d_docs != NULL) 
1505     {
1506       if (m_docs == NULL)
1507         dict_set_documents (m, d_docs);
1508       else
1509         {
1510           char *new_docs;
1511           size_t new_len;
1512
1513           new_len = strlen (m_docs) + strlen (d_docs);
1514           new_docs = xmalloc (new_len + 1);
1515           strcpy (new_docs, m_docs);
1516           strcat (new_docs, d_docs);
1517           dict_set_documents (m, new_docs);
1518           free (new_docs);
1519         }
1520     }
1521   
1522   for (i = 0; i < dict_get_var_cnt (d); i++)
1523     {
1524       struct variable *dv = dict_get_var (d, i);
1525       struct variable *mv = dict_lookup_var (m, dv->name);
1526
1527       if (dict_class_from_id (dv->name) == DC_SCRATCH)
1528         continue;
1529
1530       if (mv != NULL)
1531         {
1532           if (mv->width != dv->width) 
1533             {
1534               msg (SE, _("Variable %s in file %s (%s) has different "
1535                          "type or width from the same variable in "
1536                          "earlier file (%s)."),
1537                    dv->name, fh_get_name (f->handle),
1538                    var_type_description (dv), var_type_description (mv));
1539               return 0;
1540             }
1541         
1542           if (dv->width == mv->width)
1543             {
1544               if (val_labs_count (dv->val_labs)
1545                   && !val_labs_count (mv->val_labs)) 
1546                 {
1547                   val_labs_destroy (mv->val_labs);
1548                   mv->val_labs = val_labs_copy (dv->val_labs); 
1549                 }
1550               if (!mv_is_empty (&dv->miss) && mv_is_empty (&mv->miss))
1551                 mv_copy (&mv->miss, &dv->miss);
1552             }
1553
1554           if (dv->label && !mv->label)
1555             mv->label = xstrdup (dv->label);
1556         }
1557       else
1558         mv = dict_clone_var_assert (m, dv, dv->name);
1559     }
1560
1561   return 1;
1562 }
1563
1564 /* Marks V's master variable as MASTER. */
1565 static void
1566 set_master (struct variable *v, struct variable *master) 
1567 {
1568   var_attach_aux (v, master, NULL);
1569 }
1570
1571 /* Returns the master variable corresponding to V,
1572    as set with set_master(). */
1573 static struct variable *
1574 get_master (struct variable *v) 
1575 {
1576   return v->aux;
1577 }
1578 \f
1579
1580 \f
1581 /* Case map.
1582
1583    A case map copies data from a case that corresponds for one
1584    dictionary to a case that corresponds to a second dictionary
1585    derived from the first by, optionally, deleting, reordering,
1586    or renaming variables.  (No new variables may be created.)
1587    */
1588
1589 /* A case map. */
1590 struct case_map
1591   {
1592     size_t value_cnt;   /* Number of values in map. */
1593     int *map;           /* For each destination index, the
1594                            corresponding source index. */
1595   };
1596
1597 /* Prepares dictionary D for producing a case map.  Afterward,
1598    the caller may delete, reorder, or rename variables within D
1599    at will before using finish_case_map() to produce the case
1600    map.
1601
1602    Uses D's aux members, which must otherwise not be in use. */
1603 static void
1604 start_case_map (struct dictionary *d) 
1605 {
1606   size_t var_cnt = dict_get_var_cnt (d);
1607   size_t i;
1608   
1609   for (i = 0; i < var_cnt; i++)
1610     {
1611       struct variable *v = dict_get_var (d, i);
1612       int *src_fv = xmalloc (sizeof *src_fv);
1613       *src_fv = v->fv;
1614       var_attach_aux (v, src_fv, var_dtor_free);
1615     }
1616 }
1617
1618 /* Produces a case map from dictionary D, which must have been
1619    previously prepared with start_case_map().
1620
1621    Does not retain any reference to D, and clears the aux members
1622    set up by start_case_map().
1623
1624    Returns the new case map, or a null pointer if no mapping is
1625    required (that is, no data has changed position). */
1626 static struct case_map *
1627 finish_case_map (struct dictionary *d) 
1628 {
1629   struct case_map *map;
1630   size_t var_cnt = dict_get_var_cnt (d);
1631   size_t i;
1632   int identity_map;
1633
1634   map = xmalloc (sizeof *map);
1635   map->value_cnt = dict_get_next_value_idx (d);
1636   map->map = xnmalloc (map->value_cnt, sizeof *map->map);
1637   for (i = 0; i < map->value_cnt; i++)
1638     map->map[i] = -1;
1639
1640   identity_map = 1;
1641   for (i = 0; i < var_cnt; i++) 
1642     {
1643       struct variable *v = dict_get_var (d, i);
1644       int *src_fv = (int *) var_detach_aux (v);
1645       size_t idx;
1646
1647       if (v->fv != *src_fv)
1648         identity_map = 0;
1649       
1650       for (idx = 0; idx < v->nv; idx++)
1651         {
1652           int src_idx = *src_fv + idx;
1653           int dst_idx = v->fv + idx;
1654           
1655           assert (map->map[dst_idx] == -1);
1656           map->map[dst_idx] = src_idx;
1657         }
1658       free (src_fv);
1659     }
1660
1661   if (identity_map) 
1662     {
1663       destroy_case_map (map);
1664       return NULL;
1665     }
1666
1667   while (map->value_cnt > 0 && map->map[map->value_cnt - 1] == -1)
1668     map->value_cnt--;
1669
1670   return map;
1671 }
1672
1673 /* Maps from SRC to DST, applying case map MAP. */
1674 static void
1675 map_case (const struct case_map *map,
1676           const struct ccase *src, struct ccase *dst) 
1677 {
1678   size_t dst_idx;
1679
1680   assert (map != NULL);
1681   assert (src != NULL);
1682   assert (dst != NULL);
1683   assert (src != dst);
1684
1685   for (dst_idx = 0; dst_idx < map->value_cnt; dst_idx++)
1686     {
1687       int src_idx = map->map[dst_idx];
1688       if (src_idx != -1)
1689         *case_data_rw (dst, dst_idx) = *case_data (src, src_idx);
1690     }
1691 }
1692
1693 /* Destroys case map MAP. */
1694 static void
1695 destroy_case_map (struct case_map *map) 
1696 {
1697   if (map != NULL) 
1698     {
1699       free (map->map);
1700       free (map);
1701     }
1702 }