Replace numerous instances of xzalloc with XZALLOC
[pspp] / src / output / charts / barchart.c
index cf88d66561cc3a50d40289e2688766f02e32178a..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,6 +86,79 @@ 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
@@ -83,12 +170,11 @@ compare_freq_2level_ptr_3way (const void *a_, const void *b_, const void *bc_)
    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,
                 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);
@@ -135,7 +221,7 @@ barchart_create (const struct variable **var, int n_vars,
 
          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);
@@ -173,7 +259,7 @@ barchart_create (const struct variable **var, int n_vars,
 
          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);
@@ -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;
 
@@ -294,7 +383,7 @@ barchart_destroy (struct chart_item *chart_item)
   free (bar);
 }
 
-const struct chart_item_class barchart_class =
+const struct chart_class barchart_class =
   {
     barchart_destroy
   };