X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fattributes.c;h=b04ebf0693ebe354be103a48c00b4f2ee0c37cc2;hb=52c54183e360053b1845e46cb96cd44a0cf96040;hp=d99e945b014def2836ec1eb57ea33631fc5086d4;hpb=9e0e4996fad6563f0a1ce628b80db5c23ef8279e;p=pspp diff --git a/src/data/attributes.c b/src/data/attributes.c index d99e945b01..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 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 @@ -16,12 +16,18 @@ #include -#include +#include "data/attributes.h" + #include #include -#include -#include -#include "xalloc.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" /* A custom attribute of the sort maintained by the DATAFILE ATTRIBUTE and VARIABLE ATTRIBUTE commands. @@ -32,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 @@ -48,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; @@ -80,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); @@ -118,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); @@ -134,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. */ @@ -158,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]); @@ -166,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 @@ -199,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); } } @@ -220,8 +287,8 @@ attrset_lookup (struct attrset *set, const char *name) { struct attribute *attr; HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node, - hash_case_string (name, 0), &set->map) - if (!strcasecmp (attribute_get_name (attr), name)) + utf8_hash_case_string (name, 0), &set->map) + if (!utf8_strcasecmp (attribute_get_name (attr), name)) break; return attr; } @@ -233,8 +300,14 @@ void attrset_add (struct attrset *set, struct attribute *attr) { const char *name = attribute_get_name (attr); + assert (attrset_lookup (set, name) == NULL); - hmap_insert (&set->map, &attr->node, hash_case_string (name, 0)); + assert (attr->set == NULL); + + attrset_uncache__ (set); + + attr->set = set; + hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0)); } /* Deletes any attribute from SET that matches NAME @@ -245,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); } } @@ -254,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) @@ -296,3 +408,45 @@ attrset_next (const struct attrset *set, struct attrset_iterator *iterator) iterator->node = hmap_next (&set->map, iterator->node); return iterator_data (iterator); } + +static int +compare_attribute_by_name (const void *a_, const void *b_) +{ + const struct attribute *const *a = a_; + const struct attribute *const *b = b_; + + return strcmp ((*a)->name, (*b)->name); +} + +/* Allocates and returns an array of pointers to attributes + that is sorted by attribute name. The array has + 'attrset_count (SET)' elements. The caller is responsible for + freeing the array. */ +struct attribute ** +attrset_sorted (const struct attrset *set) +{ + if (set != NULL && attrset_count (set) > 0) + { + struct attribute **attrs; + struct attribute *attr; + size_t i; + + attrs = xmalloc (attrset_count (set) * sizeof *attrs); + i = 0; + HMAP_FOR_EACH (attr, struct attribute, node, &set->map) + attrs[i++] = attr; + assert (i == attrset_count (set)); + qsort (attrs, attrset_count (set), sizeof *attrs, + compare_attribute_by_name); + return attrs; + } + else + return NULL; +} + +static void +attrset_uncache__ (struct attrset *set UNUSED) +{ + /* XXX */ +} +