pxd: initial work
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 16 Feb 2015 19:24:46 +0000 (11:24 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 16 Feb 2015 19:24:46 +0000 (11:24 -0800)
GET SESSION works for my simple test case

41 files changed:
Smake
configure.ac
src/automake.mk
src/data/attributes.c
src/data/attributes.h
src/data/automake.mk
src/data/column.h [new file with mode: 0644]
src/data/dictionary.c
src/data/dictionary.h
src/data/format.c
src/data/format.h
src/data/missing-values.c
src/data/missing-values.h
src/data/mrset.c
src/data/mrset.h
src/data/relation.h [new file with mode: 0644]
src/data/value-labels.c
src/data/value-labels.h
src/data/variable.c
src/data/variable.h
src/data/vec.h [new file with mode: 0644]
src/data/vector.c
src/data/vector.h
src/db/automake.mk [new file with mode: 0644]
src/db/db.c [new file with mode: 0644]
src/language/command.def
src/language/data-io/automake.mk
src/language/data-io/session.c [new file with mode: 0644]
src/libpspp/automake.mk
src/libpspp/db.h [new file with mode: 0644]
src/libpspp/float-format.h
src/libpspp/integer-format.h
src/libpspp/intern.c
src/libpspp/intern.h
src/libpspp/pxd.c [new file with mode: 0644]
src/libpspp/pxd.h [new file with mode: 0644]
src/processor/automake.mk [new file with mode: 0644]
src/processor/processor.c [new file with mode: 0644]
src/processor/request.c [new file with mode: 0644]
src/processor/request.h [new file with mode: 0644]
tests/libpspp/hmapx-test.c

diff --git a/Smake b/Smake
index 227affa36ba56bfe74a7991128e0b9d04a9dc11d..a8a28a6472c8540d985ade8fb1cd765af6c41ccc 100644 (file)
--- a/Smake
+++ b/Smake
@@ -20,6 +20,7 @@ GNULIB_MODULES = \
        crc \
        crypto/md4 \
        crypto/rijndael \
+       crypto/sha1 \
        dirname \
        dtoastr \
        environ \
index 7e976a8ca62d9857a80618fbf8036fc86be31b53..8949daa4585ed766717c0d94c8ab0bbfbfed5140 100644 (file)
@@ -34,6 +34,7 @@ LIBS="$LIBINTL $LIBS"
 
 dnl Checks for libraries.
 AC_SYS_LARGEFILE
+AC_CHECK_LIB([gdbm], [gdbm_open])
 AC_SEARCH_LIBS([sin], [m])
 PSPP_LC_PAPER
 
index efbdf720126cfdb0b8b1e13ffa7d1b3a4ae487e7..a6fedef21eaf3ede00c8247b7469f553d99a4541 100644 (file)
@@ -37,3 +37,5 @@ include $(top_srcdir)/src/math/automake.mk
 include $(top_srcdir)/src/output/automake.mk
 include $(top_srcdir)/src/language/automake.mk
 include $(top_srcdir)/src/ui/automake.mk
+include $(top_srcdir)/src/processor/automake.mk
+include $(top_srcdir)/src/db/automake.mk
index c4ae97c285928ed6e701cc6594fe0fefed5824c7..b04ebf0693ebe354be103a48c00b4f2ee0c37cc2 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011, 2012, 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
 #include <string.h>
 
 #include "libpspp/array.h"
+#include "libpspp/compiler.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/i18n.h"
+#include "libpspp/pxd.h"
 
 #include "gl/xalloc.h"
 
    set. */
 struct attribute
   {
+    struct attrset *set;        /* Containing set, if any. */
     struct hmap_node node;      /* Used by attrset. */
+
     char *name;                 /* Name. */
     char **values;              /* Each value. */
     size_t n_values;            /* Number of values. */
     size_t allocated_values;    /* Amount of allocated space for values. */
   };
 
+static void attrset_uncache__ (struct attrset *);
+
 /* Creates and returns a new attribute with the given NAME.  The
    attribute initially has no values.  (Attributes with no values
    cannot be saved to system files, so at least one value should
@@ -52,6 +58,7 @@ struct attribute *
 attribute_create (const char *name)
 {
   struct attribute *attr = xmalloc (sizeof *attr);
+  attr->set = NULL;
   attr->name = xstrdup (name);
   attr->values = NULL;
   attr->n_values = 0;
@@ -84,6 +91,8 @@ attribute_destroy (struct attribute *attr)
     {
       size_t i;
 
+      assert (attr->set == NULL);
+
       for (i = 0; i < attr->n_values; i++)
         free (attr->values[i]);
       free (attr->values);
@@ -122,6 +131,8 @@ attribute_get_n_values (const struct attribute *attrs)
 void
 attribute_add_value (struct attribute *attr, const char *value)
 {
+  attrset_uncache__ (attr->set);
+
   if (attr->n_values >= attr->allocated_values)
     attr->values = x2nrealloc (attr->values, &attr->allocated_values,
                                sizeof *attr->values);
@@ -138,6 +149,8 @@ attribute_add_value (struct attribute *attr, const char *value)
 void
 attribute_set_value (struct attribute *attr, size_t index, const char *value)
 {
+  attrset_uncache__ (attr->set);
+
   if (index < attr->n_values)
     {
       /* Replace existing value. */
@@ -162,6 +175,8 @@ attribute_set_value (struct attribute *attr, size_t index, const char *value)
 void
 attribute_del_value (struct attribute *attr, size_t index)
 {
+  attrset_uncache__ (attr->set);
+
   if (index < attr->n_values)
     {
       free (attr->values[index]);
@@ -170,6 +185,49 @@ attribute_del_value (struct attribute *attr, size_t index)
       attr->n_values--;
     }
 }
+
+struct pxd_object *
+attribute_save (const struct attribute *attr, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_string (&b, attr->name);
+  pxd_builder_put_size_t (&b, attr->n_values);
+  for (i = 0; i < attr->n_values; i++)
+    pxd_builder_put_string (&b, attr->values[i]);
+
+  return pxd_builder_commit (&b);
+}
+
+struct attribute *
+attribute_load (struct pxd_object *object, const struct pxd *pxd)
+{
+  struct attribute *attr;
+  struct pxd_parser p;
+  size_t n, i;
+  char *name;
+
+  pxd_parser_init (&p, object, pxd);
+
+  name = pxd_parser_get_string (&p);
+  attr = attribute_create (name);
+  free (name);
+
+  n = pxd_parser_get_size_t (&p);
+  for (i = 0; i < n; i++)
+    {
+      char *value = pxd_parser_get_string (&p);
+      attribute_add_value (attr, value);
+      free (value);
+    }
+
+  pxd_parser_destroy (&p);
+
+  return attr;
+}
 \f
 /* Initializes SET as a new, initially empty attibute set. */
 void
@@ -203,8 +261,13 @@ attrset_destroy (struct attrset *set)
     {
       struct attribute *attr, *next;
 
+      attrset_uncache__ (set);
+
       HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
-        attribute_destroy (attr);
+        {
+          attr->set = NULL;
+          attribute_destroy (attr);
+        }
       hmap_destroy (&set->map);
     }
 }
@@ -237,7 +300,13 @@ void
 attrset_add (struct attrset *set, struct attribute *attr)
 {
   const char *name = attribute_get_name (attr);
+
   assert (attrset_lookup (set, name) == NULL);
+  assert (attr->set == NULL);
+
+  attrset_uncache__ (set);
+
+  attr->set = set;
   hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
 }
 
@@ -249,7 +318,9 @@ attrset_delete (struct attrset *set, const char *name)
   struct attribute *attr = attrset_lookup (set, name);
   if (attr != NULL)
     {
+      attrset_uncache__ (set);
       hmap_delete (&set->map, &attr->node);
+      attr->set = NULL;
       attribute_destroy (attr);
     }
 }
@@ -258,8 +329,45 @@ attrset_delete (struct attrset *set, const char *name)
 void
 attrset_clear (struct attrset *set)
 {
-  attrset_destroy (set);
+  if (!hmap_is_empty (&set->map))
+    {
+      attrset_destroy (set);
+      attrset_init (set);
+    }
+}
+
+struct pxd_object *
+attrset_save (const struct attrset *set, struct pxd *pxd)
+{
+  struct attribute *attr;
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
+    pxd_builder_put_link (&b, attribute_save (attr, pxd));
+
+  return pxd_builder_commit (&b);
+}
+
+void
+attrset_load (struct attrset *set,
+              struct pxd_object *object, const struct pxd *pxd)
+{
+  struct pxd_parser p;
+  unsigned int i;
+
+  pxd_parser_init (&p, object, pxd);
+
   attrset_init (set);
+  for (i = 0; i < pxd_object_get_n_links (object); i++)
+    {
+      struct pxd_object *attr_obj = pxd_object_get_link (object, i, pxd);
+      struct attribute *attr = attribute_load (attr_obj, pxd);
+      attrset_add (set, attr);
+    }
+
+  pxd_parser_destroy (&p);
 }
 
 static struct attribute *iterator_data (struct attrset_iterator *iterator)
@@ -335,3 +443,10 @@ attrset_sorted (const struct attrset *set)
   else
     return NULL;
 }
+
+static void
+attrset_uncache__ (struct attrset *set UNUSED)
+{
+  /* XXX */
+}
+
index ab7b12e301730cdfcc12d67e3e4ff2312bd19cc8..8795f8feafb189011fbb7741fee7af63fde74061 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2008, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008, 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
@@ -19,6 +19,8 @@
 
 #include "libpspp/hmapx.h"
 
+struct pxd;
+
 /* This header supports custom attribute of the sort maintained
    by the DATAFILE ATTRIBUTE and VARIABLE ATTRIBUTE commands.
 
@@ -41,6 +43,9 @@ void attribute_set_value (struct attribute *, size_t index, const char *);
 void attribute_del_value (struct attribute *, size_t index);
 size_t attribute_get_n_values (const struct attribute *);
 
+struct pxd_object *attribute_save (const struct attribute *, struct pxd *);
+struct attribute *attribute_load (struct pxd_object *, const struct pxd *);
+
 struct attrset 
   {
     struct hmap map;
@@ -57,6 +62,9 @@ void attrset_add (struct attrset *, struct attribute *);
 void attrset_delete (struct attrset *, const char *);
 void attrset_clear (struct attrset *);
 
+struct pxd_object *attrset_save (const struct attrset *, struct pxd *);
+void attrset_load (struct attrset *, struct pxd_object *, const struct pxd *);
+
 struct attrset_iterator
   {
     struct hmap_node *node;
index 8b26f525e45576d2264f2a5a731c445fa1adaa68..17d5ce1d6fc5c4b497f570484c8299fc3129b6c1 100644 (file)
@@ -42,6 +42,7 @@ src_data_libdata_la_SOURCES = \
        src/data/case.h \
        src/data/case-tmpfile.c \
        src/data/case-tmpfile.h \
+       src/data/column.h \
        src/data/csv-file-writer.c \
        src/data/csv-file-writer.h \
        src/data/data-in.c \
@@ -88,6 +89,7 @@ src_data_libdata_la_SOURCES = \
        src/data/por-file-writer.h \
        src/data/psql-reader.c \
        src/data/psql-reader.h \
+       src/data/relation.h \
        src/data/session.c \
        src/data/session.h \
        src/data/settings.c \
@@ -116,6 +118,7 @@ src_data_libdata_la_SOURCES = \
        src/data/vardict.h \
        src/data/variable.h \
        src/data/variable.c \
+       src/data/vec.h \
        src/data/vector.c \
        src/data/vector.h
 
diff --git a/src/data/column.h b/src/data/column.h
new file mode 100644 (file)
index 0000000..164257f
--- /dev/null
@@ -0,0 +1,55 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef DATA_COLUMN_H
+#define DATA_COLUMN_H 1
+
+#include "libpspp/compiler.h"
+#include "data/case.h"
+#include "data/value.h"
+
+struct pxd;
+
+struct column *column_create (struct pxd *, int width);
+bool column_destroy (struct column *);
+
+int column_get_width (const struct column *);
+
+void column_read (const struct column *, casenumber, union value *);
+void column_write (struct column *, casenumber, const union value *);
+void column_append (struct column *, casenumber, const union value *);
+
+struct column *column_clone (const struct column *);
+void column_split (struct column *, struct column **, struct column **);
+struct column *column_rename (struct column *);
+void column_swap (struct column *, struct column *);
+
+bool column_is_empty (struct column *);
+
+bool column_error (const struct column *);
+void column_force_error (struct column *);
+const struct taint *column_get_taint (const struct column *);
+
+casenumber column_get_size (struct column *);
+casenumber column_count (const struct column *);
+void column_truncate (struct column *, casenumber);
+
+casenumber column_advance (struct column *, casenumber);
+
+struct pxd_object *column_save (const struct column *, struct pxd *);
+struct column *column_load (struct pxd_object *, const struct pxd *);
+
+#endif /* data/column.h */
index 4eaaefae18ed9ae4889275bccd00b0e568c26e8d..7cf2a7917de2e74cb85e8ac7db01ccad356246c4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009-2015 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
@@ -41,6 +41,7 @@
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
 #include "libpspp/pool.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 #include "libpspp/string-array.h"
 
