Change many %g format specifiers to %.*g with precision DBL_DIG + 1.
[pspp] / src / language / stats / descriptives.c
index 54bc49d946a064bd3c4eee8ffdab962d611733c3..f80965616f0c1f5fc29b04a9a788440d8471f676 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-2000, 2009-2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-2000, 2009-2014 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
@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include <float.h>
 #include <limits.h>
 #include <math.h>
 #include <stdlib.h>
@@ -397,6 +398,13 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
             }
         }
 
+      /* It would be better to handle Z scores correctly (however we define
+         that) when TEMPORARY is in effect, but in the meantime this at least
+         prevents a use-after-free error.  See bug #38786.  */
+      if (proc_make_temporary_transformations_permanent (ds))
+        msg (SW, _("DESCRIPTIVES with Z scores ignores TEMPORARY.  "
+                   "Temporary transformations will be made permanent."));
+
       proto = caseproto_create ();
       for (i = 0; i < 1 + 2 * z_cnt; i++)
         proto = caseproto_add_width (proto, 0);
@@ -434,7 +442,8 @@ cmd_descriptives (struct lexer *lexer, struct dataset *ds)
       dsc->vars[i].moments = moments_create (dsc->max_moment);
 
   /* Data pass. */
-  grouper = casegrouper_create_splits (proc_open (ds), dict);
+  grouper = casegrouper_create_splits (proc_open_filtering (ds, z_cnt == 0),
+                                       dict);
   while (casegrouper_get_next_group (grouper, &group))
     calc_descriptives (dsc, group, ds);
   ok = casegrouper_destroy (grouper);
@@ -512,7 +521,7 @@ try_name (const struct dictionary *dict, struct dsc_proc *dsc,
   for (i = 0; i < dsc->var_cnt; i++)
     {
       struct dsc_var *dsc_var = &dsc->vars[i];
-      if (dsc_var->z_name != NULL && !strcasecmp (dsc_var->z_name, name))
+      if (dsc_var->z_name != NULL && !utf8_strcasecmp (dsc_var->z_name, name))
         return false;
     }
   return true;
@@ -689,6 +698,8 @@ descriptives_trns_free (void *trns_)
   casereader_destroy (t->z_reader);
   assert((t->missing_type != DSC_LISTWISE) ^ (t->vars != NULL));
   free (t->vars);
+  free (t);
+
   return ok;
 }
 
@@ -732,11 +743,13 @@ setup_z_trns (struct dsc_proc *dsc, struct dataset *ds)
        {
           struct dsc_z_score *z;
          struct variable *dst_var;
+          char *label;
 
          dst_var = dict_create_var_assert (dataset_dict (ds), dv->z_name, 0);
-          var_set_label (dst_var,
-                         xasprintf (_("Z-score of %s"),var_to_string (dv->v)),
-                         false);
+
+          label = xasprintf (_("Z-score of %s"),var_to_string (dv->v));
+          var_set_label (dst_var, label, false);
+          free (label);
 
           z = &t->z_scores[cnt++];
           z->src_var = dv->v;
@@ -990,17 +1003,18 @@ display (struct dsc_proc *dsc)
 
       nc = 0;
       tab_text (t, nc++, i + 1, TAB_LEFT, var_to_string (dv->v));
-      tab_text_format (t, nc++, i + 1, 0, "%g", dv->valid);
+      tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->valid);
       if (dsc->format == DSC_SERIAL)
-       tab_text_format (t, nc++, i + 1, 0, "%g", dv->missing);
+       tab_text_format (t, nc++, i + 1, 0, "%.*g", DBL_DIG + 1, dv->missing);
 
       for (j = 0; j < DSC_N_STATS; j++)
        if (dsc->show_stats & (1ul << j))
          tab_double (t, nc++, i + 1, TAB_NONE, dv->stats[j], NULL);
     }
 
-  tab_title (t, _("Valid cases = %g; cases with missing value(s) = %g."),
-            dsc->valid, dsc->missing_listwise);
+  tab_title (t, _("Valid cases = %.*g; cases with missing value(s) = %.*g."),
+            DBL_DIG + 1, dsc->valid,
+             DBL_DIG + 1, dsc->missing_listwise);
 
   tab_submit (t);
 }
@@ -1017,7 +1031,7 @@ descriptives_compare_dsc_vars (const void *a_, const void *b_, const void *dsc_)
   int result;
 
   if (dsc->sort_by_stat == DSC_NAME)
-    result = strcasecmp (var_get_name (a->v), var_get_name (b->v));
+    result = utf8_strcasecmp (var_get_name (a->v), var_get_name (b->v));
   else
     {
       double as = a->stats[dsc->sort_by_stat];