Fix memory leaks
[pspp-builds.git] / src / data / variable.c
index 029e3f49dd74739f6c6a3f57b98f7300bdbc7f4b..2ceeecd2717c86212378bc783b0fea293d80d6bc 100644 (file)
@@ -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"
@@ -133,7 +134,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));
@@ -157,6 +158,7 @@ var_destroy (struct variable *v)
       var_clear_aux (v);
       val_labs_destroy (v->val_labs);
       var_clear_label (v);
+      attrset_destroy (var_get_attributes (v));
       free (v->name);
       free (v);
     }
@@ -427,9 +429,11 @@ alloc_value_labels (struct variable *v)
     v->val_labs = val_labs_create (v->width);
 }
 
-/* Attempts to add a value label with the given VALUE and LABEL
-   to V.  Returns true if successful, false otherwise (probably
-   due to an existing label). */
+/* Attempts to add a value label with the given VALUE and UTF-8 encoded LABEL
+   to V.  Returns true if successful, false otherwise (probably due to an
+   existing label).
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 bool
 var_add_value_label (struct variable *v,
                      const union value *value, const char *label)
@@ -438,9 +442,10 @@ var_add_value_label (struct variable *v,
   return val_labs_add (v->val_labs, value, label);
 }
 
-/* Adds or replaces a value label with the given VALUE and LABEL
+/* Adds or replaces a value label with the given VALUE and UTF-8 encoded LABEL
    to V.
-*/
+
+   In LABEL, the two-byte sequence "\\n" is interpreted as a new-line. */
 void
 var_replace_value_label (struct variable *v,
                          const union value *value, const char *label)
@@ -456,14 +461,27 @@ var_clear_value_labels (struct variable *v)
   var_set_value_labels (v, NULL);
 }
 
-/* Returns the label associated with VALUE for variable V,
-   or a null pointer if none. */
+/* Returns the label associated with VALUE for variable V, as a UTF-8 string in
+   a format suitable for output, or a null pointer if none. */
 const char *
 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.
@@ -473,15 +491,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. */
@@ -568,22 +604,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;
 
@@ -603,8 +638,6 @@ 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);
     }
 
@@ -617,7 +650,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,
@@ -636,6 +669,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)
@@ -673,14 +726,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
@@ -700,6 +751,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)
@@ -779,10 +850,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)
 {
@@ -808,7 +881,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);
+      var->short_names[idx] = xstrdup (short_name);
       str_uppercase (var->short_names[idx]);
     }