Use the gnumeric_reopen function
[pspp] / src / data / variable.c
index c83c31ad72fb4d4dc21b1b001b5df176be8715d2..285d9d88f72d90c283db648f0425f055793e1860 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 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
@@ -26,6 +26,7 @@
 #include "data/format.h"
 #include "data/identifier.h"
 #include "data/missing-values.h"
+#include "data/settings.h"
 #include "data/value-labels.h"
 #include "data/vardict.h"
 #include "libpspp/assertion.h"
@@ -53,6 +54,7 @@ struct variable
     struct fmt_spec write;     /* Default format for WRITE. */
     struct val_labs *val_labs;  /* Value labels. */
     char *label;               /* Variable label. */
+    struct string name_and_label; /* The name and label in the same string */
 
     /* GUI information. */
     enum measure measure;       /* Nominal, ordinal, or continuous. */
@@ -70,10 +72,6 @@ struct variable
     char **short_names;
     size_t short_name_cnt;
 
-    /* Each command may use these fields as needed. */
-    void *aux;
-    void (*aux_dtor) (struct variable *);
-
     /* Custom attributes. */
     struct attrset attributes;
   };
@@ -90,9 +88,7 @@ var_create (const char *name, int width)
 
   assert (width >= 0 && width <= MAX_STRING);
 
-  v = xmalloc (sizeof *v);
-  v->vardict = NULL;
-  v->name = NULL;
+  v = xzalloc (sizeof *v);
   var_set_name (v, name);
   v->width = width;
   mv_init (&v->miss, width);
@@ -102,13 +98,8 @@ var_create (const char *name, int width)
   v->measure = var_default_measure (type);
   v->display_width = var_default_display_width (width);
   v->print = v->write = var_default_formats (width);
-  v->val_labs = NULL;
-  v->label = NULL;
-  v->short_names = NULL;
-  v->short_name_cnt = 0;
-  v->aux = NULL;
-  v->aux_dtor = NULL;
   attrset_init (&v->attributes);
+  ds_init_empty (&v->name_and_label);
 
   return v;
 }
@@ -133,7 +124,7 @@ var_clone (const struct variable *old_var)
   var_set_print_format (new_var, var_get_print_format (old_var));
   var_set_write_format (new_var, var_get_write_format (old_var));
   var_set_value_labels (new_var, var_get_value_labels (old_var));
-  var_set_label (new_var, var_get_label (old_var), NULL, false);
+  var_set_label (new_var, var_get_label (old_var), false);
   var_set_measure (new_var, var_get_measure (old_var));
   var_set_display_width (new_var, var_get_display_width (old_var));
   var_set_alignment (new_var, var_get_alignment (old_var));
@@ -154,10 +145,11 @@ var_destroy (struct variable *v)
       assert (!var_has_vardict (v));
       mv_destroy (&v->miss);
       var_clear_short_names (v);
-      var_clear_aux (v);
       val_labs_destroy (v->val_labs);
       var_clear_label (v);
+      attrset_destroy (var_get_attributes (v));
       free (v->name);
+      ds_destroy (&v->name_and_label);
       free (v);
     }
 }
@@ -171,6 +163,8 @@ var_get_name (const struct variable *v)
   return v->name;
 }
 
+
+
 /* Sets V's name to NAME, a UTF-8 encoded string.
    Do not use this function for a variable in a dictionary.  Use
    dict_rename_var instead. */
@@ -182,6 +176,8 @@ var_set_name (struct variable *v, const char *name)
 
   free (v->name);
   v->name = xstrdup (name);
+  ds_destroy (&v->name_and_label);
+  ds_init_empty (&v->name_and_label);
   dict_var_changed (v);
 }
 
@@ -200,7 +196,7 @@ compare_vars_by_name (const void *a_, const void *b_, const void *aux UNUSED)
   const struct variable *a = a_;
   const struct variable *b = b_;
 
-  return strcasecmp (a->name, b->name);
+  return utf8_strcasecmp (a->name, b->name);
 }
 
 /* A hsh_hash_func that hashes variable V based on its name. */
