1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014, 2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/tab.h"
26 #include "data/data-out.h"
27 #include "data/format.h"
28 #include "data/settings.h"
29 #include "data/value.h"
30 #include "data/variable.h"
31 #include "libpspp/assertion.h"
32 #include "libpspp/compiler.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/misc.h"
35 #include "libpspp/pool.h"
36 #include "output/driver.h"
37 #include "output/table-item.h"
38 #include "output/table-provider.h"
39 #include "output/text-item.h"
41 #include "gl/minmax.h"
42 #include "gl/xalloc.h"
45 #define _(msgid) gettext (msgid)
48 static const bool debugging = true;
51 struct tab_joined_cell
53 int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */
57 const struct footnote **footnotes;
59 const struct area_style *style;
62 /* Creates and returns a new table with NC columns and NR rows and initially no
63 header rows or columns.
65 Sets the number of header rows on each side of TABLE to HL on the
66 left, HR on the right, HT on the top, HB on the bottom. Header rows
67 are repeated when a table is broken across multiple columns or
70 The table's cells are initially empty. */
72 tab_create (int nc, int nr, int hl, int hr, int ht, int hb)
76 t = pool_create_container (struct table, container);
77 t->n[TABLE_HORZ] = nc;
78 t->n[TABLE_VERT] = nr;
79 t->h[TABLE_HORZ][0] = hl;
80 t->h[TABLE_HORZ][1] = hr;
81 t->h[TABLE_VERT][0] = ht;
82 t->h[TABLE_VERT][1] = hb;
85 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
86 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
88 t->rh = pool_nmalloc (t->container, nc, nr + 1);
89 memset (t->rh, TAL_0, nc * (nr + 1));
91 t->rv = pool_nmalloc (t->container, nr, nc + 1);
92 memset (t->rv, TAL_0, nr * (nc + 1));
94 memset (t->styles, 0, sizeof t->styles);
95 memset (t->rule_colors, 0, sizeof t->rule_colors);
102 /* Draws a vertical line to the left of cells at horizontal position X
103 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
105 tab_vline (struct table *t, int style, int x, int y1, int y2)
109 if (x < 0 || x > table_nc (t)
110 || y1 < 0 || y1 >= table_nr (t)
111 || y2 < 0 || y2 >= table_nr (t))
113 printf (_("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n"),
114 x, y1, y2, table_nc (t), table_nr (t));
120 assert (x <= table_nc (t));
123 assert (y2 <= table_nr (t));
128 for (y = y1; y <= y2; y++)
129 t->rv[x + (table_nc (t) + 1) * y] = style;
133 /* Draws a horizontal line above cells at vertical position Y from X1
134 to X2 inclusive in style STYLE, if style is not -1. */
136 tab_hline (struct table *t, int style, int x1, int x2, int y)
140 if (y < 0 || y > table_nr (t)
141 || x1 < 0 || x1 >= table_nc (t)
142 || x2 < 0 || x2 >= table_nc (t))
144 printf (_("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n"),
145 x1, x2, y, table_nc (t), table_nr (t));
151 assert (y <= table_nr (t));
154 assert (x2 < table_nc (t));
159 for (x = x1; x <= x2; x++)
160 t->rh[x + table_nc (t) * y] = style;
164 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
165 lines of style F_H and vertical lines of style F_V. Fills the
166 interior of the box with horizontal lines of style I_H and vertical
167 lines of style I_V. Any of the line styles may be -1 to avoid
168 drawing those lines. This is distinct from 0, which draws a null
171 tab_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
172 int x1, int y1, int x2, int y2)
176 if (x1 < 0 || x1 >= table_nc (t)
177 || x2 < 0 || x2 >= table_nc (t)
178 || y1 < 0 || y1 >= table_nr (t)
179 || y2 < 0 || y2 >= table_nr (t))
181 printf (_("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n"),
182 x1, y1, x2, y2, table_nc (t), table_nr (t));
191 assert (x2 < table_nc (t));
192 assert (y2 < table_nr (t));
197 for (x = x1; x <= x2; x++)
199 t->rh[x + table_nc (t) * y1] = f_h;
200 t->rh[x + table_nc (t) * (y2 + 1)] = f_h;
206 for (y = y1; y <= y2; y++)
208 t->rv[x1 + (table_nc (t) + 1) * y] = f_v;
209 t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v;
217 for (y = y1 + 1; y <= y2; y++)
221 for (x = x1; x <= x2; x++)
222 t->rh[x + table_nc (t) * y] = i_h;
229 for (x = x1 + 1; x <= x2; x++)
233 for (y = y1; y <= y2; y++)
234 t->rv[x + (table_nc (t) + 1) * y] = i_v;
242 do_tab_text (struct table *table, int c, int r, unsigned opt, char *text)
246 assert (c < table_nc (table));
247 assert (r < table_nr (table));
251 if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table))
253 printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n",
254 c, r, table_nc (table), table_nr (table));
259 table->cc[c + r * table_nc (table)] = text;
260 table->ct[c + r * table_nc (table)] = opt;
263 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
266 tab_text (struct table *table, int c, int r, unsigned opt,
269 do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
272 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
273 FORMAT, which is formatted as if passed to printf. */
275 tab_text_format (struct table *table, int c, int r, unsigned opt,
276 const char *format, ...)
280 va_start (args, format);
281 do_tab_text (table, c, r, opt,
282 pool_vasprintf (table->container, format, args));
286 static struct tab_joined_cell *
287 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
290 struct tab_joined_cell *j;
296 assert (y2 < table_nr (table));
297 assert (x2 < table_nc (table));
301 if (x1 < 0 || x1 >= table_nc (table)
302 || y1 < 0 || y1 >= table_nr (table)
303 || x2 < x1 || x2 >= table_nc (table)
304 || y2 < y1 || y2 >= table_nr (table))
306 printf ("tab_joint_text(): bad cell "
307 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
308 x1, y1, x2, y2, table_nc (table), table_nr (table));
313 tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
315 j = pool_alloc (table->container, sizeof *j);
316 j->d[TABLE_HORZ][0] = x1;
317 j->d[TABLE_VERT][0] = y1;
318 j->d[TABLE_HORZ][1] = ++x2;
319 j->d[TABLE_VERT][1] = ++y2;
325 void **cc = &table->cc[x1 + y1 * table_nc (table)];
326 unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)];
327 const int ofs = table_nc (table) - (x2 - x1);
331 for (y = y1; y < y2; y++)
335 for (x = x1; x < x2; x++)
338 *ct++ = opt | TAB_JOIN;
349 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
350 options OPT to have text value TEXT. */
352 tab_joint_text (struct table *table, int x1, int y1, int x2, int y2,
353 unsigned opt, const char *text)
355 char *s = pool_strdup (table->container, text);
356 if (x1 == x2 && y1 == y2)
357 do_tab_text (table, x1, y1, opt, s);
359 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
363 tab_create_footnote (struct table *table, size_t idx, const char *content,
364 const char *marker, struct area_style *style)
366 struct footnote *f = pool_alloc (table->container, sizeof *f);
368 f->content = pool_strdup (table->container, content);
369 f->marker = pool_strdup (table->container, marker);
375 tab_add_footnote (struct table *table, int x, int y,
376 const struct footnote *f)
378 int index = x + y * table_nc (table);
379 unsigned short opt = table->ct[index];
380 struct tab_joined_cell *j;
383 j = table->cc[index];
386 char *text = table->cc[index];
388 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
389 j->text = text ? text : xstrdup ("");
392 j->footnotes = pool_realloc (table->container, j->footnotes,
393 (j->n_footnotes + 1) * sizeof *j->footnotes);
395 j->footnotes[j->n_footnotes++] = f;
399 tab_add_style (struct table *table, int x, int y,
400 const struct area_style *style)
402 int index = x + y * table_nc (table);
403 unsigned short opt = table->ct[index];
404 struct tab_joined_cell *j;
407 j = table->cc[index];
410 char *text = table->cc[index];
412 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
413 j->text = text ? text : xstrdup ("");
420 tab_cell_is_empty (const struct table *table, int c, int r)
422 return table->cc[c + r * table_nc (table)] == NULL;
427 /* Writes STRING to the output. OPTIONS may be any valid combination of TAB_*
430 This function is obsolete. Please do not add new uses of it. Instead, use
431 a text_item (see output/text-item.h). */
433 tab_output_text (int options UNUSED, const char *string)
435 text_item_submit (text_item_create (TEXT_ITEM_LOG, string));
438 /* Same as tab_output_text(), but FORMAT is passed through printf-like
439 formatting before output. */
441 tab_output_text_format (int options, const char *format, ...)
446 va_start (args, format);
447 text = xvasprintf (format, args);
450 tab_output_text (options, text);
455 /* Table class implementation. */
458 tab_destroy (struct table *table)
460 pool_destroy (table->container);
464 tab_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
466 int index = x + y * table_nc (t);
467 unsigned short opt = t->ct[index];
468 const void *cc = t->cc[index];
471 cell->n_footnotes = 0;
473 int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT;
474 const struct area_style *style = t->styles[style_idx];
479 static const struct area_style styles[3][3] = {
480 #define S(H,V) [H][V] = { AREA_STYLE_INITIALIZER__, \
481 .cell_style.halign = H, \
482 .cell_style.valign = V }
483 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_TOP),
484 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_CENTER),
485 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_BOTTOM),
486 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_TOP),
487 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_CENTER),
488 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_BOTTOM),
489 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_TOP),
490 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_CENTER),
491 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_BOTTOM),
494 enum table_halign halign
495 = ((opt & TAB_HALIGN) == TAB_LEFT ? TABLE_HALIGN_LEFT
496 : (opt & TAB_HALIGN) == TAB_CENTER ? TABLE_HALIGN_CENTER
497 : TABLE_HALIGN_RIGHT);
498 enum table_valign valign
499 = ((opt & TAB_VALIGN) == TAB_TOP ? TABLE_VALIGN_TOP
500 : (opt & TAB_VALIGN) == TAB_MIDDLE ? TABLE_VALIGN_CENTER
501 : TABLE_VALIGN_BOTTOM);
503 cell->style = &styles[halign][valign];
508 const struct tab_joined_cell *jc = cc;
509 cell->text = jc->text;
511 cell->footnotes = jc->footnotes;
512 cell->n_footnotes = jc->n_footnotes;
514 cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
515 cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
516 cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
517 cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
520 cell->style = jc->style;
524 cell->d[TABLE_HORZ][0] = x;
525 cell->d[TABLE_HORZ][1] = x + 1;
526 cell->d[TABLE_VERT][0] = y;
527 cell->d[TABLE_VERT][1] = y + 1;
528 cell->text = CONST_CAST (char *, cc ? cc : "");
533 tab_get_rule (const struct table *t, enum table_axis axis, int x, int y,
534 struct cell_color *color)
536 uint8_t raw = (axis == TABLE_VERT
537 ? t->rh[x + table_nc (t) * y]
538 : t->rv[x + (table_nc (t) + 1) * y]);
539 struct cell_color *p = t->rule_colors[(raw & TAB_RULE_STYLE_MASK)
540 >> TAB_RULE_STYLE_SHIFT];
543 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;