gui: Fix behavior of print preview in psppire-output-window.
[pspp] / src / data / attributes.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009, 2011 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
27 #include "gl/xalloc.h"
28
29 /* A custom attribute of the sort maintained by the DATAFILE
30    ATTRIBUTE and VARIABLE ATTRIBUTE commands.
31
32    Attributes have a name (the rules for which are the same as
33    those for PSPP variable names) and one or more values, each of
34    which is a string.  An attribute may be part of one attribute
35    set. */
36 struct attribute
37   {
38     struct hmap_node node;      /* Used by attrset. */
39     char *name;                 /* Name. */
40     char **values;              /* Each value. */
41     size_t n_values;            /* Number of values. */
42     size_t allocated_values;    /* Amount of allocated space for values. */
43   };
44
45 /* Creates and returns a new attribute with the given NAME.  The
46    attribute initially has no values.  (Attributes with no values
47    cannot be saved to system files, so at least one value should
48    be added before the attribute is made available to the PSPP
49    user.) */
50 struct attribute *
51 attribute_create (const char *name)
52 {
53   struct attribute *attr = xmalloc (sizeof *attr);
54   attr->name = xstrdup (name);
55   attr->values = NULL;
56   attr->n_values = 0;
57   attr->allocated_values = 0;
58   return attr;
59 }
60
61 /* Creates and returns a new attribute with the same name and
62    values as ORIG. */
63 struct attribute *
64 attribute_clone (const struct attribute *orig)
65 {
66   struct attribute *attr;
67   size_t i;
68
69   attr = attribute_create (orig->name);
70   for (i = 0; i < orig->n_values; i++)
71     attribute_add_value (attr, orig->values[i]);
72   return attr;
73 }
74
75 /* Destroys ATTR and frees all associated memory.
76
77    This function must not be called if ATTR is part of an
78    attribute set.  Use attrset_delete() instead. */
79 void
80 attribute_destroy (struct attribute *attr)
81 {
82   if (attr != NULL)
83     {
84       size_t i;
85
86       for (i = 0; i < attr->n_values; i++)
87         free (attr->values[i]);
88       free (attr->values);
89       free (attr->name);
90       free (attr);
91     }
92 }
93
94 /* Returns the name of ATTR.  The caller must not free or modify
95    the returned string. */
96 const char *
97 attribute_get_name (const struct attribute *attr)
98 {
99   return attr->name;
100 }
101
102 /* Returns ATTR's value with the given INDEX, or a null pointer
103    if INDEX is greater than or equal to the number of values in
104    ATTR (that is, attributes are numbered starting from 0).  The
105    caller must not free or modify the returned string.  */
106 const char *
107 attribute_get_value (const struct attribute *attr, size_t index)
108 {
109   return index < attr->n_values ? attr->values[index] : NULL;
110 }
111
112 /* Returns ATTR's number of values. */
113 size_t
114 attribute_get_n_values (const struct attribute *attrs)
115 {
116   return attrs->n_values;
117 }
118
119 /* Adds a copy of VALUE as a new value to ATTR.  The caller
120    retains ownership of VALUE. */
121 void
122 attribute_add_value (struct attribute *attr, const char *value)
123 {
124   if (attr->n_values >= attr->allocated_values)
125     attr->values = x2nrealloc (attr->values, &attr->allocated_values,
126                                sizeof *attr->values);
127   attr->values[attr->n_values++] = xstrdup (value);
128 }
129
130 /* Adds or replaces the value with the given INDEX in ATTR by a
131    copy of VALUE.  The caller retains ownership of VALUE.
132
133    If INDEX is an existing value index, that value is replaced.
134    If no value index numbered INDEX exists in ATTR, then it is
135    added, and any values intermediate between the last maximum
136    index and INDEX are set to the empty string. */
137 void
138 attribute_set_value (struct attribute *attr, size_t index, const char *value)
139 {
140   if (index < attr->n_values)
141     {
142       /* Replace existing value. */
143       free (attr->values[index]);
144       attr->values[index] = xstrdup (value);
145     }
146   else
147     {
148       /* Add new value. */
149       while (index > attr->n_values)
150         attribute_add_value (attr, "");
151       attribute_add_value (attr, value);
152     }
153
154 }
155
156 /* Deletes the value with the given INDEX from ATTR.  Any values
157    with higher-numbered indexes are shifted down into the gap
158    that this creates.
159
160    If INDEX is greater than the maximum index, this has no effect.*/
161 void
162 attribute_del_value (struct attribute *attr, size_t index)
163 {
164   if (index < attr->n_values)
165     {
166       free (attr->values[index]);
167       remove_element (attr->values, attr->n_values, sizeof *attr->values,
168                       index);
169       attr->n_values--;
170     }
171 }
172 \f
173 /* Initializes SET as a new, initially empty attibute set. */
174 void
175 attrset_init (struct attrset *set)
176 {
177   hmap_init (&set->map);
178 }
179
180 /* Initializes NEW_SET as a new attribute set whose contents are
181    initially the same as that of OLD_SET. */
182 void
183 attrset_clone (struct attrset *new_set, const struct attrset *old_set)
184 {
185   struct attribute *old_attr;
186
187   attrset_init (new_set);
188   HMAP_FOR_EACH (old_attr, struct attribute, node, &old_set->map)
189     {
190       struct attribute *new_attr = attribute_clone (old_attr);
191       hmap_insert (&new_set->map, &new_attr->node,
192                    hmap_node_hash (&old_attr->node));
193     }
194 }
195
196 /* Frees the storage associated with SET, if SET is nonnull.
197    (Does not free SET itself.) */
198 void
199 attrset_destroy (struct attrset *set)
200 {
201   if (set != NULL)
202     {
203       struct attribute *attr, *next;
204
205       HMAP_FOR_EACH_SAFE (attr, next, struct attribute, node, &set->map)
206         attribute_destroy (attr);
207       hmap_destroy (&set->map);
208     }
209 }
210
211 /* Returns the number of attributes in SET. */
212 size_t
213 attrset_count (const struct attrset *set)
214 {
215   return hmap_count (&set->map);
216 }
217
218 /* Returns the attribute in SET whose name matches NAME
219    case-insensitively, or a null pointer if SET does not contain
220    an attribute with that name. */
221 struct attribute *
222 attrset_lookup (struct attrset *set, const char *name)
223 {
224   struct attribute *attr;
225   HMAP_FOR_EACH_WITH_HASH (attr, struct attribute, node,
226                            hash_case_string (name, 0), &set->map)
227     if (!strcasecmp (attribute_get_name (attr), name))
228       break;
229   return attr;
230 }
231
232 /* Adds ATTR to SET, which must not already contain an attribute
233    with the same name (matched case insensitively).  Ownership of
234    ATTR is transferred to SET. */
235 void
236 attrset_add (struct attrset *set, struct attribute *attr)
237 {
238   const char *name = attribute_get_name (attr);
239   assert (attrset_lookup (set, name) == NULL);
240   hmap_insert (&set->map, &attr->node, hash_case_string (name, 0));
241 }
242
243 /* Deletes any attribute from SET that matches NAME
244    (case-insensitively). */
245 void
246 attrset_delete (struct attrset *set, const char *name)
247 {
248   struct attribute *attr = attrset_lookup (set, name);
249   if (attr != NULL)
250     {
251       hmap_delete (&set->map, &attr->node);
252       attribute_destroy (attr);
253     }
254 }
255
256 /* Deletes all attributes from SET. */
257 void
258 attrset_clear (struct attrset *set)
259 {
260   attrset_destroy (set);
261   attrset_init (set);
262 }
263
264 static struct attribute *iterator_data (struct attrset_iterator *iterator)
265 {
266   return HMAP_NULLABLE_DATA (iterator->node, struct attribute, node);
267 }
268
269 /* Returns the first attribute in SET and initializes ITERATOR.
270    If SET is empty, returns a null pointer.
271
272    The caller must not destroy the returned attribute, but it may
273    add or remove values.
274
275    Attributes are visited in no particular order.  Calling
276    attrset_add() during iteration can cause some attributes to
277    be visited more than once and others not at all. */
278 struct attribute *
279 attrset_first (const struct attrset *set, struct attrset_iterator *iterator)
280 {
281   iterator->node = hmap_first (&set->map);
282   return iterator_data (iterator);
283 }
284
285 /* Returns the next attribute in SET and advances ITERATOR, which
286    should have been initialized by calling attrset_first().  If
287    all the attributes in SET have already been visited, returns a
288    null pointer.
289
290    The caller must not destroy the returned attribute, but it may
291    add or remove values.
292
293    Attributes are visited in no particular order.  Calling
294    attrset_add() during iteration can cause some attributes to
295    be visited more than once and others not at all. */
296 struct attribute *
297 attrset_next (const struct attrset *set, struct attrset_iterator *iterator)
298 {
299   iterator->node = hmap_next (&set->map, iterator->node);
300   return iterator_data (iterator);
301 }