@@ -209,7 +205,7 @@ hash_var_by_name (const void *v_, const void *aux UNUSED)
 {
   const struct variable *v = v_;
 
-  return hash_case_string (v->name, 0);
+  return utf8_hash_case_string (v->name, 0);
 }
 
 /* A hsh_compare_func that orders pointers to variables A and B
@@ -221,7 +217,7 @@ compare_var_ptrs_by_name (const void *a_, const void *b_,
   struct variable *const *a = a_;
   struct variable *const *b = b_;
 
-  return strcasecmp (var_get_name (*a), var_get_name (*b));
+  return utf8_strcasecmp (var_get_name (*a), var_get_name (*b));
 }
 
 /* A hsh_compare_func that orders pointers to variables A and B
@@ -245,7 +241,7 @@ hash_var_ptr_by_name (const void *v_, const void *aux UNUSED)
 {
   struct variable *const *v = v_;
 
-  return hash_case_string (var_get_name (*v), 0);
+  return utf8_hash_case_string (var_get_name (*v), 0);
 }
 \f
 /* Returns the type of variable V. */
@@ -467,6 +463,19 @@ var_lookup_value_label (const struct variable *v, const union value *value)
   return val_labs_find (v->val_labs, value);
 }
 
+/*
+   Append to STR the string representation of VALUE for variable V.
+   STR must be a pointer to an initialised struct string.
+*/
+static void
+append_value (const struct variable *v, const union value *value,
+             struct string *str)
+{
+  char *s = data_out (value, var_get_encoding (v), &v->print);
+  ds_put_cstr (str, s);
+  free (s);
+}
+
 /* Append STR with a string representing VALUE for variable V.
    That is, if VALUE has a label, append that label,
    otherwise format VALUE and append the formatted string.
@@ -476,15 +485,33 @@ void
 var_append_value_name (const struct variable *v, const union value *value,
                       struct string *str)
 {
+  enum settings_value_style style = settings_get_value_style ();
   const char *name = var_lookup_value_label (v, value);
-  if (name == NULL)
+
+  switch (style)
     {
-      char *s = data_out (value, var_get_encoding (v), &v->print);
-      ds_put_cstr (str, s);
-      free (s);
-    }
-  else
-    ds_put_cstr (str, name);
+    case SETTINGS_VAL_STYLE_VALUES:
+      append_value (v, value, str);
+      break;
+      
+    case SETTINGS_VAL_STYLE_LABELS:
+      if (name == NULL)
+       append_value (v, value, str);
+      else
+       ds_put_cstr (str, name);
+      break;
+
+    case SETTINGS_VAL_STYLE_BOTH:
+    default:
+      append_value (v, value, str);
+      if (name != NULL)
+       {
+         ds_put_cstr (str, " (");
+         ds_put_cstr (str, name);
+         ds_put_cstr (str, ")");
+       }
+      break;
+    };
 }
 \f
 /* Print and write formats. */
@@ -503,9 +530,12 @@ var_get_print_format (const struct variable *v)
 void
 var_set_print_format (struct variable *v, const struct fmt_spec *print)
 {
-  assert (fmt_check_width_compat (print, v->width));
-  v->print = *print;
-  dict_var_changed (v);
+  if (!fmt_equal (&v->print, print))
+    {
+      assert (fmt_check_width_compat (print, v->width));
+      v->print = *print;
+      dict_var_changed (v);
+    }
 }
 
 /* Returns V's write format specification. */