@@ -87,6 +88,8 @@ struct dictionary
 static void dict_unset_split_var (struct dictionary *, struct variable *);
 static void dict_unset_mrset_var (struct dictionary *, struct variable *);
 
+static void dict_uncache (struct dictionary *);
+
 /* Returns the encoding for data in dictionary D.  The return value is a
    nonnull string that contains an IANA character set name. */
 const char *
@@ -255,6 +258,8 @@ dict_clone (const struct dictionary *s)
 void
 dict_clear (struct dictionary *d)
 {
+  dict_uncache (d);
+
   /* FIXME?  Should we really clear case_limit, label, documents?
      Others are necessarily cleared by deleting all the variables.*/
   while (d->var_cnt > 0 )
@@ -1674,3 +1679,166 @@ vardict_get_dict_index (const struct vardict_info *vardict)
 {
   return vardict - vardict->dict->var;
 }
+\f
+static struct pxd_object *
+vardict_info_save (const struct vardict_info *vardict, struct pxd *pxd)
+{
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+  pxd_builder_put_s32 (&b, vardict->case_index);
+  pxd_builder_put_link (&b, var_save (vardict->var, pxd));
+  return pxd_builder_commit (&b);
+}
+
+struct pxd_object *
+dict_save (const struct dictionary *dict, struct pxd *pxd)
+{
+  struct pxd_array_builder ab;
+  struct pxd_object *vars;
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_array_builder_init (&ab, pxd);
+  for (i = 0; i < dict->var_cnt; i++)
+    pxd_array_builder_add (&ab, vardict_info_save (&dict->var[i], pxd));
+  vars = pxd_array_builder_commit (&ab);
+
+  pxd_builder_init (&b, pxd);
+  pxd_builder_put_link (&b, vars);
+  pxd_builder_put_u32 (&b, dict->next_value_idx);
+
+  pxd_builder_put_size_t (&b, dict->split_cnt);
+  for (i = 0; i < dict->split_cnt; i++)
+    pxd_builder_put_u32 (&b, var_get_dict_index (dict->split[i]));
+
+  pxd_builder_put_s32 (&b,
+                       (dict->weight == NULL ? -1
+                        : var_get_dict_index (dict->weight)));
+  pxd_builder_put_s32 (&b,
+                       (dict->filter == NULL ? -1
+                        : var_get_dict_index (dict->filter)));
+
+  pxd_builder_put_casenumber (&b, dict->case_limit);
+  pxd_builder_put_string (&b, dict->label != NULL ? dict->label : "");
+  //XXX pxd_builder_put_string (&b, ds_cstr (&dict->documents));
+
+  pxd_builder_put_size_t (&b, dict->vector_cnt);
+  for (i = 0; i < dict->split_cnt; i++)
+    pxd_builder_put_link (&b, vector_save (dict->vector[i], pxd));
+
+  pxd_builder_put_link (&b, attrset_save (&dict->attributes, pxd));
+
+  pxd_builder_put_size_t (&b, dict->n_mrsets);
+  for (i = 0; i < dict->n_mrsets; i++)
+    pxd_builder_put_link (&b, mrset_save (dict->mrsets[i], pxd));
+
+  pxd_builder_put_string (&b, dict->encoding ? dict->encoding : "");
+
+  return pxd_builder_commit (&b);
+}
+
+static void
+vardict_info_load (struct dictionary *dict, struct pxd_object *obj,
+                   const struct pxd *pxd)
+{
+  struct pxd_parser p;
+  struct variable *var;
+  int case_index;
+
+  pxd_parser_init (&p, obj, pxd);
+  case_index = pxd_parser_get_u32 (&p);
+  var = add_var (dict, var_load (pxd_parser_get_link (&p), pxd));
+  var_get_vardict (var)->case_index = case_index;
+  pxd_parser_destroy (&p);
+}
+
+struct dictionary *
+dict_load (struct pxd_object *obj, const struct pxd *pxd)
+{
+  struct dictionary *dict;
+  struct pxd_array array;
+  struct pxd_parser p;
+  char *encoding;
+  int weight_idx;
+  int filter_idx;
+  size_t i;
+
+  pxd_parser_init (&p, obj, pxd);
+
+  encoding = pxd_parser_get_string (&p);
+  dict = dict_create (encoding);
+  free (encoding);
+
+  pxd_array_init (&array, pxd_parser_get_link (&p), pxd);
+  for (i = 0; i < pxd_array_size (&array); i++)
+    vardict_info_load (dict, pxd_array_get (&array, i), pxd);
+  pxd_array_destroy (&array);
+
+  dict->next_value_idx = pxd_parser_get_u32 (&p);
+
+  dict->split_cnt = pxd_parser_get_size_t (&p);
+  if (dict->split_cnt > 0)
+    {
+      dict->split = xnmalloc (dict->split_cnt, sizeof *dict->split);
+      for (i = 0; i < dict->split_cnt; i++)
+        dict->split[i] = dict_get_var (dict, i);
+    }
+
+  weight_idx = pxd_parser_get_s32 (&p);
+  if (weight_idx >= 0)
+    dict_set_weight (dict, dict_get_var (dict, weight_idx));
+
+  filter_idx = pxd_parser_get_s32 (&p);
+  if (filter_idx >= 0)
+    dict_set_filter (dict, dict_get_var (dict, filter_idx));
+
+  dict->case_limit = pxd_parser_get_casenumber (&p);
+
+  dict->label = pxd_parser_get_string (&p);
+  if (dict->label[0] == '\0')
+    dict_set_label (dict, NULL);
+
+#if 0                           /* XXX */
+  documents = pxd_parser_get_string (&p);
+  if (documents[0] != '\0')
+    ds_assign_cstr (&dict->documents, documents);
+  free (documents);
+#endif
+
+  dict->vector_cnt = pxd_parser_get_size_t (&p);
+  if (dict->vector_cnt > 0)
+    {
+      dict->vector = xnmalloc (dict->vector_cnt, sizeof *dict->vector);
+      for (i = 0; i < dict->vector_cnt; i++)
+        dict->vector[i] = vector_load (pxd_parser_get_link (&p), pxd, dict);
+    }
+
+  attrset_destroy (&dict->attributes);
+  attrset_load (&dict->attributes, pxd_parser_get_link (&p), pxd);
+
+  dict->n_mrsets = pxd_parser_get_size_t (&p);
+  if (dict->n_mrsets > 0)
+    {
+      dict->mrsets = xnmalloc (dict->n_mrsets, sizeof *dict->mrsets);
+      for (i = 0; i < dict->n_mrsets; i++)
+        dict->mrsets[i] = mrset_load (pxd_parser_get_link (&p), pxd, dict);
+    }
+
+  dict->encoding = pxd_parser_get_string (&p);
+  if (dict->encoding[0] == '\0')
+    {
+      free (dict->encoding);
+      dict->encoding = NULL;
+    }
+
+  pxd_parser_destroy (&p);
+
+  return dict;
+}
+
+static void
+dict_uncache (struct dictionary *dict UNUSED)
+{
+}
+
index 66542469e321c630c87b2396c9d6ab0f9a84c3e2..62acd584f12acab245e4d2b5f8c28f4dcd1fdbca 100644 (file)
 #include "data/case.h"
 #include "data/dict-class.h"
 
-struct string;
 struct ccase;
+struct pxd;
+struct string;
 
 /* Creating dictionaries. */
 struct dictionary *dict_create (const char *encoding);
 struct dictionary *dict_clone (const struct dictionary *);
 
-
 /* Clearing and destroying dictionaries. */
 void dict_clear (struct dictionary *);
 void dict_destroy (struct dictionary *);
@@ -199,4 +199,8 @@ void dict_set_change_callback (struct dictionary *d,
 /* Debug use only. */
 void dict_dump (const struct dictionary *);
 
+/* Saving and loading. */
+struct pxd_object *dict_save (const struct dictionary *, struct pxd *);
+struct dictionary *dict_load (struct pxd_object *, const struct pxd *);
+
 #endif /* data/dictionary.h */
index 55e166e817a0c075de9fab55c29a5ae4afab73c5..52206b0f539af86040e4de071d92431f526321dd 100644 (file)
@@ -558,6 +558,22 @@ fmt_change_decimals (struct fmt_spec *fmt, int decimals, enum fmt_use use)
   fmt->d = decimals;
   fmt_fix (fmt, use);
 }
+
+unsigned int
+fmt_to_uint (const struct fmt_spec *fmt)
+{
+  return (fmt_to_io (fmt->type) << 24) | (fmt->w << 8) | fmt->d;
+}
+
+bool
+fmt_from_uint (struct fmt_spec *fmt, unsigned int uint)
+{
+  if (!fmt_from_io (uint >> 24, &fmt->type))
+    return false;
+  fmt->w = (uint >> 8) & 0xffff;
+  fmt->d = uint & 0xff;
+  return true;
+}
 \f
 /* Describes a display format. */
 struct fmt_desc
index d05e4436215b8d17a76507bcf9cda3be2da77186..92e66b3a9430677cce7adf5e8cb43e36cf05fc9d 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 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
@@ -105,6 +105,9 @@ void fmt_fix_output (struct fmt_spec *);
 void fmt_change_width (struct fmt_spec *, int width, enum fmt_use);
 void fmt_change_decimals (struct fmt_spec *, int decimals, enum fmt_use);
 
+unsigned int fmt_to_uint (const struct fmt_spec *);
+bool fmt_from_uint (struct fmt_spec *, unsigned int);
+
 /* Format types. */
 bool is_fmt_type (enum fmt_type);
 
index 9aba57e0e05fb6249764d2c5f778fb6337275a82..aa029a4f4d443e7f5dbd7a4ae2b8e99fedff2471 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2009, 2011, 2013 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009, 2011-2015 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
@@ -24,6 +24,7 @@
 #include "data/variable.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 
 /* Types of user-missing values.
@@ -470,3 +471,40 @@ 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);
 }
+
+struct pxd_object *
+mv_save (const struct missing_values *mv, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  int i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_u16 (&b, mv->width);
+  pxd_builder_put_u16 (&b, mv->type);
+  for (i = 0; i < 3; i++)
+    if (using_element (mv->type, i))
+      pxd_builder_put_value (&b, &mv->values[i], mv->width);
+
+  return pxd_builder_commit (&b);
+}
+
+void
+mv_load (struct missing_values *mv, struct pxd_object *object,
+         const struct pxd *pxd)
+{
+  struct pxd_parser p;
+  int i;
+
+  pxd_parser_init (&p, object, pxd);
+
+  mv->width = pxd_parser_get_u16 (&p);
+  mv->type = pxd_parser_get_u16 (&p);
+  for (i = 0; i < 3; i++)
+    if (using_element (mv->type, i))
+      pxd_parser_get_value (&p, &mv->values[i], mv->width);
+    else
+      value_init (&mv->values[i], mv->width);
+
+  pxd_parser_destroy (&p);
+}
index 511ebd7ddd37273a9f2df1b6ad1ac0c31227e792..504d06ad674e9e2bb6db5ab7a6440d8d653bb4d4 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2005, 2009, 2013 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2009, 2013-2015 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
@@ -37,6 +37,7 @@
 #include "data/value.h"
 
 struct pool;
+struct pxd;
 
 /* Missing values for long string variables after the first
    MV_MAX_STRING bytes must be all spaces. */
@@ -103,4 +104,9 @@ bool mv_replace_value (struct missing_values *, const union value *, int idx);
 bool mv_add_range (struct missing_values *, double low, double high);
 void mv_pop_range (struct missing_values *, double *low, double *high);
 
+/* Saving and loading. */
+struct pxd_object *mv_save (const struct missing_values *, struct pxd *);
+void mv_load (struct missing_values *,
+              struct pxd_object *, const struct pxd *);
+
 #endif /* data/missing-values.h */
index 38b0ab2d5266e88192342166df828cd7a98e2bd9..ce1a35851e1860b8e7f8894d65b23c113f87bd19 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010, 2011 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
@@ -25,6 +25,7 @@
 #include "data/val-type.h"
 #include "data/variable.h"
 #include "libpspp/message.h"
+#include "libpspp/pxd.h"
 
 #include "gl/xalloc.h"
 
@@ -130,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;
+}
index 9971924e0d39d2d9c1adb044e2c033d39b9ab77f..95b9784f7195242293e6de02708b3d3d1a4751a6 100644 (file)
@@ -43,6 +43,7 @@
 #include "data/value.h"
 
 struct dictionary;
