- 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,
- table->nc, table->nr);
- return;
- }
-#endif
-
- contents = pool_alloc (table->container, f->w);
- table->cc[c + r * table->cf] = ss_buffer (contents, f->w);
- table->ct[c + r * table->cf] = opt;
-
- data_out (v, f, contents);
-}
-
-/* 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 *contents;
- char buf[40], *cp;
-
- struct fmt_spec f;
- union value double_value;
-
- assert (table != NULL && w <= 40);
-
- assert (c >= 0);
- assert (c < table->nc);
- assert (r >= 0);
- assert (r < table->nr);
-
- 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 >= table->nc
- || r + table->row_ofs >= table->nr)
- {
- 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,
- table->nc, table->nr);
- return;
- }
-#endif
-
- double_value.f = val;
- data_out (&double_value, &f, buf);
-
- cp = buf;
- while (isspace ((unsigned char) *cp) && cp < &buf[w])
- cp++;
- f.w = w - (cp - buf);
-
- contents = pool_alloc (table->container, f.w);
- table->cc[c + r * table->cf] = ss_buffer (contents, f.w);
- table->ct[c + r * table->cf] = opt;
- memcpy (contents, cp, f.w);
-}
-
-/* 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)
-{
- int w;
- char *contents;
- char buf[40], *cp;
-
- union value double_value;
-
- assert (table != NULL);
-
- assert (c >= 0);
- assert (c < table->nc);
- assert (r >= 0);
- assert (r < table->nr);
-
- 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 >= table->nc
- || r + table->row_ofs >= table->nr)
- {
- printf ("tab_double(): 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,
- table->nc, table->nr);
- return;
- }
-#endif
-
- double_value.f = val;
- data_out (&double_value, fmt, buf);
-
- cp = buf;
- while (isspace ((unsigned char) *cp) && cp < &buf[fmt->w])
- cp++;
- w = fmt->w - (cp - buf);
-
- contents = pool_alloc (table->container, w);
- table->cc[c + r * table->cf] = ss_buffer (contents, w);
- table->ct[c + r * table->cf] = opt;
- memcpy (contents, cp, w);
-}
-
-
-/* Sets cell (C,R) in TABLE, with options OPT, to have text value
- TEXT. */
-void
-tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
-{
- va_list args;
-
- assert (table != NULL && text != NULL);
-
- assert (c >= 0 );
- assert (r >= 0 );
- assert (c < table->nc);
- assert (r < table->nr);
-
-
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
- {
- printf ("tab_text(): 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,
- table->nc, table->nr);
- return;
- }
-#endif
-
- va_start (args, text);
- table->cc[c + r * table->cf] = text_format (table, opt, text, args);
- table->ct[c + r * table->cf] = opt;
- va_end (args);
-}
-
-/* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
- options OPT to have text value TEXT. */
-void
-tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
- unsigned opt, const char *text, ...)
-{
- struct tab_joined_cell *j;
-
- assert (table != NULL && text != NULL);
-
- assert (x1 + table->col_ofs >= 0);
- assert (y1 + table->row_ofs >= 0);
- assert (y2 >= y1);
- assert (x2 >= x1);
- assert (y2 + table->row_ofs < table->nr);
- assert (x2 + table->col_ofs < table->nc);
-
-#if DEBUGGING
- if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
- || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
- || x2 < x1 || x2 + table->col_ofs >= table->nc
- || y2 < y2 || y2 + table->row_ofs >= table->nr)
- {
- printf ("tab_joint_text(): bad cell "
- "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
- x1, table->col_ofs, x1 + table->col_ofs,
- y1, table->row_ofs, y1 + table->row_ofs,
- x2, table->col_ofs, x2 + table->col_ofs,
- y2, table->row_ofs, y2 + table->row_ofs,
- table->nc, table->nr);
- return;
- }
-#endif
-
- tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
-
- j = pool_alloc (table->container, sizeof *j);
- j->hit = 0;
- j->x1 = x1 + table->col_ofs;
- j->y1 = y1 + table->row_ofs;
- j->x2 = ++x2 + table->col_ofs;
- j->y2 = ++y2 + table->row_ofs;
-
- {
- va_list args;
-
- va_start (args, text);
- j->contents = text_format (table, opt, text, args);
- va_end (args);
- }
-
- opt |= TAB_JOIN;
-
- {
- struct substring *cc = &table->cc[x1 + y1 * table->cf];
- unsigned char *ct = &table->ct[x1 + y1 * table->cf];
- const int ofs = table->cf - (x2 - x1);
-
- int y;
-
- for (y = y1; y < y2; y++)
- {
- int x;
-
- for (x = x1; x < x2; x++)
- {
- *cc++ = ss_buffer ((char *) j, 0);
- *ct++ = opt;
- }
-
- cc += ofs;
- ct += ofs;
- }
- }
-}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
-void
-tab_raw (struct tab_table *table, int c, int r, unsigned opt,
- struct substring *string)
-{
- assert (table != NULL && string != NULL);
-
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
- {
- printf ("tab_raw(): 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,
- table->nc, table->nr);
- return;
- }
-#endif
-
- table->cc[c + r * table->cf] = *string;
- table->ct[c + r * table->cf] = opt;
-}
-\f
-/* Miscellaneous. */
-
-/* Sets the widths of all the columns and heights of all the rows in
- table T for driver D. */
-static void
-nowrap_dim (struct tab_rendering *r, void *aux UNUSED)
-{
- r->w[0] = tab_natural_width (r, 0);
- r->h[0] = r->driver->font_height;
-}
-
-/* Sets the widths of all the columns and heights of all the rows in
- table T for driver D. */
-static void
-wrap_dim (struct tab_rendering *r, void *aux UNUSED)
-{
- r->w[0] = tab_natural_width (r, 0);
- r->h[0] = tab_natural_height (r, 0);
-}
-
-/* Outputs text BUF as a table with a single cell having cell options
- OPTIONS, which is a combination of the TAB_* and TAT_*
- constants. */
-void
-tab_output_text (int options, const char *buf, ...)
-{
- struct tab_table *t = tab_create (1, 1, 0);
- char *tmp_buf = NULL;
-
- if (options & TAT_PRINTF)
- {
- va_list args;
-
- va_start (args, buf);
- buf = tmp_buf = xvasprintf (buf, args);
- va_end (args);
- }
-
- tab_text (t, 0, 0, options & ~TAT_PRINTF, buf);
- tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
- tab_dim (t, options & TAT_NOWRAP ? nowrap_dim : wrap_dim, NULL, NULL);
- tab_submit (t);
-
- free (tmp_buf);
-}
-
-/* Set table flags to FLAGS. */
-void
-tab_flags (struct tab_table *t, unsigned flags)
-{
- assert (t != NULL);
- t->flags = flags;
-}
-
-/* Easy, type-safe way to submit a tab table to som. */
-void
-tab_submit (struct tab_table *t)
-{
- struct som_entity s;
-
- assert (t != NULL);
- s.class = &tab_table_class;
- s.ext = t;
- s.type = SOM_TABLE;
- som_submit (&s);
- tab_destroy (t);
-}
-\f
-/* Editing. */
-
-/* Set table row and column offsets for all functions that affect
- cells or rules. */
-void
-tab_offset (struct tab_table *t, int col, int row)
-{
- int diff = 0;
-
- assert (t != NULL);
-#if DEBUGGING
- if (row < -1 || row > t->nr)
- {
- printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
- NOT_REACHED ();
- }
- if (col < -1 || col > t->nc)
- {
- printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
- NOT_REACHED ();
- }
-#endif
-
- if (row != -1)
- diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
- if (col != -1)
- diff += (col - t->col_ofs), t->col_ofs = col;
-
- t->cc += diff;
- t->ct += diff;
-}
-
-/* Increment the row offset by one. If the table is too small,
- increase its size. */
-void
-tab_next_row (struct tab_table *t)
-{
- assert (t != NULL);
- t->cc += t->cf;
- t->ct += t->cf;
- if (++t->row_ofs >= t->nr)
- tab_realloc (t, -1, t->nr * 4 / 3);
-}
-\f
-/* Return the number of columns and rows in the table into N_COLUMNS
- and N_ROWS, respectively. */
-static void
-tabi_count (struct som_entity *t_, int *n_columns, int *n_rows)
-{
- struct tab_table *t = t_->ext;
- *n_columns = t->nc;
- *n_rows = t->nr;
-}
-
-/* Return the column style for this table into STYLE. */
-static void
-tabi_columns (struct som_entity *t_, int *style)
-{
- struct tab_table *t = t_->ext;
- *style = t->col_style;
-}
-
-/* Return the number of header rows/columns on the left, right, top,
- and bottom sides into HL, HR, HT, and HB, respectively. */
-static void
-tabi_headers (struct som_entity *t_, int *hl, int *hr, int *ht, int *hb)
-{
- struct tab_table *t = t_->ext;
- *hl = t->l;
- *hr = t->r;
- *ht = t->t;
- *hb = t->b;
-}
-
-/* Return flags set for the current table into FLAGS. */
-static void
-tabi_flags (struct som_entity *t_, unsigned *flags)
-{
- struct tab_table *t = t_->ext;
- *flags = t->flags;
-}
-
-/* Returns the line style to use for spacing purposes for a rule
- of the given TYPE. */
-static enum outp_line_style
-rule_to_spacing_type (unsigned char type)
-{
- switch (type)
- {
- case TAL_0:
- return OUTP_L_NONE;
- case TAL_GAP:
- case TAL_1:
- return OUTP_L_SINGLE;
- case TAL_2:
- return OUTP_L_DOUBLE;
- default:
- NOT_REACHED ();
- }
-}
-
-static void *
-tabi_render_init (struct som_entity *t_, struct outp_driver *driver,
- int hl, int hr, int ht, int hb)
-{
- const struct tab_table *t = t_->ext;
- struct tab_rendering *r;
- int col, row;
- int i;
-
- tab_offset (t_->ext, 0, 0);
-
- r = xmalloc (sizeof *r);
- r->table = t;
- r->driver = driver;
- r->w = xnmalloc (t->nc, sizeof *r->w);
- r->h = xnmalloc (t->nr, sizeof *r->h);
- r->hrh = xnmalloc (t->nr + 1, sizeof *r->hrh);
- r->wrv = xnmalloc (t->nc + 1, sizeof *r->wrv);
- r->l = hl;
- r->r = hr;
- r->t = ht;
- r->b = hb;
-
- /* Figure out sizes of rules. */
- for (row = 0; row <= t->nr; row++)
- {
- int width = 0;
- for (col = 0; col < t->nc; col++)
- {
- unsigned char rh = t->rh[col + row * t->cf];
- int w = driver->horiz_line_width[rule_to_spacing_type (rh)];
- if (w > width)
- width = w;
- }
- r->hrh[row] = width;
- }
-
- for (col = 0; col <= t->nc; col++)
- {
- int width = 0;
- for (row = 0; row < t->nr; row++)
- {
- unsigned char *rv = &t->rv[col + row * (t->cf + 1)];
- int w;
- if (*rv == UCHAR_MAX)
- *rv = col != 0 && col != t->nc ? TAL_GAP : TAL_0;
- w = driver->vert_line_width[rule_to_spacing_type (*rv)];
- if (w > width)
- width = w;
- }
- r->wrv[col] = width;
- }
-
- /* Determine row heights and columns widths. */
- for (i = 0; i < t->nr; i++)
- r->h[i] = -1;
- for (i = 0; i < t->nc; i++)
- r->w[i] = -1;
-
- t->dim (r, t->dim_aux);
-
- for (i = 0; i < t->nr; i++)
- if (r->h[i] < 0)
- error (0, 0, "height of table row %d is %d (not initialized?)",
- i, r->h[i]);
- for (i = 0; i < t->nc; i++)
- if (r->w[i] < 0)
- error (0, 0, "width of table column %d is %d (not initialized?)",
- i, r->w[i]);
-
- /* Add up header sizes. */
- for (i = 0, r->wl = r->wrv[0]; i < r->l; i++)
- r->wl += r->w[i] + r->wrv[i + 1];
- for (i = 0, r->ht = r->hrh[0]; i < r->t; i++)
- r->ht += r->h[i] + r->hrh[i + 1];
- for (i = t->nc - r->r, r->wr = r->wrv[i]; i < t->nc; i++)
- r->wr += r->w[i] + r->wrv[i + 1];
- for (i = t->nr - r->b, r->hb = r->hrh[i]; i < t->nr; i++)
- r->hb += r->h[i] + r->hrh[i + 1];
-
- /* Title. */
- if (!(t->flags & SOMF_NO_TITLE))
- r->ht += driver->font_height;
-
- return r;
-}
-
-static void
-tabi_render_free (void *r_)
-{
- struct tab_rendering *r = r_;
-
- free (r->w);
- free (r->h);
- free (r->hrh);
- free (r->wrv);
- free (r);
-}
-
-/* Return the horizontal and vertical size of the entire table,
- including headers, for the current output device, into HORIZ and
- VERT. */
-static void
-tabi_area (void *r_, int *horiz, int *vert)
-{
- struct tab_rendering *r = r_;
- const struct tab_table *t = r->table;
- int width, col;
- int height, row;
-
- width = 0;
- for (col = r->l + 1, width = r->wl + r->wr + r->w[t->l];
- col < t->nc - r->r; col++)
- width += r->w[col] + r->wrv[col];
- *horiz = width;
-
- height = 0;
- for (row = r->t + 1, height = r->ht + r->hb + r->h[t->t];
- row < t->nr - t->b; row++)
- height += r->h[row] + r->hrh[row];
- *vert = height;
-}
-
-/* Determines the number of rows or columns (including appropriate
- headers), depending on CUMTYPE, that will fit into the space
- specified. Takes rows/columns starting at index START and attempts
- to fill up available space MAX. Returns in END the index of the
- last row/column plus one; returns in ACTUAL the actual amount of
- space the selected rows/columns (including appropriate headers)
- filled. */
-static void
-tabi_cumulate (void *r_, int cumtype, int start, int *end,
- int max, int *actual)
-{
- const struct tab_rendering *r = r_;
- const struct tab_table *t = r->table;
- int limit;
- int *cells, *rules;
- int total;
- int idx;
-
- assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
- if (cumtype == SOM_ROWS)
- {
- assert (start >= 0 && start < t->nr);
- limit = t->nr - r->b;
- cells = &r->h[start];
- rules = &r->hrh[start + 1];
- total = r->ht + r->hb;