02110-1301, USA. */
#include <config.h>
+
#include "value-labels.h"
-#include "message.h"
+
#include <stdlib.h>
-#include "alloc.h"
-#include "compiler.h"
-#include "hash.h"
-#include "str.h"
+
+#include <data/variable.h>
+#include <libpspp/alloc.h>
+#include <libpspp/compiler.h>
+#include <libpspp/hash.h>
+#include <libpspp/message.h>
+#include <libpspp/str.h>
static hsh_compare_func compare_int_val_lab;
static hsh_hash_func hash_int_val_lab;
};
/* 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)
{
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)
+{
+ assert ((vls->width == 0) == (new_width == 0));
+
+ 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. */
{
if (vls != NULL)
{
- if (vls->labels != NULL)
- hsh_destroy (vls->labels);
+ hsh_destroy (vls->labels);
free (vls);
}
}
}
/* 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;
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
+bool
val_labs_replace (struct val_labs *vls, union value value, const char *label)
{
struct int_val_lab *ivl;
if (vls->labels == NULL)
{
val_labs_add (vls, value, label);
- return 0;
+ return false;
}
ivl = hsh_replace (vls->labels, create_int_val_lab (vls, value, label));
if (ivl == NULL)
- return 0;
+ return false;
else
{
free_int_val_lab (ivl, vls);
- return 1;
+ return true;
}
}
-/* 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);
return deleted;
}
else
- return 0;
+ return false;
}
/* Searches VLS for a value label for VALUE. If successful,
\f
/* 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_;
/* 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_;
/* 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_;
/* 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_;
/* 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_;
/* 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_;
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);
+ static char buf[MAX_STRING + 1];
+ data_out (buf, &var->print, val);
+ buf[var->print.w] = '\0';
s = buf;
}