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 struct ccase *create_trns_case (struct dictionary *dict);
101 static void open_active_file (void);
102 static void close_active_file (struct write_case_data *);
103 static int SPLIT_FILE_proc_func (struct ccase *, void *);
104 static void finish_compaction (void);
105 static void lag_case (const struct ccase *);
106 static write_case_func procedure_write_case;
107 static void clear_case (struct ccase *);
108 static int exclude_this_case (const struct ccase *, int case_num);
110 /* Public functions. */
112 /* Auxiliary data for executing a procedure. */
113 struct procedure_aux_data
115 struct ccase *trns_case; /* Case used for transformations. */
116 size_t cases_written; /* Number of cases written so far. */
119 /* Auxiliary data for SPLIT FILE. */
120 struct split_aux_data
122 struct ccase *prev_case; /* Data in previous case. */
125 /* Reads all the cases from the active file, transforms them by
126 the active set of transformations, passes each of them to
127 PROC_FUNC, and writes them to a new active file.
129 Divides the active file into zero or more series of one or more
130 cases each. BEGIN_FUNC is called before each series. END_FUNC is
131 called after each series.
133 Arbitrary user-specified data AUX is passed to BEGIN_FUNC,
134 PROC_FUNC, and END_FUNC as auxiliary data. */
136 procedure (void (*begin_func) (void *),
137 int (*proc_func) (struct ccase *, void *),
138 void (*end_func) (void *),
141 static int recursive_call;
143 struct write_case_data procedure_write_data;
144 struct procedure_aux_data proc_aux;
146 struct write_case_data split_file_data;
147 struct split_aux_data split_aux;
150 assert (++recursive_call == 1);
152 proc_aux.cases_written = 0;
153 proc_aux.trns_case = create_trns_case (default_dict);
155 /* Normally we just use the data passed by the user. */
156 procedure_write_data.begin_func = begin_func;
157 procedure_write_data.proc_func = proc_func;
158 procedure_write_data.end_func = end_func;
159 procedure_write_data.func_aux = func_aux;
160 procedure_write_data.aux = &proc_aux;
162 /* Under SPLIT FILE, we add a layer of indirection. */
163 split = dict_get_split_cnt (default_dict) > 0;
166 split_file_data = procedure_write_data;
167 split_file_data.aux = &split_aux;
169 split_aux.prev_case = xmalloc (dict_get_case_size (default_dict));
171 procedure_write_data.begin_func = NULL;
172 procedure_write_data.proc_func = SPLIT_FILE_proc_func;
173 procedure_write_data.end_func = end_func;
174 procedure_write_data.func_aux = &split_file_data;
177 last_vfm_invocation = time (NULL);
180 if (vfm_source != NULL)
181 vfm_source->class->read (vfm_source,
183 procedure_write_case, &procedure_write_data);
184 close_active_file (&procedure_write_data);
187 free (split_aux.prev_case);
189 free (proc_aux.trns_case);
191 assert (--recursive_call == 0);
194 /* Active file processing support. Subtly different semantics from
197 static write_case_func process_active_file_write_case;
199 /* The case_func might want us to stop calling it. */
200 static int not_canceled;
202 /* Reads all the cases from the active file and passes them
203 one-by-one to CASE_FUNC. Before any cases are passed, calls
204 BEGIN_FUNC. After all the cases have been passed, calls
205 END_FUNC. BEGIN_FUNC, CASE_FUNC, and END_FUNC can write to
206 the output file by calling process_active_file_output_case().
208 process_active_file() ignores TEMPORARY, SPLIT FILE, and N. */
210 process_active_file (void (*begin_func) (void *),
211 int (*case_func) (struct ccase *, void *),
212 void (*end_func) (void *),
215 struct procedure_aux_data proc_aux;
216 struct write_case_data process_active_write_data;
218 proc_aux.cases_written = 0;
219 proc_aux.trns_case = create_trns_case (default_dict);
221 process_active_write_data.begin_func = begin_func;
222 process_active_write_data.proc_func = case_func;
223 process_active_write_data.end_func = end_func;
224 process_active_write_data.func_aux = func_aux;
225 process_active_write_data.aux = &proc_aux;
230 begin_func (func_aux);
231 if (vfm_source != NULL)
232 vfm_source->class->read (vfm_source, proc_aux.trns_case,
233 process_active_file_write_case,
234 &process_active_write_data);
236 close_active_file (&process_active_write_data);
239 /* Pass the current case to case_func. */
241 process_active_file_write_case (struct write_case_data *wc_data)
243 struct procedure_aux_data *proc_aux = wc_data->aux;
244 int cur_trns; /* Index of current transformation. */
246 for (cur_trns = f_trns; cur_trns != temp_trns; )
250 code = t_trns[cur_trns]->proc (t_trns[cur_trns], proc_aux->trns_case,
255 /* Next transformation. */
259 /* Delete this case. */
262 /* Go to that transformation. */
269 lag_case (proc_aux->trns_case);
271 /* Call the procedure if FILTER and PROCESS IF don't prohibit it. */
272 if (not_canceled && !exclude_this_case (proc_aux->trns_case, case_count + 1))
273 not_canceled = wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux);
278 clear_case (proc_aux->trns_case);
283 /* Write the given case to the active file. */
285 process_active_file_output_case (const struct ccase *c)
287 vfm_sink->class->write (vfm_sink, c);
290 /* Creates and returns a case, initializing it from the vectors
291 that say which `value's need to be initialized just once, and
292 which ones need to be re-initialized before every case. */
293 static struct ccase *
294 create_trns_case (struct dictionary *dict)
296 struct ccase *c = xmalloc (dict_get_case_size (dict));
297 size_t var_cnt = dict_get_var_cnt (dict);
300 for (i = 0; i < var_cnt; i++)
302 struct variable *v = dict_get_var (dict, i);
304 if (v->type == NUMERIC)
307 c->data[v->fv].f = 0.0;
309 c->data[v->fv].f = SYSMIS;
312 memset (c->data[v->fv].s, ' ', v->width);
317 /* Opening the active file. */
319 /* It might be usefully noted that the following several functions are
320 given in the order that they are called by open_active_file(). */
322 /* Prepare to write to the replacement active file. */
324 prepare_for_writing (void)
326 if (vfm_sink == NULL)
328 if (workspace_overflow)
329 vfm_sink = create_case_sink (&disk_sink_class, NULL);
331 vfm_sink = create_case_sink (&memory_sink_class, NULL);
335 /* Arrange for compacting the output cases for storage. */
337 arrange_compaction (void)
339 int count_values = 0;
344 /* Count up the number of `value's that will be output. */
345 for (i = 0; i < dict_get_var_cnt (temp_dict); i++)
347 struct variable *v = dict_get_var (temp_dict, i);
349 if (v->name[0] != '#')
352 count_values += v->nv;
355 assert (temporary == 2
356 || count_values <= dict_get_next_value_idx (temp_dict));
359 /* Compaction is only necessary if the number of `value's to output
360 differs from the number already present. */
361 compaction_nval = count_values;
362 if (temporary == 2 || count_values != dict_get_next_value_idx (temp_dict))
363 compaction_necessary = 1;
365 compaction_necessary = 0;
367 if (vfm_sink->class->open != NULL)
368 vfm_sink->class->open (vfm_sink);
370 if (compaction_necessary)
371 compaction_case = xmalloc (sizeof (struct ccase)
372 + sizeof (union value) * (compaction_nval - 1));
377 /* Returns the name of the variable that owns the index CCASE_INDEX
380 index_to_varname (int ccase_index)
384 for (i = 0; i < default_dict.nvar; i++)
386 struct variable *v = default_dict.var[i];
388 if (ccase_index >= v->fv && ccase_index < v->fv + v->nv)
389 return default_dict.var[i]->name;
395 /* Sets all the lag-related variables based on value of n_lag. */
406 lag_queue = xmalloc (n_lag * sizeof *lag_queue);
407 for (i = 0; i < n_lag; i++)
408 lag_queue[i] = xmalloc (dict_get_case_size (temp_dict));
411 /* There is a lot of potential confusion in the vfm and related
412 routines over the number of `value's at each stage of the process.
413 Here is each nval count, with explanation, as set up by
416 temp_dict->nval: Number of `value's in the cases after the
417 transformations leading up to TEMPORARY have been performed.
419 compaction_nval: Number of `value's in the cases after the
420 transformations leading up to TEMPORARY have been performed
421 and the case has been compacted by compact_case(), if
422 compaction is necessary. This the number of `value's in the
423 cases saved by the sink stream. (However, note that the cases
424 passed to the sink stream have not yet been compacted. It is
425 the responsibility of the data sink to call compact_case().)
426 `compaction' becomes the new value of default_dict.nval after
427 the procedure is completed.
429 default_dict.nval: This is often an alias for temp_dict->nval.
430 As such it can really have no separate existence until the
431 procedure is complete. For this reason it should *not* be
432 referenced inside the execution of a procedure. */
433 /* Makes all preparations for reading from the data source and writing
436 open_active_file (void)
438 /* Sometimes we want to refer to the dictionary that applies to the
439 data actually written to the sink. This is either temp_dict or
440 default_dict. However, if TEMPORARY is not on, then temp_dict
441 does not apply. So, we can set temp_dict to default_dict in this
446 temp_dict = default_dict;
449 /* No cases passed to the procedure yet. */
453 prepare_for_writing ();
454 arrange_compaction ();
455 discard_ctl_stack ();
459 /* Closes the active file. */
461 close_active_file (struct write_case_data *data)
463 /* Close the current case group. */
464 if (case_count && data->end_func != NULL)
465 data->end_func (data->func_aux);
467 /* Stop lagging (catch up?). */
472 for (i = 0; i < n_lag; i++)
478 /* Assume the dictionary from right before TEMPORARY, if any. Turn
482 dict_destroy (default_dict);
483 default_dict = temp_dict;
487 /* Finish compaction. */
488 if (compaction_necessary)
489 finish_compaction ();
491 /* Old data sink --> New data source. */
492 if (vfm_source != NULL)
494 if (vfm_source->class->destroy != NULL)
495 vfm_source->class->destroy (vfm_source);
499 if (vfm_sink->class->make_source != NULL)
500 vfm_source = vfm_sink->class->make_source (vfm_sink);
504 /* Old data sink is gone now. */
508 /* Cancel TEMPORARY. */
511 /* Free temporary cases. */
512 free (compaction_case);
513 compaction_case = NULL;
515 /* Cancel PROCESS IF. */
516 expr_free (process_if_expr);
517 process_if_expr = NULL;
519 /* Cancel FILTER if temporary. */
520 if (dict_get_filter (default_dict) != NULL && !FILTER_before_TEMPORARY)
521 dict_set_filter (default_dict, NULL);
523 /* Cancel transformations. */
524 cancel_transformations ();
526 /* Turn off case limiter. */
527 dict_set_case_limit (default_dict, 0);
529 /* Clear VECTOR vectors. */
530 dict_clear_vectors (default_dict);
533 /* Disk case stream. */
535 /* Information about disk sink or source. */
536 struct disk_stream_info
538 FILE *file; /* Output file. */
539 size_t case_cnt; /* Number of cases written so far. */
540 size_t case_size; /* Number of bytes in case. */
543 /* Initializes the disk sink. */
545 disk_sink_create (struct case_sink *sink)
547 struct disk_stream_info *info = xmalloc (sizeof *info);
548 info->file = tmpfile ();
550 info->case_size = compaction_nval;
552 if (info->file == NULL)
554 msg (ME, _("An error occurred attempting to create a temporary "
555 "file for use as the active file: %s."),
561 /* Writes case C to the disk sink. */
563 disk_sink_write (struct case_sink *sink, const struct ccase *c)
565 struct disk_stream_info *info = sink->aux;
566 const union value *src_case;
568 if (compaction_necessary)
570 compact_case (compaction_case, c);
571 src_case = compaction_case->data;
573 else src_case = c->data;
576 if (fwrite (src_case, sizeof *src_case * compaction_nval, 1,
579 msg (ME, _("An error occurred while attempting to write to a "
580 "temporary file used as the active file: %s."),
586 /* Destroys the sink's internal data. */
588 disk_sink_destroy (struct case_sink *sink)
590 struct disk_stream_info *info = sink->aux;
591 if (info->file != NULL)
595 /* Closes and destroys the sink and returns a disk source to read
596 back the written data. */
597 static struct case_source *
598 disk_sink_make_source (struct case_sink *sink)
600 struct disk_stream_info *info = sink->aux;
602 /* Rewind the file. */
603 assert (info->file != NULL);
604 if (fseek (info->file, 0, SEEK_SET) != 0)
606 msg (ME, _("An error occurred while attempting to rewind a "
607 "temporary file used as the active file: %s."),
612 return create_case_source (&disk_source_class, default_dict, info);
616 const struct case_sink_class disk_sink_class =
622 disk_sink_make_source,
627 /* Returns the number of cases that will be read by
628 disk_source_read(). */
630 disk_source_count (const struct case_source *source)
632 struct disk_stream_info *info = source->aux;
634 return info->case_cnt;
637 /* Reads all cases from the disk source and passes them one by one to
640 disk_source_read (struct case_source *source,
642 write_case_func *write_case, write_case_data wc_data)
644 struct disk_stream_info *info = source->aux;
647 for (i = 0; i < info->case_cnt; i++)
649 if (!fread (c, info->case_size, 1, info->file))
651 msg (ME, _("An error occurred while attempting to read from "
652 "a temporary file created for the active file: %s."),
658 if (!write_case (wc_data))
663 /* Destroys the source's internal data. */
665 disk_source_destroy (struct case_source *source)
667 struct disk_stream_info *info = source->aux;
668 if (info->file != NULL)
674 const struct case_source_class disk_source_class =
682 /* Memory case stream. */
684 /* Memory sink data. */
685 struct memory_sink_info
687 size_t case_cnt; /* Number of cases. */
688 size_t case_size; /* Case size in bytes. */
689 int max_cases; /* Maximum cases before switching to disk. */
690 struct case_list *head; /* First case in list. */
691 struct case_list *tail; /* Last case in list. */
694 /* Memory source data. */
695 struct memory_source_info
697 size_t case_cnt; /* Number of cases. */
698 size_t case_size; /* Case size in bytes. */
699 struct case_list *cases; /* List of cases. */
702 /* Creates the SINK memory sink. */
704 memory_sink_create (struct case_sink *sink)
706 struct memory_sink_info *info;
708 sink->aux = info = xmalloc (sizeof *info);
710 assert (compaction_nval > 0);
712 info->case_size = compaction_nval * sizeof (union value);
713 info->max_cases = set_max_workspace / info->case_size;
714 info->head = info->tail = NULL;
717 /* Writes case C to memory sink SINK. */
719 memory_sink_write (struct case_sink *sink, const struct ccase *c)
721 struct memory_sink_info *info = sink->aux;
723 struct case_list *new_case;
725 case_size = sizeof (struct case_list)
726 + ((compaction_nval - 1) * sizeof (union value));
727 new_case = malloc (case_size);
729 /* If we've got memory to spare then add it to the linked list. */
730 if (info->case_cnt <= info->max_cases && new_case != NULL)
734 /* Append case to linked list. */
735 new_case->next = NULL;
736 if (info->head != NULL)
737 info->tail->next = new_case;
739 info->head = new_case;
740 info->tail = new_case;
742 /* Copy data into case. */
743 if (compaction_necessary)
744 compact_case (&new_case->c, c);
746 memcpy (&new_case->c, c, sizeof (union value) * compaction_nval);
750 /* Out of memory. Write the active file to disk. */
751 struct case_list *cur, *next;
753 /* Notify the user. */
755 msg (MW, _("Virtual memory exhausted. Writing active file "
758 msg (MW, _("Workspace limit of %d KB (%d cases at %d bytes each) "
759 "overflowed. Writing active file to disk."),
760 set_max_workspace / 1024, info->max_cases,
761 compaction_nval * sizeof (union value));
765 /* Switch to a disk sink. */
766 vfm_sink = create_case_sink (&disk_sink_class, NULL);
767 vfm_sink->class->open (vfm_sink);
768 workspace_overflow = 1;
770 /* Write the cases to disk and destroy them. We can't call
771 vfm->sink->write() because of compaction. */
772 for (cur = info->head; cur; cur = next)
775 if (fwrite (cur->c.data, sizeof (union value) * compaction_nval, 1,
778 msg (ME, _("An error occurred while attempting to "
779 "write to a temporary file created as the "
787 /* Write the current case to disk. */
788 vfm_sink->class->write (vfm_sink, c);
792 /* If the data is stored in memory, causes it to be written to disk.
793 To be called only *between* procedure()s, not within them. */
795 write_active_file_to_disk (void)
797 if (case_source_is_class (vfm_source, &memory_source_class))
799 struct memory_source_info *info = vfm_source->aux;
801 /* Switch to a disk sink. */
802 vfm_sink = create_case_sink (&disk_sink_class, NULL);
803 vfm_sink->class->open (vfm_sink);
804 workspace_overflow = 1;
806 /* Write the cases to disk and destroy them. We can't call
807 vfm->sink->write() because of compaction. */
809 struct case_list *cur, *next;
811 for (cur = info->cases; cur; cur = next)
814 if (fwrite (cur->c.data, sizeof *cur->c.data * compaction_nval, 1,
817 msg (ME, _("An error occurred while attempting to "
818 "write to a temporary file created as the "
827 vfm_source = vfm_sink->class->make_source (vfm_sink);
832 /* Destroy all memory sink data. */
834 memory_sink_destroy (struct case_sink *sink)
836 struct memory_sink_info *info = sink->aux;
837 struct case_list *cur, *next;
839 for (cur = info->head; cur; cur = next)
847 /* Switch the memory stream from sink to source mode. */
848 static struct case_source *
849 memory_sink_make_source (struct case_sink *sink)
851 struct memory_sink_info *sink_info = sink->aux;
852 struct memory_source_info *source_info;
854 source_info = xmalloc (sizeof *source_info);
855 source_info->case_cnt = sink_info->case_cnt;
856 source_info->case_size = sink_info->case_size;
857 source_info->cases = sink_info->head;
861 return create_case_source (&memory_source_class,
862 default_dict, source_info);
865 const struct case_sink_class memory_sink_class =
871 memory_sink_make_source,
874 /* Returns the number of cases in the source. */
876 memory_source_count (const struct case_source *source)
878 struct memory_source_info *info = source->aux;
880 return info->case_cnt;
883 /* Reads the case stream from memory and passes it to write_case(). */
885 memory_source_read (struct case_source *source,
887 write_case_func *write_case, write_case_data wc_data)
889 struct memory_source_info *info = source->aux;
891 while (info->cases != NULL)
893 struct case_list *iter = info->cases;
894 memcpy (c, &iter->c, info->case_size);
895 if (!write_case (wc_data))
898 info->cases = iter->next;
903 /* Destroy all memory source data. */
905 memory_source_destroy (struct case_source *source)
907 struct memory_source_info *info = source->aux;
908 struct case_list *cur, *next;
910 for (cur = info->cases; cur; cur = next)
918 /* Returns the list of cases in memory source SOURCE. */
920 memory_source_get_cases (const struct case_source *source)
922 struct memory_source_info *info = source->aux;
927 /* Sets the list of cases in memory source SOURCE to CASES. */
929 memory_source_set_cases (const struct case_source *source,
930 struct case_list *cases)
932 struct memory_source_info *info = source->aux;
938 const struct case_source_class memory_source_class =
943 memory_source_destroy,
946 /* Add C to the lag queue. */
948 lag_case (const struct ccase *c)
950 if (lag_count < n_lag)
952 memcpy (lag_queue[lag_head], c, 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 trns_case and writes it to the replacement active
975 file if advisable. Returns nonzero if more cases can be
976 accepted, zero otherwise. Do not call this function again
977 after it has returned zero once. */
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)
998 lag_case (proc_aux->trns_case);
1000 vfm_sink->class->write (vfm_sink, proc_aux->trns_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], proc_aux->trns_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->trns_case, proc_aux->cases_written + 1))
1043 wc_data->proc_func (proc_aux->trns_case, wc_data->func_aux);
1048 clear_case (proc_aux->trns_case);
1050 /* Return previously determined value. */
1054 /* Clears the variables in C that need to be cleared between
1055 processing cases. */
1057 clear_case (struct ccase *c)
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 c->data[v->fv].f = SYSMIS;
1072 memset (c->data[v->fv].s, ' ', v->width);
1077 /* Returns nonzero if case C with case number CASE_NUM should be
1078 exclude as specified on FILTER or PROCESS IF, otherwise
1081 exclude_this_case (const struct ccase *c, int case_num)
1084 struct variable *filter_var = dict_get_filter (default_dict);
1085 if (filter_var != NULL)
1087 double f = c->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, c, 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 /* Creates a case source with class CLASS and auxiliary data AUX
1297 and based on dictionary DICT. */
1298 struct case_source *
1299 create_case_source (const struct case_source_class *class,
1300 const struct dictionary *dict,
1303 struct case_source *source = xmalloc (sizeof *source);
1304 source->class = class;
1305 source->value_cnt = dict_get_next_value_idx (dict);
1310 /* Returns nonzero if a case source is "complex". */
1312 case_source_is_complex (const struct case_source *source)
1314 return source != NULL && (source->class == &input_program_source_class
1315 || source->class == &file_type_source_class);
1318 /* Returns nonzero if CLASS is the class of SOURCE. */
1320 case_source_is_class (const struct case_source *source,
1321 const struct case_source_class *class)
1323 return source != NULL && source->class == class;
1326 /* Creates a case sink with class CLASS and auxiliary data
1329 create_case_sink (const struct case_sink_class *class, void *aux)
1331 struct case_sink *sink = xmalloc (sizeof *sink);
1332 sink->class = class;