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 *
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);
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];
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];
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 *
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)
{
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);
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)
{
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];
}
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
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 (
}
\f
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);
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];
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;
}
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];
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_;
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_;
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;
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;
}
\f
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)
{
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 ();
{
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);
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)
{
*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];
}
#include "output/table-item.h"
#include "output/table-provider.h"
+#include "gl/minmax.h"
#include "gl/xalloc.h"
#include "gl/xvasprintf.h"
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)
{
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++)
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);
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))
fputs ("\n<BR>", 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 ("<SUP>", 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), " ", "<BR>");
+ }
+ fputs ("</SUP>", 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),
+ " ", "<BR>");
+ 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 ("<TABLE>", 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), " ", "<BR>");
- }
- 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, "<SUP>%s</SUP> ", marker);
- escape_string (html->file, c->footnotes[i],
- strlen (c->footnotes[i]), " ", "<BR>");
- }
- }
-
- 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 ("<SUP>", html->file);
+ escape_string (html->file, f[i]->marker, strlen (f[i]->marker),
+ " ", "<BR>");
+ fputs ("</SUP> ", html->file);
+ escape_string (html->file, f[i]->content, strlen (f[i]->content),
+ " ", "<BR>");
+ }
+ free (f);
if (tfoot)
fputs ("</TD></TR></TFOOT>\n", html->file);
- footnote_idx = 0;
fputs ("<TBODY VALIGN=\"TOP\">\n", html->file);
- if (title != NULL)
+ const struct table_item_text *title = table_item_get_title (item);
+ if (title)
{
fputs (" <CAPTION>", html->file);
- escape_string (html->file, title, strlen (title), " ", "<BR>");
+ html_put_table_item_text (html, title);
fputs ("</CAPTION>\n", html->file);
}
for (c = cell.contents; c < &cell.contents[cell.n_contents]; c++)
{
const char *s = c->text;
- int i;
if (c->options & TAB_EMPH)
fputs ("<EM>", html->file);
if (c->options & TAB_EMPH)
fputs ("</EM>", html->file);
- if (c->n_footnotes > 0)
- {
- fputs ("<SUP>", 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 ("</SUP>", html->file);
- }
+ html_put_footnote_markers (html, c->footnotes, c->n_footnotes);
}
/* Output </TH> or </TD>. */
/* 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;
}
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);
}
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"));
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
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
return NULL;
}
\f
-/* 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 ();
-}
-\f
/* Row or column dimensions. Used to figure the size of a table in
render_page_create() and discarded after that. */
struct render_row
}
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;
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;
}
/* 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++)
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);
{
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));
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;
}
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));
}
}
}
- hmap_swap (&page->footnotes, &footnotes);
- hmap_destroy (&footnotes);
- page->n_footnotes = footnote_idx;
-
free (rules[H]);
free (rules[V]);
}
}
- 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. */
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);
}
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
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);
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;
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;
}
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
{
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,
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
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. */
u;
size_t n_footnotes;
- char **footnotes;
+ const struct footnote **footnotes;
};
static const struct table_class tab_table_class;
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
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];
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
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);
#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. */
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;
}
/* 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;
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;
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
#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,
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 *);
\f
/* This boilerplate for table_item, a subclass of output_item, was
autogenerated by mk-class-boilerplate. */
#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
{
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
{
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 */
#include "libpspp/cast.h"
#include "libpspp/compiler.h"
+#include "libpspp/str.h"
#include "output/table-item.h"
#include "gl/xalloc.h"
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;
+}
\f
struct table_unshared
{
}
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");
}
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",
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;