From 5c177572411cf2a48c8a9b8aa620bb8ea0ce7bf2 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 25 Dec 2019 23:13:35 +0000 Subject: [PATCH] table: Merge tab.c into table.c. --- src/output/automake.mk | 1 - src/output/tab.c | 544 ------------------------------------ src/output/tab.h | 7 - src/output/table.c | 606 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 540 insertions(+), 618 deletions(-) delete mode 100644 src/output/tab.c diff --git a/src/output/automake.mk b/src/output/automake.mk index 668a1c5fb3..cbdaa4fc7b 100644 --- a/src/output/automake.mk +++ b/src/output/automake.mk @@ -72,7 +72,6 @@ src_output_liboutput_la_SOURCES = \ src/output/pivot-table.h \ src/output/render.c \ src/output/render.h \ - src/output/tab.c \ src/output/tab.h \ src/output/table-item.c \ src/output/table-item.h \ diff --git a/src/output/tab.c b/src/output/tab.c deleted file mode 100644 index c7df7713e2..0000000000 --- a/src/output/tab.c +++ /dev/null @@ -1,544 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014, 2016 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include - -#include "output/tab.h" - -#include -#include -#include -#include - -#include "data/data-out.h" -#include "data/format.h" -#include "data/settings.h" -#include "data/value.h" -#include "data/variable.h" -#include "libpspp/assertion.h" -#include "libpspp/compiler.h" -#include "libpspp/i18n.h" -#include "libpspp/misc.h" -#include "libpspp/pool.h" -#include "output/driver.h" -#include "output/table-item.h" -#include "output/table-provider.h" -#include "output/text-item.h" - -#include "gl/minmax.h" -#include "gl/xalloc.h" - -#include "gettext.h" -#define _(msgid) gettext (msgid) - - -static const bool debugging = true; - -/* Joined cell. */ -struct tab_joined_cell -{ - int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */ - char *text; - - size_t n_footnotes; - const struct footnote **footnotes; - - const struct area_style *style; -}; - -/* Creates and returns a new table with NC columns and NR rows and initially no - header rows or columns. - - Sets the number of header rows on each side of TABLE to HL on the - left, HR on the right, HT on the top, HB on the bottom. Header rows - are repeated when a table is broken across multiple columns or - multiple pages. - - The table's cells are initially empty. */ -struct table * -tab_create (int nc, int nr, int hl, int hr, int ht, int hb) -{ - struct table *t; - - t = pool_create_container (struct table, container); - t->n[TABLE_HORZ] = nc; - t->n[TABLE_VERT] = nr; - t->h[TABLE_HORZ][0] = hl; - t->h[TABLE_HORZ][1] = hr; - t->h[TABLE_VERT][0] = ht; - t->h[TABLE_VERT][1] = hb; - t->ref_cnt = 1; - - t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc); - t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct); - - t->rh = pool_nmalloc (t->container, nc, nr + 1); - memset (t->rh, TAL_0, nc * (nr + 1)); - - t->rv = pool_nmalloc (t->container, nr, nc + 1); - memset (t->rv, TAL_0, nr * (nc + 1)); - - memset (t->styles, 0, sizeof t->styles); - memset (t->rule_colors, 0, sizeof t->rule_colors); - - return t; -} - -/* Rules. */ - -/* Draws a vertical line to the left of cells at horizontal position X - from Y1 to Y2 inclusive in style STYLE, if style is not -1. */ -void -tab_vline (struct table *t, int style, int x, int y1, int y2) -{ - if (debugging) - { - if (x < 0 || x > table_nc (t) - || y1 < 0 || y1 >= table_nr (t) - || y2 < 0 || y2 >= table_nr (t)) - { - printf (_("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n"), - x, y1, y2, table_nc (t), table_nr (t)); - return; - } - } - - assert (x >= 0); - assert (x <= table_nc (t)); - assert (y1 >= 0); - assert (y2 >= y1); - assert (y2 <= table_nr (t)); - - if (style != -1) - { - int y; - for (y = y1; y <= y2; y++) - t->rv[x + (table_nc (t) + 1) * y] = style; - } -} - -/* Draws a horizontal line above cells at vertical position Y from X1 - to X2 inclusive in style STYLE, if style is not -1. */ -void -tab_hline (struct table *t, int style, int x1, int x2, int y) -{ - if (debugging) - { - if (y < 0 || y > table_nr (t) - || x1 < 0 || x1 >= table_nc (t) - || x2 < 0 || x2 >= table_nc (t)) - { - printf (_("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n"), - x1, x2, y, table_nc (t), table_nr (t)); - return; - } - } - - assert (y >= 0); - assert (y <= table_nr (t)); - assert (x2 >= x1); - assert (x1 >= 0); - assert (x2 < table_nc (t)); - - if (style != -1) - { - int x; - for (x = x1; x <= x2; x++) - t->rh[x + table_nc (t) * y] = style; - } -} - -/* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal - lines of style F_H and vertical lines of style F_V. Fills the - interior of the box with horizontal lines of style I_H and vertical - lines of style I_V. Any of the line styles may be -1 to avoid - drawing those lines. This is distinct from 0, which draws a null - line. */ -void -tab_box (struct table *t, int f_h, int f_v, int i_h, int i_v, - int x1, int y1, int x2, int y2) -{ - if (debugging) - { - if (x1 < 0 || x1 >= table_nc (t) - || x2 < 0 || x2 >= table_nc (t) - || y1 < 0 || y1 >= table_nr (t) - || y2 < 0 || y2 >= table_nr (t)) - { - printf (_("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n"), - x1, y1, x2, y2, table_nc (t), table_nr (t)); - NOT_REACHED (); - } - } - - assert (x2 >= x1); - assert (y2 >= y1); - assert (x1 >= 0); - assert (y1 >= 0); - assert (x2 < table_nc (t)); - assert (y2 < table_nr (t)); - - if (f_h != -1) - { - int x; - for (x = x1; x <= x2; x++) - { - t->rh[x + table_nc (t) * y1] = f_h; - t->rh[x + table_nc (t) * (y2 + 1)] = f_h; - } - } - if (f_v != -1) - { - int y; - for (y = y1; y <= y2; y++) - { - t->rv[x1 + (table_nc (t) + 1) * y] = f_v; - t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v; - } - } - - if (i_h != -1) - { - int y; - - for (y = y1 + 1; y <= y2; y++) - { - int x; - - for (x = x1; x <= x2; x++) - t->rh[x + table_nc (t) * y] = i_h; - } - } - if (i_v != -1) - { - int x; - - for (x = x1 + 1; x <= x2; x++) - { - int y; - - for (y = y1; y <= y2; y++) - t->rv[x + (table_nc (t) + 1) * y] = i_v; - } - } -} - -/* Cells. */ - -static void -do_tab_text (struct table *table, int c, int r, unsigned opt, char *text) -{ - assert (c >= 0); - assert (r >= 0); - assert (c < table_nc (table)); - assert (r < table_nr (table)); - - if (debugging) - { - if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table)) - { - printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n", - c, r, table_nc (table), table_nr (table)); - return; - } - } - - table->cc[c + r * table_nc (table)] = text; - table->ct[c + r * table_nc (table)] = opt; -} - -/* Sets cell (C,R) in TABLE, with options OPT, to have text value - TEXT. */ -void -tab_text (struct table *table, int c, int r, unsigned opt, - const char *text) -{ - do_tab_text (table, c, r, opt, pool_strdup (table->container, text)); -} - -/* Sets cell (C,R) in TABLE, with options OPT, to have text value - FORMAT, which is formatted as if passed to printf. */ -void -tab_text_format (struct table *table, int c, int r, unsigned opt, - const char *format, ...) -{ - va_list args; - - va_start (args, format); - do_tab_text (table, c, r, opt, - pool_vasprintf (table->container, format, args)); - va_end (args); -} - -static struct tab_joined_cell * -add_joined_cell (struct table *table, int x1, int y1, int x2, int y2, - unsigned opt) -{ - struct tab_joined_cell *j; - - assert (x1 >= 0); - assert (y1 >= 0); - assert (y2 >= y1); - assert (x2 >= x1); - assert (y2 < table_nr (table)); - assert (x2 < table_nc (table)); - - if (debugging) - { - if (x1 < 0 || x1 >= table_nc (table) - || y1 < 0 || y1 >= table_nr (table) - || x2 < x1 || x2 >= table_nc (table) - || y2 < y1 || y2 >= table_nr (table)) - { - printf ("tab_joint_text(): bad cell " - "(%d,%d)-(%d,%d) in table size (%d,%d)\n", - x1, y1, x2, y2, table_nc (table), table_nr (table)); - return NULL; - } - } - - tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2); - - j = pool_alloc (table->container, sizeof *j); - j->d[TABLE_HORZ][0] = x1; - j->d[TABLE_VERT][0] = y1; - j->d[TABLE_HORZ][1] = ++x2; - j->d[TABLE_VERT][1] = ++y2; - j->n_footnotes = 0; - j->footnotes = NULL; - j->style = NULL; - - { - void **cc = &table->cc[x1 + y1 * table_nc (table)]; - unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)]; - const int ofs = table_nc (table) - (x2 - x1); - - int y; - - for (y = y1; y < y2; y++) - { - int x; - - for (x = x1; x < x2; x++) - { - *cc++ = j; - *ct++ = opt | TAB_JOIN; - } - - cc += ofs; - ct += ofs; - } - } - - return j; -} - -/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with - options OPT to have text value TEXT. */ -void -tab_joint_text (struct table *table, int x1, int y1, int x2, int y2, - unsigned opt, const char *text) -{ - char *s = pool_strdup (table->container, text); - if (x1 == x2 && y1 == y2) - do_tab_text (table, x1, y1, opt, s); - else - add_joined_cell (table, x1, y1, x2, y2, opt)->text = s; -} - -struct footnote * -tab_create_footnote (struct table *table, size_t idx, const char *content, - const char *marker, struct area_style *style) -{ - 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); - f->style = style; - return f; -} - -void -tab_add_footnote (struct table *table, int x, int y, - const struct footnote *f) -{ - int index = x + y * table_nc (table); - unsigned short opt = table->ct[index]; - struct tab_joined_cell *j; - - if (opt & TAB_JOIN) - j = table->cc[index]; - else - { - char *text = table->cc[index]; - - j = add_joined_cell (table, x, y, x, y, table->ct[index]); - j->text = text ? text : xstrdup (""); - } - - j->footnotes = pool_realloc (table->container, j->footnotes, - (j->n_footnotes + 1) * sizeof *j->footnotes); - - j->footnotes[j->n_footnotes++] = f; -} - -void -tab_add_style (struct table *table, int x, int y, - const struct area_style *style) -{ - int index = x + y * table_nc (table); - unsigned short opt = table->ct[index]; - struct tab_joined_cell *j; - - if (opt & TAB_JOIN) - j = table->cc[index]; - else - { - char *text = table->cc[index]; - - j = add_joined_cell (table, x, y, x, y, table->ct[index]); - j->text = text ? text : xstrdup (""); - } - - j->style = style; -} - -bool -tab_cell_is_empty (const struct table *table, int c, int r) -{ - return table->cc[c + r * table_nc (table)] == NULL; -} - -/* Editing. */ - -/* Writes STRING to the output. OPTIONS may be any valid combination of TAB_* - bits. - - This function is obsolete. Please do not add new uses of it. Instead, use - a text_item (see output/text-item.h). */ -void -tab_output_text (int options UNUSED, const char *string) -{ - text_item_submit (text_item_create (TEXT_ITEM_LOG, string)); -} - -/* Same as tab_output_text(), but FORMAT is passed through printf-like - formatting before output. */ -void -tab_output_text_format (int options, const char *format, ...) -{ - va_list args; - char *text; - - va_start (args, format); - text = xvasprintf (format, args); - va_end (args); - - tab_output_text (options, text); - - free (text); -} - -/* Table class implementation. */ - -void -tab_destroy (struct table *table) -{ - pool_destroy (table->container); -} - -void -tab_get_cell (const struct table *t, int x, int y, struct table_cell *cell) -{ - int index = x + y * table_nc (t); - unsigned short opt = t->ct[index]; - const void *cc = t->cc[index]; - - cell->options = opt; - cell->n_footnotes = 0; - - int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT; - const struct area_style *style = t->styles[style_idx]; - if (style) - cell->style = style; - else - { - static const struct area_style styles[3][3] = { -#define S(H,V) [H][V] = { AREA_STYLE_INITIALIZER__, \ - .cell_style.halign = H, \ - .cell_style.valign = V } - S(TABLE_HALIGN_LEFT, TABLE_VALIGN_TOP), - S(TABLE_HALIGN_LEFT, TABLE_VALIGN_CENTER), - S(TABLE_HALIGN_LEFT, TABLE_VALIGN_BOTTOM), - S(TABLE_HALIGN_CENTER, TABLE_VALIGN_TOP), - S(TABLE_HALIGN_CENTER, TABLE_VALIGN_CENTER), - S(TABLE_HALIGN_CENTER, TABLE_VALIGN_BOTTOM), - S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_TOP), - S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_CENTER), - S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_BOTTOM), - }; - - enum table_halign halign - = ((opt & TAB_HALIGN) == TAB_LEFT ? TABLE_HALIGN_LEFT - : (opt & TAB_HALIGN) == TAB_CENTER ? TABLE_HALIGN_CENTER - : TABLE_HALIGN_RIGHT); - enum table_valign valign - = ((opt & TAB_VALIGN) == TAB_TOP ? TABLE_VALIGN_TOP - : (opt & TAB_VALIGN) == TAB_MIDDLE ? TABLE_VALIGN_CENTER - : TABLE_VALIGN_BOTTOM); - - cell->style = &styles[halign][valign]; - } - - if (opt & TAB_JOIN) - { - const struct tab_joined_cell *jc = cc; - cell->text = jc->text; - - cell->footnotes = jc->footnotes; - cell->n_footnotes = jc->n_footnotes; - - cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0]; - cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1]; - cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0]; - cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1]; - - if (jc->style) - cell->style = jc->style; - } - else - { - cell->d[TABLE_HORZ][0] = x; - cell->d[TABLE_HORZ][1] = x + 1; - cell->d[TABLE_VERT][0] = y; - cell->d[TABLE_VERT][1] = y + 1; - cell->text = CONST_CAST (char *, cc ? cc : ""); - } -} - -int -tab_get_rule (const struct table *t, enum table_axis axis, int x, int y, - struct cell_color *color) -{ - uint8_t raw = (axis == TABLE_VERT - ? t->rh[x + table_nc (t) * y] - : t->rv[x + (table_nc (t) + 1) * y]); - struct cell_color *p = t->rule_colors[(raw & TAB_RULE_STYLE_MASK) - >> TAB_RULE_STYLE_SHIFT]; - if (p) - *color = *p; - return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT; -} diff --git a/src/output/tab.h b/src/output/tab.h index 9beefc73d4..fd8ccf4b97 100644 --- a/src/output/tab.h +++ b/src/output/tab.h @@ -67,12 +67,5 @@ void tab_output_text (int options, const char *string); void tab_output_text_format (int options, const char *, ...) PRINTF_FORMAT (2, 3); -/* For use by table-provider only. */ -struct table_cell; -void tab_destroy (struct table *); -void tab_get_cell (const struct table *, int x, int y, struct table_cell *); -int tab_get_rule (const struct table *, enum table_axis, int x, int y, - struct cell_color *); - #endif /* output/tab.h */ diff --git a/src/output/table.c b/src/output/table.c index 9c0286e6f5..1e3c53d256 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -31,6 +31,7 @@ #include "libpspp/str.h" #include "output/table-item.h" #include "output/tab.h" +#include "output/text-item.h" #include "gl/xalloc.h" @@ -54,7 +55,7 @@ table_unref (struct table *table) { assert (table->ref_cnt > 0); if (--table->ref_cnt == 0) - tab_destroy (table); + pool_destroy (table->container); } } @@ -86,71 +87,6 @@ area_style_free (struct area_style *style) } } -/* Initializes CELL with the contents of the table cell at column X and row Y - within TABLE. When CELL is no longer needed, the caller is responsible for - freeing it by calling table_cell_free(CELL). - - The caller must ensure that CELL is destroyed before TABLE is unref'ed. */ -void -table_get_cell (const struct table *table, int x, int y, - struct table_cell *cell) -{ - assert (x >= 0 && x < table->n[TABLE_HORZ]); - assert (y >= 0 && y < table->n[TABLE_VERT]); - - static const struct area_style default_style = AREA_STYLE_INITIALIZER; - cell->style = &default_style; - - tab_get_cell (table, x, y, cell); -} - -/* Returns one of the TAL_* enumeration constants (declared in output/table.h) - representing a rule running alongside one of the cells in TABLE. - - Suppose NC is the number of columns in TABLE and NR is the number of rows. - Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) = - (0,0), the return value is the rule that runs vertically on the left side of - cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and - cell (1,0); and so on, up to (NC,0), which runs vertically on the right of - cell (NC-1,0). - - The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ - within a 7x7 table. The '|' characters at the intersection of the X labels - and Y labels show the rule whose style would be returned by calling - table_get_rule with those X and Y values: - - 0 1 2 3 4 5 6 7 - +--+--+--+--+--+--+--+ - 0 | | | | | | | | - +--+--+--+--+--+--+--+ - 1 | | | | | | | | - +--+--+--+--+--+--+--+ - 2 | | | | | | | | - +--+--+--+--+--+--+--+ - 3 | | | | | | | | - +--+--+--+--+--+--+--+ - 4 | | | | | | | | - +--+--+--+--+--+--+--+ - 5 | | | | | | | | - +--+--+--+--+--+--+--+ - 6 | | | | | | | | - +--+--+--+--+--+--+--+ - - Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If - (X,Y) = (0,0), the return value is the rule that runs horizontally above - the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule - between that cell and cell (0,1); and so on, up to (0,NR), which runs - horizontally below cell (0,NR-1). */ -int -table_get_rule (const struct table *table, enum table_axis axis, int x, int y, - struct cell_color *color) -{ - assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ)); - assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT)); - *color = (struct cell_color) CELL_COLOR_BLACK; - return tab_get_rule (table, axis, x, y, color); -} - void table_cell_format_footnote_markers (const struct table_cell *cell, struct string *s) @@ -379,3 +315,541 @@ cell_style_dump (const struct cell_style *c) c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1], c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]); } + + +static const bool debugging = true; + +/* Joined cell. */ +struct tab_joined_cell +{ + int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */ + char *text; + + size_t n_footnotes; + const struct footnote **footnotes; + + const struct area_style *style; +}; + +/* Creates and returns a new table with NC columns and NR rows and initially no + header rows or columns. + + Sets the number of header rows on each side of TABLE to HL on the + left, HR on the right, HT on the top, HB on the bottom. Header rows + are repeated when a table is broken across multiple columns or + multiple pages. + + The table's cells are initially empty. */ +struct table * +tab_create (int nc, int nr, int hl, int hr, int ht, int hb) +{ + struct table *t; + + t = pool_create_container (struct table, container); + t->n[TABLE_HORZ] = nc; + t->n[TABLE_VERT] = nr; + t->h[TABLE_HORZ][0] = hl; + t->h[TABLE_HORZ][1] = hr; + t->h[TABLE_VERT][0] = ht; + t->h[TABLE_VERT][1] = hb; + t->ref_cnt = 1; + + t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc); + t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct); + + t->rh = pool_nmalloc (t->container, nc, nr + 1); + memset (t->rh, TAL_0, nc * (nr + 1)); + + t->rv = pool_nmalloc (t->container, nr, nc + 1); + memset (t->rv, TAL_0, nr * (nc + 1)); + + memset (t->styles, 0, sizeof t->styles); + memset (t->rule_colors, 0, sizeof t->rule_colors); + + return t; +} + +/* Rules. */ + +/* Draws a vertical line to the left of cells at horizontal position X + from Y1 to Y2 inclusive in style STYLE, if style is not -1. */ +void +tab_vline (struct table *t, int style, int x, int y1, int y2) +{ + if (debugging) + { + if (x < 0 || x > table_nc (t) + || y1 < 0 || y1 >= table_nr (t) + || y2 < 0 || y2 >= table_nr (t)) + { + printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n", + x, y1, y2, table_nc (t), table_nr (t)); + return; + } + } + + assert (x >= 0); + assert (x <= table_nc (t)); + assert (y1 >= 0); + assert (y2 >= y1); + assert (y2 <= table_nr (t)); + + if (style != -1) + { + int y; + for (y = y1; y <= y2; y++) + t->rv[x + (table_nc (t) + 1) * y] = style; + } +} + +/* Draws a horizontal line above cells at vertical position Y from X1 + to X2 inclusive in style STYLE, if style is not -1. */ +void +tab_hline (struct table *t, int style, int x1, int x2, int y) +{ + if (debugging) + { + if (y < 0 || y > table_nr (t) + || x1 < 0 || x1 >= table_nc (t) + || x2 < 0 || x2 >= table_nc (t)) + { + printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n", + x1, x2, y, table_nc (t), table_nr (t)); + return; + } + } + + assert (y >= 0); + assert (y <= table_nr (t)); + assert (x2 >= x1); + assert (x1 >= 0); + assert (x2 < table_nc (t)); + + if (style != -1) + { + int x; + for (x = x1; x <= x2; x++) + t->rh[x + table_nc (t) * y] = style; + } +} + +/* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal + lines of style F_H and vertical lines of style F_V. Fills the + interior of the box with horizontal lines of style I_H and vertical + lines of style I_V. Any of the line styles may be -1 to avoid + drawing those lines. This is distinct from 0, which draws a null + line. */ +void +tab_box (struct table *t, int f_h, int f_v, int i_h, int i_v, + int x1, int y1, int x2, int y2) +{ + if (debugging) + { + if (x1 < 0 || x1 >= table_nc (t) + || x2 < 0 || x2 >= table_nc (t) + || y1 < 0 || y1 >= table_nr (t) + || y2 < 0 || y2 >= table_nr (t)) + { + printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n", + x1, y1, x2, y2, table_nc (t), table_nr (t)); + NOT_REACHED (); + } + } + + assert (x2 >= x1); + assert (y2 >= y1); + assert (x1 >= 0); + assert (y1 >= 0); + assert (x2 < table_nc (t)); + assert (y2 < table_nr (t)); + + if (f_h != -1) + { + int x; + for (x = x1; x <= x2; x++) + { + t->rh[x + table_nc (t) * y1] = f_h; + t->rh[x + table_nc (t) * (y2 + 1)] = f_h; + } + } + if (f_v != -1) + { + int y; + for (y = y1; y <= y2; y++) + { + t->rv[x1 + (table_nc (t) + 1) * y] = f_v; + t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v; + } + } + + if (i_h != -1) + { + int y; + + for (y = y1 + 1; y <= y2; y++) + { + int x; + + for (x = x1; x <= x2; x++) + t->rh[x + table_nc (t) * y] = i_h; + } + } + if (i_v != -1) + { + int x; + + for (x = x1 + 1; x <= x2; x++) + { + int y; + + for (y = y1; y <= y2; y++) + t->rv[x + (table_nc (t) + 1) * y] = i_v; + } + } +} + +/* Cells. */ + +static void +do_tab_text (struct table *table, int c, int r, unsigned opt, char *text) +{ + assert (c >= 0); + assert (r >= 0); + assert (c < table_nc (table)); + assert (r < table_nr (table)); + + if (debugging) + { + if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table)) + { + printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n", + c, r, table_nc (table), table_nr (table)); + return; + } + } + + table->cc[c + r * table_nc (table)] = text; + table->ct[c + r * table_nc (table)] = opt; +} + +/* Sets cell (C,R) in TABLE, with options OPT, to have text value + TEXT. */ +void +tab_text (struct table *table, int c, int r, unsigned opt, + const char *text) +{ + do_tab_text (table, c, r, opt, pool_strdup (table->container, text)); +} + +/* Sets cell (C,R) in TABLE, with options OPT, to have text value + FORMAT, which is formatted as if passed to printf. */ +void +tab_text_format (struct table *table, int c, int r, unsigned opt, + const char *format, ...) +{ + va_list args; + + va_start (args, format); + do_tab_text (table, c, r, opt, + pool_vasprintf (table->container, format, args)); + va_end (args); +} + +static struct tab_joined_cell * +add_joined_cell (struct table *table, int x1, int y1, int x2, int y2, + unsigned opt) +{ + struct tab_joined_cell *j; + + assert (x1 >= 0); + assert (y1 >= 0); + assert (y2 >= y1); + assert (x2 >= x1); + assert (y2 < table_nr (table)); + assert (x2 < table_nc (table)); + + if (debugging) + { + if (x1 < 0 || x1 >= table_nc (table) + || y1 < 0 || y1 >= table_nr (table) + || x2 < x1 || x2 >= table_nc (table) + || y2 < y1 || y2 >= table_nr (table)) + { + printf ("tab_joint_text(): bad cell " + "(%d,%d)-(%d,%d) in table size (%d,%d)\n", + x1, y1, x2, y2, table_nc (table), table_nr (table)); + return NULL; + } + } + + tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2); + + j = pool_alloc (table->container, sizeof *j); + j->d[TABLE_HORZ][0] = x1; + j->d[TABLE_VERT][0] = y1; + j->d[TABLE_HORZ][1] = ++x2; + j->d[TABLE_VERT][1] = ++y2; + j->n_footnotes = 0; + j->footnotes = NULL; + j->style = NULL; + + { + void **cc = &table->cc[x1 + y1 * table_nc (table)]; + unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)]; + const int ofs = table_nc (table) - (x2 - x1); + + int y; + + for (y = y1; y < y2; y++) + { + int x; + + for (x = x1; x < x2; x++) + { + *cc++ = j; + *ct++ = opt | TAB_JOIN; + } + + cc += ofs; + ct += ofs; + } + } + + return j; +} + +/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with + options OPT to have text value TEXT. */ +void +tab_joint_text (struct table *table, int x1, int y1, int x2, int y2, + unsigned opt, const char *text) +{ + char *s = pool_strdup (table->container, text); + if (x1 == x2 && y1 == y2) + do_tab_text (table, x1, y1, opt, s); + else + add_joined_cell (table, x1, y1, x2, y2, opt)->text = s; +} + +struct footnote * +tab_create_footnote (struct table *table, size_t idx, const char *content, + const char *marker, struct area_style *style) +{ + 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); + f->style = style; + return f; +} + +void +tab_add_footnote (struct table *table, int x, int y, + const struct footnote *f) +{ + int index = x + y * table_nc (table); + unsigned short opt = table->ct[index]; + struct tab_joined_cell *j; + + if (opt & TAB_JOIN) + j = table->cc[index]; + else + { + char *text = table->cc[index]; + + j = add_joined_cell (table, x, y, x, y, table->ct[index]); + j->text = text ? text : xstrdup (""); + } + + j->footnotes = pool_realloc (table->container, j->footnotes, + (j->n_footnotes + 1) * sizeof *j->footnotes); + + j->footnotes[j->n_footnotes++] = f; +} + +void +tab_add_style (struct table *table, int x, int y, + const struct area_style *style) +{ + int index = x + y * table_nc (table); + unsigned short opt = table->ct[index]; + struct tab_joined_cell *j; + + if (opt & TAB_JOIN) + j = table->cc[index]; + else + { + char *text = table->cc[index]; + + j = add_joined_cell (table, x, y, x, y, table->ct[index]); + j->text = text ? text : xstrdup (""); + } + + j->style = style; +} + +bool +tab_cell_is_empty (const struct table *table, int c, int r) +{ + return table->cc[c + r * table_nc (table)] == NULL; +} + +/* Editing. */ + +/* Writes STRING to the output. OPTIONS may be any valid combination of TAB_* + bits. + + This function is obsolete. Please do not add new uses of it. Instead, use + a text_item (see output/text-item.h). */ +void +tab_output_text (int options UNUSED, const char *string) +{ + text_item_submit (text_item_create (TEXT_ITEM_LOG, string)); +} + +/* Same as tab_output_text(), but FORMAT is passed through printf-like + formatting before output. */ +void +tab_output_text_format (int options, const char *format, ...) +{ + va_list args; + char *text; + + va_start (args, format); + text = xvasprintf (format, args); + va_end (args); + + tab_output_text (options, text); + + free (text); +} + +/* Initializes CELL with the contents of the table cell at column X and row Y + within TABLE. When CELL is no longer needed, the caller is responsible for + freeing it by calling table_cell_free(CELL). + + The caller must ensure that CELL is destroyed before TABLE is unref'ed. */ +void +table_get_cell (const struct table *t, int x, int y, struct table_cell *cell) +{ + assert (x >= 0 && x < t->n[TABLE_HORZ]); + assert (y >= 0 && y < t->n[TABLE_VERT]); + + int index = x + y * table_nc (t); + unsigned short opt = t->ct[index]; + const void *cc = t->cc[index]; + + cell->options = opt; + cell->n_footnotes = 0; + + int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT; + const struct area_style *style = t->styles[style_idx]; + if (style) + cell->style = style; + else + { + static const struct area_style styles[3][3] = { +#define S(H,V) [H][V] = { AREA_STYLE_INITIALIZER__, \ + .cell_style.halign = H, \ + .cell_style.valign = V } + S(TABLE_HALIGN_LEFT, TABLE_VALIGN_TOP), + S(TABLE_HALIGN_LEFT, TABLE_VALIGN_CENTER), + S(TABLE_HALIGN_LEFT, TABLE_VALIGN_BOTTOM), + S(TABLE_HALIGN_CENTER, TABLE_VALIGN_TOP), + S(TABLE_HALIGN_CENTER, TABLE_VALIGN_CENTER), + S(TABLE_HALIGN_CENTER, TABLE_VALIGN_BOTTOM), + S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_TOP), + S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_CENTER), + S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_BOTTOM), + }; + + enum table_halign halign + = ((opt & TAB_HALIGN) == TAB_LEFT ? TABLE_HALIGN_LEFT + : (opt & TAB_HALIGN) == TAB_CENTER ? TABLE_HALIGN_CENTER + : TABLE_HALIGN_RIGHT); + enum table_valign valign + = ((opt & TAB_VALIGN) == TAB_TOP ? TABLE_VALIGN_TOP + : (opt & TAB_VALIGN) == TAB_MIDDLE ? TABLE_VALIGN_CENTER + : TABLE_VALIGN_BOTTOM); + + cell->style = &styles[halign][valign]; + } + + if (opt & TAB_JOIN) + { + const struct tab_joined_cell *jc = cc; + cell->text = jc->text; + + cell->footnotes = jc->footnotes; + cell->n_footnotes = jc->n_footnotes; + + cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0]; + cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1]; + cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0]; + cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1]; + + if (jc->style) + cell->style = jc->style; + } + else + { + cell->d[TABLE_HORZ][0] = x; + cell->d[TABLE_HORZ][1] = x + 1; + cell->d[TABLE_VERT][0] = y; + cell->d[TABLE_VERT][1] = y + 1; + cell->text = CONST_CAST (char *, cc ? cc : ""); + } +} + +/* Returns one of the TAL_* enumeration constants (declared in output/table.h) + representing a rule running alongside one of the cells in TABLE. + + Suppose NC is the number of columns in TABLE and NR is the number of rows. + Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) = + (0,0), the return value is the rule that runs vertically on the left side of + cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and + cell (1,0); and so on, up to (NC,0), which runs vertically on the right of + cell (NC-1,0). + + The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ + within a 7x7 table. The '|' characters at the intersection of the X labels + and Y labels show the rule whose style would be returned by calling + table_get_rule with those X and Y values: + + 0 1 2 3 4 5 6 7 + +--+--+--+--+--+--+--+ + 0 | | | | | | | | + +--+--+--+--+--+--+--+ + 1 | | | | | | | | + +--+--+--+--+--+--+--+ + 2 | | | | | | | | + +--+--+--+--+--+--+--+ + 3 | | | | | | | | + +--+--+--+--+--+--+--+ + 4 | | | | | | | | + +--+--+--+--+--+--+--+ + 5 | | | | | | | | + +--+--+--+--+--+--+--+ + 6 | | | | | | | | + +--+--+--+--+--+--+--+ + + Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If + (X,Y) = (0,0), the return value is the rule that runs horizontally above + the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule + between that cell and cell (0,1); and so on, up to (0,NR), which runs + horizontally below cell (0,NR-1). */ +int +table_get_rule (const struct table *table, enum table_axis axis, int x, int y, + struct cell_color *color) +{ + assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ)); + assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT)); + + uint8_t raw = (axis == TABLE_VERT + ? table->rh[x + table_nc (table) * y] + : table->rv[x + (table_nc (table) + 1) * y]); + struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK) + >> TAB_RULE_STYLE_SHIFT]; + *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK; + return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT; +} -- 2.30.2