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