From 9f650fc3d2946c216e6cd3c7922a8a63d0f97117 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 23 Dec 2006 06:11:33 +0000 Subject: [PATCH] Make the missing value code do more work, so that its callers can do less. --- src/data/ChangeLog | 45 ++++++ src/data/casefilter.c | 21 +-- src/data/casefilter.h | 9 +- src/data/dictionary.c | 2 +- src/data/missing-values.c | 192 ++++++++++++------------ src/data/missing-values.h | 44 ++---- src/data/procedure.c | 2 +- src/data/variable.c | 56 ++----- src/data/variable.h | 17 +-- src/language/expressions/operations.def | 8 +- src/language/stats/ChangeLog | 17 +++ src/language/stats/aggregate.c | 22 ++- src/language/stats/crosstabs.q | 27 ++-- src/language/stats/descriptives.c | 35 ++--- src/language/stats/examine.q | 17 +-- src/language/stats/frequencies.q | 4 +- src/language/stats/npar.q | 2 +- src/language/stats/oneway.q | 3 +- src/language/stats/rank.q | 20 +-- src/language/stats/regression.q | 2 +- src/language/stats/t-test.q | 3 +- src/language/xforms/count.c | 14 +- src/language/xforms/recode.c | 2 +- src/math/chart-geometry.c | 2 +- src/math/coefficient.c | 1 + src/math/linreg/linreg.c | 1 + src/math/linreg/predict.c | 1 + src/math/ts/innovations.c | 1 + src/ui/gui/data-sheet.c | 1 + src/ui/gui/missing-val-dialog.c | 6 +- src/ui/gui/psppire-dict.c | 2 +- 31 files changed, 287 insertions(+), 292 deletions(-) diff --git a/src/data/ChangeLog b/src/data/ChangeLog index 352b063e..a30f8927 100644 --- a/src/data/ChangeLog +++ b/src/data/ChangeLog @@ -1,3 +1,48 @@ +Fri Dec 22 13:56:08 2006 Ben Pfaff + + Simplify missing value handling. + + * missing-values.h (enum mv_class): New type. + (enum mv_type): Moved definition into missing-values.c and renamed + each MV_* to MVT_*, to distinguish them from the exposed mv_class + enums. Updated all uses. + (struct missing_values): Changed type of `type' from `enum + mv_type' to `int' because the definition is no longer exposed. + + * missing-values.c (mv_is_value_missing): Add new enum mv_class + parameter. Update all callers. + (mv_is_num_missing): Ditto. + (mv_is_str_missing): Ditto. + (mv_is_value_user_missing): Removed. Changed callers to use + mv_is_value_missing. + (mv_is_num_user_missing): Removed. Changed callers to use + mv_is_num_missing. + (mv_is_str_user_missing): Removed. Changed callers to use + mv_is_str_missing. + (mv_is_value_system_missing): Removed. Changed callers to use + mv_is_value_missing. + (mv_set_type): Removed. Changed callers to use mv_clear. + (mv_clear): New function. + + * variable.c (var_is_value_missing): Add new enum mv_class + parameter. Update all callers. + (var_is_num_missing): Ditto. + (var_is_str_missing): Ditto. + (var_is_value_user_missing): Removed. Changed callers to use + var_is_value_missing. + (var_is_num_user_missing): Removed. Changed callers to use + var_is_num_missing. + (var_is_str_user_missing): Removed. Changed callers to use + var_is_str_missing. + (var_is_value_system_missing): Removed. Changed callers to use + var_is_value_missing. + + * casefilter.c (struct casefilter): Use enum mv_class in place of + bool. + (casefilter_variable_missing): Adapt to new member. + (casefilter_create): Change signature to take enum mv_class, + update callers. + Fri Dec 22 20:08:38 WST 2006 John Darrington * casefile-factory.h fastfile-factory.c fastfile-factory.h: New files. diff --git a/src/data/casefilter.c b/src/data/casefilter.c index 267a695a..fb23e4f6 100644 --- a/src/data/casefilter.c +++ b/src/data/casefilter.c @@ -29,7 +29,7 @@ struct casefilter { - bool exclude_user_missing; + enum mv_class class; const struct variable **vars; int n_vars; @@ -58,30 +58,21 @@ casefilter_variable_missing (const struct casefilter *filter, const struct variable *var) { const union value *val = case_data (c, var) ; - - if ( var_is_numeric (var) && val->f == SYSMIS ) - return true; - - if ( filter->exclude_user_missing && - var_is_value_user_missing (var, val) ) - return true; - - return false; + return var_is_value_missing (var, val, filter->class); } -/* Create a new casefilter. - If EXCL is true, then the filter user missing values to be missing, - otherwise they are considered at their face value. +/* Create a new casefilter that drops cases in which any of the + N_VARS variables in VARS are in the given CLASS of missing values. VARS is an array of variables which if *any* of them are missing. N_VARS is the size of VARS. */ struct casefilter * -casefilter_create (bool excl, struct variable **vars, int n_vars) +casefilter_create (enum mv_class class, struct variable **vars, int n_vars) { int i; struct casefilter * filter = xmalloc (sizeof (*filter)) ; - filter->exclude_user_missing = excl ; + filter->class = class; filter->vars = xnmalloc (n_vars, sizeof (*filter->vars) ); for ( i = 0 ; i < n_vars ; ++i ) diff --git a/src/data/casefilter.h b/src/data/casefilter.h index 0d0ee16e..083322ee 100644 --- a/src/data/casefilter.h +++ b/src/data/casefilter.h @@ -20,18 +20,19 @@ #define casefilter_h 1 #include +#include struct ccase; struct casefilter; struct variable ; -/* Create a new casefilter. - If EXCL is true, then the filter user missing values to be missing, - otherwise they are considered at their face value. +/* Create a new casefilter that drops cases in which any of the + N_VARS variables in VARS are missing in the given CLASS. VARS is an array of variables which if *any* of them are missing. N_VARS is the size of VARS. */ -struct casefilter * casefilter_create (bool, struct variable **, int); +struct casefilter * casefilter_create (enum mv_class class, + struct variable **, int); /* Add the variables in VARS to the list of variables for which the filter considers. N_VARS is the size of VARS */ diff --git a/src/data/dictionary.c b/src/data/dictionary.c index a5a36527..1d15fe8b 100644 --- a/src/data/dictionary.c +++ b/src/data/dictionary.c @@ -698,7 +698,7 @@ dict_get_case_weight (const struct dictionary *d, const struct ccase *c, else { double w = case_num (c, d->weight); - if (w < 0.0 || var_is_num_missing (d->weight, w)) + if (w < 0.0 || var_is_num_missing (d->weight, w, MV_ANY)) w = 0.0; if ( w == 0.0 && *warn_on_invalid ) { *warn_on_invalid = false; diff --git a/src/data/missing-values.c b/src/data/missing-values.c index ba9ab53b..cbed4d59 100644 --- a/src/data/missing-values.c +++ b/src/data/missing-values.c @@ -24,6 +24,17 @@ #include "variable.h" #include +/* Types of user-missing values. + Invisible--use access functions defined below instead. */ +enum mv_type + { + MVT_NONE = 0, /* No user-missing values. */ + MVT_1 = 1, /* One user-missing value. */ + MVT_2 = 2, /* Two user-missing values. */ + MVT_3 = 3, /* Three user-missing values. */ + MVT_RANGE = 4, /* A range of user-missing values. */ + MVT_RANGE_1 = 5 /* A range plus an individual value. */ + }; /* Initializes MV as a set of missing values for a variable of the given WIDTH. Although only numeric variables and short @@ -33,17 +44,17 @@ void mv_init (struct missing_values *mv, int width) { assert (width >= 0 && width <= MAX_STRING); - mv->type = MV_NONE; + mv->type = MVT_NONE; mv->width = width; } +/* Removes any missing values from MV. */ void -mv_set_type(struct missing_values *mv, enum mv_type type) +mv_clear (struct missing_values *mv) { - mv->type = type; + mv->type = MVT_NONE; } - /* Copies SRC to MV. */ void mv_copy (struct missing_values *mv, const struct missing_values *src) @@ -57,7 +68,7 @@ mv_copy (struct missing_values *mv, const struct missing_values *src) bool mv_is_empty (const struct missing_values *mv) { - return mv->type == MV_NONE; + return mv->type == MVT_NONE; } /* Returns the width of the missing values that MV may @@ -79,16 +90,16 @@ mv_add_value (struct missing_values *mv, const union value *v) return false; switch (mv->type) { - case MV_NONE: - case MV_1: - case MV_2: - case MV_RANGE: + case MVT_NONE: + case MVT_1: + case MVT_2: + case MVT_RANGE: mv->values[mv->type & 3] = *v; mv->type++; return true; - case MV_3: - case MV_RANGE_1: + case MVT_3: + case MVT_RANGE_1: return false; } NOT_REACHED (); @@ -127,17 +138,17 @@ mv_add_num_range (struct missing_values *mv, double low, double high) return false; switch (mv->type) { - case MV_NONE: - case MV_1: + case MVT_NONE: + case MVT_1: mv->values[1].f = low; mv->values[2].f = high; mv->type |= 4; return true; - case MV_2: - case MV_3: - case MV_RANGE: - case MV_RANGE_1: + case MVT_2: + case MVT_3: + case MVT_RANGE: + case MVT_RANGE_1: return false; } NOT_REACHED (); @@ -150,14 +161,14 @@ mv_has_value (const struct missing_values *mv) { switch (mv->type) { - case MV_1: - case MV_2: - case MV_3: - case MV_RANGE_1: + case MVT_1: + case MVT_2: + case MVT_3: + case MVT_RANGE_1: return true; - case MV_NONE: - case MV_RANGE: + case MVT_NONE: + case MVT_RANGE: return false; } NOT_REACHED (); @@ -215,14 +226,14 @@ mv_has_range (const struct missing_values *mv) { switch (mv->type) { - case MV_RANGE: - case MV_RANGE_1: + case MVT_RANGE: + case MVT_RANGE_1: return true; - case MV_NONE: - case MV_1: - case MV_2: - case MV_3: + case MVT_NONE: + case MVT_1: + case MVT_2: + case MVT_3: return false; } NOT_REACHED (); @@ -263,17 +274,17 @@ using_element (unsigned type, int idx) switch (type) { - case MV_NONE: + case MVT_NONE: return false; - case MV_1: + case MVT_1: return idx < 1; - case MV_2: + case MVT_2: return idx < 2; - case MV_3: + case MVT_3: return true; - case MV_RANGE: + case MVT_RANGE: return idx > 0; - case MV_RANGE_1: + case MVT_RANGE_1: return true; } NOT_REACHED (); @@ -308,7 +319,7 @@ mv_is_resizable (const struct missing_values *mv, int width) if ( var_type_from_width (width) != var_type_from_width (mv->width) ) return false; - if (width > MAX_SHORT_STRING && mv->type != MV_NONE) + if (width > MAX_SHORT_STRING && mv->type != MVT_NONE) return false; if (width >= mv->width) @@ -331,7 +342,7 @@ void mv_resize (struct missing_values *mv, int width) { assert (mv_is_resizable (mv, width)); - if (width > mv->width && mv->type != MV_NONE) + if (width > mv->width && mv->type != MVT_NONE) { int i; @@ -341,65 +352,26 @@ mv_resize (struct missing_values *mv, int width) mv->width = width; } -/* Returns true if V is system missing or a missing value in MV, - false otherwise. */ -bool -mv_is_value_missing (const struct missing_values *mv, const union value *v) -{ - return (mv->width == 0 - ? mv_is_num_missing (mv, v->f) - : mv_is_str_missing (mv, v->s)); -} - -/* Returns true if D is system missing or a missing value in MV, - false otherwise. - MV must be a set of numeric missing values. */ -bool -mv_is_num_missing (const struct missing_values *mv, double d) -{ - assert (mv->width == 0); - return d == SYSMIS || mv_is_num_user_missing (mv, d); -} - -/* Returns true if S[] is a missing value in MV, false otherwise. - MV must be a set of string missing values. - S[] must contain exactly as many characters as MV's width. */ -bool -mv_is_str_missing (const struct missing_values *mv, const char s[]) -{ - return mv_is_str_user_missing (mv, s); -} - -/* Returns true if V is a missing value in MV, false otherwise. */ -bool -mv_is_value_user_missing (const struct missing_values *mv, - const union value *v) -{ - return (mv->width == 0 - ? mv_is_num_user_missing (mv, v->f) - : mv_is_str_user_missing (mv, v->s)); -} - /* Returns true if D is a missing value in MV, false otherwise. MV must be a set of numeric missing values. */ -bool -mv_is_num_user_missing (const struct missing_values *mv, double d) +static bool +is_num_user_missing (const struct missing_values *mv, double d) { const union value *v = mv->values; assert (mv->width == 0); switch (mv->type) { - case MV_NONE: + case MVT_NONE: return false; - case MV_1: + case MVT_1: return v[0].f == d; - case MV_2: + case MVT_2: return v[0].f == d || v[1].f == d; - case MV_3: + case MVT_3: return v[0].f == d || v[1].f == d || v[2].f == d; - case MV_RANGE: + case MVT_RANGE: return v[1].f <= d && d <= v[2].f; - case MV_RANGE_1: + case MVT_RANGE_1: return v[0].f == d || (v[1].f <= d && d <= v[2].f); } NOT_REACHED (); @@ -408,37 +380,63 @@ mv_is_num_user_missing (const struct missing_values *mv, double d) /* Returns true if S[] is a missing value in MV, false otherwise. MV must be a set of string missing values. S[] must contain exactly as many characters as MV's width. */ -bool -mv_is_str_user_missing (const struct missing_values *mv, +static bool +is_str_user_missing (const struct missing_values *mv, const char s[]) { const union value *v = mv->values; assert (mv->width > 0); switch (mv->type) { - case MV_NONE: + case MVT_NONE: return false; - case MV_1: + case MVT_1: return !memcmp (v[0].s, s, mv->width); - case MV_2: + case MVT_2: return (!memcmp (v[0].s, s, mv->width) || !memcmp (v[1].s, s, mv->width)); - case MV_3: + case MVT_3: return (!memcmp (v[0].s, s, mv->width) || !memcmp (v[1].s, s, mv->width) || !memcmp (v[2].s, s, mv->width)); - case MV_RANGE: - case MV_RANGE_1: + case MVT_RANGE: + case MVT_RANGE_1: NOT_REACHED (); } NOT_REACHED (); } -/* Returns true if MV is a set of numeric missing values and V is - the system missing value. */ +/* Returns true if V is a missing value in the given CLASS in MV, + false otherwise. */ bool -mv_is_value_system_missing (const struct missing_values *mv, - const union value *v) +mv_is_value_missing (const struct missing_values *mv, const union value *v, + enum mv_class class) { - return mv->width == 0 && v->f == SYSMIS; + return (mv->width == 0 + ? mv_is_num_missing (mv, v->f, class) + : mv_is_str_missing (mv, v->s, class)); +} + +/* Returns true if D is a missing value in the given CLASS in MV, + false otherwise. + MV must be a set of numeric missing values. */ +bool +mv_is_num_missing (const struct missing_values *mv, double d, + enum mv_class class) +{ + assert (mv->width == 0); + return ((class & MV_SYSTEM && d == SYSMIS) + || (class & MV_USER && is_num_user_missing (mv, d))); +} + +/* Returns true if S[] is a missing value in the given CLASS in + MV, false otherwise. + MV must be a set of string missing values. + S[] must contain exactly as many characters as MV's width. */ +bool +mv_is_str_missing (const struct missing_values *mv, const char s[], + enum mv_class class) +{ + assert (mv->width > 0); + return class & MV_USER && is_str_user_missing (mv, s); } diff --git a/src/data/missing-values.h b/src/data/missing-values.h index 535e99a8..68348ea3 100644 --- a/src/data/missing-values.h +++ b/src/data/missing-values.h @@ -22,30 +22,26 @@ #include #include "value.h" -/* Types of user-missing values. - Invisible--use access functions defined below instead. */ -enum mv_type - { - MV_NONE = 0, /* No user-missing values. */ - MV_1 = 1, /* One user-missing value. */ - MV_2 = 2, /* Two user-missing values. */ - MV_3 = 3, /* Three user-missing values. */ - MV_RANGE = 4, /* A range of user-missing values. */ - MV_RANGE_1 = 5 /* A range plus an individual value. */ - }; - /* Missing values. Opaque--use access functions defined below. */ struct missing_values { - enum mv_type type; /* Number and type of missing values. */ + int type; /* Types of missing values, one of MVT_*. */ int width; /* 0=numeric, otherwise string width. */ union value values[3]; /* Missing values. [y,z] are the range. */ }; +/* Classes of missing values. */ +enum mv_class + { + MV_NEVER = 0, /* Never considered missing. */ + MV_USER = 1, /* Missing if value is user-missing. */ + MV_SYSTEM = 2, /* Missing if value is system-missing. */ + MV_ANY = MV_USER | MV_SYSTEM /* Missing if it is user or system-missing. */ + }; void mv_init (struct missing_values *, int width); -void mv_set_type(struct missing_values *mv, enum mv_type type); +void mv_clear (struct missing_values *); void mv_copy (struct missing_values *, const struct missing_values *); bool mv_is_empty (const struct missing_values *); @@ -74,19 +70,11 @@ void mv_resize (struct missing_values *, int width); typedef bool mv_is_missing_func (const struct missing_values *, const union value *); -/* Is a value system or user missing? */ -bool mv_is_value_missing (const struct missing_values *, const union value *); -bool mv_is_num_missing (const struct missing_values *, double); -bool mv_is_str_missing (const struct missing_values *, const char[]); - -/* Is a value user missing? */ -bool mv_is_value_user_missing (const struct missing_values *, - const union value *); -bool mv_is_num_user_missing (const struct missing_values *, double); -bool mv_is_str_user_missing (const struct missing_values *, const char[]); - -/* Is a value system missing? */ -bool mv_is_value_system_missing (const struct missing_values *, - const union value *); +/* Is a value missing? */ +bool mv_is_value_missing (const struct missing_values *, const union value *, + enum mv_class); +bool mv_is_num_missing (const struct missing_values *, double, enum mv_class); +bool mv_is_str_missing (const struct missing_values *, const char[], + enum mv_class); #endif /* missing-values.h */ diff --git a/src/data/procedure.c b/src/data/procedure.c index 8aec2c9f..29dffbca 100644 --- a/src/data/procedure.c +++ b/src/data/procedure.c @@ -978,7 +978,7 @@ filter_trns_proc (void *filter_var_, { struct variable *filter_var = filter_var_; double f = case_num (c, filter_var); - return (f != 0.0 && !var_is_num_missing (filter_var, f) + return (f != 0.0 && !var_is_num_missing (filter_var, f, MV_ANY) ? TRNS_CONTINUE : TRNS_DROP_CASE); } diff --git a/src/data/variable.c b/src/data/variable.c index cf576b12..266d0c2b 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -466,64 +466,32 @@ var_has_missing_values (const struct variable *v) return !mv_is_empty (&v->miss); } -/* Returns true if VALUE is system missing or user-missing value - for V, false otherwise. */ +/* Returns true if VALUE is in the given CLASS of missing values + in V, false otherwise. */ bool -var_is_value_missing (const struct variable *v, const union value *value) +var_is_value_missing (const struct variable *v, const union value *value, + enum mv_class class) { - return mv_is_value_missing (&v->miss, value); + return mv_is_value_missing (&v->miss, value, class); } -/* Returns true if D is system missing or a missing value in V, - false otherwise. +/* Returns true if D is in the given CLASS of missing values in + V, false otherwise. V must be a numeric variable. */ bool -var_is_num_missing (const struct variable *v, double d) +var_is_num_missing (const struct variable *v, double d, enum mv_class class) { - return mv_is_num_missing (&v->miss, d); + return mv_is_num_missing (&v->miss, d, class); } /* Returns true if S[] is a missing value for V, false otherwise. S[] must contain exactly as many characters as V's width. V must be a string variable. */ bool -var_is_str_missing (const struct variable *v, const char s[]) +var_is_str_missing (const struct variable *v, const char s[], + enum mv_class class) { - return mv_is_str_missing (&v->miss, s); -} - -/* Returns true if VALUE is a missing value for V, false - otherwise. */ -bool -var_is_value_user_missing (const struct variable *v, const union value *value) -{ - return mv_is_value_user_missing (&v->miss, value); -} - -/* Returns true if D is a user-missing value for V, false - otherwise. V must be a numeric variable. */ -bool -var_is_num_user_missing (const struct variable *v, double d) -{ - return mv_is_num_user_missing (&v->miss, d); -} - -/* Returns true if S[] is a missing value for V, false otherwise. - V must be a string variable. - S[] must contain exactly as many characters as V's width. */ -bool -var_is_str_user_missing (const struct variable *v, const char s[]) -{ - return mv_is_str_user_missing (&v->miss, s); -} - -/* Returns true if V is a numeric variable and VALUE is the - system missing value. */ -bool -var_is_value_system_missing (const struct variable *v, - const union value *value) -{ - return mv_is_value_system_missing (&v->miss, value); + return mv_is_str_missing (&v->miss, s, class); } /* Returns variable V's value labels, diff --git a/src/data/variable.h b/src/data/variable.h index 0ab2821d..88d9b5a7 100644 --- a/src/data/variable.h +++ b/src/data/variable.h @@ -20,8 +20,8 @@ #define variable_h 1 #include -#include "config.h" #include +#include union value; @@ -73,17 +73,10 @@ void var_set_missing_values (struct variable *, const struct missing_values *); void var_clear_missing_values (struct variable *); bool var_has_missing_values (const struct variable *); -typedef bool var_is_missing_func (const struct variable *, - const union value *); -bool var_is_value_missing (const struct variable *, const union value *); -bool var_is_num_missing (const struct variable *, double); -bool var_is_str_missing (const struct variable *, const char[]); -bool var_is_value_user_missing (const struct variable *, - const union value *); -bool var_is_num_user_missing (const struct variable *, double); -bool var_is_str_user_missing (const struct variable *, const char[]); -bool var_is_value_system_missing (const struct variable *, - const union value *); +bool var_is_value_missing (const struct variable *, const union value *, + enum mv_class); +bool var_is_num_missing (const struct variable *, double, enum mv_class); +bool var_is_str_missing (const struct variable *, const char[], enum mv_class); /* Value labels. */ const struct val_labs *var_get_value_labels (const struct variable *); diff --git a/src/language/expressions/operations.def b/src/language/expressions/operations.def index 59f2493e..be33a0d9 100644 --- a/src/language/expressions/operations.def +++ b/src/language/expressions/operations.def @@ -927,7 +927,7 @@ no_opt operator VEC_ELEM_NUM (idx) { const struct variable *var = vector_get_var (v, (size_t) idx - 1); double value = case_num (c, var); - return !var_is_num_user_missing (var, value) ? value : SYSMIS; + return !var_is_num_missing (var, value, MV_USER) ? value : SYSMIS; } else { @@ -974,7 +974,7 @@ no_opt operator NUM_VAR () num_var v; { double d = case_num (c, v); - return !var_is_num_user_missing (v, d) ? d : SYSMIS; + return !var_is_num_missing (v, d, MV_USER) ? d : SYSMIS; } no_opt string operator STR_VAR () @@ -994,7 +994,7 @@ no_opt perm_only function LAG (num_var v, pos_int n_before) if (c != NULL) { double x = case_num (c, v); - return !var_is_num_user_missing (v, x) ? x : SYSMIS; + return !var_is_num_missing (v, x, MV_USER) ? x : SYSMIS; } else return SYSMIS; @@ -1007,7 +1007,7 @@ no_opt perm_only function LAG (num_var v) if (c != NULL) { double x = case_num (c, v); - return !var_is_num_user_missing (v, x) ? x : SYSMIS; + return !var_is_num_missing (v, x, MV_USER) ? x : SYSMIS; } else return SYSMIS; diff --git a/src/language/stats/ChangeLog b/src/language/stats/ChangeLog index 6b0c3e63..970c0b1e 100644 --- a/src/language/stats/ChangeLog +++ b/src/language/stats/ChangeLog @@ -1,3 +1,20 @@ +Fri Dec 22 14:04:09 2006 Ben Pfaff + + Simplify missing value handling. + + * aggregate.c (struct agr_var): Remove `bool include_missing', add + `enum mv_class exclude'. Remove `int missing', add `bool + saw_missing'. Update users. + + * descriptives.c (struct dsc_trns): Removed `int + include_user_missing', add `enum mv_class exclude'. Update users. + (struct dsc_proc): Ditto. + + * examine.q: (static var value_is_missing): Rename + `exclude_values', change type to `enum mv_class'. Update users. + + * rank.q: Ditto. + Fri Dec 22 19:22:18 WST 2006 John Darrington * frequencies.q : Fixed bug #17420, where the table bounds were overun diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index 7d1c7a7a..6a275b09 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -67,14 +67,14 @@ struct agr_var struct variable *src; /* Source variable. */ struct variable *dest; /* Target variable. */ int function; /* Function. */ - int include_missing; /* 1=Include user-missing values. */ + enum mv_class exclude; /* Classes of missing values to exclude. */ union agr_argument arg[2]; /* Arguments. */ /* Accumulated during AGGREGATE execution. */ double dbl[3]; int int1, int2; char *string; - int missing; + bool saw_missing; struct moments1 *moments; }; @@ -391,7 +391,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s size_t n_dest; struct string function_name; - int include_missing; + enum mv_class exclude; const struct agr_func *function; int func_index; @@ -450,14 +450,14 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s goto error; } - include_missing = 0; + exclude = MV_ANY; ds_init_string (&function_name, lex_tokstr (lexer)); ds_chomp (&function_name, '.'); if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.') - include_missing = 1; + exclude = MV_SYSTEM; for (function = agr_func_tab; function->name; function++) if (!strcasecmp (function->name, ds_cstr (&function_name))) @@ -652,7 +652,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, s v->dest = destvar; } - v->include_missing = include_missing; + v->exclude = exclude; if (v->src != NULL) { @@ -793,9 +793,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const union value *v = case_data (input, iter->src); int src_width = var_get_width (iter->src); - if (iter->include_missing - ? var_is_numeric (iter->src) && v->f == SYSMIS - : var_is_value_missing (iter->src, v)) + if (var_is_value_missing (iter->src, v, iter->exclude)) { switch (iter->function) { @@ -808,7 +806,7 @@ accumulate_aggregate_info (struct agr_proc *agr, iter->int1++; break; } - iter->missing = 1; + iter->saw_missing = true; continue; } @@ -977,7 +975,7 @@ dump_aggregate_info (struct agr_proc *agr, struct ccase *output) { union value *v = case_data_rw (output, i->dest); - if (agr->missing == COLUMNWISE && i->missing != 0 + if (agr->missing == COLUMNWISE && i->saw_missing && (i->function & FUNC) != N && (i->function & FUNC) != NU && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS) { @@ -1091,7 +1089,7 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) for (iter = agr->agr_vars; iter; iter = iter->next) { - iter->missing = 0; + iter->saw_missing = false; iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0; iter->int1 = iter->int2 = 0; switch (iter->function) diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 04a2a54c..775e415a 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -569,6 +569,11 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds) { bool bad_warn = true; + /* Missing values to exclude. */ + enum mv_class exclude = (cmd.miss == CRS_TABLE ? MV_ANY + : cmd.miss == CRS_INCLUDE ? MV_SYSTEM + : MV_NEVER); + /* Case weight. */ double weight = dict_get_case_weight (dataset_dict (ds), c, &bad_warn); @@ -591,9 +596,7 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds) for (j = 0; j < x->nvar; j++) { const union value *v = case_data (c, x->vars[j]); - if ((cmd.miss == CRS_TABLE && var_is_value_missing (x->vars[j], v)) - || (cmd.miss == CRS_INCLUDE - && var_is_value_system_missing (x->vars[j], v))) + if (var_is_value_missing (x->vars[j], v, exclude)) { x->missing += weight; goto next_crosstab; @@ -663,7 +666,8 @@ calc_integer (const struct ccase *c, void *aux UNUSED, const struct dataset *ds) /* Note that the first test also rules out SYSMIS. */ if ((value < vr->min || value >= vr->max) - || (cmd.miss == CRS_TABLE && var_is_num_user_missing (v, value))) + || (cmd.miss == CRS_TABLE + && var_is_num_missing (v, value, MV_USER))) { x->missing += weight; goto next_crosstab; @@ -1421,7 +1425,7 @@ delete_missing (void) int r; for (r = 0; r < n_rows; r++) - if (var_is_num_user_missing (x->vars[ROW_VAR], rows[r].f)) + if (var_is_num_missing (x->vars[ROW_VAR], rows[r].f, MV_USER)) { int c; @@ -1435,7 +1439,7 @@ delete_missing (void) int c; for (c = 0; c < n_cols; c++) - if (var_is_num_user_missing (x->vars[COL_VAR], cols[c].f)) + if (var_is_num_missing (x->vars[COL_VAR], cols[c].f, MV_USER)) { int r; @@ -1675,7 +1679,7 @@ table_value_missing (struct tab_table *table, int c, int r, unsigned char opt, s.string = tab_alloc (table, print->w); format_short (s.string, print, v); s.length = strlen (s.string); - if (cmd.miss == CRS_REPORT && var_is_num_user_missing (var, v->f)) + if (cmd.miss == CRS_REPORT && var_is_num_missing (var, v->f, MV_USER)) s.string[s.length++] = 'M'; while (s.length && *s.string == ' ') { @@ -1758,8 +1762,9 @@ display_crosstabulation (void) bool mark_missing = false; double expected_value = row_tot[r] * col_tot[c] / W; if (cmd.miss == CRS_REPORT - && (var_is_num_user_missing (x->vars[COL_VAR], cols[c].f) - || var_is_num_user_missing (x->vars[ROW_VAR], rows[r].f))) + && (var_is_num_missing (x->vars[COL_VAR], cols[c].f, MV_USER) + || var_is_num_missing (x->vars[ROW_VAR], rows[r].f, + MV_USER))) mark_missing = true; for (i = 0; i < num_cells; i++) { @@ -1823,7 +1828,7 @@ display_crosstabulation (void) bool mark_missing = false; if (cmd.miss == CRS_REPORT - && var_is_num_user_missing (x->vars[ROW_VAR], rows[r].f)) + && var_is_num_missing (x->vars[ROW_VAR], rows[r].f, MV_USER)) mark_missing = true; for (i = 0; i < num_cells; i++) @@ -1878,7 +1883,7 @@ display_crosstabulation (void) int i; if (cmd.miss == CRS_REPORT && c < n_cols - && var_is_num_user_missing (x->vars[COL_VAR], cols[c].f)) + && var_is_num_missing (x->vars[COL_VAR], cols[c].f, MV_USER)) mark_missing = true; for (i = 0; i < num_cells; i++) diff --git a/src/language/stats/descriptives.c b/src/language/stats/descriptives.c index 6afb6b53..1f7fed89 100644 --- a/src/language/stats/descriptives.c +++ b/src/language/stats/descriptives.c @@ -77,7 +77,7 @@ struct dsc_trns struct variable **vars; /* Variables for listwise missing checks. */ size_t var_cnt; /* Number of variables. */ enum dsc_missing_type missing_type; /* Treatment of missing values. */ - int include_user_missing; /* Nonzero to include user-missing values. */ + enum mv_class exclude; /* Classes of missing values to exclude. */ }; /* Statistics. Used as bit indexes, so must be 32 or fewer. */ @@ -150,7 +150,7 @@ struct dsc_proc /* User options. */ enum dsc_missing_type missing_type; /* Treatment of missing values. */ - int include_user_missing; /* Nonzero to include user-missing values. */ + enum mv_class exclude; /* Classes of missing values to exclude. */ int show_var_labels; /* Nonzero to show variable labels. */ int show_index; /* Nonzero to show variable index. */ enum dsc_format format; /* Output format. */ @@ -205,7 +205,7 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) dsc->vars = NULL; dsc->var_cnt = 0; dsc->missing_type = DSC_VARIABLE; - dsc->include_user_missing = 0; + dsc->exclude = MV_ANY; dsc->show_var_labels = 1; dsc->show_index = 0; dsc->format = DSC_LINE; @@ -229,7 +229,7 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds) else if (lex_match_id (lexer, "LISTWISE")) dsc->missing_type = DSC_LISTWISE; else if (lex_match_id (lexer, "INCLUDE")) - dsc->include_user_missing = 1; + dsc->exclude = MV_SYSTEM; else { lex_error (lexer, NULL); @@ -595,9 +595,7 @@ descriptives_trns_proc (void *trns_, struct ccase * c, for (vars = t->vars; vars < t->vars + t->var_cnt; vars++) { double score = case_num (c, *vars); - if ( score == SYSMIS - || (!t->include_user_missing - && var_is_num_user_missing (*vars, score))) + if (var_is_num_missing (*vars, score, t->exclude)) { all_sysmis = 1; break; @@ -610,10 +608,8 @@ descriptives_trns_proc (void *trns_, struct ccase * c, double input = case_num (c, z->src_var); double *output = &case_data_rw (c, z->z_var)->f; - if (z->mean == SYSMIS || z->std_dev == SYSMIS - || all_sysmis || input == SYSMIS - || (!t->include_user_missing - && var_is_num_user_missing (z->src_var, input))) + if (z->mean == SYSMIS || z->std_dev == SYSMIS || all_sysmis + || var_is_num_missing (z->src_var, input, t->exclude)) *output = SYSMIS; else *output = (input - z->mean) / z->std_dev; @@ -648,7 +644,7 @@ setup_z_trns (struct dsc_proc *dsc, struct dataset *ds) t->z_scores = xnmalloc (cnt, sizeof *t->z_scores); t->z_score_cnt = cnt; t->missing_type = dsc->missing_type; - t->include_user_missing = dsc->include_user_missing; + t->exclude = dsc->exclude; if ( t->missing_type == DSC_LISTWISE ) { t->var_cnt = dsc->var_cnt; @@ -741,9 +737,7 @@ calc_descriptives (const struct ccase *first, double x = case_num (&c, dv->v); if (dsc->missing_type != DSC_LISTWISE - && (x == SYSMIS - || (!dsc->include_user_missing - && var_is_num_user_missing (dv->v, x)))) + && var_is_num_missing (dv->v, x, dsc->exclude)) { dv->missing += weight; continue; @@ -773,8 +767,7 @@ calc_descriptives (const struct ccase *first, continue; /* Check for missing values. */ - if (listwise_missing (dsc, &c) - && dsc->missing_type == DSC_LISTWISE) + if (dsc->missing_type == DSC_LISTWISE && listwise_missing (dsc, &c)) continue; for (i = 0; i < dsc->var_cnt; i++) @@ -783,9 +776,7 @@ calc_descriptives (const struct ccase *first, double x = case_num (&c, dv->v); if (dsc->missing_type != DSC_LISTWISE - && (x == SYSMIS - || (!dsc->include_user_missing - && var_is_num_user_missing (dv->v, x)))) + && var_is_num_missing (dv->v, x, dsc->exclude)) continue; if (dv->moments != NULL) @@ -849,9 +840,7 @@ listwise_missing (struct dsc_proc *dsc, const struct ccase *c) struct dsc_var *dv = &dsc->vars[i]; double x = case_num (c, dv->v); - if (x == SYSMIS - || (!dsc->include_user_missing - && var_is_num_user_missing (dv->v, x))) + if (var_is_num_missing (dv->v, x, dsc->exclude)) return true; } return false; diff --git a/src/language/stats/examine.q b/src/language/stats/examine.q index b08f6d7a..abbf9fc3 100644 --- a/src/language/stats/examine.q +++ b/src/language/stats/examine.q @@ -178,9 +178,8 @@ const char *factor_to_string_concise (const struct factor *fctr, -/* Function to use for testing for missing values */ -static var_is_missing_func *value_is_missing; - +/* Categories of missing values to exclude. */ +static enum mv_class exclude_values; /* PERCENTILES */ @@ -206,10 +205,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) } /* If /MISSING=INCLUDE is set, then user missing values are ignored */ - if (cmd.incl == XMN_INCLUDE ) - value_is_missing = var_is_value_system_missing; - else - value_is_missing = var_is_value_missing; + exclude_values = cmd.incl == XMN_INCLUDE ? MV_SYSTEM : MV_ANY; if ( cmd.st_n == SYSMIS ) cmd.st_n = 5; @@ -695,7 +691,7 @@ factor_calc (const struct ccase *c, int case_no, double weight, var_get_width (var) ); - if ( value_is_missing (var, val) || case_missing ) + if (case_missing || var_is_value_missing (var, val, exclude_values)) { free (val); continue; @@ -762,7 +758,7 @@ run_examine (const struct ccase *first, const struct casefile *cf, var_get_width (var) ); - if ( value_is_missing (var, val)) + if ( var_is_value_missing (var, val, exclude_values)) case_missing = 1; free (val); @@ -777,7 +773,8 @@ run_examine (const struct ccase *first, const struct casefile *cf, var_get_width (var) ); - if ( value_is_missing (var, val) || case_missing ) + if ( var_is_value_missing (var, val, exclude_values) + || case_missing ) { free (val) ; continue ; diff --git a/src/language/stats/frequencies.q b/src/language/stats/frequencies.q index 506d7ca3..34223e10 100644 --- a/src/language/stats/frequencies.q +++ b/src/language/stats/frequencies.q @@ -700,7 +700,7 @@ not_missing (const void *f_, const void *v_) const struct freq *f = f_; const struct variable *v = v_; - return !var_is_value_missing (v, f->value); + return !var_is_value_missing (v, f->value, MV_ANY); } /* Summarizes the frequency table data for variable V. */ @@ -1564,7 +1564,7 @@ freq_tab_to_hist(const struct freq_tab *ft, const struct variable *var) /* Find out the extremes of the x value */ for ( frq = hsh_first(fh, &hi); frq != 0; frq = hsh_next(fh, &hi) ) { - if ( var_is_value_missing(var, frq->value)) + if (var_is_value_missing(var, frq->value, MV_ANY)) continue; if ( frq->value[0].f < x_min ) x_min = frq->value[0].f ; diff --git a/src/language/stats/npar.q b/src/language/stats/npar.q index 2881ff9c..2f99b614 100644 --- a/src/language/stats/npar.q +++ b/src/language/stats/npar.q @@ -180,7 +180,7 @@ cmd_npar_tests (struct lexer *lexer, struct dataset *ds) } npar_specs.filter = - casefilter_create (cmd.incl == NPAR_EXCLUDE, 0, 0); + casefilter_create (cmd.incl == NPAR_EXCLUDE ? MV_ANY : MV_SYSTEM, 0, 0); if ( cmd.miss == NPAR_LISTWISE ) casefilter_add_variables (npar_specs.filter, diff --git a/src/language/stats/oneway.q b/src/language/stats/oneway.q index ed0add58..69ab5a48 100644 --- a/src/language/stats/oneway.q +++ b/src/language/stats/oneway.q @@ -900,7 +900,8 @@ run_oneway(const struct ccase *first, const struct casefile *cf, precalc(cmd); - filter = casefilter_create ( (cmd->incl != ONEWAY_INCLUDE), + filter = casefilter_create ( (cmd->incl != ONEWAY_INCLUDE + ? MV_ANY : MV_SYSTEM), vars, n_vars ); for(r = casefile_get_reader (cf, filter); diff --git a/src/language/stats/rank.q b/src/language/stats/rank.q index 894d2769..63319d9b 100644 --- a/src/language/stats/rank.q +++ b/src/language/stats/rank.q @@ -148,8 +148,8 @@ struct rank_spec }; -/* Function to use for testing for missing values */ -static mv_is_missing_func *value_is_missing; +/* Categories of missing values to exclude. */ +static enum mv_class exclude_values; static struct rank_spec *rank_specs; static size_t n_rank_specs; @@ -547,7 +547,7 @@ rank_cases (struct casereader *cr, casereader_destroy (lookahead); cc_1 = cc; - if ( !value_is_missing (mv, this_value) ) + if ( !mv_is_value_missing (mv, this_value, exclude_values) ) cc += c; do @@ -556,7 +556,7 @@ rank_cases (struct casereader *cr, { const struct variable *dst_var = rs[i].destvars[dest_var_index]; - if ( value_is_missing (mv, this_value) ) + if ( mv_is_value_missing (mv, this_value, exclude_values) ) case_data_rw (&this_case, dst_var)->f = SYSMIS; else case_data_rw (&this_case, dst_var)->f = @@ -566,7 +566,7 @@ rank_cases (struct casereader *cr, } while (n-- > 0 && casereader_read_xfer (cr, &this_case)); - if ( !value_is_missing (mv, this_value) ) + if ( !mv_is_value_missing (mv, this_value, exclude_values) ) iter++; } @@ -615,7 +615,7 @@ rank_sorted_casefile (struct casefile *cf, double w = 0.0; this_value = case_data_idx( &group_case, ultimate_crit->fv); - if ( !value_is_missing(mv, this_value) ) + if ( !mv_is_value_missing (mv, this_value, exclude_values) ) w = dict_get_case_weight (dict, &group_case, &warn); while (casereader_read (lookahead, &this_case)) @@ -636,7 +636,7 @@ rank_sorted_casefile (struct casefile *cf, case_destroy (&group_case); case_move (&group_case, &this_case); } - if ( !value_is_missing (mv, this_value) ) + if ( !mv_is_value_missing (mv, this_value, exclude_values) ) w += c; case_destroy (&this_case); } @@ -773,11 +773,7 @@ cmd_rank (struct lexer *lexer, struct dataset *ds) } /* If /MISSING=INCLUDE is set, then user missing values are ignored */ - if (cmd.miss == RANK_INCLUDE ) - value_is_missing = mv_is_value_system_missing; - else - value_is_missing = mv_is_value_missing; - + exclude_values = cmd.miss == RANK_INCLUDE ? MV_SYSTEM : MV_ANY; /* Default to /RANK if no function subcommands are given */ if ( !( cmd.sbc_normal || cmd.sbc_ntiles || cmd.sbc_proportion || diff --git a/src/language/stats/regression.q b/src/language/stats/regression.q index 2944cefc..a5851ff3 100644 --- a/src/language/stats/regression.q +++ b/src/language/stats/regression.q @@ -978,7 +978,7 @@ mark_missing_cases (const struct casefile *cf, struct variable *v, val = case_data (&c, v); cat_value_update (v, val); - if (var_is_value_missing (v, val)) + if (var_is_value_missing (v, val, MV_ANY)) { if (!is_missing_case[row]) { diff --git a/src/language/stats/t-test.q b/src/language/stats/t-test.q index 53136abc..450a9aba 100644 --- a/src/language/stats/t-test.q +++ b/src/language/stats/t-test.q @@ -1785,7 +1785,8 @@ calculate(const struct ccase *first, const struct casefile *cf, struct cmd_t_test *cmd = (struct cmd_t_test *) cmd_; - struct casefilter *filter = casefilter_create (cmd->miss != TTS_INCLUDE, + struct casefilter *filter = casefilter_create ((cmd->miss != TTS_INCLUDE + ? MV_ANY : MV_SYSTEM), NULL, 0); if ( cmd->miss == TTS_LISTWISE ) diff --git a/src/language/xforms/count.c b/src/language/xforms/count.c index 09e2693f..5cfc0515 100644 --- a/src/language/xforms/count.c +++ b/src/language/xforms/count.c @@ -61,7 +61,7 @@ struct criteria struct variable **vars; size_t var_cnt; - /* Count special values?. */ + /* Count special values? */ bool count_system_missing; /* Count system missing? */ bool count_user_missing; /* Count user missing? */ @@ -277,11 +277,13 @@ count_numeric (struct criteria *crit, struct ccase *c) for (i = 0; i < crit->var_cnt; i++) { double x = case_num (c, crit->vars[i]); - if (x == SYSMIS) - counter += crit->count_system_missing; - else if (crit->count_user_missing - && var_is_num_user_missing (crit->vars[i], x)) - counter++; + if (var_is_num_missing (crit->vars[i], x, MV_ANY)) + { + if (x == SYSMIS + ? crit->count_system_missing + : crit->count_user_missing) + counter++; + } else { struct num_value *v; diff --git a/src/language/xforms/recode.c b/src/language/xforms/recode.c index 4fdb5719..01f3bf76 100644 --- a/src/language/xforms/recode.c +++ b/src/language/xforms/recode.c @@ -554,7 +554,7 @@ find_src_numeric (struct recode_trns *trns, double value, struct variable *v) match = value == in->x.f; break; case MAP_MISSING: - match = var_is_num_user_missing (v, value); + match = var_is_num_missing (v, value, MV_USER); break; case MAP_RANGE: match = value >= in->x.f && value <= in->y.f; diff --git a/src/math/chart-geometry.c b/src/math/chart-geometry.c index 7449cd79..0f6da46e 100644 --- a/src/math/chart-geometry.c +++ b/src/math/chart-geometry.c @@ -16,7 +16,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - +#include #include #include diff --git a/src/math/coefficient.c b/src/math/coefficient.c index e3d9aee1..fe0cd438 100644 --- a/src/math/coefficient.c +++ b/src/math/coefficient.c @@ -21,6 +21,7 @@ /* Accessor functions for matching coefficients and variables. */ +#include #include #include #include "src/math/design-matrix.h" diff --git a/src/math/linreg/linreg.c b/src/math/linreg/linreg.c index 6bbd94c5..9224cc6b 100644 --- a/src/math/linreg/linreg.c +++ b/src/math/linreg/linreg.c @@ -18,6 +18,7 @@ Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. */ +#include #include #include diff --git a/src/math/linreg/predict.c b/src/math/linreg/predict.c index 9303ca60..7f404fcf 100644 --- a/src/math/linreg/predict.c +++ b/src/math/linreg/predict.c @@ -18,6 +18,7 @@ Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. */ +#include #include #include #include diff --git a/src/math/ts/innovations.c b/src/math/ts/innovations.c index 107d8ba4..4ac439eb 100644 --- a/src/math/ts/innovations.c +++ b/src/math/ts/innovations.c @@ -28,6 +28,7 @@ 0-387-97429-6. Sections 5.2, 8.3 and 8.4. */ +#include #include #include #include diff --git a/src/ui/gui/data-sheet.c b/src/ui/gui/data-sheet.c index 5b90b892..03cf1c4f 100644 --- a/src/ui/gui/data-sheet.c +++ b/src/ui/gui/data-sheet.c @@ -18,6 +18,7 @@ 02110-1301, USA. */ +#include #include #include diff --git a/src/ui/gui/missing-val-dialog.c b/src/ui/gui/missing-val-dialog.c index 2da1d50d..34951710 100644 --- a/src/ui/gui/missing-val-dialog.c +++ b/src/ui/gui/missing-val-dialog.c @@ -90,7 +90,7 @@ missing_val_dialog_accept(GtkWidget *w, gpointer data) gint nvals = 0; gint badvals = 0; gint i; - mv_set_type(&dialog->mvl, MV_NONE); + mv_clear(&dialog->mvl); for(i = 0 ; i < 3 ; ++i ) { gchar *text = @@ -150,7 +150,7 @@ missing_val_dialog_accept(GtkWidget *w, gpointer data) discrete_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->discrete))); - mv_set_type(&dialog->mvl, MV_NONE); + mv_clear(&dialog->mvl); mv_add_num_range(&dialog->mvl, low_val.f, high_val.f); if ( discrete_text && strlen(g_strstrip(discrete_text)) > 0 ) @@ -171,7 +171,7 @@ missing_val_dialog_accept(GtkWidget *w, gpointer data) if (gtk_toggle_button_get_active(dialog->button_none)) - mv_set_type(&dialog->mvl, MV_NONE); + mv_clear(&dialog->mvl); var_set_missing_values (dialog->pv, &dialog->mvl); diff --git a/src/ui/gui/psppire-dict.c b/src/ui/gui/psppire-dict.c index ae047d31..070ce240 100644 --- a/src/ui/gui/psppire-dict.c +++ b/src/ui/gui/psppire-dict.c @@ -17,7 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - +#include #include #include -- 2.30.2