+struct pxd;
 
 /* Type of a multiple response set. */
 enum mrset_type
@@ -82,4 +83,8 @@ bool mrset_is_valid_name (const char *name, const char *dict_encoding,
 
 bool mrset_ok (const struct mrset *, const struct dictionary *);
 
+struct pxd_object *mrset_save (const struct mrset *, struct pxd *);
+struct mrset *mrset_load (struct pxd_object *, const struct pxd *,
+                          const struct dictionary *);
+
 #endif /* data/mrset.h */
diff --git a/src/data/relation.h b/src/data/relation.h
new file mode 100644 (file)
index 0000000..0865ae5
--- /dev/null
@@ -0,0 +1,46 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef DATA_RELATION_H
+#define DATA_RELATION_H 1
+
+#include "libpspp/compiler.h"
+#include "data/column.h"
+
+struct relation_column
+  {
+    struct hmap_node hmap_node;
+    const char *name;
+    struct column *column;
+  };
+
+struct relation *relation_create (void);
+bool relation_destroy (struct relation *);
+
+void relation_add_column (struct relation *,
+                          const char *name, struct column *);
+void relation_delete_column (struct relation *, const char *name);
+void relation_rename_column (struct relation *, const char *old_name,
+                             const char *new_name);
+
+const struct column *relation_get_column (const struct relation *,
+                                          const char *name);
+struct column *relation_get_column_rw (struct relation *, const char *name);
+
+struct pxd_object *relation_save (const struct relation *, struct pxd *);
+struct relation *relation_load (struct pxd_object *, const struct pxd *);
+
+#endif /* data/relation.h */
index c405961f29d69b29a24b767b0095c5029932425d..c1dee054ac8318d9c94dc1387b88e5af46aa9ad9 100644 (file)
 #include "libpspp/hmap.h"
 #include "libpspp/intern.h"
 #include "libpspp/message.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 
 #include "gl/xalloc.h"
 
+static void val_labs_uncache__ (struct val_labs *);
+static void val_lab_uncache__ (struct val_lab *);
+
 /* Creates and returns a new, empty set of value labels with the
    given WIDTH. */
 struct val_labs *
@@ -88,7 +92,11 @@ val_labs_set_width (struct val_labs *vls, int new_width)
       HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
         value_resize (&label->value, vls->width, new_width);
     }
-  vls->width = new_width;
+  if (vls->width != new_width)
+    {
+      vls->width = new_width;
+      val_labs_uncache__ (vls);
+    }
 }
 
 /* Destroys VLS. */
@@ -97,12 +105,21 @@ val_labs_destroy (struct val_labs *vls)
 {
   if (vls != NULL)
     {
+      val_labs_uncache__ (vls);
       val_labs_clear (vls);
       hmap_destroy (&vls->labels);
       free (vls);
     }
 }
 
+static void
+val_lab_clear (struct val_lab *lab, int width)
+{
+  val_lab_uncache__ (lab);
+  value_destroy (&lab->value, width);
+  intern_unref (lab->label);
+}
+
 /* Removes all the value labels from VLS. */
 void
 val_labs_clear (struct val_labs *vls)
@@ -111,10 +128,8 @@ val_labs_clear (struct val_labs *vls)
 
   HMAP_FOR_EACH_SAFE (label, next, struct val_lab, node, &vls->labels)
     {
+      val_lab_clear (label, vls->width);
       hmap_delete (&vls->labels, &label->node);
-      value_destroy (&label->value, vls->width);
-      intern_unref (label->label);
-      intern_unref (label->escaped_label);
       free (label);
     }
 }
@@ -162,6 +177,86 @@ set_label (struct val_lab *lab, const char *escaped_label)
     }
 }
 
+static void
+val_labs_uncache__ (struct val_labs *vls UNUSED)
+{
+}
+
+static void
+val_lab_uncache__ (struct val_lab *vl UNUSED)
+{
+}
+
+static struct pxd_object *
+val_lab_save (const struct val_lab *vl, int width, struct pxd *pxd)
+{
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_value (&b, &vl->value, width);
+  pxd_builder_put_interned_string (&b, vl->label);
+
+  return pxd_builder_commit (&b);
+}
+
+struct pxd_object *
+val_labs_save (const struct val_labs *vls, struct pxd *pxd)
+{
+  struct val_lab *label;
+  struct pxd_builder b;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_u32 (&b, vls->width);
+  HMAP_FOR_EACH (label, struct val_lab, node, &vls->labels)
+    pxd_builder_put_link (&b, val_lab_save (label, vls->width, pxd));
+
+  return pxd_builder_commit (&b);
+}
+
+static struct val_lab *
+val_lab_load (struct pxd_object *object, const struct pxd *pxd, int width)
+{
+  struct pxd_parser p;
+  struct val_lab *vl;
+
+  pxd_parser_init (&p, object, pxd);
+
+  vl = xmalloc (sizeof *vl);
+  pxd_parser_get_value (&p, &vl->value, width);
+  vl->label = pxd_parser_get_interned_string (&p);
+
+  pxd_parser_destroy (&p);
+
+  return vl;
+}
+
+struct val_labs *
+val_labs_load (struct pxd_object *object, const struct pxd *pxd)
+{
+  struct val_labs *vls;
+  struct pxd_parser p;
+  unsigned int i;
+  int width;
+
+  pxd_parser_init (&p, object, pxd);
+  width = pxd_parser_get_u32 (&p);
+
+  vls = val_labs_create (width);
+  for (i = 0; i < pxd_object_get_n_links (object); i++)
+    {
+      struct pxd_object *lab_obj = pxd_object_get_link (object, i, pxd);
+      struct val_lab *lab = val_lab_load (lab_obj, pxd, width);
+      hmap_insert (&vls->labels, &lab->node,
+                   value_hash (&lab->value, width, 0));
+    }
+
+  pxd_parser_destroy (&p);
+
+  return vls;
+}
+\f
 static void
 do_add_val_lab (struct val_labs *vls, const union value *value,
                 const char *escaped_label)
@@ -201,6 +296,7 @@ val_labs_replace (struct val_labs *vls, const union value *value,
   struct val_lab *vl = val_labs_lookup (vls, value);
   if (vl != NULL)
     {
+      val_lab_uncache__ (vl);
       intern_unref (vl->label);
       intern_unref (vl->escaped_label);
       set_label (vl, label);
@@ -213,10 +309,8 @@ val_labs_replace (struct val_labs *vls, const union value *value,
 void
 val_labs_remove (struct val_labs *vls, struct val_lab *label)
 {
+  val_lab_clear (label, vls->width);
   hmap_delete (&vls->labels, &label->node);
-  value_destroy (&label->value, vls->width);
-  intern_unref (label->label);
-  intern_unref (label->escaped_label);
   free (label);
 }
 
index af98d9f9b54ef392f7623f7a3f3d050bb60b5bfb..e2d4b364092b5c9915ed0fd29cc1e04e8267eb53 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2009, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2009-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
@@ -30,6 +30,8 @@
 #include "data/value.h"
 #include "libpspp/hmap.h"
 
+struct pxd;
+
 /* One value label.
 
    A value label is normally part of a struct val_labs (see
@@ -37,6 +39,7 @@
 struct val_lab
   {
     struct hmap_node node;      /* Node in hash map. */
+    struct pxd_object *cache;   /* Object cache. */
     union value value;          /* The value being labeled. */
     const char *label;          /* An interned string. */
     const char *escaped_label;  /* An interned string. */
@@ -78,6 +81,7 @@ val_lab_get_escaped_label (const struct val_lab *vl)
 /* A set of value labels. */
 struct val_labs
   {
+    struct pxd_object *cache;   /* Object cache. */
     int width;                  /* 0=numeric, otherwise string width. */
     struct hmap labels;         /* Hash table of `struct val_lab's. */
   };
@@ -117,4 +121,8 @@ const struct val_lab **val_labs_sorted (const struct val_labs *);
 unsigned int val_labs_hash (const struct val_labs *, unsigned int basis);
 bool val_labs_equal (const struct val_labs *, const struct val_labs *);
 
+/* Saving and loading. */
+struct pxd_object *val_labs_save (const struct val_labs *, struct pxd *);
+struct val_labs *val_labs_load (struct pxd_object *, const struct pxd *);
+
 #endif /* data/value-labels.h */
index 971154368cb7ae5ede7b21d4f88374e6f1e4b752..f22bc522e4bee26924071062256fbf814e4c9eae 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009-2015 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 "libpspp/compiler.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/i18n.h"
+#include "libpspp/intern.h"
 #include "libpspp/message.h"
 #include "libpspp/misc.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 
 #include "gl/minmax.h"
@@ -76,6 +78,8 @@ struct variable
     /* Custom attributes. */
     struct attrset attributes;
   };
+
+static void var_uncache (struct variable *);
 \f
 
 static void var_set_print_format_quiet (struct variable *v, const struct fmt_spec *print);
@@ -121,6 +125,7 @@ var_destroy (struct variable *v)
   if (v != NULL)
     {
       assert (!var_has_vardict (v));
+      var_uncache (v);
       mv_destroy (&v->miss);
       var_clear_short_names (v);
       val_labs_destroy (v->val_labs);
@@ -156,6 +161,7 @@ var_set_name_quiet (struct variable *v, const char *name)
   v->name = xstrdup (name);
   ds_destroy (&v->name_and_label);
   ds_init_empty (&v->name_and_label);
+  var_uncache (v);
 }
 
 /* Sets V's name to NAME, a UTF-8 encoded string.
@@ -305,6 +311,8 @@ var_set_width_and_formats (struct variable *v, int new_width,
 
   if (traits != 0)
     dict_var_changed (v, traits, ov);
+
+  var_uncache (v);
 }
 
 /* Changes the width of V to NEW_WIDTH.
@@ -440,8 +448,14 @@ var_has_value_labels (const struct variable *v)
 static void
 var_set_value_labels_quiet (struct variable *v, const struct val_labs *vls)
 {
-  val_labs_destroy (v->val_labs);
-  v->val_labs = NULL;
+  bool changed = false;
+
+  if (v->val_labs != NULL)
+    {
+      val_labs_destroy (v->val_labs);
+      v->val_labs = NULL;
+      changed = true;
+    }
 
   if (vls != NULL)
     {
@@ -449,6 +463,9 @@ var_set_value_labels_quiet (struct variable *v, const struct val_labs *vls)
       v->val_labs = val_labs_clone (vls);
       val_labs_set_width (v->val_labs, v->width);
     }
+
+  if (changed)
+    var_uncache (v);
 }
 
 
@@ -483,8 +500,14 @@ bool
 var_add_value_label (struct variable *v,
                      const union value *value, const char *label)
 {
+  bool changed;
+
   alloc_value_labels (v);
-  return val_labs_add (v->val_labs, value, label);
+
+  changed = val_labs_add (v->val_labs, value, label);
+  if (changed)
+    var_uncache (v);
+  return changed;
 }
 
 /* Adds or replaces a value label with the given VALUE and UTF-8 encoded LABEL
@@ -497,6 +520,7 @@ var_replace_value_label (struct variable *v,
 {
   alloc_value_labels (v);
   val_labs_replace (v->val_labs, value, label);
+  var_uncache (v);
 }
 
 /* Removes V's value labels, if any. */
@@ -585,6 +609,7 @@ var_set_print_format_quiet (struct variable *v, const struct fmt_spec *print)
     {
       assert (fmt_check_width_compat (print, v->width));
       v->print = *print;
+      var_uncache (v);
     }
 }
 
@@ -598,6 +623,7 @@ var_set_print_format (struct variable *v, const struct fmt_spec *print)
   struct variable *ov = var_clone (v);
   var_set_print_format_quiet (v, print);
   dict_var_changed (v, VAR_TRAIT_PRINT_FORMAT, ov);
+  var_uncache (v);
 }
 
 /* Returns V's write format specification. */
