Delete trailing whitespace at end of lines.
[pspp-builds.git] / src / data / casereader-filter.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301, USA. */
18
19 #include <config.h>
20
21 #include <data/casereader.h>
22
23 #include <stdlib.h>
24
25 #include <data/casereader-provider.h>
26 #include <data/casewriter.h>
27 #include <data/variable.h>
28 #include <data/dictionary.h>
29 #include <libpspp/taint.h>
30 #include <libpspp/message.h>
31
32 #include "xalloc.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36
37 struct casereader_filter
38   {
39     struct casereader *subreader;
40     bool (*include) (const struct ccase *, void *aux);
41     bool (*destroy) (void *aux);
42     void *aux;
43     struct casewriter *exclude;
44   };
45
46 static struct casereader_class casereader_filter_class;
47
48 struct casereader *
49 casereader_create_filter_func (struct casereader *subreader,
50                                bool (*include) (const struct ccase *,
51                                                 void *aux),
52                                bool (*destroy) (void *aux),
53                                void *aux,
54                                struct casewriter *exclude)
55 {
56   struct casereader_filter *filter = xmalloc (sizeof *filter);
57   struct casereader *reader;
58   filter->subreader = casereader_rename (subreader);
59   filter->include = include;
60   filter->destroy = destroy;
61   filter->aux = aux;
62   filter->exclude = exclude;
63   reader = casereader_create_sequential (
64     NULL, casereader_get_value_cnt (filter->subreader), CASENUMBER_MAX,
65     &casereader_filter_class, filter);
66   taint_propagate (casereader_get_taint (filter->subreader),
67                    casereader_get_taint (reader));
68   return reader;
69 }
70
71 static bool
72 casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
73                         struct ccase *c)
74
75 {
76   struct casereader_filter *filter = filter_;
77   for (;;)
78     {
79       if (!casereader_read (filter->subreader, c))
80         return false;
81       else if (filter->include (c, filter->aux))
82         return true;
83       else if (filter->exclude != NULL)
84         casewriter_write (filter->exclude, c);
85       else
86         case_destroy (c);
87     }
88 }
89
90 static void
91 casereader_filter_destroy (struct casereader *reader, void *filter_)
92 {
93   struct casereader_filter *filter = filter_;
94   casereader_destroy (filter->subreader);
95   if (filter->destroy != NULL && !filter->destroy (filter->aux))
96     casereader_force_error (reader);
97   free (filter);
98 }
99
100 static struct casereader_class casereader_filter_class =
101   {
102     casereader_filter_read,
103     casereader_filter_destroy,
104
105     /* We could in fact delegate clone to the subreader, if the
106        filter function is required to have no memory and if we
107        added reference counting.  But it might be useful to have
108        filter functions with memory and in any case this would
109        require a little extra work. */
110     NULL,
111     NULL,
112   };
113
114 struct casereader_filter_weight
115   {
116     const struct variable *weight_var;
117     bool *warn_on_invalid;
118     bool local_warn_on_invalid;
119   };
120
121 static bool
122 casereader_filter_weight_include (const struct ccase *c, void *cfw_)
123 {
124   struct casereader_filter_weight *cfw = cfw_;
125   double value = case_num (c, cfw->weight_var);
126   if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
127     return true;
128   else
129     {
130       if (*cfw->warn_on_invalid)
131         {
132           msg (SW, _("At least one case in the data read had a weight value "
133                      "that was user-missing, system-missing, zero, or "
134                      "negative.  These case(s) were ignored."));
135           *cfw->warn_on_invalid = false;
136         }
137       return false;
138     }
139 }
140
141 static bool
142 casereader_filter_weight_destroy (void *cfw_)
143 {
144   struct casereader_filter_weight *cfw = cfw_;
145   free (cfw);
146   return true;
147 }
148
149 struct casereader *
150 casereader_create_filter_weight (struct casereader *reader,
151                                  const struct dictionary *dict,
152                                  bool *warn_on_invalid,
153                                  struct casewriter *exclude)
154 {
155   struct variable *weight_var = dict_get_weight (dict);
156   if (weight_var != NULL)
157     {
158       struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
159       cfw->weight_var = weight_var;
160       cfw->warn_on_invalid = (warn_on_invalid
161                                ? warn_on_invalid
162                                : &cfw->local_warn_on_invalid);
163       cfw->local_warn_on_invalid = true;
164       reader = casereader_create_filter_func (reader,
165                                               casereader_filter_weight_include,
166                                               casereader_filter_weight_destroy,
167                                               cfw, exclude);
168     }
169   else
170     reader = casereader_rename (reader);
171   return reader;
172 }
173 \f
174 struct casereader_filter_missing
175   {
176     struct variable **vars;
177     size_t var_cnt;
178     enum mv_class class;
179   };
180
181 static bool
182 casereader_filter_missing_include (const struct ccase *c, void *cfm_)
183 {
184   const struct casereader_filter_missing *cfm = cfm_;
185   size_t i;
186
187   for (i = 0; i < cfm->var_cnt; i++)
188     {
189       struct variable *var = cfm->vars[i];
190       const union value *value = case_data (c, var);
191       if (var_is_value_missing (var, value, cfm->class))
192         return false;
193     }
194   return true;
195 }
196
197 static bool
198 casereader_filter_missing_destroy (void *cfm_)
199 {
200   struct casereader_filter_missing *cfm = cfm_;
201   free (cfm->vars);
202   free (cfm);
203   return true;
204 }
205
206 struct casereader *
207 casereader_create_filter_missing (struct casereader *reader,
208                                   const struct variable **vars, size_t var_cnt,
209                                   enum mv_class class,
210                                   struct casewriter *exclude)
211 {
212   if (var_cnt > 0 && class != MV_NEVER)
213     {
214       struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
215       cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
216       cfm->var_cnt = var_cnt;
217       cfm->class = class;
218       return casereader_create_filter_func (reader,
219                                             casereader_filter_missing_include,
220                                             casereader_filter_missing_destroy,
221                                             cfm,
222                                             exclude);
223     }
224   else
225     return casereader_rename (reader);
226 }
227 \f
228 \f
229 static bool
230 casereader_counter_include (const struct ccase *c UNUSED, void *counter_)
231 {
232   casenumber *counter = counter_;
233   ++*counter;
234   return true;
235 }
236
237 struct casereader *
238 casereader_create_counter (struct casereader *reader, casenumber *counter,
239                            casenumber initial_value)
240 {
241   *counter = initial_value;
242   return casereader_create_filter_func (reader, casereader_counter_include,
243                                         NULL, counter, NULL);
244 }