696931ae50980147be4212dd1af477a73c2448d1
[pspp-builds.git] / src / output / table.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009 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
28 #include "gl/xalloc.h"
29
30 /* Increases TABLE's reference count, indicating that it has an additional
31    owner.  An table that is shared among multiple owners must not be
32    modified. */
33 struct table *
34 table_ref (const struct table *table_)
35 {
36   struct table *table = CONST_CAST (struct table *, table_);
37   table->ref_cnt++;
38   return table;
39 }
40
41 /* Decreases TABLE's reference count, indicating that it has one fewer owner.
42    If TABLE no longer has any owners, it is freed. */
43 void
44 table_unref (struct table *table)
45 {
46   if (table != NULL)
47     {
48       assert (table->ref_cnt > 0);
49       if (--table->ref_cnt == 0)
50         table->class->destroy (table);
51     }
52 }
53
54 /* Returns true if TABLE has more than one owner.  A table item that is shared
55    among multiple owners must not be modified. */
56 bool
57 table_is_shared (const struct table *table)
58 {
59   return table->ref_cnt > 1;
60 }
61
62 /* Sets the number of left header columns in TABLE to HL. */
63 void
64 table_set_hl (struct table *table, int hl)
65 {
66   assert (!table_is_shared (table));
67   table->h[TABLE_HORZ][0] = hl;
68 }
69
70 /* Sets the number of right header columns in TABLE to HR. */
71 void
72 table_set_hr (struct table *table, int hr)
73 {
74   assert (!table_is_shared (table));
75   table->h[TABLE_HORZ][1] = hr;
76 }
77
78 /* Sets the number of top header rows in TABLE to HT. */
79 void
80 table_set_ht (struct table *table, int ht)
81 {
82   assert (!table_is_shared (table));
83   table->h[TABLE_VERT][0] = ht;
84 }
85
86 /* Sets the number of top header rows in TABLE to HB. */
87 void
88 table_set_hb (struct table *table, int hb)
89 {
90   assert (!table_is_shared (table));
91   table->h[TABLE_VERT][1] = hb;
92 }
93 \f
94 /* Initializes TABLE as a table of the specified CLASS, initially with a
95    reference count of 1.
96
97    TABLE initially has 0 rows and columns and no headers.  The table
98    implementation should update the numbers of rows and columns.  The table
99    implementation (or its client) may update the header rows and columns.
100
101    A table is an abstract class, that is, a plain struct table is not useful on
102    its own.  Thus, this function is normally called from the initialization
103    function of some subclass of table. */
104 void
105 table_init (struct table *table, const struct table_class *class)
106 {
107   table->class = class;
108   table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
109   table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
110   table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
111   table->ref_cnt = 1;
112 }
113
114 /* Sets the number of columns in TABLE to NC. */
115 void
116 table_set_nc (struct table *table, int nc)
117 {
118   assert (!table_is_shared (table));
119   table->n[TABLE_HORZ] = nc;
120 }
121
122 /* Sets the number of rows in TABLE to NR. */
123 void
124 table_set_nr (struct table *table, int nr)
125 {
126   assert (!table_is_shared (table));
127   table->n[TABLE_VERT] = nr;
128 }
129 \f
130 /* Initializes CELL with the contents of the table cell at column X and row Y
131    within TABLE.  When CELL is no longer needed, the caller is responsible for
132    freeing it by calling table_cell_free(CELL).
133
134    The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
135 void
136 table_get_cell (const struct table *table, int x, int y,
137                 struct table_cell *cell)
138 {
139   assert (x >= 0 && x < table->n[TABLE_HORZ]);
140   assert (y >= 0 && y < table->n[TABLE_VERT]);
141   table->class->get_cell (table, x, y, cell);
142 }
143
144 /* Frees CELL, which should have been initialized by calling
145    table_get_cell(). */
146 void
147 table_cell_free (struct table_cell *cell)
148 {
149   if (cell->destructor != NULL)
150     cell->destructor (cell->destructor_aux);
151 }
152
153 /* Returns one of the TAL_* enumeration constants (declared in output/table.h)
154    representing a rule running alongside one of the cells in TABLE.
155
156    Suppose NC is the number of columns in TABLE and NR is the number of rows.
157    Then, if AXIS is TABLE_HORZ, then 0 <= X <= NC and 0 <= Y < NR.  If (X,Y) =
158    (0,0), the return value is the rule that runs vertically on the left side of
159    cell (0,0); if (X,Y) = (1,0), it is the vertical rule between that cell and
160    cell (1,0); and so on, up to (NC,0), which runs vertically on the right of
161    cell (NC-1,0).
162
163    The following diagram illustrates the meaning of (X,Y) for AXIS = TABLE_HORZ
164    within a 7x7 table.  The '|' characters at the intersection of the X labels
165    and Y labels show the rule whose style would be returned by calling
166    table_get_rule with those X and Y values:
167
168                            0  1  2  3  4  5  6  7
169                            +--+--+--+--+--+--+--+
170                          0 |  |  |  |  |  |  |  |
171                            +--+--+--+--+--+--+--+
172                          1 |  |  |  |  |  |  |  |
173                            +--+--+--+--+--+--+--+
174                          2 |  |  |  |  |  |  |  |
175                            +--+--+--+--+--+--+--+
176                          3 |  |  |  |  |  |  |  |
177                            +--+--+--+--+--+--+--+
178                          4 |  |  |  |  |  |  |  |
179                            +--+--+--+--+--+--+--+
180                          5 |  |  |  |  |  |  |  |
181                            +--+--+--+--+--+--+--+
182                          6 |  |  |  |  |  |  |  |
183                            +--+--+--+--+--+--+--+
184
185    Similarly, if AXIS is TABLE_VERT, then 0 <= X < NC and 0 <= Y <= NR.  If
186    (X,Y) = (0,0), the return value is the rule that runs horizontally above
187    the top of cell (0,0); if (X,Y) = (0,1), it is the horizontal rule
188    between that cell and cell (0,1); and so on, up to (0,NR), which runs
189    horizontally below cell (0,NR-1). */
190 int
191 table_get_rule (const struct table *table, enum table_axis axis, int x, int y)
192 {
193   assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
194   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
195   return table->class->get_rule (table, axis, x, y);
196 }
197 \f
198 struct table_unshared
199   {
200     struct table table;
201     struct table *subtable;
202   };
203
204 static const struct table_class table_unshared_class;
205
206 /* Takes ownership of TABLE and returns a table with the same contents but
207    which is guaranteed not to be shared (as returned by table_is_shared()).
208
209    If TABLE is unshared, just returns TABLE.
210
211    The only real use for this function is to create a copy of TABLE in which
212    the headers can be adjusted, which is a pretty specialized use case. */
213 struct table *
214 table_unshare (struct table *table)
215 {
216   if (!table_is_shared (table))
217     return table;
218   else
219     {
220       struct table_unshared *tiu = xmalloc (sizeof *tiu);
221       table_init (&tiu->table, &table_unshared_class);
222       table_set_nc (&tiu->table, table_nc (table));
223       table_set_nr (&tiu->table, table_nr (table));
224       table_set_hl (&tiu->table, table_hl (table));
225       table_set_hr (&tiu->table, table_hr (table));
226       table_set_ht (&tiu->table, table_ht (table));
227       table_set_hb (&tiu->table, table_hb (table));
228       tiu->subtable = table;
229       return &tiu->table;
230     }
231 }
232
233 static struct table_unshared *
234 table_unshared_cast (const struct table *table)
235 {
236   assert (table->class == &table_unshared_class);
237   return UP_CAST (table, struct table_unshared, table);
238 }
239
240 static void
241 table_unshared_destroy (struct table *tiu_)
242 {
243   struct table_unshared *tiu = table_unshared_cast (tiu_);
244   table_unref (tiu->subtable);
245   free (tiu);
246 }
247
248 static void
249 table_unshared_get_cell (const struct table *tiu_, int x, int y,
250                               struct table_cell *cell)
251 {
252   struct table_unshared *tiu = table_unshared_cast (tiu_);
253   table_get_cell (tiu->subtable, x, y, cell);
254 }
255
256 static int
257 table_unshared_get_rule (const struct table *tiu_,
258                               enum table_axis axis, int x, int y)
259 {
260   struct table_unshared *tiu = table_unshared_cast (tiu_);
261   return table_get_rule (tiu->subtable, axis, x, y);
262 }
263
264 static const struct table_class table_unshared_class =
265   {
266     table_unshared_destroy,
267     table_unshared_get_cell,
268     table_unshared_get_rule,
269     NULL,                       /* paste */
270     NULL,                       /* select */
271   };
272 \f
273 struct table_string
274   {
275     struct table table;
276     char *string;
277     unsigned int options;
278   };
279
280 static const struct table_class table_string_class;
281
282 /* Returns a table that contains a single cell, whose contents are S with
283    options OPTIONS (a combination of TAB_* values).  */
284 struct table *
285 table_from_string (unsigned int options, const char *s)
286 {
287   struct table_string *ts = xmalloc (sizeof *ts);
288   table_init (&ts->table, &table_string_class);
289   ts->table.n[TABLE_HORZ] = ts->table.n[TABLE_VERT] = 1;
290   ts->string = xstrdup (s);
291   ts->options = options;
292   return &ts->table;
293 }
294
295 static struct table_string *
296 table_string_cast (const struct table *table)
297 {
298   assert (table->class == &table_string_class);
299   return UP_CAST (table, struct table_string, table);
300 }
301
302 static void
303 table_string_destroy (struct table *ts_)
304 {
305   struct table_string *ts = table_string_cast (ts_);
306   free (ts->string);
307   free (ts);
308 }
309
310 static void
311 table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
312                        struct table_cell *cell)
313 {
314   struct table_string *ts = table_string_cast (ts_);
315   cell->d[TABLE_HORZ][0] = 0;
316   cell->d[TABLE_HORZ][1] = 1;
317   cell->d[TABLE_VERT][0] = 0;
318   cell->d[TABLE_VERT][1] = 1;
319   cell->contents = ts->string;
320   cell->options = ts->options;
321   cell->destructor = NULL;
322 }
323
324
325 static int
326 table_string_get_rule (const struct table *ts UNUSED,
327                        enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
328 {
329   return TAL_0;
330 }
331
332 static const struct table_class table_string_class =
333   {
334     table_string_destroy,
335     table_string_get_cell,
336     table_string_get_rule,
337     NULL,                       /* paste */
338     NULL,                       /* select */
339   };