@@ -618,6 +644,7 @@ var_set_write_format_quiet (struct variable *v, const struct fmt_spec *write)
     {
       assert (fmt_check_width_compat (write, v->width));
       v->write = *write;
+      var_uncache (v);
     }
 }
 
@@ -727,10 +754,9 @@ var_set_label_quiet (struct variable *v, const char *label)
 
   ds_destroy (&v->name_and_label);
   ds_init_empty (&v->name_and_label);
+  var_uncache (v);
 }
 
-
-
 /* Sets V's variable label to UTF-8 encoded string LABEL, stripping off leading
    and trailing white space.  If LABEL is a null pointer or if LABEL is an
    empty string (after stripping white space), then V's variable label (if any)
@@ -823,7 +849,6 @@ var_set_measure_quiet (struct variable *v, enum measure measure)
   v->measure = measure;
 }
 
-
 /* Sets V's measurement level to MEASURE. */
 void
 var_set_measure (struct variable *v, enum measure measure)
@@ -1173,13 +1198,17 @@ var_set_short_name (struct variable *var, size_t idx, const char *short_name)
 void
 var_clear_short_names (struct variable *v)
 {
-  size_t i;
-
-  for (i = 0; i < v->short_name_cnt; i++)
-    free (v->short_names[i]);
-  free (v->short_names);
-  v->short_names = NULL;
-  v->short_name_cnt = 0;
+  if (v->short_name_cnt > 0)
+    {
+      size_t i;
+
+      for (i = 0; i < v->short_name_cnt; i++)
+        free (v->short_names[i]);
+      free (v->short_names);
+      v->short_names = NULL;
+      v->short_name_cnt = 0;
+      var_uncache (v);
+    }
 }
 \f
 /* Relationship with dictionary. */
@@ -1221,6 +1250,7 @@ var_set_attributes_quiet (struct variable *v, const struct attrset *attrs)
 {
   attrset_destroy (&v->attributes);
   attrset_clone (&v->attributes, attrs);
+  var_uncache (v);
 }
 
 /* Replaces variable V's attributes set by a copy of ATTRS. */
@@ -1312,3 +1342,125 @@ var_clear_vardict (struct variable *v)
 {
   v->vardict = NULL;
 }
+\f
+struct pxd_object *
+var_save (const struct variable *var, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_string (&b, var->name);
+  pxd_builder_put_u16 (&b, var->width);
+  pxd_builder_put_link (&b, mv_save (&var->miss, pxd));
+  pxd_builder_put_u32 (&b, fmt_to_uint (&var->print));
+  pxd_builder_put_u32 (&b, fmt_to_uint (&var->write));
+
+  if (var_has_value_labels (var))
+    {
+      pxd_builder_put_bool (&b, true);
+      pxd_builder_put_link (&b, val_labs_save (var->val_labs, pxd));
+    }
+  else
+    pxd_builder_put_bool (&b, false);
+
+  pxd_builder_put_string (&b, var->label != NULL ? var->label : "");
+
+  pxd_builder_put_u8 (&b, var->measure);
+  pxd_builder_put_u32 (&b, var->display_width);
+  pxd_builder_put_u8 (&b, var->alignment);
+
+  pxd_builder_put_bool (&b, var->leave);
+
+  pxd_builder_put_size_t (&b, var->short_name_cnt);
+  for (i = 0; i < var->short_name_cnt; i++)
+    pxd_builder_put_string (&b, var->short_names[i]);
+
+  pxd_builder_put_link (&b, attrset_save (&var->attributes, pxd));
+
+  return pxd_builder_commit (&b);
+}
+
+struct variable *
+var_load (struct pxd_object *object, const struct pxd *pxd)
+{
+  struct fmt_spec print, write;
+  struct missing_values mv;
+  struct variable *var;
+  struct pxd_parser p;
+  char *label;
+  char *name;
+  int width;
+  size_t i;
+
+#if 0
+  cached_var = pxd_cache_search (&var_cache, pxd_object_id (object));
+  if (cached_var != NULL)
+    {
+      size_t n;
+
+      var = var_clone (cached_var);
+
+      /* var_clone() doesn't copy short names, so we need to. */
+      n = cached_var->short_name_cnt;
+      if (n > 0)
+        {
+          size_t i;
+
+          var->short_name_cnt = n;
+          var->short_names = xmalloc (n * sizeof *var->short_names);
+          for (i = 0; i < n; i++)
+            var->short_names[i] = xstrdup (cached_var->short_names[i]);
+        }
+
+      return var;
+    }
+#endif
+
+  pxd_parser_init (&p, object, pxd);
+
+  name = pxd_parser_get_string (&p);
+  width = pxd_parser_get_u16 (&p);
+  var = var_create (name, width);
+
+  mv_load (&mv, pxd_parser_get_link (&p), pxd);
+  var_set_missing_values (var, &mv);
+  mv_destroy (&mv);
+
+  fmt_from_uint (&print, pxd_parser_get_u32 (&p));
+  var_set_print_format (var, &print);
+
+  fmt_from_uint (&write, pxd_parser_get_u32 (&p));
+  var_set_write_format (var, &write);
+
+  if (pxd_parser_get_bool (&p))
+    var->val_labs = val_labs_load (pxd_parser_get_link (&p), pxd);
+
+  label = pxd_parser_get_string (&p);
+  if (label[0])
+    var_set_label (var, label);
+  free (label);
+
+  var->measure = pxd_parser_get_u8 (&p);
+  var->display_width = pxd_parser_get_u32 (&p);
+  var->alignment = pxd_parser_get_u8 (&p);
+
+  var->leave = pxd_parser_get_bool (&p);
+
+  var->short_name_cnt = pxd_parser_get_size_t (&p);
+  var->short_names = xmalloc (var->short_name_cnt * sizeof *var->short_names);
+  for (i = 0; i < var->short_name_cnt; i++)
+    var->short_names[i] = pxd_parser_get_string (&p);
+
+  attrset_load (&var->attributes, pxd_parser_get_link (&p), pxd);
+
+  pxd_parser_destroy (&p);
+
+  return var;
+}
+
+static void
+var_uncache (struct variable *var UNUSED)
+{
+}
index 25596ad368beac821803ef074bdd3eaea3e8938d..d2b905ad7359c9fd9e66c12efbbfcfd9bb3b3bfd 100644 (file)
@@ -210,4 +210,8 @@ const char *var_get_encoding (const struct variable *);
 /* Function types. */
 typedef bool var_predicate_func (const struct variable *);
 
+/* Saving and loading. */
+struct pxd_object *var_save (const struct variable *, struct pxd *);
+struct variable *var_load (struct pxd_object *, const struct pxd *);
+
 #endif /* data/variable.h */
diff --git a/src/data/vec.h b/src/data/vec.h
new file mode 100644 (file)
index 0000000..501a11f
--- /dev/null
@@ -0,0 +1,47 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef DATA_VEC_H
+#define DATA_VEC_H 1
+
+struct vec;
+
+struct vec *vec_new (int width);
+
+struct vec *vec_ref (const struct vec *);
+void vec_unref (struct vec *);
+
+int vec_width (const struct vec *);
+casenumber vec_count (const struct vec *);
+
+void vec_get (const struct vec *, casenumber, union value *);
+
+struct vec *vec_put (struct vec *, casenumber, const union value *);
+struct vec *vec_insert (struct vec *, casenumber before,
+                        const union value *);
+struct vec *vec_delete (struct vec *, casenumber start, casenumber n);
+
+struct vec *vec_head (struct vec *, casenumber n);
+struct vec *vec_tail (struct vec *, casenumber n);
+
+struct vec *vec_delete_head (struct vec *, casenumber n);
+struct vec *vec_delete_tail (struct vec *, casenumber n);
+struct vec *vec_range (struct vec *, casenumber first, casenumber last);
+
+struct pxd_object *vec_save (const struct vec *, struct pxd *);
+struct vec *vec_load (struct pxd_object *, const struct pxd *);
+
+#endif /* data/vec.h */
index 7c8ec4178dc9200473f308b385d35367441adac0..af56427899151f7b4ec55e4cd0225340df5365b5 100644 (file)
 
 #include "data/dictionary.h"
 #include "data/identifier.h"
+#include "data/variable.h"
 #include "libpspp/assertion.h"
 #include "libpspp/i18n.h"
+#include "libpspp/pxd.h"
 #include "libpspp/str.h"
 
 #include "gl/xalloc.h"
@@ -58,6 +60,7 @@ vector_create (const char *name, struct variable **vars, size_t var_cnt)
 
   assert (var_cnt > 0);
   assert (id_is_plausible (name, false));
+  vector->name = xstrdup (name);
 
   vector->name = xstrdup (name);
   vector->vars = xmemdup (vars, var_cnt * sizeof *vector->vars);
@@ -144,3 +147,41 @@ compare_vector_ptrs_by_name (const void *a_, const void *b_)
   return utf8_strcasecmp (a->name, b->name);
 }
 
