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