1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2011, 2012, 2016 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/compiler.h"
26 #include "libpspp/hash-functions.h"
27 #include "libpspp/i18n.h"
29 #include "gl/xalloc.h"
31 /* A custom attribute of the sort maintained by the DATAFILE
32 ATTRIBUTE and VARIABLE ATTRIBUTE commands.
34 Attributes have a name (the rules for which are the same as
35 those for PSPP variable names) and one or more values, each of
36 which is a string. An attribute may be part of one attribute
40 struct hmap_node node; /* Used by attrset. */
41 char *name; /* Name. */
42 char **values; /* Each value. */
43 size_t n_values; /* Number of values. */
44 size_t allocated_values; /* Amount of allocated space for values. */
47 /* Creates and returns a new attribute with the given NAME. The
48 attribute initially has no values. (Attributes with no values
49 cannot be saved to system files, so at least one value should
50 be added before the attribute is made available to the PSPP
53 attribute_create (const char *name)
55 struct attribute *attr = xmalloc (sizeof *attr);
56 attr->name = xstrdup (name);
59 attr->allocated_values = 0;
63 /* Creates and returns a new attribute with the same name and
66 attribute_clone (const struct attribute *orig)
68 struct attribute *attr;
71 attr = attribute_create (orig->name);
72 for (i = 0; i < orig->n_values; i++)
73 attribute_add_value (attr, orig->values[i]);
77 /* Destroys ATTR and frees all associated memory.
79 This function must not be called if ATTR is part of an
80 attribute set. Use attrset_delete() instead. */
82 attribute_destroy (struct attribute *attr)
88 for (i = 0; i < attr->n_values; i++)
89 free (attr->values[i]);
96 /* Returns the name of ATTR. The caller must not free or modify
97 the returned string. */
99 attribute_get_name (const struct attribute *attr)
104 /* Returns ATTR's value with the given INDEX, or a null pointer
105 if INDEX is greater than or equal to the number of values in
106 ATTR (that is, attributes are numbered starting from 0). The
107 caller must not free or modify the returned string. */
109 attribute_get_value (const struct attribute *attr, size_t index)
111 return index < attr->n_values ? attr->values[index] : NULL;
114 /* Returns ATTR's number of values. */
116 attribute_get_n_values (const struct attribute *attrs)
118 return attrs->n_values;
121 /* Adds a copy of VALUE as a new value to ATTR. The caller
122 retains ownership of VALUE. */
124 attribute_add_value (struct attribute *attr, const char *value)
126 if (attr->n_values >= attr->allocated_values)
127 attr->values = x2nrealloc (attr->values, &attr->allocated_values,
128 sizeof *attr->values);
129 attr->values[attr->n_values++] = xstrdup (value);
132 /* Adds or replaces the value with the given INDEX in ATTR by a
133 copy of VALUE. The caller retains ownership of VALUE.
135 If INDEX is an existing value index, that value is replaced.
136 If no value index numbered INDEX exists in ATTR, then it is
137 added, and any values intermediate between the last maximum
138 index and INDEX are set to the empty string. */
140 attribute_set_value (struct attribute *attr, size_t index, const char *value)
142 if (index < attr->n_values)
144 /* Replace existing value. */
145 free (attr->values[index]);
146 attr->values[index] = xstrdup (value);
151 while (index > attr->n_values)
152 attribute_add_value (attr, "");
153 attribute_add_value (attr, value);
158 /* Deletes the value with the given INDEX from ATTR. Any values
159 with higher-numbered indexes are shifted down into the gap
162 If INDEX is greater than the maximum index, this has no effect.*/
164 attribute_del_value (struct attribute *attr, size_t index)
166 if (index < attr->n_values)
168 free (attr->values[index]);
169 remove_element (attr->values, attr->n_values, sizeof *attr->values,
175 /* Initializes SET as a new, initially empty attibute set. */
177 attrset_init (struct attrset *set)
179 hmap_init (&set->map);
182 /* Initializes NEW_SET as a new attribute set whose contents are
183 initially the same as that of OLD_SET. */
185 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
187 struct attribute *old_attr;
189 attrset_init (new_set);
190 HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
192 struct attribute *new_attr = attribute_clone (old_attr);
193 hmap_insert (&new_set->map, &new_attr->node,
194 hmap_node_hash (&old_attr->node));
198 /* Frees the storage associated with SET, if SET is nonnull.
199 (Does not free SET itself.) */
201 attrset_destroy (struct attrset *set)
205 struct attribute *attr, *next;
207 HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
208 attribute_destroy (attr);
209 hmap_destroy (&set->map);
213 /* Returns the number of attributes in SET. */
215 attrset_count (const struct attrset *set)
217 return hmap_count (&set->map);
220 /* Returns the attribute in SET whose name matches NAME
221 case-insensitively, or a null pointer if SET does not contain
222 an attribute with that name. */
224 attrset_lookup (const struct attrset *set, const char *name)
226 const struct attribute *attr;
227 HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
228 utf8_hash_case_string (name, 0), &set->map)
229 if (!utf8_strcasecmp (attribute_get_name (attr), name))
231 return CONST_CAST (struct attribute *, attr);
234 /* Adds ATTR to SET. Succeeds and returns true if SET does not already contain
235 an attribute with the same name (matched case insensitively); otherwise
236 fails and returns false. On success only, ownership of ATTR is transferred
239 attrset_try_add (struct attrset *set, struct attribute *attr)
241 const char *name = attribute_get_name (attr);
242 if (attrset_lookup (set, name))
244 hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
248 /* Adds ATTR to SET, which must not already contain an attribute
249 with the same name (matched case insensitively). Ownership of
250 ATTR is transferred to SET. */
252 attrset_add (struct attrset *set, struct attribute *attr)
254 bool ok UNUSED = attrset_try_add (set, attr);
258 /* Deletes any attribute from SET that matches NAME
259 (case-insensitively). */
261 attrset_delete (struct attrset *set, const char *name)
263 struct attribute *attr = attrset_lookup (set, name);
266 hmap_delete (&set->map, &attr->node);
267 attribute_destroy (attr);
271 /* Deletes all attributes from SET. */
273 attrset_clear (struct attrset *set)
275 attrset_destroy (set);
279 static struct attribute *iterator_data (struct attrset_iterator *iterator)
281 return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
284 /* Returns the first attribute in SET and initializes ITERATOR.
285 If SET is empty, returns a null pointer.
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_first (const struct attrset *set, struct attrset_iterator *iterator)
296 iterator->node = hmap_first (&set->map);
297 return iterator_data (iterator);
300 /* Returns the next attribute in SET and advances ITERATOR, which
301 should have been initialized by calling attrset_first(). If
302 all the attributes in SET have already been visited, returns a
305 The caller must not destroy the returned attribute, but it may
306 add or remove values.
308 Attributes are visited in no particular order. Calling
309 attrset_add() during iteration can cause some attributes to
310 be visited more than once and others not at all. */
312 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
314 iterator->node = hmap_next (&set->map, iterator->node);
315 return iterator_data (iterator);
319 compare_attribute_by_name (const void *a_, const void *b_)
321 const struct attribute *const *a = a_;
322 const struct attribute *const *b = b_;
324 return strcmp ((*a)->name, (*b)->name);
327 /* Allocates and returns an array of pointers to attributes
328 that is sorted by attribute name. The array has
329 'attrset_count (SET)' elements. The caller is responsible for
330 freeing the array. */
332 attrset_sorted (const struct attrset *set)
334 if (set != NULL && attrset_count (set) > 0)
336 struct attribute **attrs;
337 struct attribute *attr;
340 attrs = xmalloc (attrset_count (set) * sizeof *attrs);
342 HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
344 assert (i == attrset_count (set));
345 qsort (attrs, attrset_count (set), sizeof *attrs,
346 compare_attribute_by_name);