Work to get rid of GCC 4.0 warnings, part 2.
[pspp-builds.git] / src / missing-values.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2005 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "missing-values.h"
22 #include <assert.h>
23 #include <stdlib.h>
24 #include "str.h"
25
26 /* Initializes MV as a set of missing values for a variable of
27    the given WIDTH.  Although only numeric variables and short
28    string variables may have missing values, WIDTH may be any
29    valid variable width. */
30 void
31 mv_init (struct missing_values *mv, int width) 
32 {
33   assert (width >= 0 && width <= MAX_STRING);
34   mv->type = MV_NONE;
35   mv->width = width;
36 }
37
38 /* Copies SRC to MV. */
39 void
40 mv_copy (struct missing_values *mv, const struct missing_values *src) 
41 {
42   *mv = *src;
43 }
44
45 /* Returns true if MV is an empty set of missing values. */
46 bool
47 mv_is_empty (const struct missing_values *mv) 
48 {
49   return mv->type == MV_NONE;
50 }
51
52 /* Returns the width of the missing values that MV may
53    contain. */
54 int
55 mv_get_width (const struct missing_values *mv)
56 {
57   return mv->width;
58 }
59
60 /* Attempts to add individual value V to the set of missing
61    values MV.  Returns true if successful, false if MV has no
62    more room for missing values.  (Long string variables never
63    accept missing values.) */
64 bool
65 mv_add_value (struct missing_values *mv, const union value *v)
66 {
67   if (mv->width > MAX_SHORT_STRING)
68     return false;
69   switch (mv->type) 
70     {
71     case MV_NONE:
72     case MV_1:
73     case MV_2:
74     case MV_RANGE:
75       mv->values[mv->type & 3] = *v;
76       mv->type++;
77       return true;
78
79     case MV_3:
80     case MV_RANGE_1:
81       return false;
82     }
83   abort ();
84 }
85
86 /* Attempts to add S to the set of string missing values MV.  S
87    must contain exactly as many characters as MV's width.
88    Returns true if successful, false if MV has no more room for
89    missing values.  (Long string variables never accept missing
90    values.) */
91 bool
92 mv_add_str (struct missing_values *mv, const char s[]) 
93 {
94   assert (mv->width > 0);
95   return mv_add_value (mv, (union value *) s);
96 }
97
98 /* Attempts to add D to the set of numeric missing values MV.
99    Returns true if successful, false if MV has no more room for
100    missing values.  */
101 bool
102 mv_add_num (struct missing_values *mv, double d) 
103 {
104   assert (mv->width == 0);
105   return mv_add_value (mv, (union value *) &d);
106 }
107
108 /* Attempts to add range [LOW, HIGH] to the set of numeric
109    missing values MV.  Returns true if successful, false if MV
110    has no room for a range. */
111 bool
112 mv_add_num_range (struct missing_values *mv, double low, double high) 
113 {
114   assert (mv->width == 0);
115   switch (mv->type) 
116     {
117     case MV_NONE:
118     case MV_1:
119       mv->values[1].f = low;
120       mv->values[2].f = high;
121       mv->type |= 4;
122       return true;
123
124     case MV_2:
125     case MV_3:
126     case MV_RANGE:
127     case MV_RANGE_1:
128       return false;
129     }
130   abort ();
131 }
132
133 /* Returns true if MV contains an individual value,
134    false if MV is empty (or contains only a range). */
135 bool
136 mv_has_value (struct missing_values *mv)
137 {
138   switch (mv->type) 
139     {
140     case MV_1:
141     case MV_2:
142     case MV_3:
143     case MV_RANGE_1:
144       return true;
145       
146     case MV_NONE:
147     case MV_RANGE:
148       return false;
149     }
150   abort ();
151 }
152
153 /* Removes one individual value from MV and stores it in *V.
154    MV must contain an individual value (as determined by
155    mv_has_value()). */
156 void
157 mv_pop_value (struct missing_values *mv, union value *v) 
158 {
159   assert (mv_has_value (mv));
160   mv->type--;
161   *v = mv->values[mv->type & 3];
162 }
163
164 /* Returns true if MV contains a numeric range,
165    false if MV is empty (or contains only individual values). */
166 bool
167 mv_has_range (struct missing_values *mv) 
168 {
169   switch (mv->type) 
170     {
171     case MV_RANGE:
172     case MV_RANGE_1:
173       return true;
174       
175     case MV_NONE:
176     case MV_1:
177     case MV_2:
178     case MV_3:
179       return false;
180     }
181   abort ();
182 }
183
184 /* Removes the numeric range from MV and stores it in *LOW and
185    *HIGH.  MV must contain a individual range (as determined by
186    mv_has_range()). */
187 void
188 mv_pop_range (struct missing_values *mv, double *low, double *high) 
189 {
190   assert (mv_has_range (mv));
191   *low = mv->values[1].f;
192   *high = mv->values[2].f;
193   mv->type &= 3;
194 }
195
196 /* Returns true if values[IDX] is in use when the `type' member
197    is set to TYPE (in struct missing_values),
198    false otherwise. */
199 static bool
200 using_element (unsigned type, int idx) 
201 {
202   assert (idx >= 0 && idx < 3);
203   
204   switch (type) 
205     {
206     case MV_NONE:
207       return false;
208     case MV_1:
209       return idx < 1;
210     case MV_2:
211       return idx < 2;
212     case MV_3:
213       return true;
214     case MV_RANGE:
215       return idx > 0;
216     case MV_RANGE_1:
217       return true;
218     }
219   abort ();
220 }
221
222 /* Returns true if S contains only spaces between indexes
223    NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
224    false otherwise. */
225 static bool
226 can_resize_string (const char *s, int old_width, int new_width) 
227 {
228   int i;
229
230   assert (new_width < old_width);
231   for (i = new_width; i < old_width; i++)
232     if (s[i] != ' ')
233       return false;
234   return true;
235 }
236
237 /* Returns true if MV can be resized to the given WIDTH with
238    mv_resize(), false otherwise.  Resizing to the same width is
239    always possible.  Resizing to a long string WIDTH is only
240    possible if MV is an empty set of missing values; otherwise,
241    resizing to a larger WIDTH is always possible.  Resizing to a
242    shorter width is possible only when each missing value
243    contains only spaces in the characters that will be
244    trimmed. */
245 bool
246 mv_is_resizable (struct missing_values *mv, int width) 
247 {
248   assert ((width == 0) == (mv->width == 0));
249   if (width > MAX_SHORT_STRING && mv->type != MV_NONE)
250     return false;
251   else if (width >= mv->width)
252     return true;
253   else 
254     {
255       int i;
256       
257       for (i = 0; i < 3; i++)
258         if (using_element (mv->type, i)
259             && !can_resize_string (mv->values[i].s, mv->width, width))
260           return false;
261       return true;
262     }
263 }
264
265 /* Resizes MV to the given WIDTH.  WIDTH must fit the constraints
266    explained for mv_is_resizable(). */
267 void
268 mv_resize (struct missing_values *mv, int width) 
269 {
270   assert (mv_is_resizable (mv, width));
271   if (width > mv->width) 
272     {
273       int i;
274       
275       for (i = 0; i < 3; i++)
276         memset (mv->values[i].s + mv->width, ' ', width - mv->width);
277     }
278   mv->width = width;
279 }
280
281 /* Returns true if V is system missing or a missing value in MV,
282    false otherwise. */
283 bool
284 mv_is_value_missing (const struct missing_values *mv, const union value *v)
285 {
286   return (mv->width == 0
287           ? mv_is_num_missing (mv, v->f)
288           : mv_is_str_missing (mv, v->s));
289 }
290
291 /* Returns true if D is system missing or a missing value in MV,
292    false otherwise.
293    MV must be a set of numeric missing values. */
294 bool
295 mv_is_num_missing (const struct missing_values *mv, double d)
296 {
297   assert (mv->width == 0);
298   return d == SYSMIS || mv_is_num_user_missing (mv, d);
299 }
300
301 /* Returns true if S[] is a missing value in MV, false otherwise.
302    MV must be a set of string missing values. 
303    S[] must contain exactly as many characters as MV's width. */
304 bool
305 mv_is_str_missing (const struct missing_values *mv, const char s[])
306 {
307   return mv_is_str_user_missing (mv, s);
308 }
309
310 /* Returns true if V is a missing value in MV, false otherwise. */
311 bool
312 mv_is_value_user_missing (const struct missing_values *mv,
313                           const union value *v)
314 {
315   return (mv->width == 0
316           ? mv_is_num_user_missing (mv, v->f)
317           : mv_is_str_user_missing (mv, v->s));
318 }
319
320 /* Returns true if D is a missing value in MV, false otherwise.
321    MV must be a set of numeric missing values. */
322 bool
323 mv_is_num_user_missing (const struct missing_values *mv, double d)
324 {
325   const union value *v = mv->values;
326   assert (mv->width == 0);
327   switch (mv->type) 
328     {
329     case MV_NONE:
330       return false;
331     case MV_1:
332       return v[0].f == d;
333     case MV_2:
334       return v[0].f == d || v[1].f == d;
335     case MV_3:
336       return v[0].f == d || v[1].f == d || v[2].f == d;
337     case MV_RANGE:
338       return v[1].f <= d && d <= v[2].f;
339     case MV_RANGE_1:
340       return v[0].f == d || (v[1].f <= d && d <= v[2].f);
341     }
342   abort ();
343 }
344
345 /* Returns true if S[] is a missing value in MV, false otherwise.
346    MV must be a set of string missing values. 
347    S[] must contain exactly as many characters as MV's width. */
348 bool
349 mv_is_str_user_missing (const struct missing_values *mv,
350                         const char s[])
351 {
352   const union value *v = mv->values;
353   assert (mv->width > 0);
354   switch (mv->type) 
355     {
356     case MV_NONE:
357       return false;
358     case MV_1:
359       return !memcmp (v[0].s, s, mv->width);
360     case MV_2:
361       return (!memcmp (v[0].s, s, mv->width)
362               || !memcmp (v[1].s, s, mv->width));
363     case MV_3:
364       return (!memcmp (v[0].s, s, mv->width)
365               || !memcmp (v[1].s, s, mv->width)
366               || !memcmp (v[2].s, s, mv->width));
367     case MV_RANGE:
368     case MV_RANGE_1:
369       abort ();
370     }
371   abort ();
372 }
373
374 /* Returns true if MV is a set of numeric missing values and V is
375    the system missing value. */
376 bool
377 mv_is_value_system_missing (const struct missing_values *mv,
378                             const union value *v)
379 {
380   return mv->width == 0 ? v->f == SYSMIS : false;
381 }