X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fmissing-values.c;h=44d0bf9ee67315148224715f3ae4f083019c3636;hb=f4491cda2715c59495d963d0a3d8ae4518c1c13d;hp=61bb9bcb13c4968a4500fc4fc98ee13e2f631c1b;hpb=b5c82cc9aabe7e641011130240ae1b2e84348e23;p=pspp diff --git a/src/data/missing-values.c b/src/data/missing-values.c index 61bb9bcb13..44d0bf9ee6 100644 --- a/src/data/missing-values.c +++ b/src/data/missing-values.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2005, 2009 Free Software Foundation, Inc. + Copyright (C) 2005, 2009, 2011, 2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,12 +15,19 @@ along with this program. If not, see . */ #include -#include + +#include "data/missing-values.h" + #include #include -#include -#include -#include + +#include "data/variable.h" +#include "libpspp/assertion.h" +#include "libpspp/cast.h" +#include "libpspp/i18n.h" +#include "libpspp/str.h" + +#include "gl/minmax.h" /* Types of user-missing values. Invisible--use access functions defined below instead. */ @@ -108,7 +115,7 @@ mv_is_acceptable (const union value *value, int width) int i; for (i = MV_MAX_STRING; i < width; i++) - if (value_str (value, width)[i] != ' ') + if (value->s[i] != ' ') return false; return true; } @@ -155,19 +162,23 @@ mv_add_value (struct missing_values *mv, const union value *v) NOT_REACHED (); } -/* Attempts to add S to the set of string missing values MV. S - must contain exactly as many characters as MV's width. - Returns true if successful, false if MV has no more room for +/* Attempts to add S, which is LEN bytes long, to the set of string missing + values MV. Returns true if successful, false if MV has no more room for missing values or if S is not an acceptable missing value. */ bool -mv_add_str (struct missing_values *mv, const uint8_t s[]) +mv_add_str (struct missing_values *mv, const uint8_t s[], size_t len) { union value v; bool ok; assert (mv->width > 0); + while (len > mv->width) + if (s[--len] != ' ') + return false; + value_init (&v, mv->width); - memcpy (value_str_rw (&v, mv->width), s, mv->width); + buf_copy_rpad (CHAR_CAST (char *, v.s), mv->width, + CHAR_CAST (char *, s), len, ' '); ok = mv_add_value (mv, &v); value_destroy (&v, mv->width); @@ -413,14 +424,14 @@ is_str_user_missing (const struct missing_values *mv, const uint8_t s[]) case MVT_NONE: return false; case MVT_1: - return !memcmp (value_str (&v[0], mv->width), s, mv->width); + return !memcmp (v[0].s, s, mv->width); case MVT_2: - return (!memcmp (value_str (&v[0], mv->width), s, mv->width) - || !memcmp (value_str (&v[1], mv->width), s, mv->width)); + return (!memcmp (v[0].s, s, mv->width) + || !memcmp (v[1].s, s, mv->width)); case MVT_3: - return (!memcmp (value_str (&v[0], mv->width), s, mv->width) - || !memcmp (value_str (&v[1], mv->width), s, mv->width) - || !memcmp (value_str (&v[2], mv->width), s, mv->width)); + return (!memcmp (v[0].s, s, mv->width) + || !memcmp (v[1].s, s, mv->width) + || !memcmp (v[2].s, s, mv->width)); case MVT_RANGE: case MVT_RANGE_1: NOT_REACHED (); @@ -428,37 +439,97 @@ is_str_user_missing (const struct missing_values *mv, const uint8_t s[]) NOT_REACHED (); } -/* Returns true if V is a missing value in the given CLASS in MV, - false otherwise. */ -bool -mv_is_value_missing (const struct missing_values *mv, const union value *v, - enum mv_class class) +/* Returns MV_USER if V is a user-missing value in MV, MV_SYSTEM if V is + system-missing (and MV is numeric), or 0 if V is not missing. */ +enum mv_class +mv_is_value_missing (const struct missing_values *mv, const union value *v) { return (mv->width == 0 - ? mv_is_num_missing (mv, v->f, class) - : mv_is_str_missing (mv, value_str (v, mv->width), class)); + ? mv_is_num_missing (mv, v->f) + : mv_is_str_missing (mv, v->s)); } -/* 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) +/* Returns MV_USER if V is a user-missing value in MV, MV_SYSTEM if V is + system-missing, or 0 if V is not missing. MV must be a set of numeric + missing values. */ +enum mv_class +mv_is_num_missing (const struct missing_values *mv, double d) { assert (mv->width == 0); - return ((class & MV_SYSTEM && d == SYSMIS) - || (class & MV_USER && is_num_user_missing (mv, d))); + return (d == SYSMIS ? MV_SYSTEM + : is_num_user_missing (mv, d) ? MV_USER + : 0); } -/* 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 uint8_t s[], - enum mv_class class) +/* Returns MV_USER if S[] is a user-missing value in MV, or 0 if V is not + missing. MV must be a set of string missing values. S[] must contain + exactly as many characters as MV's width. */ +enum mv_class +mv_is_str_missing (const struct missing_values *mv, const uint8_t s[]) { assert (mv->width > 0); - return class & MV_USER && is_str_user_missing (mv, s); + return is_str_user_missing (mv, s) ? MV_USER : 0; +} + +/* Like mv_is_value_missing(), this tests whether V is a missing value in MV. + It supports the uncommon case where V and MV might have different widths: + the caller must specify VW, the width of V. MV and VW must be both numeric + or both string. + + Comparison of strings of different width is done by conceptually extending + both strings to infinite width by appending spaces. */ +enum mv_class +mv_is_value_missing_varwidth (const struct missing_values *mv, + const union value *v, int vw) +{ + int mvw = mv->width; + if (mvw == vw) + return mv_is_value_missing (mv, v); + + /* Make sure they're both strings. */ + assert (mvw && vw); + if (mv->type == MVT_NONE) + return false; + + for (int i = 0; i < mv->type; i++) + if (!buf_compare_rpad (CHAR_CAST_BUG (const char *, mv->values[i].s), mvw, + CHAR_CAST_BUG (const char *, v->s), vw)) + return MV_USER; + return 0; +} + +char * +mv_to_string (const struct missing_values *mv, const char *encoding) +{ + struct string s = DS_EMPTY_INITIALIZER; + if (mv_has_range (mv)) + { + double x, y; + mv_get_range (mv, &x, &y); + if (x == LOWEST) + ds_put_format (&s, "LOWEST THRU %.*g", DBL_DIG + 1, y); + else if (y == HIGHEST) + ds_put_format (&s, "%.*g THRU HIGHEST", DBL_DIG + 1, x); + else + ds_put_format (&s, "%.*g THRU %.*g", + DBL_DIG + 1, x, + DBL_DIG + 1, y); + } + for (size_t j = 0; j < mv_n_values (mv); j++) + { + const union value *value = mv_get_value (mv, j); + if (!ds_is_empty (&s)) + ds_put_cstr (&s, "; "); + if (!mv->width) + ds_put_format (&s, "%.*g", DBL_DIG + 1, value->f); + else + { + char *mvs = recode_string ( + "UTF-8", encoding, CHAR_CAST (char *, value->s), + MIN (mv->width, MV_MAX_STRING)); + ds_put_format (&s, "\"%s\"", mvs); + free (mvs); + } + } + return ds_is_empty (&s) ? NULL : ds_steal_cstr (&s); }