1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2011, 2012 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"
26 #include "libpspp/i18n.h"
28 #include "gl/xalloc.h"
30 /* A custom attribute of the sort maintained by the DATAFILE
31 ATTRIBUTE and VARIABLE ATTRIBUTE commands.
33 Attributes have a name (the rules for which are the same as
34 those for PSPP variable names) and one or more values, each of
35 which is a string. An attribute may be part of one attribute
39 struct hmap_node node; /* Used by attrset. */
40 char *name; /* Name. */
41 char **values; /* Each value. */
42 size_t n_values; /* Number of values. */
43 size_t allocated_values; /* Amount of allocated space for values. */
46 /* Creates and returns a new attribute with the given NAME. The
47 attribute initially has no values. (Attributes with no values
48 cannot be saved to system files, so at least one value should
49 be added before the attribute is made available to the PSPP
52 attribute_create (const char *name)
54 struct attribute *attr = xmalloc (sizeof *attr);
55 attr->name = xstrdup (name);
58 attr->allocated_values = 0;
62 /* Creates and returns a new attribute with the same name and
65 attribute_clone (const struct attribute *orig)
67 struct attribute *attr;
70 attr = attribute_create (orig->name);
71 for (i = 0; i < orig->n_values; i++)
72 attribute_add_value (attr, orig->values[i]);
76 /* Destroys ATTR and frees all associated memory.
78 This function must not be called if ATTR is part of an
79 attribute set. Use attrset_delete() instead. */
81 attribute_destroy (struct attribute *attr)
87 for (i = 0; i < attr->n_values; i++)
88 free (attr->values[i]);
95 /* Returns the name of ATTR. The caller must not free or modify
96 the returned string. */
98 attribute_get_name (const struct attribute *attr)
103 /* Returns ATTR's value with the given INDEX, or a null pointer
104 if INDEX is greater than or equal to the number of values in
105 ATTR (that is, attributes are numbered starting from 0). The
106 caller must not free or modify the returned string. */
108 attribute_get_value (const struct attribute *attr, size_t index)
110 return index < attr->n_values ? attr->values[index] : NULL;
113 /* Returns ATTR's number of values. */
115 attribute_get_n_values (const struct attribute *attrs)
117 return attrs->n_values;
120 /* Adds a copy of VALUE as a new value to ATTR. The caller
121 retains ownership of VALUE. */
123 attribute_add_value (struct attribute *attr, const char *value)
125 if (attr->n_values >= attr->allocated_values)
126 attr->values = x2nrealloc (attr->values, &attr->allocated_values,
127 sizeof *attr->values);
128 attr->values[attr->n_values++] = xstrdup (value);
131 /* Adds or replaces the value with the given INDEX in ATTR by a
132 copy of VALUE. The caller retains ownership of VALUE.
134 If INDEX is an existing value index, that value is replaced.
135 If no value index numbered INDEX exists in ATTR, then it is
136 added, and any values intermediate between the last maximum
137 index and INDEX are set to the empty string. */
139 attribute_set_value (struct attribute *attr, size_t index, const char *value)
141 if (index < attr->n_values)
143 /* Replace existing value. */
144 free (attr->values[index]);
145 attr->values[index] = xstrdup (value);
150 while (index > attr->n_values)
151 attribute_add_value (attr, "");
152 attribute_add_value (attr, value);
157 /* Deletes the value with the given INDEX from ATTR. Any values
158 with higher-numbered indexes are shifted down into the gap
161 If INDEX is greater than the maximum index, this has no effect.*/
163 attribute_del_value (struct attribute *attr, size_t index)
165 if (index < attr->n_values)
167 free (attr->values[index]);
168 remove_element (attr->values, attr->n_values, sizeof *attr->values,
174 /* Initializes SET as a new, initially empty attibute set. */
176 attrset_init (struct attrset *set)
178 hmap_init (&set->map);
181 /* Initializes NEW_SET as a new attribute set whose contents are
182 initially the same as that of OLD_SET. */
184 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
186 struct attribute *old_attr;
188 attrset_init (new_set);
189 HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
191 struct attribute *new_attr = attribute_clone (old_attr);
192 hmap_insert (&new_set->map, &new_attr->node,
193 hmap_node_hash (&old_attr->node));
197 /* Frees the storage associated with SET, if SET is nonnull.
198 (Does not free SET itself.) */
200 attrset_destroy (struct attrset *set)
204 struct attribute *attr, *next;
206 HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
207 attribute_destroy (attr);
208 hmap_destroy (&set->map);
212 /* Returns the number of attributes in SET. */
214 attrset_count (const struct attrset *set)
216 return hmap_count (&set->map);
219 /* Returns the attribute in SET whose name matches NAME
220 case-insensitively, or a null pointer if SET does not contain
221 an attribute with that name. */
223 attrset_lookup (struct attrset *set, const char *name)
225 struct attribute *attr;
226 HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
227 utf8_hash_case_string (name, 0), &set->map)
228 if (!utf8_strcasecmp (attribute_get_name (attr), name))
233 /* Adds ATTR to SET, which must not already contain an attribute
234 with the same name (matched case insensitively). Ownership of
235 ATTR is transferred to SET. */
237 attrset_add (struct attrset *set, struct attribute *attr)
239 const char *name = attribute_get_name (attr);
240 assert (attrset_lookup (set, name) == NULL);
241 hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
244 /* Deletes any attribute from SET that matches NAME
245 (case-insensitively). */
247 attrset_delete (struct attrset *set, const char *name)
249 struct attribute *attr = attrset_lookup (set, name);
252 hmap_delete (&set->map, &attr->node);
253 attribute_destroy (attr);
257 /* Deletes all attributes from SET. */
259 attrset_clear (struct attrset *set)
261 attrset_destroy (set);
265 static struct attribute *iterator_data (struct attrset_iterator *iterator)
267 return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
270 /* Returns the first attribute in SET and initializes ITERATOR.
271 If SET is empty, returns a null pointer.
273 The caller must not destroy the returned attribute, but it may
274 add or remove values.
276 Attributes are visited in no particular order. Calling
277 attrset_add() during iteration can cause some attributes to
278 be visited more than once and others not at all. */
280 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
282 iterator->node = hmap_first (&set->map);
283 return iterator_data (iterator);
286 /* Returns the next attribute in SET and advances ITERATOR, which
287 should have been initialized by calling attrset_first(). If
288 all the attributes in SET have already been visited, returns a
291 The caller must not destroy the returned attribute, but it may
292 add or remove values.
294 Attributes are visited in no particular order. Calling
295 attrset_add() during iteration can cause some attributes to
296 be visited more than once and others not at all. */
298 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
300 iterator->node = hmap_next (&set->map, iterator->node);
301 return iterator_data (iterator);
305 compare_attribute_by_name (const void *a_, const void *b_)
307 const struct attribute *const *a = a_;
308 const struct attribute *const *b = b_;
310 return strcmp ((*a)->name, (*b)->name);
313 /* Allocates and returns an array of pointers to attributes
314 that is sorted by attribute name. The array has
315 'attrset_count (SET)' elements. The caller is responsible for
316 freeing the array. */
318 attrset_sorted (const struct attrset *set)
320 if (set != NULL && attrset_count (set) > 0)
322 struct attribute **attrs;
323 struct attribute *attr;
326 attrs = xmalloc (attrset_count (set) * sizeof *attrs);
328 HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
330 assert (i == attrset_count (set));
331 qsort (attrs, attrset_count (set), sizeof *attrs,
332 compare_attribute_by_name);