it works again
[pspp] / src / output / pivot-output.c
index 2d88610eae72db4ebe6b86cee146a21afa5d8dba..8c1aacc0a7ce8867871989516e0d01706f45db4c 100644 (file)
@@ -46,7 +46,7 @@ pivot_output_next_layer (const struct pivot_table *pt, size_t *indexes,
   else if (!indexes)
     {
       size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer;
-      return xmemdup (pt->current_layer, MAX (size, 1));
+      return size ? xmemdup (pt->current_layer, size) : xmalloc (1);
     }
   else
     {
@@ -135,7 +135,7 @@ format_cell (const struct pivot_value *value, int style_idx,
 static void
 fill_cell (struct table *t, int x1, int y1, int x2, int y2,
            const struct table_area_style *style, int style_idx,
-           const struct pivot_value *value, struct footnote **footnotes,
+           const struct pivot_value *value,
            enum settings_value_show show_values,
            enum settings_value_show show_variables,
            bool rotate_label)
@@ -155,12 +155,9 @@ fill_cell (struct table *t, int x1, int y1, int x2, int y2,
                                                     value->font_style,
                                                     rotate_label));
 
-      for (size_t i = 0; i < value->n_footnotes; i++)
-        {
-          struct footnote *f = footnotes[value->footnotes[i]->idx];
-          if (f)
-            table_add_footnote (t, x1, y1, f);
-        }
+      table_add_footnotes (t, x1, y1,
+                           (struct pivot_footnote **) value->footnotes,
+                           value->n_footnotes);
 
       if (value->n_subscripts)
         table_add_subscripts (t, x1, y1,
@@ -200,7 +197,6 @@ compose_headings (struct table *t,
                   const struct table_area_style *label_style,
                   int label_style_idx,
                   const struct table_area_style *corner_style,
-                  struct footnote **footnotes,
                   enum settings_value_show show_values,
                   enum settings_value_show show_variables,
                   bool rotate_inner_labels, bool rotate_outer_labels)
@@ -255,7 +251,7 @@ compose_headings (struct table *t,
                   bool rotate = ((rotate_inner_labels && is_inner_row)
                                  || (rotate_outer_labels && is_outer_row));
                   fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
-                             label_style, label_style_idx, c->name, footnotes,
+                             label_style, label_style_idx, c->name,
                              show_values, show_variables, rotate);
 
                   if (pivot_category_is_leaf (c) && x2 + 1 <= n_columns)
@@ -293,7 +289,7 @@ compose_headings (struct table *t,
           bb[b][0] = bottom_row - d->label_depth + 1;
           bb[b][1] = bottom_row;
           fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
-                     corner_style, PIVOT_AREA_CORNER, d->root->name, footnotes,
+                     corner_style, PIVOT_AREA_CORNER, d->root->name,
                      show_values, show_variables, false);
         }
 
@@ -311,80 +307,76 @@ create_aux_table (const struct pivot_table *pt, int nc, int nr,
 {
   struct table *table = table_create (nr, nc, 0, 0, 0, 0);
   table->styles[style_idx] = table_area_style_override (
-      t->container, &pt->look->areas[style_idx], NULL, NULL, false);
+      table->container, &pt->look->areas[style_idx], NULL, NULL, false);
   return table;
 }
 
 
-static struct footnote **
-add_footnotes (struct footnote **refs, size_t n_refs,
-               struct footnote **footnotes, size_t *allocated, size_t *n)
+static void
+add_references (const struct pivot_table *pt, const struct table *table,
+                bool *refs, size_t *n_refs)
 {
-  for (size_t i = 0; i < n_refs; i++)
-    {
-      struct footnote *f = refs[i];
-      if (f->idx >= *allocated)
-        {
-          size_t new_allocated = (f->idx + 1) * 2;
-          footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
-          while (*allocated < new_allocated)
-            footnotes[(*allocated)++] = NULL;
-        }
-      footnotes[f->idx] = f;
-      if (f->idx >= *n)
-        *n = f->idx + 1;
-    }
-  return footnotes;
+  if (!table)
+    return;
+
+  for (int y = 0; y < table->n[V]; y++)
+    for (int x = 0; x < table->n[H]; )
+      {
+        struct table_cell cell;
+        table_get_cell (table, x, y, &cell);
+
+        if (x == cell.d[H][0] && y == cell.d[V][0])
+          {
+            for (size_t i = 0; i < cell.n_footnotes; i++)
+              {
+                const struct pivot_footnote *f = cell.footnotes[i];
+                assert (f->idx < pt->n_footnotes);
+                assert (f == pt->footnotes[f->idx]);
+
+                if (!refs[f->idx])
+                  {
+                    refs[f->idx] = true;
+                    (*n_refs)++;
+                  }
+              }
+          }
+
+        x = cell.d[TABLE_HORZ][1];
+      }
 }
 
-size_t
-table_collect_footnotes (const struct table *
-                         struct footnote ***footnotesp)
+static struct pivot_footnote **
+collect_footnotes (const struct pivot_table *pt,
+                   const struct table *title,
+                   const struct table *layers,
+                   const struct table *body,
+                   const struct table *caption,
+                   size_t *n_footnotesp)
 {
-  struct footnote **footnotes = NULL;
-  size_t allocated = 0;
-  size_t n = 0;
-
-  struct table *t = item->table;
-  for (int y = 0; y < t->n[V]; y++)
+  if (!pt->n_footnotes)
     {
-      struct table_cell cell;
-      for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1])
-        {
-          table_get_cell (t, x, y, &cell);
-
-          if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
-            footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
-                                       footnotes, &allocated, &n);
-        }
+      *n_footnotesp = 0;
+      return NULL;
     }
 
