1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2009, 2010, 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/value.h"
21 #include "data/val-type.h"
22 #include "data/variable.h"
23 #include "libpspp/hash-functions.h"
24 #include "libpspp/pool.h"
25 #include "libpspp/str.h"
26 #include "gl/unistr.h"
28 #include "gl/minmax.h"
29 #include "gl/xalloc.h"
31 /* Copies the contents of string value SRC with width SRC_WIDTH
32 to string value DST with width DST_WIDTH. If SRC_WIDTH is
33 greater than DST_WIDTH, then only the first DST_WIDTH bytes
34 are copied; if DST_WIDTH is greater than SRC_WIDTH, then DST
35 is padded on the right with PAD bytes.
37 SRC and DST must be string values; that is, SRC_WIDTH and
38 DST_WIDTH must both be positive. */
40 value_copy_rpad (union value *dst, int dst_width,
41 const union value *src, int src_width,
44 u8_buf_copy_rpad (dst->s, dst_width, src->s, src_width, pad);
47 /* Copies the contents of null-terminated string SRC to string
48 value DST with width DST_WIDTH. If SRC is more than DST_WIDTH
49 bytes long, then only the first DST_WIDTH bytes are copied; if
50 DST_WIDTH is greater than the length of SRC, then DST is
51 padded on the right with PAD bytes.
53 DST must be a string value; that is, DST_WIDTH must be
56 value_copy_str_rpad (union value *dst, int dst_width, const uint8_t *src,
59 value_copy_buf_rpad (dst, dst_width, src, u8_strlen (src), pad);
62 /* Copies the SRC_LEN bytes at SRC to string value DST with width
63 DST_WIDTH. If SRC_LEN is greater than DST_WIDTH, then only
64 the first DST_WIDTH bytes are copied; if DST_WIDTH is greater
65 than SRC_LEN, then DST is padded on the right with PAD bytes.
67 DST must be a string value; that is, DST_WIDTH must be
70 value_copy_buf_rpad (union value *dst, int dst_width,
71 const uint8_t *src, size_t src_len, char pad)
73 u8_buf_copy_rpad (dst->s, dst_width, src, src_len, pad);
76 /* Sets V to the system-missing value for data of the given
79 value_set_missing (union value *v, int width)
86 memset (v->s, ' ', width);
90 /* Compares A and B, which both have the given WIDTH, and returns
91 a strcmp()-type result. */
93 value_compare_3way (const union value *a, const union value *b, int width)
95 return (width == -1 ? 0
96 : width == 0 ? (a->f < b->f ? -1 : a->f > b->f)
97 : memcmp (a->s, b->s, width));
100 /* Returns true if A and B, which must both have the given WIDTH,
101 have equal contents, false if their contents differ. */
103 value_equal (const union value *a, const union value *b, int width)
105 return (width == -1 ? true
106 : width == 0 ? a->f == b->f
107 : !memcmp (a->s, b->s, width));
110 /* Returns a hash of the data in VALUE, which must have the given
111 WIDTH, folding BASIS into the hash value calculation. */
113 value_hash (const union value *value, int width, unsigned int basis)
115 return (width == -1 ? basis
116 : width == 0 ? hash_double (value->f, basis)
117 : hash_bytes (value->s, width, basis));
120 /* Tests whether VALUE may be resized from OLD_WIDTH to
121 NEW_WIDTH, using the following rules that match those for
122 resizing missing values and value labels. First, OLD_WIDTH
123 and NEW_WIDTH must be both numeric or both string. Second, if
124 NEW_WIDTH is less than OLD_WIDTH, then the bytes that would be
125 trimmed off the right end of VALUE must be all spaces. */
127 value_is_resizable (const union value *value, int old_width, int new_width)
129 if (old_width == new_width)
131 else if (val_type_from_width (old_width) != val_type_from_width (new_width))
135 const uint8_t *str = value->s;
138 for (i = new_width; i < old_width; i++)
145 /* Resizes VALUE from OLD_WIDTH to NEW_WIDTH. The arguments must
146 satisfy the rules specified above for value_is_resizable. */
148 value_resize (union value *value, int old_width, int new_width)
150 assert (value_is_resizable (value, old_width, new_width));
151 if (new_width != old_width && new_width > 0)
154 value_init (&tmp, new_width);
155 value_copy_rpad (&tmp, new_width, value, old_width, ' ');
156 value_destroy (value, old_width);
161 /* Returns true if VALUE, with the given WIDTH, is all spaces, false otherwise.
162 Returns false if VALUE is numeric. */
164 value_is_spaces (const union value *value, int width)
168 for (i = 0; i < width; i++)
169 if (value->s[i] != ' ')
175 /* Returns true if resizing a value from OLD_WIDTH to NEW_WIDTH
176 actually changes anything, false otherwise. If false is
177 returned, calls to value_resize() with the specified
178 parameters may be omitted without any ill effects.
180 This is generally useful only if many values can skip being
181 resized from OLD_WIDTH to NEW_WIDTH. Otherwise you might as
182 well just call value_resize directly. */
184 value_needs_resize (int old_width, int new_width)
186 assert (val_type_from_width (old_width) == val_type_from_width (new_width));
188 return old_width != new_width;
191 /* Same as value_init, except that memory for VALUE (if
192 necessary) is allocated from POOL and will be freed
193 automatically when POOL is destroyed.
195 VALUE must not be freed manually by calling value_destroy. If
196 it needs to be resized, it must be done using
197 value_resize_pool instead of value_resize. */
199 value_init_pool (struct pool *pool, union value *value, int width)
202 value->s = pool_alloc_unaligned (pool, width);
205 /* Same as value_clone(), except that memory for VALUE (if necessary) is
206 allocated from POOL and will be freed automatically when POOL is destroyed.
208 VALUE must not be freed manually by calling value_destroy(). If it needs to
209 be resized, it must be done using value_resize_pool() instead of
212 value_clone_pool (struct pool *pool,
213 union value *value, const union value *src, int width)
216 value->s = pool_clone_unaligned (pool, src->s, width);
221 /* Same as value_resize, except that VALUE must have been
222 allocated from POOL using value_init_pool.
224 This function causes some memory in POOL to be wasted in some
225 cases (until the pool is freed), so it should only be done if
226 this is acceptable. */
228 value_resize_pool (struct pool *pool, union value *value,
229 int old_width, int new_width)
231 assert (value_is_resizable (value, old_width, new_width));
232 if (new_width > old_width)
234 uint8_t *new_string = pool_alloc_unaligned (pool, new_width);
235 memcpy (new_string, value->s, old_width);
236 value->s = new_string;
238 memset (value->s + old_width, ' ', new_width - old_width);