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
28 #include <unistd.h> /* Required by SunOS4. */
41 #include "value-labels.h"
44 Virtual File Manager (vfm):
46 vfm is used to process data files. It uses the model that
47 data is read from one stream (the data source), processed,
48 then written to another (the data sink). The data source is
49 then deleted and the data sink becomes the data source for the
52 /* Procedure execution data. */
53 struct write_case_data
55 /* Functions to call... */
56 void (*begin_func) (void *); /* ...before data. */
57 int (*proc_func) (struct ccase *, void *); /* ...with data. */
58 void (*end_func) (void *); /* ...after data. */
59 void *func_aux; /* Auxiliary data. */
61 /* Extra auxiliary data. */
65 /* The current active file, from which cases are read. */
66 struct case_source *vfm_source;
68 /* The replacement active file, to which cases are written. */
69 struct case_sink *vfm_sink;
71 /* Nonzero if the case needs to have values deleted before being
72 stored, zero otherwise. */
73 int compaction_necessary;
75 /* Number of values after compaction. */
78 /* Temporary case buffer with enough room for `compaction_nval'
80 struct ccase *compaction_case;
82 /* Nonzero means that we've overflowed our allotted workspace.
83 After that happens once during a session, we always store the
84 active file on disk instead of in memory. (This policy may be
86 static int workspace_overflow = 0;
88 /* Time at which vfm was last invoked. */
89 time_t last_vfm_invocation;
91 /* Number of cases passed to proc_func(). */
92 static int case_count;
95 int n_lag; /* Number of cases to lag. */
96 static int lag_count; /* Number of cases in lag_queue so far. */
97 static int lag_head; /* Index where next case will be added. */
98 static struct ccase **lag_queue; /* Array of n_lag ccase * elements. */
100 static void open_active_file (void);
101 static void close_active_file (struct write_case_data *);
102 static int SPLIT_FILE_proc_func (struct ccase *, void *);
103 static void finish_compaction (void);
104 static void lag_case (void);
105 static int procedure_write_case (struct write_case_data *);
106 static void clear_temp_case (void);
107 static int exclude_this_case (int case_num);
109 /* Public functions. */
111 struct procedure_aux_data
113 size_t cases_written; /* Number of cases written so far. */
116 struct split_aux_data
118 struct ccase *prev_case; /* Data in previous case. */
121 /* Reads all the cases from the active file, transforms them by
122 the active set of transformations, calls PROC_FUNC with CURCASE
123 set to the case, and writes them to a new active file.
125 Divides the active file into zero or more series of one or more
126 cases each. BEGIN_FUNC is called before each series. END_FUNC is
127 called after each series.
129 Arbitrary user-specified data AUX is passed to BEGIN_FUNC,
130 PROC_FUNC, and END_FUNC as auxiliary data. */
132 procedure (void (*begin_func) (void *),
133 int (*proc_func) (struct ccase *curcase, void *),
134 void (*end_func) (void *),
137 static int recursive_call;
139 struct write_case_data procedure_write_data;
140 struct procedure_aux_data proc_aux;
142 struct write_case_data split_file_data;
143 struct split_aux_data split_aux;
146 assert (++recursive_call == 1);
148 proc_aux.cases_written = 0;
150 /* Normally we just use the data passed by the user. */
151 procedure_write_data.begin_func = begin_func;
152 procedure_write_data.proc_func = proc_func;
153 procedure_write_data.end_func = end_func;
154 procedure_write_data.func_aux = func_aux;
155 procedure_write_data.aux = &proc_aux;
157 /* Under SPLIT FILE, we add a layer of indirection. */
158 split = dict_get_split_cnt (default_dict) > 0;
161 split_file_data = procedure_write_data;
162 split_file_data.aux = &split_aux;
164 split_aux.prev_case = xmalloc (dict_get_case_size (default_dict));
166 procedure_write_data.begin_func = NULL;
167 procedure_write_data.proc_func = SPLIT_FILE_proc_func;
168 procedure_write_data.end_func = end_func;
169 procedure_write_data.func_aux = &split_file_data;
172 last_vfm_invocation = time (NULL);
175 if (vfm_source != NULL)
176 vfm_source->class->read (vfm_source,
177 procedure_write_case, &procedure_write_data);
178 close_active_file (&procedure_write_data);
181 free (split_aux.prev_case);
183 assert (--recursive_call == 0);
186 /* Active file processing support. Subtly different semantics from
189 static int process_active_file_write_case (struct write_case_data *data);
191 /* The casefunc might want us to stop calling it. */
192 static int not_canceled;
194 /* Reads all the cases from the active file and passes them one-by-one
195 to CASEFUNC in temp_case. Before any cases are passed, calls
196 BEGIN_FUNC. After all the cases have been passed, calls END_FUNC.
197 BEGIN_FUNC, CASEFUNC, and END_FUNC can write temp_case to the output
198 file by calling process_active_file_output_case().
200 process_active_file() ignores TEMPORARY, SPLIT FILE, and N. */
202 process_active_file (void (*begin_func) (void *),
203 int (*casefunc) (struct ccase *curcase, void *),
204 void (*end_func) (void *),
207 struct write_case_data process_active_write_data;
209 process_active_write_data.begin_func = begin_func;
210 process_active_write_data.proc_func = casefunc;
211 process_active_write_data.end_func = end_func;
212 process_active_write_data.func_aux = func_aux;
217 begin_func (func_aux);
218 if (vfm_source != NULL)
219 vfm_source->class->read (vfm_source, process_active_file_write_case,
220 &process_active_write_data);
222 close_active_file (&process_active_write_data);
225 /* Pass the current case to casefunc. */
227 process_active_file_write_case (struct write_case_data *data)
229 /* Index of current transformation. */
232 for (cur_trns = f_trns ; cur_trns != temp_trns; )
236 code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case,
241 /* Next transformation. */
245 /* Delete this case. */
248 /* Go to that transformation. */
257 /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
258 if (not_canceled && !exclude_this_case (case_count + 1))
259 not_canceled = data->proc_func (temp_case, data->func_aux);
269 /* Write temp_case to the active file. */
271 process_active_file_output_case (void)
273 vfm_sink->class->write (vfm_sink, temp_case);
276 /* Opening the active file. */
278 /* It might be usefully noted that the following several functions are
279 given in the order that they are called by open_active_file(). */
281 /* Prepare to write to the replacement active file. */
283 prepare_for_writing (void)
285 /* FIXME: If ALL the conditions listed below hold true, then the
286 replacement active file is guaranteed to be identical to the
287 original active file:
289 1. TEMPORARY was the first transformation, OR, there were no
290 transformations at all.
292 2. Input is not coming from an input program.
294 3. Compaction is not necessary.
296 So, in this case, we shouldn't have to replace the active
297 file--it's just a waste of time and space. */
299 if (vfm_sink == NULL)
301 if (workspace_overflow)
302 vfm_sink = create_case_sink (&disk_sink_class, NULL);
304 vfm_sink = create_case_sink (&memory_sink_class, NULL);
308 /* Arrange for compacting the output cases for storage. */
310 arrange_compaction (void)
312 int count_values = 0;
317 /* Count up the number of `value's that will be output. */
318 for (i = 0; i < dict_get_var_cnt (temp_dict); i++)
320 struct variable *v = dict_get_var (temp_dict, i);
322 if (v->name[0] != '#')
325 count_values += v->nv;
328 assert (temporary == 2
329 || count_values <= dict_get_next_value_idx (temp_dict));
332 /* Compaction is only necessary if the number of `value's to output
333 differs from the number already present. */
334 compaction_nval = count_values;
335 if (temporary == 2 || count_values != dict_get_next_value_idx (temp_dict))
336 compaction_necessary = 1;
338 compaction_necessary = 0;
340 if (vfm_sink->class->open != NULL)
341 vfm_sink->class->open (vfm_sink);
344 /* Prepares the temporary case and compaction case. */
346 make_temp_case (void)
348 temp_case = xmalloc (dict_get_case_size (default_dict));
350 if (compaction_necessary)
351 compaction_case = xmalloc (sizeof (struct ccase)
352 + sizeof (union value) * (compaction_nval - 1));
356 /* Returns the name of the variable that owns the index CCASE_INDEX
359 index_to_varname (int ccase_index)
363 for (i = 0; i < default_dict.nvar; i++)
365 struct variable *v = default_dict.var[i];
367 if (ccase_index >= v->fv && ccase_index < v->fv + v->nv)
368 return default_dict.var[i]->name;
374 /* Initializes temp_case from the vectors that say which `value's
375 need to be initialized just once, and which ones need to be
376 re-initialized before every case. */
378 vector_initialization (void)
380 size_t var_cnt = dict_get_var_cnt (default_dict);
383 for (i = 0; i < var_cnt; i++)
385 struct variable *v = dict_get_var (default_dict, i);
387 if (v->type == NUMERIC)
390 temp_case->data[v->fv].f = 0.0;
392 temp_case->data[v->fv].f = SYSMIS;
395 memset (temp_case->data[v->fv].s, ' ', v->width);
399 /* Sets all the lag-related variables based on value of n_lag. */
410 lag_queue = xmalloc (n_lag * sizeof *lag_queue);
411 for (i = 0; i < n_lag; i++)
412 lag_queue[i] = xmalloc (dict_get_case_size (temp_dict));
415 /* There is a lot of potential confusion in the vfm and related
416 routines over the number of `value's at each stage of the process.
417 Here is each nval count, with explanation, as set up by
420 temp_dict->nval: Number of `value's in the cases after the
421 transformations leading up to TEMPORARY have been performed.
423 compaction_nval: Number of `value's in the cases after the
424 transformations leading up to TEMPORARY have been performed
425 and the case has been compacted by compact_case(), if
426 compaction is necessary. This the number of `value's in the
427 cases saved by the sink stream. (However, note that the cases
428 passed to the sink stream have not yet been compacted. It is
429 the responsibility of the data sink to call compact_case().)
430 `compaction' becomes the new value of default_dict.nval after
431 the procedure is completed.
433 default_dict.nval: This is often an alias for temp_dict->nval.
434 As such it can really have no separate existence until the
435 procedure is complete. For this reason it should *not* be
436 referenced inside the execution of a procedure. */
437 /* Makes all preparations for reading from the data source and writing
440 open_active_file (void)
442 /* Sometimes we want to refer to the dictionary that applies to the
443 data actually written to the sink. This is either temp_dict or
444 default_dict. However, if TEMPORARY is not on, then temp_dict
445 does not apply. So, we can set temp_dict to default_dict in this
450 temp_dict = default_dict;
453 /* No cases passed to the procedure yet. */
457 prepare_for_writing ();
458 arrange_compaction ();
460 vector_initialization ();
461 discard_ctl_stack ();
465 /* Closes the active file. */
467 close_active_file (struct write_case_data *data)
469 /* Close the current case group. */
470 if (case_count && data->end_func != NULL)
471 data->end_func (data->func_aux);
473 /* Stop lagging (catch up?). */
478 for (i = 0; i < n_lag; i++)
484 /* Assume the dictionary from right before TEMPORARY, if any. Turn
488 dict_destroy (default_dict);
489 default_dict = temp_dict;
493 /* Finish compaction. */
494 if (compaction_necessary)
495 finish_compaction ();
497 /* Old data sink --> New data source. */
498 if (vfm_source != NULL)
500 if (vfm_source->class->destroy != NULL)
501 vfm_source->class->destroy (vfm_source);
505 vfm_source = vfm_sink->class->make_source (vfm_sink);
507 /* Old data sink is gone now. */
511 /* Cancel TEMPORARY. */
514 /* Free temporary cases. */
518 free (compaction_case);
519 compaction_case = NULL;
521 /* Cancel PROCESS IF. */
522 expr_free (process_if_expr);
523 process_if_expr = NULL;
525 /* Cancel FILTER if temporary. */
526 if (dict_get_filter (default_dict) != NULL && !FILTER_before_TEMPORARY)
527 dict_set_filter (default_dict, NULL);
529 /* Cancel transformations. */
530 cancel_transformations ();
532 /* Turn off case limiter. */
533 dict_set_case_limit (default_dict, 0);
535 /* Clear VECTOR vectors. */
536 dict_clear_vectors (default_dict);
539 /* Disk case stream. */
541 /* Information about disk sink or source. */
542 struct disk_stream_info
544 FILE *file; /* Output file. */
545 size_t case_cnt; /* Number of cases written so far. */
546 size_t case_size; /* Number of bytes in case. */
549 /* Initializes the disk sink. */
551 disk_sink_create (struct case_sink *sink)
553 struct disk_stream_info *info = xmalloc (sizeof *info);
554 info->file = tmpfile ();
556 info->case_size = compaction_nval;
558 if (info->file == NULL)
560 msg (ME, _("An error occurred attempting to create a temporary "
561 "file for use as the active file: %s."),
567 /* Writes temp_case to the disk sink. */
569 disk_sink_write (struct case_sink *sink, struct ccase *c)
571 struct disk_stream_info *info = sink->aux;
572 union value *src_case;
574 if (compaction_necessary)
576 compact_case (compaction_case, c);
577 src_case = compaction_case->data;
579 else src_case = c->data;
582 if (fwrite (src_case, sizeof *src_case * compaction_nval, 1,
585 msg (ME, _("An error occurred while attempting to write to a "
586 "temporary file used as the active file: %s."),
592 /* Destroys the sink's internal data. */
594 disk_sink_destroy (struct case_sink *sink)
596 struct disk_stream_info *info = sink->aux;
597 if (info->file != NULL)
601 /* Closes and destroys the sink and returns a disk source to read
602 back the written data. */
603 static struct case_source *
604 disk_sink_make_source (struct case_sink *sink)
606 struct disk_stream_info *info = sink->aux;
608 /* Rewind the file. */
609 assert (info->file != NULL);
610 if (fseek (info->file, 0, SEEK_SET) != 0)
612 msg (ME, _("An error occurred while attempting to rewind a "
613 "temporary file used as the active file: %s."),
618 return create_case_source (&disk_source_class, info);
622 const struct case_sink_class disk_sink_class =
628 disk_sink_make_source,
633 /* Returns the number of cases that will be read by
634 disk_source_read(). */
636 disk_source_count (const struct case_source *source)
638 struct disk_stream_info *info = source->aux;
640 return info->case_cnt;
643 /* Reads all cases from the disk source and passes them one by one to
646 disk_source_read (struct case_source *source,
647 write_case_func *write_case, write_case_data wc_data)
649 struct disk_stream_info *info = source->aux;
652 for (i = 0; i < info->case_cnt; i++)
654 if (!fread (temp_case, info->case_size, 1, info->file))
656 msg (ME, _("An error occurred while attempting to read from "
657 "a temporary file created for the active file: %s."),
663 if (!write_case (wc_data))
668 /* Destroys the source's internal data. */
670 disk_source_destroy (struct case_source *source)
672 struct disk_stream_info *info = source->aux;
673 if (info->file != NULL)
679 const struct case_source_class disk_source_class =
687 /* Memory case stream. */
689 /* Memory sink data. */
690 struct memory_sink_info
692 size_t case_cnt; /* Number of cases. */
693 size_t case_size; /* Case size in bytes. */
694 int max_cases; /* Maximum cases before switching to disk. */
695 struct case_list *head; /* First case in list. */
696 struct case_list *tail; /* Last case in list. */
699 /* Memory source data. */
700 struct memory_source_info
702 size_t case_cnt; /* Number of cases. */
703 size_t case_size; /* Case size in bytes. */
704 struct case_list *cases; /* List of cases. */
708 memory_sink_create (struct case_sink *sink)
710 struct memory_sink_info *info;
712 sink->aux = info = xmalloc (sizeof *info);
714 assert (compaction_nval > 0);
716 info->case_size = compaction_nval * sizeof (union value);
717 info->max_cases = set_max_workspace / info->case_size;
718 info->head = info->tail = NULL;
722 memory_sink_write (struct case_sink *sink, struct ccase *c)
724 struct memory_sink_info *info = sink->aux;
726 struct case_list *new_case;
728 case_size = sizeof (struct case_list)
729 + ((compaction_nval - 1) * sizeof (union value));
730 new_case = malloc (case_size);
732 /* If we've got memory to spare then add it to the linked list. */
733 if (info->case_cnt <= info->max_cases && new_case != NULL)
737 /* Append case to linked list. */
738 new_case->next = NULL;
739 if (info->head != NULL)
740 info->tail->next = new_case;
742 info->head = new_case;
743 info->tail = new_case;
745 /* Copy data into case. */
746 if (compaction_necessary)
747 compact_case (&new_case->c, c);
749 memcpy (&new_case->c, c, sizeof (union value) * compaction_nval);
753 /* Out of memory. Write the active file to disk. */
754 struct case_list *cur, *next;
756 /* Notify the user. */
758 msg (MW, _("Virtual memory exhausted. Writing active file "
761 msg (MW, _("Workspace limit of %d KB (%d cases at %d bytes each) "
762 "overflowed. Writing active file to disk."),
763 set_max_workspace / 1024, info->max_cases,
764 compaction_nval * sizeof (union value));
768 /* Switch to a disk sink. */
769 vfm_sink = create_case_sink (&disk_sink_class, NULL);
770 vfm_sink->class->open (vfm_sink);
771 workspace_overflow = 1;
773 /* Write the cases to disk and destroy them. We can't call
774 vfm->sink->write() because of compaction. */
775 for (cur = info->head; cur; cur = next)
778 if (fwrite (cur->c.data, sizeof (union value) * compaction_nval, 1,
781 msg (ME, _("An error occurred while attempting to "
782 "write to a temporary file created as the "
790 /* Write the current case to disk. */
791 vfm_sink->class->write (vfm_sink, c);
795 /* If the data is stored in memory, causes it to be written to disk.
796 To be called only *between* procedure()s, not within them. */
798 write_active_file_to_disk (void)
800 if (case_source_is_class (vfm_source, &memory_source_class))
802 struct memory_source_info *info = vfm_source->aux;
804 /* Switch to a disk sink. */
805 vfm_sink = create_case_sink (&disk_sink_class, NULL);
806 vfm_sink->class->open (vfm_sink);
807 workspace_overflow = 1;
809 /* Write the cases to disk and destroy them. We can't call
810 vfm->sink->write() because of compaction. */
812 struct case_list *cur, *next;
814 for (cur = info->cases; cur; cur = next)
817 if (fwrite (cur->c.data, sizeof *cur->c.data * compaction_nval, 1,
820 msg (ME, _("An error occurred while attempting to "
821 "write to a temporary file created as the "
830 vfm_source = vfm_sink->class->make_source (vfm_sink);
835 /* Destroy all memory sink data. */
837 memory_sink_destroy (struct case_sink *sink)
839 struct memory_sink_info *info = sink->aux;
840 struct case_list *cur, *next;
842 for (cur = info->head; cur; cur = next)
850 /* Switch the memory stream from sink to source mode. */
851 static struct case_source *
852 memory_sink_make_source (struct case_sink *sink)
854 struct memory_sink_info *sink_info = sink->aux;
855 struct memory_source_info *source_info;
857 source_info = xmalloc (sizeof *source_info);
858 source_info->case_cnt = sink_info->case_cnt;
859 source_info->case_size = sink_info->case_size;
860 source_info->cases = sink_info->head;
864 return create_case_source (&memory_source_class, source_info);
867 const struct case_sink_class memory_sink_class =
873 memory_sink_make_source,
876 /* Returns the number of cases in the source. */
878 memory_source_count (const struct case_source *source)
880 struct memory_source_info *info = source->aux;
882 return info->case_cnt;
885 /* Reads the case stream from memory and passes it to write_case(). */
887 memory_source_read (struct case_source *source,
888 write_case_func *write_case, write_case_data wc_data)
890 struct memory_source_info *info = source->aux;
892 while (info->cases != NULL)
894 struct case_list *iter = info->cases;
895 info->cases = iter->next;
896 memcpy (temp_case, &iter->c, info->case_size);
899 if (!write_case (wc_data))
904 /* Destroy all memory source data. */
906 memory_source_destroy (struct case_source *source)
908 struct memory_source_info *info = source->aux;
909 struct case_list *cur, *next;
911 for (cur = info->cases; cur; cur = next)
920 memory_source_get_cases (const struct case_source *source)
922 struct memory_source_info *info = source->aux;
928 memory_source_set_cases (const struct case_source *source,
929 struct case_list *cases)
931 struct memory_source_info *info = source->aux;
937 const struct case_source_class memory_source_class =
942 memory_source_destroy,
945 /* Add temp_case to the lag queue. */
949 if (lag_count < n_lag)
951 memcpy (lag_queue[lag_head], temp_case,
952 dict_get_case_size (temp_dict));
953 if (++lag_head >= n_lag)
957 /* Returns a pointer to the lagged case from N_BEFORE cases before the
958 current one, or NULL if there haven't been that many cases yet. */
960 lagged_case (int n_before)
962 assert (n_before <= n_lag);
963 if (n_before > lag_count)
967 int index = lag_head - n_before;
970 return lag_queue[index];
974 /* Transforms temp_case and writes it to the replacement active file
975 if advisable. Returns nonzero if more cases can be accepted, zero
976 otherwise. Do not call this function again after it has returned
979 procedure_write_case (write_case_data wc_data)
981 struct procedure_aux_data *proc_aux = wc_data->aux;
983 /* Index of current transformation. */
986 /* Return value: whether it's reasonable to write any more cases. */
992 /* Output the case if this is temp_trns. */
993 if (cur_trns == temp_trns)
1000 vfm_sink->class->write (vfm_sink, temp_case);
1002 proc_aux->cases_written++;
1003 case_limit = dict_get_case_limit (default_dict);
1004 if (case_limit != 0 && proc_aux->cases_written >= case_limit)
1009 if (cur_trns >= n_trns)
1012 /* Decide which transformation should come next. */
1016 code = t_trns[cur_trns]->proc (t_trns[cur_trns], temp_case,
1017 proc_aux->cases_written + 1);
1021 /* Next transformation. */
1025 /* Delete this case. */
1028 /* Go to that transformation. */
1035 /* Call the beginning of group function. */
1036 if (!case_count && wc_data->begin_func != NULL)
1037 wc_data->begin_func (wc_data->func_aux);
1039 /* Call the procedure if there is one and FILTER and PROCESS IF
1040 don't prohibit it. */
1041 if (wc_data->proc_func != NULL
1042 && !exclude_this_case (proc_aux->cases_written + 1))
1043 wc_data->proc_func (temp_case, wc_data->func_aux);
1050 /* Return previously determined value. */
1054 /* Clears the variables in the temporary case that need to be
1055 cleared between processing cases. */
1057 clear_temp_case (void)
1059 /* FIXME? This is linear in the number of variables, but
1060 doesn't need to be, so it's an easy optimization target. */
1061 size_t var_cnt = dict_get_var_cnt (default_dict);
1064 for (i = 0; i < var_cnt; i++)
1066 struct variable *v = dict_get_var (default_dict, i);
1067 if (v->init && v->reinit)
1069 if (v->type == NUMERIC)
1070 temp_case->data[v->fv].f = SYSMIS;
1072 memset (temp_case->data[v->fv].s, ' ', v->width);
1077 /* Returns nonzero if this case (numbered CASE_NUM) should be
1078 exclude as specified on FILTER or PROCESS IF, otherwise
1081 exclude_this_case (int case_num)
1084 struct variable *filter_var = dict_get_filter (default_dict);
1085 if (filter_var != NULL)
1087 double f = temp_case->data[filter_var->fv].f;
1088 if (f == 0.0 || f == SYSMIS || is_num_user_missing (f, filter_var))
1093 if (process_if_expr != NULL
1094 && expr_evaluate (process_if_expr, temp_case, case_num, NULL) != 1.0)
1100 /* Appends TRNS to t_trns[], the list of all transformations to be
1101 performed on data as it is read from the active file. */
1103 add_transformation (struct trns_header * trns)
1105 if (n_trns >= m_trns)
1108 t_trns = xrealloc (t_trns, sizeof *t_trns * m_trns);
1110 t_trns[n_trns] = trns;
1111 trns->index = n_trns++;
1114 /* Cancels all active transformations, including any transformations
1115 created by the input program. */
1117 cancel_transformations (void)
1120 for (i = 0; i < n_trns; i++)
1122 if (t_trns[i]->free)
1123 t_trns[i]->free (t_trns[i]);
1126 n_trns = f_trns = 0;
1134 /* Dumps out the values of all the split variables for the case C. */
1136 dump_splits (struct ccase *c)
1138 struct variable *const *split;
1139 struct tab_table *t;
1143 split_cnt = dict_get_split_cnt (default_dict);
1144 t = tab_create (3, split_cnt + 1, 0);
1145 tab_dim (t, tab_natural_dimensions);
1146 tab_vline (t, TAL_1 | TAL_SPACING, 1, 0, split_cnt);
1147 tab_vline (t, TAL_1 | TAL_SPACING, 2, 0, split_cnt);
1148 tab_text (t, 0, 0, TAB_NONE, _("Variable"));
1149 tab_text (t, 1, 0, TAB_LEFT, _("Value"));
1150 tab_text (t, 2, 0, TAB_LEFT, _("Label"));
1151 split = dict_get_split_vars (default_dict);
1152 for (i = 0; i < split_cnt; i++)
1154 struct variable *v = split[i];
1156 const char *val_lab;
1158 assert (v->type == NUMERIC || v->type == ALPHA);
1159 tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", v->name);
1161 data_out (temp_buf, &v->print, &c->data[v->fv]);
1163 temp_buf[v->print.w] = 0;
1164 tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", v->print.w, temp_buf);
1166 val_lab = val_labs_find (v->val_labs, c->data[v->fv]);
1168 tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
1170 tab_flags (t, SOMF_NO_TITLE);
1174 /* This proc_func is substituted for the user-supplied proc_func when
1175 SPLIT FILE is active. This function forms a wrapper around that
1176 proc_func by dividing the input into series. */
1178 SPLIT_FILE_proc_func (struct ccase *c, void *data_)
1180 struct write_case_data *data = data_;
1181 struct split_aux_data *split_aux = data->aux;
1182 struct variable *const *split;
1186 /* The first case always begins a new series. We also need to
1187 preserve the values of the case for later comparison. */
1188 if (case_count == 0)
1190 memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict));
1193 if (data->begin_func != NULL)
1194 data->begin_func (data->func_aux);
1196 return data->proc_func (c, data->func_aux);
1199 /* Compare the value of each SPLIT FILE variable to the values on
1200 the previous case. */
1201 split = dict_get_split_vars (default_dict);
1202 split_cnt = dict_get_split_cnt (default_dict);
1203 for (i = 0; i < split_cnt; i++)
1205 struct variable *v = split[i];
1210 if (c->data[v->fv].f != split_aux->prev_case->data[v->fv].f)
1214 if (memcmp (c->data[v->fv].s,
1215 split_aux->prev_case->data[v->fv].s, v->width))
1222 return data->proc_func (c, data->func_aux);
1225 /* The values of the SPLIT FILE variable are different from the
1226 values on the previous case. That means that it's time to begin
1228 if (data->end_func != NULL)
1229 data->end_func (data->func_aux);
1231 if (data->begin_func != NULL)
1232 data->begin_func (data->func_aux);
1233 memcpy (split_aux->prev_case, c, dict_get_case_size (default_dict));
1234 return data->proc_func (c, data->func_aux);
1237 /* Case compaction. */
1239 /* Copies case SRC to case DEST, compacting it in the process. */
1241 compact_case (struct ccase *dest, const struct ccase *src)
1247 assert (compaction_necessary);
1251 if (dest != compaction_case)
1252 memcpy (dest, compaction_case, sizeof (union value) * compaction_nval);
1256 /* Copy all the variables except the scratch variables from SRC to
1258 var_cnt = dict_get_var_cnt (default_dict);
1259 for (i = 0; i < var_cnt; i++)
1261 struct variable *v = dict_get_var (default_dict, i);
1263 if (v->name[0] == '#')
1266 if (v->type == NUMERIC)
1267 dest->data[nval++] = src->data[v->fv];
1270 int w = DIV_RND_UP (v->width, sizeof (union value));
1272 memcpy (&dest->data[nval], &src->data[v->fv], w * sizeof (union value));
1278 /* Reassigns `fv' for each variable. Deletes scratch variables. */
1280 finish_compaction (void)
1284 for (i = 0; i < dict_get_var_cnt (default_dict); )
1286 struct variable *v = dict_get_var (default_dict, i);
1288 if (v->name[0] == '#')
1289 dict_delete_var (default_dict, v);
1293 dict_compact_values (default_dict);
1296 struct case_source *
1297 create_case_source (const struct case_source_class *class, void *aux)
1299 struct case_source *source = xmalloc (sizeof *source);
1300 source->class = class;
1306 case_source_is_complex (const struct case_source *source)
1308 return source != NULL && (source->class == &input_program_source_class
1309 || source->class == &file_type_source_class);
1313 case_source_is_class (const struct case_source *source,
1314 const struct case_source_class *class)
1316 return source != NULL && source->class == class;
1320 create_case_sink (const struct case_sink_class *class, void *aux)
1322 struct case_sink *sink = xmalloc (sizeof *sink);
1323 sink->class = class;