Use XCALLOC / XZALLOC macros where reasonable
[pspp] / src / output / pivot-output.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2018 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include "output/pivot-output.h"
22
23 #include "data/settings.h"
24 #include "libpspp/assertion.h"
25 #include "libpspp/pool.h"
26 #include "output/output-item.h"
27 #include "output/pivot-table.h"
28 #include "output/table-provider.h"
29 #include "output/table.h"
30
31 #include "gl/minmax.h"
32 #include "gl/xalloc.h"
33
34 #define H TABLE_HORZ
35 #define V TABLE_VERT
36
37 size_t *
38 pivot_output_next_layer (const struct pivot_table *pt, size_t *indexes,
39                          bool print)
40 {
41   const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
42   if (print && pt->look->print_all_layers)
43     return pivot_axis_iterator_next (indexes, layer_axis);
44   else if (!indexes)
45     {
46       size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer;
47       return size ? xmemdup (pt->current_layer, size) : xmalloc (1);
48     }
49   else
50     {
51       free (indexes);
52       return NULL;
53     }
54 }
55
56 static const struct pivot_category *
57 find_category (const struct pivot_dimension *d, int dim_index,
58                const size_t *indexes, int row_ofs)
59 {
60   size_t index = indexes[dim_index];
61   assert (index < d->n_leaves);
62   for (const struct pivot_category *c = d->presentation_leaves[index];
63        c; c = c->parent)
64     {
65       /* A category can cover multiple rows.  Only return the category for its
66          top row. */
67       if (row_ofs == c->extra_depth)
68         return c;
69
70       row_ofs -= 1 + c->extra_depth;
71       if (row_ofs < 0)
72         return NULL;
73     }
74   return NULL;
75 }
76
77 static struct table_area_style *
78 table_area_style_override (struct pool *pool,
79                            const struct table_area_style *in,
80                            const struct cell_style *cell_,
81                            const struct font_style *font_,
82                            bool rotate_label)
83 {
84   const struct cell_style *cell = cell_ ? cell_ : &in->cell_style;
85   const struct font_style *font = font_ ? font_ : &in->font_style;
86
87   struct table_area_style *out = (pool
88                             ? pool_alloc (pool, sizeof *out)
89                             : xmalloc (sizeof *out));
90   *out = (struct table_area_style) {
91     .cell_style.halign = rotate_label ? TABLE_HALIGN_CENTER : cell->halign,
92     .cell_style.valign = rotate_label ? TABLE_VALIGN_CENTER : cell->valign,
93     .cell_style.decimal_offset = cell->decimal_offset,
94     .cell_style.margin[H][0] = cell->margin[H][0],
95     .cell_style.margin[H][1] = cell->margin[H][1],
96     .cell_style.margin[V][0] = cell->margin[V][0],
97     .cell_style.margin[V][1] = cell->margin[V][1],
98     .font_style.fg[0] = font->fg[0],
99     .font_style.fg[1] = font->fg[1],
100     .font_style.bg[0] = font->bg[0],
101     .font_style.bg[1] = font->bg[1],
102     .font_style.typeface = (font->typeface
103                             ? pool_strdup (pool, font->typeface)
104                             : NULL),
105     .font_style.size = font->size,
106     .font_style.bold = font->bold,
107     .font_style.italic = font->italic,
108     .font_style.underline = font->underline,
109     .font_style.markup = font->markup,
110   };
111   return out;
112 }
113
114 static void
115 fill_cell (struct table *t, int x1, int y1, int x2, int y2,
116            int style_idx, const struct pivot_value *value,
117            bool rotate_label)
118 {
119   int options = style_idx << TAB_STYLE_SHIFT;
120   if (rotate_label)
121     options |= TAB_ROTATE;
122
123   table_put (t, x1, y1, x2, y2, options, value);
124 }
125
126 static void
127 fill_cell_owned (struct table *t, int x1, int y1, int x2, int y2,
128                  int style_idx, struct string *s, bool rotate_label)
129 {
130   int options = style_idx << TAB_STYLE_SHIFT;
131   if (rotate_label)
132     options |= TAB_ROTATE;
133
134   table_put_owned (t, x1, y1, x2, y2, options,
135                    pivot_value_new_user_text_nocopy (ds_steal_cstr (s)));
136 }
137
138 static int
139 get_table_rule (const struct table_border_style *styles,
140                 enum pivot_border style_idx)
141 {
142   return styles[style_idx].stroke | (style_idx << TAB_RULE_STYLE_SHIFT);
143 }
144
145 static void
146 draw_line (struct table *t, const struct table_border_style *styles,
147            enum pivot_border style_idx,
148            enum table_axis axis, int a, int b0, int b1)
149 {
150   int rule = get_table_rule (styles, style_idx);
151   if (axis == H)
152     table_hline (t, rule, b0, b1, a);
153   else
154     table_vline (t, rule, a, b0, b1);
155 }
156
157 /* Fills row or column headings into T.
158
159    This function uses terminology and variable names for column headings, but
160    it also applies to row headings because it uses variables for the
161    differences, e.g. when for column headings it would use the H axis, it
162    instead uses 'h', which is set to H for column headings and V for row
163    headings.  */
164 static void
165 compose_headings (struct table *t,
166                   const struct pivot_axis *h_axis, enum table_axis h,
167                   const struct pivot_axis *v_axis,
168                   const struct table_border_style *borders,
169                   enum pivot_border dim_col_horz,
170                   enum pivot_border dim_col_vert,
171                   enum pivot_border cat_col_horz,
172                   enum pivot_border cat_col_vert,
173                   const size_t *column_enumeration, size_t n_columns,
174                   int label_style_idx,
175                   bool rotate_inner_labels, bool rotate_outer_labels)
176 {
177   const enum table_axis v = !h;
178   const int v_size = h_axis->label_depth;
179   const int h_ofs = v_axis->label_depth;
180
181   if (!h_axis->n_dimensions || !n_columns || !v_size)
182     return;
183
184   const int stride = MAX (1, h_axis->n_dimensions);
185
186   /* Below, we're going to iterate through the dimensions.  Each dimension
187      occupies one or more rows in the heading.  'top_row' is the top row of
188      these (and 'top_row + d->label_depth - 1' is the bottom row). */
189   int top_row = 0;
190
191   /* We're going to iterate through dimensions and the rows that label them
192      from top to bottom (from outer to inner dimensions).  As we move downward,
193      we start drawing vertical rules to separate categories and groups.  After
194      we start drawing a vertical rule in a particular horizontal position, it
195      continues until the bottom of the heading.  vrules[pos] indicates whether,
196      in our current row, we have already started drawing a vertical rule in
197      horizontal position 'pos'.  (There are n_columns + 1 horizontal positions.
198      We allocate all of them for convenience below but only the inner n_columns
199      - 1 of them really matter.)
200
201      Here's an example that shows how vertical rules continue all the way
202      downward:
203
204      +-----------------------------------------------------+ __
205      |                         bbbb                        |  |
206      +-----------------+-----------------+-----------------+  |dimension "bbbb"
207      |      bbbb1      |      bbbb2      |      bbbb3      | _|
208      +-----------------+-----------------+-----------------+ __
209      |       aaaa      |       aaaa      |       aaaa      |  |
210      +-----+-----+-----+-----+-----+-----+-----+-----+-----+  |dimension "aaaa"
211      |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3| _|
212      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
213
214      ^     ^     ^     ^     ^     ^     ^     ^     ^     ^
215      |     |     |     |     |     |     |     |     |     |
216      0     1     2     3     4     5     6     7     8     9
217      |___________________vrules[] indexes__________________|
218
219      Our data structures are more naturally iterated from bottom to top (inner
220      to outer dimensions).  A previous version of this code actually worked
221      like that, but it didn't draw all of the vertical lines correctly as shown
222      above.  It ended up rendering the above heading much like shown below,
223      which isn't what users expect.  The "aaaa" label really needs to be shown
224      three times for clarity:
225
226      +-----------------------------------------------------+
227      |                         bbbb                        |
228      +-----------------+-----------------+-----------------+
229      |      bbbb1      |      bbbb2      |      bbbb3      |
230      +-----------------+-----------------+-----------------+
231      |                 |       aaaa      |                 |
232      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
233      |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|
234      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
235   */
236   bool *vrules = XCALLOC (n_columns + 1, bool);
237   vrules[0] = vrules[n_columns] = true;
238   for (int dim_index = h_axis->n_dimensions; --dim_index >= 0; )
239     {
240       const struct pivot_dimension *d = h_axis->dimensions[dim_index];
241       if (d->hide_all_labels)
242         continue;
243
244       for (int row_ofs = 0; row_ofs < d->label_depth; row_ofs++)
245         {
246           for (size_t x1 = 0; x1 < n_columns;)
247             {
248               const struct pivot_category *c = find_category (
249                 d, dim_index, column_enumeration + x1 * stride,
250                 d->label_depth - row_ofs - 1);
251               if (!c)
252                 {
253                   x1++;
254                   continue;
255                 }
256
257               size_t x2;
258               for (x2 = x1 + 1; x2 < n_columns; x2++)
259                 {
260                   if (vrules[x2])
261                     break;
262                   const struct pivot_category *c2 = find_category (
263                     d, dim_index, column_enumeration + x2 * stride,
264                     d->label_depth - row_ofs - 1);
265                   if (c != c2)
266                     break;
267                 }
268
269               int y1 = top_row + row_ofs;
270               int y2 = top_row + row_ofs + c->extra_depth + 1;
271               bool is_outer_row = y1 == 0;
272               bool is_inner_row = y2 == v_size;
273               if (pivot_category_is_leaf (c) || c->show_label)
274                 {
275                   int bb[TABLE_N_AXES][2];
276                   bb[h][0] = x1 + h_ofs;
277                   bb[h][1] = x2 + h_ofs - 1;
278                   bb[v][0] = y1;
279                   bb[v][1] = y2 - 1;
280                   bool rotate = ((rotate_inner_labels && is_inner_row)
281                                  || (rotate_outer_labels && is_outer_row));
282                   fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
283                              label_style_idx, c->name, rotate);
284
285                   /* Draw all the vertical lines in our running example, other
286                      than the far left and far right ones.  Only the ones that
287                      start in the last row of the heading are drawn with the
288                      "category" style, the rest with the "dimension" style,
289                      e.g. only the # below are category style:
290
291                      +-----------------------------------------------------+
292                      |                         bbbb                        |
293                      +-----------------+-----------------+-----------------+
294                      |      bbbb1      |      bbbb2      |      bbbb3      |
295                      +-----------------+-----------------+-----------------+
296                      |       aaaa      |       aaaa      |       aaaa      |
297                      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
298                      |aaaa1#aaaa2#aaaa3|aaaa1#aaaa2#aaaa3|aaaa1#aaaa2#aaaa3|
299                      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
300                   */
301                   enum pivot_border style
302                     = (y1 == v_size - 1 ? cat_col_vert : dim_col_vert);
303                   if (!vrules[x2])
304                     {
305                       draw_line (t, borders, style, v, x2 + h_ofs, y1,
306                                  t->n[v] - 1);
307                       vrules[x2] = true;
308                     }
309                   if (!vrules[x1])
310                     {
311                       draw_line (t, borders, style, v, x1 + h_ofs, y1,
312                                  t->n[v] - 1);
313                       vrules[x1] = true;
314                     }
315                 }
316
317               /* Draws the horizontal lines within a dimension, that is, those
318                  that separate a separating a category (or group) from its
319                  parent group or dimension's label.  Our running example
320                  doesn't have groups but the ==== lines below show the
321                  separators between categories and their dimension label:
322
323                  +-----------------------------------------------------+
324                  |                         bbbb                        |
325                  +=================+=================+=================+
326                  |      bbbb1      |      bbbb2      |      bbbb3      |
327                  +-----------------+-----------------+-----------------+
328                  |       aaaa      |       aaaa      |       aaaa      |
329                  +=====+=====+=====+=====+=====+=====+=====+=====+=====+
330                  |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|
331                  +-----+-----+-----+-----+-----+-----+-----+-----+-----+
332               */
333               if (c->parent && c->parent->show_label)
334                 draw_line (t, borders, cat_col_horz, h, y1,
335                            x1 + h_ofs, x2 + h_ofs - 1);
336               x1 = x2;
337             }
338         }
339
340       if (d->root->show_label_in_corner && h_ofs > 0)
341         {
342           int bb[TABLE_N_AXES][2];
343           bb[h][0] = 0;
344           bb[h][1] = h_ofs - 1;
345           bb[v][0] = top_row;
346           bb[v][1] = top_row + d->label_depth - 1;
347           fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
348                      PIVOT_AREA_CORNER, d->root->name, false);
349         }
350
351       /* Draw the horizontal line between dimensions, e.g. the ===== line here:
352
353          +-----------------------------------------------------+ __
354          |                         bbbb                        |  |
355          +-----------------+-----------------+-----------------+  |dim "bbbb"
356          |      bbbb1      |      bbbb2      |      bbbb3      | _|
357          +=================+=================+=================+ __
358          |       aaaa      |       aaaa      |       aaaa      |  |
359          +-----+-----+-----+-----+-----+-----+-----+-----+-----+  |dim "aaaa"
360          |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3| _|
361          +-----+-----+-----+-----+-----+-----+-----+-----+-----+
362       */
363       if (dim_index != h_axis->n_dimensions - 1)
364         draw_line (t, borders, dim_col_horz, h, top_row, h_ofs,
365                    t->n[h] - 1);
366       top_row += d->label_depth;
367     }
368   free (vrules);
369 }
370
371 static struct table *
372 create_aux_table (const struct pivot_table *pt, int nc, int nr,
373                   int style_idx)
374 {
375   struct table *table = table_create (nc, nr, 0, 0, 0, 0);
376   table->styles[style_idx] = table_area_style_override (
377       table->container, &pt->look->areas[style_idx], NULL, NULL, false);
378   return table;
379 }
380
381
382 static void
383 add_references (const struct pivot_table *pt, const struct table *table,
384                 bool *refs, size_t *n_refs)
385 {
386   if (!table)
387     return;
388
389   for (int y = 0; y < table->n[V]; y++)
390     for (int x = 0; x < table->n[H]; )
391       {
392         struct table_cell cell;
393         table_get_cell (table, x, y, &cell);
394
395         if (x == cell.d[H][0] && y == cell.d[V][0])
396           {
397             const struct pivot_value_ex *ex = pivot_value_ex (cell.value);
398             for (size_t i = 0; i < ex->n_footnotes; i++)
399               {
400                 size_t idx = ex->footnote_indexes[i];
401                 assert (idx < pt->n_footnotes);
402
403                 if (!refs[idx] && pt->footnotes[idx]->show)
404                   {
405                     refs[idx] = true;
406                     (*n_refs)++;
407                   }
408               }
409           }
410
411         x = cell.d[TABLE_HORZ][1];
412       }
413 }
414
415 static struct pivot_footnote **
416 collect_footnotes (const struct pivot_table *pt,
417                    const struct table *title,
418                    const struct table *layers,
419                    const struct table *body,
420                    const struct table *caption,
421                    size_t *n_footnotesp)
422 {
423   if (!pt->n_footnotes)
424     {
425       *n_footnotesp = 0;
426       return NULL;
427     }
428
429   bool *refs = XCALLOC (pt->n_footnotes, bool);
430   size_t n_refs = 0;
431   add_references (pt, title, refs, &n_refs);
432   add_references (pt, layers, refs, &n_refs);
433   add_references (pt, body, refs, &n_refs);
434   add_references (pt, caption, refs, &n_refs);
435
436   struct pivot_footnote **footnotes = xnmalloc (n_refs, sizeof *footnotes);
437   size_t n_footnotes = 0;
438   for (size_t i = 0; i < pt->n_footnotes; i++)
439     if (refs[i])
440       footnotes[n_footnotes++] = pt->footnotes[i];
441   assert (n_footnotes == n_refs);
442
443   free (refs);
444
445   *n_footnotesp = n_footnotes;
446   return footnotes;
447 }
448
449 void
450 pivot_output (const struct pivot_table *pt,
451               const size_t *layer_indexes,
452               bool printing UNUSED,
453               struct table **titlep,
454               struct table **layersp,
455               struct table **bodyp,
456               struct table **captionp,
457               struct table **footnotesp,
458               struct pivot_footnote ***fp, size_t *nfp)
459 {
460   const size_t *pindexes[PIVOT_N_AXES]
461     = { [PIVOT_AXIS_LAYER] = layer_indexes };
462
463   size_t data[TABLE_N_AXES];
464   size_t *column_enumeration = pivot_table_enumerate_axis (
465     pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &data[H]);
466   size_t *row_enumeration = pivot_table_enumerate_axis (
467     pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &data[V]);
468
469   int stub[TABLE_N_AXES] = {
470     [H] = pt->axes[PIVOT_AXIS_ROW].label_depth,
471     [V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth,
472   };
473   struct table *body = table_create (data[H] + stub[H],
474                                      data[V] + stub[V],
475                                      stub[H], 0, stub[V], 0);
476   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
477     body->styles[i] = table_area_style_override (
478       body->container, &pt->look->areas[i], NULL, NULL, false);
479
480   struct table_border_style borders[PIVOT_N_BORDERS];
481   memcpy (borders, pt->look->borders, sizeof borders);
482   if (!printing && pt->show_grid_lines)
483     for (int b = 0; b < PIVOT_N_BORDERS; b++)
484       if (borders[b].stroke == TABLE_STROKE_NONE)
485         borders[b].stroke = TABLE_STROKE_DASHED;
486
487   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
488     {
489       const struct table_border_style *in = &pt->look->borders[i];
490       body->rule_colors[i] = pool_alloc (body->container,
491                                          sizeof *body->rule_colors[i]);
492       *body->rule_colors[i] = in->color;
493     }
494
495   compose_headings (body,
496                     &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
497                     borders,
498                     PIVOT_BORDER_DIM_COL_HORZ,
499                     PIVOT_BORDER_DIM_COL_VERT,
500                     PIVOT_BORDER_CAT_COL_HORZ,
501                     PIVOT_BORDER_CAT_COL_VERT,
502                     column_enumeration, data[H],
503                     PIVOT_AREA_COLUMN_LABELS,
504                     pt->rotate_outer_row_labels, false);
505
506   compose_headings (body,
507                     &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
508                     borders,
509                     PIVOT_BORDER_DIM_ROW_VERT,
510                     PIVOT_BORDER_DIM_ROW_HORZ,
511                     PIVOT_BORDER_CAT_ROW_VERT,
512                     PIVOT_BORDER_CAT_ROW_HORZ,
513                     row_enumeration, data[V],
514                     PIVOT_AREA_ROW_LABELS,
515                     false, pt->rotate_inner_column_labels);
516
517   size_t *dindexes = XCALLOC (pt->n_dimensions, size_t);
518   size_t y = 0;
519   PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
520                               &pt->axes[PIVOT_AXIS_ROW])
521     {
522       size_t x = 0;
523       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
524                                   column_enumeration,
525                                   &pt->axes[PIVOT_AXIS_COLUMN])
526         {
527           pivot_table_convert_indexes_ptod (pt, pindexes, dindexes);
528           const struct pivot_value *value = pivot_table_get (pt, dindexes);
529           fill_cell (body, x + stub[H], y + stub[V], x + stub[H], y + stub[V],
530                      PIVOT_AREA_DATA, value, false);
531
532           x++;
533         }
534
535       y++;
536     }
537   free (dindexes);
538
539   if ((pt->corner_text || !pt->look->row_labels_in_corner)
540       && stub[H] && stub[V])
541     fill_cell (body, 0, 0, stub[H] - 1, stub[V] - 1,
542                PIVOT_AREA_CORNER, pt->corner_text, false);
543
544   if (body->n[H] && body->n[V])
545     {
546       table_hline (
547         body, get_table_rule (borders, PIVOT_BORDER_INNER_TOP),
548         0, body->n[H] - 1, 0);
549       table_hline (
550         body, get_table_rule (borders, PIVOT_BORDER_INNER_BOTTOM),
551         0, body->n[H] - 1, body->n[V]);
552       table_vline (
553         body, get_table_rule (borders, PIVOT_BORDER_INNER_LEFT),
554         0, 0, body->n[V] - 1);
555       table_vline (
556         body, get_table_rule (borders, PIVOT_BORDER_INNER_RIGHT),
557         body->n[H], 0, body->n[V] - 1);
558
559       if (stub[V])
560         table_hline (
561           body, get_table_rule (borders, PIVOT_BORDER_DATA_TOP),
562           0, body->n[H] - 1, stub[V]);
563       if (stub[H])
564         table_vline (
565           body, get_table_rule (borders, PIVOT_BORDER_DATA_LEFT),
566           stub[H], 0, body->n[V] - 1);
567
568     }
569   free (column_enumeration);
570   free (row_enumeration);
571
572   /* Title. */
573   struct table *title;
574   if (pt->title && pt->show_title && titlep)
575     {
576       title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
577       fill_cell (title, 0, 0, 0, 0, PIVOT_AREA_TITLE, pt->title, false);
578     }
579   else
580     title = NULL;
581
582   /* Layers. */
583   const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
584   int n_layers = 0;
585   if (layersp)
586     for (size_t i = 0; i < layer_axis->n_dimensions; i++)
587       {
588         const struct pivot_dimension *d = layer_axis->dimensions[i];
589         if (d->n_leaves)
590           n_layers++;
591       }
592
593   struct table *layers;
594   if (n_layers > 0)
595     {
596       layers = create_aux_table (pt, 1, n_layers, PIVOT_AREA_LAYERS);
597       size_t y = n_layers - 1;
598       for (size_t i = 0; i < layer_axis->n_dimensions; i++)
599         {
600           const struct pivot_dimension *d = layer_axis->dimensions[i];
601           if (!d->n_leaves)
602             continue;
603
604           struct string s = DS_EMPTY_INITIALIZER;
605           pivot_value_format (d->data_leaves[layer_indexes[i]]->name, pt, &s);
606           fill_cell_owned (layers, 0, y, 0, y, PIVOT_AREA_LAYERS, &s, false);
607           y--;
608         }
609     }
610   else
611     layers = NULL;
612
613   /* Caption. */
614   struct table *caption;
615   if (pt->caption && pt->show_caption && captionp)
616     {
617       caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
618       fill_cell (caption, 0, 0, 0, 0, PIVOT_AREA_CAPTION, pt->caption, false);
619     }
620   else
621     caption = NULL;
622
623   /* Footnotes. */
624   size_t nf;
625   struct pivot_footnote **f = collect_footnotes (pt, title, layers, body,
626                                                  caption, &nf);
627   struct table *footnotes;
628   if (nf && footnotesp)
629     {
630       footnotes = create_aux_table (pt, 1, nf, PIVOT_AREA_FOOTER);
631
632       for (size_t i = 0; i < nf; i++)
633         {
634           struct string s = DS_EMPTY_INITIALIZER;
635           pivot_footnote_format_marker (f[i], pt, &s);
636           ds_put_cstr (&s, ". ");
637           pivot_value_format (f[i]->content, pt, &s);
638           fill_cell_owned (footnotes, 0, i, 0, i, PIVOT_AREA_FOOTER, &s,
639                            false);
640         }
641     }
642   else
643     footnotes = NULL;
644
645   *titlep = title;
646   if (layersp)
647     *layersp = layers;
648   *bodyp = body;
649   if (captionp)
650     *captionp = caption;
651   if (footnotesp)
652     *footnotesp = footnotes;
653   if (fp)
654     {
655       *fp = f;
656       *nfp = nf;
657     }
658   else
659     free (f);
660 }
661
662 void
663 pivot_table_submit (struct pivot_table *pt)
664 {
665   output_item_submit (table_item_create (pt));
666 }