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/str.h"
28 #include "output/table-item.h"
30 #include "gl/xalloc.h"
32 /* Increases TABLE's reference count, indicating that it has an additional
33 owner. An table that is shared among multiple owners must not be
36 table_ref (const struct table *table_)
38 struct table *table = CONST_CAST (struct table *, table_);
43 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
44 If TABLE no longer has any owners, it is freed. */
46 table_unref (struct table *table)
50 assert (table->ref_cnt > 0);
51 if (--table->ref_cnt == 0)
52 table->klass->destroy (table);
56 /* Returns true if TABLE has more than one owner. A table item that is shared
57 among multiple owners must not be modified. */
59 table_is_shared (const struct table *table)
61 return table->ref_cnt > 1;
64 /* Sets the number of left header columns in TABLE to HL. */
66 table_set_hl (struct table *table, int hl)
68 assert (!table_is_shared (table));
69 table->h[TABLE_HORZ][0] = hl;
72 /* Sets the number of right header columns in TABLE to HR. */
74 table_set_hr (struct table *table, int hr)
76 assert (!table_is_shared (table));
77 table->h[TABLE_HORZ][1] = hr;
80 /* Sets the number of top header rows in TABLE to HT. */
82 table_set_ht (struct table *table, int ht)
84 assert (!table_is_shared (table));
85 table->h[TABLE_VERT][0] = ht;
88 /* Sets the number of top header rows in TABLE to HB. */
90 table_set_hb (struct table *table, int hb)
92 assert (!table_is_shared (table));
93 table->h[TABLE_VERT][1] = hb;
96 /* Initializes TABLE as a table of the specified CLASS, initially with a
99 TABLE initially has 0 rows and columns and no headers. The table
100 implementation should update the numbers of rows and columns. The table
101 implementation (or its client) may update the header rows and columns.
103 A table is an abstract class, that is, a plain struct table is not useful on
104 its own. Thus, this function is normally called from the initialization
105 function of some subclass of table. */
107 table_init (struct table *table, const struct table_class *class)
109 table->klass = class;
110 table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
111 table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
112 table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
116 /* Sets the number of columns in TABLE to NC. */
118 table_set_nc (struct table *table, int nc)
120 assert (!table_is_shared (table));
121 table->n[TABLE_HORZ] = nc;
124 /* Sets the number of rows in TABLE to NR. */
126 table_set_nr (struct table *table, int nr)
128 assert (!table_is_shared (table));
129 table->n[TABLE_VERT] = nr;
133 cell_style_clone (const struct cell_style *old)
135 struct cell_style *new = xmalloc (sizeof *new);
138 new->font = strdup (new->font);
143 cell_style_free (struct cell_style *style)
152 /* Initializes CELL with the contents of the table cell at column X and row Y
153 within TABLE. When CELL is no longer needed, the caller is responsible for
154 freeing it by calling table_cell_free(CELL).
156 The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
158 table_get_cell (const struct table *table, int x, int y,
159 struct table_cell *cell)
161 assert (x >= 0 && x < table->n[TABLE_HORZ]);
162 assert (y >= 0 && y < table->n[TABLE_VERT]);
164 static const struct cell_style default_style = CELL_STYLE_INITIALIZER;
165 cell->style = &default_style;
167 table->klass->get_cell (table, x, y, cell);
170 /* Frees CELL, which should have been initialized by calling
173 table_cell_free (struct table_cell *cell)
175 if (cell->destructor != NULL)
176 cell->destructor (cell->destructor_aux);
179 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
180 representing a rule running alongside one of the cells in TABLE.
182 Suppose NC is the number of columns in TABLE and NR is the number of rows.
183 Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR. If (X,Y) =
184 (0,0), the return value is the rule that runs vertically on the left side of
185 cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
186 cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
189 The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
190 within a 7x7 table. The '|' characters at the intersection of the X labels
191 and Y labels show the rule whose style would be returned by calling
192 table_get_rule with those X and Y values:
195 +--+--+--+--+--+--+--+
197 +--+--+--+--+--+--+--+
199 +--+--+--+--+--+--+--+
201 +--+--+--+--+--+--+--+
203 +--+--+--+--+--+--+--+
205 +--+--+--+--+--+--+--+
207 +--+--+--+--+--+--+--+
209 +--+--+--+--+--+--+--+
211 Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR. If
212 (X,Y) = (0,0), the return value is the rule that runs horizontally above
213 the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
214 between that cell and cell (0,1); and so on, up to (0,NR), which runs
215 horizontally below cell (0,NR-1). */
217 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
218 struct cell_color *color)
220 assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
221 assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
222 *color = CELL_COLOR_BLACK;
223 return table->klass->get_rule (table, axis, x, y, color);
227 cell_contents_format_footnote_markers (const struct cell_contents *c,
230 for (size_t i = 0; i < c->n_footnotes; i++)
233 ds_put_byte (s, ',');
234 ds_put_cstr (s, c->footnotes[i]->marker);
238 static const struct footnote **
239 add_footnotes (const struct footnote **refs, size_t n_refs,
240 const struct footnote **footnotes, size_t *allocated, size_t *n)
242 for (size_t i = 0; i < n_refs; i++)
244 const struct footnote *f = refs[i];
245 if (f->idx >= *allocated)
247 size_t new_allocated = (f->idx + 1) * 2;
248 footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
249 while (*allocated < new_allocated)
250 footnotes[(*allocated)++] = NULL;
252 footnotes[f->idx] = f;
260 table_collect_footnotes (const struct table_item *item,
261 const struct footnote ***footnotesp)
263 const struct footnote **footnotes = NULL;
264 size_t allocated = 0;
267 struct table *t = item->table;
268 for (int y = 0; y < table_nr (t); y++)
270 struct table_cell cell;
271 for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
273 table_get_cell (t, x, y, &cell);
275 if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
276 for (size_t i = 0; i < cell.n_contents; i++)
278 const struct cell_contents *c = &cell.contents[i];
279 footnotes = add_footnotes (c->footnotes, c->n_footnotes,
280 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,
380 unsigned int options;
383 static const struct table_class table_string_class;
385 /* Returns a table that contains a single cell, whose contents are S with
386 options OPTIONS (a combination of TAB_* values). */
388 table_from_string (unsigned int options, const char *s)
390 struct table_string *ts = xmalloc (sizeof *ts);
391 table_init (&ts->table, &table_string_class);
392 ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
393 ts->string = xstrdup (s);
394 ts->options = options;
398 static struct table_string *
399 table_string_cast (const struct table *table)
401 assert (table->klass == &table_string_class);
402 return UP_CAST (table, struct table_string, table);
406 table_string_destroy (struct table *ts_)
408 struct table_string *ts = table_string_cast (ts_);
414 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
415 struct table_cell *cell)
417 struct table_string *ts = table_string_cast (ts_);
418 cell->d[TABLE_HORZ][0] = 0;
419 cell->d[TABLE_HORZ][1] = 1;
420 cell->d[TABLE_VERT][0] = 0;
421 cell->d[TABLE_VERT][1] = 1;
422 cell->contents = &cell->inline_contents;
423 cell->inline_contents.options = ts->options;
424 cell->inline_contents.text = ts->string;
425 cell->inline_contents.n_footnotes = 0;
426 cell->n_contents = 1;
427 cell->destructor = NULL;
432 table_string_get_rule (const struct table *ts UNUSED,
433 enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
434 struct cell_color *color UNUSED)
439 static const struct table_class table_string_class =
441 table_string_destroy,
442 table_string_get_cell,
443 table_string_get_rule,