-  const struct table_cell *title = table_item_get_title (item);
-  if (title)
-    footnotes = add_footnotes (title->footnotes, title->n_footnotes,
-                               footnotes, &allocated, &n);
-
-  const struct table_item_layers *layers = table_item_get_layers (item);
-  if (layers)
-    {
-      for (size_t i = 0; i < layers->n_layers; i++)
-        footnotes = add_footnotes (layers->layers[i].footnotes,
-                                   layers->layers[i].n_footnotes,
-                                   footnotes, &allocated, &n);
-    }
+  bool *refs = xzalloc (pt->n_footnotes);
+  size_t n_refs = 0;
+  add_references (pt, title, refs, &n_refs);
+  add_references (pt, layers, refs, &n_refs);
+  add_references (pt, body, refs, &n_refs);
+  add_references (pt, caption, refs, &n_refs);
 
-  const struct table_cell *caption = table_item_get_caption (item);
-  if (caption)
-    footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
-                               footnotes, &allocated, &n);
+  struct pivot_footnote **footnotes = xnmalloc (n_refs, sizeof *footnotes);
+  size_t n_footnotes = 0;
+  for (size_t i = 0; i < pt->n_footnotes; i++)
+    if (refs[i])
+      footnotes[n_footnotes++] = pt->footnotes[i];
+  assert (n_footnotes == n_refs);
 
-  size_t n_nonnull = 0;
-  for (size_t i = 0; i < n; i++)
-    if (footnotes[i])
-      footnotes[n_nonnull++] = footnotes[i];
+  free (refs);
 
-  *footnotesp = footnotes;
-  return n_nonnull;
+  *n_footnotesp = n_footnotes;
+  return footnotes;
 }
 
 void
@@ -395,7 +387,7 @@ pivot_output (const struct pivot_table *pt,
               struct table **bodyp,
               struct table **captionp,
               struct table **footnotesp,
-              struct footnote ***fp, size_t *nfp)
+              struct pivot_footnote ***fp, size_t *nfp)
 {
   const size_t *pindexes[PIVOT_N_AXES]
     = { [PIVOT_AXIS_LAYER] = layer_indexes };
@@ -425,29 +417,6 @@ pivot_output (const struct pivot_table *pt,
       *body->rule_colors[i] = in->color;
     }
 
-  struct footnote **footnotes = XCALLOC (pt->n_footnotes,  struct footnote *);
-  for (size_t i = 0; i < pt->n_footnotes; i++)
-    {
-      const struct pivot_footnote *pf = pt->footnotes[i];
-
-      if (!pf->show)
-        continue;
-
-      char *content = pivot_value_to_string (pf->content, pt->show_values,
-                                             pt->show_variables);
-      char *marker = pivot_value_to_string (pf->marker, pt->show_values,
-                                            pt->show_variables);
-      footnotes[i] = table_create_footnote (
-        body, i, content, marker,
-        table_area_style_override (body->container,
-                                   &pt->look->areas[PIVOT_AREA_FOOTER],
-                                   pf->content->cell_style,
-                                   pf->content->font_style,
-                                   false));
-      free (marker);
-      free (content);
-    }
-
   compose_headings (body,
                     &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
                     pt->look->borders,
@@ -458,7 +427,7 @@ pivot_output (const struct pivot_table *pt,
                     column_enumeration, data[H],
                     &pt->look->areas[PIVOT_AREA_COLUMN_LABELS],
                     PIVOT_AREA_COLUMN_LABELS,
-                    &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
+                    &pt->look->areas[PIVOT_AREA_CORNER],
                     pt->show_values, pt->show_variables,
                     pt->rotate_outer_row_labels, false);
 
@@ -472,7 +441,7 @@ pivot_output (const struct pivot_table *pt,
                     row_enumeration, data[V],
                     &pt->look->areas[PIVOT_AREA_ROW_LABELS],
                     PIVOT_AREA_ROW_LABELS,
-                    &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
+                    &pt->look->areas[PIVOT_AREA_CORNER],
                     pt->show_values, pt->show_variables,
                     false, pt->rotate_inner_column_labels);
 
@@ -492,8 +461,7 @@ pivot_output (const struct pivot_table *pt,
                      x + stub[H], y + stub[V],
                      x + stub[H], y + stub[V],
                      &pt->look->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA,
-                     value, footnotes,
-                     pt->show_values, pt->show_variables, false);
+                     value, pt->show_values, pt->show_variables, false);
 
           x++;
         }
