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;
52 #define TAB_JOIN (1u << TAB_FIRST_AVAILABLE)
55 struct tab_joined_cell
57 int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */
61 const struct footnote **footnotes;
63 const struct area_style *style;
66 /* Creates and returns a new table with NC columns and NR rows and initially no
67 header rows or columns.
69 Sets the number of header rows on each side of TABLE to HL on the
70 left, HR on the right, HT on the top, HB on the bottom. Header rows
71 are repeated when a table is broken across multiple columns or
74 The table's cells are initially empty. */
76 tab_create (int nc, int nr, int hl, int hr, int ht, int hb)
80 t = pool_create_container (struct tab_table, container);
81 t->table.n[TABLE_HORZ] = nc;
82 t->table.n[TABLE_VERT] = nr;
83 t->table.h[TABLE_HORZ][0] = hl;
84 t->table.h[TABLE_HORZ][1] = hr;
85 t->table.h[TABLE_VERT][0] = ht;
86 t->table.h[TABLE_VERT][1] = hb;
89 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
90 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
92 t->rh = pool_nmalloc (t->container, nc, nr + 1);
93 memset (t->rh, TAL_0, nc * (nr + 1));
95 t->rv = pool_nmalloc (t->container, nr, nc + 1);
96 memset (t->rv, TAL_0, nr * (nc + 1));
98 memset (t->styles, 0, sizeof t->styles);
99 memset (t->rule_colors, 0, sizeof t->rule_colors);
106 /* Draws a vertical line to the left of cells at horizontal position X
107 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
109 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
113 if (x < 0 || x > tab_nc (t)
114 || y1 < 0 || y1 >= tab_nr (t)
115 || y2 < 0 || y2 >= tab_nr (t))
117 printf (_("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n"),
118 x, y1, y2, tab_nc (t), tab_nr (t));
124 assert (x <= tab_nc (t));
127 assert (y2 <= tab_nr (t));
132 for (y = y1; y <= y2; y++)
133 t->rv[x + (tab_nc (t) + 1) * y] = style;
137 /* Draws a horizontal line above cells at vertical position Y from X1
138 to X2 inclusive in style STYLE, if style is not -1. */
140 tab_hline (struct tab_table *t, int style, int x1, int x2, int y)
144 if (y < 0 || y > tab_nr (t)
145 || x1 < 0 || x1 >= tab_nc (t)
146 || x2 < 0 || x2 >= tab_nc (t))
148 printf (_("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n"),
149 x1, x2, y, tab_nc (t), tab_nr (t));
155 assert (y <= tab_nr (t));
158 assert (x2 < tab_nc (t));
163 for (x = x1; x <= x2; x++)
164 t->rh[x + tab_nc (t) * y] = style;
168 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
169 lines of style F_H and vertical lines of style F_V. Fills the
170 interior of the box with horizontal lines of style I_H and vertical
171 lines of style I_V. Any of the line styles may be -1 to avoid
172 drawing those lines. This is distinct from 0, which draws a null
175 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
176 int x1, int y1, int x2, int y2)
180 if (x1 < 0 || x1 >= tab_nc (t)
181 || x2 < 0 || x2 >= tab_nc (t)
182 || y1 < 0 || y1 >= tab_nr (t)
183 || y2 < 0 || y2 >= tab_nr (t))
185 printf (_("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n"),
186 x1, y1, x2, y2, tab_nc (t), tab_nr (t));
195 assert (x2 < tab_nc (t));
196 assert (y2 < tab_nr (t));
201 for (x = x1; x <= x2; x++)
203 t->rh[x + tab_nc (t) * y1] = f_h;
204 t->rh[x + tab_nc (t) * (y2 + 1)] = f_h;
210 for (y = y1; y <= y2; y++)
212 t->rv[x1 + (tab_nc (t) + 1) * y] = f_v;
213 t->rv[(x2 + 1) + (tab_nc (t) + 1) * y] = f_v;
221 for (y = y1 + 1; y <= y2; y++)
225 for (x = x1; x <= x2; x++)
226 t->rh[x + tab_nc (t) * y] = i_h;
233 for (x = x1 + 1; x <= x2; x++)
237 for (y = y1; y <= y2; y++)
238 t->rv[x + (tab_nc (t) + 1) * y] = i_v;
246 do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
250 assert (c < tab_nc (table));
251 assert (r < tab_nr (table));
255 if (c < 0 || r < 0 || c >= tab_nc (table) || r >= tab_nr (table))
257 printf ("tab_text(): bad cell (%d,%d) in table size (%d,%d)\n",
258 c, r, tab_nc (table), tab_nr (table));
263 table->cc[c + r * tab_nc (table)] = text;
264 table->ct[c + r * tab_nc (table)] = opt;
267 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
270 tab_text (struct tab_table *table, int c, int r, unsigned opt,
273 do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
276 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
277 FORMAT, which is formatted as if passed to printf. */
279 tab_text_format (struct tab_table *table, int c, int r, unsigned opt,
280 const char *format, ...)
284 va_start (args, format);
285 do_tab_text (table, c, r, opt,
286 pool_vasprintf (table->container, format, args));
290 static struct tab_joined_cell *
291 add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
294 struct tab_joined_cell *j;
300 assert (y2 < tab_nr (table));
301 assert (x2 < tab_nc (table));
305 if (x1 < 0 || x1 >= tab_nc (table)
306 || y1 < 0 || y1 >= tab_nr (table)
307 || x2 < x1 || x2 >= tab_nc (table)
308 || y2 < y1 || y2 >= tab_nr (table))
310 printf ("tab_joint_text(): bad cell "
311 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
312 x1, y1, x2, y2, tab_nc (table), tab_nr (table));
317 tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
319 j = pool_alloc (table->container, sizeof *j);
320 j->d[TABLE_HORZ][0] = x1;
321 j->d[TABLE_VERT][0] = y1;
322 j->d[TABLE_HORZ][1] = ++x2;
323 j->d[TABLE_VERT][1] = ++y2;
329 void **cc = &table->cc[x1 + y1 * tab_nc (table)];
330 unsigned short *ct = &table->ct[x1 + y1 * tab_nc (table)];
331 const int ofs = tab_nc (table) - (x2 - x1);
335 for (y = y1; y < y2; y++)
339 for (x = x1; x < x2; x++)
342 *ct++ = opt | TAB_JOIN;
353 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
354 options OPT to have text value TEXT. */
356 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
357 unsigned opt, const char *text)
359 char *s = pool_strdup (table->container, text);
360 if (x1 == x2 && y1 == y2)
361 do_tab_text (table, x1, y1, opt, s);
363 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
367 tab_create_footnote (struct tab_table *table, size_t idx, const char *content,
368 const char *marker, struct area_style *style)
370 struct footnote *f = pool_alloc (table->container, sizeof *f);
372 f->content = pool_strdup (table->container, content);
373 f->marker = pool_strdup (table->container, marker);
379 tab_add_footnote (struct tab_table *table, int x, int y,
380 const struct footnote *f)
382 int index = x + y * tab_nc (table);
383 unsigned short opt = table->ct[index];
384 struct tab_joined_cell *j;
387 j = table->cc[index];
390 char *text = table->cc[index];
392 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
393 j->text = text ? text : xstrdup ("");
396 j->footnotes = pool_realloc (table->container, j->footnotes,
397 (j->n_footnotes + 1) * sizeof *j->footnotes);
399 j->footnotes[j->n_footnotes++] = f;
403 tab_add_style (struct tab_table *table, int x, int y,
404 const struct area_style *style)
406 int index = x + y * tab_nc (table);
407 unsigned short opt = table->ct[index];
408 struct tab_joined_cell *j;
411 j = table->cc[index];
414 char *text = table->cc[index];
416 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
417 j->text = text ? text : xstrdup ("");
424 tab_cell_is_empty (const struct tab_table *table, int c, int r)
426 return table->cc[c + r * tab_nc (table)] == NULL;
431 /* Writes STRING to the output. OPTIONS may be any valid combination of TAB_*
434 This function is obsolete. Please do not add new uses of it. Instead, use
435 a text_item (see output/text-item.h). */
437 tab_output_text (int options UNUSED, const char *string)
439 text_item_submit (text_item_create (TEXT_ITEM_LOG, string));
442 /* Same as tab_output_text(), but FORMAT is passed through printf-like
443 formatting before output. */
445 tab_output_text_format (int options, const char *format, ...)
450 va_start (args, format);
451 text = xvasprintf (format, args);
454 tab_output_text (options, text);
459 /* Table class implementation. */
462 tab_destroy (struct table *table)
464 struct tab_table *t = tab_cast (table);
465 pool_destroy (t->container);
469 tab_get_cell (const struct table *table, int x, int y,
470 struct table_cell *cell)
472 const struct tab_table *t = tab_cast (table);
473 int index = x + y * tab_nc (t);
474 unsigned short opt = t->ct[index];
475 const void *cc = t->cc[index];
478 cell->n_footnotes = 0;
480 int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT;
481 const struct area_style *style = t->styles[style_idx];
486 static const struct area_style styles[3][3] = {
487 #define S(H,V) [H][V] = { AREA_STYLE_INITIALIZER__, \
488 .cell_style.halign = H, \
489 .cell_style.valign = V }
490 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_TOP),
491 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_CENTER),
492 S(TABLE_HALIGN_LEFT, TABLE_VALIGN_BOTTOM),
493 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_TOP),
494 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_CENTER),
495 S(TABLE_HALIGN_CENTER, TABLE_VALIGN_BOTTOM),
496 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_TOP),
497 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_CENTER),
498 S(TABLE_HALIGN_RIGHT, TABLE_VALIGN_BOTTOM),
501 enum table_halign halign
502 = ((opt & TAB_HALIGN) == TAB_LEFT ? TABLE_HALIGN_LEFT
503 : (opt & TAB_HALIGN) == TAB_CENTER ? TABLE_HALIGN_CENTER
504 : TABLE_HALIGN_RIGHT);
505 enum table_valign valign
506 = ((opt & TAB_VALIGN) == TAB_TOP ? TABLE_VALIGN_TOP
507 : (opt & TAB_VALIGN) == TAB_MIDDLE ? TABLE_VALIGN_CENTER
508 : TABLE_VALIGN_BOTTOM);
510 cell->style = &styles[halign][valign];
515 const struct tab_joined_cell *jc = cc;
516 cell->text = jc->text;
518 cell->footnotes = jc->footnotes;
519 cell->n_footnotes = jc->n_footnotes;
521 cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
522 cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
523 cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
524 cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
527 cell->style = jc->style;
531 cell->d[TABLE_HORZ][0] = x;
532 cell->d[TABLE_HORZ][1] = x + 1;
533 cell->d[TABLE_VERT][0] = y;
534 cell->d[TABLE_VERT][1] = y + 1;
535 cell->text = CONST_CAST (char *, cc ? cc : "");
540 tab_get_rule (const struct table *table, enum table_axis axis, int x, int y,
541 struct cell_color *color)
543 const struct tab_table *t = tab_cast (table);
544 uint8_t raw = (axis == TABLE_VERT
545 ? t->rh[x + tab_nc (t) * y]
546 : t->rv[x + (tab_nc (t) + 1) * y]);
547 struct cell_color *p = t->rule_colors[(raw & TAB_RULE_STYLE_MASK)
548 >> TAB_RULE_STYLE_SHIFT];
551 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;
555 tab_cast (const struct table *table)
557 return UP_CAST (table, struct tab_table, table);