DATA LIST: Fix assertion when RECORDS given twice with decreasing value.
[pspp] / src / data / missing-values.c
index 742ddd2acfe7891682ec5da39f79db867e36bd82..267d34fb9102247bec8d5e02d139640297935716 100644 (file)
@@ -115,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;
 }
@@ -177,7 +177,7 @@ mv_add_str (struct missing_values *mv, const uint8_t s[], size_t len)
       return false;
 
   value_init (&v, mv->width);
-  buf_copy_rpad (CHAR_CAST (char *, value_str_rw (&v, mv->width)), 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);
@@ -424,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 ();
@@ -447,7 +447,7 @@ 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_str_missing (mv, v->s, class));
 }
 
 /* Returns true if D is a missing value in the given CLASS in MV,
@@ -474,6 +474,34 @@ mv_is_str_missing (const struct missing_values *mv, const uint8_t s[],
   return class & MV_USER && is_str_user_missing (mv, s);
 }
 
+/* Like mv_is_value_missing(), this tests whether V is a missing value
+   in the given CLASS 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. */
+bool
+mv_is_value_missing_varwidth (const struct missing_values *mv,
+                              const union value *v, int vw,
+                              enum mv_class class)
+{
+  int mvw = mv->width;
+  if (mvw == vw)
+    return mv_is_value_missing (mv, v, class);
+
+  /* Make sure they're both strings. */
+  assert (mvw && vw);
+  if (!(class & MV_USER) || 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 true;
+  return false;
+}
+
 char *
 mv_to_string (const struct missing_values *mv, const char *encoding)
 {
@@ -501,8 +529,7 @@ mv_to_string (const struct missing_values *mv, const char *encoding)
       else
         {
           char *mvs = recode_string (
-            "UTF-8", encoding,
-            CHAR_CAST (char *, value_str (value, mv->width)),
+            "UTF-8", encoding, CHAR_CAST (char *, value->s),
             MIN (mv->width, MV_MAX_STRING));
           ds_put_format (&s, "\"%s\"", mvs);
           free (mvs);