output: Add support for colors in cells.
[pspp] / src / output / table.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2011, 2014, 2016 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "output/table.h"
20 #include "output/table-provider.h"
21
22 #include <assert.h>
23 #include <stdlib.h>
24
25 #include "libpspp/cast.h"
26 #include "libpspp/compiler.h"
27 #include "libpspp/str.h"
28 #include "output/table-item.h"
29
30 #include "gl/xalloc.h"
31
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
34    modified. */
35 struct table *
36 table_ref (const struct table *table_)
37 {
38   struct table *table = CONST_CAST (struct table *, table_);
39   table->ref_cnt++;
40   return table;
41 }
42
43 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
44    If TABLE no longer has any owners, it is freed. */
45 void
46 table_unref (struct table *table)
47 {
48   if (table != NULL)
49     {
50       assert (table->ref_cnt > 0);
51       if (--table->ref_cnt == 0)
52         table->klass->destroy (table);
53     }
54 }
55
56 /* Returns true if TABLE has more than one owner.  A table item that is shared
57    among multiple owners must not be modified. */
58 bool
59 table_is_shared (const struct table *table)
60 {
61   return table->ref_cnt > 1;
62 }
63
64 /* Sets the number of left header columns in TABLE to HL. */
65 void
66 table_set_hl (struct table *table, int hl)
67 {
68   assert (!table_is_shared (table));
69   table->h[TABLE_HORZ][0] = hl;
70 }
71
72 /* Sets the number of right header columns in TABLE to HR. */
73 void
74 table_set_hr (struct table *table, int hr)
75 {
76   assert (!table_is_shared (table));
77   table->h[TABLE_HORZ][1] = hr;
78 }
79
80 /* Sets the number of top header rows in TABLE to HT. */
81 void
82 table_set_ht (struct table *table, int ht)
83 {
84   assert (!table_is_shared (table));
85   table->h[TABLE_VERT][0] = ht;
86 }
87
88 /* Sets the number of top header rows in TABLE to HB. */
89 void
90 table_set_hb (struct table *table, int hb)
91 {
92   assert (!table_is_shared (table));
93   table->h[TABLE_VERT][1] = hb;
94 }
95 \f
96 /* Initializes TABLE as a table of the specified CLASS, initially with a
97    reference count of 1.
98
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.
102
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. */
106 void
107 table_init (struct table *table, const struct table_class *class)
108 {
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;
113   table->ref_cnt = 1;
114 }
115
116 /* Sets the number of columns in TABLE to NC. */
117 void
118 table_set_nc (struct table *table, int nc)
119 {
120   assert (!table_is_shared (table));
121   table->n[TABLE_HORZ] = nc;
122 }
123
124 /* Sets the number of rows in TABLE to NR. */
125 void
126 table_set_nr (struct table *table, int nr)
127 {
128   assert (!table_is_shared (table));
129   table->n[TABLE_VERT] = nr;
130 }
131 \f
132 /* Initializes CELL with the contents of the table cell at column X and row Y
133    within TABLE.  When CELL is no longer needed, the caller is responsible for
134    freeing it by calling table_cell_free(CELL).
135
136    The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
137 void
138 table_get_cell (const struct table *table, int x, int y,
139                 struct table_cell *cell)
140 {
141   assert (x >= 0 && x < table->n[TABLE_HORZ]);
142   assert (y >= 0 && y < table->n[TABLE_VERT]);
143
144   static const struct cell_style default_style =
145     {
146       .fg = { 0, 0, 0 },
147       .bg = { 255, 255, 255 },
148     };
149   cell->style = &default_style;
150
151   table->klass->get_cell (table, x, y, cell);
152 }
153
154 /* Frees CELL, which should have been initialized by calling
155    table_get_cell(). */
156 void
157 table_cell_free (struct table_cell *cell)
158 {
159   if (cell->destructor != NULL)
160     cell->destructor (cell->destructor_aux);
161 }
162
163 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
164    representing a rule running alongside one of the cells in TABLE.
165
166    Suppose NC is the number of columns in TABLE and NR is the number of rows.
167    Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR.  If (X,Y) =
168    (0,0), the return value is the rule that runs vertically on the left side of
169    cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
170    cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
171    cell (NC-1,0).
172
173    The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
174    within a 7x7 table.  The '|' characters at the intersection of the X labels
175    and Y labels show the rule whose style would be returned by calling
176    table_get_rule with those X and Y values:
177
178                            0  1  2  3  4  5  6  7
179                            +--+--+--+--+--+--+--+
180                          0 |  |  |  |  |  |  |  |
181                            +--+--+--+--+--+--+--+
182                          1 |  |  |  |  |  |  |  |
183                            +--+--+--+--+--+--+--+
184                          2 |  |  |  |  |  |  |  |
185                            +--+--+--+--+--+--+--+
186                          3 |  |  |  |  |  |  |  |
187                            +--+--+--+--+--+--+--+
188                          4 |  |  |  |  |  |  |  |
189                            +--+--+--+--+--+--+--+
190                          5 |  |  |  |  |  |  |  |
191                            +--+--+--+--+--+--+--+
192                          6 |  |  |  |  |  |  |  |
193                            +--+--+--+--+--+--+--+
194
195    Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR.  If
196    (X,Y) = (0,0), the return value is the rule that runs horizontally above
197    the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
198    between that cell and cell (0,1); and so on, up to (0,NR), which runs
199    horizontally below cell (0,NR-1). */
200 int
201 table_get_rule (const struct table *table, enum table_axis axis, int x, int y)
202 {
203   assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
204   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
205   return table->klass->get_rule (table, axis, x, y);
206 }
207
208 void
209 cell_contents_format_footnote_markers (const struct cell_contents *c,
210                                        struct string *s)
211 {
212   for (size_t i = 0; i < c->n_footnotes; i++)
213     {
214       if (i)
215         ds_put_byte (s, ',');
216       ds_put_cstr (s, c->footnotes[i]->marker);
217     }
218 }
219
220 static const struct footnote **
221 add_footnotes (const struct footnote **refs, size_t n_refs,
222                const struct footnote **footnotes, size_t *allocated, size_t *n)
223 {
224   for (size_t i = 0; i < n_refs; i++)
225     {
226       const struct footnote *f = refs[i];
227       if (f->idx >= *allocated)
228         {
229           size_t new_allocated = (f->idx + 1) * 2;
230           footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
231           while (*allocated < new_allocated)
232             footnotes[(*allocated)++] = NULL;
233         }
234       footnotes[f->idx] = f;
235       if (f->idx >= *n)
236         *n = f->idx + 1;
237     }
238   return footnotes;
239 }
240
241 size_t
242 table_collect_footnotes (const struct table_item *item,
243                          const struct footnote ***footnotesp)
244 {
245   const struct footnote **footnotes = NULL;
246   size_t allocated = 0;
247   size_t n = 0;
248
249   struct table *t = item->table;
250   for (int y = 0; y < table_nr (t); y++)
251     {
252       struct table_cell cell;
253       for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
254         {
255           table_get_cell (t, x, y, &cell);
256
257           if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
258             for (size_t i = 0; i < cell.n_contents; i++)
259               {
260                 const struct cell_contents *c = &cell.contents[i];
261                 footnotes = add_footnotes (c->footnotes, c->n_footnotes,
262                                            footnotes, &allocated, &n);
263               }
264           table_cell_free (&cell);
265         }
266     }
267
268   const struct table_item_text *title = table_item_get_title (item);
269   if (title)
270     footnotes = add_footnotes (title->footnotes, title->n_footnotes,
271                                footnotes, &allocated, &n);
272
273   const struct table_item_text *caption = table_item_get_caption (item);
274   if (caption)
275     footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
276                                footnotes, &allocated, &n);
277
278   *footnotesp = footnotes;
279   return n;
280 }
281 \f
282 struct table_unshared
283   {
284     struct table table;
285     struct table *subtable;
286   };
287
288 static const struct table_class table_unshared_class;
289
290 /* Takes ownership of TABLE and returns a table with the same contents but
291    which is guaranteed not to be shared (as returned by table_is_shared()).
292
293    If TABLE is unshared, just returns TABLE.
294
295    The only real use for this function is to create a copy of TABLE in which
296    the headers can be adjusted, which is a pretty specialized use case. */
297 struct table *
298 table_unshare (struct table *table)
299 {
300   if (!table_is_shared (table))
301     return table;
302   else
303     {
304       struct table_unshared *tiu = xmalloc (sizeof *tiu);
305       table_init (&tiu->table, &table_unshared_class);
306       table_set_nc (&tiu->table, table_nc (table));
307       table_set_nr (&tiu->table, table_nr (table));
308       table_set_hl (&tiu->table, table_hl (table));
309       table_set_hr (&tiu->table, table_hr (table));
310       table_set_ht (&tiu->table, table_ht (table));
311       table_set_hb (&tiu->table, table_hb (table));
312       tiu->subtable = table;
313       return &tiu->table;
314     }
315 }
316
317 static struct table_unshared *
318 table_unshared_cast (const struct table *table)
319 {
320   assert (table->klass == &table_unshared_class);
321   return UP_CAST (table, struct table_unshared, table);
322 }
323
324 static void
325 table_unshared_destroy (struct table *tiu_)
326 {
327   struct table_unshared *tiu = table_unshared_cast (tiu_);
328   table_unref (tiu->subtable);
329   free (tiu);
330 }
331
332 static void
333 table_unshared_get_cell (const struct table *tiu_, int x, int y,
334                               struct table_cell *cell)
335 {
336   struct table_unshared *tiu = table_unshared_cast (tiu_);
337   table_get_cell (tiu->subtable, x, y, cell);
338 }
339
340 static int
341 table_unshared_get_rule (const struct table *tiu_,
342                               enum table_axis axis, int x, int y)
343 {
344   struct table_unshared *tiu = table_unshared_cast (tiu_);
345   return table_get_rule (tiu->subtable, axis, x, y);
346 }
347
348 static const struct table_class table_unshared_class =
349   {
350     table_unshared_destroy,
351     table_unshared_get_cell,
352     table_unshared_get_rule,
353     NULL,                       /* paste */
354     NULL,                       /* select */
355   };
356 \f
357 struct table_string
358   {
359     struct table table;
360     char *string;
361     unsigned int options;
362   };
363
364 static const struct table_class table_string_class;
365
366 /* Returns a table that contains a single cell, whose contents are S with
367    options OPTIONS (a combination of TAB_* values).  */
368 struct table *
369 table_from_string (unsigned int options, const char *s)
370 {
371   struct table_string *ts = xmalloc (sizeof *ts);
372   table_init (&ts->table, &table_string_class);
373   ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
374   ts->string = xstrdup (s);
375   ts->options = options;
376   return &ts->table;
377 }
378
379 static struct table_string *
380 table_string_cast (const struct table *table)
381 {
382   assert (table->klass == &table_string_class);
383   return UP_CAST (table, struct table_string, table);
384 }
385
386 static void
387 table_string_destroy (struct table *ts_)
388 {
389   struct table_string *ts = table_string_cast (ts_);
390   free (ts->string);
391   free (ts);
392 }
393
394 static void
395 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
396                        struct table_cell *cell)
397 {
398   struct table_string *ts = table_string_cast (ts_);
399   cell->d[TABLE_HORZ][0] = 0;
400   cell->d[TABLE_HORZ][1] = 1;
401   cell->d[TABLE_VERT][0] = 0;
402   cell->d[TABLE_VERT][1] = 1;
403   cell->contents = &cell->inline_contents;
404   cell->inline_contents.options = ts->options;
405   cell->inline_contents.text = ts->string;
406   cell->inline_contents.n_footnotes = 0;
407   cell->n_contents = 1;
408   cell->destructor = NULL;
409 }
410
411
412 static int
413 table_string_get_rule (const struct table *ts UNUSED,
414                        enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
415 {
416   return TAL_0;
417 }
418
419 static const struct table_class table_string_class =
420   {
421     table_string_destroy,
422     table_string_get_cell,
423     table_string_get_rule,
424     NULL,                       /* paste */
425     NULL,                       /* select */
426   };