From: Ben Pfaff Date: Sat, 17 Nov 2018 04:42:13 +0000 (-0800) Subject: output: Expand footnote support. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp;a=commitdiff_plain;h=395cd4395449dbdff7c9ba0d56ba14529063d350 output: Expand footnote support. This adds support for multiple footnotes per table cell and the ability to add footnotes to titles and captions. --- diff --git a/src/output/ascii.c b/src/output/ascii.c index bb776d0c2a..507e758e3f 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -191,11 +191,11 @@ static bool ascii_open_page (struct ascii_driver *); static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2], enum render_line_style styles[TABLE_N_AXES][2]); static void ascii_measure_cell_width (void *, const struct table_cell *, - int footnote_idx, int *min, int *max); + int *min, int *max); static int ascii_measure_cell_height (void *, const struct table_cell *, - int footnote_idx, int width); + int width); static void ascii_draw_cell (void *, const struct table_cell *, - int footnote_idx, int bb[TABLE_N_AXES][2], + int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]); static struct ascii_driver * @@ -505,7 +505,6 @@ static char *ascii_reserve (struct ascii_driver *, int y, int x0, int x1, int n); static void ascii_layout_cell (struct ascii_driver *, const struct table_cell *, - int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *width, int *height); @@ -546,7 +545,7 @@ ascii_draw_line (void *a_, int bb[TABLE_N_AXES][2], static void ascii_measure_cell_width (void *a_, const struct table_cell *cell, - int footnote_idx, int *min_width, int *max_width) + int *min_width, int *max_width) { struct ascii_driver *a = a_; int bb[TABLE_N_AXES][2]; @@ -558,22 +557,21 @@ ascii_measure_cell_width (void *a_, const struct table_cell *cell, bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - ascii_layout_cell (a, cell, footnote_idx, bb, clip, max_width, &h); + ascii_layout_cell (a, cell, bb, clip, max_width, &h); if (cell->n_contents != 1 || cell->contents[0].n_footnotes || strchr (cell->contents[0].text, ' ')) { bb[H][1] = 1; - ascii_layout_cell (a, cell, footnote_idx, bb, clip, min_width, &h); + ascii_layout_cell (a, cell, bb, clip, min_width, &h); } else *min_width = *max_width; } static int -ascii_measure_cell_height (void *a_, const struct table_cell *cell, - int footnote_idx, int width) +ascii_measure_cell_height (void *a_, const struct table_cell *cell, int width) { struct ascii_driver *a = a_; int bb[TABLE_N_AXES][2]; @@ -585,18 +583,18 @@ ascii_measure_cell_height (void *a_, const struct table_cell *cell, bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - ascii_layout_cell (a, cell, footnote_idx, bb, clip, &w, &h); + ascii_layout_cell (a, cell, bb, clip, &w, &h); return h; } static void -ascii_draw_cell (void *a_, const struct table_cell *cell, int footnote_idx, +ascii_draw_cell (void *a_, const struct table_cell *cell, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]) { struct ascii_driver *a = a_; int w, h; - ascii_layout_cell (a, cell, footnote_idx, bb, clip, &w, &h); + ascii_layout_cell (a, cell, bb, clip, &w, &h); } static char * @@ -744,7 +742,7 @@ text_draw (struct ascii_driver *a, unsigned int options, static int ascii_layout_cell_text (struct ascii_driver *a, - const struct cell_contents *contents, int *footnote_idx, + const struct cell_contents *contents, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *widthp) { @@ -766,12 +764,7 @@ ascii_layout_cell_text (struct ascii_driver *a, ds_extend (&s, length + contents->n_footnotes * 4); ds_put_cstr (&s, contents->text); for (i = 0; i < contents->n_footnotes; i++) - { - char marker[10]; - - str_format_26adic (++*footnote_idx, false, marker, sizeof marker); - ds_put_format (&s, "[%s]", marker); - } + ds_put_format (&s, "[%s]", contents->footnotes[i]->marker); length = ds_length (&s); text = ds_steal_cstr (&s); @@ -868,7 +861,6 @@ ascii_layout_cell_text (struct ascii_driver *a, static void ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell, - int footnote_idx, int bb_[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *widthp, int *heightp) { @@ -891,8 +883,7 @@ ascii_layout_cell (struct ascii_driver *a, const struct table_cell *cell, break; } - bb[V][0] = ascii_layout_cell_text (a, contents, &footnote_idx, - bb, clip, widthp); + bb[V][0] = ascii_layout_cell_text (a, contents, bb, clip, widthp); } *heightp = bb[V][0] - bb_[V][0]; } @@ -902,28 +893,28 @@ ascii_test_write (struct output_driver *driver, const char *s, int x, int y, unsigned int options) { struct ascii_driver *a = ascii_driver_cast (driver); - struct cell_contents contents; - struct table_cell cell; int bb[TABLE_N_AXES][2]; int width, height; if (a->file == NULL && !ascii_open_page (a)) return; - contents.options = options | TAB_LEFT; - contents.text = CONST_CAST (char *, s); - contents.n_footnotes = 0; + struct cell_contents contents = { + .options = options | TAB_LEFT, + .text = CONST_CAST (char *, s), + }; - memset (&cell, 0, sizeof cell); - cell.contents = &contents; - cell.n_contents = 1; + struct table_cell cell = { + .contents = &contents, + .n_contents = 1, + }; bb[TABLE_HORZ][0] = x; bb[TABLE_HORZ][1] = a->width; bb[TABLE_VERT][0] = y; bb[TABLE_VERT][1] = INT_MAX; - ascii_layout_cell (a, &cell, 0, bb, bb, &width, &height); + ascii_layout_cell (a, &cell, bb, bb, &width, &height); } void diff --git a/src/output/cairo.c b/src/output/cairo.c index 745c16e1eb..c0a2b5ee0f 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -163,13 +163,13 @@ static void xr_driver_run_fsm (struct xr_driver *); static void xr_draw_line (void *, int bb[TABLE_N_AXES][2], enum render_line_style styles[TABLE_N_AXES][2]); static void xr_measure_cell_width (void *, const struct table_cell *, - int footnote_idx, int *min, int *max); + int *min, int *max); static int xr_measure_cell_height (void *, const struct table_cell *, - int footnote_idx, int width); -static void xr_draw_cell (void *, const struct table_cell *, int footnote_idx, + int width); +static void xr_draw_cell (void *, const struct table_cell *, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]); -static int xr_adjust_break (void *, const struct table_cell *, int footnote_idx, +static int xr_adjust_break (void *, const struct table_cell *, int width, int height); static struct xr_render_fsm *xr_render_output_item ( @@ -635,7 +635,7 @@ xr_driver_run_fsm (struct xr_driver *xr) } static void -xr_layout_cell (struct xr_driver *, const struct table_cell *, int footnote_idx, +xr_layout_cell (struct xr_driver *, const struct table_cell *, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *width, int *height, int *brk); @@ -813,7 +813,7 @@ xr_draw_line (void *xr_, int bb[TABLE_N_AXES][2], static void xr_measure_cell_width (void *xr_, const struct table_cell *cell, - int footnote_idx, int *min_width, int *max_width) + int *min_width, int *max_width) { struct xr_driver *xr = xr_; int bb[TABLE_N_AXES][2]; @@ -825,10 +825,10 @@ xr_measure_cell_width (void *xr_, const struct table_cell *cell, bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, footnote_idx, bb, clip, max_width, &h, NULL); + xr_layout_cell (xr, cell, bb, clip, max_width, &h, NULL); bb[H][1] = 1; - xr_layout_cell (xr, cell, footnote_idx, bb, clip, min_width, &h, NULL); + xr_layout_cell (xr, cell, bb, clip, min_width, &h, NULL); if (*min_width > 0) *min_width += xr->cell_margin * 2; @@ -837,8 +837,7 @@ xr_measure_cell_width (void *xr_, const struct table_cell *cell, } static int -xr_measure_cell_height (void *xr_, const struct table_cell *cell, - int footnote_idx, int width) +xr_measure_cell_height (void *xr_, const struct table_cell *cell, int width) { struct xr_driver *xr = xr_; int bb[TABLE_N_AXES][2]; @@ -850,12 +849,12 @@ xr_measure_cell_height (void *xr_, const struct table_cell *cell, bb[V][0] = 0; bb[V][1] = INT_MAX; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, NULL); + xr_layout_cell (xr, cell, bb, clip, &w, &h, NULL); return h; } static void -xr_draw_cell (void *xr_, const struct table_cell *cell, int footnote_idx, +xr_draw_cell (void *xr_, const struct table_cell *cell, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]) { struct xr_driver *xr = xr_; @@ -865,11 +864,11 @@ xr_draw_cell (void *xr_, const struct table_cell *cell, int footnote_idx, bb[H][1] -= xr->cell_margin; if (bb[H][0] >= bb[H][1]) return; - xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk); + xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); } static int -xr_adjust_break (void *xr_, const struct table_cell *cell, int footnote_idx, +xr_adjust_break (void *xr_, const struct table_cell *cell, int width, int height) { struct xr_driver *xr = xr_; @@ -877,7 +876,7 @@ xr_adjust_break (void *xr_, const struct table_cell *cell, int footnote_idx, int clip[TABLE_N_AXES][2]; int w, h, brk; - if (xr_measure_cell_height (xr_, cell, footnote_idx, width) < height) + if (xr_measure_cell_height (xr_, cell, width) < height) return -1; bb[H][0] = 0; @@ -887,7 +886,7 @@ xr_adjust_break (void *xr_, const struct table_cell *cell, int footnote_idx, bb[V][0] = 0; bb[V][1] = height; clip[H][0] = clip[H][1] = clip[V][0] = clip[V][1] = 0; - xr_layout_cell (xr, cell, footnote_idx, bb, clip, &w, &h, &brk); + xr_layout_cell (xr, cell, bb, clip, &w, &h, &brk); return brk; } @@ -915,7 +914,7 @@ add_attr_with_start (PangoAttrList *list, PangoAttribute *attr, guint start_inde static int xr_layout_cell_text (struct xr_driver *xr, - const struct cell_contents *contents, int footnote_idx, + const struct cell_contents *contents, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *widthp, int *brk) { @@ -930,11 +929,10 @@ xr_layout_cell_text (struct xr_driver *xr, else if (contents->n_footnotes == 1 && (options & TAB_ALIGNMENT) == TAB_RIGHT) { PangoAttrList *attrs; - char marker[16]; font = &xr->fonts[XR_FONT_MARKER]; - str_format_26adic (footnote_idx + 1, false, marker, sizeof marker); + const char *marker = contents->footnotes[0]->marker; pango_layout_set_text (font->layout, marker, strlen (marker)); attrs = pango_attr_list_new (); @@ -971,22 +969,13 @@ xr_layout_cell_text (struct xr_driver *xr, { PangoAttrList *attrs; struct string s; - size_t i; bb[H][1] += xr->cell_margin; ds_init_empty (&s); ds_extend (&s, length + contents->n_footnotes * 10); ds_put_cstr (&s, contents->text); - for (i = 0; i < contents->n_footnotes; i++) - { - char marker[16]; - - if (i > 0) - ds_put_byte (&s, ','); - str_format_26adic (footnote_idx + i + 1, false, marker, sizeof marker); - ds_put_cstr (&s, marker); - } + cell_contents_format_footnote_markers (contents, &s); pango_layout_set_text (font->layout, ds_cstr (&s), ds_length (&s)); ds_destroy (&s); @@ -1105,7 +1094,6 @@ xr_layout_cell_text (struct xr_driver *xr, static void xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell, - int footnote_idx, int bb_[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2], int *width, int *height, int *brk) { @@ -1151,9 +1139,7 @@ xr_layout_cell (struct xr_driver *xr, const struct table_cell *cell, *brk = bb[V][0]; } - bb[V][0] = xr_layout_cell_text (xr, contents, footnote_idx, bb, clip, - width, brk); - footnote_idx += contents->n_footnotes; + bb[V][0] = xr_layout_cell_text (xr, contents, bb, clip, width, brk); } *height = bb[V][0] - bb_[V][0]; } diff --git a/src/output/csv.c b/src/output/csv.c index ef49759566..763d191372 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -33,6 +33,7 @@ #include "output/table-item.h" #include "output/table-provider.h" +#include "gl/minmax.h" #include "gl/xalloc.h" #include "gl/xvasprintf.h" @@ -163,6 +164,29 @@ csv_output_field_format (struct csv_driver *csv, const char *format, ...) free (s); } +static void +csv_format_footnotes (const struct footnote **f, size_t n, struct string *s) +{ + for (size_t i = 0; i < n; i++) + ds_put_format (s, "[%s]", f[i]->marker); +} + +static void +csv_output_table_item_text (struct csv_driver *csv, + const struct table_item_text *text, + const char *leader) +{ + if (!text) + return; + + struct string s = DS_EMPTY_INITIALIZER; + ds_put_format (&s, "%s: %s", leader, text->content); + csv_format_footnotes (text->footnotes, text->n_footnotes, &s); + csv_output_field (csv, ds_cstr (&s)); + ds_destroy (&s); + putc ('\n', csv->file); +} + static void csv_put_separator (struct csv_driver *csv) { @@ -179,21 +203,15 @@ csv_submit (struct output_driver *driver, if (is_table_item (output_item)) { struct table_item *table_item = to_table_item (output_item); - const char *title = table_item_get_title (table_item); - const char *caption = table_item_get_caption (table_item); const struct table *t = table_item_get_table (table_item); - int footnote_idx; int x, y; csv_put_separator (csv); - if (csv->titles && title != NULL) - { - csv_output_field_format (csv, "Table: %s", title); - putc ('\n', csv->file); - } + if (csv->titles) + csv_output_table_item_text (csv, table_item_get_title (table_item), + "Table"); - footnote_idx = 0; for (y = 0; y < table_nr (t); y++) { for (x = 0; x < table_nc (t); x++) @@ -220,21 +238,12 @@ csv_submit (struct output_driver *driver, for (i = 0; i < cell.n_contents; i++) { const struct cell_contents *c = &cell.contents[i]; - int j; if (i > 0) ds_put_cstr (&s, "\n\n"); ds_put_cstr (&s, c->text); - - for (j = 0; j < c->n_footnotes; j++) - { - char marker[16]; - - str_format_26adic (++footnote_idx, false, - marker, sizeof marker); - ds_put_format (&s, "[%s]", marker); - } + csv_format_footnotes (c->footnotes, c->n_footnotes, &s); } csv_output_field (csv, ds_cstr (&s)); ds_destroy (&s); @@ -245,47 +254,26 @@ csv_submit (struct output_driver *driver, putc ('\n', csv->file); } - if (csv->captions && caption != NULL) - { - csv_output_field_format (csv, "Caption: %s", caption); - putc ('\n', csv->file); - } + if (csv->captions) + csv_output_table_item_text (csv, table_item_get_caption (table_item), + "Caption"); - if (footnote_idx) + const struct footnote **f; + size_t n_footnotes = table_collect_footnotes (table_item, &f); + if (n_footnotes) { - size_t i; - fputs ("\nFootnotes:\n", csv->file); - footnote_idx = 0; - for (y = 0; y < table_nr (t); y++) - { - struct table_cell cell; - for (x = 0; x < table_nc (t); 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]) - for (i = 0; i < cell.n_contents; i++) - { - const struct cell_contents *c = &cell.contents[i]; - int j; - - for (j = 0; j < c->n_footnotes; j++) - { - char marker[16]; - - str_format_26adic (++footnote_idx, false, - marker, sizeof marker); - csv_output_field (csv, marker); - fputs (csv->separator, csv->file); - csv_output_field (csv, c->footnotes[j]); - putc ('\n', csv->file); - } - } - table_cell_free (&cell); - } - } + for (size_t i = 0; i < n_footnotes; i++) + if (f[i]) + { + csv_output_field (csv, f[i]->marker); + fputs (csv->separator, csv->file); + csv_output_field (csv, f[i]->content); + putc ('\n', csv->file); + } + + free (f); } } else if (is_text_item (output_item)) diff --git a/src/output/html.c b/src/output/html.c index e79cd8afea..55bcb6daa0 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -382,67 +382,76 @@ put_tfoot (struct html_driver *html, const struct table *t, bool *tfoot) fputs ("\n
", html->file); } +static void +html_put_footnote_markers (struct html_driver *html, + const struct footnote **footnotes, + size_t n_footnotes) +{ + if (n_footnotes > 0) + { + fputs ("", html->file); + for (size_t i = 0; i < n_footnotes; i++) + { + const struct footnote *f = footnotes[i]; + + if (i > 0) + putc (',', html->file); + escape_string (html->file, f->marker, + strlen (f->marker), " ", "
"); + } + fputs ("
", html->file); + } +} + +static void +html_put_table_item_text (struct html_driver *html, + const struct table_item_text *text) +{ + escape_string (html->file, text->content, strlen (text->content), + " ", "
"); + html_put_footnote_markers (html, text->footnotes, text->n_footnotes); +} + static void html_output_table (struct html_driver *html, const struct table_item *item) { const struct table *t = table_item_get_table (item); - const char *title = table_item_get_title (item); - const char *caption = table_item_get_caption (item); - int footnote_idx = 0; bool tfoot = false; int y; fputs ("", html->file); + const struct table_item_text *caption = table_item_get_caption (item); if (caption) { put_tfoot (html, t, &tfoot); - escape_string (html->file, caption, strlen (caption), " ", "
"); - } - footnote_idx = 0; - for (y = 0; y < table_nr (t); y++) - { - int x; - for (x = 0; x < table_nc (t); ) - { - const struct cell_contents *c; - struct table_cell cell; - - table_get_cell (t, x, y, &cell); - if (y != cell.d[TABLE_VERT][0]) - goto next_0; - - for (c = cell.contents; c < &cell.contents[cell.n_contents]; c++) - { - int i; - - for (i = 0; i < c->n_footnotes; i++) - { - char marker[16]; - - put_tfoot (html, t, &tfoot); - str_format_26adic (++footnote_idx, false, marker, sizeof marker); - fprintf (html->file, "%s ", marker); - escape_string (html->file, c->footnotes[i], - strlen (c->footnotes[i]), " ", "
"); - } - } - - next_0: - x = cell.d[TABLE_HORZ][1]; - table_cell_free (&cell); - } + html_put_table_item_text (html, caption); } + const struct footnote **f; + size_t n_footnotes = table_collect_footnotes (item, &f); + + for (size_t i = 0; i < n_footnotes; i++) + if (f[i]) + { + put_tfoot (html, t, &tfoot); + fputs ("", html->file); + escape_string (html->file, f[i]->marker, strlen (f[i]->marker), + " ", "
"); + fputs ("
", html->file); + escape_string (html->file, f[i]->content, strlen (f[i]->content), + " ", "
"); + } + free (f); if (tfoot) fputs ("\n", html->file); - footnote_idx = 0; fputs ("\n", html->file); - if (title != NULL) + const struct table_item_text *title = table_item_get_title (item); + if (title) { fputs (" \n", html->file); } @@ -524,7 +533,6 @@ html_output_table (struct html_driver *html, const struct table_item *item) for (c = cell.contents; c < &cell.contents[cell.n_contents]; c++) { const char *s = c->text; - int i; if (c->options & TAB_EMPH) fputs ("", html->file); @@ -542,21 +550,7 @@ html_output_table (struct html_driver *html, const struct table_item *item) if (c->options & TAB_EMPH) fputs ("", html->file); - if (c->n_footnotes > 0) - { - fputs ("", html->file); - for (i = 0; i < c->n_footnotes; i++) - { - char marker[16]; - - if (i > 0) - putc (',', html->file); - str_format_26adic (++footnote_idx, false, - marker, sizeof marker); - fputs (marker, html->file); - } - fputs ("", html->file); - } + html_put_footnote_markers (html, c->footnotes, c->n_footnotes); } /* Output or . */ diff --git a/src/output/odt.c b/src/output/odt.c index 1d11594a15..153cd393c1 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -69,9 +69,6 @@ struct odt_driver /* Number of tables so far. */ int table_num; - - /* Number of footnotes so far. */ - int n_footnotes; }; static const struct output_driver_class odt_driver_class; @@ -422,30 +419,43 @@ write_xml_with_line_breaks (struct odt_driver *odt, const char *line_) } static void -write_footnote (struct odt_driver *odt, const char *footnote) +write_footnote (struct odt_driver *odt, const struct footnote *f) { - char marker[16]; - xmlTextWriterStartElement (odt->content_wtr, _xml("text:note")); xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:note-class"), _xml("footnote")); xmlTextWriterStartElement (odt->content_wtr, _xml("text:note-citation")); - str_format_26adic (++odt->n_footnotes, false, marker, sizeof marker); - if (strlen (marker) > 1) + if (strlen (f->marker) > 1) xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("text:label"), - "(%s)", marker); + "(%s)", f->marker); else xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:label"), - _xml(marker)); + _xml(f->marker)); xmlTextWriterEndElement (odt->content_wtr); xmlTextWriterStartElement (odt->content_wtr, _xml("text:note-body")); xmlTextWriterStartElement (odt->content_wtr, _xml("text:p")); - write_xml_with_line_breaks (odt, footnote); + write_xml_with_line_breaks (odt, f->content); + xmlTextWriterEndElement (odt->content_wtr); xmlTextWriterEndElement (odt->content_wtr); + xmlTextWriterEndElement (odt->content_wtr); +} +static void +write_table_item_text (struct odt_driver *odt, + const struct table_item_text *text) +{ + if (!text) + return; + + xmlTextWriterStartElement (odt->content_wtr, _xml("text:h")); + xmlTextWriterWriteFormatAttribute (odt->content_wtr, + _xml("text:outline-level"), "%d", 2); + xmlTextWriterWriteString (odt->content_wtr, _xml (text->content) ); + for (size_t i = 0; i < text->n_footnotes; i++) + write_footnote (odt, text->footnotes[i]); xmlTextWriterEndElement (odt->content_wtr); } @@ -453,20 +463,10 @@ static void write_table (struct odt_driver *odt, const struct table_item *item) { const struct table *tab = table_item_get_table (item); - const char *caption = table_item_get_caption (item); - const char *title = table_item_get_title (item); int r, c; /* Write a heading for the table */ - if (title != NULL) - { - xmlTextWriterStartElement (odt->content_wtr, _xml("text:h")); - xmlTextWriterWriteFormatAttribute (odt->content_wtr, - _xml("text:outline-level"), "%d", 2); - xmlTextWriterWriteString (odt->content_wtr, - _xml (table_item_get_title (item)) ); - xmlTextWriterEndElement (odt->content_wtr); - } + write_table_item_text (odt, table_item_get_title (item)); /* Start table */ xmlTextWriterStartElement (odt->content_wtr, _xml("table:table")); @@ -556,16 +556,7 @@ write_table (struct odt_driver *odt, const struct table_item *item) xmlTextWriterEndElement (odt->content_wtr); /* table */ /* Write a caption for the table */ - if (caption != NULL) - { - xmlTextWriterStartElement (odt->content_wtr, _xml("text:h")); - xmlTextWriterWriteFormatAttribute (odt->content_wtr, - _xml("text:outline-level"), "%d", 2); - xmlTextWriterWriteString (odt->content_wtr, - _xml (table_item_get_caption (item)) ); - xmlTextWriterEndElement (odt->content_wtr); - } - + write_table_item_text (odt, table_item_get_caption (item)); } static void diff --git a/src/output/render.c b/src/output/render.c index 6c7f3bca51..84ef8c1d35 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -94,15 +94,6 @@ struct render_page entire page can overflow on all four sides!) */ struct hmap overflows; - /* Contains "struct render_footnote"s, one for each cell with one or more - footnotes. - - 'n_footnotes' is the number of footnotes in the table. There might be - more than hmap_count(&page->footnotes) because there can be more than - one footnote in a cell. */ - struct hmap footnotes; - size_t n_footnotes; - /* If a single column (or row) is too wide (or tall) to fit on a page reasonably, then render_break_next() will split a single row or column across multiple render_pages. This member indicates when this has @@ -339,55 +330,6 @@ find_overflow (const struct render_page *page, int x, int y) return NULL; } -/* A footnote. */ -struct render_footnote - { - struct hmap_node node; - - /* The area of the table covered by the cell that has the footnote. - - d[H][0] is the leftmost column. - d[H][1] is the rightmost column, plus 1. - d[V][0] is the top row. - d[V][1] is the bottom row, plus 1. - - The cell in its original table might occupy a larger region. This - member reflects the size of the cell in the current render_page, after - trimming off any rows or columns due to page-breaking. */ - int d[TABLE_N_AXES][2]; - - /* The index of the first footnote in the cell. */ - int idx; - }; - -static int -count_footnotes (const struct table_cell *cell) -{ - size_t i; - int n; - - n = 0; - for (i = 0; i < cell->n_contents; i++) - n += cell->contents[i].n_footnotes; - return n; -} - -static int -find_footnote_idx (const struct table_cell *cell, const struct hmap *footnotes) -{ - const struct render_footnote *f; - - if (!count_footnotes (cell)) - return 0; - - HMAP_FOR_EACH_WITH_HASH (f, struct render_footnote, node, - hash_cell (cell->d[H][0], cell->d[V][0]), footnotes) - if (f->d[H][0] == cell->d[H][0] && f->d[V][0] == cell->d[V][0]) - return f->idx; - - NOT_REACHED (); -} - /* Row or column dimensions. Used to figure the size of a table in render_page_create() and discarded after that. */ struct render_row @@ -592,8 +534,6 @@ render_page_allocate (const struct render_params *params, } hmap_init (&page->overflows); - hmap_init (&page->footnotes); - page->n_footnotes = 0; memset (page->is_edge_cutoff, 0, sizeof page->is_edge_cutoff); return page; @@ -683,8 +623,6 @@ render_page_create (const struct render_params *params, struct table *table) struct render_row *rows; int table_widths[2]; int *rules[TABLE_N_AXES]; - struct hmap footnotes; - int footnote_idx; int nr, nc; int x, y; int i; @@ -705,9 +643,7 @@ render_page_create (const struct render_params *params, struct table *table) } /* Calculate minimum and maximum widths of cells that do not - span multiple columns. Assign footnote markers. */ - hmap_init (&footnotes); - footnote_idx = 0; + span multiple columns. */ for (i = 0; i < 2; i++) columns[i] = xzalloc (nc * sizeof *columns[i]); for (y = 0; y < nr; y++) @@ -718,33 +654,17 @@ render_page_create (const struct render_params *params, struct table *table) table_get_cell (table, x, y, &cell); if (y == cell.d[V][0]) { - int n; - if (table_cell_colspan (&cell) == 1) { int w[2]; int i; - params->measure_cell_width (params->aux, &cell, footnote_idx, + params->measure_cell_width (params->aux, &cell, &w[MIN], &w[MAX]); for (i = 0; i < 2; i++) if (columns[i][x].unspanned < w[i]) columns[i][x].unspanned = w[i]; } - - n = count_footnotes (&cell); - if (n > 0) - { - struct render_footnote *f = xmalloc (sizeof *f); - f->d[H][0] = cell.d[H][0]; - f->d[H][1] = cell.d[H][1]; - f->d[V][0] = cell.d[V][0]; - f->d[V][1] = cell.d[V][1]; - f->idx = footnote_idx; - hmap_insert (&footnotes, &f->node, hash_cell (x, y)); - - footnote_idx += n; - } } x = cell.d[H][1]; table_cell_free (&cell); @@ -764,9 +684,7 @@ render_page_create (const struct render_params *params, struct table *table) { int w[2]; - params->measure_cell_width (params->aux, &cell, - find_footnote_idx (&cell, &footnotes), - &w[MIN], &w[MAX]); + params->measure_cell_width (params->aux, &cell, &w[MIN], &w[MAX]); for (i = 0; i < 2; i++) distribute_spanned_width (w[i], &columns[i][cell.d[H][0]], rules[H], table_cell_colspan (&cell)); @@ -822,8 +740,7 @@ render_page_create (const struct render_params *params, struct table *table) if (table_cell_rowspan (&cell) == 1) { int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]); - int h = params->measure_cell_height ( - params->aux, &cell, find_footnote_idx (&cell, &footnotes), w); + int h = params->measure_cell_height (params->aux, &cell, w); if (h > r->unspanned) r->unspanned = r->width = h; } @@ -850,8 +767,7 @@ render_page_create (const struct render_params *params, struct table *table) if (y == cell.d[V][0] && table_cell_rowspan (&cell) > 1) { int w = joined_width (page, H, cell.d[H][0], cell.d[H][1]); - int h = params->measure_cell_height ( - params->aux, &cell, find_footnote_idx (&cell, &footnotes), w); + int h = params->measure_cell_height (params->aux, &cell, w); distribute_spanned_width (h, &rows[cell.d[V][0]], rules[V], table_cell_rowspan (&cell)); } @@ -876,10 +792,6 @@ render_page_create (const struct render_params *params, struct table *table) } } - hmap_swap (&page->footnotes, &footnotes); - hmap_destroy (&footnotes); - page->n_footnotes = footnote_idx; - free (rules[H]); free (rules[V]); @@ -1077,8 +989,7 @@ render_cell (const struct render_page *page, const int ofs[TABLE_N_AXES], } } - page->params->draw_cell (page->params->aux, cell, - find_footnote_idx (cell, &page->footnotes), bb, clip); + page->params->draw_cell (page->params->aux, cell, bb, clip); } /* Draws the cells of PAGE indicated in BB. */ @@ -1338,8 +1249,7 @@ render_break_next (struct render_break *b, int size) table_get_cell (page->table, x, z, &cell); w = joined_width (page, H, cell.d[H][0], cell.d[H][1]); better_pixel = page->params->adjust_break ( - page->params->aux, &cell, - find_footnote_idx (&cell, &page->footnotes), w, pixel); + page->params->aux, &cell, w, pixel); x = cell.d[H][1]; table_cell_free (&cell); @@ -1464,49 +1374,38 @@ render_pager_start_page (struct render_pager *p) } static void -add_footnote_page (struct render_pager *p, const struct render_page *body) +add_footnote_page (struct render_pager *p, const struct table_item *item) { - const struct table *table = body->table; - int nc = table_nc (table); - int nr = table_nr (table); - int footnote_idx = 0; - struct tab_table *t; - int x, y; - - if (!body->n_footnotes) + const struct footnote **f; + size_t n_footnotes = table_collect_footnotes (item, &f); + if (!n_footnotes) return; - t = tab_create (2, body->n_footnotes); - for (y = 0; y < nr; y++) - for (x = 0; x < nc; ) - { - struct table_cell cell; + struct tab_table *t = tab_create (2, n_footnotes); - table_get_cell (table, x, y, &cell); - if (y == cell.d[V][0]) - { - size_t i; - - for (i = 0; i < cell.n_contents; i++) - { - const struct cell_contents *cc = &cell.contents[i]; - size_t j; - - for (j = 0; j < cc->n_footnotes; j++) - { - const char *f = cc->footnotes[j]; - - tab_text (t, 0, footnote_idx, TAB_LEFT, ""); - tab_footnote (t, 0, footnote_idx, "(none)"); - tab_text (t, 1, footnote_idx, TAB_LEFT, f); - footnote_idx++; - } - } - } - x = cell.d[H][1]; - table_cell_free (&cell); + for (size_t i = 0; i < n_footnotes; i++) + if (f[i]) + { + tab_text (t, 0, i, TAB_LEFT, ""); + tab_add_footnote (t, 0, i, f[i]); + tab_text (t, 1, i, TAB_LEFT, f[i]->content); } render_pager_add_table (p, &t->table); + + free (f); +} + +static void +add_text_page (struct render_pager *p, const struct table_item_text *t) +{ + if (!t) + return; + + struct tab_table *tab = tab_create (1, 1); + tab_text (tab, 0, 0, TAB_LEFT, t->content); + for (size_t i = 0; i < t->n_footnotes; i++) + tab_add_footnote (tab, 0, 0, t->footnotes[i]); + render_pager_add_table (p, &tab->table); } /* Creates and returns a new render_pager for rendering TABLE_ITEM on the @@ -1515,28 +1414,22 @@ struct render_pager * render_pager_create (const struct render_params *params, const struct table_item *table_item) { - const char *caption = table_item_get_caption (table_item); - const char *title = table_item_get_title (table_item); - const struct render_page *body_page; struct render_pager *p; p = xzalloc (sizeof *p); p->params = params; /* Title. */ - if (title) - render_pager_add_table (p, table_from_string (TAB_LEFT, title)); + add_text_page (p, table_item_get_title (table_item)); /* Body. */ - body_page = render_pager_add_table (p, table_ref (table_item_get_table ( - table_item))); + render_pager_add_table (p, table_ref (table_item_get_table (table_item))); /* Caption. */ - if (caption) - render_pager_add_table (p, table_from_string (TAB_LEFT, caption)); + add_text_page (p, table_item_get_caption (table_item)); /* Footnotes. */ - add_footnote_page (p, body_page); + add_footnote_page (p, table_item); render_pager_start_page (p); @@ -1727,7 +1620,6 @@ static struct render_page * render_page_select (const struct render_page *page, enum table_axis axis, int z0, int p0, int z1, int p1) { - const struct render_footnote *f; struct render_page_selection s; enum table_axis a = axis; enum table_axis b = !a; @@ -1894,21 +1786,6 @@ render_page_select (const struct render_page *page, enum table_axis axis, table_cell_free (&cell); } - /* Copy footnotes from PAGE into subpage. */ - HMAP_FOR_EACH (f, struct render_footnote, node, &page->footnotes) - if ((f->d[a][0] >= z0 && f->d[a][0] < z1) - || (f->d[a][1] - 1 >= z0 && f->d[a][1] - 1 < z1)) - { - struct render_footnote *nf = xmalloc (sizeof *nf); - nf->d[a][0] = MAX (z0, f->d[a][0]) - z0 + page->h[a][0]; - nf->d[a][1] = MIN (z1, f->d[a][1]) - z0 + page->h[a][0]; - nf->d[b][0] = f->d[b][0]; - nf->d[b][1] = f->d[b][1]; - nf->idx = f->idx; - hmap_insert (&subpage->footnotes, &nf->node, - hash_cell (nf->d[H][0], nf->d[V][0])); - } - return subpage; } diff --git a/src/output/render.h b/src/output/render.h index d1f085fb2c..365c8036d4 100644 --- a/src/output/render.h +++ b/src/output/render.h @@ -51,14 +51,6 @@ enum render_line_style For each of the callback functions, AUX is passed as the 'aux' member of the render_params structure. - - The device is expected to transform numerical footnote index numbers into - footnote markers. The existing drivers use str_format_26adic() to transform - index 0 to "a", index 1 to "b", and so on. The FOOTNOTE_IDX supplied to - each function is the footnote index number for the first footnote in the - cell. If a cell contains more than one footnote, then the additional - footnote indexes increase sequentially, e.g. the second footnote has index - FOOTNOTE_IDX + 1. */ struct render_params { @@ -68,12 +60,11 @@ struct render_params minimum width required to avoid line breaks other than at new-lines. */ void (*measure_cell_width) (void *aux, const struct table_cell *cell, - int footnote_idx, int *min_width, int *max_width); /* Returns the height required to render CELL given a width of WIDTH. */ int (*measure_cell_height) (void *aux, const struct table_cell *cell, - int footnote_idx, int width); + int width); /* Given that there is space measuring WIDTH by HEIGHT to render CELL, where HEIGHT is insufficient to render the entire height of the cell, @@ -86,7 +77,7 @@ struct render_params Optional. If NULL, the rendering engine assumes that all breakpoints are acceptable. */ int (*adjust_break) (void *aux, const struct table_cell *cell, - int footnote_idx, int width, int height); + int width, int height); /* Draws a generalized intersection of lines in the rectangle whose top-left corner is (BB[TABLE_HORZ][0], BB[TABLE_VERT][0]) and whose @@ -106,7 +97,6 @@ struct render_params of the cell that lies within CLIP should actually be drawn, although BB should used to determine the layout of the cell. */ void (*draw_cell) (void *aux, const struct table_cell *cell, - int footnote_idx, int bb[TABLE_N_AXES][2], int clip[TABLE_N_AXES][2]); /* Auxiliary data passed to each of the above functions. */ diff --git a/src/output/tab.c b/src/output/tab.c index af43d6c2bc..dcd6fe29a2 100644 --- a/src/output/tab.c +++ b/src/output/tab.c @@ -66,7 +66,7 @@ struct tab_joined_cell u; size_t n_footnotes; - char **footnotes; + const struct footnote **footnotes; }; static const struct table_class tab_table_class; @@ -593,7 +593,10 @@ tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2, unsigned opt, const char *text) { char *s = pool_strdup (table->container, text); - add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s; + if (x1 == x2 && y1 == y2) + do_tab_text (table, x1, y1, opt, s); + else + add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s; } /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them @@ -613,13 +616,24 @@ tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s; } +struct footnote * +tab_create_footnote (struct tab_table *table, size_t idx, const char *content, + const char *marker) +{ + struct footnote *f = pool_alloc (table->container, sizeof *f); + f->idx = idx; + f->content = pool_strdup (table->container, content); + f->marker = pool_strdup (table->container, marker); + return f; +} + void -tab_footnote (struct tab_table *table, int x, int y, const char *format, ...) +tab_add_footnote (struct tab_table *table, int x, int y, + const struct footnote *f) { int index = x + y * table->cf; unsigned char opt = table->ct[index]; struct tab_joined_cell *j; - va_list args; if (opt & TAB_JOIN) j = table->cc[index]; @@ -631,13 +645,10 @@ tab_footnote (struct tab_table *table, int x, int y, const char *format, ...) j->u.text = text ? text : xstrdup (""); } - j->footnotes = xrealloc (j->footnotes, - (j->n_footnotes + 1) * sizeof *j->footnotes); + j->footnotes = pool_realloc (table->container, j->footnotes, + (j->n_footnotes + 1) * sizeof *j->footnotes); - va_start (args, format); - j->footnotes[j->n_footnotes++] = - pool_vasprintf (table->container, format, args); - va_end (args); + j->footnotes[j->n_footnotes++] = f; } bool diff --git a/src/output/tab.h b/src/output/tab.h index 3109e39439..00d8fab93c 100644 --- a/src/output/tab.h +++ b/src/output/tab.h @@ -143,8 +143,10 @@ void tab_joint_text_format (struct tab_table *, int x1, int y1, int x2, int y2, unsigned opt, const char *, ...) PRINTF_FORMAT (7, 8); -void tab_footnote (struct tab_table *, int x, int y, const char *format, ...) - PRINTF_FORMAT (4, 5); +struct footnote *tab_create_footnote (struct tab_table *, size_t idx, + const char *content, const char *marker); +void tab_add_footnote (struct tab_table *, int x, int y, + const struct footnote *); bool tab_cell_is_empty (const struct tab_table *, int c, int r); diff --git a/src/output/table-item.c b/src/output/table-item.c index c9fd0a62a7..645d8ca45f 100644 --- a/src/output/table-item.c +++ b/src/output/table-item.c @@ -28,6 +28,44 @@ #include "gl/xalloc.h" +struct table_item_text * +table_item_text_create (const char *content) +{ + if (!content) + return NULL; + + struct table_item_text *text = xmalloc (sizeof *text); + *text = (struct table_item_text) { .content = xstrdup (content) }; + return text; +} + +struct table_item_text * +table_item_text_clone (const struct table_item_text *old) +{ + if (!old) + return NULL; + + struct table_item_text *new = xmalloc (sizeof *new); + *new = (struct table_item_text) { + .content = xstrdup (old->content), + .footnotes = xmemdup (old->footnotes, + old->n_footnotes * sizeof *old->footnotes), + .n_footnotes = old->n_footnotes, + }; + return new; +} + +void +table_item_text_destroy (struct table_item_text *text) +{ + if (text) + { + free (text->content); + free (text->footnotes); + free (text); + } +} + /* Initializes ITEM as a table item for rendering TABLE. The new table item initially has the specified TITLE and CAPTION, which may each be NULL. The caller retains ownership of TITLE and CAPTION. */ @@ -37,8 +75,8 @@ table_item_create (struct table *table, const char *title, const char *caption) struct table_item *item = xmalloc (sizeof *item); output_item_init (&item->output_item, &table_item_class); item->table = table; - item->title = title != NULL ? xstrdup (title) : NULL; - item->caption = caption != NULL ? xstrdup (caption) : NULL; + item->title = table_item_text_create (title); + item->caption = table_item_text_create (caption); return item; } @@ -52,7 +90,7 @@ table_item_get_table (const struct table_item *table_item) /* Returns ITEM's title, which is a null pointer if no title has been set. */ -const char * +const struct table_item_text * table_item_get_title (const struct table_item *item) { return item->title; @@ -63,16 +101,17 @@ table_item_get_title (const struct table_item *item) This function may only be used on a table_item that is unshared. */ void -table_item_set_title (struct table_item *item, const char *title) +table_item_set_title (struct table_item *item, + const struct table_item_text *title) { assert (!table_item_is_shared (item)); - free (item->title); - item->title = title != NULL ? xstrdup (title) : NULL; + table_item_text_destroy (item->title); + item->title = table_item_text_clone (title); } /* Returns ITEM's caption, which is a null pointer if no caption has been set. */ -const char * +const struct table_item_text * table_item_get_caption (const struct table_item *item) { return item->caption; @@ -84,11 +123,12 @@ table_item_get_caption (const struct table_item *item) This function may only be used on a table_item that is unshared. */ void -table_item_set_caption (struct table_item *item, const char *caption) +table_item_set_caption (struct table_item *item, + const struct table_item_text *caption) { assert (!table_item_is_shared (item)); - free (item->caption); - item->caption = caption != NULL ? xstrdup (caption) : NULL; + table_item_text_destroy (item->caption); + item->caption = table_item_text_clone (caption); } /* Submits TABLE_ITEM to the configured output drivers, and transfers ownership diff --git a/src/output/table-item.h b/src/output/table-item.h index 855324416f..4e070ddabf 100644 --- a/src/output/table-item.h +++ b/src/output/table-item.h @@ -28,16 +28,28 @@ #include "libpspp/compiler.h" #include "output/output-item.h" +/* Title or caption in a table item. */ +struct table_item_text + { + char *content; + const struct footnote **footnotes; + size_t n_footnotes; + }; + +struct table_item_text *table_item_text_create (const char *); +struct table_item_text *table_item_text_clone (const struct table_item_text *); +void table_item_text_destroy (struct table_item_text *); + /* A table item. The members of struct table_item should not be accessed directly. Use one of the accessor functions defined below. */ struct table_item { - struct output_item output_item; /* Superclass. */ - struct table *table; /* The table to be rendered. */ - char *title; /* May be null if there is no title. */ - char *caption; /* May be null if there is no caption. */ + struct output_item output_item; /* Superclass. */ + struct table *table; /* The table to be rendered. */ + struct table_item_text *title; /* Null if there is no title. */ + struct table_item_text *caption; /* Null if there is no caption. */ }; struct table_item *table_item_create (struct table *, const char *title, @@ -45,11 +57,14 @@ struct table_item *table_item_create (struct table *, const char *title, const struct table *table_item_get_table (const struct table_item *); -const char *table_item_get_title (const struct table_item *); -void table_item_set_title (struct table_item *, const char *); +const struct table_item_text *table_item_get_title (const struct table_item *); +void table_item_set_title (struct table_item *, + const struct table_item_text *); -const char *table_item_get_caption (const struct table_item *); -void table_item_set_caption (struct table_item *, const char *); +const struct table_item_text *table_item_get_caption ( + const struct table_item *); +void table_item_set_caption (struct table_item *, + const struct table_item_text *); /* This boilerplate for table_item, a subclass of output_item, was autogenerated by mk-class-boilerplate. */ diff --git a/src/output/table-provider.h b/src/output/table-provider.h index 5dbf99b15a..a511e13bd5 100644 --- a/src/output/table-provider.h +++ b/src/output/table-provider.h @@ -19,6 +19,15 @@ #include "output/table.h" +struct string; + +struct footnote + { + size_t idx; + char *content; + char *marker; + }; + /* An item of contents within a table cell. */ struct cell_contents { @@ -26,10 +35,13 @@ struct cell_contents char *text; /* A paragraph of text. */ /* Optional footnote(s). */ - char **footnotes; + const struct footnote **footnotes; size_t n_footnotes; }; +void cell_contents_format_footnote_markers (const struct cell_contents *, + struct string *); + /* A cell in a table. */ struct table_cell { @@ -194,5 +206,7 @@ void table_set_nr (struct table *, int nr); void table_get_cell (const struct table *, int x, int y, struct table_cell *); int table_get_rule (const struct table *, enum table_axis, int x, int y); +size_t table_collect_footnotes (const struct table_item *, + const struct footnote ***); #endif /* output/table-provider.h */ diff --git a/src/output/table.c b/src/output/table.c index 2158ca723e..7f37479984 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -24,6 +24,7 @@ #include "libpspp/cast.h" #include "libpspp/compiler.h" +#include "libpspp/str.h" #include "output/table-item.h" #include "gl/xalloc.h" @@ -195,6 +196,80 @@ table_get_rule (const struct table *table, enum table_axis axis, int x, int y) assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT)); return table->klass->get_rule (table, axis, x, y); } + +void +cell_contents_format_footnote_markers (const struct cell_contents *c, + struct string *s) +{ + for (size_t i = 0; i < c->n_footnotes; i++) + { + if (i) + ds_put_byte (s, ','); + ds_put_cstr (s, c->footnotes[i]->marker); + } +} + +static const struct footnote ** +add_footnotes (const struct footnote **refs, size_t n_refs, + const struct footnote **footnotes, size_t *allocated, size_t *n) +{ + for (size_t i = 0; i < n_refs; i++) + { + const 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; +} + +size_t +table_collect_footnotes (const struct table_item *item, + const struct footnote ***footnotesp) +{ + const struct footnote **footnotes = NULL; + size_t allocated = 0; + size_t n = 0; + + struct table *t = item->table; + for (int y = 0; y < table_nr (t); y++) + { + struct table_cell cell; + for (int x = 0; x < table_nc (t); 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]) + for (size_t i = 0; i < cell.n_contents; i++) + { + const struct cell_contents *c = &cell.contents[i]; + footnotes = add_footnotes (c->footnotes, c->n_footnotes, + footnotes, &allocated, &n); + } + table_cell_free (&cell); + } + } + + const struct table_item_text *title = table_item_get_title (item); + if (title) + footnotes = add_footnotes (title->footnotes, title->n_footnotes, + footnotes, &allocated, &n); + + const struct table_item_text *caption = table_item_get_caption (item); + if (caption) + footnotes = add_footnotes (caption->footnotes, caption->n_footnotes, + footnotes, &allocated, &n); + + *footnotesp = footnotes; + return n; +} struct table_unshared { diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index f30914135a..dd8618f733 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -369,9 +369,10 @@ psppire_output_view_put (struct psppire_output_view *view, } else if (is_table_item (item)) { - const char *title = table_item_get_title (to_table_item (item)); + const struct table_item_text *title + = table_item_get_title (to_table_item (item)); if (title != NULL) - ds_put_format (&name, "Table: %s", title); + ds_put_format (&name, "Table: %s", title->content); else ds_put_cstr (&name, "Table"); } diff --git a/tests/output/render-test.c b/tests/output/render-test.c index 03e4238e41..2a874d1c91 100644 --- a/tests/output/render-test.c +++ b/tests/output/render-test.c @@ -353,6 +353,7 @@ read_table (FILE *stream) int n_input = 0; int nr, nc, hl, hr, ht, hb; int r, c; + size_t n_footnotes = 0; if (fgets (buffer, sizeof buffer, stream) == NULL || (n_input = sscanf (buffer, "%d %d %d %d %d %d", @@ -454,7 +455,13 @@ read_table (FILE *stream) tab_joint_text (tab, c, r, c + cs - 1, r + rs - 1, opt, content); else - tab_footnote (tab, c, r, "%s", content); + { + char marker[2] = { 'a' + n_footnotes, '\0' }; + struct footnote *f = tab_create_footnote ( + tab, n_footnotes, content, marker); + tab_add_footnote (tab, c, r, f); + n_footnotes++; + } } return &tab->table;
", html->file); - escape_string (html->file, title, strlen (title), " ", "
"); + html_put_table_item_text (html, title); fputs ("