1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "data/attributes.h"
24 #include "libpspp/array.h"
25 #include "libpspp/hash-functions.h"
27 #include "gl/xalloc.h"
29 /* A custom attribute of the sort maintained by the DATAFILE
30 ATTRIBUTE and VARIABLE ATTRIBUTE commands.
32 Attributes have a name (the rules for which are the same as
33 those for PSPP variable names) and one or more values, each of
34 which is a string. An attribute may be part of one attribute
38 struct hmap_node node; /* Used by attrset. */
39 char *name; /* Name. */
40 char **values; /* Each value. */
41 size_t n_values; /* Number of values. */
42 size_t allocated_values; /* Amount of allocated space for values. */
45 /* Creates and returns a new attribute with the given NAME. The
46 attribute initially has no values. (Attributes with no values
47 cannot be saved to system files, so at least one value should
48 be added before the attribute is made available to the PSPP
51 attribute_create (const char *name)
53 struct attribute *attr = xmalloc (sizeof *attr);
54 attr->name = xstrdup (name);
57 attr->allocated_values = 0;
61 /* Creates and returns a new attribute with the same name and
64 attribute_clone (const struct attribute *orig)
66 struct attribute *attr;
69 attr = attribute_create (orig->name);
70 for (i = 0; i < orig->n_values; i++)
71 attribute_add_value (attr, orig->values[i]);
75 /* Destroys ATTR and frees all associated memory.
77 This function must not be called if ATTR is part of an
78 attribute set. Use attrset_delete() instead. */
80 attribute_destroy (struct attribute *attr)
86 for (i = 0; i < attr->n_values; i++)
87 free (attr->values[i]);
94 /* Returns the name of ATTR. The caller must not free or modify
95 the returned string. */
97 attribute_get_name (const struct attribute *attr)
102 /* Returns ATTR's value with the given INDEX, or a null pointer
103 if INDEX is greater than or equal to the number of values in
104 ATTR (that is, attributes are numbered starting from 0). The
105 caller must not free or modify the returned string. */
107 attribute_get_value (const struct attribute *attr, size_t index)
109 return index < attr->n_values ? attr->values[index] : NULL;
112 /* Returns ATTR's number of values. */
114 attribute_get_n_values (const struct attribute *attrs)
116 return attrs->n_values;
119 /* Adds a copy of VALUE as a new value to ATTR. The caller
120 retains ownership of VALUE. */
122 attribute_add_value (struct attribute *attr, const char *value)
124 if (attr->n_values >= attr->allocated_values)
125 attr->values = x2nrealloc (attr->values, &attr->allocated_values,
126 sizeof *attr->values);
127 attr->values[attr->n_values++] = xstrdup (value);
130 /* Adds or replaces the value with the given INDEX in ATTR by a
131 copy of VALUE. The caller retains ownership of VALUE.
133 If INDEX is an existing value index, that value is replaced.
134 If no value index numbered INDEX exists in ATTR, then it is
135 added, and any values intermediate between the last maximum
136 index and INDEX are set to the empty string. */
138 attribute_set_value (struct attribute *attr, size_t index, const char *value)
140 if (index < attr->n_values)
142 /* Replace existing value. */
143 free (attr->values[index]);
144 attr->values[index] = xstrdup (value);
149 while (index > attr->n_values)
150 attribute_add_value (attr, "");
151 attribute_add_value (attr, value);
156 /* Deletes the value with the given INDEX from ATTR. Any values
157 with higher-numbered indexes are shifted down into the gap
160 If INDEX is greater than the maximum index, this has no effect.*/
162 attribute_del_value (struct attribute *attr, size_t index)
164 if (index < attr->n_values)
166 free (attr->values[index]);
167 remove_element (attr->values, attr->n_values, sizeof *attr->values,
173 /* Initializes SET as a new, initially empty attibute set. */
175 attrset_init (struct attrset *set)
177 hmap_init (&set->map);
180 /* Initializes NEW_SET as a new attribute set whose contents are
181 initially the same as that of OLD_SET. */
183 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
185 struct attribute *old_attr;
187 attrset_init (new_set);
188 HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
190 struct attribute *new_attr = attribute_clone (old_attr);
191 hmap_insert (&new_set->map, &new_attr->node,
192 hmap_node_hash (&old_attr->node));
196 /* Frees the storage associated with SET, if SET is nonnull.
197 (Does not free SET itself.) */
199 attrset_destroy (struct attrset *set)
203 struct attribute *attr, *next;
205 HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
206 attribute_destroy (attr);
207 hmap_destroy (&set->map);
211 /* Returns the number of attributes in SET. */
213 attrset_count (const struct attrset *set)
215 return hmap_count (&set->map);
218 /* Returns the attribute in SET whose name matches NAME
219 case-insensitively, or a null pointer if SET does not contain
220 an attribute with that name. */
222 attrset_lookup (struct attrset *set, const char *name)
224 struct attribute *attr;
225 HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
226 hash_case_string (name, 0), &set->map)
227 if (!strcasecmp (attribute_get_name (attr), name))
232 /* Adds ATTR to SET, which must not already contain an attribute
233 with the same name (matched case insensitively). Ownership of
234 ATTR is transferred to SET. */
236 attrset_add (struct attrset *set, struct attribute *attr)
238 const char *name = attribute_get_name (attr);
239 assert (attrset_lookup (set, name) == NULL);
240 hmap_insert (&set->map, &attr->node, hash_case_string (name, 0));
243 /* Deletes any attribute from SET that matches NAME
244 (case-insensitively). */
246 attrset_delete (struct attrset *set, const char *name)
248 struct attribute *attr = attrset_lookup (set, name);
251 hmap_delete (&set->map, &attr->node);
252 attribute_destroy (attr);
256 /* Deletes all attributes from SET. */
258 attrset_clear (struct attrset *set)
260 attrset_destroy (set);
264 static struct attribute *iterator_data (struct attrset_iterator *iterator)
266 return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
269 /* Returns the first attribute in SET and initializes ITERATOR.
270 If SET is empty, returns a null pointer.
272 The caller must not destroy the returned attribute, but it may
273 add or remove values.
275 Attributes are visited in no particular order. Calling
276 attrset_add() during iteration can cause some attributes to
277 be visited more than once and others not at all. */
279 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
281 iterator->node = hmap_first (&set->map);
282 return iterator_data (iterator);
285 /* Returns the next attribute in SET and advances ITERATOR, which
286 should have been initialized by calling attrset_first(). If
287 all the attributes in SET have already been visited, returns a
290 The caller must not destroy the returned attribute, but it may
291 add or remove values.
293 Attributes are visited in no particular order. Calling
294 attrset_add() during iteration can cause some attributes to
295 be visited more than once and others not at all. */
297 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
299 iterator->node = hmap_next (&set->map, iterator->node);
300 return iterator_data (iterator);