Replace numerous instances of xzalloc with XZALLOC
[pspp] / src / output / charts / barchart.c
index aca03ee8c41ad3320f11d499ddfd6fe52baf619a..1b946fddffb780a0cd636eb8b3ff15742f4153f3 100644 (file)
 #include "libpspp/cast.h"
 #include "libpspp/str.h"
 #include "libpspp/array.h"
-#include "output/chart-item-provider.h"
+#include "output/chart-provider.h"
 
 #include "gl/xalloc.h"
 #include "data/variable.h"
+#include "data/settings.h"
 #include "language/stats/freq.h"
 
 
@@ -42,6 +43,19 @@ compare_category_3way (const void *a_, const void *b_, const void *bc_)
 }
 
 
+static int
+compare_category_by_index_3way (const void *a_, const void *b_,
+                                const void *unused UNUSED)
+{
+  const struct category *const*a = a_;
+  const struct category *const*b = b_;
+
+  if ( (*a)->idx < (*b)->idx)
+    return -1;
+
+  return ((*a)->idx > (*b)->idx);
+}
+
 static unsigned int
 hash_freq_2level_ptr (const void *a_, const void *bc_)
 {
@@ -72,23 +86,95 @@ compare_freq_2level_ptr_3way (const void *a_, const void *b_, const void *bc_)
   return level0;
 }
 
+/* Print out a textual representation of a barchart.
+   This is intended only for testing, and not as a means
+   of visualising the data.
+*/
+static void
+barchart_dump (const struct barchart *bc, FILE *fp)
+{
+  fprintf (fp, "Graphic: Barchart\n");
+  fprintf (fp, "Percentage: %d\n", bc->percent);
+  fprintf (fp, "Total Categories: %d\n", bc->n_nzcats);
+  fprintf (fp, "Primary Categories: %d\n", bc->n_pcats);
+  fprintf (fp, "Largest Category: %g\n", bc->largest);
+  fprintf (fp, "Total Count: %g\n", bc->total_count);
+
+  fprintf (fp, "Y Label: \"%s\"\n", bc->ylabel);
+
+  fprintf (fp, "Categorical Variables:\n");
+  for (int i = 0; i < bc->n_vars; ++i)
+    {
+      fprintf (fp, "  Var: \"%s\"\n", var_get_name (bc->var[i]));
+    }
+
+  fprintf (fp, "Categories:\n");
+  struct category *cat;
+  struct category **cats = XCALLOC (hmap_count (&bc->primaries), struct category *);
+  int  i = 0;
+  HMAP_FOR_EACH (cat, struct category, node, &bc->primaries)
+    {
+      cats[i++] = cat;
+    }
+  /* HMAP_FOR_EACH is not guaranteed to iterate in any particular order.  So
+     we must sort here before we output the results.  */
+  sort (cats, i, sizeof (struct category *),  compare_category_by_index_3way, bc);
+  for (i = 0; i < hmap_count (&bc->primaries); ++i)
+    {
+      const struct category *c = cats[i];
+      fprintf (fp, "  %d \"%s\"\n", c->idx, ds_cstr (&c->label));
+    }
+  free (cats);
+
+  if (bc->ss)
+    {
+      fprintf (fp, "Sub-categories:\n");
+      for (int i = 0; i < bc->n_nzcats / bc->n_pcats; ++i)
+       {
+         const struct category *cat = bc->ss[i];
+         fprintf (fp, "  %d \"%s\"\n", cat->idx, ds_cstr(&cat->label));
+       }
+    }
+
+  fprintf (fp, "All Categories:\n");
+  for (int i = 0; i < bc->n_nzcats; ++i)
+    {
+      const struct freq *frq = bc->cats[i];
+      fprintf (fp, "Count: %g; ", frq->count);
+
+      struct string s = DS_EMPTY_INITIALIZER;
+      var_append_value_name (bc->var[0], &frq->values[0], &s);
+
+      fprintf (fp, "Cat: \"%s\"", ds_cstr (&s));
+      ds_clear (&s);
+
+      if (bc->ss)
+       {
+         var_append_value_name (bc->var[1], &frq->values[1], &s);
+         fprintf (fp, ", \"%s\"", ds_cstr (&s));
+       }
+      ds_destroy (&s);
+      fputc ('\n', fp);
+    }
+
+  fputc ('\n', fp);
+}
 
 
 /* Creates and returns a chart that will render a barchart with
-   the given TITLE and the N_CATS described in CATS. 
+   the given TITLE and the N_CATS described in CATS.
 
-   VAR is an array containing the categorical variables, and N_VAR 
+   VAR is an array containing the categorical variables, and N_VAR
    the number of them. N_VAR must be exactly 1 or 2.
 
    CATS are the counts of the values of those variables. N_CATS is the
    number of distinct values.
 */
