1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009 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>
22 #include <libpspp/array.h>
23 #include <libpspp/hash-functions.h>
26 /* A custom attribute of the sort maintained by the DATAFILE
27 ATTRIBUTE and VARIABLE ATTRIBUTE commands.
29 Attributes have a name (the rules for which are the same as
30 those for PSPP variable names) and one or more values, each of
31 which is a string. An attribute may be part of one attribute
35 struct hmap_node node; /* Used by attrset. */
36 char *name; /* Name. */
37 char **values; /* Each value. */
38 size_t n_values; /* Number of values. */
39 size_t allocated_values; /* Amount of allocated space for values. */
42 /* Creates and returns a new attribute with the given NAME. The
43 attribute initially has no values. (Attributes with no values
44 cannot be saved to system files, so at least one value should
45 be added before the attribute is made available to the PSPP
48 attribute_create (const char *name)
50 struct attribute *attr = xmalloc (sizeof *attr);
51 attr->name = xstrdup (name);
54 attr->allocated_values = 0;
58 /* Creates and returns a new attribute with the same name and
61 attribute_clone (const struct attribute *orig)
63 struct attribute *attr;
66 attr = attribute_create (orig->name);
67 for (i = 0; i < orig->n_values; i++)
68 attribute_add_value (attr, orig->values[i]);
72 /* Destroys ATTR and frees all associated memory.
74 This function must not be called if ATTR is part of an
75 attribute set. Use attrset_delete() instead. */
77 attribute_destroy (struct attribute *attr)
83 for (i = 0; i < attr->n_values; i++)
84 free (attr->values[i]);
91 /* Returns the name of ATTR. The caller must not free or modify
92 the returned string. */
94 attribute_get_name (const struct attribute *attr)
99 /* Returns ATTR's value with the given INDEX, or a null pointer
100 if INDEX is greater than or equal to the number of values in
101 ATTR (that is, attributes are numbered starting from 0). The
102 caller must not free or modify the returned string. */
104 attribute_get_value (const struct attribute *attr, size_t index)
106 return index < attr->n_values ? attr->values[index] : NULL;
109 /* Returns ATTR's number of values. */
111 attribute_get_n_values (const struct attribute *attrs)
113 return attrs->n_values;
116 /* Adds a copy of VALUE as a new value to ATTR. The caller
117 retains ownership of VALUE. */
119 attribute_add_value (struct attribute *attr, const char *value)
121 if (attr->n_values >= attr->allocated_values)
122 attr->values = x2nrealloc (attr->values, &attr->allocated_values,
123 sizeof *attr->values);
124 attr->values[attr->n_values++] = xstrdup (value);
127 /* Adds or replaces the value with the given INDEX in ATTR by a
128 copy of VALUE. The caller retains ownership of VALUE.
130 If INDEX is an existing value index, that value is replaced.
131 If no value index numbered INDEX exists in ATTR, then it is
132 added, and any values intermediate between the last maximum
133 index and INDEX are set to the empty string. */
135 attribute_set_value (struct attribute *attr, size_t index, const char *value)
137 if (index < attr->n_values)
139 /* Replace existing value. */
140 free (attr->values[index]);
141 attr->values[index] = xstrdup (value);
146 while (index > attr->n_values)
147 attribute_add_value (attr, "");
148 attribute_add_value (attr, value);
153 /* Deletes the value with the given INDEX from ATTR. Any values
154 with higher-numbered indexes are shifted down into the gap
157 If INDEX is greater than the maximum index, this has no effect.*/
159 attribute_del_value (struct attribute *attr, size_t index)
161 if (index < attr->n_values)
163 free (attr->values[index]);
164 remove_element (attr->values, attr->n_values, sizeof *attr->values,
170 /* Initializes SET as a new, initially empty attibute set. */
172 attrset_init (struct attrset *set)
174 hmap_init (&set->map);
177 /* Initializes NEW_SET as a new attribute set whose contents are
178 initially the same as that of OLD_SET. */
180 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
182 struct attribute *old_attr;
184 attrset_init (new_set);
185 HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
187 struct attribute *new_attr = attribute_clone (old_attr);
188 hmap_insert (&new_set->map, &new_attr->node,
189 hmap_node_hash (&old_attr->node));
193 /* Frees the storage associated with SET, if SET is nonnull.
194 (Does not free SET itself.) */
196 attrset_destroy (struct attrset *set)
200 struct attribute *attr, *next;
202 HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
203 attribute_destroy (attr);
204 hmap_destroy (&set->map);
208 /* Returns the number of attributes in SET. */
210 attrset_count (const struct attrset *set)
212 return hmap_count (&set->map);
215 /* Returns the attribute in SET whose name matches NAME
216 case-insensitively, or a null pointer if SET does not contain
217 an attribute with that name. */
219 attrset_lookup (struct attrset *set, const char *name)
221 struct attribute *attr;
222 HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
223 hash_case_string (name, 0), &set->map)
224 if (!strcasecmp (attribute_get_name (attr), name))
229 /* Adds ATTR to SET, which must not already contain an attribute
230 with the same name (matched case insensitively). Ownership of
231 ATTR is transferred to SET. */
233 attrset_add (struct attrset *set, struct attribute *attr)
235 const char *name = attribute_get_name (attr);
236 assert (attrset_lookup (set, name) == NULL);
237 hmap_insert (&set->map, &attr->node, hash_case_string (name, 0));
240 /* Deletes any attribute from SET that matches NAME
241 (case-insensitively). */
243 attrset_delete (struct attrset *set, const char *name)
245 struct attribute *attr = attrset_lookup (set, name);
248 hmap_delete (&set->map, &attr->node);
249 attribute_destroy (attr);
253 /* Deletes all attributes from SET. */
255 attrset_clear (struct attrset *set)
257 attrset_destroy (set);
261 static struct attribute *iterator_data (struct attrset_iterator *iterator)
263 return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
266 /* Returns the first attribute in SET and initializes ITERATOR.
267 If SET is empty, returns a null pointer.
269 The caller must not destroy the returned attribute, but it may
270 add or remove values.
272 Attributes are visited in no particular order. Calling
273 attrset_add() during iteration can cause some attributes to
274 be visited more than once and others not at all. */
276 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
278 iterator->node = hmap_first (&set->map);
279 return iterator_data (iterator);
282 /* Returns the next attribute in SET and advances ITERATOR, which
283 should have been initialized by calling attrset_first(). If
284 all the attributes in SET have already been visited, returns a
287 The caller must not destroy the returned attribute, but it may
288 add or remove values.
290 Attributes are visited in no particular order. Calling
291 attrset_add() during iteration can cause some attributes to
292 be visited more than once and others not at all. */
294 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
296 iterator->node = hmap_next (&set->map, iterator->node);
297 return iterator_data (iterator);