+add_references (const struct pivot_table *pt, const struct table *table,
+ bool *refs, size_t *n_refs)
+{
+ 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])
+ {
+ const struct pivot_value_ex *ex = pivot_value_ex (cell.value);
+ for (size_t i = 0; i < ex->n_footnotes; i++)
+ {
+ size_t idx = ex->footnote_indexes[i];
+ assert (idx < pt->n_footnotes);
+
+ if (!refs[idx] && pt->footnotes[idx]->show)
+ {
+ refs[idx] = true;
+ (*n_refs)++;
+ }
+ }
+ }
+
+ x = cell.d[TABLE_HORZ][1];
+ }
+}
+
+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)
+{
+ if (!pt->n_footnotes)
+ {
+ *n_footnotesp = 0;
+ return NULL;
+ }
+
+ bool *refs = XCALLOC (pt->n_footnotes, bool);
+ 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);
+
+ 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);
+
+ free (refs);
+
+ *n_footnotesp = n_footnotes;
+ return footnotes;
+}
+
+void
+pivot_output (const struct pivot_table *pt,
+ const size_t *layer_indexes,
+ bool printing UNUSED,
+ struct table **titlep,
+ struct table **layersp,
+ struct table **bodyp,
+ struct table **captionp,
+ struct table **footnotesp,
+ struct pivot_footnote ***fp, size_t *nfp)