1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA
26 #include "file-handle.h"
34 #include "value-labels.h"
39 #include "debug-print.h"
41 /* GET or IMPORT input program. */
44 struct file_handle *handle; /* File to GET or IMPORT from. */
45 size_t case_size; /* Case size in bytes. */
48 /* XSAVE transformation (and related SAVE, EXPORT procedures). */
52 struct file_handle *f; /* Associated system file. */
53 int nvar; /* Number of variables. */
54 struct variable **var; /* Variables. */
55 flt64 *case_buf; /* Case transfer buffer. */
58 /* Options bits set by trim_dictionary(). */
59 #define GTSV_OPT_COMPRESSED 001 /* Compression; (X)SAVE only. */
60 #define GTSV_OPT_SAVE 002 /* The SAVE/XSAVE/EXPORT procedures. */
61 #define GTSV_OPT_MATCH_FILES 004 /* The MATCH FILES procedure. */
62 #define GTSV_OPT_NONE 0
64 static int trim_dictionary (struct dictionary * dict, int *options);
65 static int save_write_case_func (struct ccase *, void *);
66 static trns_proc_func save_trns_proc;
67 static trns_free_func save_trns_free;
70 void dump_dict_variables (struct dictionary *);
73 /* Parses the GET command. */
77 struct file_handle *handle;
78 struct dictionary *dict;
80 int options = GTSV_OPT_NONE;
86 if (lex_match_id ("FILE"))
89 handle = fh_parse_file_handle ();
93 dict = sfm_read_dictionary (handle, NULL);
98 dump_dict_variables (dict);
100 if (0 == trim_dictionary (dict, &options))
102 fh_close_handle (handle);
106 dump_dict_variables (dict);
109 dict_compact_values (dict);
112 printf (_("GET translation table from file to memory:\n"));
113 for (i = 0; i < dict->nvar; i++)
115 struct variable *v = dict->var[i];
117 printf (_(" %8s from %3d,%3d to %3d,%3d\n"), v->name,
118 v->get.fv, v->get.nv, v->fv, v->nv);
122 dict_destroy (default_dict);
125 pgm = xmalloc (sizeof *pgm);
126 pgm->handle = handle;
127 pgm->case_size = dict_get_case_size (default_dict);
128 vfm_source = create_case_source (&get_source_class, default_dict, pgm);
133 /* SAVE or XSAVE command? */
140 /* Parses the SAVE and XSAVE commands. */
142 cmd_save_internal (enum save_cmd save_cmd)
144 struct file_handle *handle;
145 struct dictionary *dict;
146 int options = GTSV_OPT_SAVE;
149 struct sfm_write_info inf;
153 lex_match_id ("SAVE");
156 if (lex_match_id ("OUTFILE"))
159 handle = fh_parse_file_handle ();
163 dict = dict_clone (default_dict);
165 dump_dict_variables (dict);
167 for (i = 0; i < dict_get_var_cnt (dict); i++)
168 dict_get_var (dict, i)->aux = dict_get_var (default_dict, i);
169 if (0 == trim_dictionary (dict, &options))
171 fh_close_handle (handle);
176 dump_dict_variables (dict);
179 /* Write dictionary. */
182 inf.compress = !!(options & GTSV_OPT_COMPRESSED);
183 if (!sfm_write_dictionary (&inf))
186 fh_close_handle (handle);
190 /* Fill in transformation structure. */
191 t = xmalloc (sizeof *t);
192 t->h.proc = save_trns_proc;
193 t->h.free = save_trns_free;
195 t->nvar = dict_get_var_cnt (dict);
196 t->var = xmalloc (sizeof *t->var * t->nvar);
197 for (i = 0; i < t->nvar; i++)
198 t->var[i] = dict_get_var (dict, i)->aux;
199 t->case_buf = xmalloc (sizeof *t->case_buf * inf.case_size);
202 if (save_cmd == CMD_SAVE)
204 procedure (save_write_case_func, t);
205 save_trns_free (&t->h);
209 assert (save_cmd == CMD_XSAVE);
210 add_transformation (&t->h);
216 /* Parses and performs the SAVE procedure. */
220 return cmd_save_internal (CMD_SAVE);
223 /* Parses the XSAVE transformation command. */
227 return cmd_save_internal (CMD_XSAVE);
230 /* Writes the given C to the file specified by T. */
232 do_write_case (struct save_trns *t, struct ccase *c)
234 flt64 *p = t->case_buf;
237 for (i = 0; i < t->nvar; i++)
239 struct variable *v = t->var[i];
240 if (v->type == NUMERIC)
242 double src = c->data[v->fv].f;
250 memcpy (p, c->data[v->fv].s, v->width);
251 memset (&((char *) p)[v->width], ' ',
252 REM_RND_UP (v->width, sizeof *p));
253 p += DIV_RND_UP (v->width, sizeof *p);
257 sfm_write_case (t->f, t->case_buf, p - t->case_buf);
260 /* Writes case C to the system file specified on SAVE. */
262 save_write_case_func (struct ccase *c, void *aux UNUSED)
264 do_write_case (aux, c);
268 /* Writes case C to the system file specified on XSAVE. */
270 save_trns_proc (struct trns_header *h, struct ccase *c, int case_num UNUSED)
272 struct save_trns *t = (struct save_trns *) h;
273 do_write_case (t, c);
277 /* Frees a SAVE transformation. */
279 save_trns_free (struct trns_header *pt)
281 struct save_trns *t = (struct save_trns *) pt;
283 fh_close_handle (t->f);
289 static int rename_variables (struct dictionary * dict);
291 /* The GET and SAVE commands have a common structure after the
292 FILE/OUTFILE subcommand. This function parses this structure and
293 returns nonzero on success, zero on failure. It both reads
294 *OPTIONS, for the GTSV_OPT_SAVE bit, and writes it, for the
295 GTSV_OPT_COMPRESSED bit. */
296 /* FIXME: IN, FIRST, LAST, MAP. */
297 /* FIXME? Should we call dict_compact_values() on dict as a
300 trim_dictionary (struct dictionary *dict, int *options)
302 if (set_scompression)
303 *options |= GTSV_OPT_COMPRESSED;
305 if (*options & GTSV_OPT_SAVE)
307 /* Delete all the scratch variables. */
312 v = xmalloc (sizeof *v * dict_get_var_cnt (dict));
314 for (i = 0; i < dict_get_var_cnt (dict); i++)
315 if (dict_class_from_id (dict_get_var (dict, i)->name) == DC_SCRATCH)
316 v[nv++] = dict_get_var (dict, i);
317 dict_delete_vars (dict, v, nv);
321 while ((*options & GTSV_OPT_MATCH_FILES) || lex_match ('/'))
323 if (!(*options & GTSV_OPT_MATCH_FILES) && lex_match_id ("COMPRESSED"))
324 *options |= GTSV_OPT_COMPRESSED;
325 else if (!(*options & GTSV_OPT_MATCH_FILES) && lex_match_id ("UNCOMPRESSED"))
326 *options &= ~GTSV_OPT_COMPRESSED;
327 else if (lex_match_id ("DROP"))
333 if (!parse_variables (dict, &v, &nv, PV_NONE))
335 dict_delete_vars (dict, v, nv);
338 else if (lex_match_id ("KEEP"))
345 if (!parse_variables (dict, &v, &nv, PV_NONE))
348 /* Move the specified variables to the beginning. */
349 dict_reorder_vars (dict, v, nv);
351 /* Delete the remaining variables. */
352 v = xrealloc (v, (dict_get_var_cnt (dict) - nv) * sizeof *v);
353 for (i = nv; i < dict_get_var_cnt (dict); i++)
354 v[i - nv] = dict_get_var (dict, i);
355 dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);
358 else if (lex_match_id ("RENAME"))
360 if (!rename_variables (dict))
365 lex_error (_("while expecting a valid subcommand"));
369 if (dict_get_var_cnt (dict) == 0)
371 msg (SE, _("All variables deleted from system file dictionary."));
375 if (*options & GTSV_OPT_MATCH_FILES)
381 lex_error (_("expecting end of command"));
388 /* Parses and performs the RENAME subcommand of GET and SAVE. */
390 rename_variables (struct dictionary * dict)
408 v = parse_dict_variable (dict);
411 if (!lex_force_match ('=')
414 if (!strncmp (tokid, v->name, 8))
416 if (dict_lookup_var (dict, tokid) != NULL)
418 msg (SE, _("Cannot rename %s as %s because there already exists "
419 "a variable named %s. To rename variables with "
420 "overlapping names, use a single RENAME subcommand "
421 "such as \"/RENAME (A=B)(B=C)(C=A)\", or equivalently, "
422 "\"/RENAME (A B C=B C A)\"."), v->name, tokid, tokid);
426 dict_rename_var (dict, v, tokid);
435 while (lex_match ('('))
439 if (!parse_variables (dict, &v, &nv, PV_NO_DUPLICATE | PV_APPEND))
441 if (!lex_match ('='))
443 msg (SE, _("`=' expected after variable list."));
446 if (!parse_DATA_LIST_vars (&new_names, &nn, PV_APPEND | PV_NO_SCRATCH))
450 msg (SE, _("Number of variables on left side of `=' (%d) does not "
451 "match number of variables on right side (%d), in "
452 "parenthesized group %d of RENAME subcommand."),
453 nv - old_nv, nn - old_nv, group);
456 if (!lex_force_match (')'))
461 if (!dict_rename_vars (dict, v, new_names, nv, &err_name))
463 msg (SE, _("Requested renaming duplicates variable name %s."), err_name);
469 for (i = 0; i < nn; i++)
479 dump_dict_variables (struct dictionary * dict)
483 printf (_("\nVariables in dictionary:\n"));
484 for (i = 0; i < dict->nvar; i++)
485 printf ("%s, ", dict->var[i]->name);
490 /* Clears internal state related to GET input procedure. */
492 get_source_destroy (struct case_source *source)
494 struct get_pgm *pgm = source->aux;
496 /* It is not necessary to destroy the dictionary because if we get
497 to this point then the dictionary is default_dict. */
498 fh_close_handle (pgm->handle);
502 /* Reads all the cases from the data file into C and passes them
503 to WRITE_CASE one by one, passing WC_DATA. */
505 get_source_read (struct case_source *source,
507 write_case_func *write_case, write_case_data wc_data)
509 struct get_pgm *pgm = source->aux;
511 while (sfm_read_case (pgm->handle, c->data, default_dict)
512 && write_case (wc_data))
516 const struct case_source_class get_source_class =
527 #include "debug-print.h"
532 MTF_FILE, /* Specified on FILE= subcommand. */
533 MTF_TABLE /* Specified on TABLE= subcommand. */
536 /* One of the files on MATCH FILES. */
539 struct mtf_file *next, *prev;
540 /* Next, previous in the list of files. */
541 struct mtf_file *next_min; /* Next in the chain of minimums. */
543 int type; /* One of MTF_*. */
544 struct variable **by; /* List of BY variables for this file. */
545 struct file_handle *handle; /* File handle for the file. */
546 struct dictionary *dict; /* Dictionary from system file. */
547 char in[9]; /* Name of the variable from IN=. */
548 char first[9], last[9]; /* Name of the variables from FIRST=, LAST=. */
549 union value *input; /* Input record. */
552 /* All the files mentioned on FILE or TABLE. */
553 static struct mtf_file *mtf_head, *mtf_tail;
555 /* Variables on the BY subcommand. */
556 static struct variable **mtf_by;
559 /* Master dictionary. */
560 static struct dictionary *mtf_master;
562 /* Used to determine whether we've already initialized this
564 static unsigned mtf_seq_num;
566 /* Sequence numbers for each variable in mtf_master. */
567 static unsigned *mtf_seq_nums;
569 /* Sink for MATCH FILES output. */
570 static struct case_sink *mtf_sink;
572 /* Case used for MATCH FILES output. */
573 static struct ccase *mtf_case;
575 static void mtf_free (void);
576 static void mtf_free_file (struct mtf_file *file);
577 static int mtf_merge_dictionary (struct mtf_file *f);
578 static void mtf_delete_file_in_place (struct mtf_file **file);
580 static void mtf_read_nonactive_records (void *);
581 static void mtf_processing_finish (void *);
582 static int mtf_processing (struct ccase *, void *);
584 static char *var_type_description (struct variable *);
586 /* Parse and execute the MATCH FILES command. */
588 cmd_match_files (void)
590 struct mtf_file *first_table = NULL;
594 lex_match_id ("MATCH");
595 lex_match_id ("FILES");
597 mtf_head = mtf_tail = NULL;
600 mtf_master = dict_create ();
603 dict_set_case_limit (mtf_master, dict_get_case_limit (default_dict));
609 if (lex_match (T_BY))
613 msg (SE, _("The BY subcommand may be given once at most."));
619 if (!parse_variables (mtf_master, &mtf_by, &mtf_n_by,
620 PV_NO_DUPLICATE | PV_NO_SCRATCH))
623 else if (token != T_ID)
628 else if (lex_id_match ("FILE", tokid) || lex_id_match ("TABLE", tokid))
630 struct mtf_file *file = xmalloc (sizeof *file);
632 file->in[0] = file->first[0] = file->last[0] = '\0';
637 if (lex_match_id ("FILE"))
638 file->type = MTF_FILE;
639 else if (lex_match_id ("TABLE"))
641 file->type = MTF_TABLE;
647 /* FILEs go first, then TABLEs. */
648 if (file->type == MTF_TABLE || first_table == NULL)
651 file->prev = mtf_tail;
653 mtf_tail->next = file;
655 if (mtf_head == NULL)
657 if (file->type == MTF_TABLE && first_table == NULL)
662 assert (file->type == MTF_FILE);
663 file->next = first_table;
664 file->prev = first_table->prev;
665 if (first_table->prev)
666 first_table->prev->next = file;
669 first_table->prev = file;
680 msg (SE, _("The active file may not be specified more "
686 assert (pgm_state != STATE_INPUT);
687 if (pgm_state == STATE_INIT)
689 msg (SE, _("Cannot specify the active file since no active "
690 "file has been defined."));
697 _("MATCH FILES may not be used after TEMPORARY when "
698 "the active file is an input source. "
699 "Temporary transformations will be made permanent."));
705 file->handle = fh_parse_file_handle ();
712 file->dict = sfm_read_dictionary (file->handle, NULL);
717 file->dict = default_dict;
718 if (!mtf_merge_dictionary (file))
721 else if (lex_id_match ("IN", tokid)
722 || lex_id_match ("FIRST", tokid)
723 || lex_id_match ("LAST", tokid))
728 if (mtf_tail == NULL)
730 msg (SE, _("IN, FIRST, and LAST subcommands may not occur "
731 "before the first FILE or TABLE."));
735 if (lex_match_id ("IN"))
740 else if (lex_match_id ("FIRST"))
742 name = mtf_tail->first;
745 else if (lex_match_id ("LAST"))
747 name = mtf_tail->last;
762 msg (SE, _("Multiple %s subcommands for a single FILE or "
767 strcpy (name, tokid);
770 if (!dict_create_var (mtf_master, name, 0))
772 msg (SE, _("Duplicate variable name %s while creating %s "
778 else if (lex_id_match ("RENAME", tokid)
779 || lex_id_match ("KEEP", tokid)
780 || lex_id_match ("DROP", tokid))
782 int options = GTSV_OPT_MATCH_FILES;
784 if (mtf_tail == NULL)
786 msg (SE, _("RENAME, KEEP, and DROP subcommands may not occur "
787 "before the first FILE or TABLE."));
791 if (!trim_dictionary (mtf_tail->dict, &options))
794 else if (lex_match_id ("MAP"))
804 while (token != '.');
810 msg (SE, _("The BY subcommand is required when a TABLE subcommand "
818 struct mtf_file *iter;
820 for (iter = mtf_head; iter; iter = iter->next)
824 iter->by = xmalloc (sizeof *iter->by * mtf_n_by);
826 for (i = 0; i < mtf_n_by; i++)
828 iter->by[i] = dict_lookup_var (iter->dict, mtf_by[i]->name);
829 if (iter->by[i] == NULL)
831 msg (SE, _("File %s lacks BY variable %s."),
832 iter->handle ? fh_handle_name (iter->handle) : "*",
842 /* From sfm-read.c. */
843 extern void dump_dictionary (struct dictionary *);
845 dump_dictionary (mtf_master);
849 /* MATCH FILES performs an n-way merge on all its input files.
852 1. Read one input record from every input FILE.
854 2. If no FILEs are left, stop. Otherwise, proceed to step 3.
856 3. Find the FILE input record with minimum BY values. Store all
857 the values from this input record into the output record.
859 4. Find all the FILE input records with BY values identical to
860 the minimums. Store all the values from these input records into
863 5. For every TABLE, read another record as long as the BY values
864 on the TABLE's input record are less than the FILEs' BY values.
865 If an exact match is found, store all the values from the TABLE
866 input record into the output record.
868 6. Write the output record.
870 7. Read another record from each input file FILE and TABLE that
871 we stored values from above. If we come to the end of one of the
872 input files, remove it from the list of input files.
874 8. Repeat from step 2.
876 Unfortunately, this algorithm can't be directly implemented
877 because there's no function to read a record from the active
878 file; instead, it has to be done using callbacks.
880 FIXME: For merging large numbers of files (more than 10?) a
881 better algorithm would use a heap for finding minimum
885 discard_variables ();
887 mtf_sink = create_case_sink (&storage_sink_class, mtf_master, NULL);
889 mtf_seq_nums = xmalloc (dict_get_var_cnt (mtf_master)
890 * sizeof *mtf_seq_nums);
891 memset (mtf_seq_nums, 0,
892 dict_get_var_cnt (mtf_master) * sizeof *mtf_seq_nums);
893 mtf_case = xmalloc (dict_get_case_size (mtf_master));
895 mtf_read_nonactive_records (NULL);
897 procedure (mtf_processing, NULL);
898 mtf_processing_finish (NULL);
900 dict_destroy (default_dict);
901 default_dict = mtf_master;
903 vfm_source = mtf_sink->class->make_source (mtf_sink);
904 free_case_sink (mtf_sink);
914 /* Repeats 2...8 an arbitrary number of times. */
916 mtf_processing_finish (void *aux UNUSED)
918 /* Find the active file and delete it. */
920 struct mtf_file *iter;
922 for (iter = mtf_head; iter; iter = iter->next)
923 if (iter->handle == NULL)
925 mtf_delete_file_in_place (&iter);
930 while (mtf_head && mtf_head->type == MTF_FILE)
931 if (!mtf_processing (NULL, NULL))
935 /* Return a string in a static buffer describing V's variable type and
938 var_type_description (struct variable *v)
940 static char buf[2][32];
947 if (v->type == NUMERIC)
948 strcpy (s, "numeric");
951 assert (v->type == ALPHA);
952 sprintf (s, "string with width %d", v->width);
957 /* Free FILE and associated data. */
959 mtf_free_file (struct mtf_file *file)
961 fh_close_handle (file->handle);
962 if (file->dict != NULL && file->dict != default_dict)
963 dict_destroy (file->dict);
970 /* Free all the data for the MATCH FILES procedure. */
974 struct mtf_file *iter, *next;
976 for (iter = mtf_head; iter; iter = next)
980 mtf_free_file (iter);
985 dict_destroy (mtf_master);
989 /* Remove *FILE from the mtf_file chain. Make *FILE point to the next
990 file in the chain, or to NULL if was the last in the chain. */
992 mtf_delete_file_in_place (struct mtf_file **file)
994 struct mtf_file *f = *file;
997 f->prev->next = f->next;
999 f->next->prev = f->prev;
1009 for (i = 0; i < dict_get_var_cnt (f->dict); i++)
1011 struct variable *v = dict_get_var (f->dict, i);
1013 if (v->type == NUMERIC)
1014 mtf_case->data[v->p.mtf.master->fv].f = SYSMIS;
1016 memset (mtf_case->data[v->p.mtf.master->fv].s, ' ', v->width);
1023 /* Read a record from every input file except the active file. */
1025 mtf_read_nonactive_records (void *aux UNUSED)
1027 struct mtf_file *iter;
1029 for (iter = mtf_head; iter; )
1033 assert (iter->input == NULL);
1034 iter->input = xmalloc (dict_get_case_size (iter->dict));
1036 if (!sfm_read_case (iter->handle, iter->input, iter->dict))
1037 mtf_delete_file_in_place (&iter);
1046 /* Compare the BY variables for files A and B; return -1 if A < B, 0
1047 if A == B, 1 if A > B. */
1049 mtf_compare_BY_values (struct mtf_file *a, struct mtf_file *b,
1052 union value *a_input, *b_input;
1055 assert ((a == NULL) + (b == NULL) + (c == NULL) <= 1);
1056 a_input = a->input != NULL ? a->input : c->data;
1057 b_input = b->input != NULL ? b->input : c->data;
1058 for (i = 0; i < mtf_n_by; i++)
1060 assert (a->by[i]->type == b->by[i]->type);
1061 assert (a->by[i]->width == b->by[i]->width);
1063 if (a->by[i]->type == NUMERIC)
1065 double af = a_input[a->by[i]->fv].f;
1066 double bf = b_input[b->by[i]->fv].f;
1077 assert (a->by[i]->type == ALPHA);
1078 result = memcmp (a_input[a->by[i]->fv].s,
1079 b_input[b->by[i]->fv].s,
1083 else if (result > 0)
1090 /* Perform one iteration of steps 3...7 above. */
1092 mtf_processing (struct ccase *c, void *aux UNUSED)
1094 /* List of files with minimum BY values. */
1095 struct mtf_file *min_head, *min_tail;
1097 /* List of files with non-minimum BY values. */
1098 struct mtf_file *max_head, *max_tail;
1101 struct mtf_file *iter;
1105 /* If the active file doesn't have the minimum BY values, don't
1106 return because that would cause a record to be skipped. */
1109 if (mtf_head->type == MTF_TABLE)
1112 /* 3. Find the FILE input record with minimum BY values. Store
1113 all the values from this input record into the output record.
1115 4. Find all the FILE input records with BY values identical
1116 to the minimums. Store all the values from these input
1117 records into the output record. */
1118 min_head = min_tail = mtf_head;
1119 max_head = max_tail = NULL;
1120 for (iter = mtf_head->next; iter && iter->type == MTF_FILE;
1122 switch (mtf_compare_BY_values (min_head, iter, c))
1126 max_tail = max_tail->next_min = iter;
1128 max_head = max_tail = iter;
1132 min_tail = min_tail->next_min = iter;
1138 max_tail->next_min = min_head;
1139 max_tail = min_tail;
1143 max_head = min_head;
1144 max_tail = min_tail;
1146 min_head = min_tail = iter;
1153 /* 5. For every TABLE, read another record as long as the BY
1154 values on the TABLE's input record are less than the FILEs'
1155 BY values. If an exact match is found, store all the values
1156 from the TABLE input record into the output record. */
1159 struct mtf_file *next = iter->next;
1161 assert (iter->type == MTF_TABLE);
1163 if (iter->handle == NULL)
1167 switch (mtf_compare_BY_values (min_head, iter, c))
1171 max_tail = max_tail->next_min = iter;
1173 max_head = max_tail = iter;
1177 min_tail = min_tail->next_min = iter;
1181 if (iter->handle == NULL)
1183 if (sfm_read_case (iter->handle, iter->input, iter->dict))
1185 mtf_delete_file_in_place (&iter);
1195 /* Next sequence number. */
1198 /* Store data to all the records we are using. */
1200 min_tail->next_min = NULL;
1201 for (iter = min_head; iter; iter = iter->next_min)
1205 for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1207 struct variable *v = dict_get_var (iter->dict, i);
1208 union value *record;
1210 if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num)
1212 mtf_seq_nums[v->p.mtf.master->index] = mtf_seq_num;
1214 record = iter->input != NULL ? iter->input : c->data;
1216 assert (v->type == NUMERIC || v->type == ALPHA);
1217 if (v->type == NUMERIC)
1218 mtf_case->data[v->p.mtf.master->fv].f = record[v->fv].f;
1220 memcpy (mtf_case->data[v->p.mtf.master->fv].s,
1221 record[v->fv].s, v->width);
1225 /* Store missing values to all the records we're not using. */
1227 max_tail->next_min = NULL;
1228 for (iter = max_head; iter; iter = iter->next_min)
1232 for (i = 0; i < dict_get_var_cnt (iter->dict); i++)
1234 struct variable *v = dict_get_var (iter->dict, i);
1236 if (mtf_seq_nums[v->p.mtf.master->index] == mtf_seq_num)
1238 mtf_seq_nums[v->p.mtf.master->index] = mtf_seq_num;
1241 printf ("%s/%s: dest-fv=%d\n",
1242 fh_handle_name (iter->handle),
1244 v->p.mtf.master->fv);
1246 if (v->type == NUMERIC)
1247 mtf_case->data[v->p.mtf.master->fv].f = SYSMIS;
1249 memset (mtf_case->data[v->p.mtf.master->fv].s, ' ',
1253 if (iter->handle == NULL)
1257 /* 6. Write the output record. */
1258 mtf_sink->class->write (mtf_sink, mtf_case);
1260 /* 7. Read another record from each input file FILE and TABLE
1261 that we stored values from above. If we come to the end of
1262 one of the input files, remove it from the list of input
1264 for (iter = min_head; iter && iter->type == MTF_FILE; )
1266 struct mtf_file *next = iter->next_min;
1270 assert (iter->input != NULL);
1272 if (!sfm_read_case (iter->handle, iter->input, iter->dict))
1273 mtf_delete_file_in_place (&iter);
1283 return (mtf_head && mtf_head->type != MTF_TABLE);
1286 /* Merge the dictionary for file F into the master dictionary
1289 mtf_merge_dictionary (struct mtf_file *f)
1291 struct dictionary *const m = mtf_master;
1292 struct dictionary *d = f->dict;
1293 const char *d_docs, *m_docs;
1295 if (dict_get_label (m) == NULL)
1296 dict_set_label (m, dict_get_label (d));
1298 d_docs = dict_get_documents (d);
1299 m_docs = dict_get_documents (m);
1303 dict_set_documents (m, d_docs);
1309 new_len = strlen (m_docs) + strlen (d_docs);
1310 new_docs = xmalloc (new_len + 1);
1311 strcpy (new_docs, m_docs);
1312 strcat (new_docs, d_docs);
1313 dict_set_documents (m, new_docs);
1318 dict_compact_values (d);
1323 for (i = 0; i < dict_get_var_cnt (d); i++)
1325 struct variable *dv = dict_get_var (d, i);
1326 struct variable *mv = dict_lookup_var (m, dv->name);
1328 assert (dv->type == ALPHA || dv->width == 0);
1329 assert (!mv || mv->type == ALPHA || mv->width == 0);
1330 if (mv && dv->width == mv->width)
1332 if (val_labs_count (dv->val_labs)
1333 && !val_labs_count (mv->val_labs))
1334 mv->val_labs = val_labs_copy (dv->val_labs);
1335 if (dv->miss_type != MISSING_NONE
1336 && mv->miss_type == MISSING_NONE)
1337 copy_missing_values (mv, dv);
1339 if (mv && dv->label && !mv->label)
1340 mv->label = xstrdup (dv->label);
1343 mv = dict_clone_var (m, dv, dv->name);
1344 assert (mv != NULL);
1346 else if (mv->width != dv->width)
1348 msg (SE, _("Variable %s in file %s (%s) has different "
1349 "type or width from the same variable in "
1350 "earlier file (%s)."),
1351 dv->name, fh_handle_name (f->handle),
1352 var_type_description (dv), var_type_description (mv));
1355 dv->p.mtf.master = mv;
1362 /* IMPORT command. */
1364 /* Parses the IMPORT command. */
1368 struct file_handle *handle = NULL;
1369 struct dictionary *dict;
1370 struct get_pgm *pgm;
1371 int options = GTSV_OPT_NONE;
1374 lex_match_id ("IMPORT");
1380 if (lex_match_id ("FILE") || token == T_STRING)
1384 handle = fh_parse_file_handle ();
1388 else if (lex_match_id ("TYPE"))
1392 if (lex_match_id ("COMM"))
1394 else if (lex_match_id ("TAPE"))
1398 lex_error (_("expecting COMM or TAPE"));
1404 if (!lex_match ('/') && token != '.')
1410 discard_variables ();
1412 dict = pfm_read_dictionary (handle, NULL);
1417 dump_dict_variables (dict);
1419 if (0 == trim_dictionary (dict, &options))
1421 fh_close_handle (handle);
1425 dump_dict_variables (dict);
1428 dict_compact_values (dict);
1431 printf (_("IMPORT translation table from file to memory:\n"));
1432 for (i = 0; i < dict->nvar; i++)
1434 struct variable *v = dict->var[i];
1436 printf (_(" %8s from %3d,%3d to %3d,%3d\n"), v->name,
1437 v->get.fv, v->get.nv, v->fv, v->nv);
1441 dict_destroy (default_dict);
1442 default_dict = dict;
1444 pgm = xmalloc (sizeof *pgm);
1445 pgm->handle = handle;
1446 pgm->case_size = dict_get_case_size (default_dict);
1447 vfm_source = create_case_source (&import_source_class, default_dict, pgm);
1452 /* Reads all the cases from the data file and passes them to
1455 import_source_read (struct case_source *source,
1457 write_case_func *write_case, write_case_data wc_data)
1459 struct get_pgm *pgm = source->aux;
1461 while (pfm_read_case (pgm->handle, c->data, default_dict))
1462 if (!write_case (wc_data))
1466 const struct case_source_class import_source_class =
1474 static int export_write_case_func (struct ccase *c, void *);
1476 /* Parses the EXPORT command. */
1477 /* FIXME: same as cmd_save_internal(). */
1481 struct file_handle *handle;
1482 struct dictionary *dict;
1483 int options = GTSV_OPT_SAVE;
1485 struct save_trns *t;
1489 lex_match_id ("EXPORT");
1492 if (lex_match_id ("OUTFILE"))
1495 handle = fh_parse_file_handle ();
1499 dict = dict_clone (default_dict);
1501 dump_dict_variables (dict);
1503 for (i = 0; i < dict_get_var_cnt (dict); i++)
1504 dict_get_var (dict, i)->aux = dict_get_var (default_dict, i);
1505 if (0 == trim_dictionary (dict, &options))
1507 fh_close_handle (handle);
1512 dump_dict_variables (dict);
1515 /* Write dictionary. */
1516 if (!pfm_write_dictionary (handle, dict))
1518 dict_destroy (dict);
1519 fh_close_handle (handle);
1523 /* Fill in transformation structure. */
1524 t = xmalloc (sizeof *t);
1525 t->h.proc = save_trns_proc;
1526 t->h.free = save_trns_free;
1528 t->nvar = dict_get_var_cnt (dict);
1529 t->var = xmalloc (sizeof *t->var * t->nvar);
1530 for (i = 0; i < t->nvar; i++)
1531 t->var[i] = dict_get_var (dict, i)->aux;
1532 t->case_buf = xmalloc (sizeof *t->case_buf * t->nvar);
1533 dict_destroy (dict);
1535 procedure (export_write_case_func, t);
1536 save_trns_free (&t->h);
1541 /* Writes case C to the EXPORT file. */
1543 export_write_case_func (struct ccase *c, void *aux)
1545 struct save_trns *t = aux;
1546 union value *p = (union value *) t->case_buf;
1549 for (i = 0; i < t->nvar; i++)
1551 struct variable *v = t->var[i];
1553 if (v->type == NUMERIC)
1554 *p++ = c->data[v->fv];
1556 (*p++).c = c->data[v->fv].s;
1559 pfm_write_case (t->f, (union value *) t->case_buf);