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