1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2011, 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/table.h"
20 #include "output/table-provider.h"
26 #include "data/format.h"
27 #include "libpspp/assertion.h"
28 #include "libpspp/cast.h"
29 #include "libpspp/compiler.h"
30 #include "libpspp/pool.h"
31 #include "libpspp/str.h"
32 #include "output/table-item.h"
33 #include "output/table.h"
34 #include "output/text-item.h"
36 #include "gl/xalloc.h"
38 /* Increases TABLE's reference count, indicating that it has an additional
39 owner. An table that is shared among multiple owners must not be
42 table_ref (const struct table *table_)
44 struct table *table = CONST_CAST (struct table *, table_);
49 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
50 If TABLE no longer has any owners, it is freed. */
52 table_unref (struct table *table)
56 assert (table->ref_cnt > 0);
57 if (--table->ref_cnt == 0)
58 pool_destroy (table->container);
62 /* Returns true if TABLE has more than one owner. A table item that is shared
63 among multiple owners must not be modified. */
65 table_is_shared (const struct table *table)
67 return table->ref_cnt > 1;
71 area_style_clone (struct pool *pool, const struct area_style *old)
73 struct area_style *new = pool_malloc (pool, sizeof *new);
75 if (new->font_style.typeface)
76 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
81 area_style_free (struct area_style *style)
85 free (style->font_style.typeface);
91 table_cell_format_footnote_markers (const struct table_cell *cell,
94 for (size_t i = 0; i < cell->n_footnotes; i++)
98 ds_put_cstr (s, cell->footnotes[i]->marker);
102 static const struct footnote **
103 add_footnotes (const struct footnote **refs, size_t n_refs,
104 const struct footnote **footnotes, size_t *allocated, size_t *n)
106 for (size_t i = 0; i < n_refs; i++)
108 const struct footnote *f = refs[i];
109 if (f->idx >= *allocated)
111 size_t new_allocated = (f->idx + 1) * 2;
112 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
113 while (*allocated < new_allocated)
114 footnotes[(*allocated)++] = NULL;
116 footnotes[f->idx] = f;
124 table_collect_footnotes (const struct table_item *item,
125 const struct footnote ***footnotesp)
127 const struct footnote **footnotes = NULL;
128 size_t allocated = 0;
131 struct table *t = item->table;
132 for (int y = 0; y < table_nr (t); y++)
134 struct table_cell cell;
135 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
137 table_get_cell (t, x, y, &cell);
139 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
140 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
141 footnotes, &allocated, &n);
145 const struct table_item_text *title = table_item_get_title (item);
147 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
148 footnotes, &allocated, &n);
150 const struct table_item_layers *layers = table_item_get_layers (item);
153 for (size_t i = 0; i < layers->n_layers; i++)
154 footnotes = add_footnotes (layers->layers[i].footnotes,
155 layers->layers[i].n_footnotes,
156 footnotes, &allocated, &n);
159 const struct table_item_text *caption = table_item_get_caption (item);
161 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
162 footnotes, &allocated, &n);
164 size_t n_nonnull = 0;
165 for (size_t i = 0; i < n; i++)
167 footnotes[n_nonnull++] = footnotes[i];
169 *footnotesp = footnotes;
173 /* Returns a table that contains a single cell, whose contents are the
174 left-aligned TEXT. */
176 table_from_string (const char *text)
178 struct table *t = table_create (1, 1, 0, 0, 0, 0);
179 t->styles[0] = xmalloc (sizeof *t->styles[0]);
180 *t->styles[0] = (struct area_style) {
181 AREA_STYLE_INITIALIZER__,
182 .cell_style.halign = TABLE_HALIGN_LEFT,
183 .cell_style.valign = TABLE_VALIGN_TOP
185 table_text (t, 0, 0, 0 << TAB_STYLE_SHIFT, text);
190 table_halign_to_string (enum table_halign halign)
194 case TABLE_HALIGN_LEFT: return "left";
195 case TABLE_HALIGN_CENTER: return "center";
196 case TABLE_HALIGN_RIGHT: return "right";
197 case TABLE_HALIGN_DECIMAL: return "decimal";
198 case TABLE_HALIGN_MIXED: return "mixed";
199 default: return "**error**";
204 table_valign_to_string (enum table_valign valign)
208 case TABLE_VALIGN_TOP: return "top";
209 case TABLE_VALIGN_CENTER: return "center";
210 case TABLE_VALIGN_BOTTOM: return "bottom";
211 default: return "**error**";
216 table_halign_interpret (enum table_halign halign, bool numeric)
220 case TABLE_HALIGN_LEFT:
221 case TABLE_HALIGN_CENTER:
222 case TABLE_HALIGN_RIGHT:
225 case TABLE_HALIGN_MIXED:
226 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
228 case TABLE_HALIGN_DECIMAL:
229 return TABLE_HALIGN_DECIMAL;
237 font_style_copy (struct pool *container,
238 struct font_style *dst, const struct font_style *src)
242 dst->typeface = pool_strdup (container, dst->typeface);
246 font_style_uninit (struct font_style *font)
249 free (font->typeface);
253 area_style_copy (struct pool *container,
254 struct area_style *dst, const struct area_style *src)
256 font_style_copy (container, &dst->font_style, &src->font_style);
257 dst->cell_style = src->cell_style;
261 area_style_uninit (struct area_style *area)
264 font_style_uninit (&area->font_style);
268 table_stroke_to_string (enum table_stroke stroke)
272 case TABLE_STROKE_NONE: return "none";
273 case TABLE_STROKE_SOLID: return "solid";
274 case TABLE_STROKE_DASHED: return "dashed";
275 case TABLE_STROKE_THICK: return "thick";
276 case TABLE_STROKE_THIN: return "thin";
277 case TABLE_STROKE_DOUBLE: return "double";
284 cell_color_dump (const struct cell_color *c)
287 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
289 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
293 font_style_dump (const struct font_style *f)
295 printf ("%s %dpx ", f->typeface, f->size);
296 cell_color_dump (&f->fg[0]);
298 cell_color_dump (&f->bg[0]);
299 if (!cell_color_equal (&f->fg[0], &f->fg[1])
300 || !cell_color_equal (&f->bg[0], &f->bg[1]))
303 cell_color_dump (&f->fg[1]);
305 cell_color_dump (&f->bg[1]);
308 fputs (" bold", stdout);
310 fputs (" italic", stdout);
312 fputs (" underline", stdout);
316 cell_style_dump (const struct cell_style *c)
318 fputs (table_halign_to_string (c->halign), stdout);
319 if (c->halign == TABLE_HALIGN_DECIMAL)
320 printf ("(%.2gpx)", c->decimal_offset);
321 printf (" %s", table_valign_to_string (c->valign));
322 printf (" %d,%d,%d,%dpx",
323 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
324 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
328 static const bool debugging = true;
331 struct table_joined_cell
333 int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */
337 const struct footnote **footnotes;
339 const struct area_style *style;
342 /* Creates and returns a new table with NC columns and NR rows and initially no
343 header rows or columns.
345 Sets the number of header rows on each side of TABLE to HL on the
346 left, HR on the right, HT on the top, HB on the bottom. Header rows
347 are repeated when a table is broken across multiple columns or
350 The table's cells are initially empty. */
352 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
356 t = pool_create_container (struct table, container);
357 t->n[TABLE_HORZ] = nc;
358 t->n[TABLE_VERT] = nr;
359 t->h[TABLE_HORZ][0] = hl;
360 t->h[TABLE_HORZ][1] = hr;
361 t->h[TABLE_VERT][0] = ht;
362 t->h[TABLE_VERT][1] = hb;
365 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
366 t->ct = pool_calloc (t->container, nr * nc, sizeof *t->ct);
368 t->rh = pool_nmalloc (t->container, nc, nr + 1);
369 memset (t->rh, TABLE_STROKE_NONE, nc * (nr + 1));
371 t->rv = pool_nmalloc (t->container, nr, nc + 1);
372 memset (t->rv, TABLE_STROKE_NONE, nr * (nc + 1));
374 memset (t->styles, 0, sizeof t->styles);
375 memset (t->rule_colors, 0, sizeof t->rule_colors);
382 /* Draws a vertical line to the left of cells at horizontal position X
383 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
385 table_vline (struct table *t, int style, int x, int y1, int y2)
389 if (x < 0 || x > table_nc (t)
390 || y1 < 0 || y1 >= table_nr (t)
391 || y2 < 0 || y2 >= table_nr (t))
393 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
394 x, y1, y2, table_nc (t), table_nr (t));
400 assert (x <= table_nc (t));
403 assert (y2 <= table_nr (t));
408 for (y = y1; y <= y2; y++)
409 t->rv[x + (table_nc (t) + 1) * y] = style;
413 /* Draws a horizontal line above cells at vertical position Y from X1
414 to X2 inclusive in style STYLE, if style is not -1. */
416 table_hline (struct table *t, int style, int x1, int x2, int y)
420 if (y < 0 || y > table_nr (t)
421 || x1 < 0 || x1 >= table_nc (t)
422 || x2 < 0 || x2 >= table_nc (t))
424 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
425 x1, x2, y, table_nc (t), table_nr (t));
431 assert (y <= table_nr (t));
434 assert (x2 < table_nc (t));
439 for (x = x1; x <= x2; x++)
440 t->rh[x + table_nc (t) * y] = style;
444 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
445 lines of style F_H and vertical lines of style F_V. Fills the
446 interior of the box with horizontal lines of style I_H and vertical
447 lines of style I_V. Any of the line styles may be -1 to avoid
448 drawing those lines. This is distinct from 0, which draws a null
451 table_box (struct table *t, int f_h, int f_v, int i_h, int i_v,
452 int x1, int y1, int x2, int y2)
456 if (x1 < 0 || x1 >= table_nc (t)
457 || x2 < 0 || x2 >= table_nc (t)
458 || y1 < 0 || y1 >= table_nr (t)
459 || y2 < 0 || y2 >= table_nr (t))
461 printf ("bad box: (%d,%d)-(%d,%d) in table size (%d,%d)\n",
462 x1, y1, x2, y2, table_nc (t), table_nr (t));
471 assert (x2 < table_nc (t));
472 assert (y2 < table_nr (t));
477 for (x = x1; x <= x2; x++)
479 t->rh[x + table_nc (t) * y1] = f_h;
480 t->rh[x + table_nc (t) * (y2 + 1)] = f_h;
486 for (y = y1; y <= y2; y++)
488 t->rv[x1 + (table_nc (t) + 1) * y] = f_v;
489 t->rv[(x2 + 1) + (table_nc (t) + 1) * y] = f_v;
497 for (y = y1 + 1; y <= y2; y++)
501 for (x = x1; x <= x2; x++)
502 t->rh[x + table_nc (t) * y] = i_h;
509 for (x = x1 + 1; x <= x2; x++)
513 for (y = y1; y <= y2; y++)
514 t->rv[x + (table_nc (t) + 1) * y] = i_v;
522 do_table_text (struct table *table, int c, int r, unsigned opt, char *text)
526 assert (c < table_nc (table));
527 assert (r < table_nr (table));
531 if (c < 0 || r < 0 || c >= table_nc (table) || r >= table_nr (table))
533 printf ("table_text(): bad cell (%d,%d) in table size (%d,%d)\n",
534 c, r, table_nc (table), table_nr (table));
539 table->cc[c + r * table_nc (table)] = text;
540 table->ct[c + r * table_nc (table)] = opt;
543 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
546 table_text (struct table *table, int c, int r, unsigned opt,
549 do_table_text (table, c, r, opt, pool_strdup (table->container, text));
552 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
553 FORMAT, which is formatted as if passed to printf. */
555 table_text_format (struct table *table, int c, int r, unsigned opt,
556 const char *format, ...)
560 va_start (args, format);
561 do_table_text (table, c, r, opt,
562 pool_vasprintf (table->container, format, args));
566 static struct table_joined_cell *
567 add_joined_cell (struct table *table, int x1, int y1, int x2, int y2,
570 struct table_joined_cell *j;
576 assert (y2 < table_nr (table));
577 assert (x2 < table_nc (table));
581 if (x1 < 0 || x1 >= table_nc (table)
582 || y1 < 0 || y1 >= table_nr (table)
583 || x2 < x1 || x2 >= table_nc (table)
584 || y2 < y1 || y2 >= table_nr (table))
586 printf ("table_joint_text(): bad cell "
587 "(%d,%d)-(%d,%d) in table size (%d,%d)\n",
588 x1, y1, x2, y2, table_nc (table), table_nr (table));
593 table_box (table, -1, -1, TABLE_STROKE_NONE, TABLE_STROKE_NONE,
596 j = pool_alloc (table->container, sizeof *j);
597 j->d[TABLE_HORZ][0] = x1;
598 j->d[TABLE_VERT][0] = y1;
599 j->d[TABLE_HORZ][1] = ++x2;
600 j->d[TABLE_VERT][1] = ++y2;
606 void **cc = &table->cc[x1 + y1 * table_nc (table)];
607 unsigned short *ct = &table->ct[x1 + y1 * table_nc (table)];
608 const int ofs = table_nc (table) - (x2 - x1);
612 for (y = y1; y < y2; y++)
616 for (x = x1; x < x2; x++)
619 *ct++ = opt | TAB_JOIN;
630 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
631 options OPT to have text value TEXT. */
633 table_joint_text (struct table *table, int x1, int y1, int x2, int y2,
634 unsigned opt, const char *text)
636 char *s = pool_strdup (table->container, text);
637 if (x1 == x2 && y1 == y2)
638 do_table_text (table, x1, y1, opt, s);
640 add_joined_cell (table, x1, y1, x2, y2, opt)->text = s;
644 table_create_footnote (struct table *table, size_t idx, const char *content,
645 const char *marker, struct area_style *style)
649 struct footnote *f = pool_alloc (table->container, sizeof *f);
651 f->content = pool_strdup (table->container, content);
652 f->marker = pool_strdup (table->container, marker);
658 table_add_footnote (struct table *table, int x, int y,
659 const struct footnote *f)
663 int index = x + y * table_nc (table);
664 unsigned short opt = table->ct[index];
665 struct table_joined_cell *j;
668 j = table->cc[index];
671 char *text = table->cc[index];
673 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
674 j->text = text ? text : xstrdup ("");
677 j->footnotes = pool_realloc (table->container, j->footnotes,
678 (j->n_footnotes + 1) * sizeof *j->footnotes);
680 j->footnotes[j->n_footnotes++] = f;
684 table_add_style (struct table *table, int x, int y,
685 const struct area_style *style)
687 int index = x + y * table_nc (table);
688 unsigned short opt = table->ct[index];
689 struct table_joined_cell *j;
692 j = table->cc[index];
695 char *text = table->cc[index];
697 j = add_joined_cell (table, x, y, x, y, table->ct[index]);
698 j->text = text ? text : xstrdup ("");
705 table_cell_is_empty (const struct table *table, int c, int r)
707 return table->cc[c + r * table_nc (table)] == NULL;
712 /* Writes STRING to the output. OPTIONS may be any valid combination of TAB_*
715 This function is obsolete. Please do not add new uses of it. Instead, use
716 a text_item (see output/text-item.h). */
718 table_output_text (int options UNUSED, const char *string)
720 text_item_submit (text_item_create (TEXT_ITEM_LOG, string));
723 /* Same as table_output_text(), but FORMAT is passed through printf-like
724 formatting before output. */
726 table_output_text_format (int options, const char *format, ...)
731 va_start (args, format);
732 text = xvasprintf (format, args);
735 table_output_text (options, text);
740 /* Initializes CELL with the contents of the table cell at column X and row Y
741 within TABLE. When CELL is no longer needed, the caller is responsible for
742 freeing it by calling table_cell_free(CELL).
744 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
746 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
748 assert (x >= 0 && x < t->n[TABLE_HORZ]);
749 assert (y >= 0 && y < t->n[TABLE_VERT]);
751 int index = x + y * table_nc (t);
752 unsigned short opt = t->ct[index];
753 const void *cc = t->cc[index];
756 cell->n_footnotes = 0;
758 int style_idx = (opt & TAB_STYLE_MASK) >> TAB_STYLE_SHIFT;
759 cell->style = t->styles[style_idx];
763 const struct table_joined_cell *jc = cc;
764 cell->text = jc->text;
766 cell->footnotes = jc->footnotes;
767 cell->n_footnotes = jc->n_footnotes;
769 cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
770 cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
771 cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
772 cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
775 cell->style = jc->style;
779 cell->d[TABLE_HORZ][0] = x;
780 cell->d[TABLE_HORZ][1] = x + 1;
781 cell->d[TABLE_VERT][0] = y;
782 cell->d[TABLE_VERT][1] = y + 1;
783 cell->text = CONST_CAST (char *, cc ? cc : "");
786 assert (cell->style);
789 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
790 representing a rule running alongside one of the cells in TABLE.
792 Suppose NC is the number of columns in TABLE and NR is the number of rows.
793 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
794 (0,0), the return value is the rule that runs vertically on the left side of
795 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
796 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
799 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
800 within a 7x7 table. The '|' characters at the intersection of the X labels
801 and Y labels show the rule whose style would be returned by calling
802 table_get_rule with those X and Y values:
805 +--+--+--+--+--+--+--+
807 +--+--+--+--+--+--+--+
809 +--+--+--+--+--+--+--+
811 +--+--+--+--+--+--+--+
813 +--+--+--+--+--+--+--+
815 +--+--+--+--+--+--+--+
817 +--+--+--+--+--+--+--+
819 +--+--+--+--+--+--+--+
821 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
822 (X,Y) = (0,0), the return value is the rule that runs horizontally above
823 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
824 between that cell and cell (0,1); and so on, up to (0,NR), which runs
825 horizontally below cell (0,NR-1). */
827 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
828 struct cell_color *color)
830 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
831 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
833 uint8_t raw = (axis == TABLE_VERT
834 ? table->rh[x + table_nc (table) * y]
835 : table->rv[x + (table_nc (table) + 1) * y]);
836 struct cell_color *p = table->rule_colors[(raw & TAB_RULE_STYLE_MASK)
837 >> TAB_RULE_STYLE_SHIFT];
838 *color = p ? *p : (struct cell_color) CELL_COLOR_BLACK;
839 return (raw & TAB_RULE_TYPE_MASK) >> TAB_RULE_TYPE_SHIFT;