1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 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"
28 #include "libpspp/pxd.h"
30 #include "gl/xalloc.h"
32 /* A custom attribute of the sort maintained by the DATAFILE
33 ATTRIBUTE and VARIABLE ATTRIBUTE commands.
35 Attributes have a name (the rules for which are the same as
36 those for PSPP variable names) and one or more values, each of
37 which is a string. An attribute may be part of one attribute
41 struct attrset *set; /* Containing set, if any. */
42 struct hmap_node node; /* Used by attrset. */
44 char *name; /* Name. */
45 char **values; /* Each value. */
46 size_t n_values; /* Number of values. */
47 size_t allocated_values; /* Amount of allocated space for values. */
50 static void attrset_uncache__ (struct attrset *);
52 /* Creates and returns a new attribute with the given NAME. The
53 attribute initially has no values. (Attributes with no values
54 cannot be saved to system files, so at least one value should
55 be added before the attribute is made available to the PSPP
58 attribute_create (const char *name)
60 struct attribute *attr = xmalloc (sizeof *attr);
62 attr->name = xstrdup (name);
65 attr->allocated_values = 0;
69 /* Creates and returns a new attribute with the same name and
72 attribute_clone (const struct attribute *orig)
74 struct attribute *attr;
77 attr = attribute_create (orig->name);
78 for (i = 0; i < orig->n_values; i++)
79 attribute_add_value (attr, orig->values[i]);
83 /* Destroys ATTR and frees all associated memory.
85 This function must not be called if ATTR is part of an
86 attribute set. Use attrset_delete() instead. */
88 attribute_destroy (struct attribute *attr)
94 assert (attr->set == NULL);
96 for (i = 0; i < attr->n_values; i++)
97 free (attr->values[i]);
104 /* Returns the name of ATTR. The caller must not free or modify
105 the returned string. */
107 attribute_get_name (const struct attribute *attr)
112 /* Returns ATTR's value with the given INDEX, or a null pointer
113 if INDEX is greater than or equal to the number of values in
114 ATTR (that is, attributes are numbered starting from 0). The
115 caller must not free or modify the returned string. */
117 attribute_get_value (const struct attribute *attr, size_t index)
119 return index < attr->n_values ? attr->values[index] : NULL;
122 /* Returns ATTR's number of values. */
124 attribute_get_n_values (const struct attribute *attrs)
126 return attrs->n_values;
129 /* Adds a copy of VALUE as a new value to ATTR. The caller
130 retains ownership of VALUE. */
132 attribute_add_value (struct attribute *attr, const char *value)
134 attrset_uncache__ (attr->set);
136 if (attr->n_values >= attr->allocated_values)
137 attr->values = x2nrealloc (attr->values, &attr->allocated_values,
138 sizeof *attr->values);
139 attr->values[attr->n_values++] = xstrdup (value);
142 /* Adds or replaces the value with the given INDEX in ATTR by a
143 copy of VALUE. The caller retains ownership of VALUE.
145 If INDEX is an existing value index, that value is replaced.
146 If no value index numbered INDEX exists in ATTR, then it is
147 added, and any values intermediate between the last maximum
148 index and INDEX are set to the empty string. */
150 attribute_set_value (struct attribute *attr, size_t index, const char *value)
152 attrset_uncache__ (attr->set);
154 if (index < attr->n_values)
156 /* Replace existing value. */
157 free (attr->values[index]);
158 attr->values[index] = xstrdup (value);
163 while (index > attr->n_values)
164 attribute_add_value (attr, "");
165 attribute_add_value (attr, value);
170 /* Deletes the value with the given INDEX from ATTR. Any values
171 with higher-numbered indexes are shifted down into the gap
174 If INDEX is greater than the maximum index, this has no effect.*/
176 attribute_del_value (struct attribute *attr, size_t index)
178 attrset_uncache__ (attr->set);
180 if (index < attr->n_values)
182 free (attr->values[index]);
183 remove_element (attr->values, attr->n_values, sizeof *attr->values,
190 attribute_save (const struct attribute *attr, struct pxd *pxd)
192 struct pxd_builder b;
195 pxd_builder_init (&b, pxd);
197 pxd_builder_put_string (&b, attr->name);
198 pxd_builder_put_size_t (&b, attr->n_values);
199 for (i = 0; i < attr->n_values; i++)
200 pxd_builder_put_string (&b, attr->values[i]);
202 return pxd_builder_commit (&b);
206 attribute_load (struct pxd_object *object, const struct pxd *pxd)
208 struct attribute *attr;
213 pxd_parser_init (&p, object, pxd);
215 name = pxd_parser_get_string (&p);
216 attr = attribute_create (name);
219 n = pxd_parser_get_size_t (&p);
220 for (i = 0; i < n; i++)
222 char *value = pxd_parser_get_string (&p);
223 attribute_add_value (attr, value);
227 pxd_parser_destroy (&p);
232 /* Initializes SET as a new, initially empty attibute set. */
234 attrset_init (struct attrset *set)
236 hmap_init (&set->map);
239 /* Initializes NEW_SET as a new attribute set whose contents are
240 initially the same as that of OLD_SET. */
242 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
244 struct attribute *old_attr;
246 attrset_init (new_set);
247 HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
249 struct attribute *new_attr = attribute_clone (old_attr);
250 hmap_insert (&new_set->map, &new_attr->node,
251 hmap_node_hash (&old_attr->node));
255 /* Frees the storage associated with SET, if SET is nonnull.
256 (Does not free SET itself.) */
258 attrset_destroy (struct attrset *set)
262 struct attribute *attr, *next;
264 attrset_uncache__ (set);
266 HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
269 attribute_destroy (attr);
271 hmap_destroy (&set->map);
275 /* Returns the number of attributes in SET. */
277 attrset_count (const struct attrset *set)
279 return hmap_count (&set->map);
282 /* Returns the attribute in SET whose name matches NAME
283 case-insensitively, or a null pointer if SET does not contain
284 an attribute with that name. */
286 attrset_lookup (struct attrset *set, const char *name)
288 struct attribute *attr;
289 HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
290 utf8_hash_case_string (name, 0), &set->map)
291 if (!utf8_strcasecmp (attribute_get_name (attr), name))
296 /* Adds ATTR to SET, which must not already contain an attribute
297 with the same name (matched case insensitively). Ownership of
298 ATTR is transferred to SET. */
300 attrset_add (struct attrset *set, struct attribute *attr)
302 const char *name = attribute_get_name (attr);
304 assert (attrset_lookup (set, name) == NULL);
305 assert (attr->set == NULL);
307 attrset_uncache__ (set);
310 hmap_insert (&set->map, &attr->node, utf8_hash_case_string (name, 0));
313 /* Deletes any attribute from SET that matches NAME
314 (case-insensitively). */
316 attrset_delete (struct attrset *set, const char *name)
318 struct attribute *attr = attrset_lookup (set, name);
321 attrset_uncache__ (set);
322 hmap_delete (&set->map, &attr->node);
324 attribute_destroy (attr);
328 /* Deletes all attributes from SET. */
330 attrset_clear (struct attrset *set)
332 if (!hmap_is_empty (&set->map))
334 attrset_destroy (set);
340 attrset_save (const struct attrset *set, struct pxd *pxd)
342 struct attribute *attr;
343 struct pxd_builder b;
345 pxd_builder_init (&b, pxd);
347 HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
348 pxd_builder_put_link (&b, attribute_save (attr, pxd));
350 return pxd_builder_commit (&b);
354 attrset_load (struct attrset *set,
355 struct pxd_object *object, const struct pxd *pxd)
360 pxd_parser_init (&p, object, pxd);
363 for (i = 0; i < pxd_object_get_n_links (object); i++)
365 struct pxd_object *attr_obj = pxd_object_get_link (object, i, pxd);
366 struct attribute *attr = attribute_load (attr_obj, pxd);
367 attrset_add (set, attr);
370 pxd_parser_destroy (&p);
373 static struct attribute *iterator_data (struct attrset_iterator *iterator)
375 return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
378 /* Returns the first attribute in SET and initializes ITERATOR.
379 If SET is empty, returns a null pointer.
381 The caller must not destroy the returned attribute, but it may
382 add or remove values.
384 Attributes are visited in no particular order. Calling
385 attrset_add() during iteration can cause some attributes to
386 be visited more than once and others not at all. */
388 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
390 iterator->node = hmap_first (&set->map);
391 return iterator_data (iterator);
394 /* Returns the next attribute in SET and advances ITERATOR, which
395 should have been initialized by calling attrset_first(). If
396 all the attributes in SET have already been visited, returns a
399 The caller must not destroy the returned attribute, but it may
400 add or remove values.
402 Attributes are visited in no particular order. Calling
403 attrset_add() during iteration can cause some attributes to
404 be visited more than once and others not at all. */
406 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
408 iterator->node = hmap_next (&set->map, iterator->node);
409 return iterator_data (iterator);
413 compare_attribute_by_name (const void *a_, const void *b_)
415 const struct attribute *const *a = a_;
416 const struct attribute *const *b = b_;
418 return strcmp ((*a)->name, (*b)->name);
421 /* Allocates and returns an array of pointers to attributes
422 that is sorted by attribute name. The array has
423 'attrset_count (SET)' elements. The caller is responsible for
424 freeing the array. */
426 attrset_sorted (const struct attrset *set)
428 if (set != NULL && attrset_count (set) > 0)
430 struct attribute **attrs;
431 struct attribute *attr;
434 attrs = xmalloc (attrset_count (set) * sizeof *attrs);
436 HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
438 assert (i == attrset_count (set));
439 qsort (attrs, attrset_count (set), sizeof *attrs,
440 compare_attribute_by_name);
448 attrset_uncache__ (struct attrset *set UNUSED)