@@ -506,8 +474,7 @@ pivot_output (const struct pivot_table *pt,
       && stub[H] && stub[V])
     fill_cell (body, 0, 0, stub[H] - 1, stub[V] - 1,
                &pt->look->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER,
-               pt->corner_text, footnotes,
-               pt->show_values, pt->show_variables, false);
+               pt->corner_text, pt->show_values, pt->show_variables, false);
 
   if (body->n[H] && body->n[V])
     {
@@ -542,10 +509,9 @@ pivot_output (const struct pivot_table *pt,
   if (pt->title && titlep)
     {
       title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
-      fill_cell (title, 0, 0, 1, 1,
+      fill_cell (title, 0, 0, 0, 0,
                  &pt->look->areas[PIVOT_AREA_TITLE], PIVOT_AREA_TITLE,
-                 pt->title, footnotes,
-                 pt->show_values, pt->show_variables, false);
+                 pt->title, pt->show_values, pt->show_variables, false);
     }
   else
     title = NULL;
@@ -575,10 +541,9 @@ pivot_output (const struct pivot_table *pt,
           /* XXX This puts in the layer values, but not the variable names. */
           const struct pivot_value *name
             = d->data_leaves[layer_indexes[i]]->name;
-          fill_cell (layers, 0, y, 1, y + 1,
+          fill_cell (layers, 0, y, 0, y,
                      &pt->look->areas[PIVOT_AREA_LAYERS], PIVOT_AREA_LAYERS,
-                     name, footnotes,
-                     pt->show_values, pt->show_variables, false);
+                     name, pt->show_values, pt->show_variables, false);
           y++;
         }
     }
@@ -590,17 +555,57 @@ pivot_output (const struct pivot_table *pt,
   if (pt->caption && captionp)
     {
       caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
-      fill_cell (caption, 0, 0, 1, 1,
+      fill_cell (caption, 0, 0, 0, 0,
                  &pt->look->areas[PIVOT_AREA_CAPTION], PIVOT_AREA_CAPTION,
-                 pt->caption, footnotes,
-                 pt->show_values, pt->show_variables, false);
+                 pt->caption, pt->show_values, pt->show_variables, false);
     }
   else
     caption = NULL;
 
-  free (footnotes);
+  /* Footnotes. */
+  size_t nf;
+  struct pivot_footnote **f = collect_footnotes (pt, title, layers, body,
+                                                 caption, &nf);
+  struct table *footnotes;
+  if (nf && footnotesp)
+    {
+      footnotes = create_aux_table (pt, 1, nf, PIVOT_AREA_FOOTER);
 
+      for (size_t i = 0; i < nf; i++)
+        {
+          struct string s = DS_EMPTY_INITIALIZER;
+          pivot_value_format (f[i]->marker, pt->show_values,
+                              pt->show_variables, &s);
+          ds_put_cstr (&s, ". ");
+          pivot_value_format (f[i]->content, pt->show_values,
+                              pt->show_variables, &s);
+
+          struct pivot_value *value = pivot_value_new_user_text_nocopy (
+            ds_steal_cstr (&s));
+
+          fill_cell (layers, 0, i, 0, i,
+                     &pt->look->areas[PIVOT_AREA_FOOTER], PIVOT_AREA_FOOTER,
+                     value, pt->show_values, pt->show_variables, false);
+        }
+    }
+  else
+    footnotes = NULL;
+
+  *titlep = title;
+  if (layersp)
+    *layersp = layers;
   *bodyp = body;
+  if (captionp)
+    *captionp = caption;
+  if (footnotesp)
+    *footnotesp = footnotes;
+  if (fp)
+    {
+      *fp = f;
+      *nfp = nf;
+    }
+  else
+    free (f);
 }
 
 void