1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2005 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/>. */
18 #include "missing-values.h"
21 #include <libpspp/assertion.h>
23 #include <libpspp/str.h>
25 /* Types of user-missing values.
26 Invisible--use access functions defined below instead. */
29 MVT_NONE = 0, /* No user-missing values. */
30 MVT_1 = 1, /* One user-missing value. */
31 MVT_2 = 2, /* Two user-missing values. */
32 MVT_3 = 3, /* Three user-missing values. */
33 MVT_RANGE = 4, /* A range of user-missing values. */
34 MVT_RANGE_1 = 5 /* A range plus an individual value. */
37 /* Initializes MV as a set of missing values for a variable of
38 the given WIDTH. Although only numeric variables and short
39 string variables may have missing values, WIDTH may be any
40 valid variable width. */
42 mv_init (struct missing_values *mv, int width)
44 assert (width >= 0 && width <= MAX_STRING);
49 /* Removes any missing values from MV. */
51 mv_clear (struct missing_values *mv)
56 /* Copies SRC to MV. */
58 mv_copy (struct missing_values *mv, const struct missing_values *src)
65 /* Returns true if MV is an empty set of missing values. */
67 mv_is_empty (const struct missing_values *mv)
69 return mv->type == MVT_NONE;
72 /* Returns the width of the missing values that MV may
75 mv_get_width (const struct missing_values *mv)
80 /* Attempts to add individual value V to the set of missing
81 values MV. Returns true if successful, false if MV has no
82 more room for missing values. (Long string variables never
83 accept missing values.) */
85 mv_add_value (struct missing_values *mv, const union value *v)
87 if (mv->width > MAX_SHORT_STRING)
95 mv->values[mv->type & 3] = *v;
106 /* Attempts to add S to the set of string missing values MV. S
107 must contain exactly as many characters as MV's width.
108 Returns true if successful, false if MV has no more room for
109 missing values. (Long string variables never accept missing
112 mv_add_str (struct missing_values *mv, const char s[])
114 assert (mv->width > 0);
115 return mv_add_value (mv, (union value *) s);
118 /* Attempts to add D to the set of numeric missing values MV.
119 Returns true if successful, false if MV has no more room for
122 mv_add_num (struct missing_values *mv, double d)
124 assert (mv->width == 0);
125 return mv_add_value (mv, (union value *) &d);
128 /* Attempts to add range [LOW, HIGH] to the set of numeric
129 missing values MV. Returns true if successful, false if MV
130 has no room for a range, or if LOW > HIGH. */
132 mv_add_num_range (struct missing_values *mv, double low, double high)
134 assert (mv->width == 0);
141 mv->values[1].f = low;
142 mv->values[2].f = high;
155 /* Returns true if MV contains an individual value,
156 false if MV is empty (or contains only a range). */
158 mv_has_value (const struct missing_values *mv)
175 /* Removes one individual value from MV and stores it in *V.
176 MV must contain an individual value (as determined by
179 mv_pop_value (struct missing_values *mv, union value *v)
181 assert (mv_has_value (mv));
183 *v = mv->values[mv->type & 3];
186 /* Stores a value in *V.
187 MV must contain an individual value (as determined by
189 IDX is the zero based index of the value to get
192 mv_peek_value (const struct missing_values *mv, union value *v, int idx)
197 assert (mv_has_value (mv));
198 *v = mv->values[idx];
202 mv_replace_value (struct missing_values *mv, const union value *v, int idx)
205 assert (idx < mv_n_values(mv));
207 mv->values[idx] = *v;
211 /* Returns the number of individual (not part of a range) missing
214 mv_n_values (const struct missing_values *mv)
220 /* Returns true if MV contains a numeric range,
221 false if MV is empty (or contains only individual values). */
223 mv_has_range (const struct missing_values *mv)
240 /* Removes the numeric range from MV and stores it in *LOW and
241 *HIGH. MV must contain a individual range (as determined by
244 mv_pop_range (struct missing_values *mv, double *low, double *high)
246 assert (mv_has_range (mv));
247 *low = mv->values[1].f;
248 *high = mv->values[2].f;
253 /* Returns the numeric range from MV into *LOW and
254 *HIGH. MV must contain a individual range (as determined by
257 mv_peek_range (const struct missing_values *mv, double *low, double *high)
259 assert (mv_has_range (mv));
260 *low = mv->values[1].f;
261 *high = mv->values[2].f;
265 /* Returns true if values[IDX] is in use when the `type' member
266 is set to TYPE (in struct missing_values),
269 using_element (unsigned type, int idx)
271 assert (idx >= 0 && idx < 3);
291 /* Returns true if S contains only spaces between indexes
292 NEW_WIDTH (inclusive) and OLD_WIDTH (exclusive),
295 can_resize_string (const char *s, int old_width, int new_width)
299 assert (new_width < old_width);
300 for (i = new_width; i < old_width; i++)
306 /* Returns true if MV can be resized to the given WIDTH with
307 mv_resize(), false otherwise. Resizing to the same width is
308 always possible. Resizing to a long string WIDTH is only
309 possible if MV is an empty set of missing values; otherwise,
310 resizing to a larger WIDTH is always possible. Resizing to a
311 shorter width is possible only when each missing value
312 contains only spaces in the characters that will be
315 mv_is_resizable (const struct missing_values *mv, int width)
317 if ( var_type_from_width (width) != var_type_from_width (mv->width) )
320 if (width > MAX_SHORT_STRING && mv->type != MVT_NONE)
323 if (width >= mv->width)
329 for (i = 0; i < 3; i++)
330 if (using_element (mv->type, i)
331 && !can_resize_string (mv->values[i].s, mv->width, width))
337 /* Resizes MV to the given WIDTH. WIDTH must fit the constraints
338 explained for mv_is_resizable(). */
340 mv_resize (struct missing_values *mv, int width)
342 assert (mv_is_resizable (mv, width));
343 if (width > mv->width && mv->type != MVT_NONE)
347 for (i = 0; i < 3; i++)
348 memset (mv->values[i].s + mv->width, ' ', width - mv->width);
353 /* Returns true if D is a missing value in MV, false otherwise.
354 MV must be a set of numeric missing values. */
356 is_num_user_missing (const struct missing_values *mv, double d)
358 const union value *v = mv->values;
359 assert (mv->width == 0);
367 return v[0].f == d || v[1].f == d;
369 return v[0].f == d || v[1].f == d || v[2].f == d;
371 return v[1].f <= d && d <= v[2].f;
373 return v[0].f == d || (v[1].f <= d && d <= v[2].f);
378 /* Returns true if S[] is a missing value in MV, false otherwise.
379 MV must be a set of string missing values.
380 S[] must contain exactly as many characters as MV's width. */
382 is_str_user_missing (const struct missing_values *mv,
385 const union value *v = mv->values;
386 assert (mv->width > 0);
392 return !memcmp (v[0].s, s, mv->width);
394 return (!memcmp (v[0].s, s, mv->width)
395 || !memcmp (v[1].s, s, mv->width));
397 return (!memcmp (v[0].s, s, mv->width)
398 || !memcmp (v[1].s, s, mv->width)
399 || !memcmp (v[2].s, s, mv->width));
407 /* Returns true if V is a missing value in the given CLASS in MV,
410 mv_is_value_missing (const struct missing_values *mv, const union value *v,
413 return (mv->width == 0
414 ? mv_is_num_missing (mv, v->f, class)
415 : mv_is_str_missing (mv, v->s, class));
418 /* Returns true if D is a missing value in the given CLASS in MV,
420 MV must be a set of numeric missing values. */
422 mv_is_num_missing (const struct missing_values *mv, double d,
425 assert (mv->width == 0);
426 return ((class & MV_SYSTEM && d == SYSMIS)
427 || (class & MV_USER && is_num_user_missing (mv, d)));
430 /* Returns true if S[] is a missing value in the given CLASS in
432 MV must be a set of string missing values.
433 S[] must contain exactly as many characters as MV's width. */
435 mv_is_str_missing (const struct missing_values *mv, const char s[],
438 assert (mv->width > 0);
439 return class & MV_USER && is_str_user_missing (mv, s);