/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009-2015 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
#include "libpspp/compiler.h"
#include "libpspp/hash-functions.h"
#include "libpspp/i18n.h"
+#include "libpspp/intern.h"
#include "libpspp/message.h"
#include "libpspp/misc.h"
+#include "libpspp/pxd.h"
#include "libpspp/str.h"
#include "gl/minmax.h"
/* Custom attributes. */
struct attrset attributes;
};
+
+static void var_uncache (struct variable *);
\f
static void var_set_print_format_quiet (struct variable *v, const struct fmt_spec *print);
if (v != NULL)
{
assert (!var_has_vardict (v));
+ var_uncache (v);
mv_destroy (&v->miss);
var_clear_short_names (v);
val_labs_destroy (v->val_labs);
v->name = xstrdup (name);
ds_destroy (&v->name_and_label);
ds_init_empty (&v->name_and_label);
+ var_uncache (v);
}
/* Sets V's name to NAME, a UTF-8 encoded string.
if (traits != 0)
dict_var_changed (v, traits, ov);
+
+ var_uncache (v);
}
/* Changes the width of V to NEW_WIDTH.
static void
var_set_value_labels_quiet (struct variable *v, const struct val_labs *vls)
{
- val_labs_destroy (v->val_labs);
- v->val_labs = NULL;
+ bool changed = false;
+
+ if (v->val_labs != NULL)
+ {
+ val_labs_destroy (v->val_labs);
+ v->val_labs = NULL;
+ changed = true;
+ }
if (vls != NULL)
{
v->val_labs = val_labs_clone (vls);
val_labs_set_width (v->val_labs, v->width);
}
+
+ if (changed)
+ var_uncache (v);
}
var_add_value_label (struct variable *v,
const union value *value, const char *label)
{
+ bool changed;
+
alloc_value_labels (v);
- return val_labs_add (v->val_labs, value, label);
+
+ changed = val_labs_add (v->val_labs, value, label);
+ if (changed)
+ var_uncache (v);
+ return changed;
}
/* Adds or replaces a value label with the given VALUE and UTF-8 encoded LABEL
{
alloc_value_labels (v);
val_labs_replace (v->val_labs, value, label);
+ var_uncache (v);
}
/* Removes V's value labels, if any. */
{
assert (fmt_check_width_compat (print, v->width));
v->print = *print;
+ var_uncache (v);
}
}
struct variable *ov = var_clone (v);
var_set_print_format_quiet (v, print);
dict_var_changed (v, VAR_TRAIT_PRINT_FORMAT, ov);
+ var_uncache (v);
}
/* Returns V's write format specification. */
{
assert (fmt_check_width_compat (write, v->width));
v->write = *write;
+ var_uncache (v);
}
}
ds_destroy (&v->name_and_label);
ds_init_empty (&v->name_and_label);
+ var_uncache (v);
}
-
-
/* Sets V's variable label to UTF-8 encoded string LABEL, stripping off leading
and trailing white space. If LABEL is a null pointer or if LABEL is an
empty string (after stripping white space), then V's variable label (if any)
v->measure = measure;
}
-
/* Sets V's measurement level to MEASURE. */
void
var_set_measure (struct variable *v, enum measure measure)
void
var_set_display_width (struct variable *v, int new_width)
{
- struct variable *ov = var_clone (v);
- var_set_display_width_quiet (v, new_width);
- dict_var_changed (v, VAR_TRAIT_DISPLAY_WIDTH, ov);
+ if (v->display_width != new_width)
+ {
+ struct variable *ov = var_clone (v);
+ var_set_display_width_quiet (v, new_width);
+ dict_var_changed (v, VAR_TRAIT_DISPLAY_WIDTH, ov);
+ }
}
-
/* Returns the default display width for a variable of the given
WIDTH, as set by var_create. The return value can be used to
reset a variable's display width to the default. */
void
var_clear_short_names (struct variable *v)
{
- size_t i;
-
- for (i = 0; i < v->short_name_cnt; i++)
- free (v->short_names[i]);
- free (v->short_names);
- v->short_names = NULL;
- v->short_name_cnt = 0;
+ if (v->short_name_cnt > 0)
+ {
+ size_t i;
+
+ for (i = 0; i < v->short_name_cnt; i++)
+ free (v->short_names[i]);
+ free (v->short_names);
+ v->short_names = NULL;
+ v->short_name_cnt = 0;
+ var_uncache (v);
+ }
}
\f
/* Relationship with dictionary. */
{
attrset_destroy (&v->attributes);
attrset_clone (&v->attributes, attrs);
+ var_uncache (v);
}
/* Replaces variable V's attributes set by a copy of ATTRS. */
{
v->vardict = NULL;
}
+\f
+struct pxd_object *
+var_save (const struct variable *var, struct pxd *pxd)
+{
+ struct pxd_builder b;
+ size_t i;
+
+ pxd_builder_init (&b, pxd);
+
+ pxd_builder_put_string (&b, var->name);
+ pxd_builder_put_u16 (&b, var->width);
+ pxd_builder_put_link (&b, mv_save (&var->miss, pxd));
+ pxd_builder_put_u32 (&b, fmt_to_uint (&var->print));
+ pxd_builder_put_u32 (&b, fmt_to_uint (&var->write));
+
+ if (var_has_value_labels (var))
+ {
+ pxd_builder_put_bool (&b, true);
+ pxd_builder_put_link (&b, val_labs_save (var->val_labs, pxd));
+ }
+ else
+ pxd_builder_put_bool (&b, false);
+
+ pxd_builder_put_string (&b, var->label != NULL ? var->label : "");
+
+ pxd_builder_put_u8 (&b, var->measure);
+ pxd_builder_put_u32 (&b, var->display_width);
+ pxd_builder_put_u8 (&b, var->alignment);
+
+ pxd_builder_put_bool (&b, var->leave);
+
+ pxd_builder_put_size_t (&b, var->short_name_cnt);
+ for (i = 0; i < var->short_name_cnt; i++)
+ pxd_builder_put_string (&b, var->short_names[i]);
+
+ pxd_builder_put_link (&b, attrset_save (&var->attributes, pxd));
+
+ return pxd_builder_commit (&b);
+}
+
+struct variable *
+var_load (struct pxd_object *object, const struct pxd *pxd)
+{
+ struct fmt_spec print, write;
+ struct missing_values mv;
+ struct variable *var;
+ struct pxd_parser p;
+ char *label;
+ char *name;
+ int width;
+ size_t i;
+
+#if 0
+ cached_var = pxd_cache_search (&var_cache, pxd_object_id (object));
+ if (cached_var != NULL)
+ {
+ size_t n;
+
+ var = var_clone (cached_var);
+
+ /* var_clone() doesn't copy short names, so we need to. */
+ n = cached_var->short_name_cnt;
+ if (n > 0)
+ {
+ size_t i;
+
+ var->short_name_cnt = n;
+ var->short_names = xmalloc (n * sizeof *var->short_names);
+ for (i = 0; i < n; i++)
+ var->short_names[i] = xstrdup (cached_var->short_names[i]);
+ }
+
+ return var;
+ }
+#endif
+
+ pxd_parser_init (&p, object, pxd);
+
+ name = pxd_parser_get_string (&p);
+ width = pxd_parser_get_u16 (&p);
+ var = var_create (name, width);
+
+ mv_load (&mv, pxd_parser_get_link (&p), pxd);
+ var_set_missing_values (var, &mv);
+ mv_destroy (&mv);
+
+ fmt_from_uint (&print, pxd_parser_get_u32 (&p));
+ var_set_print_format (var, &print);
+
+ fmt_from_uint (&write, pxd_parser_get_u32 (&p));
+ var_set_write_format (var, &write);
+
+ if (pxd_parser_get_bool (&p))
+ var->val_labs = val_labs_load (pxd_parser_get_link (&p), pxd);
+
+ label = pxd_parser_get_string (&p);
+ if (label[0])
+ var_set_label (var, label);
+ free (label);
+
+ var->measure = pxd_parser_get_u8 (&p);
+ var->display_width = pxd_parser_get_u32 (&p);
+ var->alignment = pxd_parser_get_u8 (&p);
+
+ var->leave = pxd_parser_get_bool (&p);
+
+ var->short_name_cnt = pxd_parser_get_size_t (&p);
+ var->short_names = xmalloc (var->short_name_cnt * sizeof *var->short_names);
+ for (i = 0; i < var->short_name_cnt; i++)
+ var->short_names[i] = pxd_parser_get_string (&p);
+
+ attrset_load (&var->attributes, pxd_parser_get_link (&p), pxd);
+
+ pxd_parser_destroy (&p);
+
+ return var;
+}
+
+static void
+var_uncache (struct variable *var UNUSED)
+{
+}