44efa3abc34f1fc379356598742212dca7ed6b10
[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 struct cell_style *
133 cell_style_clone (const struct cell_style *old)
134 {
135   struct cell_style *new = xmalloc (sizeof *new);
136   *new = *old;
137   if (new->font)
138     new->font = strdup (new->font);
139   return new;
140 }
141
142 void
143 cell_style_free (struct cell_style *style)
144 {
145   if (style)
146     {
147       free (style->font);
148       free (style);
149     }
150 }
151
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).
155
156    The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
157 void
158 table_get_cell (const struct table *table, int x, int y,
159                 struct table_cell *cell)
160 {
161   assert (x >= 0 && x < table->n[TABLE_HORZ]);
162   assert (y >= 0 && y < table->n[TABLE_VERT]);
163
164   static const struct cell_style default_style = CELL_STYLE_INITIALIZER;
165   cell->style = &default_style;
166
167   table->klass->get_cell (table, x, y, cell);
168 }
169
170 /* Frees CELL, which should have been initialized by calling
171    table_get_cell(). */
172 void
173 table_cell_free (struct table_cell *cell)
174 {
175   if (cell->destructor != NULL)
176     cell->destructor (cell->destructor_aux);
177 }
178
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.
181
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
187    cell (NC-1,0).
188
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:
193
194                            0  1  2  3  4  5  6  7
195                            +--+--+--+--+--+--+--+
196                          0 |  |  |  |  |  |  |  |
197                            +--+--+--+--+--+--+--+
198                          1 |  |  |  |  |  |  |  |
199                            +--+--+--+--+--+--+--+
200                          2 |  |  |  |  |  |  |  |
201                            +--+--+--+--+--+--+--+
202                          3 |  |  |  |  |  |  |  |
203                            +--+--+--+--+--+--+--+
204                          4 |  |  |  |  |  |  |  |
205                            +--+--+--+--+--+--+--+
206                          5 |  |  |  |  |  |  |  |
207                            +--+--+--+--+--+--+--+
208                          6 |  |  |  |  |  |  |  |
209                            +--+--+--+--+--+--+--+
210
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). */
216 int
217 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
218                 struct cell_color *color)
219 {
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);
224 }
225
226 void
227 cell_contents_format_footnote_markers (const struct cell_contents *c,
228                                        struct string *s)
229 {
230   for (size_t i = 0; i < c->n_footnotes; i++)
231     {
232       if (i)
233         ds_put_byte (s, ',');
234       ds_put_cstr (s, c->footnotes[i]->marker);
235     }
236 }
237
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)
241 {
242   for (size_t i = 0; i < n_refs; i++)
243     {
244       const struct footnote *f = refs[i];
245       if (f->idx >= *allocated)
246         {
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;
251         }
252       footnotes[f->idx] = f;
253       if (f->idx >= *n)
254         *n = f->idx + 1;
255     }
256   return footnotes;
257 }
258
259 size_t
260 table_collect_footnotes (const struct table_item *item,
261                          const struct footnote ***footnotesp)
262 {
263   const struct footnote **footnotes = NULL;
264   size_t allocated = 0;
265   size_t n = 0;
266
267   struct table *t = item->table;
268   for (int y = 0; y < table_nr (t); y++)
269     {
270       struct table_cell cell;
271       for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
272         {
273           table_get_cell (t, x, y, &cell);
274
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++)
277               {
278                 const struct cell_contents *c = &cell.contents[i];
279                 footnotes = add_footnotes (c->footnotes, c->n_footnotes,
280                                            footnotes, &allocated, &n);
281               }
282           table_cell_free (&cell);
283         }
284     }
285
286   const struct table_item_text *title = table_item_get_title (item);
287   if (title)
288     footnotes = add_footnotes (title->footnotes, title->n_footnotes,
289                                footnotes, &allocated, &n);
290
291   const struct table_item_text *caption = table_item_get_caption (item);
292   if (caption)
293     footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
294                                footnotes, &allocated, &n);
295
296   *footnotesp = footnotes;
297   return n;
298 }
299 \f
300 struct table_unshared
301   {
302     struct table table;
303     struct table *subtable;
304   };
305
306 static const struct table_class table_unshared_class;
307
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()).
310
311    If TABLE is unshared, just returns TABLE.
312
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. */
315 struct table *
316 table_unshare (struct table *table)
317 {
318   if (!table_is_shared (table))
319     return table;
320   else
321     {
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;
331       return &tiu->table;
332     }
333 }
334
335 static struct table_unshared *
336 table_unshared_cast (const struct table *table)
337 {
338   assert (table->klass == &table_unshared_class);
339   return UP_CAST (table, struct table_unshared, table);
340 }
341
342 static void
343 table_unshared_destroy (struct table *tiu_)
344 {
345   struct table_unshared *tiu = table_unshared_cast (tiu_);
346   table_unref (tiu->subtable);
347   free (tiu);
348 }
349
350 static void
351 table_unshared_get_cell (const struct table *tiu_, int x, int y,
352                               struct table_cell *cell)
353 {
354   struct table_unshared *tiu = table_unshared_cast (tiu_);
355   table_get_cell (tiu->subtable, x, y, cell);
356 }
357
358 static int
359 table_unshared_get_rule (const struct table *tiu_,
360                          enum table_axis axis, int x, int y,
361                          struct cell_color *color)
362 {
363   struct table_unshared *tiu = table_unshared_cast (tiu_);
364   return table_get_rule (tiu->subtable, axis, x, y, color);
365 }
366
367 static const struct table_class table_unshared_class =
368   {
369     table_unshared_destroy,
370     table_unshared_get_cell,
371     table_unshared_get_rule,
372     NULL,                       /* paste */
373     NULL,                       /* select */
374   };
375 \f
376 struct table_string
377   {
378     struct table table;
379     char *string;
380     unsigned int options;
381   };
382
383 static const struct table_class table_string_class;
384
385 /* Returns a table that contains a single cell, whose contents are S with
386    options OPTIONS (a combination of TAB_* values).  */
387 struct table *
388 table_from_string (unsigned int options, const char *s)
389 {
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;
395   return &ts->table;
396 }
397
398 static struct table_string *
399 table_string_cast (const struct table *table)
400 {
401   assert (table->klass == &table_string_class);
402   return UP_CAST (table, struct table_string, table);
403 }
404
405 static void
406 table_string_destroy (struct table *ts_)
407 {
408   struct table_string *ts = table_string_cast (ts_);
409   free (ts->string);
410   free (ts);
411 }
412
413 static void
414 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
415                        struct table_cell *cell)
416 {
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;
428 }
429
430
431 static int
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)
435 {
436   return TAL_0;
437 }
438
439 static const struct table_class table_string_class =
440   {
441     table_string_destroy,
442     table_string_get_cell,
443     table_string_get_rule,
444     NULL,                       /* paste */
445     NULL,                       /* select */
446   };