@@ -522,9 +552,12 @@ var_get_write_format (const struct variable *v)
 void
 var_set_write_format (struct variable *v, const struct fmt_spec *write)
 {
-  assert (fmt_check_width_compat (write, v->width));
-  v->write = *write;
-  dict_var_changed (v);
+  if (!fmt_equal (&v->write, write))
+    {
+      assert (fmt_check_width_compat (write, v->width));
+      v->write = *write;
+      dict_var_changed (v);
+    }
 }
 
 /* Sets V's print and write format specifications to FORMAT,
@@ -549,14 +582,51 @@ var_default_formats (int width)
           ? fmt_for_output (FMT_F, 8, 2)
           : fmt_for_output (FMT_A, width, 0));
 }
+
+
 \f
+
+/* Update the combined name and label string if necessary */
+static void
+update_vl_string (const struct variable *v)
+{
+  /* Cast away const! */
+  struct string *str = (struct string *) &v->name_and_label;
+
+  if (ds_is_empty (str))
+    {
+      if (v->label)
+        ds_put_format (str, _("%s (%s)"), v->label, v->name);
+      else
+        ds_put_cstr (str, v->name);
+    }
+}
+
+
 /* Return a string representing this variable, in the form most
    appropriate from a human factors perspective, that is, its
    variable label if it has one, otherwise its name. */
 const char *
 var_to_string (const struct variable *v)
 {
-  return v->label != NULL ? v->label : v->name;
+  enum settings_var_style style = settings_get_var_style ();
+
+  switch (style)
+  {
+    case SETTINGS_VAR_STYLE_NAMES:
+      return v->name;
+      break;
+    case SETTINGS_VAR_STYLE_LABELS:
+      return v->label != NULL ? v->label : v->name;
+      break;
+    case SETTINGS_VAR_STYLE_BOTH:
+      update_vl_string (v);
+      return ds_cstr (&v->name_and_label);
+      break;
+    default:
+      NOT_REACHED ();
+      break;
+  };
 }
 
 /* Returns V's variable label, or a null pointer if it has none. */
@@ -571,22 +641,21 @@ var_get_label (const struct variable *v)
    empty string (after stripping white space), then V's variable label (if any)
    is removed.
 
-   Variable labels are limited to 255 bytes in the dictionary encoding, which
-   should be specified as DICT_ENCODING.  If LABEL fits within this limit, this
-   function returns true.  Otherwise, the variable label is set to a truncated
-   value, this function returns false and, if ISSUE_WARNING is true, issues a
-   warning.  */
+   Variable labels are limited to 255 bytes in V's encoding (as returned by
+   var_get_encoding()).  If LABEL fits within this limit, this function returns
+   true.  Otherwise, the variable label is set to a truncated value, this
+   function returns false and, if ISSUE_WARNING is true, issues a warning.  */
 bool
-var_set_label (struct variable *v, const char *label,
-               const char *dict_encoding, bool issue_warning)
+var_set_label (struct variable *v, const char *label, bool issue_warning)
 {
   bool truncated = false;
 
   free (v->label);
   v->label = NULL;
 
-  if (label != NULL)
+  if (label != NULL && label[strspn (label, CC_SPACES)])
     {
+      const char *dict_encoding = var_get_encoding (v);
       struct substring s = ss_cstr (label);
       size_t trunc_len;
 
@@ -606,11 +675,12 @@ var_set_label (struct variable *v, const char *label,
             }
         }
 
-      ss_trim (&s, ss_cstr (CC_SPACES));
-      if (!ss_is_empty (s))
         v->label = ss_xstrdup (s);
     }
 
+  ds_destroy (&v->name_and_label);
+  ds_init_empty (&v->name_and_label);
+
   dict_var_changed (v);
 
   return truncated;