+struct pxd_object *
+vector_save (const struct vector *vector, struct pxd *pxd)
+{
+  struct pxd_builder b;
+  size_t i;
+
+  pxd_builder_init (&b, pxd);
+
+  pxd_builder_put_string (&b, vector->name);
+
+  pxd_builder_put_size_t (&b, vector->var_cnt);
+  for (i = 0; i < vector->var_cnt; i++)
+    pxd_builder_put_size_t (&b, var_get_dict_index (vector->vars[i]));
+
+  return pxd_builder_commit (&b);
+}
+
+struct vector *
+vector_load (struct pxd_object *object, const struct pxd *pxd,
+             const struct dictionary *dict)
+{
+  struct pxd_parser p;
+  struct vector *vector;
+  size_t i;
+
+  vector = xzalloc (sizeof *vector);
+
+  pxd_parser_init (&p, object, pxd);
+
+  vector->name = pxd_parser_get_string (&p);
+
+  vector->var_cnt = pxd_parser_get_size_t (&p);
+  vector->vars = xmalloc (vector->var_cnt * sizeof *vector->vars);
+  for (i = 0; i < vector->var_cnt; i++)
+    vector->vars[i] = dict_get_var (dict, pxd_parser_get_size_t (&p));
+
+  return vector;
+}
index f8fe0888497cc543a8a87e91b8c705ddcfd71cb1..831962965f03bf1442d07e76748d285f2e313fb3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2010, 2011  Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010-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
 #define DATA_VECTOR_H 1
 
 #include <stddef.h>
-#include "data/variable.h"
+#include "data/val-type.h"
 
 struct dictionary;
+struct pxd;
+struct variable;
 
 struct vector *vector_create (const char *name,
                               struct variable **var, size_t var_cnt);
@@ -38,4 +40,8 @@ bool vector_is_valid_name (const char *name, bool issue_error);
 
 int compare_vector_ptrs_by_name (const void *a_, const void *b_);
 
+struct pxd_object *vector_save (const struct vector *, struct pxd *);
+struct vector *vector_load (struct pxd_object *, const struct pxd *,
+                            const struct dictionary *);
+
 #endif /* data/vector.h */
diff --git a/src/db/automake.mk b/src/db/automake.mk
new file mode 100644 (file)
index 0000000..a366ea1
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST += src/db/db.c
diff --git a/src/db/db.c b/src/db/db.c
new file mode 100644 (file)
index 0000000..88149c3
--- /dev/null
@@ -0,0 +1,25 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+int
+main (int argc, char **argv)
+{
+  set_program_name (argv[0]);
+
+  
+}
index 2ba0f2673dd5215ef56c0027c8350ff8aee601af..4f21f1c312ee6d1ebffd76de4391d272c8ba50fb 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009, 2010, 2011, 2013, 2015 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
@@ -49,6 +49,7 @@ DEF_CMD (S_INITIAL | S_DATA, 0, "ADD FILES", cmd_add_files)
 DEF_CMD (S_INITIAL | S_DATA | S_INPUT_PROGRAM | S_FILE_TYPE, 0, "DATA LIST", cmd_data_list)
 DEF_CMD (S_INITIAL | S_DATA, 0, "GET", cmd_get)
 DEF_CMD (S_INITIAL | S_DATA, 0, "GET DATA", cmd_get_data)
+DEF_CMD (S_INITIAL | S_DATA, 0, "GET SESSION", cmd_get_session)
 DEF_CMD (S_INITIAL | S_DATA, 0, "IMPORT", cmd_import)
 DEF_CMD (S_INITIAL | S_DATA, 0, "INPUT PROGRAM", cmd_input_program)
 DEF_CMD (S_INITIAL | S_DATA, 0, "MATCH FILES", cmd_match_files)
@@ -59,6 +60,7 @@ DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET CLOSE", cmd_dataset_close)
 DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET COPY", cmd_dataset_copy)
 DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET NAME", cmd_dataset_name)
 DEF_CMD (S_INITIAL | S_DATA, 0, "DATASET DISPLAY", cmd_dataset_display)
+DEF_CMD (S_INITIAL | S_DATA, 0, "SAVE SESSION", cmd_save_session)
 
 /* Transformations and utilities that may appear after active
    file definition or within INPUT PROGRAM. */
index 906a8ed15816e2f2bbb62d9268f45eb29e1fc4ab..397299b527971a92933c8103622ca0ac84e716ae 100644 (file)
@@ -25,6 +25,7 @@ language_data_io_sources = \
        src/language/data-io/print.c \
        src/language/data-io/save-translate.c \
        src/language/data-io/save.c \
+       src/language/data-io/session.c \
        src/language/data-io/trim.c \
        src/language/data-io/trim.h
 
diff --git a/src/language/data-io/session.c b/src/language/data-io/session.c
new file mode 100644 (file)
index 0000000..86b2671
--- /dev/null
@@ -0,0 +1,79 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "data/case.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "language/command.h"
+#include "language/data-io/file-handle.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/pxd.h"
+
+#include "gl/xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+int
+cmd_save_session (struct lexer *lexer, struct dataset *ds)
+{
+  struct file_handle *handle;
+  struct pxd_object *obj;
+  struct pxd_id root;
+  struct pxd *pxd;
+
+  if (!lex_force_match_id (lexer, "OUTFILE"))
+    return CMD_FAILURE;
+  lex_match (lexer, '=');
+
+  handle = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
+  if (handle == NULL)
+    return CMD_FAILURE;
+
+  pxd = pxd_open (fh_get_file_name (handle), true);
+  obj = dict_save (dataset_dict (ds), pxd);
+  pxd_get_root (pxd, &root);
+  pxd_swap_root (pxd, &root, obj);
+  pxd_close (pxd);
+
+  return CMD_SUCCESS;
+}
+
+int
+cmd_get_session (struct lexer *lexer, struct dataset *ds)
+{
+  struct file_handle *handle;
+  struct pxd_object *obj;
+  struct pxd_id root;
+  struct pxd *pxd;
+
+  if (lex_match_id (lexer, "FILE"))
+    lex_match (lexer, '=');
+
+  handle = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
+  if (handle == NULL)
+    return CMD_FAILURE;
+
+  pxd = pxd_open (fh_get_file_name (handle), false);
+  pxd_get_root (pxd, &root);
+  obj = pxd_fetch (pxd, &root);
+  dict_destroy (dict_load (obj, pxd));
+  pxd_close (pxd);
+
+  return CMD_SUCCESS;
+}
index 55e1a1f6cc7f60474dd75d49402cd95cd931b0b5..9c5ad560a58f24c096a070124240580aea99f6ab 100644 (file)
@@ -20,6 +20,7 @@ src_libpspp_liblibpspp_la_SOURCES = \
        src/libpspp/compiler.h \
        src/libpspp/copyleft.c \
        src/libpspp/copyleft.h \
+       src/libpspp/db.h \
        src/libpspp/deque.c \
        src/libpspp/deque.h \
        src/libpspp/encoding-guesser.c \
@@ -62,6 +63,8 @@ src_libpspp_liblibpspp_la_SOURCES = \
        src/libpspp/pool.h \
        src/libpspp/prompt.c \
        src/libpspp/prompt.h \
+       src/libpspp/pxd.c \
+       src/libpspp/pxd.h \
        src/libpspp/range-map.c \
        src/libpspp/range-map.h \
        src/libpspp/range-set.c \
diff --git a/src/libpspp/db.h b/src/libpspp/db.h
new file mode 100644 (file)
index 0000000..66603d7
--- /dev/null
@@ -0,0 +1,22 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_DB_H
+#define LIBPSPP_DB_H 1
+
+
+
+#endif /* libpspp/db.h */
index 9cabf9bf2e228c0db8be76526096bc3c1694e4ba..028a4e8d0c7ad711ac3135285f2a798567d2f6bc 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2010-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
 #ifndef LIBPSPP_FLOAT_FORMAT_H
 #define LIBPSPP_FLOAT_FORMAT_H 1
 
+#include <byteswap.h>
 #include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
 #include <stddef.h>
 #include "libpspp/compiler.h"
 
@@ -56,6 +59,9 @@ enum float_format
 #endif
   };
 
+static inline uint64_t double_to_ieee64le (double x);
+static inline double ieee64le_to_double (uint64_t x);
+
 void float_convert (enum float_format, const void *,
                     enum float_format, void *);
 
@@ -67,5 +73,39 @@ int float_identify (double expected_value, const void *, size_t,
                     enum float_format *best_guess);
 
 double float_get_lowest (void);
+\f
+static inline uint64_t
+double_to_ieee64le (double x)
+{
+  uint64_t y;
+
+#if FLOAT_NATIVE_DOUBLE == FLOAT_IEEE_DOUBLE_LE
+  memcpy (&y, &x, sizeof y);
+#elif FLOAT_NATIVE_DOUBLE == FLOAT_IEEE_DOUBLE_BE
+  memcpy (&y, &x, sizeof y);
+  y = bswap_64 (y);
+#else
+  float_convert (&x, FLOAT_NATIVE_DOUBLE, &y, FLOAT_IEEE_DOUBLE_LE);
+#endif
+
+  return y;
+}
+
+static inline double
+ieee64le_to_double (uint64_t x)
+{
+  double y;
+
+#if FLOAT_NATIVE_DOUBLE == FLOAT_IEEE_DOUBLE_LE
+  memcpy (&y, &x, sizeof y);
+#elif FLOAT_NATIVE_DOUBLE == FLOAT_IEEE_DOUBLE_BE
+  x = bswap_64 (x);
+  memcpy (&y, &x, sizeof y);
+#else
+  float_convert (&x, FLOAT_IEEE_DOUBLE_LE, &y, FLOAT_NATIVE_DOUBLE);
+#endif
+
+  return y;
+}
 
 #endif /* float-format.h */
index a8a3cb32756125c5333bf1fa3021d3624c047488..6229acea383f9ca137883eb51f05fc3b92a33015 100644 (file)
@@ -38,7 +38,7 @@ enum integer_format
 #endif
   };
 
-/* Byte-order conversion macros.
+/* Endian conversion macros.
 
    These are intended for use only in contexts where a function cannot be
    called, e.g. static initializers or case labels.
@@ -65,9 +65,9 @@ enum integer_format
 #define LE32_TO_CPU(X) CPU_TO_LE32 (X)
 #define LE64_TO_CPU(X) CPU_TO_LE64 (X)
 
-/* Byte-order conversion functions.
+/* Endian conversion functions.
 
-   These should be preferred to the macros. */
+   Use these in preference to the macros above. */
 static inline uint16_t cpu_to_be16 (uint16_t x) { return CPU_TO_BE16 (x); }
 static inline uint32_t cpu_to_be32 (uint32_t x) { return CPU_TO_BE32 (x); }
 static inline uint64_t cpu_to_be64 (uint64_t x) { return CPU_TO_BE64 (x); }
index fc31acf0b439fec19c339296abe3e5fe8f5ce314..101a14d3c3a829df3d6ce38989339069b260cf71 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010, 2011 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
@@ -59,7 +59,12 @@ intern_lookup__ (const char *s, size_t length, unsigned int hash)
 const char *
 intern_new (const char *s)
 {
-  size_t length = strlen (s);
+  return intern_buffer (s, strlen (s));
+}
+
+const char *
+intern_buffer (const char *s, size_t length)
+{
   unsigned int hash = hash_bytes (s, length, 0);
   struct interned_string *is;
 
@@ -110,6 +115,13 @@ intern_unref (const char *s)
     }
 }
 
