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"
34 #include "gl/xalloc.h"
36 /* Increases TABLE's reference count, indicating that it has an additional
37 owner. An table that is shared among multiple owners must not be
40 table_ref (const struct table *table_)
42 struct table *table = CONST_CAST (struct table *, table_);
47 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
48 If TABLE no longer has any owners, it is freed. */
50 table_unref (struct table *table)
54 assert (table->ref_cnt > 0);
55 if (--table->ref_cnt == 0)
56 table->klass->destroy (table);
60 /* Returns true if TABLE has more than one owner. A table item that is shared
61 among multiple owners must not be modified. */
63 table_is_shared (const struct table *table)
65 return table->ref_cnt > 1;
68 /* Sets the number of left header columns in TABLE to HL. */
70 table_set_hl (struct table *table, int hl)
72 assert (!table_is_shared (table));
73 table->h[TABLE_HORZ][0] = hl;
76 /* Sets the number of right header columns in TABLE to HR. */
78 table_set_hr (struct table *table, int hr)
80 assert (!table_is_shared (table));
81 table->h[TABLE_HORZ][1] = hr;
84 /* Sets the number of top header rows in TABLE to HT. */
86 table_set_ht (struct table *table, int ht)
88 assert (!table_is_shared (table));
89 table->h[TABLE_VERT][0] = ht;
92 /* Sets the number of top header rows in TABLE to HB. */
94 table_set_hb (struct table *table, int hb)
96 assert (!table_is_shared (table));
97 table->h[TABLE_VERT][1] = hb;
100 /* Initializes TABLE as a table of the specified CLASS, initially with a
101 reference count of 1.
103 TABLE initially has 0 rows and columns and no headers. The table
104 implementation should update the numbers of rows and columns. The table
105 implementation (or its client) may update the header rows and columns.
107 A table is an abstract class, that is, a plain struct table is not useful on
108 its own. Thus, this function is normally called from the initialization
109 function of some subclass of table. */
111 table_init (struct table *table, const struct table_class *class)
113 table->klass = class;
114 table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
115 table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
116 table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
120 /* Sets the number of columns in TABLE to NC. */
122 table_set_nc (struct table *table, int nc)
124 assert (!table_is_shared (table));
125 table->n[TABLE_HORZ] = nc;
128 /* Sets the number of rows in TABLE to NR. */
130 table_set_nr (struct table *table, int nr)
132 assert (!table_is_shared (table));
133 table->n[TABLE_VERT] = nr;
137 area_style_clone (struct pool *pool, const struct area_style *old)
139 struct area_style *new = pool_malloc (pool, sizeof *new);
141 if (new->font_style.typeface)
142 new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
147 area_style_free (struct area_style *style)
151 free (style->font_style.typeface);
156 /* Initializes CELL with the contents of the table cell at column X and row Y
157 within TABLE. When CELL is no longer needed, the caller is responsible for
158 freeing it by calling table_cell_free(CELL).
160 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
162 table_get_cell (const struct table *table, int x, int y,
163 struct table_cell *cell)
165 assert (x >= 0 && x < table->n[TABLE_HORZ]);
166 assert (y >= 0 && y < table->n[TABLE_VERT]);
168 static const struct area_style default_style = AREA_STYLE_INITIALIZER;
169 cell->style = &default_style;
171 table->klass->get_cell (table, x, y, cell);
174 /* Frees CELL, which should have been initialized by calling
177 table_cell_free (struct table_cell *cell)
179 if (cell->destructor != NULL)
180 cell->destructor (cell->destructor_aux);
183 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
184 representing a rule running alongside one of the cells in TABLE.
186 Suppose NC is the number of columns in TABLE and NR is the number of rows.
187 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
188 (0,0), the return value is the rule that runs vertically on the left side of
189 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
190 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
193 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
194 within a 7x7 table. The '|' characters at the intersection of the X labels
195 and Y labels show the rule whose style would be returned by calling
196 table_get_rule with those X and Y values:
199 +--+--+--+--+--+--+--+
201 +--+--+--+--+--+--+--+
203 +--+--+--+--+--+--+--+
205 +--+--+--+--+--+--+--+
207 +--+--+--+--+--+--+--+
209 +--+--+--+--+--+--+--+
211 +--+--+--+--+--+--+--+
213 +--+--+--+--+--+--+--+
215 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
216 (X,Y) = (0,0), the return value is the rule that runs horizontally above
217 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
218 between that cell and cell (0,1); and so on, up to (0,NR), which runs
219 horizontally below cell (0,NR-1). */
221 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
222 struct cell_color *color)
224 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
225 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
226 *color = (struct cell_color) CELL_COLOR_BLACK;
227 return table->klass->get_rule (table, axis, x, y, color);
231 table_cell_format_footnote_markers (const struct table_cell *cell,
234 for (size_t i = 0; i < cell->n_footnotes; i++)
237 ds_put_byte (s, ',');
238 ds_put_cstr (s, cell->footnotes[i]->marker);
242 static const struct footnote **
243 add_footnotes (const struct footnote **refs, size_t n_refs,
244 const struct footnote **footnotes, size_t *allocated, size_t *n)
246 for (size_t i = 0; i < n_refs; i++)
248 const struct footnote *f = refs[i];
249 if (f->idx >= *allocated)
251 size_t new_allocated = (f->idx + 1) * 2;
252 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
253 while (*allocated < new_allocated)
254 footnotes[(*allocated)++] = NULL;
256 footnotes[f->idx] = f;
264 table_collect_footnotes (const struct table_item *item,
265 const struct footnote ***footnotesp)
267 const struct footnote **footnotes = NULL;
268 size_t allocated = 0;
271 struct table *t = item->table;
272 for (int y = 0; y < table_nr (t); y++)
274 struct table_cell cell;
275 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
277 table_get_cell (t, x, y, &cell);
279 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
280 footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
281 footnotes, &allocated, &n);
282 table_cell_free (&cell);
286 const struct table_item_text *title = table_item_get_title (item);
288 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
289 footnotes, &allocated, &n);
291 const struct table_item_text *caption = table_item_get_caption (item);
293 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
294 footnotes, &allocated, &n);
296 *footnotesp = footnotes;
300 struct table_unshared
303 struct table *subtable;
306 static const struct table_class table_unshared_class;
308 /* Takes ownership of TABLE and returns a table with the same contents but
309 which is guaranteed not to be shared (as returned by table_is_shared()).
311 If TABLE is unshared, just returns TABLE.
313 The only real use for this function is to create a copy of TABLE in which
314 the headers can be adjusted, which is a pretty specialized use case. */
316 table_unshare (struct table *table)
318 if (!table_is_shared (table))
322 struct table_unshared *tiu = xmalloc (sizeof *tiu);
323 table_init (&tiu->table, &table_unshared_class);
324 table_set_nc (&tiu->table, table_nc (table));
325 table_set_nr (&tiu->table, table_nr (table));
326 table_set_hl (&tiu->table, table_hl (table));
327 table_set_hr (&tiu->table, table_hr (table));
328 table_set_ht (&tiu->table, table_ht (table));
329 table_set_hb (&tiu->table, table_hb (table));
330 tiu->subtable = table;
335 static struct table_unshared *
336 table_unshared_cast (const struct table *table)
338 assert (table->klass == &table_unshared_class);
339 return UP_CAST (table, struct table_unshared, table);
343 table_unshared_destroy (struct table *tiu_)
345 struct table_unshared *tiu = table_unshared_cast (tiu_);
346 table_unref (tiu->subtable);
351 table_unshared_get_cell (const struct table *tiu_, int x, int y,
352 struct table_cell *cell)
354 struct table_unshared *tiu = table_unshared_cast (tiu_);
355 table_get_cell (tiu->subtable, x, y, cell);
359 table_unshared_get_rule (const struct table *tiu_,
360 enum table_axis axis, int x, int y,
361 struct cell_color *color)
363 struct table_unshared *tiu = table_unshared_cast (tiu_);
364 return table_get_rule (tiu->subtable, axis, x, y, color);
367 static const struct table_class table_unshared_class =
369 table_unshared_destroy,
370 table_unshared_get_cell,
371 table_unshared_get_rule,
378 enum table_halign halign;
381 static const struct table_class table_string_class;
383 /* Returns a table that contains a single cell, whose contents are S with
384 options OPTIONS (a combination of TAB_* values). */
386 table_from_string (enum table_halign halign, const char *s)
388 struct table_string *ts = xmalloc (sizeof *ts);
389 table_init (&ts->table, &table_string_class);
390 ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
391 ts->string = xstrdup (s);
396 static struct table_string *
397 table_string_cast (const struct table *table)
399 assert (table->klass == &table_string_class);
400 return UP_CAST (table, struct table_string, table);
404 table_string_destroy (struct table *ts_)
406 struct table_string *ts = table_string_cast (ts_);
412 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
413 struct table_cell *cell)
415 static const struct area_style styles[] = {
416 #define S(H) [H] = { AREA_STYLE_INITIALIZER__, .cell_style.halign = H }
417 S(TABLE_HALIGN_LEFT),
418 S(TABLE_HALIGN_CENTER),
419 S(TABLE_HALIGN_RIGHT),
420 S(TABLE_HALIGN_MIXED),
421 S(TABLE_HALIGN_DECIMAL),
423 struct table_string *ts = table_string_cast (ts_);
424 cell->d[TABLE_HORZ][0] = 0;
425 cell->d[TABLE_HORZ][1] = 1;
426 cell->d[TABLE_VERT][0] = 0;
427 cell->d[TABLE_VERT][1] = 1;
429 cell->style = &styles[table_halign_interpret (ts->halign, false)];
430 cell->text = ts->string;
431 cell->n_footnotes = 0;
432 cell->destructor = NULL;
437 table_string_get_rule (const struct table *ts UNUSED,
438 enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
439 struct cell_color *color UNUSED)
444 static const struct table_class table_string_class =
446 table_string_destroy,
447 table_string_get_cell,
448 table_string_get_rule,
452 table_halign_to_string (enum table_halign halign)
456 case TABLE_HALIGN_LEFT: return "left";
457 case TABLE_HALIGN_CENTER: return "center";
458 case TABLE_HALIGN_RIGHT: return "right";
459 case TABLE_HALIGN_DECIMAL: return "decimal";
460 case TABLE_HALIGN_MIXED: return "mixed";
461 default: return "**error**";
466 table_valign_to_string (enum table_valign valign)
470 case TABLE_VALIGN_TOP: return "top";
471 case TABLE_VALIGN_CENTER: return "center";
472 case TABLE_VALIGN_BOTTOM: return "bottom";
473 default: return "**error**";
478 table_halign_interpret (enum table_halign halign, bool numeric)
482 case TABLE_HALIGN_LEFT:
483 case TABLE_HALIGN_CENTER:
484 case TABLE_HALIGN_RIGHT:
487 case TABLE_HALIGN_MIXED:
488 return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
490 case TABLE_HALIGN_DECIMAL:
491 return TABLE_HALIGN_DECIMAL;
499 font_style_copy (struct font_style *dst, const struct font_style *src)
503 dst->typeface = xstrdup (dst->typeface);
507 font_style_uninit (struct font_style *font)
510 free (font->typeface);
514 area_style_copy (struct area_style *dst, const struct area_style *src)
516 font_style_copy (&dst->font_style, &src->font_style);
517 dst->cell_style = src->cell_style;
521 area_style_uninit (struct area_style *area)
524 font_style_uninit (&area->font_style);
528 table_stroke_to_string (enum table_stroke stroke)
532 case TABLE_STROKE_NONE: return "none";
533 case TABLE_STROKE_SOLID: return "solid";
534 case TABLE_STROKE_DASHED: return "dashed";
535 case TABLE_STROKE_THICK: return "thick";
536 case TABLE_STROKE_THIN: return "thin";
537 case TABLE_STROKE_DOUBLE: return "double";
544 cell_color_dump (const struct cell_color *c)
547 printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
549 printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
553 font_style_dump (const struct font_style *f)
555 printf ("%s %dpx ", f->typeface, f->size);
556 cell_color_dump (&f->fg[0]);
558 cell_color_dump (&f->bg[0]);
559 if (!cell_color_equal (&f->fg[0], &f->fg[1])
560 || !cell_color_equal (&f->bg[0], &f->bg[1]))
563 cell_color_dump (&f->fg[1]);
565 cell_color_dump (&f->bg[1]);
568 fputs (" bold", stdout);
570 fputs (" italic", stdout);
572 fputs (" underline", stdout);
576 cell_style_dump (const struct cell_style *c)
578 fputs (table_halign_to_string (c->halign), stdout);
579 if (c->halign == TABLE_HALIGN_DECIMAL)
580 printf ("(%.2gpx)", c->decimal_offset);
581 printf (" %s", table_valign_to_string (c->valign));
582 printf (" %d,%d,%d,%dpx",
583 c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
584 c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);