d94316eed2bc62ed430d6085431652ec7554e347
[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 <inttypes.h>
24 #include <stdlib.h>
25
26 #include "libpspp/assertion.h"
27 #include "libpspp/cast.h"
28 #include "libpspp/compiler.h"
29 #include "libpspp/pool.h"
30 #include "libpspp/str.h"
31 #include "output/table-item.h"
32
33 #include "gl/xalloc.h"
34
35 /* Increases TABLE's reference count, indicating that it has an additional
36    owner.  An table that is shared among multiple owners must not be
37    modified. */
38 struct table *
39 table_ref (const struct table *table_)
40 {
41   struct table *table = CONST_CAST (struct table *, table_);
42   table->ref_cnt++;
43   return table;
44 }
45
46 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
47    If TABLE no longer has any owners, it is freed. */
48 void
49 table_unref (struct table *table)
50 {
51   if (table != NULL)
52     {
53       assert (table->ref_cnt > 0);
54       if (--table->ref_cnt == 0)
55         table->klass->destroy (table);
56     }
57 }
58
59 /* Returns true if TABLE has more than one owner.  A table item that is shared
60    among multiple owners must not be modified. */
61 bool
62 table_is_shared (const struct table *table)
63 {
64   return table->ref_cnt > 1;
65 }
66
67 /* Sets the number of left header columns in TABLE to HL. */
68 void
69 table_set_hl (struct table *table, int hl)
70 {
71   assert (!table_is_shared (table));
72   table->h[TABLE_HORZ][0] = hl;
73 }
74
75 /* Sets the number of right header columns in TABLE to HR. */
76 void
77 table_set_hr (struct table *table, int hr)
78 {
79   assert (!table_is_shared (table));
80   table->h[TABLE_HORZ][1] = hr;
81 }
82
83 /* Sets the number of top header rows in TABLE to HT. */
84 void
85 table_set_ht (struct table *table, int ht)
86 {
87   assert (!table_is_shared (table));
88   table->h[TABLE_VERT][0] = ht;
89 }
90
91 /* Sets the number of top header rows in TABLE to HB. */
92 void
93 table_set_hb (struct table *table, int hb)
94 {
95   assert (!table_is_shared (table));
96   table->h[TABLE_VERT][1] = hb;
97 }
98 \f
99 /* Initializes TABLE as a table of the specified CLASS, initially with a
100    reference count of 1.
101
102    TABLE initially has 0 rows and columns and no headers.  The table
103    implementation should update the numbers of rows and columns.  The table
104    implementation (or its client) may update the header rows and columns.
105
106    A table is an abstract class, that is, a plain struct table is not useful on
107    its own.  Thus, this function is normally called from the initialization
108    function of some subclass of table. */
109 void
110 table_init (struct table *table, const struct table_class *class)
111 {
112   table->klass = class;
113   table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
114   table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
115   table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
116   table->ref_cnt = 1;
117 }
118
119 /* Sets the number of columns in TABLE to NC. */
120 void
121 table_set_nc (struct table *table, int nc)
122 {
123   assert (!table_is_shared (table));
124   table->n[TABLE_HORZ] = nc;
125 }
126
127 /* Sets the number of rows in TABLE to NR. */
128 void
129 table_set_nr (struct table *table, int nr)
130 {
131   assert (!table_is_shared (table));
132   table->n[TABLE_VERT] = nr;
133 }
134 \f
135 struct area_style *
136 area_style_clone (struct pool *pool, const struct area_style *old)
137 {
138   struct area_style *new = pool_malloc (pool, sizeof *new);
139   *new = *old;
140   if (new->font_style.typeface)
141     new->font_style.typeface = pool_strdup (pool, new->font_style.typeface);
142   return new;
143 }
144
145 void
146 area_style_free (struct area_style *style)
147 {
148   if (style)
149     {
150       free (style->font_style.typeface);
151       free (style);
152     }
153 }
154
155 /* Initializes CELL with the contents of the table cell at column X and row Y
156    within TABLE.  When CELL is no longer needed, the caller is responsible for
157    freeing it by calling table_cell_free(CELL).
158
159    The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
160 void
161 table_get_cell (const struct table *table, int x, int y,
162                 struct table_cell *cell)
163 {
164   assert (x >= 0 && x < table->n[TABLE_HORZ]);
165   assert (y >= 0 && y < table->n[TABLE_VERT]);
166
167   static const struct area_style default_style = AREA_STYLE_INITIALIZER;
168   cell->style = &default_style;
169
170   table->klass->get_cell (table, x, y, cell);
171 }
172
173 /* Frees CELL, which should have been initialized by calling
174    table_get_cell(). */
175 void
176 table_cell_free (struct table_cell *cell)
177 {
178   if (cell->destructor != NULL)
179     cell->destructor (cell->destructor_aux);
180 }
181
182 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
183    representing a rule running alongside one of the cells in TABLE.
184
185    Suppose NC is the number of columns in TABLE and NR is the number of rows.
186    Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR.  If (X,Y) =
187    (0,0), the return value is the rule that runs vertically on the left side of
188    cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
189    cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
190    cell (NC-1,0).
191
192    The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
193    within a 7x7 table.  The '|' characters at the intersection of the X labels
194    and Y labels show the rule whose style would be returned by calling
195    table_get_rule with those X and Y values:
196
197                            0  1  2  3  4  5  6  7
198                            +--+--+--+--+--+--+--+
199                          0 |  |  |  |  |  |  |  |
200                            +--+--+--+--+--+--+--+
201                          1 |  |  |  |  |  |  |  |
202                            +--+--+--+--+--+--+--+
203                          2 |  |  |  |  |  |  |  |
204                            +--+--+--+--+--+--+--+
205                          3 |  |  |  |  |  |  |  |
206                            +--+--+--+--+--+--+--+
207                          4 |  |  |  |  |  |  |  |
208                            +--+--+--+--+--+--+--+
209                          5 |  |  |  |  |  |  |  |
210                            +--+--+--+--+--+--+--+
211                          6 |  |  |  |  |  |  |  |
212                            +--+--+--+--+--+--+--+
213
214    Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR.  If
215    (X,Y) = (0,0), the return value is the rule that runs horizontally above
216    the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
217    between that cell and cell (0,1); and so on, up to (0,NR), which runs
218    horizontally below cell (0,NR-1). */
219 int
220 table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
221                 struct cell_color *color)
222 {
223   assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
224   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
225   *color = (struct cell_color) CELL_COLOR_BLACK;
226   return table->klass->get_rule (table, axis, x, y, color);
227 }
228
229 void
230 table_cell_format_footnote_markers (const struct table_cell *cell,
231                                     struct string *s)
232 {
233   for (size_t i = 0; i < cell->n_footnotes; i++)
234     {
235       if (i)
236         ds_put_byte (s, ',');
237       ds_put_cstr (s, cell->footnotes[i]->marker);
238     }
239 }
240
241 static const struct footnote **
242 add_footnotes (const struct footnote **refs, size_t n_refs,
243                const struct footnote **footnotes, size_t *allocated, size_t *n)
244 {
245   for (size_t i = 0; i < n_refs; i++)
246     {
247       const struct footnote *f = refs[i];
248       if (f->idx >= *allocated)
249         {
250           size_t new_allocated = (f->idx + 1) * 2;
251           footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
252           while (*allocated < new_allocated)
253             footnotes[(*allocated)++] = NULL;
254         }
255       footnotes[f->idx] = f;
256       if (f->idx >= *n)
257         *n = f->idx + 1;
258     }
259   return footnotes;
260 }
261
262 size_t
263 table_collect_footnotes (const struct table_item *item,
264                          const struct footnote ***footnotesp)
265 {
266   const struct footnote **footnotes = NULL;
267   size_t allocated = 0;
268   size_t n = 0;
269
270   struct table *t = item->table;
271   for (int y = 0; y < table_nr (t); y++)
272     {
273       struct table_cell cell;
274       for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
275         {
276           table_get_cell (t, x, y, &cell);
277
278           if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
279             footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
280                                        footnotes, &allocated, &n);
281           table_cell_free (&cell);
282         }
283     }
284
285   const struct table_item_text *title = table_item_get_title (item);
286   if (title)
287     footnotes = add_footnotes (title->footnotes, title->n_footnotes,
288                                footnotes, &allocated, &n);
289
290   const struct table_item_text *caption = table_item_get_caption (item);
291   if (caption)
292     footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
293                                footnotes, &allocated, &n);
294
295   *footnotesp = footnotes;
296   return n;
297 }
298 \f
299 struct table_unshared
300   {
301     struct table table;
302     struct table *subtable;
303   };
304
305 static const struct table_class table_unshared_class;
306
307 /* Takes ownership of TABLE and returns a table with the same contents but
308    which is guaranteed not to be shared (as returned by table_is_shared()).
309
310    If TABLE is unshared, just returns TABLE.
311
312    The only real use for this function is to create a copy of TABLE in which
313    the headers can be adjusted, which is a pretty specialized use case. */
314 struct table *
315 table_unshare (struct table *table)
316 {
317   if (!table_is_shared (table))
318     return table;
319   else
320     {
321       struct table_unshared *tiu = xmalloc (sizeof *tiu);
322       table_init (&tiu->table, &table_unshared_class);
323       table_set_nc (&tiu->table, table_nc (table));
324       table_set_nr (&tiu->table, table_nr (table));
325       table_set_hl (&tiu->table, table_hl (table));
326       table_set_hr (&tiu->table, table_hr (table));
327       table_set_ht (&tiu->table, table_ht (table));
328       table_set_hb (&tiu->table, table_hb (table));
329       tiu->subtable = table;
330       return &tiu->table;
331     }
332 }
333
334 static struct table_unshared *
335 table_unshared_cast (const struct table *table)
336 {
337   assert (table->klass == &table_unshared_class);
338   return UP_CAST (table, struct table_unshared, table);
339 }
340
341 static void
342 table_unshared_destroy (struct table *tiu_)
343 {
344   struct table_unshared *tiu = table_unshared_cast (tiu_);
345   table_unref (tiu->subtable);
346   free (tiu);
347 }
348
349 static void
350 table_unshared_get_cell (const struct table *tiu_, int x, int y,
351                               struct table_cell *cell)
352 {
353   struct table_unshared *tiu = table_unshared_cast (tiu_);
354   table_get_cell (tiu->subtable, x, y, cell);
355 }
356
357 static int
358 table_unshared_get_rule (const struct table *tiu_,
359                          enum table_axis axis, int x, int y,
360                          struct cell_color *color)
361 {
362   struct table_unshared *tiu = table_unshared_cast (tiu_);
363   return table_get_rule (tiu->subtable, axis, x, y, color);
364 }
365
366 static const struct table_class table_unshared_class =
367   {
368     table_unshared_destroy,
369     table_unshared_get_cell,
370     table_unshared_get_rule,
371     NULL,                       /* paste */
372     NULL,                       /* select */
373   };
374 \f
375 struct table_string
376   {
377     struct table table;
378     char *string;
379     enum table_halign halign;
380   };
381
382 static const struct table_class table_string_class;
383
384 /* Returns a table that contains a single cell, whose contents are S with
385    options OPTIONS (a combination of TAB_* values).  */
386 struct table *
387 table_from_string (enum table_halign halign, const char *s)
388 {
389   struct table_string *ts = xmalloc (sizeof *ts);
390   table_init (&ts->table, &table_string_class);
391   ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
392   ts->string = xstrdup (s);
393   ts->halign = halign;
394   return &ts->table;
395 }
396
397 static struct table_string *
398 table_string_cast (const struct table *table)
399 {
400   assert (table->klass == &table_string_class);
401   return UP_CAST (table, struct table_string, table);
402 }
403
404 static void
405 table_string_destroy (struct table *ts_)
406 {
407   struct table_string *ts = table_string_cast (ts_);
408   free (ts->string);
409   free (ts);
410 }
411
412 static void
413 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
414                        struct table_cell *cell)
415 {
416   static const struct area_style styles[] = {
417 #define S(H) [H] = { AREA_STYLE_INITIALIZER__, .cell_style.halign = H }
418     S(TABLE_HALIGN_LEFT),
419     S(TABLE_HALIGN_CENTER),
420     S(TABLE_HALIGN_RIGHT),
421     S(TABLE_HALIGN_MIXED),
422     S(TABLE_HALIGN_DECIMAL),
423   };
424   struct table_string *ts = table_string_cast (ts_);
425   cell->d[TABLE_HORZ][0] = 0;
426   cell->d[TABLE_HORZ][1] = 1;
427   cell->d[TABLE_VERT][0] = 0;
428   cell->d[TABLE_VERT][1] = 1;
429   cell->options = 0;
430   cell->style = &styles[table_halign_interpret (ts->halign, false)];
431   cell->text = ts->string;
432   cell->n_footnotes = 0;
433   cell->destructor = NULL;
434 }
435
436
437 static int
438 table_string_get_rule (const struct table *ts UNUSED,
439                        enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
440                        struct cell_color *color UNUSED)
441 {
442   return TAL_0;
443 }
444
445 static const struct table_class table_string_class =
446   {
447     table_string_destroy,
448     table_string_get_cell,
449     table_string_get_rule,
450     NULL,                       /* paste */
451     NULL,                       /* select */
452   };
453 \f
454 const char *
455 table_halign_to_string (enum table_halign halign)
456 {
457   switch (halign)
458     {
459     case TABLE_HALIGN_LEFT: return "left";
460     case TABLE_HALIGN_CENTER: return "center";
461     case TABLE_HALIGN_RIGHT: return "right";
462     case TABLE_HALIGN_DECIMAL: return "decimal";
463     case TABLE_HALIGN_MIXED: return "mixed";
464     default: return "**error**";
465     }
466 }
467
468 const char *
469 table_valign_to_string (enum table_valign valign)
470 {
471   switch (valign)
472     {
473     case TABLE_VALIGN_TOP: return "top";
474     case TABLE_VALIGN_CENTER: return "center";
475     case TABLE_VALIGN_BOTTOM: return "bottom";
476     default: return "**error**";
477     }
478 }
479
480 enum table_halign
481 table_halign_interpret (enum table_halign halign, bool numeric)
482 {
483   switch (halign)
484     {
485     case TABLE_HALIGN_LEFT:
486     case TABLE_HALIGN_CENTER:
487     case TABLE_HALIGN_RIGHT:
488       return halign;
489
490     case TABLE_HALIGN_MIXED:
491       return numeric ? TABLE_HALIGN_RIGHT : TABLE_HALIGN_LEFT;
492
493     case TABLE_HALIGN_DECIMAL:
494       return TABLE_HALIGN_DECIMAL;
495
496     default:
497       NOT_REACHED ();
498     }
499 }
500
501 void
502 font_style_copy (struct font_style *dst, const struct font_style *src)
503 {
504   *dst = *src;
505   if (dst->typeface)
506     dst->typeface = xstrdup (dst->typeface);
507 }
508
509 void
510 font_style_uninit (struct font_style *font)
511 {
512   if (font)
513     free (font->typeface);
514 }
515
516 void
517 area_style_copy (struct area_style *dst, const struct area_style *src)
518 {
519   font_style_copy (&dst->font_style, &src->font_style);
520   dst->cell_style = src->cell_style;
521 }
522
523 void
524 area_style_uninit (struct area_style *area)
525 {
526   if (area)
527     font_style_uninit (&area->font_style);
528 }
529
530 const char *
531 table_stroke_to_string (enum table_stroke stroke)
532 {
533   switch (stroke)
534     {
535     case TABLE_STROKE_NONE: return "none";
536     case TABLE_STROKE_SOLID: return "solid";
537     case TABLE_STROKE_DASHED: return "dashed";
538     case TABLE_STROKE_THICK: return "thick";
539     case TABLE_STROKE_THIN: return "thin";
540     case TABLE_STROKE_DOUBLE: return "double";
541     default:
542       return "**error**";
543     }
544 }
545
546 void
547 cell_color_dump (const struct cell_color *c)
548 {
549   if (c->alpha != 255)
550     printf ("rgba(%d, %d, %d, %d)", c->r, c->g, c->b, c->alpha);
551   else
552     printf ("#%02"PRIx8"%02"PRIx8"%02"PRIx8, c->r, c->g, c->b);
553 }
554
555 void
556 font_style_dump (const struct font_style *f)
557 {
558   printf ("%s %dpx ", f->typeface, f->size);
559   cell_color_dump (&f->fg[0]);
560   putchar ('/');
561   cell_color_dump (&f->bg[0]);
562   if (!cell_color_equal (&f->fg[0], &f->fg[1])
563       || !cell_color_equal (&f->bg[0], &f->bg[1]))
564     {
565       printf (" alt=");
566       cell_color_dump (&f->fg[1]);
567       putchar ('/');
568       cell_color_dump (&f->bg[1]);
569     }
570   if (f->bold)
571     fputs (" bold", stdout);
572   if (f->italic)
573     fputs (" italic", stdout);
574   if (f->underline)
575     fputs (" underline", stdout);
576 }
577
578 void
579 cell_style_dump (const struct cell_style *c)
580 {
581   fputs (table_halign_to_string (c->halign), stdout);
582   if (c->halign == TABLE_HALIGN_DECIMAL)
583     printf ("(%.2gpx)", c->decimal_offset);
584   printf (" %s", table_valign_to_string (c->valign));
585   printf (" %d,%d,%d,%dpx",
586           c->margin[TABLE_HORZ][0], c->margin[TABLE_HORZ][1],
587           c->margin[TABLE_VERT][0], c->margin[TABLE_VERT][1]);
588 }