/* PSPP - a program for statistical analysis. Copyright (C) 1997-9, 2000, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "data/value.h" #include "data/val-type.h" #include "data/variable.h" #include "libpspp/hash-functions.h" #include "libpspp/pool.h" #include "libpspp/str.h" #include "gl/unistr.h" #include "gl/minmax.h" #include "gl/xalloc.h" /* Copies the contents of string value SRC with width SRC_WIDTH to string value DST with width DST_WIDTH. If SRC_WIDTH is greater than DST_WIDTH, then only the first DST_WIDTH bytes are copied; if DST_WIDTH is greater than SRC_WIDTH, then DST is padded on the right with PAD bytes. SRC and DST must be string values; that is, SRC_WIDTH and DST_WIDTH must both be positive. */ void value_copy_rpad (union value *dst, int dst_width, const union value *src, int src_width, char pad) { u8_buf_copy_rpad (dst->s, dst_width, src->s, src_width, pad); } /* Copies the contents of null-terminated string SRC to string value DST with width DST_WIDTH. If SRC is more than DST_WIDTH bytes long, then only the first DST_WIDTH bytes are copied; if DST_WIDTH is greater than the length of SRC, then DST is padded on the right with PAD bytes. DST must be a string value; that is, DST_WIDTH must be positive. */ void value_copy_str_rpad (union value *dst, int dst_width, const uint8_t *src, char pad) { value_copy_buf_rpad (dst, dst_width, src, u8_strlen (src), pad); } /* Copies the SRC_LEN bytes at SRC to string value DST with width DST_WIDTH. If SRC_LEN is greater than DST_WIDTH, then only the first DST_WIDTH bytes are copied; if DST_WIDTH is greater than SRC_LEN, then DST is padded on the right with PAD bytes. DST must be a string value; that is, DST_WIDTH must be positive. */ void value_copy_buf_rpad (union value *dst, int dst_width, const uint8_t *src, size_t src_len, char pad) { u8_buf_copy_rpad (dst->s, dst_width, src, src_len, pad); } /* Sets V to the system-missing value for data of the given WIDTH. */ void value_set_missing (union value *v, int width) { if (width != -1) { if (width == 0) v->f = SYSMIS; else memset (v->s, ' ', width); } } /* Compares A and B, which both have the given WIDTH, and returns a strcmp()-type result. */ int value_compare_3way (const union value *a, const union value *b, int width) { return (width == -1 ? 0 : width == 0 ? (a->f < b->f ? -1 : a->f> b->f) : memcmp (a->s, b->s, width)); } /* Returns true if A and B, which must both have the given WIDTH, have equal contents, false if their contents differ. */ bool value_equal (const union value *a, const union value *b, int width) { return (width == -1 ? true : width == 0 ? a->f == b->f : !memcmp (a->s, b->s, width)); } /* Returns a hash of the data in VALUE, which must have the given WIDTH, folding BASIS into the hash value calculation. */ unsigned int value_hash (const union value *value, int width, unsigned int basis) { return (width == -1 ? basis : width == 0 ? hash_double (value->f, basis) : hash_bytes (value->s, width, basis)); } /* Tests whether VALUE may be resized from OLD_WIDTH to NEW_WIDTH, using the following rules that match those for resizing missing values and value labels. First, OLD_WIDTH and NEW_WIDTH must be both numeric or both string. Second, if NEW_WIDTH is less than OLD_WIDTH, then the bytes that would be trimmed off the right end of VALUE must be all spaces. */ bool value_is_resizable (const union value *value, int old_width, int new_width) { if (old_width == new_width) return true; else if (val_type_from_width (old_width) != val_type_from_width (new_width)) return false; else { const uint8_t *str = value->s; int i; for (i = new_width; i < old_width; i++) if (str[i] != ' ') return false; return true; } } /* Resizes VALUE from OLD_WIDTH to NEW_WIDTH. The arguments must satisfy the rules specified above for value_is_resizable. */ void value_resize (union value *value, int old_width, int new_width) { assert (value_is_resizable (value, old_width, new_width)); if (new_width != old_width && new_width> 0) { union value tmp; value_init (&tmp, new_width); value_copy_rpad (&tmp, new_width, value, old_width, ' '); value_destroy (value, old_width); *value = tmp; } } /* Returns true if VALUE, with the given WIDTH, is all spaces, false otherwise. Returns false if VALUE is numeric. */ bool value_is_spaces (const union value *value, int width) { int i; for (i = 0; i < width; i++) if (value->s[i] != ' ') return false; return true; } /* Returns true if resizing a value from OLD_WIDTH to NEW_WIDTH actually changes anything, false otherwise. If false is returned, calls to value_resize() with the specified parameters may be omitted without any ill effects. This is generally useful only if many values can skip being resized from OLD_WIDTH to NEW_WIDTH. Otherwise you might as well just call value_resize directly. */ bool value_needs_resize (int old_width, int new_width) { assert (val_type_from_width (old_width) == val_type_from_width (new_width)); return old_width != new_width; } /* Same as value_init, except that memory for VALUE (if necessary) is allocated from POOL and will be freed automatically when POOL is destroyed. VALUE must not be freed manually by calling value_destroy. If it needs to be resized, it must be done using value_resize_pool instead of value_resize. */ void value_init_pool (struct pool *pool, union value *value, int width) { if (width> 0) value->s = pool_alloc_unaligned (pool, width); } /* Same as value_clone(), except that memory for VALUE (if necessary) is allocated from POOL and will be freed automatically when POOL is destroyed. VALUE must not be freed manually by calling value_destroy(). If it needs to be resized, it must be done using value_resize_pool() instead of value_resize(). */ void value_clone_pool (struct pool *pool, union value *value, const union value *src, int width) { if (width> 0) value->s = pool_clone_unaligned (pool, src->s, width); else value->f = src->f; } /* Same as value_resize, except that VALUE must have been allocated from POOL using value_init_pool. This function causes some memory in POOL to be wasted in some cases (until the pool is freed), so it should only be done if this is acceptable. */ void value_resize_pool (struct pool *pool, union value *value, int old_width, int new_width) { assert (value_is_resizable (value, old_width, new_width)); if (new_width> old_width) { uint8_t *new_string = pool_alloc_unaligned (pool, new_width); memcpy (new_string, value->s, old_width); value->s = new_string; memset (value->s + old_width, ' ', new_width - old_width); } }

AltStyle によって変換されたページ (->オリジナル) /