X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fvalue-labels.c;h=f54a4870fc05bf3b02ac9a2e6405cde5dbfefe62;hb=8021cf8974a46fe82af7b8952e448c0ea6858a48;hp=594518e07758611882ef428c519543a2f4af0fab;hpb=396f0111f30096a7615f4767e10cdff42c03e57d;p=pspp-builds.git diff --git a/src/data/value-labels.c b/src/data/value-labels.c index 594518e0..f54a4870 100644 --- a/src/data/value-labels.c +++ b/src/data/value-labels.c @@ -1,6 +1,5 @@ /* PSPP - computes sample statistics. Copyright (C) 1997-9, 2000 Free Software Foundation, Inc. - Written by Ben Pfaff . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -23,6 +22,9 @@ #include +#include +#include +#include #include #include #include @@ -47,8 +49,8 @@ struct val_labs }; /* Creates and returns a new, empty set of value labels with the - given WIDTH, which must designate a numeric (0) or short - string (1...MAX_SHORT_STRING inclusive) width. */ + given WIDTH. To actually add any value labels, WIDTH must be + a numeric or short string width. */ struct val_labs * val_labs_create (int width) { @@ -71,7 +73,8 @@ val_labs_copy (const struct val_labs *vls) struct val_labs_iterator *i; struct val_lab *vl; - assert (vls != NULL); + if (vls == NULL) + return NULL; copy = val_labs_create (vls->width); for (vl = val_labs_first (vls, &i); vl != NULL; @@ -80,16 +83,54 @@ val_labs_copy (const struct val_labs *vls) return copy; } +/* Determines whether VLS's width can be changed to NEW_WIDTH. + Numeric widths cannot be changed at all. + Strings can be widened. They can be shortened only if the + characters that will be truncated are spaces. */ +bool +val_labs_can_set_width (const struct val_labs *vls, int new_width) +{ + if ( var_type_from_width (new_width) != var_type_from_width (vls->width )) + return false; + + if (vls->width == 0) + return new_width == 0; + else if (new_width < vls->width) + { + struct val_labs_iterator *i; + struct val_lab *lab; + + for (lab = val_labs_first (vls, &i); lab != NULL; + lab = val_labs_next (vls, &i)) + { + int j; + + /* We can shorten the value labels only if all the + truncated characters are blanks. */ + for (j = vls->width; j < new_width; j++) + if (lab->value.s[j] != ' ') + { + val_labs_done (&i); + return false; + } + } + return true; + } + else + return true; +} + /* Changes the width of VLS to NEW_WIDTH. If VLS is numeric, NEW_WIDTH must be 0, otherwise it must be within the range 1...MAX_SHORT_STRING inclusive. */ void val_labs_set_width (struct val_labs *vls, int new_width) { - assert (vls != NULL); - assert ((vls->width == 0) == (new_width == 0)); + assert (val_labs_can_set_width (vls, new_width)); vls->width = new_width; + if (new_width > MAX_SHORT_STRING) + val_labs_clear (vls); } /* Destroys VLS. */ @@ -98,8 +139,7 @@ val_labs_destroy (struct val_labs *vls) { if (vls != NULL) { - if (vls->labels != NULL) - hsh_destroy (vls->labels); + hsh_destroy (vls->labels); free (vls); } } @@ -118,12 +158,7 @@ val_labs_clear (struct val_labs *vls) size_t val_labs_count (const struct val_labs *vls) { - assert (vls != NULL); - - if (vls->labels == NULL) - return 0; - else - return hsh_count (vls->labels); + return vls == NULL || vls->labels == NULL ? 0 : hsh_count (vls->labels); } /* One value label in internal format. */ @@ -153,10 +188,10 @@ create_int_val_lab (struct val_labs *vls, union value value, const char *label) } /* If VLS does not already contain a value label for VALUE, adds - LABEL for it and returns nonzero. Otherwise, returns zero. + LABEL for it and returns true. Otherwise, returns false. Behavior is undefined if VLS's width is greater than MAX_SHORT_STRING. */ -int +bool val_labs_add (struct val_labs *vls, union value value, const char *label) { struct int_val_lab *ivl; @@ -175,48 +210,35 @@ val_labs_add (struct val_labs *vls, union value value, const char *label) if (*vlpp == NULL) { *vlpp = ivl; - return 1; - } - else - { - free_int_val_lab (ivl, vls); - return 0; + return true; } + free_int_val_lab (ivl, vls); + return false; } -/* Sets LABEL as the value label for VALUE in VLS. Returns zero - if there wasn't already a value label for VALUE, or nonzero if +/* Sets LABEL as the value label for VALUE in VLS. Returns false + if there wasn't already a value label for VALUE, or true if there was. Behavior is undefined if VLS's width is greater than MAX_SHORT_STRING. */ -int +void val_labs_replace (struct val_labs *vls, union value value, const char *label) { - struct int_val_lab *ivl; - - assert (vls != NULL); assert (vls->width <= MAX_SHORT_STRING); - assert (label != NULL); - - if (vls->labels == NULL) + if (vls->labels != NULL) { - val_labs_add (vls, value, label); - return 0; + struct int_val_lab *new = create_int_val_lab (vls, value, label); + struct int_val_lab *old = hsh_replace (vls->labels, new); + if (old != NULL) + free_int_val_lab (old, vls); } - - ivl = hsh_replace (vls->labels, create_int_val_lab (vls, value, label)); - if (ivl == NULL) - return 0; else - { - free_int_val_lab (ivl, vls); - return 1; - } + val_labs_add (vls, value, label); } -/* Removes any value label for VALUE within VLS. Returns nonzero +/* Removes any value label for VALUE within VLS. Returns true if a value label was removed. Behavior is undefined if VLS's width is greater than MAX_SHORT_STRING. */ -int +bool val_labs_remove (struct val_labs *vls, union value value) { assert (vls != NULL); @@ -230,7 +252,7 @@ val_labs_remove (struct val_labs *vls, union value value) return deleted; } else - return 0; + return false; } /* Searches VLS for a value label for VALUE. If successful, @@ -240,12 +262,9 @@ val_labs_remove (struct val_labs *vls, union value value) char * val_labs_find (const struct val_labs *vls, union value value) { - assert (vls != NULL); - - if (vls->width > MAX_SHORT_STRING) - return NULL; - - if (vls->labels != NULL) + if (vls != NULL + && vls->width <= MAX_SHORT_STRING + && vls->labels != NULL) { struct int_val_lab ivl, *vlp; @@ -362,7 +381,7 @@ val_labs_done (struct val_labs_iterator **ip) /* Compares two value labels and returns a strcmp()-type result. */ int -compare_int_val_lab (const void *a_, const void *b_, void *vls_) +compare_int_val_lab (const void *a_, const void *b_, const void *vls_) { const struct int_val_lab *a = a_; const struct int_val_lab *b = b_; @@ -376,7 +395,7 @@ compare_int_val_lab (const void *a_, const void *b_, void *vls_) /* Hash a value label. */ unsigned -hash_int_val_lab (const void *vl_, void *vls_) +hash_int_val_lab (const void *vl_, const void *vls_) { const struct int_val_lab *vl = vl_; const struct val_labs *vls = vls_; @@ -384,12 +403,12 @@ hash_int_val_lab (const void *vl_, void *vls_) if (vls->width == 0) return hsh_hash_double (vl->value.f); else - return hsh_hash_bytes (vl->value.s, sizeof vl->value.s); + return hsh_hash_bytes (vl->value.s, vls->width); } /* Free a value label. */ void -free_int_val_lab (void *vl_, void *vls_ UNUSED) +free_int_val_lab (void *vl_, const void *vls_ UNUSED) { struct int_val_lab *vl = vl_; @@ -413,6 +432,12 @@ static hsh_free_func free_atom; /* Hash table of atoms. */ static struct hsh_table *atoms; +static void +destroy_atoms (void) +{ + hsh_destroy (atoms); +} + /* Creates and returns an atom for STRING. */ static struct atom * atom_create (const char *string) @@ -423,7 +448,10 @@ atom_create (const char *string) assert (string != NULL); if (atoms == NULL) - atoms = hsh_create (8, compare_atoms, hash_atom, free_atom, NULL); + { + atoms = hsh_create (8, compare_atoms, hash_atom, free_atom, NULL); + atexit (destroy_atoms); + } a.string = (char *) string; app = hsh_probe (atoms, &a); @@ -467,7 +495,7 @@ atom_to_string (const struct atom *atom) /* A hsh_compare_func that compares A and B. */ static int -compare_atoms (const void *a_, const void *b_, void *aux UNUSED) +compare_atoms (const void *a_, const void *b_, const void *aux UNUSED) { const struct atom *a = a_; const struct atom *b = b_; @@ -477,7 +505,7 @@ compare_atoms (const void *a_, const void *b_, void *aux UNUSED) /* A hsh_hash_func that hashes ATOM. */ static unsigned -hash_atom (const void *atom_, void *aux UNUSED) +hash_atom (const void *atom_, const void *aux UNUSED) { const struct atom *atom = atom_; @@ -486,38 +514,10 @@ hash_atom (const void *atom_, void *aux UNUSED) /* A hsh_free_func that destroys ATOM. */ static void -free_atom (void *atom_, void *aux UNUSED) +free_atom (void *atom_, const void *aux UNUSED) { struct atom *atom = atom_; free (atom->string); free (atom); } - - -/* Get a string representing the value. - That is, if it has a label, then return that label, - otherwise, if the value is alpha, then return the string for it, - else format it and return the formatted string -*/ -const char * -value_to_string (const union value *val, const struct variable *var) -{ - char *s; - - assert (val != NULL); - assert (var != NULL); - - s = val_labs_find (var->val_labs, *val); - if (s == NULL) - { - static char buf[256]; - if (var->width != 0) - str_copy_buf_trunc (buf, sizeof buf, val->s, var->width); - else - snprintf(buf, 100, "%g", val->f); - s = buf; - } - - return s; -}