- assert (t->ref_cnt > 0);
- t->ref_cnt++;
-}
-
-/* Sets the width and height of a table, in columns and rows,
- respectively. Use only to reduce the size of a table, since it
- does not change the amount of allocated memory. */
-void
-tab_resize (struct tab_table *t, int nc, int nr)
-{
- assert (t != NULL);
- if (nc != -1)
- {
- assert (nc + t->col_ofs <= t->cf);
- t->nc = nc + t->col_ofs;
- }
- if (nr != -1)
- {
- assert (nr + t->row_ofs <= tab_nr (t));
- t->nr = nr + t->row_ofs;
- }
-}
-
-/* Changes either or both dimensions of a table. Consider using the
- above routine instead if it won't waste a lot of space.
-
- Changing the number of columns in a table is particularly expensive
- in space and time. Avoid doing such. FIXME: In fact, transferring
- of rules isn't even implemented yet. */
-void
-tab_realloc (struct tab_table *t, int nc, int nr)
-{
- int ro, co;
-
- assert (t != NULL);
- ro = t->row_ofs;
- co = t->col_ofs;
- if (ro || co)
- tab_offset (t, 0, 0);
-
- if (nc == -1)
- nc = tab_nc (t);
- if (nr == -1)
- nr = tab_nr (t);
-
- assert (nc == tab_nc (t));
-
- if (nc > t->cf)
- {
- int mr1 = MIN (nr, tab_nr (t));
- int mc1 = MIN (nc, tab_nc (t));
-
- struct substring *new_cc;
- unsigned char *new_ct;
- int r;
-
- new_cc = pool_nmalloc (t->container, nr * nc, sizeof *new_cc);
- new_ct = pool_malloc (t->container, nr * nc);
- for (r = 0; r < mr1; r++)
- {
- memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], mc1 * sizeof *t->cc);
- memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
- memset (&new_ct[r * nc + tab_nc (t)], TAB_EMPTY, nc - tab_nc (t));
- }
- pool_free (t->container, t->cc);
- pool_free (t->container, t->ct);
- t->cc = new_cc;
- t->ct = new_ct;
- t->cf = nc;
- }
- else if (nr != tab_nr (t))
- {
- t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
- t->ct = pool_realloc (t->container, t->ct, nr * nc);
-
- t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
- t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
-
- if (nr > tab_nr (t))
- {
- memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, (nr - tab_nr (t)) * nc);
- memset (&t->rv[(nc + 1) * tab_nr (t)], UCHAR_MAX,
- (nr - tab_nr (t)) * (nc + 1));
- }
- }
-
- memset (&t->ct[nc * tab_nr (t)], TAB_EMPTY, nc * (nr - tab_nr (t)));
-
- t->nr = nr;
- t->nc = nc;
-
- if (ro || co)
- tab_offset (t, co, ro);
-}
-
-/* Sets the number of header rows on each side of TABLE to L on the
- left, R on the right, T on the top, B on the bottom. Header rows
- are repeated when a table is broken across multiple columns or
- multiple pages. */
-void
-tab_headers (struct tab_table *table, int l, int r, int t, int b)
-{
- assert (table != NULL);
- assert (l < table->nc);
- assert (r < table->nc);
- assert (t < table->nr);
- assert (b < table->nr);
-
-
- table->l = l;
- table->r = r;
- table->t = t;
- table->b = b;
-}
-
-/* Set up table T so that, when it is an appropriate size, it will be
- displayed across the page in columns.
-
- STYLE is a TAB_COL_* constant. */
-void
-tab_columns (struct tab_table *t, int style)
-{
- assert (t != NULL);
- t->col_style = style;
-}
-\f
-/* Rules. */
-
-/* Draws a vertical line to the left of cells at horizontal position X
- from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
-void
-tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
-{
- assert (t != NULL);
-
-#if DEBUGGING
- if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
- {
- printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
- "table size (%d,%d)\n"),
- x, t->col_ofs, x + t->col_ofs,
- y1, t->row_ofs, y1 + t->row_ofs,
- y2, t->row_ofs, y2 + t->row_ofs,
- tab_nc (t), tab_nr (t));
- return;
- }
-#endif
-
- x += t->col_ofs;
- y1 += t->row_ofs;
- y2 += t->row_ofs;
-
- assert (x > 0);
- assert (x < tab_nc (t));
- assert (y1 >= 0);
- assert (y2 >= y1);
- assert (y2 <= tab_nr (t));
-
- if (style != -1)
- {
- int y;
- for (y = y1; y <= y2; y++)
- t->rv[x + (t->cf + 1) * y] = style;
- }
-}
-
-/* Draws a horizontal line above cells at vertical position Y from X1
- to X2 inclusive in style STYLE, if style is not -1. */
-void
-tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
-{
- assert (t != NULL);
-
- x1 += t->col_ofs;
- x2 += t->col_ofs;
- y += t->row_ofs;
-
- assert (y >= 0);
- assert (y <= tab_nr (t));
- assert (x2 >= x1 );
- assert (x1 >= 0 );
- assert (x2 < tab_nc (t));
-
- if (style != -1)
- {
- int x;
- for (x = x1; x <= x2; x++)
- t->rh[x + t->cf * y] = style;
- }
-}
-
-/* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
- lines of style F_H and vertical lines of style F_V. Fills the
- interior of the box with horizontal lines of style I_H and vertical
- lines of style I_V. Any of the line styles may be -1 to avoid
- drawing those lines. This is distinct from 0, which draws a null
- line. */
-void
-tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
- int x1, int y1, int x2, int y2)
-{
- assert (t != NULL);
-
-#if DEBUGGING
- if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
- || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
- {
- printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
- "in table size (%d,%d)\n"),
- x1, t->col_ofs, x1 + t->col_ofs,
- y1, t->row_ofs, y1 + t->row_ofs,
- x2, t->col_ofs, x2 + t->col_ofs,
- y2, t->row_ofs, y2 + t->row_ofs,
- tab_nc (t), tab_nr (t));
- NOT_REACHED ();
- }
-#endif
-
- x1 += t->col_ofs;
- x2 += t->col_ofs;
- y1 += t->row_ofs;
- y2 += t->row_ofs;
-
- assert (x2 >= x1);
- assert (y2 >= y1);
- assert (x1 >= 0);
- assert (y1 >= 0);
- assert (x2 < tab_nc (t));
- assert (y2 < tab_nr (t));
-
- if (f_h != -1)
- {
- int x;
- for (x = x1; x <= x2; x++)
- {
- t->rh[x + t->cf * y1] = f_h;
- t->rh[x + t->cf * (y2 + 1)] = f_h;
- }
- }
- if (f_v != -1)
- {
- int y;
- for (y = y1; y <= y2; y++)
- {
- t->rv[x1 + (t->cf + 1) * y] = f_v;
- t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
- }
- }
-
- if (i_h != -1)
- {
- int y;
-
- for (y = y1 + 1; y <= y2; y++)
- {
- int x;
-
- for (x = x1; x <= x2; x++)
- t->rh[x + t->cf * y] = i_h;
- }
- }
- if (i_v != -1)
- {
- int x;
-
- for (x = x1 + 1; x <= x2; x++)
- {
- int y;
-
- for (y = y1; y <= y2; y++)
- t->rv[x + (t->cf + 1) * y] = i_v;
- }
- }
-}
-
-/* Set the title of table T to TITLE, which is formatted as if
- passed to printf(). */
-void
-tab_title (struct tab_table *t, const char *title, ...)
-{
- va_list args;
-
- assert (t != NULL && title != NULL);
- va_start (args, title);
- t->title = xvasprintf (title, args);
- va_end (args);
-}
-
-/* Set DIM_FUNC, which will be passed auxiliary data AUX, as the
- dimension function for table T.
-
- DIM_FUNC must not assume that it is called from the same
- context as tab_dim; for example, table T might be kept in
- memory and, thus, DIM_FUNC might be called after the currently
- running command completes. If it is non-null, FREE_FUNC is
- called when the table is destroyed, to allow any data
- allocated for use by DIM_FUNC to be freed. */
-void
-tab_dim (struct tab_table *t,
- tab_dim_func *dim_func, tab_dim_free_func *free_func, void *aux)
-{
- assert (t->dim == NULL);
- t->dim = dim_func;
- t->dim_free = free_func;
- t->dim_aux = aux;
-}
-
-/* Returns the natural width of column C in table T for driver D, that
- is, the smallest width necessary to display all its cells without
- wrapping. The width will be no larger than the page width minus
- left and right rule widths. */
-int
-tab_natural_width (const struct tab_rendering *r, int col)
-{
- const struct tab_table *t = r->table;
- int width, row, max_width;
-
- assert (col >= 0 && col < tab_nc (t));
-
- width = 0;
- for (row = 0; row < tab_nr (t); row++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[col + row * t->cf];
- int w;
-
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
-
- text.string = t->cc[col + row * t->cf];
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = text.v = INT_MAX;
-
- r->driver->class->text_metrics (r->driver, &text, &w, NULL);
- if (w > width)
- width = w;
- }
-
- if (width == 0)
- {
- /* FIXME: This is an ugly kluge to compensate for the fact
- that we don't let joined cells contribute to column
- widths. */
- width = r->driver->prop_em_width * 8;
- }
-
- max_width = r->driver->width - r->wrv[0] - r->wrv[tab_nc (t)];
- return MIN (width, max_width);
-}
-
-/* Returns the natural height of row R in table T for driver D, that
- is, the minimum height necessary to display the information in the
- cell at the widths set for each column. */
-int
-tab_natural_height (const struct tab_rendering *r, int row)
-{
- const struct tab_table *t = r->table;
- int height, col;
-
- assert (row >= 0 && row < tab_nr (t));
-
- height = r->driver->font_height;
- for (col = 0; col < tab_nc (t); col++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[col + row * t->cf];
- int h;
-
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
-
- text.string = t->cc[col + row * t->cf];
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = r->w[col];
- text.v = INT_MAX;
- r->driver->class->text_metrics (r->driver, &text, NULL, &h);
-
- if (h > height)
- height = h;
- }
-
- return height;
-}
-
-/* Callback function to set all columns and rows to their natural
- dimensions. Not really meant to be called directly. */
-void
-tab_natural_dimensions (struct tab_rendering *r, void *aux UNUSED)
-{
- const struct tab_table *t = r->table;
- int i;
-
- for (i = 0; i < tab_nc (t); i++)
- r->w[i] = tab_natural_width (r, i);
-
- for (i = 0; i < tab_nr (t); i++)
- r->h[i] = tab_natural_height (r, i);
-}
-
-\f
-/* Cells. */
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
- from V, displayed with format spec F. */
-void
-tab_value (struct tab_table *table, int c, int r, unsigned char opt,
- const union value *v, const struct dictionary *dict,
- const struct fmt_spec *f)
-{
- char *contents;
-
- assert (table != NULL && v != NULL && f != NULL);
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= tab_nc (table)
- || r + table->row_ofs >= tab_nr (table))
- {
- printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
- "(%d,%d)\n",
- c, table->col_ofs, c + table->col_ofs,
- r, table->row_ofs, r + table->row_ofs,
- tab_nc (table), tab_nr (table));
- return;
- }
-#endif
-
- contents = data_out_pool (v, dict_get_encoding (dict), f, table->container);
-
- table->cc[c + r * table->cf] = ss_cstr (contents);
- table->ct[c + r * table->cf] = opt;
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
- with NDEC decimal places. */
-void
-tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
- double val, int w, int d)
-{
- char *s, *cp;
-
- struct fmt_spec f;
- union value double_value;
-
- assert (table != NULL && w <= 40);
-
- assert (c >= 0);
- assert (c < tab_nc (table));
- assert (r >= 0);
- assert (r < tab_nr (table));
-
- f = fmt_for_output (FMT_F, w, d);
-
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= tab_nc (table)
- || r + table->row_ofs >= tab_nr (table))
- {
- printf ("tab_fixed(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
- "(%d,%d)\n",
- c, table->col_ofs, c + table->col_ofs,
- r, table->row_ofs, r + table->row_ofs,
- tab_nc (table), tab_nr (table));
- return;
- }
-#endif
-
- double_value.f = val;
- s = data_out_pool (&double_value, LEGACY_NATIVE, &f, table->container);
-
- cp = s;
- while (isspace ((unsigned char) *cp) && cp < &s[w])
- cp++;
- f.w = w - (cp - s);
-
- table->cc[c + r * table->cf] = ss_buffer (cp, f.w);
- table->ct[c + r * table->cf] = opt;
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
- formatted by FMT.
- If FMT is null, then the default print format will be used.
-*/
-void
-tab_double (struct tab_table *table, int c, int r, unsigned char opt,
- double val, const struct fmt_spec *fmt)
-{
- struct substring ss;
- union value double_value ;
-
- assert (table != NULL);
-
- assert (c >= 0);
- assert (c < tab_nc (table));
- assert (r >= 0);
- assert (r < tab_nr (table));
-
- if ( fmt == NULL)
- fmt = settings_get_format ();
-
- fmt_check_output (fmt);
-
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= tab_nc (table)
- || r + table->row_ofs >= tab_nr (table))