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