8ef077e38fae99f8a8b2d8c54b4c3b22f541e296
[pspp] / src / output / tab.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2013, 2014 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/tab.h"
20
21 #include <ctype.h>
22 #include <stdarg.h>
23 #include <limits.h>
24 #include <stdlib.h>
25
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"
40
41 #include "gl/minmax.h"
42 #include "gl/xalloc.h"
43
44 #include "gettext.h"
45 #define _(msgid) gettext (msgid)
46 \f
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))
51
52 /* Joined cell. */
53 struct tab_joined_cell
54   {
55     int d[TABLE_N_AXES][2];     /* Table region, same as struct table_cell. */
56     union
57       {
58         char *text;
59         struct table_item *subtable;
60       }
61     u;
62
63     size_t n_footnotes;
64     char **footnotes;
65   };
66
67 static const struct table_class tab_table_class;
68
69 struct fmt_spec ugly [n_RC] = 
70   {
71     {FMT_F, 8, 0}, /* INTEGER */
72     {FMT_F, 8, 3}, /* WEIGHT (ignored) */
73     {FMT_F, 8, 3}, /* PVALUE */
74     {FMT_F, 8, 3}  /* OTHER (ignored) */
75   };
76
77
78 /* Creates and returns a new table with NC columns and NR rows and initially no
79    header rows or columns.  The table's cells are initially empty. */
80 struct tab_table *
81 tab_create (int nc, int nr)
82 {
83   struct tab_table *t;
84
85   t = pool_create_container (struct tab_table, container);
86   table_init (&t->table, &tab_table_class);
87   table_set_nc (&t->table, nc);
88   table_set_nr (&t->table, nr);
89
90   t->title = NULL;
91   t->cf = nc;
92   t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
93   t->ct = pool_malloc (t->container, nr * nc);
94   memset (t->ct, 0, nc * nr);
95
96   t->rh = pool_nmalloc (t->container, nc, nr + 1);
97   memset (t->rh, 0, nc * (nr + 1));
98
99   t->rv = pool_nmalloc (t->container, nr, nc + 1);
100   memset (t->fmtmap, 0, sizeof (*t->fmtmap) * n_RC);
101
102   memset (t->rv, TAL_GAP, nr * (nc + 1));
103
104   t->fmtmap[RC_PVALUE] = ugly[RC_PVALUE];
105   t->fmtmap[RC_INTEGER] = ugly[RC_INTEGER];
106   t->fmtmap[RC_OTHER] = *settings_get_format ();
107
108   t->col_ofs = t->row_ofs = 0;
109
110   return t;
111 }
112
113
114 void 
115 tab_set_format (struct tab_table *t, enum result_class rc, const struct fmt_spec *fmt)
116 {
117   t->fmtmap[rc] = *fmt;
118 }
119
120
121 /* Sets the width and height of a table, in columns and rows,
122    respectively.  Use only to reduce the size of a table, since it
123    does not change the amount of allocated memory.
124
125    This function is obsolete.  Please do not add new uses of it.  (Instead, use
126    table_select() or one of its helper functions.) */
127 void
128 tab_resize (struct tab_table *t, int nc, int nr)
129 {
130   if (nc != -1)
131     {
132       assert (nc + t->col_ofs <= t->cf);
133       table_set_nc (&t->table, nc + t->col_ofs);
134     }
135   if (nr != -1)
136     {
137       assert (nr + t->row_ofs <= tab_nr (t));
138       table_set_nr (&t->table, nr + t->row_ofs);
139     }
140 }
141
142 /* Changes either or both dimensions of a table and reallocates memory as
143    necessary.
144
145    This function is obsolete.  Please do not add new uses of it.  (Instead, use
146    table_paste() or one of its helper functions to paste multiple tables
147    together into a larger one.) */
148 void
149 tab_realloc (struct tab_table *t, int nc, int nr)
150 {
151   int ro, co;
152
153   ro = t->row_ofs;
154   co = t->col_ofs;
155   if (ro || co)
156     tab_offset (t, 0, 0);
157
158   if (nc == -1)
159     nc = tab_nc (t);
160   if (nr == -1)
161     nr = tab_nr (t);
162
163   assert (nc == tab_nc (t));
164
165   if (nc > t->cf)
166     {
167       int mr1 = MIN (nr, tab_nr (t));
168       int mc1 = MIN (nc, tab_nc (t));
169
170       void **new_cc;
171       unsigned char *new_ct;
172       int r;
173
174       new_cc = pool_calloc (t->container, nr * nc, sizeof *new_cc);
175       new_ct = pool_malloc (t->container, nr * nc);
176       for (r = 0; r < mr1; r++)
177         {
178           memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], mc1 * sizeof *t->cc);
179           memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
180           memset (&new_ct[r * nc + tab_nc (t)], 0, nc - tab_nc (t));
181         }
182       pool_free (t->container, t->cc);
183       pool_free (t->container, t->ct);
184       t->cc = new_cc;
185       t->ct = new_ct;
186       t->cf = nc;
187     }
188   else if (nr != tab_nr (t))
189     {
190       t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
191       t->ct = pool_realloc (t->container, t->ct, nr * nc);
192
193       t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
194       t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
195
196       if (nr > tab_nr (t))
197         {
198           memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, (nr - tab_nr (t)) * nc);
199           memset (&t->rv[(nc + 1) * tab_nr (t)], TAL_GAP,
200                   (nr - tab_nr (t)) * (nc + 1));
201         }
202     }
203
204   memset (&t->ct[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)));
205   memset (&t->cc[nc * tab_nr (t)], 0, nc * (nr - tab_nr (t)) * sizeof *t->cc);
206
207   table_set_nr (&t->table, nr);
208   table_set_nc (&t->table, nc);
209
210   if (ro || co)
211     tab_offset (t, co, ro);
212 }
213
214 /* Sets the number of header rows on each side of TABLE to L on the
215    left, R on the right, T on the top, B on the bottom.  Header rows
216    are repeated when a table is broken across multiple columns or
217    multiple pages. */
218 void
219 tab_headers (struct tab_table *table, int l, int r, int t, int b)
220 {
221   table_set_hl (&table->table, l);
222   table_set_hr (&table->table, r);
223   table_set_ht (&table->table, t);
224   table_set_hb (&table->table, b);
225 }
226 \f
227 /* Rules. */
228
229 /* Draws a vertical line to the left of cells at horizontal position X
230    from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
231 void
232 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
233 {
234 #if DEBUGGING
235   if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
236       || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
237       || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
238     {
239       printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
240                 "table size (%d,%d)\n"),
241               x, t->col_ofs, x + t->col_ofs,
242               y1, t->row_ofs, y1 + t->row_ofs,
243               y2, t->row_ofs, y2 + t->row_ofs,
244               tab_nc (t), tab_nr (t));
245       return;
246     }
247 #endif
248
249   x += t->col_ofs;
250   y1 += t->row_ofs;
251   y2 += t->row_ofs;
252
253   assert (x >= 0);
254   assert (x <= tab_nc (t));
255   assert (y1 >= 0);
256   assert (y2 >= y1);
257   assert (y2 <= tab_nr (t));
258
259   if (style != -1)
260     {
261       int y;
262       for (y = y1; y <= y2; y++)
263         t->rv[x + (t->cf + 1) * y] = style;
264     }
265 }
266
267 /* Draws a horizontal line above cells at vertical position Y from X1
268    to X2 inclusive in style STYLE, if style is not -1. */
269 void
270 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
271 {
272 #if DEBUGGING
273   if (y + t->row_ofs < 0 || y + t->row_ofs > tab_nr (t)
274       || x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
275       || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t))
276     {
277       printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d in "
278                 "table size (%d,%d)\n"),
279               x1, t->col_ofs, x1 + t->col_ofs,
280               x2, t->col_ofs, x2 + t->col_ofs,
281               y, t->row_ofs, y + t->row_ofs,
282               tab_nc (t), tab_nr (t));
283       return;
284     }
285 #endif
286
287   x1 += t->col_ofs;
288   x2 += t->col_ofs;
289   y += t->row_ofs;
290
291   assert (y >= 0);
292   assert (y <= tab_nr (t));
293   assert (x2 >= x1 );
294   assert (x1 >= 0 );
295   assert (x2 < tab_nc (t));
296
297   if (style != -1)
298     {
299       int x;
300       for (x = x1; x <= x2; x++)
301         t->rh[x + t->cf * y] = style;
302     }
303 }
304
305 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
306    lines of style F_H and vertical lines of style F_V.  Fills the
307    interior of the box with horizontal lines of style I_H and vertical
308    lines of style I_V.  Any of the line styles may be -1 to avoid
309    drawing those lines.  This is distinct from 0, which draws a null
310    line. */
311 void
312 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
313          int x1, int y1, int x2, int y2)
314 {
315 #if DEBUGGING
316   if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
317       || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
318       || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
319       || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
320     {
321       printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
322                 "in table size (%d,%d)\n"),
323               x1, t->col_ofs, x1 + t->col_ofs,
324               y1, t->row_ofs, y1 + t->row_ofs,
325               x2, t->col_ofs, x2 + t->col_ofs,
326               y2, t->row_ofs, y2 + t->row_ofs,
327               tab_nc (t), tab_nr (t));
328       NOT_REACHED ();
329     }
330 #endif
331
332   x1 += t->col_ofs;
333   x2 += t->col_ofs;
334   y1 += t->row_ofs;
335   y2 += t->row_ofs;
336
337   assert (x2 >= x1);
338   assert (y2 >= y1);
339   assert (x1 >= 0);
340   assert (y1 >= 0);
341   assert (x2 < tab_nc (t));
342   assert (y2 < tab_nr (t));
343
344   if (f_h != -1)
345     {
346       int x;
347       for (x = x1; x <= x2; x++)
348         {
349           t->rh[x + t->cf * y1] = f_h;
350           t->rh[x + t->cf * (y2 + 1)] = f_h;
351         }
352     }
353   if (f_v != -1)
354     {
355       int y;
356       for (y = y1; y <= y2; y++)
357         {
358           t->rv[x1 + (t->cf + 1) * y] = f_v;
359           t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
360         }
361     }
362
363   if (i_h != -1)
364     {
365       int y;
366
367       for (y = y1 + 1; y <= y2; y++)
368         {
369           int x;
370
371           for (x = x1; x <= x2; x++)
372             t->rh[x + t->cf * y] = i_h;
373         }
374     }
375   if (i_v != -1)
376     {
377       int x;
378
379       for (x = x1 + 1; x <= x2; x++)
380         {
381           int y;
382
383           for (y = y1; y <= y2; y++)
384             t->rv[x + (t->cf + 1) * y] = i_v;
385         }
386     }
387 }
388 \f
389 /* Cells. */
390
391 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
392    from V, displayed with format spec F. */
393 void
394 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
395            const union value *v, const struct variable *var,
396            const struct fmt_spec *f)
397 {
398   char *contents;
399
400 #if DEBUGGING
401   if (c + table->col_ofs < 0 || r + table->row_ofs < 0
402       || c + table->col_ofs >= tab_nc (table)
403       || r + table->row_ofs >= tab_nr (table))
404     {
405       printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
406               "(%d,%d)\n",
407               c, table->col_ofs, c + table->col_ofs,
408               r, table->row_ofs, r + table->row_ofs,
409               tab_nc (table), tab_nr (table));
410       return;
411     }
412 #endif
413
414   contents = data_out_stretchy (v, var_get_encoding (var),
415                                 f != NULL ? f : var_get_print_format (var),
416                                 table->container);
417
418   table->cc[c + r * table->cf] = contents;
419   table->ct[c + r * table->cf] = opt;
420 }
421
422 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
423    formatted by FMT.
424    If FMT is null, then the default print format will be used.
425 */
426 void
427 tab_double (struct tab_table *table, int c, int r, unsigned char opt,
428             double val, const struct fmt_spec *fmt, enum result_class rc)
429 {
430   union value double_value ;
431   char *s;
432
433   assert (c >= 0);
434   assert (c < tab_nc (table));
435   assert (r >= 0);
436   assert (r < tab_nr (table));
437
438   if (fmt == NULL)
439     fmt = &table->fmtmap[rc];
440   
441   fmt_check_output (fmt);
442
443 #if DEBUGGING
444   if (c + table->col_ofs < 0 || r + table->row_ofs < 0
445       || c + table->col_ofs >= tab_nc (table)
446       || r + table->row_ofs >= tab_nr (table))
447     {
448       printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
449               "(%d,%d)\n",
450               c, table->col_ofs, c + table->col_ofs,
451               r, table->row_ofs, r + table->row_ofs,
452               tab_nc (table), tab_nr (table));
453       return;
454     }
455 #endif
456
457   double_value.f = val;
458   s = data_out_stretchy (&double_value, C_ENCODING, fmt, table->container);
459   table->cc[c + r * table->cf] = s + strspn (s, " ");
460   table->ct[c + r * table->cf] = opt;
461 }
462
463
464 static void
465 do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
466 {
467   assert (c >= 0 );
468   assert (r >= 0 );
469   assert (c < tab_nc (table));
470   assert (r < tab_nr (table));
471
472 #if DEBUGGING
473   if (c + table->col_ofs < 0 || r + table->row_ofs < 0
474       || c + table->col_ofs >= tab_nc (table)
475       || r + table->row_ofs >= tab_nr (table))
476     {
477       printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
478               "(%d,%d)\n",
479               c, table->col_ofs, c + table->col_ofs,
480               r, table->row_ofs, r + table->row_ofs,
481               tab_nc (table), tab_nr (table));
482       return;
483     }
484 #endif
485
486   table->cc[c + r * table->cf] = text;
487   table->ct[c + r * table->cf] = opt;
488 }
489
490 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
491    TEXT. */
492 void
493 tab_text (struct tab_table *table, int c, int r, unsigned opt,
494           const char *text)
495 {
496   do_tab_text (table, c, r, opt, pool_strdup (table->container, text));
497 }
498
499 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
500    FORMAT, which is formatted as if passed to printf. */
501 void
502 tab_text_format (struct tab_table *table, int c, int r, unsigned opt,
503                  const char *format, ...)
504 {
505   va_list args;
506
507   va_start (args, format);
508   do_tab_text (table, c, r, opt,
509                pool_vasprintf (table->container, format, args));
510   va_end (args);
511 }
512
513 static struct tab_joined_cell *
514 add_joined_cell (struct tab_table *table, int x1, int y1, int x2, int y2,
515                  unsigned opt)
516 {
517   struct tab_joined_cell *j;
518
519   assert (x1 + table->col_ofs >= 0);
520   assert (y1 + table->row_ofs >= 0);
521   assert (y2 >= y1);
522   assert (x2 >= x1);
523   assert (y2 + table->row_ofs < tab_nr (table));
524   assert (x2 + table->col_ofs < tab_nc (table));
525
526 #if DEBUGGING
527   if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
528       || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
529       || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
530       || y2 < y2 || y2 + table->row_ofs >= tab_nr (table))
531     {
532       printf ("tab_joint_text(): bad cell "
533               "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
534               x1, table->col_ofs, x1 + table->col_ofs,
535               y1, table->row_ofs, y1 + table->row_ofs,
536               x2, table->col_ofs, x2 + table->col_ofs,
537               y2, table->row_ofs, y2 + table->row_ofs,
538               tab_nc (table), tab_nr (table));
539       return;
540     }
541 #endif
542
543   tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
544
545   j = pool_alloc (table->container, sizeof *j);
546   j->d[TABLE_HORZ][0] = x1 + table->col_ofs;
547   j->d[TABLE_VERT][0] = y1 + table->row_ofs;
548   j->d[TABLE_HORZ][1] = ++x2 + table->col_ofs;
549   j->d[TABLE_VERT][1] = ++y2 + table->row_ofs;
550   j->n_footnotes = 0;
551   j->footnotes = NULL;
552
553   {
554     void **cc = &table->cc[x1 + y1 * table->cf];
555     unsigned char *ct = &table->ct[x1 + y1 * table->cf];
556     const int ofs = table->cf - (x2 - x1);
557
558     int y;
559
560     for (y = y1; y < y2; y++)
561       {
562         int x;
563
564         for (x = x1; x < x2; x++)
565           {
566             *cc++ = j;
567             *ct++ = opt | TAB_JOIN;
568           }
569
570         cc += ofs;
571         ct += ofs;
572       }
573   }
574
575   return j;
576 }
577
578 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
579    options OPT to have text value TEXT. */
580 void
581 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
582                 unsigned opt, const char *text)
583 {
584   char *s = pool_strdup (table->container, text);
585   add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
586 }
587
588 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them
589    with options OPT to have text value FORMAT, which is formatted
590    as if passed to printf. */
591 void
592 tab_joint_text_format (struct tab_table *table, int x1, int y1, int x2, int y2,
593                        unsigned opt, const char *format, ...)
594 {
595   va_list args;
596   char *s;
597
598   va_start (args, format);
599   s = pool_vasprintf (table->container, format, args);
600   va_end (args);
601
602   add_joined_cell (table, x1, y1, x2, y2, opt)->u.text = s;
603 }
604
605 void
606 tab_footnote (struct tab_table *table, int x, int y, const char *format, ...)
607 {
608   int index = x + y * table->cf;
609   unsigned char opt = table->ct[index];
610   struct tab_joined_cell *j;
611   va_list args;
612
613   if (opt & TAB_JOIN)
614     j = table->cc[index];
615   else
616     {
617       char *text = table->cc[index];
618
619       j = add_joined_cell (table, x, y, x, y, table->ct[index]);
620       j->u.text = text ? text : xstrdup ("");
621     }
622
623   j->footnotes = xrealloc (j->footnotes,
624                            (j->n_footnotes + 1) * sizeof *j->footnotes);
625
626   va_start (args, format);
627   j->footnotes[j->n_footnotes++] = pool_vasprintf (table->container, format, args);
628   va_end (args);
629 }
630
631 static void
632 subtable_unref (void *subtable)
633 {
634   table_item_unref (subtable);
635 }
636
637 /* Places SUBTABLE as the content for cells (X1,X2)-(Y1,Y2) inclusive in TABLE
638    with options OPT. */
639 void
640 tab_subtable (struct tab_table *table, int x1, int y1, int x2, int y2,
641               unsigned opt, struct table_item *subtable)
642 {
643   add_joined_cell (table, x1, y1, x2, y2, opt | TAB_SUBTABLE)->u.subtable
644     = subtable;
645   pool_register (table->container, subtable_unref, subtable);
646 }
647
648 /* Places the contents of SUBTABLE as the content for cells (X1,X2)-(Y1,Y2)
649    inclusive in TABLE with options OPT.
650
651    SUBTABLE must have exactly one row and column.  The contents of its single
652    cell are used as the contents of TABLE's cell; that is, SUBTABLE is not used
653    as a nested table but its contents become part of TABLE. */
654 void
655 tab_subtable_bare (struct tab_table *table, int x1, int y1, int x2, int y2,
656                    unsigned opt, struct table_item *subtable)
657 {
658   const struct table *t UNUSED = table_item_get_table (subtable);
659   assert (table_nc (t) == 1);
660   assert (table_nr (t) == 1);
661   tab_subtable (table, x1, y1, x2, y2, opt | TAB_BARE, subtable);
662 }
663
664 bool
665 tab_cell_is_empty (const struct tab_table *table, int c, int r)
666 {
667   return table->cc[c + r * table->cf] == NULL;
668 }
669 \f
670 /* Miscellaneous. */
671
672 /* Set the title of table T to TITLE, which is formatted as if
673    passed to printf(). */
674 void
675 tab_title (struct tab_table *t, const char *title, ...)
676 {
677   va_list args;
678
679   free (t->title);
680   va_start (args, title);
681   t->title = xvasprintf (title, args);
682   va_end (args);
683 }
684
685 /* Easy, type-safe way to submit a tab table to som. */
686 void
687 tab_submit (struct tab_table *t)
688 {
689   table_item_submit (table_item_create (&t->table, t->title));
690 }
691 \f
692 /* Editing. */
693
694 /* Set table row and column offsets for all functions that affect
695    cells or rules. */
696 void
697 tab_offset (struct tab_table *t, int col, int row)
698 {
699   int diff = 0;
700
701 #if DEBUGGING
702   if (row < -1 || row > tab_nr (t))
703     {
704       printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
705       NOT_REACHED ();
706     }
707   if (col < -1 || col > tab_nc (t))
708     {
709       printf ("tab_offset(): col=%d in %d-column table\n", col, tab_nc (t));
710       NOT_REACHED ();
711     }
712 #endif
713
714   if (row != -1)
715     diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
716   if (col != -1)
717     diff += (col - t->col_ofs), t->col_ofs = col;
718
719   t->cc += diff;
720   t->ct += diff;
721 }
722
723 /* Increment the row offset by one. If the table is too small,
724    increase its size. */
725 void
726 tab_next_row (struct tab_table *t)
727 {
728   t->cc += t->cf;
729   t->ct += t->cf;
730   if (++t->row_ofs >= tab_nr (t))
731     tab_realloc (t, -1, tab_nr (t) * 4 / 3);
732 }
733 \f
734 /* Writes STRING to the output.  OPTIONS may be any valid combination of TAB_*
735    bits.
736
737    This function is obsolete.  Please do not add new uses of it.  Instead, use
738    a text_item (see output/text-item.h). */
739 void
740 tab_output_text (int options, const char *string)
741 {
742   enum text_item_type type = (options & TAB_EMPH ? TEXT_ITEM_SUBHEAD
743                               : options & TAB_FIX ? TEXT_ITEM_MONOSPACE
744                               : TEXT_ITEM_PARAGRAPH);
745   text_item_submit (text_item_create (type, string));
746 }
747
748 /* Same as tab_output_text(), but FORMAT is passed through printf-like
749    formatting before output. */
750 void
751 tab_output_text_format (int options, const char *format, ...)
752 {
753   va_list args;
754   char *text;
755
756   va_start (args, format);
757   text = xvasprintf (format, args);
758   va_end (args);
759
760   tab_output_text (options, text);
761
762   free (text);
763 }
764 \f
765 /* Table class implementation. */
766
767 static void
768 tab_destroy (struct table *table)
769 {
770   struct tab_table *t = tab_cast (table);
771   free (t->title);
772   t->title = NULL;
773   pool_destroy (t->container);
774 }
775
776 static void
777 tab_get_cell (const struct table *table, int x, int y, struct table_cell *cell)
778 {
779   const struct tab_table *t = tab_cast (table);
780   int index = x + y * t->cf;
781   unsigned char opt = t->ct[index];
782   const void *cc = t->cc[index];
783
784   cell->inline_contents.options = opt;
785   cell->inline_contents.table = NULL;
786   cell->inline_contents.n_footnotes = 0;
787   cell->destructor = NULL;
788
789   if (opt & TAB_JOIN)
790     {
791       const struct tab_joined_cell *jc = cc;
792       if (opt & TAB_BARE)
793         {
794           assert (opt & TAB_SUBTABLE);
795
796           /* This overwrites all of the members of CELL. */
797           table_get_cell (table_item_get_table (jc->u.subtable), 0, 0, cell);
798         }
799       else
800         {
801           cell->contents = &cell->inline_contents;
802           cell->n_contents = 1;
803           if (opt & TAB_SUBTABLE)
804             {
805               cell->inline_contents.table = jc->u.subtable;
806               cell->inline_contents.text = NULL;
807             }
808           else
809             cell->inline_contents.text = jc->u.text;
810         }
811
812       cell->inline_contents.footnotes = jc->footnotes;
813       cell->inline_contents.n_footnotes = jc->n_footnotes;
814
815       cell->d[TABLE_HORZ][0] = jc->d[TABLE_HORZ][0];
816       cell->d[TABLE_HORZ][1] = jc->d[TABLE_HORZ][1];
817       cell->d[TABLE_VERT][0] = jc->d[TABLE_VERT][0];
818       cell->d[TABLE_VERT][1] = jc->d[TABLE_VERT][1];
819     }
820   else
821     {
822       cell->d[TABLE_HORZ][0] = x;
823       cell->d[TABLE_HORZ][1] = x + 1;
824       cell->d[TABLE_VERT][0] = y;
825       cell->d[TABLE_VERT][1] = y + 1;
826       if (cc != NULL)
827         {
828           cell->contents = &cell->inline_contents;
829           cell->n_contents = 1;
830           cell->inline_contents.text = CONST_CAST (char *, cc);
831         }
832       else
833         {
834           cell->contents = NULL;
835           cell->n_contents = 0;
836         }
837     }
838 }
839
840 static int
841 tab_get_rule (const struct table *table, enum table_axis axis, int x, int y)
842 {
843   const struct tab_table *t = tab_cast (table);
844   return (axis == TABLE_VERT
845           ? t->rh[x + t->cf * y]
846           : t->rv[x + (t->cf + 1) * y]);
847 }
848
849 static const struct table_class tab_table_class =
850   {
851     tab_destroy,
852     tab_get_cell,
853     tab_get_rule,
854     NULL,                       /* paste */
855     NULL,                       /* select */
856   };
857
858 struct tab_table *
859 tab_cast (const struct table *table)
860 {
861   assert (table->klass == &tab_table_class);
862   return UP_CAST (table, struct tab_table, table);
863 }