Merge 'master' into 'psppsheet'.
[pspp] / src / data / variable.c
index 2ceeecd2717c86212378bc783b0fea293d80d6bc..fe4645ee41e1b7d7fad9042e5dc5014076ace03c 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
@@ -54,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. */
@@ -91,9 +92,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);
@@ -103,13 +102,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;
 }
@@ -160,6 +154,7 @@ var_destroy (struct variable *v)
       var_clear_label (v);
       attrset_destroy (var_get_attributes (v));
       free (v->name);
+      ds_destroy (&v->name_and_label);
       free (v);
     }
 }
@@ -173,6 +168,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. */
@@ -184,6 +181,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);
 }
 
@@ -202,7 +201,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. */
@@ -211,7 +210,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
@@ -223,7 +222,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
@@ -247,7 +246,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. */
@@ -536,9 +535,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. */
@@ -555,9 +557,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,
@@ -582,14 +587,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. */
@@ -641,6 +683,9 @@ var_set_label (struct variable *v, const char *label, bool issue_warning)
         v->label = ss_xstrdup (s);
     }
 
+  ds_destroy (&v->name_and_label);
+  ds_init_empty (&v->name_and_label);
+
   dict_var_changed (v);
 
   return truncated;
@@ -881,8 +926,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] = xstrdup (short_name);
-      str_uppercase (var->short_names[idx]);
+      var->short_names[idx] = utf8_to_upper (short_name);
     }
 
   dict_var_changed (var);