-/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
- Written by Ben Pfaff <blp@gnu.org>.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
+
#include "table.h"
+
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
-#include <libpspp/message.h>
-#include <libpspp/alloc.h>
-#include <libpspp/compiler.h>
+
+#include "output.h"
+#include "manager.h"
+
+#include <data/data-out.h>
#include <data/format.h>
-#include <libpspp/magic.h>
+#include <data/value.h>
+#include <libpspp/assertion.h>
+#include <libpspp/compiler.h>
#include <libpspp/misc.h>
-#include "minmax.h"
-#include "output.h"
#include <libpspp/pool.h>
-#include "manager.h"
-#include <data/variable.h>
+
+#include <data/settings.h>
+
+#include "error.h"
+#include "minmax.h"
+#include "xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
\f
-struct som_table_class tab_table_class;
-static char *command_name;
+const struct som_table_class tab_table_class;
/* Returns the font to use for a cell with the given OPTIONS. */
static enum outp_font
-options_to_font (unsigned options)
+options_to_font (unsigned options)
{
return (options & TAB_FIX ? OUTP_FIXED
: options & TAB_EMPH ? OUTP_EMPHASIS
struct tab_table *t;
t = pool_create_container (struct tab_table, container);
+ t->ref_cnt = 1;
t->col_style = TAB_COL_NONE;
- t->col_group = 0;
- ls_null (&t->title);
+ t->title = NULL;
t->flags = SOMF_NONE;
t->nr = nr;
t->nc = t->cf = nc;
t->rh = pool_nmalloc (t->container, nc, nr + 1);
memset (t->rh, 0, nc * (nr + 1));
- t->hrh = pool_nmalloc (t->container, nr + 1, sizeof *t->hrh);
- memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
-
t->rv = pool_nmalloc (t->container, nr, nc + 1);
memset (t->rv, UCHAR_MAX, nr * (nc + 1));
- t->wrv = pool_nmalloc (t->container, nc + 1, sizeof *t->wrv);
- memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
-
t->dim = NULL;
- t->w = t->h = NULL;
t->col_ofs = t->row_ofs = 0;
return t;
}
-/* Destroys table T. */
+/* Increases T's reference count and, if this causes T's
+ reference count to reach 0, destroys T. */
void
tab_destroy (struct tab_table *t)
{
- assert (t != NULL);
+ assert (t->ref_cnt > 0);
+ if (--t->ref_cnt > 0)
+ return;
+ if (t->dim_free != NULL)
+ t->dim_free (t->dim_aux);
+ free (t->title);
pool_destroy (t->container);
}
+/* Increases T's reference count. */
+void
+tab_ref (struct tab_table *t)
+{
+ 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. */
}
if (nr != -1)
{
- assert (nr + t->row_ofs <= t->nr);
+ assert (nr + t->row_ofs <= tab_nr (t));
t->nr = nr + t->row_ofs;
}
}
tab_realloc (struct tab_table *t, int nc, int nr)
{
int ro, co;
-
+
assert (t != NULL);
ro = t->row_ofs;
co = t->col_ofs;
tab_offset (t, 0, 0);
if (nc == -1)
- nc = t->nc;
+ nc = tab_nc (t);
if (nr == -1)
- nr = t->nr;
-
- assert (nc == t->nc);
-
+ nr = tab_nr (t);
+
+ assert (nc == tab_nc (t));
+
if (nc > t->cf)
{
- int mr1 = min (nr, t->nr);
- int mc1 = min (nc, t->nc);
-
- struct fixed_string *new_cc;
+ 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_ct = pool_malloc (t->container, nr * nc);
for (r = 0; r < mr1; r++)
{
- memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
- memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
- memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
+ 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->ct = new_ct;
t->cf = nc;
}
- else if (nr != t->nr)
+ 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 > t->nr)
+
+ if (nr > tab_nr (t))
{
- memset (&t->rh[nc * (t->nr + 1)], TAL_0, (nr - t->nr) * nc);
- memset (&t->rv[(nc + 1) * t->nr], UCHAR_MAX,
- (nr - t->nr) * (nc + 1));
+ 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 * t->nr], TAB_EMPTY, nc * (nr - t->nr));
-
+ memset (&t->ct[nc * tab_nr (t)], TAB_EMPTY, nc * (nr - tab_nr (t)));
+
t->nr = nr;
t->nc = nc;
/* 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. GROUP is the number of rows to take
- as a unit. */
+ STYLE is a TAB_COL_* constant. */
void
-tab_columns (struct tab_table *t, int style, int group)
+tab_columns (struct tab_table *t, int style)
{
assert (t != NULL);
t->col_style = style;
- t->col_group = group;
}
\f
/* Rules. */
assert (t != NULL);
#if DEBUGGING
- if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
+ 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,
- t->nc, t->nr);
+ tab_nc (t), tab_nr (t));
return;
}
#endif
y2 += t->row_ofs;
assert (x > 0);
- assert (x < t->nc);
+ assert (x < tab_nc (t));
assert (y1 >= 0);
assert (y2 >= y1);
- assert (y2 <= t->nr);
+ assert (y2 <= tab_nr (t));
if (style != -1)
{
y += t->row_ofs;
assert (y >= 0);
- assert (y < t->nr);
+ assert (y <= tab_nr (t));
assert (x2 >= x1 );
assert (x1 >= 0 );
- assert (x2 < t->nc);
+ assert (x2 < tab_nc (t));
if (style != -1)
{
assert (t != NULL);
#if DEBUGGING
- if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
- || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
+ 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"),
y1, t->row_ofs, y1 + t->row_ofs,
x2, t->col_ofs, x2 + t->col_ofs,
y2, t->row_ofs, y2 + t->row_ofs,
- t->nc, t->nr);
- abort ();
+ tab_nc (t), tab_nr (t));
+ NOT_REACHED ();
}
#endif
assert (y2 >= y1);
assert (x1 >= 0);
assert (y1 >= 0);
- assert (x2 < t->nc);
- assert (y2 < t->nr);
+ assert (x2 < tab_nc (t));
+ assert (y2 < tab_nr (t));
if (f_h != -1)
{
if (i_h != -1)
{
int y;
-
+
for (y = y1 + 1; y <= y2; y++)
{
int x;
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;
}
}
}
-/* Formats text TEXT and arguments ARGS as indicated in OPT and sets
- the resultant string into S in TABLE's pool. */
-static void
-text_format (struct tab_table *table, int opt, const char *text, va_list args,
- struct fixed_string *s)
+/* Formats text TEXT and arguments ARGS as indicated in OPT in
+ TABLE's pool and returns the resultant string. */
+static struct substring
+text_format (struct tab_table *table, int opt, const char *text, va_list args)
{
- char *tmp = NULL;
-
- assert (table != NULL && text != NULL && s != NULL);
-
- if (opt & TAT_PRINTF)
- text = tmp = xvasprintf (text, args);
-
- ls_create_buffer (s, text, strlen (text));
- pool_register (table->container, free, s->string);
-
- free (tmp);
+ assert (table != NULL && text != NULL);
+
+ return ss_cstr (opt & TAT_PRINTF
+ ? pool_vasprintf (table->container, text, args)
+ : pool_strdup (table->container, text));
}
/* Set the title of table T to TITLE, which is formatted as if
assert (t != NULL && title != NULL);
va_start (args, title);
- text_format (t, TAT_PRINTF, title, args, &t->title);
+ t->title = xvasprintf (title, args);
va_end (args);
}
-/* Set DIM_FUNC as the dimension function for table T. */
+/* 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 (struct tab_table *t,
+ tab_dim_func *dim_func, tab_dim_free_func *free_func, void *aux)
{
- assert (t != NULL && t->dim == NULL);
+ 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
wrapping. The width will be no larger than the page width minus
left and right rule widths. */
int
-tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
+tab_natural_width (const struct tab_rendering *r, int col)
{
- int width;
+ const struct tab_table *t = r->table;
+ int width, row, max_width;
- assert (t != NULL && c >= 0 && c < t->nc);
- {
- int r;
+ assert (col >= 0 && col < tab_nc (t));
- for (width = r = 0; r < t->nr; r++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[c + r * t->cf];
- int w;
-
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
-
- text.string = t->cc[c + r * t->cf];
- assert (!ls_null_p (&text.string));
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = text.v = INT_MAX;
-
- d->class->text_metrics (d, &text, &w, NULL);
- if (w > width)
- width = w;
- }
- }
+ 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)
{
- width = d->prop_em_width * 8;
-#if DEBUGGING
- printf ("warning: table column %d contains no data.\n", c);
-#endif
+ /* 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;
}
-
- {
- const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
-
- if (width > clamp)
- width = clamp;
- }
- return width;
+ 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 (struct tab_table *t, struct outp_driver *d, int r)
+tab_natural_height (const struct tab_rendering *r, int row)
{
- int height;
+ const struct tab_table *t = r->table;
+ int height, col;
- assert (t != NULL && r >= 0 && r < t->nr);
-
- {
- int c;
-
- for (height = d->font_height, c = 0; c < t->nc; c++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[c + r * t->cf];
- int h;
-
- assert (t->w[c] != NOT_INT);
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
-
- text.string = t->cc[c + r * t->cf];
- assert (!ls_null_p (&text.string));
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = t->w[c];
- text.v = INT_MAX;
- d->class->text_metrics (d, &text, NULL, &h);
-
- if (h > height)
- height = h;
- }
- }
+ 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_table *t, struct outp_driver *d)
+tab_natural_dimensions (struct tab_rendering *r, void *aux UNUSED)
{
+ const struct tab_table *t = r->table;
int i;
- assert (t != NULL);
-
- for (i = 0; i < t->nc; i++)
- t->w[i] = tab_natural_width (t, d, i);
-
- for (i = 0; i < t->nr; i++)
- t->h[i] = tab_natural_height (t, d, 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
assert (table != NULL && v != NULL && f != 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)
+ || 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,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
contents = pool_alloc (table->container, f->w);
- ls_init (&table->cc[c + r * table->cf], contents, f->w);
+ table->cc[c + r * table->cf] = ss_buffer (contents, f->w);
table->ct[c + r * table->cf] = opt;
-
- data_out (contents, f, v);
+
+ data_out (v, f, contents);
}
/* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
with NDEC decimal places. */
void
-tab_float (struct tab_table *table, int c, int r, unsigned char opt,
+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 (c < tab_nc (table));
assert (r >= 0);
- assert (r < table->nr);
+ assert (r < tab_nr (table));
+
+ f = fmt_for_output (FMT_F, w, d);
- f = make_output_format (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)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
- printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
+ 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);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
double_value.f = val;
- data_out (buf, &f, &double_value);
+ data_out (&double_value, &f, buf);
cp = buf;
while (isspace ((unsigned char) *cp) && cp < &buf[w])
f.w = w - (cp - buf);
contents = pool_alloc (table->container, f.w);
- ls_init (&table->cc[c + r * table->cf], contents, 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 < 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))
+ {
+ 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,
+ tab_nc (table), tab_nr (table));
+ 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
assert (c >= 0 );
assert (r >= 0 );
- assert (c < table->nc);
- assert (r < table->nr);
-
+ assert (c < tab_nc (table));
+ assert (r < tab_nr (table));
+
#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)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
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);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
va_start (args, text);
- text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
+ table->cc[c + r * table->cf] = text_format (table, opt, text, args);
table->ct[c + r * table->cf] = opt;
va_end (args);
}
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);
+ assert (y2 + table->row_ofs < tab_nr (table));
+ assert (x2 + table->col_ofs < tab_nc (table));
#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)
+ if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
+ || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
+ || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
+ || y2 < y2 || y2 + table->row_ofs >= tab_nr (table))
{
printf ("tab_joint_text(): bad cell "
"(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
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);
+ tab_nc (table), tab_nr (table));
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);
- text_format (table, opt, text, args, &j->contents);
+ j->contents = text_format (table, opt, text, args);
va_end (args);
}
-
+
opt |= TAB_JOIN;
-
+
{
- struct fixed_string *cc = &table->cc[x1 + y1 * table->cf];
+ 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++)
{
- ls_init (cc++, (char *) j, 0);
+ *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 fixed_string *string)
+ 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)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
- printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
+ 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);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
/* 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_table *t, struct outp_driver *d)
+nowrap_dim (struct tab_rendering *r, void *aux UNUSED)
{
- t->w[0] = tab_natural_width (t, d, 0);
- t->h[0] = d->font_height;
+ 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_table *t, struct outp_driver *d)
+wrap_dim (struct tab_rendering *r, void *aux UNUSED)
{
- t->w[0] = tab_natural_width (t, d, 0);
- t->h[0] = tab_natural_height (t, d, 0);
+ 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
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);
+ tab_dim (t, options & TAT_NOWRAP ? nowrap_dim : wrap_dim, NULL, NULL);
tab_submit (t);
-
+
free (tmp_buf);
}
assert (t != NULL);
#if DEBUGGING
- if (row < -1 || row >= t->nr)
+ if (row < -1 || row > tab_nr (t))
{
- printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
- abort ();
+ printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
+ NOT_REACHED ();
}
- if (col < -1 || col >= t->nc)
+ if (col < -1 || col > tab_nc (t))
{
- printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
- abort ();
+ printf ("tab_offset(): col=%d in %d-column table\n", col, tab_nc (t));
+ NOT_REACHED ();
}
#endif
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);
+ if (++t->row_ofs >= tab_nr (t))
+ tab_realloc (t, -1, tab_nr (t) * 4 / 3);
}
\f
-static struct tab_table *t;
-static struct outp_driver *d;
-int tab_hit;
+/* 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;
+}
-/* Set the current table to TABLE. */
+/* Return the column style for this table into STYLE. */
static void
-tabi_table (struct som_entity *table)
+tabi_columns (struct som_entity *t_, int *style)
{
- assert (table != NULL);
- assert (table->type == SOM_TABLE);
-
- t = table->ext;
- tab_offset (t, 0, 0);
-
- assert (t->w == NULL && t->h == NULL);
- t->w = pool_nalloc (t->container, t->nc, sizeof *t->w);
- t->h = pool_nalloc (t->container, t->nr, sizeof *t->h);
+ 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)
+rule_to_spacing_type (unsigned char type)
{
- switch (type)
+ switch (type)
{
case TAL_0:
return OUTP_L_NONE;
case TAL_2:
return OUTP_L_DOUBLE;
default:
- abort ();
+ NOT_REACHED ();
}
}
-/* Set the current output device to DRIVER. */
-static void
-tabi_driver (struct outp_driver *driver)
+static void *
+tabi_render_init (struct som_entity *t_, struct outp_driver *driver,
+ int hl, int hr, int ht, int hb)
{
- int c, r;
+ const struct tab_table *t = t_->ext;
+ struct tab_rendering *r;
+ int col, row;
int i;
-
- assert (driver != NULL);
- d = driver;
-
+
+ tab_offset (t_->ext, 0, 0);
+
+ r = xmalloc (sizeof *r);
+ r->table = t;
+ r->driver = driver;
+ r->w = xnmalloc (tab_nc (t), sizeof *r->w);
+ r->h = xnmalloc (tab_nr (t), sizeof *r->h);
+ r->hrh = xnmalloc (tab_nr (t) + 1, sizeof *r->hrh);
+ r->wrv = xnmalloc (tab_nc (t) + 1, sizeof *r->wrv);
+ r->l = hl;
+ r->r = hr;
+ r->t = ht;
+ r->b = hb;
+
/* Figure out sizes of rules. */
- for (r = 0; r <= t->nr; r++)
+ for (row = 0; row <= tab_nr (t); row++)
{
int width = 0;
- for (c = 0; c < t->nc; c++)
+ for (col = 0; col < tab_nc (t); col++)
{
- unsigned char rh = t->rh[c + r * t->cf];
+ 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;
+ width = w;
}
- t->hrh[r] = width;
+ r->hrh[row] = width;
}
- for (c = 0; c <= t->nc; c++)
+ for (col = 0; col <= tab_nc (t); col++)
{
int width = 0;
- for (r = 0; r < t->nr; r++)
+ for (row = 0; row < tab_nr (t); row++)
{
- unsigned char *rv = &t->rv[c + r * (t->cf + 1)];
+ unsigned char *rv = &t->rv[col + row * (t->cf + 1)];
int w;
if (*rv == UCHAR_MAX)
- *rv = c != 0 && c != t->nc ? TAL_GAP : TAL_0;
+ *rv = col != 0 && col != tab_nc (t) ? TAL_GAP : TAL_0;
w = driver->vert_line_width[rule_to_spacing_type (*rv)];
if (w > width)
width = w;
}
- t->wrv[c] = width;
+ r->wrv[col] = width;
}
-#if DEBUGGING
- for (i = 0; i < t->nr; i++)
- t->h[i] = -1;
- for (i = 0; i < t->nc; i++)
- t->w[i] = -1;
-#endif
+ /* Determine row heights and columns widths. */
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = -1;
+ for (i = 0; i < tab_nc (t); i++)
+ r->w[i] = -1;
- assert (t->dim != NULL);
- t->dim (t, d);
+ t->dim (r, t->dim_aux);
-#if DEBUGGING
- {
- int error = 0;
+ for (i = 0; i < tab_nr (t); 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 < tab_nc (t); i++)
+ if (r->w[i] < 0)
+ error (0, 0, "width of table column %d is %d (not initialized?)",
+ i, r->w[i]);
- for (i = 0; i < t->nr; i++)
- {
- if (t->h[i] == -1)
- {
- printf ("Table row %d height not initialized.\n", i);
- error = 1;
- }
- assert (t->h[i] > 0);
- }
-
- for (i = 0; i < t->nc; i++)
- {
- if (t->w[i] == -1)
- {
- printf ("Table column %d width not initialized.\n", i);
- error = 1;
- }
- assert (t->w[i] > 0);
- }
- }
-#endif
-
/* Add up header sizes. */
- for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
- t->wl += t->w[i] + t->wrv[i + 1];
- for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
- t->ht += t->h[i] + t->hrh[i + 1];
- for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
- t->wr += t->w[i] + t->wrv[i + 1];
- for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
- t->hb += t->h[i] + t->hrh[i + 1];
-
+ 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 = tab_nc (t) - r->r, r->wr = r->wrv[i]; i < tab_nc (t); i++)
+ r->wr += r->w[i] + r->wrv[i + 1];
+ for (i = tab_nr (t) - r->b, r->hb = r->hrh[i]; i < tab_nr (t); i++)
+ r->hb += r->h[i] + r->hrh[i + 1];
+
/* Title. */
if (!(t->flags & SOMF_NO_TITLE))
- t->ht += d->font_height;
+ r->ht += driver->font_height;
+
+ return r;
}
-/* Return the number of columns and rows in the table into N_COLUMNS
- and N_ROWS, respectively. */
static void
-tabi_count (int *n_columns, int *n_rows)
+tabi_render_free (void *r_)
{
- assert (n_columns != NULL && n_rows != NULL);
- *n_columns = t->nc;
- *n_rows = t->nr;
-}
+ struct tab_rendering *r = r_;
-static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
+ 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 (int *horiz, int *vert)
-{
- assert (horiz != NULL && vert != NULL);
-
- {
- int w, c;
-
- for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
- c < t->nc - t->r; c++)
- w += t->w[c] + t->wrv[c];
- *horiz = w;
- }
-
- {
- int h, r;
- for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
- r < t->nr - t->b; r++)
- h += t->h[r] + t->hrh[r];
- *vert = h;
- }
-}
-
-/* Return the column style for this table into STYLE. */
-static void
-tabi_columns (int *style)
+tabi_area (void *r_, int *horiz, int *vert)
{
- assert (style != NULL);
- *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 (int *hl, int *hr, int *ht, int *hb)
-{
- assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
- *hl = t->l;
- *hr = t->r;
- *ht = t->t;
- *hb = t->b;
+ 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[tab_l (t)];
+ col < tab_nc (t) - 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[tab_t (t)];
+ row < tab_nr (t) - tab_b (t); row++)
+ height += r->h[row] + r->hrh[row];
+ *vert = height;
}
/* Determines the number of rows or columns (including appropriate
space the selected rows/columns (including appropriate headers)
filled. */
static void
-tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
+tabi_cumulate (void *r_, int cumtype, int start, int *end,
+ int max, int *actual)
{
- int n;
- int *d;
- int *r;
+ 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);
- n = t->nr - t->b;
- d = &t->h[start];
- r = &t->hrh[start + 1];
- total = t->ht + t->hb;
+ assert (start >= 0 && start < tab_nr (t));
+ limit = tab_nr (t) - r->b;
+ cells = &r->h[start];
+ rules = &r->hrh[start + 1];
+ total = r->ht + r->hb;
}
else
{
- assert (start >= 0 && start < t->nc);
- n = t->nc - t->r;
- d = &t->w[start];
- r = &t->wrv[start + 1];
- total = t->wl + t->wr;
+ assert (start >= 0 && start < tab_nc (t));
+ limit = tab_nc (t) - tab_r (t);
+ cells = &r->w[start];
+ rules = &r->wrv[start + 1];
+ total = r->wl + r->wr;
}
-
- total += *d++;
+
+ total += *cells++;
if (total > max)
{
if (end)
*actual = 0;
return;
}
-
- {
- int x;
-
- for (x = start + 1; x < n; x++)
- {
- int amt = *d++ + *r++;
-
- total += amt;
- if (total > max)
- {
- total -= amt;
- break;
- }
- }
-
- if (end)
- *end = x;
-
- if (actual)
- *actual = total;
- }
-}
-
-/* Return flags set for the current table into FLAGS. */
-static void
-tabi_flags (unsigned *flags)
-{
- assert (flags != NULL);
- *flags = t->flags;
-}
-
-/* Returns true if the table will fit in the given page WIDTH,
- false otherwise. */
-static bool
-tabi_fits_width (int width)
-{
- int i;
- for (i = t->l; i < t->nc - t->r; i++)
- if (t->wl + t->wr + t->w[i] > width)
- return false;
-
- return true;
-}
-
-/* Returns true if the table will fit in the given page LENGTH,
- false otherwise. */
-static bool
-tabi_fits_length (int length)
-{
- int i;
+ for (idx = start + 1; idx < limit; idx++)
+ {
+ int amt = *cells++ + *rules++;
- for (i = t->t; i < t->nr - t->b; i++)
- if (t->ht + t->hb + t->h[i] > length)
- return false;
+ total += amt;
+ if (total > max)
+ {
+ total -= amt;
+ break;
+ }
+ }
- return true;
-}
+ if (end)
+ *end = idx;
-/* Sets the number of header rows/columns on the left, right, top,
- and bottom sides to HL, HR, HT, and HB, respectively. */
-static void
-tabi_set_headers (int hl, int hr, int ht, int hb)
-{
- t->l = hl;
- t->r = hr;
- t->t = ht;
- t->b = hb;
+ if (actual)
+ *actual = total;
}
/* Render title for current table, with major index X and minor index
Y. Y may be zero, or X and Y may be zero, but X should be nonzero
if Y is nonzero. */
static void
-tabi_title (int x, int y)
+tabi_title (void *r_, int x, int y, int table_num, int subtable_num,
+ const char *command_name)
{
- char buf[1024];
- char *cp;
+ const struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ struct outp_text text;
+ struct string title;
if (t->flags & SOMF_NO_TITLE)
return;
-
- cp = spprintf (buf, "%d.%d", table_num, subtable_num);
+
+ ds_init_empty (&title);
+ ds_put_format (&title,"%d.%d", table_num, subtable_num);
if (x && y)
- cp = spprintf (cp, "(%d:%d)", x, y);
+ ds_put_format (&title, "(%d:%d)", x, y);
else if (x)
- cp = spprintf (cp, "(%d)", x);
+ ds_put_format (&title, "(%d)", x);
if (command_name != NULL)
- cp = spprintf (cp, " %s", command_name);
- cp = stpcpy (cp, ". ");
- if (!ls_empty_p (&t->title))
- {
- memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
- cp += ls_length (&t->title);
- }
- *cp = 0;
-
- {
- struct outp_text text;
-
- text.font = OUTP_PROPORTIONAL;
- text.justification = OUTP_LEFT;
- ls_init (&text.string, buf, cp - buf);
- text.h = d->width;
- text.v = d->font_height;
- text.x = 0;
- text.y = d->cp_y;
- d->class->text_draw (d, &text);
- }
+ ds_put_format (&title, " %s", command_name);
+ ds_put_cstr (&title, ". ");
+ if (t->title != NULL)
+ ds_put_cstr (&title, t->title);
+
+ text.font = OUTP_PROPORTIONAL;
+ text.justification = OUTP_LEFT;
+ text.string = ds_ss (&title);
+ text.h = r->driver->width;
+ text.v = r->driver->font_height;
+ text.x = 0;
+ text.y = r->driver->cp_y;
+ r->driver->class->text_draw (r->driver, &text);
+
+ ds_destroy (&title);
}
-static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
+static int render_strip (const struct tab_rendering *,
+ int x, int y, int r, int c1, int c2, int r1, int r2);
-/* Renders columns C0...C1, plus headers, of rows R0...R1,
- at the given vertical position Y.
- C0 and C1 count vertical rules as columns,
- but R0 and R1 do not count horizontal rules as rows.
- Returns the vertical position after rendering. */
-static int
-render_rows (int y, int c0, int c1, int r0, int r1)
+static void
+add_range (int ranges[][2], int *np, int start, int end)
{
- int r;
- for (r = r0; r < r1; r++)
+ int n = *np;
+ if (n == 0 || start > ranges[n - 1][1])
{
- int x = d->cp_x;
- x = render_strip (x, y, r, 0, t->l * 2 + 1, r0, r1);
- x = render_strip (x, y, r, c0 * 2 + 1, c1 * 2, r0, r1);
- x = render_strip (x, y, r, (t->nc - t->r) * 2, t->nc * 2 + 1, r0, r1);
- y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
+ ranges[n][0] = start;
+ ranges[n][1] = end;
+ ++*np;
}
- return y;
+ else
+ ranges[n - 1][1] = end;
}
/* Draws table region (C0,R0)-(C1,R1), plus headers, at the
current position on the current output device. */
static void
-tabi_render (int c0, int r0, int c1, int r1)
+tabi_render (void *r_, int c0, int r0, int c1, int r1)
{
- int y;
-
- tab_hit++;
-
- y = d->cp_y;
+ const struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ int rows[3][2], cols[3][2];
+ int n_row_ranges, n_col_ranges;
+ int y, i;
+
+ /* Rows to render, counting horizontal rules as rows. */
+ n_row_ranges = 0;
+ add_range (rows, &n_row_ranges, 0, tab_t (t) * 2 + 1);
+ add_range (rows, &n_row_ranges, r0 * 2 + 1, r1 * 2);
+ add_range (rows, &n_row_ranges, (tab_nr (t) - tab_b (t)) * 2,
+ tab_nr (t) * 2 + 1);
+
+ /* Columns to render, counting vertical rules as columns. */
+ n_col_ranges = 0;
+ add_range (cols, &n_col_ranges, 0, r->l * 2 + 1);
+ add_range (cols, &n_col_ranges, c0 * 2 + 1, c1 * 2);
+ add_range (cols, &n_col_ranges, (tab_nc (t) - r->r) * 2, tab_nc (t) * 2 + 1);
+
+ y = r->driver->cp_y;
if (!(t->flags & SOMF_NO_TITLE))
- y += d->font_height;
+ y += r->driver->font_height;
+ for (i = 0; i < n_row_ranges; i++)
+ {
+ int row;
- y = render_rows (y, c0, c1, 0, t->t * 2 + 1);
- y = render_rows (y, c0, c1, r0 * 2 + 1, r1 * 2);
- y = render_rows (y, c0, c1, (t->nr - t->b) * 2, t->nr * 2 + 1);
+ for (row = rows[i][0]; row < rows[i][1]; row++)
+ {
+ int x, j;
+
+ x = r->driver->cp_x;
+ for (j = 0; j < n_col_ranges; j++)
+ x = render_strip (r, x, y, row,
+ cols[j][0], cols[j][1],
+ rows[i][0], rows[i][1]);
+
+ y += (row & 1) ? r->h[row / 2] : r->hrh[row / 2];
+ }
+ }
}
-struct som_table_class tab_table_class =
+const struct som_table_class tab_table_class =
{
- tabi_table,
- tabi_driver,
-
tabi_count,
- tabi_area,
- NULL,
- NULL,
tabi_columns,
- NULL,
tabi_headers,
- NULL,
- tabi_cumulate,
tabi_flags,
- tabi_fits_width,
- tabi_fits_length,
-
- NULL,
- NULL,
- tabi_set_headers,
+ tabi_render_init,
+ tabi_render_free,
+
+ tabi_area,
+ tabi_cumulate,
tabi_title,
tabi_render,
};
static enum outp_justification
translate_justification (unsigned int opt)
{
- switch (opt & TAB_ALIGN_MASK)
+ switch (opt & TAB_ALIGN_MASK)
{
case TAB_RIGHT:
return OUTP_RIGHT;
case TAB_CENTER:
return OUTP_CENTER;
default:
- abort ();
+ NOT_REACHED ();
}
}
/* Returns the line style to use for drawing a rule of the given
TYPE. */
static enum outp_line_style
-rule_to_draw_type (unsigned char type)
+rule_to_draw_type (unsigned char type)
{
- switch (type)
+ switch (type)
{
case TAL_0:
case TAL_GAP:
case TAL_2:
return OUTP_L_DOUBLE;
default:
- abort ();
+ NOT_REACHED ();
}
}
/* Returns the horizontal rule at the given column and row. */
static int
-get_hrule (int c, int r)
+get_hrule (const struct tab_table *t, int col, int row)
{
- return t->rh[c + r * t->cf];
+ return t->rh[col + row * t->cf];
}
/* Returns the vertical rule at the given column and row. */
static int
-get_vrule (int c, int r)
+get_vrule (const struct tab_table *t, int col, int row)
{
- return t->rv[c + r * (t->cf + 1)];
+ return t->rv[col + row * (t->cf + 1)];
}
/* Renders the horizontal rule at the given column and row
at (X,Y) on the page. */
static void
-render_horz_rule (int x, int y, int c, int r)
+render_horz_rule (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
- enum outp_line_style style = rule_to_draw_type (get_hrule (c, r));
+ enum outp_line_style style;
+ style = rule_to_draw_type (get_hrule (r->table, col, row));
if (style != OUTP_L_NONE)
- d->class->line (d, x, y, x + t->w[c], y + t->hrh[r],
- OUTP_L_NONE, style, OUTP_L_NONE, style);
+ r->driver->class->line (r->driver, x, y, x + r->w[col], y + r->hrh[row],
+ OUTP_L_NONE, style, OUTP_L_NONE, style);
}
/* Renders the vertical rule at the given column and row
at (X,Y) on the page. */
static void
-render_vert_rule (int x, int y, int c, int r)
+render_vert_rule (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
- enum outp_line_style style = rule_to_draw_type (get_vrule (c, r));
+ enum outp_line_style style;
+ style = rule_to_draw_type (get_vrule (r->table, col, row));
if (style != OUTP_L_NONE)
- d->class->line (d, x, y, x + t->wrv[c], y + t->h[r],
- style, OUTP_L_NONE, style, OUTP_L_NONE);
+ r->driver->class->line (r->driver, x, y, x + r->wrv[col], y + r->h[row],
+ style, OUTP_L_NONE, style, OUTP_L_NONE);
}
/* Renders the rule intersection at the given column and row
at (X,Y) on the page. */
static void
-render_rule_intersection (int x, int y, int c, int r)
+render_rule_intersection (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
+ const struct tab_table *t = r->table;
+
/* Bounds of intersection. */
int x0 = x;
int y0 = y;
- int x1 = x + t->wrv[c];
- int y1 = y + t->hrh[r];
+ int x1 = x + r->wrv[col];
+ int y1 = y + r->hrh[row];
/* Lines on each side of intersection. */
- int top = r > 0 ? get_vrule (c, r - 1) : TAL_0;
- int left = c > 0 ? get_hrule (c - 1, r) : TAL_0;
- int bottom = r < t->nr ? get_vrule (c, r) : TAL_0;
- int right = c < t->nc ? get_hrule (c, r) : TAL_0;
+ int top = row > 0 ? get_vrule (t, col, row - 1) : TAL_0;
+ int left = col > 0 ? get_hrule (t, col - 1, row) : TAL_0;
+ int bottom = row < tab_nr (t) ? get_vrule (t, col, row) : TAL_0;
+ int right = col < tab_nc (t) ? get_hrule (t, col, row) : TAL_0;
/* Output style for each line. */
enum outp_line_style o_top = rule_to_draw_type (top);
if (o_top != OUTP_L_NONE || o_left != OUTP_L_NONE
|| o_bottom != OUTP_L_NONE || o_right != OUTP_L_NONE)
- d->class->line (d, x0, y0, x1, y1, o_top, o_left, o_bottom, o_right);
+ r->driver->class->line (r->driver, x0, y0, x1, y1,
+ o_top, o_left, o_bottom, o_right);
}
/* Returns the width of columns C1...C2 exclusive,
including interior but not exterior rules. */
static int
-strip_width (int c1, int c2)
+strip_width (const struct tab_rendering *r, int c1, int c2)
{
int width = 0;
int c;
- for (c = c1; c < c2; c++)
- width += t->w[c] + t->wrv[c + 1];
+ for (c = c1; c < c2; c++)
+ width += r->w[c] + r->wrv[c + 1];
if (c1 < c2)
- width -= t->wrv[c2];
+ width -= r->wrv[c2];
return width;
}
/* Returns the height of rows R1...R2 exclusive,
including interior but not exterior rules. */
static int
-strip_height (int r1, int r2)
+strip_height (const struct tab_rendering *r, int r1, int r2)
{
int height = 0;
- int r;
+ int row;
- for (r = r1; r < r2; r++)
- height += t->h[r] + t->hrh[r + 1];
+ for (row = r1; row < r2; row++)
+ height += r->h[row] + r->hrh[row + 1];
if (r1 < r2)
- height -= t->hrh[r2];
+ height -= r->hrh[r2];
return height;
}
page. Also renders joined cells that extend as far to the
right as C1 and as far down as R1. */
static void
-render_cell (int x, int y, int c, int r, int c1, int r1)
+render_cell (const struct tab_rendering *r,
+ int x, int y, int col, int row, int c1, int r1)
{
- const int index = c + (r * t->cf);
+ const struct tab_table *t = r->table;
+ const int index = col + (row * t->cf);
unsigned char type = t->ct[index];
- struct fixed_string *content = &t->cc[index];
-
+ struct substring *content = &t->cc[index];
+
if (!(type & TAB_JOIN))
{
if (!(type & TAB_EMPTY))
text.font = options_to_font (type);
text.justification = translate_justification (type);
text.string = *content;
- text.h = t->w[c];
- text.v = t->h[r];
+ text.h = r->w[col];
+ text.v = r->h[row];
text.x = x;
text.y = y;
- d->class->text_draw (d, &text);
+ r->driver->class->text_draw (r->driver, &text);
}
}
else
{
struct tab_joined_cell *j
- = (struct tab_joined_cell *) ls_c_str (content);
+ = (struct tab_joined_cell *) ss_data (*content);
- if (j->hit != tab_hit)
+ if (j->x1 == col && j->y1 == row)
{
- j->hit = tab_hit;
-
- if (j->x1 == c && j->y1 == r)
- {
- struct outp_text text;
- text.font = options_to_font (type);
- text.justification = translate_justification (type);
- text.string = j->contents;
- text.x = x;
- text.y = y;
- text.h = strip_width (j->x1, MIN (j->x2, c1));
- text.v = strip_height (j->y1, MIN (j->y2, r1));
- d->class->text_draw (d, &text);
- }
+ struct outp_text text;
+ text.font = options_to_font (type);
+ text.justification = translate_justification (type);
+ text.string = j->contents;
+ text.x = x;
+ text.y = y;
+ text.h = strip_width (r, j->x1, MIN (j->x2, c1));
+ text.v = strip_height (r, j->y1, MIN (j->y2, r1));
+ r->driver->class->text_draw (r->driver, &text);
}
}
}
/* Render contiguous strip consisting of columns C0...C1, exclusive,
- on row R, at (X,Y). Returns X position after rendering.
+ on row ROW, at (X,Y). Returns X position after rendering.
Also renders joined cells that extend beyond that strip,
cropping them to lie within rendering region (C0,R0)-(C1,R1).
C0 and C1 count vertical rules as columns.
- R counts horizontal rules as rows, but R0 and R1 do not. */
+ ROW counts horizontal rules as rows, but R0 and R1 do not. */
static int
-render_strip (int x, int y, int r, int c0, int c1, int r0 UNUSED, int r1)
+render_strip (const struct tab_rendering *r,
+ int x, int y, int row, int c0, int c1, int r0 UNUSED, int r1)
{
- int c;
+ int col;
- for (c = c0; c < c1; c++)
- if (c & 1)
+ for (col = c0; col < c1; col++)
+ if (col & 1)
{
- if (r & 1)
- render_cell (x, y, c / 2, r / 2, c1 / 2, r1);
+ if (row & 1)
+ render_cell (r, x, y, col / 2, row / 2, c1 / 2, r1);
else
- render_horz_rule (x, y, c / 2, r / 2);
- x += t->w[c / 2];
+ render_horz_rule (r, x, y, col / 2, row / 2);
+ x += r->w[col / 2];
}
else
{
- if (r & 1)
- render_vert_rule (x, y, c / 2, r / 2);
+ if (row & 1)
+ render_vert_rule (r, x, y, col / 2, row / 2);
else
- render_rule_intersection (x, y, c / 2, r / 2);
- x += t->wrv[c / 2];
+ render_rule_intersection (r, x, y, col / 2, row / 2);
+ x += r->wrv[col / 2];
}
-
- return x;
-}
-/* Sets COMMAND_NAME as the name of the current command,
- for embedding in output. */
-void
-tab_set_command_name (const char *command_name_)
-{
- free (command_name);
- command_name = command_name_ ? xstrdup (command_name_) : NULL;
+ return x;
}