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/output-item.h"
33 #include "output/pivot-table.h"
34 #include "output/table.h"
36 #include "gl/xalloc.h"
38 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
42 /* Increases TABLE's reference count, indicating that it has an additional
43 owner. An table that is shared among multiple owners must not be
46 table_ref (const struct table *table_)
48 struct table *table = CONST_CAST (struct table *, table_);
53 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
54 If TABLE no longer has any owners, it is freed. */
56 table_unref (struct table *table)
60 assert (table->ref_cnt > 0);
61 if (--table->ref_cnt == 0)
62 pool_destroy (table->container);
66 /* Returns true if TABLE has more than one owner. A table item that is shared
67 among multiple owners must not be modified. */
69 table_is_shared (const struct table *table)
71 return table->ref_cnt > 1;
74 struct table_area_style *
75 table_area_style_clone (struct pool *pool, const struct table_area_style *old)
77 struct table_area_style *new = pool_malloc (pool, sizeof *new);
79 if (new->font_style.typeface)
80 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
85 table_area_style_free (struct table_area_style *style)
89 free (style->font_style.typeface);
95 table_halign_to_string (enum table_halign halign)
99 case TABLE_HALIGN_LEFT: return "left";
100 case TABLE_HALIGN_CENTER: return "center";
101 case TABLE_HALIGN_RIGHT: return "right";
102 case TABLE_HALIGN_DECIMAL: return "decimal";
103 case TABLE_HALIGN_MIXED: return "mixed";
104 default: return "**error**";
109 table_valign_to_string (enum table_valign valign)
113 case TABLE_VALIGN_TOP: return "top";
114 case TABLE_VALIGN_CENTER: return "center";
115 case TABLE_VALIGN_BOTTOM: return "bottom";
116 default: return "**error**";
121 table_halign_interpret (enum table_halign halign, bool numeric)
125 case TABLE_HALIGN_LEFT:
126 case TABLE_HALIGN_CENTER:
127 case TABLE_HALIGN_RIGHT:
130 case TABLE_HALIGN_MIXED:
131 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
133 case TABLE_HALIGN_DECIMAL:
134 return TABLE_HALIGN_DECIMAL;
142 font_style_copy (struct pool *container,
143 struct font_style *dst, const struct font_style *src)
147 dst->typeface = pool_strdup (container, dst->typeface);
151 font_style_uninit (struct font_style *font)
154 free (font->typeface);
158 table_area_style_copy (struct pool *container, struct table_area_style *dst,
159 const struct table_area_style *src)
161 font_style_copy (container, &dst->font_style, &src->font_style);
162 dst->cell_style = src->cell_style;
166 table_area_style_uninit (struct table_area_style *area)
169 font_style_uninit (&area->font_style);
173 table_stroke_to_string (enum table_stroke stroke)
177 case TABLE_STROKE_NONE: return "none";
178 case TABLE_STROKE_SOLID: return "solid";
179 case TABLE_STROKE_DASHED: return "dashed";
180 case TABLE_STROKE_THICK: return "thick";
181 case TABLE_STROKE_THIN: return "thin";
182 case TABLE_STROKE_DOUBLE: return "double";
189 cell_color_dump (const struct cell_color *c)
192 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
194 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
198 font_style_dump (const struct font_style *f)
200 printf ("%s %dpx ", f->typeface, f->size);
201 cell_color_dump (&f->fg[0]);
203 cell_color_dump (&f->bg[0]);
204 if (!cell_color_equal (f->fg[0], f->fg[1])
205 || !cell_color_equal (f->bg[0], f->bg[1]))
208 cell_color_dump (&f->fg[1]);
210 cell_color_dump (&f->bg[1]);
213 fputs (" bold", stdout);
215 fputs (" italic", stdout);
217 fputs (" underline", stdout);
221 font_style_equal (const struct font_style *a, const struct font_style *b)
223 return (a->bold == b->bold
224 && a->italic == b->italic
225 && a->underline == b->underline
226 && a->markup == b->markup
227 && cell_color_equal (a->fg[0], b->fg[0])
228 && cell_color_equal (a->fg[1], b->fg[1])
229 && cell_color_equal (a->bg[0], b->bg[0])
230 && cell_color_equal (a->bg[1], b->bg[1])
231 && !strcmp (a->typeface ? a->typeface : "",
232 b->typeface ? b->typeface : "")
233 && a->size == b->size);
237 cell_style_dump (const struct cell_style *c)
239 fputs (table_halign_to_string (c->halign), stdout);
240 if (c->halign == TABLE_HALIGN_DECIMAL)
241 printf ("(%.2gpx)", c->decimal_offset);
242 printf (" %s", table_valign_to_string (c->valign));
243 printf (" %d,%d,%d,%dpx",
244 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
245 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
248 /* Creates and returns a new table with NC columns and NR rows and initially no
249 header rows or columns.
251 Sets the number of header rows on each side of TABLE to HL on the
252 left, HR on the right, HT on the top, HB on the bottom. Header rows
253 are repeated when a table is broken across multiple columns or
256 The table's cells are initially empty. */
258 table_create (int nc, int nr, int hl, int hr, int ht, int hb)
260 struct pool *pool = pool_create ();
261 struct table *t = pool_alloc (pool, sizeof *t);
262 *t = (struct table) {
264 .n = { [H] = nc, [V] = nr },
265 .h = { [H] = { hl, hr }, [V] = { ht, hb } },
267 .cc = pool_calloc (pool, nr * nc, sizeof *t->cc),
268 .cp = pool_calloc (pool, nr * nc, sizeof *t->cp),
269 .rh = pool_calloc (pool, nc, nr + 1),
270 .rv = pool_calloc (pool, nr, nc + 1),
277 /* Draws a vertical line to the left of cells at horizontal position X
278 from Y1 to Y2 inclusive in style STYLE. */
280 table_vline (struct table *t, int style, int x, int y1, int y2)
282 if (x < 0 || x > t->n[H] || y1 < 0 || y1 > y2 || y2 >= t->n[V])
284 printf ("bad vline: x=%d y=(%d,%d) in table size (%d,%d)\n",
285 x, y1, y2, t->n[H], t->n[V]);
289 for (int y = y1; y <= y2; y++)
290 t->rv[x + (t->n[H] + 1) * y] = style;
293 /* Draws a horizontal line above cells at vertical position Y from X1
294 to X2 inclusive in style STYLE. */
296 table_hline (struct table *t, int style, int x1, int x2, int y)
298 if (y < 0 || y > t->n[V] || x1 < 0 || x1 > x2 || x2 >= t->n[H])
300 printf ("bad hline: x=(%d,%d) y=%d in table size (%d,%d)\n",
301 x1, x2, y, t->n[H], t->n[V]);
305 for (int x = x1; x <= x2; x++)
306 t->rh[x + t->n[H] * y] = style;
311 /* Fill TABLE cells (X1,X2)-(Y1,Y2), inclusive, with VALUE and OPT. */
313 table_put (struct table *table, int x1, int y1, int x2, int y2,
314 unsigned int opt, const struct pivot_value *value)
316 assert (0 <= x1 && x1 <= x2 && x2 < table->n[H]);
317 assert (0 <= y1 && y1 <= y2 && y2 < table->n[V]);
319 const bool debugging = false;
326 printf ("%d-%d", x1, x2);
331 printf ("%d-%d", y1, y2);
333 char *value_s = value ? pivot_value_to_string (value, NULL) : NULL;
334 printf (": \"%s\"\n", value_s ? value_s : "");
338 if (x1 == x2 && y1 == y2)
340 table->cc[x1 + y1 * table->n[H]] = CONST_CAST (struct pivot_value *, value);
341 table->cp[x1 + y1 * table->n[H]] = opt;
345 struct table_cell *cell = pool_alloc (table->container, sizeof *cell);
346 *cell = (struct table_cell) {
347 .d = { [H] = { x1, x2 + 1 }, [V] = { y1, y2 + 1 } },
352 for (int y = y1; y <= y2; y++)
354 size_t ofs = x1 + y * table->n[H];
355 void **cc = &table->cc[ofs];
356 unsigned char *ct = &table->cp[ofs];
357 for (int x = x1; x <= x2; x++)
360 *ct++ = opt | TABLE_CELL_JOIN;
367 free_value (void *value_)
369 struct pivot_value *value = value_;
370 pivot_value_destroy (value);
374 table_put_owned (struct table *table, int x1, int y1, int x2, int y2,
375 unsigned opt, struct pivot_value *value)
377 table_put (table, x1, y1, x2, y2, opt, value);
378 pool_register (table->container, free_value, value);
381 /* Returns true if column C, row R has no contents, otherwise false. */
383 table_cell_is_empty (const struct table *table, int c, int r)
385 return table->cc[c + r * table->n[H]] == NULL;
388 /* Initializes CELL with the contents of the table cell at column X and row Y
391 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
393 assert (x >= 0 && x < t->n[TABLE_HORZ]);
394 assert (y >= 0 && y < t->n[TABLE_VERT]);
396 int index = x + y * t->n[H];
397 unsigned char opt = t->cp[index];
398 const void *cc = t->cc[index];
400 struct table_area_style *style
401 = t->styles[(opt & TABLE_CELL_STYLE_MASK) >> TABLE_CELL_STYLE_SHIFT];
403 static const struct pivot_value empty_value = {
405 .type = PIVOT_VALUE_TEXT,
406 .local = (char *) "",
409 .user_provided = true,
413 if (opt & TABLE_CELL_JOIN)
415 const struct table_cell *jc = cc;
418 cell->value = &empty_value;
419 if (!cell->font_style)
420 cell->font_style = &style->font_style;
421 if (!cell->cell_style)
422 cell->cell_style = &style->cell_style;
426 const struct pivot_value *v = cc ? cc : &empty_value;
427 const struct pivot_value_ex *ex = pivot_value_ex (v);
428 *cell = (struct table_cell) {
429 .d = { [H] = { x, x + 1 }, [V] = { y, y + 1 } },
432 .font_style = ex->font_style ? ex->font_style : &style->font_style,
433 .cell_style = ex->cell_style ? ex->cell_style : &style->cell_style,
437 assert (cell->font_style);
438 assert (cell->cell_style);
441 /* Returns one of the TABLE_STROKE_* enumeration constants (declared in
442 output/table.h) representing a rule running alongside one of the cells in
445 Suppose NC is the number of columns in TABLE and NR is the number of rows.
446 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
447 (0,0), the return value is the rule that runs vertically on the left side of
448 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
449 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
452 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
453 within a 7x7 table. The '|' characters at the intersection of the X labels
454 and Y labels show the rule whose style would be returned by calling
455 table_get_rule with those X and Y values:
458 +--+--+--+--+--+--+--+
460 +--+--+--+--+--+--+--+
462 +--+--+--+--+--+--+--+
464 +--+--+--+--+--+--+--+
466 +--+--+--+--+--+--+--+
468 +--+--+--+--+--+--+--+
470 +--+--+--+--+--+--+--+
472 +--+--+--+--+--+--+--+
474 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
475 (X,Y) = (0,0), the return value is the rule that runs horizontally above
476 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
477 between that cell and cell (0,1); and so on, up to (0,NR), which runs
478 horizontally below cell (0,NR-1). */
479 struct table_border_style
480 table_get_rule (const struct table *table, enum table_axis axis, int x, int y)
482 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
483 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
485 size_t border_idx = (axis == TABLE_VERT
486 ? table->rh[x + table->n[H] * y]
487 : table->rv[x + (table->n[H] + 1) * y]);
488 return (border_idx < table->n_borders
489 ? table->borders[border_idx]
490 : (struct table_border_style) { TABLE_STROKE_NONE,