@@ -620,7 +690,7 @@ var_set_label (struct variable *v, const char *label,
 void
 var_clear_label (struct variable *v)
 {
-  var_set_label (v, NULL, NULL, false);
+  var_set_label (v, NULL, false);
 }
 
 /* Returns true if V has a variable V,
@@ -639,6 +709,26 @@ measure_is_valid (enum measure m)
   return m == MEASURE_NOMINAL || m == MEASURE_ORDINAL || m == MEASURE_SCALE;
 }
 
+/* Returns a string version of measurement level M, for display to a user. */
+const char *
+measure_to_string (enum measure m)
+{
+  switch (m)
+    {
+    case MEASURE_NOMINAL:
+      return _("Nominal");
+
+    case MEASURE_ORDINAL:
+      return _("Ordinal");
+
+    case MEASURE_SCALE:
+      return _("Scale");
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's measurement level. */
 enum measure
 var_get_measure (const struct variable *v)
@@ -676,14 +766,12 @@ var_get_display_width (const struct variable *v)
 void
 var_set_display_width (struct variable *v, int new_width)
 {
-  int old_width = v->display_width;
-
-  v->display_width = new_width;
-
-  if ( old_width != new_width)
-    dict_var_display_width_changed (v);
-
-  dict_var_changed (v);
+  if (v->display_width != new_width)
+    {
+      v->display_width = new_width;
+      dict_var_display_width_changed (v);
+      dict_var_changed (v);
+    }
 }
 
 /* Returns the default display width for a variable of the given
@@ -703,6 +791,26 @@ alignment_is_valid (enum alignment a)
   return a == ALIGN_LEFT || a == ALIGN_RIGHT || a == ALIGN_CENTRE;
 }
 
+/* Returns a string version of alignment A, for display to a user. */
+const char *
+alignment_to_string (enum alignment a)
+{
+  switch (a)
+    {
+    case ALIGN_LEFT:
+      return _("Left");
+
+    case ALIGN_RIGHT:
+      return _("Right");
+
+    case ALIGN_CENTRE:
+      return _("Center");
+
+    default:
+      return "Invalid";
+    }
+}
+
 /* Returns V's display alignment, which applies only to GUIs. */
 enum alignment
 var_get_alignment (const struct variable *v)
@@ -782,10 +890,12 @@ var_get_short_name (const struct variable *var, size_t idx)
   return idx < var->short_name_cnt ? var->short_names[idx] : NULL;
 }
 
-/* Sets VAR's short name with the given IDX to SHORT_NAME,
-   truncating it to SHORT_NAME_LEN characters and converting it
-   to uppercase in the process.  Specifying a null pointer for
-   SHORT_NAME clears the specified short name. */
+/* Sets VAR's short name with the given IDX to the UTF-8 string SHORT_NAME.
+   The caller must already have checked that, in the dictionary encoding,
+   SHORT_NAME is no more than SHORT_NAME_LEN bytes long.  The new short name
+   will be converted to uppercase.
+
+   Specifying a null pointer for SHORT_NAME clears the specified short name. */
 void
 var_set_short_name (struct variable *var, size_t idx, const char *short_name)
 {
@@ -811,8 +921,7 @@ var_set_short_name (struct variable *var, size_t idx, const char *short_name)
           for (i = old_cnt; i < var->short_name_cnt; i++)
             var->short_names[i] = NULL;
         }
-      var->short_names[idx] = xstrndup (short_name, MAX_SHORT_STRING);
-      str_uppercase (var->short_names[idx]);
+      var->short_names[idx] = utf8_to_upper (short_name);
     }
 
   dict_var_changed (var);
@@ -854,63 +963,6 @@ var_get_case_index (const struct variable *v)
   return vardict_get_case_index (v->vardict);
 }
 \f
-/* Returns V's auxiliary data, or a null pointer if none has been
-   attached. */
-void *
-var_get_aux (const struct variable *v)
-{
-  return v->aux;
-}
-
-/* Assign auxiliary data AUX to variable V, which must not
-   already have auxiliary data.  Before V's auxiliary data is
-   cleared, AUX_DTOR(V) will be called.  (var_dtor_free, below,
-   may be appropriate for use as AUX_DTOR.) */
-void *
-var_attach_aux (const struct variable *v_,
-                void *aux, void (*aux_dtor) (struct variable *))
-{
-  struct variable *v = CONST_CAST (struct variable *, v_);
-  assert (v->aux == NULL);
-  assert (aux != NULL);
-  v->aux = aux;
-  v->aux_dtor = aux_dtor;
-  return aux;
-}
-
-/* Remove auxiliary data, if any, from V, and return it, without
-   calling any associated destructor. */
-void *
-var_detach_aux (struct variable *v)
-{
-  void *aux = v->aux;
-  assert (aux != NULL);
-  v->aux = NULL;
-  return aux;
-}
-
-/* Clears auxiliary data, if any, from V, and calls any
-   associated destructor. */
-void
-var_clear_aux (struct variable *v)
-{
-  if (v->aux != NULL)
-    {
-      if (v->aux_dtor != NULL)
-        v->aux_dtor (v);
-      v->aux = NULL;
-    }
-}
-
-/* This function is appropriate for use an auxiliary data
-   destructor (passed as AUX_DTOR to var_attach_aux()) for the
-   case where the auxiliary data should be passed to free(). */
-void
-var_dtor_free (struct variable *v)
-{
-  free (v->aux);
-}
-\f
 /* Returns variable V's attribute set.  The caller may examine or
    modify the attribute set, but must not destroy it.  Destroying
    V, or calling var_set_attributes() on V, will also destroy its