From 52c54183e360053b1845e46cb96cd44a0cf96040 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 16 Feb 2015 11:24:46 -0800 Subject: [PATCH] pxd: initial work GET SESSION works for my simple test case --- Smake | 1 + configure.ac | 1 + src/automake.mk | 2 + src/data/attributes.c | 121 +++++- src/data/attributes.h | 10 +- src/data/automake.mk | 3 + src/data/column.h | 55 +++ src/data/dictionary.c | 170 +++++++- src/data/dictionary.h | 8 +- src/data/format.c | 16 + src/data/format.h | 5 +- src/data/missing-values.c | 40 +- src/data/missing-values.h | 8 +- src/data/mrset.c | 75 +++- src/data/mrset.h | 5 + src/data/relation.h | 46 ++ src/data/value-labels.c | 108 ++++- src/data/value-labels.h | 10 +- src/data/variable.c | 180 +++++++- src/data/variable.h | 4 + src/data/vec.h | 47 +++ src/data/vector.c | 41 ++ src/data/vector.h | 10 +- src/db/automake.mk | 1 + src/db/db.c | 25 ++ src/language/command.def | 4 +- src/language/data-io/automake.mk | 1 + src/language/data-io/session.c | 79 ++++ src/libpspp/automake.mk | 3 + src/libpspp/db.h | 22 + src/libpspp/float-format.h | 42 +- src/libpspp/integer-format.h | 6 +- src/libpspp/intern.c | 24 +- src/libpspp/intern.h | 2 + src/libpspp/pxd.c | 692 +++++++++++++++++++++++++++++++ src/libpspp/pxd.h | 254 ++++++++++++ src/processor/automake.mk | 6 + src/processor/processor.c | 188 +++++++++ src/processor/request.c | 41 ++ src/processor/request.h | 30 ++ tests/libpspp/hmapx-test.c | 4 +- 41 files changed, 2338 insertions(+), 52 deletions(-) create mode 100644 src/data/column.h create mode 100644 src/data/relation.h create mode 100644 src/data/vec.h create mode 100644 src/db/automake.mk create mode 100644 src/db/db.c create mode 100644 src/language/data-io/session.c create mode 100644 src/libpspp/db.h create mode 100644 src/libpspp/pxd.c create mode 100644 src/libpspp/pxd.h create mode 100644 src/processor/automake.mk create mode 100644 src/processor/processor.c create mode 100644 src/processor/request.c create mode 100644 src/processor/request.h diff --git a/Smake b/Smake index 227affa36b..a8a28a6472 100644 --- a/Smake +++ b/Smake @@ -20,6 +20,7 @@ GNULIB_MODULES = \ crc \ crypto/md4 \ crypto/rijndael \ + crypto/sha1 \ dirname \ dtoastr \ environ \ diff --git a/configure.ac b/configure.ac index 7e976a8ca6..8949daa458 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/automake.mk b/src/automake.mk index efbdf72012..a6fedef21e 100644 --- a/src/automake.mk +++ b/src/automake.mk @@ -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 diff --git a/src/data/attributes.c b/src/data/attributes.c index c4ae97c285..b04ebf0693 100644 --- a/src/data/attributes.c +++ b/src/data/attributes.c @@ -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 @@ -22,8 +22,10 @@ #include #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" @@ -36,13 +38,17 @@ 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; +} /* 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 */ +} + diff --git a/src/data/attributes.h b/src/data/attributes.h index ab7b12e301..8795f8feaf 100644 --- a/src/data/attributes.h +++ b/src/data/attributes.h @@ -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; diff --git a/src/data/automake.mk b/src/data/automake.mk index 8b26f525e4..17d5ce1d6f 100644 --- a/src/data/automake.mk +++ b/src/data/automake.mk @@ -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 index 0000000000..164257f096 --- /dev/null +++ b/src/data/column.h @@ -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 . */ + +#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 */ diff --git a/src/data/dictionary.c b/src/data/dictionary.c index 4eaaefae18..7cf2a7917d 100644 --- a/src/data/dictionary.c +++ b/src/data/dictionary.c @@ -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; } + +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) +{ +} + diff --git a/src/data/dictionary.h b/src/data/dictionary.h index 66542469e3..62acd584f1 100644 --- a/src/data/dictionary.h +++ b/src/data/dictionary.h @@ -22,14 +22,14 @@ #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 */ diff --git a/src/data/format.c b/src/data/format.c index 55e166e817..52206b0f53 100644 --- a/src/data/format.c +++ b/src/data/format.c @@ -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; +} /* Describes a display format. */ struct fmt_desc diff --git a/src/data/format.h b/src/data/format.h index d05e443621..92e66b3a94 100644 --- a/src/data/format.h +++ b/src/data/format.h @@ -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); diff --git a/src/data/missing-values.c b/src/data/missing-values.c index 9aba57e0e0..aa029a4f4d 100644 --- a/src/data/missing-values.c +++ b/src/data/missing-values.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2005, 2009, 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); +} diff --git a/src/data/missing-values.h b/src/data/missing-values.h index 511ebd7ddd..504d06ad67 100644 --- a/src/data/missing-values.h +++ b/src/data/missing-values.h @@ -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 */ diff --git a/src/data/mrset.c b/src/data/mrset.c index 38b0ab2d52..ce1a35851e 100644 --- a/src/data/mrset.c +++ b/src/data/mrset.c @@ -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; +} diff --git a/src/data/mrset.h b/src/data/mrset.h index 9971924e0d..95b9784f71 100644 --- a/src/data/mrset.h +++ b/src/data/mrset.h @@ -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 index 0000000000..0865ae5102 --- /dev/null +++ b/src/data/relation.h @@ -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 . */ + +#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 */ diff --git a/src/data/value-labels.c b/src/data/value-labels.c index c405961f29..c1dee054ac 100644 --- a/src/data/value-labels.c +++ b/src/data/value-labels.c @@ -30,10 +30,14 @@ #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; +} + 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); } diff --git a/src/data/value-labels.h b/src/data/value-labels.h index af98d9f9b5..e2d4b36409 100644 --- a/src/data/value-labels.h +++ b/src/data/value-labels.h @@ -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 */ diff --git a/src/data/variable.c b/src/data/variable.c index 971154368c..f22bc522e4 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -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 @@ -33,8 +33,10 @@ #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 *); 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); + } } /* 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; } + +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) +{ +} diff --git a/src/data/variable.h b/src/data/variable.h index 25596ad368..d2b905ad73 100644 --- a/src/data/variable.h +++ b/src/data/variable.h @@ -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 index 0000000000..501a11f403 --- /dev/null +++ b/src/data/vec.h @@ -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 . */ + +#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 */ diff --git a/src/data/vector.c b/src/data/vector.c index 7c8ec4178d..af56427899 100644 --- a/src/data/vector.c +++ b/src/data/vector.c @@ -22,8 +22,10 @@ #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; +} diff --git a/src/data/vector.h b/src/data/vector.h index f8fe088849..831962965f 100644 --- a/src/data/vector.h +++ b/src/data/vector.h @@ -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 @@ -18,9 +18,11 @@ #define DATA_VECTOR_H 1 #include -#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 index 0000000000..a366ea1003 --- /dev/null +++ b/src/db/automake.mk @@ -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 index 0000000000..88149c3ed1 --- /dev/null +++ b/src/db/db.c @@ -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 . */ + +#include + +int +main (int argc, char **argv) +{ + set_program_name (argv[0]); + + +} diff --git a/src/language/command.def b/src/language/command.def index 2ba0f2673d..4f21f1c312 100644 --- a/src/language/command.def +++ b/src/language/command.def @@ -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. */ diff --git a/src/language/data-io/automake.mk b/src/language/data-io/automake.mk index 906a8ed158..397299b527 100644 --- a/src/language/data-io/automake.mk +++ b/src/language/data-io/automake.mk @@ -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 index 0000000000..86b2671475 --- /dev/null +++ b/src/language/data-io/session.c @@ -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 . */ + +#include + +#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; +} diff --git a/src/libpspp/automake.mk b/src/libpspp/automake.mk index 55e1a1f6cc..9c5ad560a5 100644 --- a/src/libpspp/automake.mk +++ b/src/libpspp/automake.mk @@ -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 index 0000000000..66603d7dae --- /dev/null +++ b/src/libpspp/db.h @@ -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 . */ + +#ifndef LIBPSPP_DB_H +#define LIBPSPP_DB_H 1 + + + +#endif /* libpspp/db.h */ diff --git a/src/libpspp/float-format.h b/src/libpspp/float-format.h index 9cabf9bf2e..028a4e8d0c 100644 --- a/src/libpspp/float-format.h +++ b/src/libpspp/float-format.h @@ -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 @@ -17,7 +17,10 @@ #ifndef LIBPSPP_FLOAT_FORMAT_H #define LIBPSPP_FLOAT_FORMAT_H 1 +#include #include +#include +#include #include #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); + +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 */ diff --git a/src/libpspp/integer-format.h b/src/libpspp/integer-format.h index a8a3cb3275..6229acea38 100644 --- a/src/libpspp/integer-format.h +++ b/src/libpspp/integer-format.h @@ -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); } diff --git a/src/libpspp/intern.c b/src/libpspp/intern.c index fc31acf0b4..101a14d3c3 100644 --- a/src/libpspp/intern.c +++ b/src/libpspp/intern.c @@ -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; -} diff --git a/src/libpspp/intern.h b/src/libpspp/intern.h index 2f07a9ef77..9d8beb439a 100644 --- a/src/libpspp/intern.h +++ b/src/libpspp/intern.h @@ -34,6 +34,8 @@ #include 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 index 0000000000..00bc8882d8 --- /dev/null +++ b/src/libpspp/pxd.c @@ -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 . */ + +#include + +#include "libpspp/pxd.h" + +#include +#include + +#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; +} + +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; +} + +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; +} + +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++]); +} + +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); +} + +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 index 0000000000..22b34c4606 --- /dev/null +++ b/src/libpspp/pxd.h @@ -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 . */ + +#ifndef LIBPSPP_PXD_H +#define LIBPSPP_PXD_H 1 + +#include +#include +#include +#include + +#include "data/case.h" +#include "libpspp/hmap.h" + +struct pxd; +struct pxd_object; +struct pxd_id; +union value; + +/* 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); + +/* 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]; +} + +/* 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 *); + +/* 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 *); + +/* 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 *); + +/* 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 *); + +/* 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 index 0000000000..bbeefe8015 --- /dev/null +++ b/src/processor/automake.mk @@ -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 index 0000000000..6b7c6c7329 --- /dev/null +++ b/src/processor/processor.c @@ -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 . */ + +#include + +#include +#include +#include +#if HAVE_FPU_CONTROL_H +#include +#endif +#if HAVE_FENV_H +#include +#endif +#if HAVE_IEEEFP_H +#include +#endif +#include + +#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 (); +} + +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 index 0000000000..a97539e1ab --- /dev/null +++ b/src/processor/request.c @@ -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 . */ + +#include + +#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 index 0000000000..3dad3fb3ca --- /dev/null +++ b/src/processor/request.h @@ -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 . */ + +#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 */ diff --git a/tests/libpspp/hmapx-test.c b/tests/libpspp/hmapx-test.c index c93a2cd1b1..93df1bfe53 100644 --- a/tests/libpspp/hmapx-test.c +++ b/tests/libpspp/hmapx-test.c @@ -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; -- 2.30.2