+/* Returns the length of interned string S. */
+size_t
+intern_strlen (const char *s)
+{
+  return interned_string_from_string (s)->length;
+}
+
 /* Given null-terminated string S, returns true if S is an interned string
    returned by intern_string_new(), false otherwise.
 
@@ -123,11 +135,3 @@ is_interned_string (const char *s)
   unsigned int hash = hash_bytes (s, length, 0);
   return intern_lookup__ (s, length, hash) != NULL;
 }
-
-/* Returns the length of S, which must be an interned string returned by
-   intern_new(). */
-size_t
-intern_strlen (const char *s)
-{
-  return interned_string_from_string (s)->length;
-}
index 2f07a9ef77808b17f19e85adc2ffc9dc8d024262..9d8beb439a843ba37d6ba69b58822f1ea693b1c6 100644 (file)
@@ -34,6 +34,8 @@
 #include <stddef.h>
 
 const char *intern_new (const char *);
+const char *intern_buffer (const char *, size_t length);
+
 const char *intern_ref (const char *);
 void intern_unref (const char *);
 
diff --git a/src/libpspp/pxd.c b/src/libpspp/pxd.c
new file mode 100644 (file)
index 0000000..00bc888
--- /dev/null
@@ -0,0 +1,692 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "libpspp/pxd.h"
+
+#include <gdbm.h>
+#include <stdlib.h>
+
+#include "data/value.h"
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "libpspp/float-format.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/intern.h"
+
+#include "gl/error.h"
+#include "gl/minmax.h"
+#include "gl/sha1.h"
+#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
+
+struct pxd
+  {
+    GDBM_FILE dbf;
+  };
+
+static struct pxd_object *pxd_object_lookup__ (const struct pxd_id *id);
+static struct pxd_object *pxd_object_create_raw__ (char *raw, size_t n_links,
+                                                   size_t size,
+                                                   const struct pxd_id *);
+
+static datum
+make_datum (const void *data, size_t size)
+{
+  datum d;
+
+  d.dptr = CONST_CAST (void *, data);
+  d.dsize = size;
+
+  return d;
+}
+
+static datum
+string_datum (const char *s)
+{
+  return make_datum (s, strlen (s));
+}
+
+static datum
+id_datum (const struct pxd_id *id)
+{
+  return make_datum (id, sizeof *id);
+}
+
+static datum
+root_key (void)
+{
+  return string_datum ("root");
+}
+
+void
+pxd_get_root (const struct pxd *pxd, struct pxd_id *id)
+{
+  datum content;
+
+  content = gdbm_fetch (pxd->dbf, root_key ());
+  if (content.dptr != NULL && content.dsize == sizeof *id)
+    memcpy (id, content.dptr, sizeof *id);
+  else
+    memset (id, 0, sizeof *id);
+  free (content.dptr);
+}
+
+struct pxd *
+pxd_open (const char *name, bool may_create)
+{
+  struct pxd *pxd;
+  GDBM_FILE dbf;
+
+  dbf = gdbm_open (CONST_CAST (char *, name), 4096,
+                   may_create ? GDBM_WRCREAT : GDBM_WRITER, 0777, NULL);
+  if (dbf == NULL)
+    {
+      error (0, 0, "%s: open failed (%s)", name, gdbm_strerror (gdbm_errno));
+      return NULL;
+    }
+
+  pxd = xmalloc (sizeof *pxd);
+  pxd->dbf = dbf;
+  return pxd;
+}
+
+void
+pxd_close (struct pxd *pxd)
+{
+  if (pxd != NULL)
+    {
+      gdbm_close (pxd->dbf);
+      free (pxd);
+    }
+}
+
+struct pxd_object *
+pxd_fetch (const struct pxd *pxd, const struct pxd_id *id)
+{
+  struct pxd_object *obj;
+  datum content;
+  uint32_t n_links;
+  size_t header_size;
+
+  obj = pxd_object_lookup__ (id);
+  if (obj != NULL)
+    return obj;
+
+  content = gdbm_fetch (pxd->dbf, id_datum (id));
+  if (content.dptr == NULL)
+    error (1, 0, PXD_ID_FMT": not found in database", PXD_ID_ARGS (id));
+
+  if (content.dsize < sizeof n_links)
+    error (1, 0, PXD_ID_FMT": size %d is less than minimum size 4",
+           PXD_ID_ARGS(id), content.dsize);
+
+  n_links = le32_to_cpu (*(uint32_t *) content.dptr);
+  header_size = 4 + n_links * sizeof (struct pxd_id);
+  if (header_size > content.dsize)
+    error (1, 0, PXD_ID_FMT": size %d is less than minimum size %zu for "
+           "object with %"PRIu32" links",
+           PXD_ID_ARGS (id), content.dsize, header_size, n_links);
+
+  return pxd_object_create_raw__ (content.dptr, n_links,
+                                  content.dsize - header_size, id);
+}
+
+void
+pxd_store (struct pxd *pxd, const struct pxd_object *object)
+{
+  datum content;
+
+  content = make_datum (pxd_object_raw_data__ (object),
+                        pxd_object_raw_size__ (object));
+  if (gdbm_store (pxd->dbf, id_datum (&object->id), content, GDBM_INSERT) < 0)
+    error (1, 0, PXD_ID_FMT": storing object failed",
+           PXD_ID_ARGS (&object->id));
+}
+
+bool
+pxd_swap_root (struct pxd *pxd, const struct pxd_id *old_root,
+               struct pxd_object *new_root)
+{
+  struct pxd_id cur_root;
+
+  pxd_get_root (pxd, &cur_root);
+  if (pxd_id_equals (&cur_root, old_root))
+    {
+      if (gdbm_store (pxd->dbf, root_key (), id_datum (&new_root->id),
+                      GDBM_INSERT) < 0)
+        error (1, 0, "storing root object failed");
+      pxd_object_unref (new_root);
+      return true;
+    }
+  else
+    return false;
+}
+\f
+static struct hmap object_table = HMAP_INITIALIZER (object_table);
+
+static struct pxd_object *
+pxd_object_lookup__ (const struct pxd_id *id)
+{
+  const struct pxd_object *obj;
+
+  HMAP_FOR_EACH_IN_BUCKET (obj, struct pxd_object, hmap_node,
+                           pxd_id_hash (id), &object_table)
+    if (pxd_id_equals (id, &obj->id))
+      return pxd_object_ref (obj);
+
+  return NULL;
+}
+
+static struct pxd_object *
+pxd_object_create_raw__ (char *raw, size_t n_links, size_t size,
+                         const struct pxd_id *id)
+{
+  struct pxd_object *obj;
+
+  obj = xmalloc (sizeof *obj);
+  hmap_insert (&object_table, &obj->hmap_node, pxd_id_hash (id));
+  obj->n_refs = 1;
+  obj->id = *id;
+  obj->n_links = n_links;
+  obj->size = size;
+  obj->links = (struct pxd_id *) (raw + sizeof (uint32_t));
+  obj->data = (uint8_t *) (obj->links + obj->n_links);
+
+  return obj;
+}
+
+struct pxd_object *
+pxd_object_create (const struct pxd_id links[], size_t n_links,
+                   const void *data, size_t size)
+{
+  struct pxd_object *obj;
+  struct sha1_ctx sha;
+  uint32_t le_n_links;
+  struct pxd_id id;
+  char *raw;
+
+  /* Hash the raw form of the object. */
+  sha1_init_ctx (&sha);
+  le_n_links = cpu_to_le32 (n_links);
+  sha1_process_bytes (&le_n_links, sizeof le_n_links, &sha);
+  sha1_process_bytes (links, n_links * sizeof *links, &sha);
+  sha1_process_bytes (data, size, &sha);
+  sha1_finish_ctx (&sha, &id);
+
+  /* Reuse an existing copy if there is one. */
+  obj = pxd_object_lookup__ (&id);
+  if (obj != NULL)
+    return obj;
+
+  /* Build a new object. */
+  raw = xmalloc (sizeof le_n_links + n_links * sizeof *links +
+                 size);
+  memcpy (raw, &le_n_links, sizeof le_n_links);
+  memcpy (raw + sizeof le_n_links, links, n_links * sizeof *links);
+  memcpy (raw + sizeof le_n_links + n_links * sizeof *links, data, size);
+
+  return pxd_object_create_raw__ (raw, n_links, size, &id);
+}
+
+struct pxd_object *
+pxd_object_ref (const struct pxd_object *const_obj)
+{
+  struct pxd_object *obj = CONST_CAST (struct pxd_object *, const_obj);
+  obj->n_refs++;
+  return obj;
+}
+
+void
+pxd_object_unref (struct pxd_object *obj)
+{
+  if (obj != NULL && --obj->n_refs == 0)
+    {
+      hmap_delete (&object_table, &obj->hmap_node);
+      free (pxd_object_raw_data__ (obj));
+      free (obj);
+    }
+}
+
+void *
+pxd_object_raw_data__ (const struct pxd_object *obj)
+{
+  return ((uint32_t *) obj->links) - 1;
+}
+
+size_t
+pxd_object_raw_size__ (const struct pxd_object *obj)
+{
+  return sizeof (uint32_t *) + obj->n_links * sizeof *obj->links + obj->size;
+}
+\f
+void
+pxd_builder_init (struct pxd_builder *b, struct pxd *pxd)
+{
+  b->pxd = pxd;
+
+  b->links = NULL;
+  b->n_links = b->links_allocated = 0;
+
+  b->data = NULL;
+  b->size = b->data_allocated = 0;
+}
+
+void
+pxd_builder_destroy (struct pxd_builder *b)
+{
+  if (b != NULL)
+    {
+      free (b->links);
+      b->links = NULL;
+
+      free (b->data);
+      b->data = NULL;
+    }
+}
+
+struct pxd_object *
+pxd_builder_commit (struct pxd_builder *b)
+{
+  struct pxd_object *obj;
+
+  obj = pxd_object_create (b->links, b->n_links, b->data, b->size);
+  pxd_store (b->pxd, obj);
+  pxd_builder_destroy (b);
+
+  return obj;
+}
+
+void *
+pxd_builder_put_uninit (struct pxd_builder *b, size_t n)
+{
+  void *p;
+
+  if (b->size + n > b->data_allocated)
+    {
+      b->data_allocated = MAX (b->size + n + 64, b->data_allocated * 2);
+      b->data = xrealloc (b->data, b->data_allocated);
+    }
+
+  p = &b->data[b->size];
+  b->size += n;
+  return p;
+}
+
+void
+pxd_builder_put (struct pxd_builder *b, const void *p, size_t n)
+{
+  memcpy (pxd_builder_put_uninit (b, n), p, n);
+}
+
+void
+pxd_builder_put_value (struct pxd_builder *b,
+                       const union value *value, int width)
+{
+  if (width == 0)
+    pxd_builder_put_double (b, value->f);
+  else
+    {
+      const uint8_t *s = value_str (value, width);
+      if (width < sizeof (struct pxd_id))
+        pxd_builder_put (b, s, width);
+      else
+        pxd_builder_put_link (b, pxd_object_create (NULL, 0, s, width));
+    }
+}
+
+static void
+pxd_builder_put_string__ (struct pxd_builder *b, const char *s, size_t length)
+{
+  pxd_builder_put_u32 (b, length);
+  if (length < sizeof (struct pxd_id))
+    pxd_builder_put (b, s, length);
+  else
+    pxd_builder_put_link (b, pxd_object_create (NULL, 0, s, length));
+}
+
+void
+pxd_builder_put_string (struct pxd_builder *b, const char *s)
+{
+  return pxd_builder_put_string__ (b, s, strlen (s));
+}
+
+void
+pxd_builder_put_interned_string (struct pxd_builder *b, const char *s)
+{
+  return pxd_builder_put_string__ (b, s, intern_strlen (s));
+}
+
+void
+pxd_builder_put_bool (struct pxd_builder *b, bool x)
+{
+  pxd_builder_put_u8 (b, x != 0);
+}
+
+void
+pxd_builder_put_u8 (struct pxd_builder *b, unsigned char x)
+{
+  pxd_builder_put (b, &x, 1);
+}
+
+void
+pxd_builder_put_u16 (struct pxd_builder *b, unsigned short int x)
+{
+  uint16_t le_x = cpu_to_le16 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void pxd_builder_put_u32 (struct pxd_builder *b, unsigned int x)
+{
+  uint32_t le_x = cpu_to_le32 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void
+pxd_builder_put_u64 (struct pxd_builder *b, unsigned long long int x)
+{
+  uint64_t le_x = cpu_to_le64 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void
+pxd_builder_put_s8 (struct pxd_builder *b, signed char x)
+{
+  pxd_builder_put (b, &x, 1);
+}
+
+void
+pxd_builder_put_s16 (struct pxd_builder *b, short int x)
+{
+  uint16_t le_x = cpu_to_le16 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void pxd_builder_put_s32 (struct pxd_builder *b, int x)
+{
+  uint32_t le_x = cpu_to_le32 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void
+pxd_builder_put_s64 (struct pxd_builder *b, long long int x)
+{
+  uint64_t le_x = cpu_to_le64 (x);
+  pxd_builder_put (b, &le_x, sizeof (le_x));
+}
+
+void
+pxd_builder_put_size_t (struct pxd_builder *b, size_t x)
+{
+  pxd_builder_put_u64 (b, x);
+}
+
+void
+pxd_builder_put_casenumber (struct pxd_builder *b, casenumber x)
+{
+  pxd_builder_put_u64 (b, x);
+}
+
+void
+pxd_builder_put_double (struct pxd_builder *b, double x)
+{
+  pxd_builder_put_u64 (b, double_to_ieee64le (x));
+}
+
+void
+pxd_builder_put_link (struct pxd_builder *b, struct pxd_object *obj)
+{
+  if (b->n_links >= b->links_allocated)
+    b->links = x2nrealloc (b->links, &b->links_allocated, sizeof *b->links);
+
+  b->links[b->n_links++] = obj->id;
+}
+\f
+void
+pxd_parser_init (struct pxd_parser *p,
+                 struct pxd_object *obj, const struct pxd *pxd)
+{
+  p->obj = obj;
+  p->pxd = pxd;
+  p->offset = 0;
+  p->link = 0;
+}
+
+void
+pxd_parser_destroy (struct pxd_parser *p)
+{
+  if (p != NULL)
+    pxd_object_unref (p->obj);
+}
+
+
+const void *
+pxd_parser_get (struct pxd_parser *p, size_t n)
+{
+  const void *data;
+
+  assert (p->offset + n <= p->obj->size);
+
+  data = &p->obj->data[p->offset];
+  p->offset += n;
+  return data;
+}
+
+void
+pxd_parser_get_copy (struct pxd_parser *p, void *dst, size_t n)
+{
+  memcpy (dst, pxd_parser_get (p, n), n);
+}
+
+void
+pxd_parser_get_value (struct pxd_parser *p, union value *value, int width)
+{
+  value_init (value, width);
+  if (width == 0)
+    value->f = ieee64le_to_double (pxd_parser_get_u64 (p));
+  else
+    {
+      uint8_t *s = value_str_rw (value, width);
+      if (width < sizeof (struct pxd_id))
+        pxd_parser_get_copy (p, s, width);
+      else
+        {
+          struct pxd_object *link = pxd_parser_get_link (p);
+          assert (link->size == width);
+          memcpy (s, link->data, width);
+          pxd_object_unref (link);
+        }
+    }
+}
+
+char *
+pxd_parser_get_string (struct pxd_parser *p)
+{
+  uint32_t length = pxd_parser_get_u32 (p);
+  if (length < sizeof (struct pxd_id))
+    return xmemdup0 (pxd_parser_get (p, length), length);
+  else
+    {
+      struct pxd_object *link;
+      char *s;
+
+      link = pxd_parser_get_link (p);
+      assert (link->size == length);
+      s = xmemdup0 (link->data, link->size);
+      pxd_object_unref (link);
+
+      return s;
+    }
+}
+
+const char *
+pxd_parser_get_interned_string (struct pxd_parser *p)
+{
+  uint32_t length = pxd_parser_get_u32 (p);
+  if (length < sizeof (struct pxd_id))
+    return intern_buffer (pxd_parser_get (p, length), length);
+  else
+    {
+      struct pxd_object *link;
+      const char *s;
+
+      link = pxd_parser_get_link (p);
+      assert (link->size == length);
+      s = intern_buffer ((const void *) link->data, link->size);
+      pxd_object_unref (link);
+
+      return s;
+    }
+}
+
+bool
+pxd_parser_get_bool (struct pxd_parser *p)
+{
+  return pxd_parser_get_u8 (p) != 0;
+}
+
+unsigned char
+pxd_parser_get_u8 (struct pxd_parser *p)
+{
+  uint8_t x;
+  pxd_parser_get_copy (p, &x, 1);
+  return x;
+}
+
+unsigned short int
+pxd_parser_get_u16 (struct pxd_parser *p)
+{
+  uint16_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le16_to_cpu (x);
+}
+
+unsigned int
+pxd_parser_get_u32 (struct pxd_parser *p)
+{
+  uint32_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le32_to_cpu (x);
+}
+
+unsigned long long int
+pxd_parser_get_u64 (struct pxd_parser *p)
+{
+  uint64_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le64_to_cpu (x);
+}
+
+signed char
+pxd_parser_get_s8 (struct pxd_parser *p)
+{
+  int8_t x;
+  pxd_parser_get_copy (p, &x, 1);
+  return x;
+}
+
+short int
+pxd_parser_get_s16 (struct pxd_parser *p)
+{
+  uint16_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le16_to_cpu (x);
+}
+
+int
+pxd_parser_get_s32 (struct pxd_parser *p)
+{
+  uint32_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le32_to_cpu (x);
+}
+
+long long int
+pxd_parser_get_s64 (struct pxd_parser *p)
+{
+  uint64_t x;
+  pxd_parser_get_copy (p, &x, sizeof x);
+  return le64_to_cpu (x);
+}
+
+size_t
+pxd_parser_get_size_t (struct pxd_parser *p)
+{
+  uint64_t x = pxd_parser_get_u64 (p);
+  assert (x <= SIZE_MAX);
+  return x;
+}
+
+casenumber
+pxd_parser_get_casenumber (struct pxd_parser *p)
+{
+  uint64_t x = pxd_parser_get_u64 (p);
+  assert (x <= CASENUMBER_MAX);
+  return x;
+}
+
+double
+pxd_parser_get_double (struct pxd_parser *p)
+{
+  return ieee64le_to_double (pxd_parser_get_u64 (p));
+}
+
+struct pxd_object *
+pxd_parser_get_link (struct pxd_parser *p)
+{
+  assert (p->link < p->obj->n_links);
+
+  return pxd_fetch (p->pxd, &p->obj->links[p->link++]);
+}
+\f
+void
+pxd_array_builder_init (struct pxd_array_builder *ab, struct pxd *pxd)
+{
+  pxd_builder_init (&ab->b, pxd);
+}
+
+void
+pxd_array_builder_destroy (struct pxd_array_builder *ab)
+{
+  pxd_builder_destroy (&ab->b);
+}
+
+struct pxd_object *
+pxd_array_builder_commit (struct pxd_array_builder *ab)
+{
+  return pxd_builder_commit (&ab->b);
+}
+
+void
+pxd_array_builder_add (struct pxd_array_builder *ab, struct pxd_object *obj)
+{
+  pxd_builder_put_link (&ab->b, obj);
+}
+\f
+void
+pxd_array_init (struct pxd_array *array, struct pxd_object *obj,
+                const struct pxd *pxd)
+{
+  array->pxd = pxd;
+  array->obj = obj;
+}
+
+void
+pxd_array_destroy (struct pxd_array *array)
+{
+  pxd_object_unref (array->obj);
+}
diff --git a/src/libpspp/pxd.h b/src/libpspp/pxd.h
new file mode 100644 (file)
index 0000000..22b34c4
--- /dev/null
@@ -0,0 +1,254 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2010, 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_PXD_H
+#define LIBPSPP_PXD_H 1
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "data/case.h"
+#include "libpspp/hmap.h"
+
+struct pxd;
+struct pxd_object;
+struct pxd_id;
+union value;
+\f
+/* Databases. */
+
+struct pxd *pxd_open (const char *name, bool create);
+void pxd_close (struct pxd *);
+
+struct pxd_object *pxd_fetch (const struct pxd *, const struct pxd_id *);
+void pxd_store (struct pxd *, const struct pxd_object *);
+
+void pxd_get_root (const struct pxd *, struct pxd_id *);
+bool pxd_swap_root (struct pxd *, const struct pxd_id *old_root,
+                    struct pxd_object *new_root);
+\f
+/* Object IDs. */
+
+struct pxd_id
+  {
+    uint32_t opaque[5];
+  };
+
+#define PXD_ID_FMT "%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32
+#define PXD_ID_ARGS(ID)                         \
+        (ID)->opaque[0],                        \
+        (ID)->opaque[1],                        \
+        (ID)->opaque[2],                        \
+        (ID)->opaque[3],                        \
+        (ID)->opaque[4]
+#define PXD_ID_SCAN_ARGS(ID)                    \
+        &(ID)->opaque[0],                       \
+        &(ID)->opaque[1],                       \
+        &(ID)->opaque[2],                       \
+        &(ID)->opaque[3],                       \
+        &(ID)->opaque[4]
+
+static inline bool
+pxd_id_equals (const struct pxd_id *a, const struct pxd_id *b)
+{
+  return (a->opaque[0] == b->opaque[0]
+          && a->opaque[1] == b->opaque[1]
+          && a->opaque[2] == b->opaque[2]
+          && a->opaque[3] == b->opaque[3]
+          && a->opaque[4] == b->opaque[4]);
+}
+
+static inline uint32_t
+pxd_id_hash (const struct pxd_id *id)
+{
+  return id->opaque[0];
+}
+\f
+/* Objects. */
+
+struct pxd_object
+  {
+    struct hmap_node hmap_node;
+    unsigned int n_refs;
+    struct pxd_id id;
+    unsigned int n_links;
+    unsigned int size;
+    struct pxd_id *links;
+    uint8_t *data;
+  };
+
+struct pxd_object *pxd_object_create (const struct pxd_id[], size_t,
+                                      const void *, size_t);
+
+struct pxd_object *pxd_object_ref (const struct pxd_object *);
+void pxd_object_unref (struct pxd_object *);
+
+static inline const struct pxd_id *
+pxd_object_id (const struct pxd_object *obj)
+{
+  return &obj->id;
+}
+
+static inline unsigned int
+pxd_object_get_n_links (const struct pxd_object *obj)
+{
+  return obj->n_links;
+}
+
+static inline const struct pxd_id *
+pxd_object_get_link_id (const struct pxd_object *obj, unsigned int idx)
+{
+  return &obj->links[idx];
+}
+
+static inline struct pxd_object *
+pxd_object_get_link (const struct pxd_object *obj, unsigned int idx,
+                     const struct pxd *pxd)
+{
+  return pxd_fetch (pxd, pxd_object_get_link_id (obj, idx));
+}
+
+static inline unsigned int
+pxd_object_size (const struct pxd_object *obj)
+{
+  return obj->size;
+}
+
+static inline const uint8_t *
+pxd_object_data (const struct pxd_object *obj)
+{
+  return obj->data;
+}
+
+void *pxd_object_raw_data__ (const struct pxd_object *);
+size_t pxd_object_raw_size__ (const struct pxd_object *);
+\f
+/* Object builder. */
+
+struct pxd_builder
+  {
+    struct pxd *pxd;
+
+    struct pxd_id *links;
+    unsigned int n_links, links_allocated;
+
+    uint8_t *data;
+    unsigned int size, data_allocated;
+  };
+
+void pxd_builder_init (struct pxd_builder *, struct pxd *);
+void pxd_builder_destroy (struct pxd_builder *);
+
+struct pxd_object *pxd_builder_commit (struct pxd_builder *);
+
+void *pxd_builder_put_uninit (struct pxd_builder *, size_t);
+void pxd_builder_put (struct pxd_builder *, const void *, size_t);
+void pxd_builder_put_value (struct pxd_builder *,
+                            const union value *, int width);
+void pxd_builder_put_string (struct pxd_builder *, const char *);
+void pxd_builder_put_interned_string (struct pxd_builder *, const char *);
+void pxd_builder_put_bool (struct pxd_builder *, bool);
+void pxd_builder_put_u8 (struct pxd_builder *, unsigned char);
+void pxd_builder_put_u16 (struct pxd_builder *, unsigned short int);
+void pxd_builder_put_u32 (struct pxd_builder *, unsigned int);
+void pxd_builder_put_u64 (struct pxd_builder *, unsigned long long int);
+void pxd_builder_put_s8 (struct pxd_builder *, signed char);
+void pxd_builder_put_s16 (struct pxd_builder *, short int);
+void pxd_builder_put_s32 (struct pxd_builder *, int);
+void pxd_builder_put_s64 (struct pxd_builder *, long long int);
+void pxd_builder_put_size_t (struct pxd_builder *, size_t);
+void pxd_builder_put_casenumber (struct pxd_builder *, casenumber);
+void pxd_builder_put_double (struct pxd_builder *, double);
+
+void pxd_builder_put_link (struct pxd_builder *, struct pxd_object *);
+\f
+/* Object parser. */
+
+struct pxd_parser
+  {
+    struct pxd_object *obj;
+    const struct pxd *pxd;
+    unsigned int offset;
+    unsigned int link;
+  };
+
+void pxd_parser_init (struct pxd_parser *,
+                      struct pxd_object *, const struct pxd *);
+void pxd_parser_destroy (struct pxd_parser *);
+
+const void *pxd_parser_get (struct pxd_parser *, size_t);
+void pxd_parser_get_copy (struct pxd_parser *, void *, size_t);
+void pxd_parser_get_value (struct pxd_parser *, union value *, int width);
+char *pxd_parser_get_string (struct pxd_parser *);
+const char *pxd_parser_get_interned_string (struct pxd_parser *);
+bool pxd_parser_get_bool (struct pxd_parser *);
+unsigned char pxd_parser_get_u8 (struct pxd_parser *);
+unsigned short int pxd_parser_get_u16 (struct pxd_parser *);
+unsigned int pxd_parser_get_u32 (struct pxd_parser *);
+unsigned long long int pxd_parser_get_u64 (struct pxd_parser *);
+signed char pxd_parser_get_s8 (struct pxd_parser *);
+short int pxd_parser_get_s16 (struct pxd_parser *);
+int pxd_parser_get_s32 (struct pxd_parser *);
+long long int pxd_parser_get_s64 (struct pxd_parser *);
+size_t pxd_parser_get_size_t (struct pxd_parser *);
+casenumber pxd_parser_get_casenumber (struct pxd_parser *);
+double pxd_parser_get_double (struct pxd_parser *);
+struct pxd_object *pxd_parser_get_link (struct pxd_parser *);
+\f
+/* Array builder. */
+
+#define PXD_ARRAY_LEVELS 10
+#define PXD_ARRAY_BITS 5
+
+struct pxd_array_builder
+  {
+    struct pxd_builder b;
+  };
+
+void pxd_array_builder_init (struct pxd_array_builder *, struct pxd *);
+void pxd_array_builder_destroy (struct pxd_array_builder *);
+
+struct pxd_object *pxd_array_builder_commit (struct pxd_array_builder *);
+
+void pxd_array_builder_add (struct pxd_array_builder *, struct pxd_object *);
+\f
+/* Array reader. */
+
+struct pxd_array
+  {
+    const struct pxd *pxd;
+    struct pxd_object *obj;
+  };
+
+void pxd_array_init (struct pxd_array *, struct pxd_object *,
+                     const struct pxd *);
+void pxd_array_destroy (struct pxd_array *);
+
+static inline unsigned long long int
+pxd_array_size (const struct pxd_array *array)
+{
+  return array->obj->n_links;
+}
+
+static inline struct pxd_object *
+pxd_array_get (const struct pxd_array *array, unsigned long long int index)
+{
+  return pxd_object_get_link (array->obj, index, array->pxd);
+}
+
+#endif /* libpspp/pxd.h */
diff --git a/src/processor/automake.mk b/src/processor/automake.mk
new file mode 100644 (file)
index 0000000..bbeefe8
--- /dev/null
@@ -0,0 +1,6 @@
+## Process this file with automake to produce Makefile.in  -*- makefile -*-
+
+EXTRA_DIST += \
+       src/processor/processor.c \
+       src/processor/request.c \
+       src/processor/request.h
diff --git a/src/processor/processor.c b/src/processor/processor.c
new file mode 100644 (file)
index 0000000..6b7c6c7
--- /dev/null
@@ -0,0 +1,188 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_FPU_CONTROL_H
+#include <fpu_control.h>
+#endif
+#if HAVE_FENV_H
+#include <fenv.h>
+#endif
+#if HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#include <unistd.h>
+
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/file-handle-def.h"
+#include "data/file-name.h"
+#include "data/session.h"
+#include "data/settings.h"
+#include "data/variable.h"
+#include "gsl/gsl_errno.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/include-path.h"
+#include "libpspp/argv-parser.h"
+#include "libpspp/compiler.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/version.h"
+#include "math/random.h"
+#include "output/driver.h"
+#include "output/message-item.h"
+#include "ui/source-init-opts.h"
+
+#include "gl/fatal-signal.h"
+#include "gl/progname.h"
+#include "gl/relocatable.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static void bug_handler(int sig);
+static void fpu_init (void);
+
+/* Program entry point. */
+int
+main (int argc, char **argv)
+{
+  char s[128];
+
+  set_program_name (argv[0]);
+
+  signal (SIGABRT, bug_handler);
+  signal (SIGSEGV, bug_handler);
+  signal (SIGFPE, bug_handler);
+
+  i18n_init ();
+  fpu_init ();
+  gsl_set_error_handler_off ();
+
+  fh_init ();
+  settings_init ();
+  random_init ();
+
+  //msg_set_handler (output_msg, lexer);
+
+  while (fgets (s, sizeof s, stdin))
+    {
+      struct pspp_proc_request *request;
+      struct pxd_object *object;
+      struct pxd_id id;
+      int n = -1;
+
+      if (sscanf (s, PXD_ID_FMT"%n", PXD_ID_SCAN_ARGS (&id), &n) <= 0 || n < 0)
+        {
+          printf ("bad input format\n");
+          fflush (stdout);
+          continue;
+        }
+
+      object = pxd_fetch (pxd, &id);
+      if (object == NULL)
+        {
+          printf (PXD_ID_FMT": object not found\n", PXD_ID_ARGS (&id));
+          fflush (stdout);
+          continue;
+        }
+
+      request = pspp_proc_request_load (object, pxd);
+      pxd_object_unref (object);
+      if (request == NULL)
+        {
+          printf (PXD_ID_FMT": bad request\n", PXD_ID_FMT (&id));
+          fflush (stdout);
+          continue;
+        }
+
+      reply = pspp_proc_request_execute (request);
+      if (reply == NULL)
+        {
+          printf (PXD_ID_FMT": could not execute request\n", PXD_ID_FMT (&id));
+          fflush (stdout);
+          continue;
+        }
+
+      object = pspp_proc_reply_save (reply, pxd);
+      pspp_proc_reply_destroy (reply);
+      if (object == NULL)
+        {
+          printf (PXD_ID_FMT": could not save reply\n", PXD_ID_FMT (&id));
+          fflush (stdout);
+          continue;
+        }
+
+      printf (PXD_ID_FMT"\n", PXD_ID_FMT (pxd_object_id (object)));
+      fflush (stdout);
+      pxd_object_unref (object);
+
+      /* XXX what keeps the reply from getting garbage collected? */
+    }
+
+  random_done ();
+  settings_done ();
+  fh_done ();
+  lex_destroy (lexer);
+  output_close ();
+  i18n_done ();
+}
+\f
+static void
+fpu_init (void)
+{
+#if HAVE_FEHOLDEXCEPT
+  fenv_t foo;
+  feholdexcept (&foo);
+#elif HAVE___SETFPUCW && defined(_FPU_IEEE)
+  __setfpucw (_FPU_IEEE);
+#elif HAVE_FPSETMASK
+  fpsetmask (0);
+#endif
+}
+
+/* If a segfault happens, issue a message to that effect and halt */
+static void
+bug_handler(int sig)
+{
+  /* Reset SIG to its default handling so that if it happens again we won't
+     recurse. */
+  signal (sig, SIG_DFL);
+
+  switch (sig)
+    {
+    case SIGABRT:
+      request_bug_report("Assertion Failure/Abort");
+      break;
+    case SIGFPE:
+      request_bug_report("Floating Point Exception");
+      break;
+    case SIGSEGV:
+      request_bug_report("Segmentation Violation");
+      break;
+    default:
+      request_bug_report("Unknown");
+      break;
+    }
+
+  /* Re-raise the signal so that we terminate with the correct status. */
+  raise (sig);
+}
diff --git a/src/processor/request.c b/src/processor/request.c
new file mode 100644 (file)
index 0000000..a97539e
--- /dev/null
@@ -0,0 +1,41 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "request.h"
+
+struct pspp_proc_request
+  {
+    struct session *session;
+    
+
+  };
+
+struct pspp_proc_request *
+pspp_proc_request_load (struct pxd_object *object,
+                        const struct pxd *pxd)
+{
+  
+
+}
+
+struct pxd_object *pspp_proc_reply_save (const struct pspp_proc_reply *,
+                                         struct pxd *);
+struct pspp_proc_reply *pspp_proc_reply_load (struct pxd_object *,
+                                              const struct pxd *);
+
+#endif /* processor/request.h */
diff --git a/src/processor/request.h b/src/processor/request.h
new file mode 100644 (file)
index 0000000..3dad3fb
--- /dev/null
@@ -0,0 +1,30 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef PSPP_PROC_REQUEST_H
+#define PSPP_PROC_REQUEST_H 1
+
+struct pxd_object *pspp_proc_request_save (const struct pspp_proc_request *,
+                                           struct pxd *);
+struct pspp_proc_request *pspp_proc_request_load (struct pxd_object *,
+                                                  const struct pxd *);
+
+struct pxd_object *pspp_proc_reply_save (const struct pspp_proc_reply *,
+                                         struct pxd *);
+struct pspp_proc_reply *pspp_proc_reply_load (struct pxd_object *,
+                                              const struct pxd *);
+
+#endif /* processor/request.h */
index c93a2cd1b1ea2bb16555d298131faf47d3c85cc3..93df1bfe530cefd218681d06d3766a1293ee3360 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009, 2010, 2015 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
@@ -617,7 +617,7 @@ test_insert_ordered (int max_elems, hash_function *hash)
           int max = INT_MIN;
           int j;
 
-          for (j = 0; j <= hmapx.hmap.mask; j++) 
+          for (j = 0; j < hmap_n_buckets (&hmapx.hmap); j++) 
             {
               int count = 0;
               struct hmap_node *node;