1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "data/any-reader.h"
22 #include "data/case-matcher.h"
23 #include "data/case.h"
24 #include "data/casereader.h"
25 #include "data/casewriter.h"
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/format.h"
29 #include "data/subcase.h"
30 #include "data/variable.h"
31 #include "language/command.h"
32 #include "language/commands/file-handle.h"
33 #include "language/commands/trim.h"
34 #include "language/lexer/lexer.h"
35 #include "language/lexer/variable-parser.h"
36 #include "language/commands/sort-criteria.h"
37 #include "libpspp/assertion.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/message.h"
40 #include "libpspp/string-array.h"
41 #include "libpspp/taint.h"
42 #include "math/sort.h"
44 #include "gl/minmax.h"
45 #include "gl/xalloc.h"
48 #define _(msgid) gettext (msgid)
50 enum comb_command_type
60 COMB_FILE, /* Specified on FILE= subcommand. */
61 COMB_TABLE /* Specified on TABLE= subcommand. */
64 /* One FILE or TABLE subcommand. */
68 enum comb_file_type type; /* COMB_FILE or COMB_TABLE. */
69 int start_ofs, end_ofs; /* Lexer offsets. */
72 struct subcase by_vars; /* BY variables in this input file. */
73 struct subcase src, dst; /* Data to copy to output; where to put it. */
74 const struct missing_values **mv; /* Each variable's missing values. */
77 struct file_handle *handle; /* Input file handle. */
78 struct dictionary *dict; /* Input file dictionary. */
79 struct casereader *reader; /* Input data source. */
80 struct ccase *data; /* The current input case. */
81 bool is_minimal; /* Does 'data' have minimum BY values across
83 bool is_sorted; /* Is file presorted on the BY variables? */
88 struct variable *in_var;
93 struct comb_file *files; /* All the files being merged. */
94 size_t n_files; /* Number of files. */
96 struct dictionary *dict; /* Dictionary of output file. */
97 struct subcase by_vars; /* BY variables in the output. */
98 struct casewriter *output; /* Destination for output. */
101 size_t n_var_sources, allocated_var_sources;
103 struct case_matcher *matcher;
106 Only if "first" or "last" is nonnull are the remaining
108 struct variable *first; /* Variable specified on FIRST (if any). */
109 struct variable *last; /* Variable specified on LAST (if any). */
110 struct ccase *buffered_case; /* Case ready for output except that we don't
111 know the value for the LAST var yet. */
112 union value *prev_BY; /* Values of BY vars in buffered_case. */
115 static int combine_files (enum comb_command_type, struct lexer *,
117 static void free_comb_proc (struct comb_proc *);
119 static void close_all_comb_files (struct comb_proc *);
120 static bool merge_dictionary (struct comb_proc *, struct lexer *,
123 static void execute_update (struct comb_proc *);
124 static void execute_match_files (struct comb_proc *);
125 static void execute_add_files (struct comb_proc *);
127 static bool create_flag_var (struct lexer *lexer, const char *subcommand_name,
128 const char *var_name, int var_ofs,
129 struct dictionary *, struct variable **);
130 static void output_case (struct comb_proc *, struct ccase *, union value *by);
131 static void output_buffered_case (struct comb_proc *);
134 cmd_add_files (struct lexer *lexer, struct dataset *ds)
136 return combine_files (COMB_ADD, lexer, ds);
140 cmd_match_files (struct lexer *lexer, struct dataset *ds)
142 return combine_files (COMB_MATCH, lexer, ds);
146 cmd_update (struct lexer *lexer, struct dataset *ds)
148 return combine_files (COMB_UPDATE, lexer, ds);
152 combine_files (enum comb_command_type command,
153 struct lexer *lexer, struct dataset *ds)
155 struct comb_proc proc = {
156 .dict = dict_create (get_default_encoding ()),
160 bool saw_sort = false;
161 struct casereader *active_file = NULL;
163 char *first_name = NULL;
165 char *last_name = NULL;
168 struct taint *taint = NULL;
170 size_t table_idx = SIZE_MAX;
171 int sort_ofs = INT_MAX;
172 size_t allocated_files = 0;
174 dict_set_case_limit (proc.dict, dict_get_case_limit (dataset_dict (ds)));
176 lex_match (lexer, T_SLASH);
179 int start_ofs = lex_ofs (lexer);
180 enum comb_file_type type;
181 if (lex_match_id (lexer, "FILE"))
183 else if (command == COMB_MATCH && lex_match_id (lexer, "TABLE"))
186 table_idx = MIN (table_idx, proc.n_files);
190 lex_match (lexer, T_EQUALS);
192 if (proc.n_files >= allocated_files)
193 proc.files = x2nrealloc (proc.files, &allocated_files,
195 struct comb_file *file = &proc.files[proc.n_files++];
196 *file = (struct comb_file) {
198 .start_ofs = start_ofs,
202 if (lex_match (lexer, T_ASTERISK))
204 if (!dataset_has_source (ds))
206 lex_next_error (lexer, -1, -1,
207 _("Cannot specify the active dataset since none "
208 "has been defined."));
212 if (proc_make_temporary_transformations_permanent (ds))
213 lex_next_error (lexer, -1, -1,
214 _("This command may not be used after TEMPORARY "
215 "when the active dataset is an input source. "
216 "Temporary transformations will be made "
219 file->dict = dict_clone (dataset_dict (ds));
223 file->handle = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
224 if (file->handle == NULL)
227 file->reader = any_reader_open_and_decode (file->handle, NULL,
229 if (file->reader == NULL)
232 file->end_ofs = lex_ofs (lexer) - 1;
234 while (lex_match (lexer, T_SLASH))
235 if (lex_match_id (lexer, "RENAME"))
237 if (!parse_dict_rename (lexer, file->dict))
240 else if (lex_match_id (lexer, "IN"))
242 lex_match (lexer, T_EQUALS);
243 if (!lex_force_id (lexer))
248 lex_error (lexer, _("Multiple IN subcommands for a single FILE "
252 file->in_name = xstrdup (lex_tokcstr (lexer));
253 file->in_ofs = lex_ofs (lexer);
256 else if (lex_match_id (lexer, "SORT"))
258 file->is_sorted = false;
260 sort_ofs = MIN (sort_ofs, lex_ofs (lexer) - 1);
263 if (!merge_dictionary (&proc, lexer, file))
267 while (lex_token (lexer) != T_ENDCMD)
269 if (lex_match (lexer, T_BY))
273 lex_sbc_only_once (lexer, "BY");
278 lex_match (lexer, T_EQUALS);
280 const struct variable **by_vars;
281 if (!parse_sort_criteria (lexer, proc.dict, &proc.by_vars,
286 for (size_t i = 0; i < proc.n_files; i++)
288 struct comb_file *file = &proc.files[i];
289 for (size_t j = 0; j < subcase_get_n_fields (&proc.by_vars); j++)
291 const char *name = var_get_name (by_vars[j]);
292 struct variable *var = dict_lookup_var (file->dict, name);
294 subcase_add_var (&file->by_vars, var,
295 subcase_get_direction (&proc.by_vars, j));
299 = file->handle ? fh_get_name (file->handle) : "*";
300 lex_ofs_error (lexer, file->start_ofs, file->end_ofs,
301 _("File %s lacks BY variable %s."),
306 assert (!ok || subcase_conformable (&file->by_vars,
307 &proc.files[0].by_vars));
314 else if (command != COMB_UPDATE && lex_match_id (lexer, "FIRST"))
316 if (first_name != NULL)
318 lex_sbc_only_once (lexer, "FIRST");
322 lex_match (lexer, T_EQUALS);
323 if (!lex_force_id (lexer))
325 first_name = xstrdup (lex_tokcstr (lexer));
326 first_ofs = lex_ofs (lexer);
329 else if (command != COMB_UPDATE && lex_match_id (lexer, "LAST"))
331 if (last_name != NULL)
333 lex_sbc_only_once (lexer, "LAST");
337 lex_match (lexer, T_EQUALS);
338 if (!lex_force_id (lexer))
340 last_name = xstrdup (lex_tokcstr (lexer));
341 last_ofs = lex_ofs (lexer);
344 else if (lex_match_id (lexer, "MAP"))
348 else if (lex_match_id (lexer, "DROP"))
350 if (!parse_dict_drop (lexer, proc.dict))
353 else if (lex_match_id (lexer, "KEEP"))
355 if (!parse_dict_keep (lexer, proc.dict))
360 if (command == COMB_UPDATE)
361 lex_error_expecting (lexer, "BY", "MAP", "DROP", "KEEP");
363 lex_error_expecting (lexer, "BY", "FIRST", "LAST",
364 "MAP", "DROP", "KEEP");
368 if (!lex_match (lexer, T_SLASH) && lex_token (lexer) != T_ENDCMD)
370 lex_end_of_command (lexer);
377 if (command == COMB_UPDATE)
379 lex_sbc_missing (lexer, "BY");
382 if (table_idx != SIZE_MAX)
384 const struct comb_file *table = &proc.files[table_idx];
385 lex_ofs_error (lexer, table->start_ofs, table->end_ofs,
386 _("BY is required when %s is specified."), "TABLE");
391 lex_ofs_error (lexer, sort_ofs, sort_ofs,
392 _("BY is required when %s is specified."), "SORT");
397 /* Add IN, FIRST, and LAST variables to master dictionary. */
398 for (size_t i = 0; i < proc.n_files; i++)
400 struct comb_file *file = &proc.files[i];
401 if (!create_flag_var (lexer, "IN", file->in_name, file->in_ofs,
402 proc.dict, &file->in_var))
405 if (!create_flag_var (lexer, "FIRST", first_name, first_ofs, proc.dict, &proc.first)
406 || !create_flag_var (lexer, "LAST", last_name, last_ofs, proc.dict, &proc.last))
409 dict_delete_scratch_vars (proc.dict);
410 dict_compact_values (proc.dict);
412 /* Set up mapping from each file's variables to master
414 for (size_t i = 0; i < proc.n_files; i++)
416 struct comb_file *file = &proc.files[i];
417 size_t src_n_vars = dict_get_n_vars (file->dict);
419 file->mv = xnmalloc (src_n_vars, sizeof *file->mv);
420 for (size_t j = 0; j < src_n_vars; j++)
422 struct variable *src_var = dict_get_var (file->dict, j);
423 struct variable *dst_var = dict_lookup_var (proc.dict,
424 var_get_name (src_var));
427 size_t n = subcase_get_n_fields (&file->src);
428 file->mv[n] = var_get_missing_values (src_var);
429 subcase_add_var (&file->src, src_var, SC_ASCEND);
430 subcase_add_var (&file->dst, dst_var, SC_ASCEND);
435 proc.output = autopaging_writer_create (dict_get_proto (proc.dict));
436 taint = taint_clone (casewriter_get_taint (proc.output));
438 /* Set up case matcher. */
439 proc.matcher = case_matcher_create ();
440 for (size_t i = 0; i < proc.n_files; i++)
442 struct comb_file *file = &proc.files[i];
443 if (file->reader == NULL)
445 if (active_file == NULL)
447 proc_discard_output (ds);
448 file->reader = active_file = proc_open_filtering (ds, false);
451 file->reader = casereader_clone (active_file);
453 if (!file->is_sorted)
454 file->reader = sort_execute (file->reader, &file->by_vars);
455 taint_propagate (casereader_get_taint (file->reader), taint);
456 file->data = casereader_read (file->reader);
457 if (file->type == COMB_FILE)
458 case_matcher_add_input (proc.matcher, &file->by_vars,
459 &file->data, &file->is_minimal);
462 if (command == COMB_ADD)
463 execute_add_files (&proc);
464 else if (command == COMB_MATCH)
465 execute_match_files (&proc);
466 else if (command == COMB_UPDATE)
467 execute_update (&proc);
471 case_matcher_destroy (proc.matcher);
473 close_all_comb_files (&proc);
474 if (active_file != NULL)
477 dataset_set_dict (ds, proc.dict);
478 dataset_set_source (ds, casewriter_make_reader (proc.output));
482 free_comb_proc (&proc);
487 return taint_destroy (taint) ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
490 if (active_file != NULL)
492 free_comb_proc (&proc);
493 taint_destroy (taint);
496 return CMD_CASCADING_FAILURE;
499 /* Merge the dictionary for file F into master dictionary for PROC. */
501 merge_dictionary (struct comb_proc *proc, struct lexer *lexer,
504 struct dictionary *m = proc->dict;
505 struct dictionary *d = f->dict;
507 if (dict_get_label (m) == NULL)
508 dict_set_label (m, dict_get_label (d));
510 /* FIXME: If the input files have different encodings, then
511 the result is undefined.
512 The correct thing to do would be to convert to an encoding
513 which can cope with all the input files (eg UTF-8).
515 if (strcmp (dict_get_encoding (f->dict), dict_get_encoding (m)))
516 msg (MW, _("Combining files with incompatible encodings. String data may "
517 "not be represented correctly."));
519 const struct string_array *d_docs = dict_get_documents (d);
520 const struct string_array *m_docs = dict_get_documents (m);
524 dict_set_documents (m, d_docs);
527 size_t n = m_docs->n + d_docs->n;
528 struct string_array new_docs = {
529 .strings = xmalloc (n * sizeof *new_docs.strings),
531 for (size_t i = 0; i < m_docs->n; i++)
532 new_docs.strings[new_docs.n++] = m_docs->strings[i];
533 for (size_t i = 0; i < d_docs->n; i++)
534 new_docs.strings[new_docs.n++] = d_docs->strings[i];
536 dict_set_documents (m, &new_docs);
538 free (new_docs.strings);
542 for (size_t i = 0; i < dict_get_n_vars (d); i++)
544 struct variable *dv = dict_get_var (d, i);
545 struct variable *mv = dict_lookup_var (m, var_get_name (dv));
547 if (dict_class_from_id (var_get_name (dv)) == DC_SCRATCH)
552 mv = dict_clone_var_assert (m, dv);
553 if (proc->n_var_sources >= proc->allocated_var_sources)
554 proc->var_sources = x2nrealloc (proc->var_sources,
555 &proc->allocated_var_sources,
556 sizeof *proc->var_sources);
557 proc->var_sources[proc->n_var_sources++] = f - proc->files;
561 if (var_get_width (mv) != var_get_width (dv))
563 const char *var_name = var_get_name (dv);
564 msg (SE, _("Variable %s has different type or width in different "
565 "files."), var_name);
567 for (size_t j = 0; j < 2; j++)
569 const struct variable *ev = !j ? mv : dv;
570 const struct comb_file *ef
571 = !j ? &proc->files[proc->var_sources[var_get_dict_index (mv)]] : f;
572 const char *fn = ef->handle ? fh_get_name (ef->handle) : "*";
574 if (var_is_numeric (ev))
575 lex_ofs_msg (lexer, SN, ef->start_ofs, ef->end_ofs,
576 _("In file %s, %s is numeric."),
579 lex_ofs_msg (lexer, SN, ef->start_ofs, ef->end_ofs,
580 _("In file %s, %s is a string with width %d."),
581 fn, var_name, var_get_width (ev));
587 if (var_has_value_labels (dv) && !var_has_value_labels (mv))
588 var_set_value_labels (mv, var_get_value_labels (dv));
589 if (var_has_missing_values (dv) && !var_has_missing_values (mv))
590 var_set_missing_values (mv, var_get_missing_values (dv));
591 if (var_get_label (dv) && !var_get_label (mv))
592 var_set_label (mv, var_get_label (dv));
599 /* If VAR_NAME is non-NULL, attempts to create a
600 variable named VAR_NAME, with format F1.0, in DICT, and stores
601 a pointer to the variable in *VAR. Returns true if
602 successful, false if the variable name is a duplicate (in
603 which case a message saying that the variable specified on the
604 given SUBCOMMAND is a duplicate is emitted).
606 Does nothing and returns true if VAR_NAME is null. */
608 create_flag_var (struct lexer *lexer, const char *subcommand,
609 const char *var_name, int var_ofs,
610 struct dictionary *dict, struct variable **var)
612 if (var_name != NULL)
614 struct fmt_spec format = fmt_for_output (FMT_F, 1, 0);
615 *var = dict_create_var (dict, var_name, 0);
618 lex_ofs_error (lexer, var_ofs, var_ofs,
619 _("Variable name %s specified on %s subcommand "
620 "duplicates an existing variable name."),
621 var_name, subcommand);
624 var_set_both_formats (*var, format);
631 /* Closes all the files in PROC and frees their associated data. */
633 close_all_comb_files (struct comb_proc *proc)
635 for (size_t i = 0; i < proc->n_files; i++)
637 struct comb_file *file = &proc->files[i];
638 subcase_uninit (&file->by_vars);
639 subcase_uninit (&file->src);
640 subcase_uninit (&file->dst);
642 fh_unref (file->handle);
643 dict_unref (file->dict);
644 casereader_destroy (file->reader);
645 case_unref (file->data);
646 free (file->in_name);
653 /* Frees all the data for the procedure. */
655 free_comb_proc (struct comb_proc *proc)
657 close_all_comb_files (proc);
658 dict_unref (proc->dict);
659 casewriter_destroy (proc->output);
660 case_matcher_destroy (proc->matcher);
663 caseproto_destroy_values (subcase_get_proto (&proc->by_vars),
665 free (proc->prev_BY);
667 subcase_uninit (&proc->by_vars);
668 case_unref (proc->buffered_case);
669 free (proc->var_sources);
672 static bool scan_table (struct comb_file *, union value by[]);
673 static struct ccase *create_output_case (const struct comb_proc *);
674 static void apply_case (const struct comb_file *, struct ccase *);
675 static void apply_nonmissing_case (const struct comb_file *, struct ccase *);
676 static void advance_file (struct comb_file *, union value by[]);
677 static void output_case (struct comb_proc *, struct ccase *, union value by[]);
678 static void output_buffered_case (struct comb_proc *);
680 /* Executes the ADD FILES command. */
682 execute_add_files (struct comb_proc *proc)
686 while (case_matcher_match (proc->matcher, &by))
687 for (size_t i = 0; i < proc->n_files; i++)
689 struct comb_file *file = &proc->files[i];
690 while (file->is_minimal)
692 struct ccase *output = create_output_case (proc);
693 apply_case (file, output);
694 advance_file (file, by);
695 output_case (proc, output, by);
698 output_buffered_case (proc);
701 /* Executes the MATCH FILES command. */
703 execute_match_files (struct comb_proc *proc)
707 while (case_matcher_match (proc->matcher, &by))
709 struct ccase *output = create_output_case (proc);
710 for (size_t i = proc->n_files; i-- > 0;)
712 struct comb_file *file = &proc->files[i];
713 if (file->type == COMB_FILE)
715 if (file->is_minimal)
717 apply_case (file, output);
718 advance_file (file, NULL);
723 if (scan_table (file, by))
724 apply_case (file, output);
727 output_case (proc, output, by);
729 output_buffered_case (proc);
732 /* Executes the UPDATE command. */
734 execute_update (struct comb_proc *proc)
737 size_t n_duplicates = 0;
739 while (case_matcher_match (proc->matcher, &by))
741 struct comb_file *first, *file;
742 struct ccase *output;
744 /* Find first nonnull case in array and make an output case
746 output = create_output_case (proc);
747 for (first = &proc->files[0]; ; first++)
748 if (first->is_minimal)
750 apply_case (first, output);
751 advance_file (first, by);
753 /* Read additional cases and update the output case from
754 them. (Don't update the output case from any duplicate
755 cases in the master file.) */
756 for (file = first + (first == proc->files);
757 file < &proc->files[proc->n_files]; file++)
759 while (file->is_minimal)
761 apply_nonmissing_case (file, output);
762 advance_file (file, by);
765 casewriter_write (proc->output, output);
767 /* Write duplicate cases in the master file directly to the
769 if (first == proc->files && first->is_minimal)
772 while (first->is_minimal)
774 output = create_output_case (proc);
775 apply_case (first, output);
776 advance_file (first, by);
777 casewriter_write (proc->output, output);
783 msg (SW, _("Encountered %zu sets of duplicate cases in the master file."),
787 /* Reads FILE, which must be of type COMB_TABLE, until it
788 encounters a case with BY or greater for its BY variables.
789 Returns true if a case with exactly BY for its BY variables
790 was found, otherwise false. */
792 scan_table (struct comb_file *file, union value by[])
794 while (file->data != NULL)
796 int cmp = subcase_compare_3way_xc (&file->by_vars, by, file->data);
799 case_unref (file->data);
800 file->data = casereader_read (file->reader);
808 /* Creates and returns an output case for PROC, initializing each
809 of its values to system-missing or blanks, except that the
810 values of IN variables are set to 0. */
811 static struct ccase *
812 create_output_case (const struct comb_proc *proc)
814 size_t n_vars = dict_get_n_vars (proc->dict);
815 struct ccase *output = case_create (dict_get_proto (proc->dict));
816 for (size_t i = 0; i < n_vars; i++)
818 struct variable *v = dict_get_var (proc->dict, i);
819 value_set_missing (case_data_rw (output, v), var_get_width (v));
821 for (size_t i = 0; i < proc->n_files; i++)
823 struct comb_file *file = &proc->files[i];
824 if (file->in_var != NULL)
825 *case_num_rw (output, file->in_var) = false;
831 mark_file_used (const struct comb_file *file, struct ccase *output)
833 if (file->in_var != NULL)
834 *case_num_rw (output, file->in_var) = true;
837 /* Copies the data from FILE's case into output case OUTPUT.
838 If FILE has an IN variable, then it is set to 1 in OUTPUT. */
840 apply_case (const struct comb_file *file, struct ccase *output)
842 subcase_copy (&file->src, file->data, &file->dst, output);
843 mark_file_used (file, output);
846 /* Copies the data from FILE's case into output case OUTPUT,
847 skipping values that are missing or all spaces.
849 If FILE has an IN variable, then it is set to 1 in OUTPUT. */
851 apply_nonmissing_case (const struct comb_file *file, struct ccase *output)
853 for (size_t i = 0; i < subcase_get_n_fields (&file->src); i++)
855 const struct subcase_field *src_field = &file->src.fields[i];
856 const struct subcase_field *dst_field = &file->dst.fields[i];
857 const union value *src_value
858 = case_data_idx (file->data, src_field->case_index);
859 int width = src_field->width;
861 if (!mv_is_value_missing (file->mv[i], src_value)
862 && !(width > 0 && value_is_spaces (src_value, width)))
863 value_copy (case_data_rw_idx (output, dst_field->case_index),
866 mark_file_used (file, output);
869 /* Advances FILE to its next case. If BY is nonnull, then FILE's is_minimal
870 member is updated based on whether the new case's BY values still match
873 advance_file (struct comb_file *file, union value by[])
875 case_unref (file->data);
876 file->data = casereader_read (file->reader);
878 file->is_minimal = (file->data != NULL
879 && subcase_equal_cx (&file->by_vars, file->data, by));
882 /* Writes OUTPUT, whose BY values has been extracted into BY, to
883 PROC's output file, first initializing any FIRST or LAST
884 variables in OUTPUT to the correct values. */
886 output_case (struct comb_proc *proc, struct ccase *output, union value by[])
888 if (proc->first == NULL && proc->last == NULL)
889 casewriter_write (proc->output, output);
892 /* It's harder with LAST, because we can't know whether
893 this case is the last in a group until we've prepared
894 the *next* case also. Thus, we buffer the previous
895 output case until the next one is ready. */
897 if (proc->prev_BY != NULL)
899 new_BY = !subcase_equal_xx (&proc->by_vars, proc->prev_BY, by);
900 if (proc->last != NULL)
901 *case_num_rw (proc->buffered_case, proc->last) = new_BY;
902 casewriter_write (proc->output, proc->buffered_case);
907 proc->buffered_case = output;
908 if (proc->first != NULL)
909 *case_num_rw (proc->buffered_case, proc->first) = new_BY;
913 size_t n_values = subcase_get_n_fields (&proc->by_vars);
914 const struct caseproto *proto = subcase_get_proto (&proc->by_vars);
915 if (proc->prev_BY == NULL)
917 proc->prev_BY = xmalloc (n_values * sizeof *proc->prev_BY);
918 caseproto_init_values (proto, proc->prev_BY);
920 caseproto_copy (subcase_get_proto (&proc->by_vars), 0, n_values,
926 /* Writes a trailing buffered case to the output, if FIRST or
929 output_buffered_case (struct comb_proc *proc)
931 if (proc->prev_BY != NULL)
933 if (proc->last != NULL)
934 *case_num_rw (proc->buffered_case, proc->last) = 1.0;
935 casewriter_write (proc->output, proc->buffered_case);
936 proc->buffered_case = NULL;