f516dc61a172f72afb792f27026a109447b5c903
[pspp] / src / data / attributes.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009, 2011, 2012, 2016 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "data/attributes.h"
20
21 #include <assert.h>
22 #include <string.h>
23
24 #include "libpspp/array.h"
25 #include "libpspp/hash-functions.h"
26 #include "libpspp/i18n.h"
27
28 #include "gl/xalloc.h"
29
30 /* A custom attribute of the sort maintained by the DATAFILE
31    ATTRIBUTE and VARIABLE ATTRIBUTE commands.
32
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
36    set. */
37 struct attribute
38   {
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. */
44   };
45
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
50    user.) */
51 struct attribute *
52 attribute_create (const char *name)
53 {
54   struct attribute *attr = xmalloc (sizeof *attr);
55   attr->name = xstrdup (name);
56   attr->values = NULL;
57   attr->n_values = 0;
58   attr->allocated_values = 0;
59   return attr;
60 }
61
62 /* Creates and returns a new attribute with the same name and
63    values as ORIG. */
64 struct attribute *
65 attribute_clone (const struct attribute *orig)
66 {
67   struct attribute *attr;
68   size_t i;
69
70   attr = attribute_create (orig->name);
71   for (i = 0; i < orig->n_values; i++)
72     attribute_add_value (attr, orig->values[i]);
73   return attr;
74 }
75
76 /* Destroys ATTR and frees all associated memory.
77
78    This function must not be called if ATTR is part of an
79    attribute set.  Use attrset_delete() instead. */
80 void
81 attribute_destroy (struct attribute *attr)
82 {
83   if (attr != NULL)
84     {
85       size_t i;
86
87       for (i = 0; i < attr->n_values; i++)
88         free (attr->values[i]);
89       free (attr->values);
90       free (attr->name);
91       free (attr);
92     }
93 }
94
95 /* Returns the name of ATTR.  The caller must not free or modify
96    the returned string. */
97 const char *
98 attribute_get_name (const struct attribute *attr)
99 {
100   return attr->name;
101 }
102
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.  */
107 const char *
108 attribute_get_value (const struct attribute *attr, size_t index)
109 {
110   return index < attr->n_values ? attr->values[index] : NULL;
111 }
112
113 /* Returns ATTR's number of values. */
114 size_t
115 attribute_get_n_values (const struct attribute *attrs)
116 {
117   return attrs->n_values;
118 }
119
120 /* Adds a copy of VALUE as a new value to ATTR.  The caller
121    retains ownership of VALUE. */
122 void
123 attribute_add_value (struct attribute *attr, const char *value)
124 {
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);
129 }
130
131 /* Adds or replaces the value with the given INDEX in ATTR by a
132    copy of VALUE.  The caller retains ownership of VALUE.
133
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. */
138 void
139 attribute_set_value (struct attribute *attr, size_t index, const char *value)
140 {
141   if (index < attr->n_values)
142     {
143       /* Replace existing value. */
144       free (attr->values[index]);
145       attr->values[index] = xstrdup (value);
146     }
147   else
148     {
149       /* Add new value. */
150       while (index > attr->n_values)
151         attribute_add_value (attr, "");
152       attribute_add_value (attr, value);
153     }
154
155 }
156
157 /* Deletes the value with the given INDEX from ATTR.  Any values
158    with higher-numbered indexes are shifted down into the gap
159    that this creates.
160
161    If INDEX is greater than the maximum index, this has no effect.*/
162 void
163 attribute_del_value (struct attribute *attr, size_t index)
164 {
165   if (index < attr->n_values)
166     {
167       free (attr->values[index]);
168       remove_element (attr->values, attr->n_values, sizeof *attr->values,
169                       index);
170       attr->n_values--;
171     }
172 }
173 \f
174 /* Initializes SET as a new, initially empty attibute set. */
175 void
176 attrset_init (struct attrset *set)
177 {
178   hmap_init (&set->map);
179 }
180
181 /* Initializes NEW_SET as a new attribute set whose contents are
182    initially the same as that of OLD_SET. */
183 void
184 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
185 {
186   struct attribute *old_attr;
187
188   attrset_init (new_set);
189   HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
190     {
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));
194     }
195 }
196
197 /* Frees the storage associated with SET, if SET is nonnull.
198    (Does not free SET itself.) */
199 void
200 attrset_destroy (struct attrset *set)
201 {
202   if (set != NULL)
203     {
204       struct attribute *attr, *next;
205
206       HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
207         attribute_destroy (attr);
208       hmap_destroy (&set->map);
209     }
210 }
211
212 /* Returns the number of attributes in SET. */
213 size_t
214 attrset_count (const struct attrset *set)
215 {
216   return hmap_count (&set->map);
217 }
218
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. */
222 struct attribute *
223 attrset_lookup (const struct attrset *set, const char *name)
224 {
225   const 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))
229       break;
230   return CONST_CAST (struct attribute *, attr);
231 }
232
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. */
236 void
237 attrset_add (struct attrset *set, struct attribute *attr)
238 {
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));
242 }
243
244 /* Deletes any attribute from SET that matches NAME
245    (case-insensitively). */
246 void
247 attrset_delete (struct attrset *set, const char *name)
248 {
249   struct attribute *attr = attrset_lookup (set, name);
250   if (attr != NULL)
251     {
252       hmap_delete (&set->map, &attr->node);
253       attribute_destroy (attr);
254     }
255 }
256
257 /* Deletes all attributes from SET. */
258 void
259 attrset_clear (struct attrset *set)
260 {
261   attrset_destroy (set);
262   attrset_init (set);
263 }
264
265 static struct attribute *iterator_data (struct attrset_iterator *iterator)
266 {
267   return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
268 }
269
270 /* Returns the first attribute in SET and initializes ITERATOR.
271    If SET is empty, returns a null pointer.
272
273    The caller must not destroy the returned attribute, but it may
274    add or remove values.
275
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. */
279 struct attribute *
280 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
281 {
282   iterator->node = hmap_first (&set->map);
283   return iterator_data (iterator);
284 }
285
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
289    null pointer.
290
291    The caller must not destroy the returned attribute, but it may
292    add or remove values.
293
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. */
297 struct attribute *
298 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
299 {
300   iterator->node = hmap_next (&set->map, iterator->node);
301   return iterator_data (iterator);
302 }
303
304 static int
305 compare_attribute_by_name (const void *a_, const void *b_)
306 {
307   const struct attribute *const *a = a_;
308   const struct attribute *const *b = b_;
309
310   return strcmp ((*a)->name, (*b)->name);
311 }
312
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. */
317 struct attribute **
318 attrset_sorted (const struct attrset *set)
319 {
320   if (set != NULL && attrset_count (set) > 0)
321     {
322       struct attribute **attrs;
323       struct attribute *attr;
324       size_t i;
325
326       attrs = xmalloc (attrset_count (set) * sizeof *attrs);
327       i = 0;
328       HMAP_FOR_EACH (attr, struct attribute, node, &set->map)
329         attrs[i++] = attr;
330       assert (i == attrset_count (set));
331       qsort (attrs, attrset_count (set), sizeof *attrs,
332              compare_attribute_by_name);
333       return attrs;
334     }
335   else
336     return NULL;
337 }