X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=src%2Fdata%2Fattributes.c;fp=src%2Fdata%2Fattributes.c;h=aa1282908438857be3437936f0d78574790625db;hb=5a0b0d607efde2ab3a47d0d9c9fc62128a3156c1;hp=0000000000000000000000000000000000000000;hpb=5165d8c7ed098d87a481f08652f3e1aa6d82c366;p=pspp diff --git a/src/data/attributes.c b/src/data/attributes.c new file mode 100644 index 0000000000..aa12829084 --- /dev/null +++ b/src/data/attributes.c @@ -0,0 +1,298 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2008 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 +#include +#include +#include "xalloc.h" + +/* A custom attribute of the sort maintained by the DATAFILE + ATTRIBUTE and VARIABLE ATTRIBUTE commands. + + Attributes have a name (the rules for which are the same as + those for PSPP variable names) and one or more values, each of + which is a string. An attribute may be part of one attribute + set. */ +struct attribute + { + 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. */ + }; + +/* 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 + be added before the attribute is made available to the PSPP + user.) */ +struct attribute * +attribute_create (const char *name) +{ + struct attribute *attr = xmalloc (sizeof *attr); + attr->name = xstrdup (name); + attr->values = NULL; + attr->n_values = 0; + attr->allocated_values = 0; + return attr; +} + +/* Creates and returns a new attribute with the same name and + values as ORIG. */ +struct attribute * +attribute_clone (const struct attribute *orig) +{ + struct attribute *attr; + size_t i; + + attr = attribute_create (orig->name); + for (i = 0; i < orig->n_values; i++) + attribute_add_value (attr, orig->values[i]); + return attr; +} + +/* Destroys ATTR and frees all associated memory. + + This function must not be called if ATTR is part of an + attribute set. Use attrset_delete() instead. */ +void +attribute_destroy (struct attribute *attr) +{ + if (attr != NULL) + { + size_t i; + + for (i = 0; i < attr->n_values; i++) + free (attr->values[i]); + free (attr->values); + free (attr->name); + free (attr); + } +} + +/* Returns the name of ATTR. The caller must not free or modify + the returned string. */ +const char * +attribute_get_name (const struct attribute *attr) +{ + return attr->name; +} + +/* Returns ATTR's value with the given INDEX, or a null pointer + if INDEX is greater than or equal to the number of values in + ATTR (that is, attributes are numbered starting from 0). The + caller must not free or modify the returned string. */ +const char * +attribute_get_value (const struct attribute *attr, size_t index) +{ + return index < attr->n_values ? attr->values[index] : NULL; +} + +/* Returns ATTR's number of values. */ +size_t +attribute_get_n_values (const struct attribute *attrs) +{ + return attrs->n_values; +} + +/* Adds a copy of VALUE as a new value to ATTR. The caller + retains ownership of VALUE. */ +void +attribute_add_value (struct attribute *attr, const char *value) +{ + if (attr->n_values >= attr->allocated_values) + attr->values = x2nrealloc (attr->values, &attr->allocated_values, + sizeof *attr->values); + attr->values[attr->n_values++] = xstrdup (value); +} + +/* Adds or replaces the value with the given INDEX in ATTR by a + copy of VALUE. The caller retains ownership of VALUE. + + If INDEX is an existing value index, that value is replaced. + If no value index numbered INDEX exists in ATTR, then it is + added, and any values intermediate between the last maximum + index and INDEX are set to the empty string. */ +void +attribute_set_value (struct attribute *attr, size_t index, const char *value) +{ + if (index < attr->n_values) + { + /* Replace existing value. */ + free (attr->values[index]); + attr->values[index] = xstrdup (value); + } + else + { + /* Add new value. */ + while (index > attr->n_values) + attribute_add_value (attr, ""); + attribute_add_value (attr, value); + } + +} + +/* Deletes the value with the given INDEX from ATTR. Any values + with higher-numbered indexes are shifted down into the gap + that this creates. + + If INDEX is greater than the maximum index, this has no effect.*/ +void +attribute_del_value (struct attribute *attr, size_t index) +{ + if (index < attr->n_values) + { + free (attr->values[index]); + remove_element (attr->values, attr->n_values, sizeof *attr->values, + index); + attr->n_values--; + } +} + +/* Initializes SET as a new, initially empty attibute set. */ +void +attrset_init (struct attrset *set) +{ + hmap_init (&set->map); +} + +/* Initializes NEW_SET as a new attribute set whose contents are + initially the same as that of OLD_SET. */ +void +attrset_clone (struct attrset *new_set, const struct attrset *old_set) +{ + struct attribute *old_attr; + + attrset_init (new_set); + HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map) + { + struct attribute *new_attr = attribute_clone (old_attr); + hmap_insert (&new_set->map, &new_attr->node, + hmap_node_hash (&old_attr->node)); + } +} + +/* Frees the storage associated with SET, if SET is nonnull. + (Does not free SET itself.) */ +void +attrset_destroy (struct attrset *set) +{ + if (set != NULL) + { + struct attribute *attr, *next; + + HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map) + attribute_destroy (attr); + hmap_destroy (&set->map); + } +} + +/* Returns the number of attributes in SET. */ +size_t +attrset_count (const struct attrset *set) +{ + return hmap_count (&set->map); +} + +/* Returns the attribute in SET whose name matches NAME + case-insensitively, or a null pointer if SET does not contain + an attribute with that name. */ +struct attribute * +attrset_lookup (struct attrset *set, const char *name) +{ + struct attribute *attr; + HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node, + hsh_hash_case_string (name), &set->map) + if (!strcasecmp (attribute_get_name (attr), name)) + break; + return attr; +} + +/* Adds ATTR to SET, which must not already contain an attribute + with the same name (matched case insensitively). Ownership of + ATTR is transferred to SET. */ +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, hsh_hash_case_string (name)); +} + +/* Deletes any attribute from SET that matches NAME + (case-insensitively). */ +void +attrset_delete (struct attrset *set, const char *name) +{ + struct attribute *attr = attrset_lookup (set, name); + if (attr != NULL) + { + hmap_delete (&set->map, &attr->node); + attribute_destroy (attr); + } +} + +/* Deletes all attributes from SET. */ +void +attrset_clear (struct attrset *set) +{ + attrset_destroy (set); + attrset_init (set); +} + +static struct attribute *iterator_data (struct attrset_iterator *iterator) +{ + return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node); +} + +/* Returns the first attribute in SET and initializes ITERATOR. + If SET is empty, returns a null pointer. + + The caller must not destroy the returned attribute, but it may + add or remove values. + + Attributes are visited in no particular order. Calling + attrset_add() during iteration can cause some attributes to + be visited more than once and others not at all. */ +struct attribute * +attrset_first (const struct attrset *set, struct attrset_iterator *iterator) +{ + iterator->node = hmap_first (&set->map); + return iterator_data (iterator); +} + +/* Returns the next attribute in SET and advances ITERATOR, which + should have been initialized by calling attrset_first(). If + all the attributes in SET have already been visited, returns a + null pointer. + + The caller must not destroy the returned attribute, but it may + add or remove values. + + Attributes are visited in no particular order. Calling + attrset_add() during iteration can cause some attributes to + be visited more than once and others not at all. */ +struct attribute * +attrset_next (const struct attrset *set, struct attrset_iterator *iterator) +{ + iterator->node = hmap_next (&set->map, iterator->node); + return iterator_data (iterator); +}