-struct chart_item *
+struct chart *
 barchart_create (const struct variable **var, int n_vars,
-                const char *ylabel, bool percent, 
+                const char *ylabel, bool percent,
                 struct freq *const *cats, int n_cats)
 {
-  struct barchart *bar;
   int i;
 
   const int pidx = 0;
@@ -97,14 +183,14 @@ barchart_create (const struct variable **var, int n_vars,
 
   int width = var_get_width (var[pidx]);
 
-  assert (n_vars >= 1);
+  assert (n_vars >= 1 && n_vars <= 2);
 
-  bar = xzalloc (sizeof *bar);
+  struct barchart *bar = XZALLOC (struct barchart);
   bar->percent = percent;
   bar->var = var;
   bar->n_vars = n_vars;
   bar->n_nzcats = n_cats;
-  chart_item_init (&bar->chart_item, &barchart_class, var_to_string (var[pidx]));
+  chart_init (&bar->chart, &barchart_class, var_to_string (var[pidx]));
 
   bar->largest = -1;
   bar->ylabel = strdup (ylabel);
@@ -113,7 +199,7 @@ barchart_create (const struct variable **var, int n_vars,
       int idx = 0;
       hmap_init (&bar->primaries);
 
-      /* 
+      /*
         Iterate the categories and create a hash table of the primary categories.
         We need to do this to find out how many there are and to cache the labels.
       */
@@ -133,9 +219,9 @@ barchart_create (const struct variable **var, int n_vars,
                }
            }
 
-         if (!flag) 
+         if (!flag)
            {
-             struct category *s = xzalloc (sizeof *s);
+             struct category *s = XZALLOC (struct category);
              s->idx = idx++;
              s->width = var_get_width (var[pidx]);
              value_init (&s->val, s->width);
@@ -170,10 +256,10 @@ barchart_create (const struct variable **var, int n_vars,
                  break;
                }
            }
-      
-         if (!flag) 
+
+         if (!flag)
            {
-             struct category *s = xzalloc (sizeof *s);
+             struct category *s = XZALLOC (struct category);
              s->idx = idx++;
              s->width = var_get_width (var[sidx]);
              value_init (&s->val, s->width);
@@ -192,7 +278,7 @@ barchart_create (const struct variable **var, int n_vars,
       sort (bar->ss, n_category, sizeof *bar->ss,
            compare_category_3way, bar);
     }
-    
+
 
   /* Deep copy.  Not necessary for cmd line, but essential for the GUI,
      since an expose callback will access these structs which may not
@@ -208,7 +294,7 @@ barchart_create (const struct variable **var, int n_vars,
     struct hmap level2table;
     hmap_init (&level2table);
     int x = 0;
-  
+
     for (i = 0; i < n_cats; i++)
       {
        struct freq *c = cats[i];
@@ -222,23 +308,23 @@ barchart_create (const struct variable **var, int n_vars,
              {
                foo->count += c->count;
                bar->total_count += c->count;
-               
+
                if (foo->count > bar->largest)
                  bar->largest = foo->count;
-               
+
                flag = true;
                break;
              }
          }
-       
-       if (!flag) 
+
+       if (!flag)
          {
-           struct freq *aggregated_freq = freq_clone (c, n_vars, bar->widths); 
+           struct freq *aggregated_freq = freq_clone (c, n_vars, bar->widths);
            hmap_insert (&level2table, &aggregated_freq->node, hash);
-           
+
            if (c->count > bar->largest)
              bar->largest = aggregated_freq->count;
-           
+
            bar->total_count += c->count;
            bar->cats[x++] = aggregated_freq;
          }
@@ -251,7 +337,10 @@ barchart_create (const struct variable **var, int n_vars,
   sort (bar->cats, bar->n_nzcats, sizeof *bar->cats,
        compare_freq_2level_ptr_3way, bar);
 
-  return &bar->chart_item;
+  if (settings_get_testing_mode ())
+    barchart_dump (bar, stdout);
+
+  return &bar->chart;
 }
 
 static void
@@ -271,9 +360,9 @@ destroy_cat_map (struct hmap *m)
 }
 
 static void
-barchart_destroy (struct chart_item *chart_item)
+barchart_destroy (struct chart *chart)
 {
-  struct barchart *bar = to_barchart (chart_item);
+  struct barchart *bar = to_barchart (chart);
 
   int i;
 
@@ -287,14 +376,14 @@ barchart_destroy (struct chart_item *chart_item)
     {
       freq_destroy (bar->cats[i], bar->n_vars, bar->widths);
     }
-  
+
   free (bar->cats);
   free (bar->ylabel);
   free (bar->ss);
   free (bar);
 }
 
-const struct chart_item_class barchart_class =
+const struct chart_class barchart_class =
   {
     barchart_destroy
   };