output: Implement nested tables.
[pspp.git] / src / output / tab.c
blob2e788e5a37f9b38faa17f3b17286848bab49747b
1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014 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/>. */
17 #include <config.h>
19 #include "output/tab.h"
21 #include <ctype.h>
22 #include <stdarg.h>
23 #include <limits.h>
24 #include <stdlib.h>
26 #include "data/data-out.h"
27 #include "data/format.h"
28 #include "data/settings.h"
29 #include "data/value.h"
30 #include "data/variable.h"
31 #include "libpspp/assertion.h"
32 #include "libpspp/compiler.h"
33 #include "libpspp/i18n.h"
34 #include "libpspp/misc.h"
35 #include "libpspp/pool.h"
36 #include "output/driver.h"
37 #include "output/table-item.h"
38 #include "output/table-provider.h"
39 #include "output/text-item.h"
41 #include "gl/minmax.h"
42 #include "gl/xalloc.h"
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
47 /* Cell options. */
48 #define TAB_JOIN (1u << TAB_FIRST_AVAILABLE)
49 #define TAB_SUBTABLE (1u << (TAB_FIRST_AVAILABLE + 1))
50 #define TAB_BARE (1u << (TAB_FIRST_AVAILABLE + 2))
52 /* Joined cell. */
53 struct tab_joined_cell
55 int d[TABLE_N_AXES][2]; /* Table region, same as struct table_cell. */
56 union
58 char *text;
59 struct table *subtable;
64 static const struct table_class tab_table_class;
66 struct fmt_spec ugly [n_RC] =
68 {FMT_F, 8, 0}, /* INTEGER */
69 {FMT_F, 8, 3}, /* WEIGHT (ignored) */
70 {FMT_F, 8, 3}, /* PVALUE */
71 {FMT_F, 8, 3} /* OTHER (ignored) */
75 /* Creates and returns a new table with NC columns and NR rows and initially no
76 header rows or columns. The table's cells are initially empty. */
77 struct tab_table *
78 tab_create (int nc, int nr)
80 struct tab_table *t;
82 t = pool_create_container (struct tab_table, container);
83 table_init (&t->table, &tab_table_class);
84 table_set_nc (&t->table, nc);
85 table_set_nr (&t->table, nr);
87 t->title = NULL;
88 t->cf = nc;
89 t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
90 t->ct = pool_malloc (t->container, nr * nc);
91 memset (t->ct, 0, nc * nr);
93 t->rh = pool_nmalloc (t->container, nc, nr + 1);
94 memset (t->rh, 0, nc * (nr + 1));
96 t->rv = pool_nmalloc (t->container, nr, nc + 1);
97 memset (t->fmtmap, 0, sizeof (*t->fmtmap) * n_RC);
99 memset (t->rv, TAL_GAP, nr * (nc + 1));
101 t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE];
102 t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER];
103 t->fmtmap[RC_OTHER] = *settings_get_format ();
105 t->col_ofs = t->row_ofs = 0;
107 return t;
111 void
112 tab_set_format (struct tab_table *t, enum result_class rc, const struct fmt_spec *fmt)
114 t->fmtmap[rc] = *fmt;
118 /* Sets the width and height of a table, in columns and rows,
119 respectively. Use only to reduce the size of a table, since it
120 does not change the amount of allocated memory.
122 This function is obsolete. Please do not add new uses of it. (Instead, use
123 table_select() or one of its helper functions.) */
124 void
125 tab_resize (struct tab_table *t, int nc, int nr)
127 if (nc != -1)
129 assert (nc + t->col_ofs <= t->cf);
130 table_set_nc (&t->table, nc + t->col_ofs);
132 if (nr != -1)
134 assert (nr + t->row_ofs <= tab_nr (t));
135 table_set_nr (&t->table, nr + t->row_ofs);
139 /* Changes either or both dimensions of a table and reallocates memory as
140 necessary.
142 This function is obsolete. Please do not add new uses of it. (Instead, use
143 table_paste() or one of its helper functions to paste multiple tables
144 together into a larger one.) */
145 void
146 tab_realloc (struct tab_table *t, int nc, int nr)
148 int ro, co;
150 ro = t->row_ofs;
151 co = t->col_ofs;
152 if (ro || co)
153 tab_offset (t, 0, 0);
155 if (nc == -1)
156 nc = tab_nc (t);
157 if (nr == -1)
158 nr = tab_nr (t);
160 assert (nc == tab_nc (t));
162 if (nc > t->cf)
164 int mr1 = MIN (nr, tab_nr (t));
165 int mc1 = MIN (nc, tab_nc (t));
167 void **new_cc;
168 unsigned char *new_ct;
169 int r;
171 new_cc = pool_calloc (t->container, nr * nc, sizeof *new_cc);
172 new_ct = pool_malloc (t->container, nr * nc);
173 for (r = 0; r < mr1; r++)
175 memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], mc1 * sizeof *t->cc);
176 memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
177 memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t));
179 pool_free (t->container, t->cc);
180 pool_free (t->container, t->ct);
181 t->cc = new_cc;
182 t->ct = new_ct;
183 t->cf = nc;
185 else if (nr != tab_nr (t))
187 t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
188 t->ct = pool_realloc (t->container, t->ct, nr * nc);
190 t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
191 t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
193 if (nr > tab_nr (t))
195 memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, (nr - tab_nr (t)) * nc);
196 memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_GAP,
197 (nr - tab_nr (t)) * (nc + 1));
201 memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)));
202 memset (&t->cc[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->cc);
204 table_set_nr (&t->table, nr);
205 table_set_nc (&t->table, nc);
207 if (ro || co)
208 tab_offset (t, co, ro);
211 /* Sets the number of header rows on each side of TABLE to L on the
212 left, R on the right, T on the top, B on the bottom. Header rows
213 are repeated when a table is broken across multiple columns or
214 multiple pages. */
215 void
216 tab_headers (struct tab_table *table, int l, int r, int t, int b)
218 table_set_hl (&table->table, l);
219 table_set_hr (&table->table, r);
220 table_set_ht (&table->table, t);
221 table_set_hb (&table->table, b);
224 /* Rules. */
226 /* Draws a vertical line to the left of cells at horizontal position X
227 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
228 void
229 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
231 #if DEBUGGING
232 if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
233 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
234 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
236 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
237 "table size (%d,%d)\n"),
238 x, t->col_ofs, x + t->col_ofs,
239 y1, t->row_ofs, y1 + t->row_ofs,
240 y2, t->row_ofs, y2 + t->row_ofs,
241 tab_nc (t), tab_nr (t));
242 return;
244 #endif
246 x += t->col_ofs;
247 y1 += t->row_ofs;
248 y2 += t->row_ofs;
250 assert (x >= 0);
251 assert (x <= tab_nc (t));
252 assert (y1 >= 0);
253 assert (y2 >= y1);
254 assert (y2 <= tab_nr (t));
256 if (style != -1)
258 int y;
259 for (y = y1; y <= y2; y++)
260 t->rv[x + (t->cf + 1) * y] = style;
264 /* Draws a horizontal line above cells at vertical position Y from X1
265 to X2 inclusive in style STYLE, if style is not -1. */
266 void
267 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
269 #if DEBUGGING
270 if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t)
271 || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
272 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t))
274 printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in "
275 "table size (%d,%d)\n"),
276 x1, t->col_ofs, x1 + t->col_ofs,
277 x2, t->col_ofs, x2 + t->col_ofs,
278 y, t->row_ofs, y + t->row_ofs,
279 tab_nc (t), tab_nr (t));
280 return;
282 #endif
284 x1 += t->col_ofs;
285 x2 += t->col_ofs;
286 y += t->row_ofs;
288 assert (y >= 0);
289 assert (y <= tab_nr (t));
290 assert (x2 >= x1 );
291 assert (x1 >= 0 );
292 assert (x2 < tab_nc (t));
294 if (style != -1)
296 int x;
297 for (x = x1; x <= x2; x++)
298 t->rh[x + t->cf * y] = style;
302 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
303 lines of style F_H and vertical lines of style F_V. Fills the
304 interior of the box with horizontal lines of style I_H and vertical
305 lines of style I_V. Any of the line styles may be -1 to avoid
306 drawing those lines. This is distinct from 0, which draws a null
307 line. */
308 void
309 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
310 int x1, int y1, int x2, int y2)
312 #if DEBUGGING
313 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
314 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
315 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
316 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
318 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
319 "in table size (%d,%d)\n"),
320 x1, t->col_ofs, x1 + t->col_ofs,
321 y1, t->row_ofs, y1 + t->row_ofs,
322 x2, t->col_ofs, x2 + t->col_ofs,
323 y2, t->row_ofs, y2 + t->row_ofs,
324 tab_nc (t), tab_nr (t));
325 NOT_REACHED ();
327 #endif
329 x1 += t->col_ofs;
330 x2 += t->col_ofs;
331 y1 += t->row_ofs;
332 y2 += t->row_ofs;
334 assert (x2 >= x1);
335 assert (y2 >= y1);
336 assert (x1 >= 0);
337 assert (y1 >= 0);
338 assert (x2 < tab_nc (t));
339 assert (y2 < tab_nr (t));
341 if (f_h != -1)
343 int x;
344 for (x = x1; x <= x2; x++)
346 t->rh[x + t->cf * y1] = f_h;
347 t->rh[x + t->cf * (y2 + 1)] = f_h;
350 if (f_v != -1)
352 int y;
353 for (y = y1; y <= y2; y++)
355 t->rv[x1 + (t->cf + 1) * y] = f_v;
356 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
360 if (i_h != -1)
362 int y;
364 for (y = y1 + 1; y <= y2; y++)
366 int x;
368 for (x = x1; x <= x2; x++)
369 t->rh[x + t->cf * y] = i_h;
372 if (i_v != -1)
374 int x;
376 for (x = x1 + 1; x <= x2; x++)
378 int y;
380 for (y = y1; y <= y2; y++)
381 t->rv[x + (t->cf + 1) * y] = i_v;
386 /* Cells. */
388 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
389 from V, displayed with format spec F. */
390 void
391 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
392 const union value *v, const struct variable *var,
393 const struct fmt_spec *f)
395 char *contents;
397 #if DEBUGGING
398 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
399 || c + table->col_ofs >= tab_nc (table)
400 || r + table->row_ofs >= tab_nr (table))
402 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
403 "(%d,%d)\n",
404 c, table->col_ofs, c + table->col_ofs,
405 r, table->row_ofs, r + table->row_ofs,
406 tab_nc (table), tab_nr (table));
407 return;
409 #endif
411 contents = data_out_stretchy (v, var_get_encoding (var),
412 f != NULL ? f : var_get_print_format (var),
413 table->container);
415 table->cc[c + r * table->cf] = contents;
416 table->ct[c + r * table->cf] = opt;
419 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
420 formatted by FMT.
421 If FMT is null, then the default print format will be used.
423 void
424 tab_double (struct tab_table *table, int c, int r, unsigned char opt,
425 double val, const struct fmt_spec *fmt, enum result_class rc)
427 union value double_value ;
428 char *s;
430 assert (c >= 0);
431 assert (c < tab_nc (table));
432 assert (r >= 0);
433 assert (r < tab_nr (table));
435 if (fmt == NULL)
436 fmt = &table->fmtmap[rc];
438 fmt_check_output (fmt);
440 #if DEBUGGING
441 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
442 || c + table->col_ofs >= tab_nc (table)
443 || r + table->row_ofs >= tab_nr (table))
445 printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
446 "(%d,%d)\n",
447 c, table->col_ofs, c + table->col_ofs,
448 r, table->row_ofs, r + table->row_ofs,
449 tab_nc (table), tab_nr (table));
450 return;
452 #endif
454 double_value.f = val;
455 s = data_out_stretchy (&double_value, C_ENCODING, fmt, table->container);
456 table->cc[c + r * table->cf] = s + strspn (s, " ");
457 table->ct[c + r * table->cf] = opt;
461 static void
462 do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
464 assert (c >= 0 );
465 assert (r >= 0 );
466 assert (c < tab_nc (table));
467 assert (r < tab_nr (table));
469 #if DEBUGGING
470 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
471 || c + table->col_ofs >= tab_nc (table)
472 || r + table->row_ofs >= tab_nr (table))
474 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
475 "(%d,%d)\n",
476 c, table->col_ofs, c + table->col_ofs,
477 r, table->row_ofs, r + table->row_ofs,
478 tab_nc (table), tab_nr (table));
479 return;
481 #endif
483 table->cc[c + r * table->cf] = text;
484 table->ct[c + r * table->cf] = opt;
487 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
488 TEXT. */
489 void
490 tab_text (struct tab_table *table, int c, int r, unsigned opt,
491 const char *text)
493 do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
496 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
497 FORMAT, which is formatted as if passed to printf. */
498 void
499 tab_text_format (struct tab_table *table, int c, int r, unsigned opt,
500 const char *format, ...)
502 va_list args;
504 va_start (args, format);
505 do_tab_text (table, c, r, opt,
506 pool_vasprintf (table->container, format, args));
507 va_end (args);
510 static struct tab_joined_cell *
511 add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
512 unsigned opt)
514 struct tab_joined_cell *j;
516 assert (x1 + table->col_ofs >= 0);
517 assert (y1 + table->row_ofs >= 0);
518 assert (y2 >= y1);
519 assert (x2 >= x1);
520 assert (y2 + table->row_ofs < tab_nr (table));
521 assert (x2 + table->col_ofs < tab_nc (table));
523 #if DEBUGGING
524 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
525 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
526 || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
527 || y2 < y2 || y2 + table->row_ofs >= tab_nr (table))
529 printf ("tab_joint_text(): bad cell "
530 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
531 x1, table->col_ofs, x1 + table->col_ofs,
532 y1, table->row_ofs, y1 + table->row_ofs,
533 x2, table->col_ofs, x2 + table->col_ofs,
534 y2, table->row_ofs, y2 + table->row_ofs,
535 tab_nc (table), tab_nr (table));
536 return;
538 #endif
540 tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
542 j = pool_alloc (table->container, sizeof *j);
543 j->d[TABLE_HORZ][0] = x1 + table->col_ofs;
544 j->d[TABLE_VERT][0] = y1 + table->row_ofs;
545 j->d[TABLE_HORZ][1] = ++x2 + table->col_ofs;
546 j->d[TABLE_VERT][1] = ++y2 + table->row_ofs;
549 void **cc = &table->cc[x1 + y1 * table->cf];
550 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
551 const int ofs = table->cf - (x2 - x1);
553 int y;
555 for (y = y1; y < y2; y++)
557 int x;
559 for (x = x1; x < x2; x++)
561 *cc++ = j;
562 *ct++ = opt | TAB_JOIN;
565 cc += ofs;
566 ct += ofs;
570 return j;
573 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
574 options OPT to have text value TEXT. */
575 void
576 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
577 unsigned opt, const char *text)
579 char *s = pool_strdup (table->container, text);
580 add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
583 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them
584 with options OPT to have text value FORMAT, which is formatted
585 as if passed to printf. */
586 void
587 tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, int y2,
588 unsigned opt, const char *format, ...)
590 va_list args;
591 char *s;
593 va_start (args, format);
594 s = pool_vasprintf (table->container, format, args);
595 va_end (args);
597 add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
600 static void
601 subtable_unref (void *subtable)
603 table_unref (subtable);
606 /* Places SUBTABLE as the content for cells (X1,X2)-(Y1,Y2) inclusive in TABLE
607 with options OPT. */
608 void
609 tab_subtable (struct tab_table *table, int x1, int y1, int x2, int y2,
610 unsigned opt, struct table *subtable)
612 add_joined_cell (table, x1, y1, x2, y2, opt | TAB_SUBTABLE)->u.subtable
613 = subtable;
614 pool_register (table->container, subtable_unref, subtable);
617 /* Places the contents of SUBTABLE as the content for cells (X1,X2)-(Y1,Y2)
618 inclusive in TABLE with options OPT.
620 SUBTABLE must have exactly one row and column. The contents of its single
621 cell are used as the contents of TABLE's cell; that is, SUBTABLE is not used
622 as a nested table but its contents become part of TABLE. */
623 void
624 tab_subtable_bare (struct tab_table *table, int x1, int y1, int x2, int y2,
625 unsigned opt, struct table *subtable)
627 assert (table_nc (subtable) == 1);
628 assert (table_nr (subtable) == 1);
629 tab_subtable (table, x1, y1, x2, y2, opt | TAB_BARE, subtable);
632 bool
633 tab_cell_is_empty (const struct tab_table *table, int c, int r)
635 return table->cc[c + r * table->cf] == NULL;
638 /* Miscellaneous. */
640 /* Set the title of table T to TITLE, which is formatted as if
641 passed to printf(). */
642 void
643 tab_title (struct tab_table *t, const char *title, ...)
645 va_list args;
647 free (t->title);
648 va_start (args, title);
649 t->title = xvasprintf (title, args);
650 va_end (args);
653 /* Easy, type-safe way to submit a tab table to som. */
654 void
655 tab_submit (struct tab_table *t)
657 table_item_submit (table_item_create (&t->table, t->title));
660 /* Editing. */
662 /* Set table row and column offsets for all functions that affect
663 cells or rules. */
664 void
665 tab_offset (struct tab_table *t, int col, int row)
667 int diff = 0;
669 #if DEBUGGING
670 if (row < -1 || row > tab_nr (t))
672 printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
673 NOT_REACHED ();
675 if (col < -1 || col > tab_nc (t))
677 printf ("tab_offset(): col=%d in %d-column table\n", col, tab_nc (t));
678 NOT_REACHED ();
680 #endif
682 if (row != -1)
683 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
684 if (col != -1)
685 diff += (col - t->col_ofs), t->col_ofs = col;
687 t->cc += diff;
688 t->ct += diff;
691 /* Increment the row offset by one. If the table is too small,
692 increase its size. */
693 void
694 tab_next_row (struct tab_table *t)
696 t->cc += t->cf;
697 t->ct += t->cf;
698 if (++t->row_ofs >= tab_nr (t))
699 tab_realloc (t, -1, tab_nr (t) * 4 / 3);
702 /* Writes STRING to the output. OPTIONS may be any valid combination of TAB_*
703 bits.
705 This function is obsolete. Please do not add new uses of it. Instead, use
706 a text_item (see output/text-item.h). */
707 void
708 tab_output_text (int options, const char *string)
710 enum text_item_type type = (options & TAB_EMPH ? TEXT_ITEM_SUBHEAD
711 : options & TAB_FIX ? TEXT_ITEM_MONOSPACE
712 : TEXT_ITEM_PARAGRAPH);
713 text_item_submit (text_item_create (type, string));
716 /* Same as tab_output_text(), but FORMAT is passed through printf-like
717 formatting before output. */
718 void
719 tab_output_text_format (int options, const char *format, ...)
721 va_list args;
722 char *text;
724 va_start (args, format);
725 text = xvasprintf (format, args);
726 va_end (args);
728 tab_output_text (options, text);
730 free (text);
733 /* Table class implementation. */
735 static void
736 tab_destroy (struct table *table)
738 struct tab_table *t = tab_cast (table);
739 free (t->title);
740 t->title = NULL;
741 pool_destroy (t->container);
744 static void
745 tab_get_cell (const struct table *table, int x, int y, struct table_cell *cell)
747 const struct tab_table *t = tab_cast (table);
748 int index = x + y * t->cf;
749 unsigned char opt = t->ct[index];
750 const void *cc = t->cc[index];
752 cell->inline_contents.options = opt;
753 cell->inline_contents.table = NULL;
754 cell->destructor = NULL;
756 if (opt & TAB_JOIN)
758 const struct tab_joined_cell *jc = cc;
759 if (opt & TAB_BARE)
761 assert (opt & TAB_SUBTABLE);
763 /* This overwrites all of the members of CELL. */
764 table_get_cell (jc->u.subtable, 0, 0, cell);
766 else
768 cell->contents = &cell->inline_contents;
769 cell->n_contents = 1;
770 if (opt & TAB_SUBTABLE)
772 cell->inline_contents.table = jc->u.subtable;
773 cell->inline_contents.text = NULL;
775 else
776 cell->inline_contents.text = jc->u.text;
779 cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
780 cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
781 cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
782 cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
784 else
786 cell->d[TABLE_HORZ][0] = x;
787 cell->d[TABLE_HORZ][1] = x + 1;
788 cell->d[TABLE_VERT][0] = y;
789 cell->d[TABLE_VERT][1] = y + 1;
790 if (cc != NULL)
792 cell->contents = &cell->inline_contents;
793 cell->n_contents = 1;
794 cell->inline_contents.text = CONST_CAST (char *, cc);
796 else
798 cell->contents = NULL;
799 cell->n_contents = 0;
804 static int
805 tab_get_rule (const struct table *table, enum table_axis axis, int x, int y)
807 const struct tab_table *t = tab_cast (table);
808 return (axis == TABLE_VERT
809 ? t->rh[x + t->cf * y]
810 : t->rv[x + (t->cf + 1) * y]);
813 static const struct table_class tab_table_class =
815 tab_destroy,
816 tab_get_cell,
817 tab_get_rule,
818 NULL, /* paste */
819 NULL, /* select */
822 struct tab_table *
823 tab_cast (const struct table *table)
825 assert (table->klass == &tab_table_class);
826 return UP_CAST (table, struct tab_table, table);