pxd: initial work
[pspp] / src / data / mrset.c
index 2f05edb845886786caab5b5ce94503ea22e206c5..ce1a35851e1860b8e7f8894d65b23c113f87bd19 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011, 2012 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
 #include <stdlib.h>
 
 #include "data/dictionary.h"
+#include "data/identifier.h"
 #include "data/val-type.h"
 #include "data/variable.h"
+#include "libpspp/message.h"
+#include "libpspp/pxd.h"
 
 #include "gl/xalloc.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
 /* Creates and returns a clone of OLD.  The caller is responsible for freeing
    the new multiple response set (using mrset_destroy()). */
 struct mrset *
@@ -58,12 +64,35 @@ mrset_destroy (struct mrset *mrset)
       free (mrset->label);
       free (mrset->vars);
       value_destroy (&mrset->counted, mrset->width);
+      free (mrset);
+    }
+}
+
+/* Returns true if the UTF-8 encoded NAME is a valid name for a multiple
+   response set in a dictionary encoded in DICT_ENCODING, false otherwise.  If
+   ISSUE_ERROR is true, issues an explanatory error message on failure. */
+bool
+mrset_is_valid_name (const char *name, const char *dict_encoding,
+                     bool issue_error)
+{
+  if (!id_is_valid (name, dict_encoding, issue_error))
+    return false;
+
+  if (name[0] != '$')
+    {
+      if (issue_error)
+        msg (SE, _("%s is not a valid name for a multiple response "
+                   "set.  Multiple response set names must begin with "
+                   "`$'."), name);
+      return false;
     }
+
+  return true;
 }
 
 /* Checks various constraints on MRSET:
 
-   - MRSET has a valid name for a multiple response set (beginning with '$').
+   - MRSET's name begins with '$' and is valid as an identifier in DICT.
 
    - MRSET has a valid type.
 
@@ -84,7 +113,7 @@ mrset_ok (const struct mrset *mrset, const struct dictionary *dict)
   size_t i;
 
   if (mrset->name == NULL
-      || mrset->name[0] != '$'
+      || !mrset_is_valid_name (mrset->name, dict_get_encoding (dict), false)
       || (mrset->type != MRSET_MD && mrset->type != MRSET_MC)
       || mrset->vars == NULL
       || mrset->n_vars < 2)
@@ -102,3 +131,75 @@ mrset_ok (const struct mrset *mrset, const struct dictionary *dict)
 
   return true;
 }
+
+struct pxd_object *
+mrset_save (const struct mrset *mrset, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_string (&b, mrset->name);
+  pxd_builder_put_string (&b, mrset->label != NULL ? mrset->label : "");
+  pxd_builder_put_u8 (&b, mrset->type);
+
+  pxd_builder_put_size_t (&b, mrset->n_vars);
+  for (i = 0; i < mrset->n_vars; i++)
+    pxd_builder_put_string (&b, var_get_name (mrset->vars[i]));
+
+  if (mrset->type == MRSET_MD)
+    {
+      pxd_builder_put_u8 (&b, mrset->cat_source);
+      pxd_builder_put_bool (&b, mrset->label_from_var_label);
+      pxd_builder_put_u16 (&b, mrset->width);
+      pxd_builder_put_value (&b, &mrset->counted, mrset->width);
+    }
+
+  return pxd_builder_commit (&b);
+}
+
+struct mrset *
+mrset_load (struct pxd_object *object, const struct pxd *pxd,
+            const struct dictionary *dict)
+{
+  struct pxd_parser p;
+  struct mrset *mrset;
+  size_t i;
+
+  mrset = xzalloc (sizeof *mrset);
+
+  pxd_parser_init (&p, object, pxd);
+
+  mrset->name = pxd_parser_get_string (&p);
+
+  mrset->label = pxd_parser_get_string (&p);
+  if (mrset->label[0] == '\0')
+    {
+      free (mrset->label);
+      mrset->label = NULL;
+    }
+
+  mrset->type = pxd_parser_get_u8 (&p);
+
+  mrset->n_vars = pxd_parser_get_size_t (&p);
+  mrset->vars = xmalloc (mrset->n_vars * sizeof *mrset->vars);
+  for (i = 0; i < mrset->n_vars; i++)
+    {
+      char *name = pxd_parser_get_string (&p);
+      mrset->vars[i] = dict_lookup_var_assert (dict, name);
+      free (name);
+    }
+
+  if (mrset->type == MRSET_MD)
+    {
+      mrset->cat_source = pxd_parser_get_u8 (&p);
+      mrset->label_from_var_label = pxd_parser_get_bool (&p);
+      mrset->width = pxd_parser_get_u16 (&p);
+      pxd_parser_get_value (&p, &mrset->counted, mrset->width);
+    }
+  else
+    value_init (&mrset->counted, 0);
+
+  return mrset;
+}