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"
25 #include "libpspp/cast.h"
26 #include "libpspp/compiler.h"
27 #include "libpspp/pool.h"
28 #include "libpspp/str.h"
29 #include "output/table-item.h"
31 #include "gl/xalloc.h"
33 /* Increases TABLE's reference count, indicating that it has an additional
34 owner. An table that is shared among multiple owners must not be
37 table_ref (const struct table *table_)
39 struct table *table = CONST_CAST (struct table *, table_);
44 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
45 If TABLE no longer has any owners, it is freed. */
47 table_unref (struct table *table)
51 assert (table->ref_cnt > 0);
52 if (--table->ref_cnt == 0)
53 table->klass->destroy (table);
57 /* Returns true if TABLE has more than one owner. A table item that is shared
58 among multiple owners must not be modified. */
60 table_is_shared (const struct table *table)
62 return table->ref_cnt > 1;
65 /* Sets the number of left header columns in TABLE to HL. */
67 table_set_hl (struct table *table, int hl)
69 assert (!table_is_shared (table));
70 table->h[TABLE_HORZ][0] = hl;
73 /* Sets the number of right header columns in TABLE to HR. */
75 table_set_hr (struct table *table, int hr)
77 assert (!table_is_shared (table));
78 table->h[TABLE_HORZ][1] = hr;
81 /* Sets the number of top header rows in TABLE to HT. */
83 table_set_ht (struct table *table, int ht)
85 assert (!table_is_shared (table));
86 table->h[TABLE_VERT][0] = ht;
89 /* Sets the number of top header rows in TABLE to HB. */
91 table_set_hb (struct table *table, int hb)
93 assert (!table_is_shared (table));
94 table->h[TABLE_VERT][1] = hb;
97 /* Initializes TABLE as a table of the specified CLASS, initially with a
100 TABLE initially has 0 rows and columns and no headers. The table
101 implementation should update the numbers of rows and columns. The table
102 implementation (or its client) may update the header rows and columns.
104 A table is an abstract class, that is, a plain struct table is not useful on
105 its own. Thus, this function is normally called from the initialization
106 function of some subclass of table. */
108 table_init (struct table *table, const struct table_class *class)
110 table->klass = class;
111 table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
112 table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
113 table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
117 /* Sets the number of columns in TABLE to NC. */
119 table_set_nc (struct table *table, int nc)
121 assert (!table_is_shared (table));
122 table->n[TABLE_HORZ] = nc;
125 /* Sets the number of rows in TABLE to NR. */
127 table_set_nr (struct table *table, int nr)
129 assert (!table_is_shared (table));
130 table->n[TABLE_VERT] = nr;
134 cell_style_clone (struct pool *pool, const struct cell_style *old)
136 struct cell_style *new = pool_malloc (pool, sizeof *new);
139 new->font = pool_strdup (pool, new->font);
144 cell_style_free (struct cell_style *style)
153 /* Initializes CELL with the contents of the table cell at column X and row Y
154 within TABLE. When CELL is no longer needed, the caller is responsible for
155 freeing it by calling table_cell_free(CELL).
157 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
159 table_get_cell (const struct table *table, int x, int y,
160 struct table_cell *cell)
162 assert (x >= 0 && x < table->n[TABLE_HORZ]);
163 assert (y >= 0 && y < table->n[TABLE_VERT]);
165 static const struct cell_style default_style = CELL_STYLE_INITIALIZER;
166 cell->style = &default_style;
168 table->klass->get_cell (table, x, y, cell);
171 /* Frees CELL, which should have been initialized by calling
174 table_cell_free (struct table_cell *cell)
176 if (cell->destructor != NULL)
177 cell->destructor (cell->destructor_aux);
180 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
181 representing a rule running alongside one of the cells in TABLE.
183 Suppose NC is the number of columns in TABLE and NR is the number of rows.
184 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
185 (0,0), the return value is the rule that runs vertically on the left side of
186 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
187 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
190 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
191 within a 7x7 table. The '|' characters at the intersection of the X labels
192 and Y labels show the rule whose style would be returned by calling
193 table_get_rule with those X and Y values:
196 +--+--+--+--+--+--+--+
198 +--+--+--+--+--+--+--+
200 +--+--+--+--+--+--+--+
202 +--+--+--+--+--+--+--+
204 +--+--+--+--+--+--+--+
206 +--+--+--+--+--+--+--+
208 +--+--+--+--+--+--+--+
210 +--+--+--+--+--+--+--+
212 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
213 (X,Y) = (0,0), the return value is the rule that runs horizontally above
214 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
215 between that cell and cell (0,1); and so on, up to (0,NR), which runs
216 horizontally below cell (0,NR-1). */
218 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
219 struct cell_color *color)
221 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
222 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
223 *color = CELL_COLOR_BLACK;
224 return table->klass->get_rule (table, axis, x, y, color);
228 cell_contents_format_footnote_markers (const struct cell_contents *c,
231 for (size_t i = 0; i < c->n_footnotes; i++)
234 ds_put_byte (s, ',');
235 ds_put_cstr (s, c->footnotes[i]->marker);
239 static const struct footnote **
240 add_footnotes (const struct footnote **refs, size_t n_refs,
241 const struct footnote **footnotes, size_t *allocated, size_t *n)
243 for (size_t i = 0; i < n_refs; i++)
245 const struct footnote *f = refs[i];
246 if (f->idx >= *allocated)
248 size_t new_allocated = (f->idx + 1) * 2;
249 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
250 while (*allocated < new_allocated)
251 footnotes[(*allocated)++] = NULL;
253 footnotes[f->idx] = f;
261 table_collect_footnotes (const struct table_item *item,
262 const struct footnote ***footnotesp)
264 const struct footnote **footnotes = NULL;
265 size_t allocated = 0;
268 struct table *t = item->table;
269 for (int y = 0; y < table_nr (t); y++)
271 struct table_cell cell;
272 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
274 table_get_cell (t, x, y, &cell);
276 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
277 for (size_t i = 0; i < cell.n_contents; i++)
279 const struct cell_contents *c = &cell.contents[i];
280 footnotes = add_footnotes (c->footnotes, c->n_footnotes,
281 footnotes, &allocated, &n);
283 table_cell_free (&cell);
287 const struct table_item_text *title = table_item_get_title (item);
289 footnotes = add_footnotes (title->footnotes, title->n_footnotes,
290 footnotes, &allocated, &n);
292 const struct table_item_text *caption = table_item_get_caption (item);
294 footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
295 footnotes, &allocated, &n);
297 *footnotesp = footnotes;
301 struct table_unshared
304 struct table *subtable;
307 static const struct table_class table_unshared_class;
309 /* Takes ownership of TABLE and returns a table with the same contents but
310 which is guaranteed not to be shared (as returned by table_is_shared()).
312 If TABLE is unshared, just returns TABLE.
314 The only real use for this function is to create a copy of TABLE in which
315 the headers can be adjusted, which is a pretty specialized use case. */
317 table_unshare (struct table *table)
319 if (!table_is_shared (table))
323 struct table_unshared *tiu = xmalloc (sizeof *tiu);
324 table_init (&tiu->table, &table_unshared_class);
325 table_set_nc (&tiu->table, table_nc (table));
326 table_set_nr (&tiu->table, table_nr (table));
327 table_set_hl (&tiu->table, table_hl (table));
328 table_set_hr (&tiu->table, table_hr (table));
329 table_set_ht (&tiu->table, table_ht (table));
330 table_set_hb (&tiu->table, table_hb (table));
331 tiu->subtable = table;
336 static struct table_unshared *
337 table_unshared_cast (const struct table *table)
339 assert (table->klass == &table_unshared_class);
340 return UP_CAST (table, struct table_unshared, table);
344 table_unshared_destroy (struct table *tiu_)
346 struct table_unshared *tiu = table_unshared_cast (tiu_);
347 table_unref (tiu->subtable);
352 table_unshared_get_cell (const struct table *tiu_, int x, int y,
353 struct table_cell *cell)
355 struct table_unshared *tiu = table_unshared_cast (tiu_);
356 table_get_cell (tiu->subtable, x, y, cell);
360 table_unshared_get_rule (const struct table *tiu_,
361 enum table_axis axis, int x, int y,
362 struct cell_color *color)
364 struct table_unshared *tiu = table_unshared_cast (tiu_);
365 return table_get_rule (tiu->subtable, axis, x, y, color);
368 static const struct table_class table_unshared_class =
370 table_unshared_destroy,
371 table_unshared_get_cell,
372 table_unshared_get_rule,
381 unsigned int options;
384 static const struct table_class table_string_class;
386 /* Returns a table that contains a single cell, whose contents are S with
387 options OPTIONS (a combination of TAB_* values). */
389 table_from_string (unsigned int options, const char *s)
391 struct table_string *ts = xmalloc (sizeof *ts);
392 table_init (&ts->table, &table_string_class);
393 ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
394 ts->string = xstrdup (s);
395 ts->options = options;
399 static struct table_string *
400 table_string_cast (const struct table *table)
402 assert (table->klass == &table_string_class);
403 return UP_CAST (table, struct table_string, table);
407 table_string_destroy (struct table *ts_)
409 struct table_string *ts = table_string_cast (ts_);
415 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
416 struct table_cell *cell)
418 struct table_string *ts = table_string_cast (ts_);
419 cell->d[TABLE_HORZ][0] = 0;
420 cell->d[TABLE_HORZ][1] = 1;
421 cell->d[TABLE_VERT][0] = 0;
422 cell->d[TABLE_VERT][1] = 1;
423 cell->contents = &cell->inline_contents;
424 cell->inline_contents.options = ts->options;
425 cell->inline_contents.text = ts->string;
426 cell->inline_contents.n_footnotes = 0;
427 cell->n_contents = 1;
428 cell->destructor = NULL;
433 table_string_get_rule (const struct table *ts UNUSED,
434 enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
435 struct cell_color *color UNUSED)
440 static const struct table_class table_string_class =
442 table_string_destroy,
443 table_string_get_cell,
444 table_string_get_rule,