1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
37 #include "debug-print.h"
39 struct som_table_class tab_table_class;
42 #define DEFFIRST(NAME, LABEL) LABEL,
43 #define DEFTAB(NAME, LABEL) LABEL,
45 static const char *tab_names[] =
54 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
55 nonzero then the table's size can be increased later; otherwise,
56 its size can only be reduced. */
58 tab_create (int nc, int nr, int reallocable)
60 void *(*alloc_func) (struct pool *, size_t);
65 struct pool *container = pool_create ();
66 t = pool_alloc (container, sizeof *t);
67 t->container = container;
70 t->col_style = TAB_COL_NONE;
76 t->l = t->r = t->t = t->b = 0;
78 alloc_func = reallocable ? pool_malloc : pool_alloc;
80 t->reallocable = reallocable;
83 t->cc = alloc_func (t->container, nr * nc * sizeof *t->cc);
84 t->ct = alloc_func (t->container, nr * nc);
85 memset (t->ct, TAB_EMPTY, nc * nr);
87 t->rh = alloc_func (t->container, nc * (nr + 1));
88 memset (t->rh, 0, nc * (nr + 1));
90 t->hrh = alloc_func (t->container, sizeof *t->hrh * (nr + 1));
91 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
93 t->trh = alloc_func (t->container, nr + 1);
94 memset (t->trh, 0, nr + 1);
96 t->rv = alloc_func (t->container, (nc + 1) * nr);
97 memset (t->rv, 0, (nc + 1) * nr);
99 t->wrv = alloc_func (t->container, sizeof *t->wrv * (nc + 1));
100 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
102 t->trv = alloc_func (t->container, nc + 1);
103 memset (t->trv, 0, nc + 1);
107 t->col_ofs = t->row_ofs = 0;
112 /* Destroys table T. */
114 tab_destroy (struct tab_table *t)
117 pool_destroy (t->container);
121 /* Sets the width and height of a table, in columns and rows,
122 respectively. Use only to reduce the size of a table, since it
123 does not change the amount of allocated memory. */
125 tab_resize (struct tab_table *t, int nc, int nr)
130 assert (nc + t->col_ofs <= t->cf);
131 t->nc = nc + t->col_ofs;
135 assert (nr + t->row_ofs <= t->nr);
136 t->nr = nr + t->row_ofs;
140 /* Changes either or both dimensions of a table. Consider using the
141 above routine instead if it won't waste a lot of space.
143 Changing the number of columns in a table is particularly expensive
144 in space and time. Avoid doing such. FIXME: In fact, transferring
145 of rules isn't even implemented yet. */
147 tab_realloc (struct tab_table *t, int nc, int nr)
153 assert (t->reallocable);
158 tab_offset (t, 0, 0);
165 assert (nc == t->nc);
169 int mr1 = min (nr, t->nr);
170 int mc1 = min (nc, t->nc);
172 struct len_string *new_cc;
173 unsigned char *new_ct;
176 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
177 new_ct = pool_malloc (t->container, nr * nc);
178 for (r = 0; r < mr1; r++)
180 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
181 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
182 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
184 pool_free (t->container, t->cc);
185 pool_free (t->container, t->ct);
190 else if (nr != t->nr)
192 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
193 t->ct = pool_realloc (t->container, t->ct, nr * nc);
195 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
196 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
197 t->trh = pool_realloc (t->container, t->trh, nr + 1);
198 t->hrh = pool_realloc (t->container, t->hrh,
199 sizeof *t->hrh * (nr + 1));
203 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
204 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
205 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
209 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
215 tab_offset (t, co, ro);
218 /* Sets the number of header rows on each side of TABLE to L on the
219 left, R on the right, T on the top, B on the bottom. Header rows
220 are repeated when a table is broken across multiple columns or
223 tab_headers (struct tab_table *table, int l, int r, int t, int b)
225 assert (table != NULL);
232 /* Set up table T so that, when it is an appropriate size, it will be
233 displayed across the page in columns.
235 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
238 tab_columns (struct tab_table *t, int style, int group)
241 t->col_style = style;
242 t->col_group = group;
247 /* Draws a vertical line to the left of cells at horizontal position X
248 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
250 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
259 assert (y2 <= t->nr);
262 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
263 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
264 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
266 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
267 "table size (%d,%d)\n"),
268 x, t->col_ofs, x + t->col_ofs,
269 y1, t->row_ofs, y1 + t->row_ofs,
270 y2, t->row_ofs, y2 + t->row_ofs,
282 if ((style & TAL_SPACING) == 0)
283 for (y = y1; y <= y2; y++)
284 t->rv[x + (t->cf + 1) * y] = style;
285 t->trv[x] |= (1 << (style & ~TAL_SPACING));
289 /* Draws a horizontal line above cells at vertical position Y from X1
290 to X2 inclusive in style STYLE, if style is not -1. */
292 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
310 if ((style & TAL_SPACING) == 0)
311 for (x = x1; x <= x2; x++)
312 t->rh[x + t->cf * y] = style;
313 t->trh[y] |= (1 << (style & ~TAL_SPACING));
317 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
318 lines of style F_H and vertical lines of style F_V. Fills the
319 interior of the box with horizontal lines of style I_H and vertical
320 lines of style I_V. Any of the line styles may be -1 to avoid
321 drawing those lines. This is distinct from 0, which draws a null
324 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
325 int x1, int y1, int x2, int y2)
337 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
338 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
339 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
340 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
342 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
343 "in table size (%d,%d)\n"),
344 x1, t->col_ofs, x1 + t->col_ofs,
345 y1, t->row_ofs, y1 + t->row_ofs,
346 x2, t->col_ofs, x2 + t->col_ofs,
347 y2, t->row_ofs, y2 + t->row_ofs,
361 if ((f_h & TAL_SPACING) == 0)
362 for (x = x1; x <= x2; x++)
364 t->rh[x + t->cf * y1] = f_h;
365 t->rh[x + t->cf * (y2 + 1)] = f_h;
367 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
368 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
373 if ((f_v & TAL_SPACING) == 0)
374 for (y = y1; y <= y2; y++)
376 t->rv[x1 + (t->cf + 1) * y] = f_v;
377 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
379 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
380 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
387 for (y = y1 + 1; y <= y2; y++)
391 if ((i_h & TAL_SPACING) == 0)
392 for (x = x1; x <= x2; x++)
393 t->rh[x + t->cf * y] = i_h;
395 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
402 for (x = x1 + 1; x <= x2; x++)
406 if ((i_v & TAL_SPACING) == 0)
407 for (y = y1; y <= y2; y++)
408 t->rv[x + (t->cf + 1) * y] = i_v;
410 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
415 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
416 the resultant string into S in TABLE's pool. */
418 text_format (struct tab_table *table, int opt, const char *text, va_list args,
419 struct len_string *s)
423 assert (table != NULL && text != NULL && s != NULL);
425 if (opt & TAT_PRINTF)
427 char *temp_buf = local_alloc (1024);
429 len = nvsprintf (temp_buf, text, args);
435 ls_create_buffer (table->container, s, text, len);
437 if (opt & TAT_PRINTF)
441 /* Set the title of table T to TITLE, which is formatted with printf
442 if FORMAT is nonzero. */
444 tab_title (struct tab_table *t, int format, const char *title, ...)
448 assert (t != NULL && title != NULL);
449 va_start (args, title);
450 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
454 /* Set DIM_FUNC as the dimension function for table T. */
456 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
458 assert (t != NULL && t->dim == NULL);
462 /* Returns the natural width of column C in table T for driver D, that
463 is, the smallest width necessary to display all its cells without
464 wrapping. The width will be no larger than the page width minus
465 left and right rule widths. */
467 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
471 assert (t != NULL && c >= 0 && c < t->nc);
475 for (width = r = 0; r < t->nr; r++)
477 struct outp_text text;
478 unsigned char opt = t->ct[c + r * t->cf];
480 if (opt & (TAB_JOIN | TAB_EMPTY))
483 text.s = t->cc[c + r * t->cf];
484 assert (!ls_null_p (&text.s));
485 text.options = OUTP_T_JUST_LEFT;
487 d->class->text_metrics (d, &text);
495 width = d->prop_em_width * 8;
497 printf ("warning: table column %d contains no data.\n", c);
502 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
511 /* Returns the natural height of row R in table T for driver D, that
512 is, the minimum height necessary to display the information in the
513 cell at the widths set for each column. */
515 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
519 assert (t != NULL && r >= 0 && r < t->nr);
524 for (height = d->font_height, c = 0; c < t->nc; c++)
526 struct outp_text text;
527 unsigned char opt = t->ct[c + r * t->cf];
529 assert (t->w[c] != NOT_INT);
530 if (opt & (TAB_JOIN | TAB_EMPTY))
533 text.s = t->cc[c + r * t->cf];
534 assert (!ls_null_p (&text.s));
535 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
537 d->class->text_metrics (d, &text);
547 /* Callback function to set all columns and rows to their natural
548 dimensions. Not really meant to be called directly. */
550 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
556 for (i = 0; i < t->nc; i++)
557 t->w[i] = tab_natural_width (t, d, i);
559 for (i = 0; i < t->nr; i++)
560 t->h[i] = tab_natural_height (t, d, i);
566 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
567 from V, displayed with format spec F. */
569 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
570 const union value *v, const struct fmt_spec *f)
573 union value temp_val;
575 assert (table != NULL && v != NULL && f != NULL);
577 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
578 || c + table->col_ofs >= table->nc
579 || r + table->row_ofs >= table->nr)
581 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
583 c, table->col_ofs, c + table->col_ofs,
584 r, table->row_ofs, r + table->row_ofs,
585 table->nc, table->nr);
590 contents = pool_alloc (table->container, f->w);
591 ls_init (&table->cc[c + r * table->cf], contents, f->w);
592 table->ct[c + r * table->cf] = opt;
594 if (formats[f->type].cat & FCAT_STRING)
596 temp_val.c = (char *) v->s;
599 data_out (contents, f, v);
602 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
603 with NDEC decimal places. */
605 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
606 double val, int w, int d)
613 assert (table != NULL && w <= 40);
616 assert (c < table->nc);
618 assert (r < table->nr);
625 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
626 || c + table->col_ofs >= table->nc
627 || r + table->row_ofs >= table->nr)
629 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
631 c, table->col_ofs, c + table->col_ofs,
632 r, table->row_ofs, r + table->row_ofs,
633 table->nc, table->nr);
638 data_out (buf, &f, (union value *) &val);
640 while (isspace ((unsigned char) *cp) && cp < &buf[w])
642 f.w = w - (cp - buf);
644 contents = pool_alloc (table->container, f.w);
645 ls_init (&table->cc[c + r * table->cf], contents, f.w);
646 table->ct[c + r * table->cf] = opt;
647 memcpy (contents, cp, f.w);
650 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
653 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
657 assert (table != NULL && text != NULL);
661 assert (c < table->nc);
662 assert (r < table->nr);
666 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
667 || c + table->col_ofs >= table->nc
668 || r + table->row_ofs >= table->nr)
670 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
672 c, table->col_ofs, c + table->col_ofs,
673 r, table->row_ofs, r + table->row_ofs,
674 table->nc, table->nr);
679 va_start (args, text);
680 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
681 table->ct[c + r * table->cf] = opt;
685 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
686 options OPT to have text value TEXT. */
688 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
689 unsigned opt, const char *text, ...)
691 struct tab_joined_cell *j;
693 assert (table != NULL && text != NULL);
699 assert (y2 < table->nr);
700 assert (x2 < table->nc);
703 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
704 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
705 || x2 < x1 || x2 + table->col_ofs >= table->nc
706 || y2 < y2 || y2 + table->row_ofs >= table->nr)
708 printf ("tab_joint_text(): bad cell "
709 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
710 x1, table->col_ofs, x1 + table->col_ofs,
711 y1, table->row_ofs, y1 + table->row_ofs,
712 x2, table->col_ofs, x2 + table->col_ofs,
713 y2, table->row_ofs, y2 + table->row_ofs,
714 table->nc, table->nr);
719 j = pool_alloc (table->container, sizeof *j);
721 j->x1 = x1 + table->col_ofs;
722 j->y1 = y1 + table->row_ofs;
723 j->x2 = ++x2 + table->col_ofs;
724 j->y2 = ++y2 + table->row_ofs;
729 va_start (args, text);
730 text_format (table, opt, text, args, &j->contents);
737 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
738 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
739 const int ofs = table->cf - (x2 - x1);
743 for (y = y1; y < y2; y++)
747 for (x = x1; x < x2; x++)
749 ls_init (cc++, (char *) j, 0);
759 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
761 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
762 struct len_string *string)
764 assert (table != NULL && string != NULL);
767 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
768 || c + table->col_ofs >= table->nc
769 || r + table->row_ofs >= table->nr)
771 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
773 c, table->col_ofs, c + table->col_ofs,
774 r, table->row_ofs, r + table->row_ofs,
775 table->nc, table->nr);
780 table->cc[c + r * table->cf] = *string;
781 table->ct[c + r * table->cf] = opt;
786 /* Sets the widths of all the columns and heights of all the rows in
787 table T for driver D. */
789 nowrap_dim (struct tab_table *t, struct outp_driver *d)
791 t->w[0] = tab_natural_width (t, d, 0);
792 t->h[0] = d->font_height;
795 /* Sets the widths of all the columns and heights of all the rows in
796 table T for driver D. */
798 wrap_dim (struct tab_table *t, struct outp_driver *d)
800 t->w[0] = tab_natural_width (t, d, 0);
801 t->h[0] = tab_natural_height (t, d, 0);
804 /* Outputs text BUF as a table with a single cell having cell options
805 OPTIONS, which is a combination of the TAB_* and TAT_*
808 tab_output_text (int options, const char *buf, ...)
810 struct tab_table *t = tab_create (1, 1, 0);
812 assert (buf != NULL);
813 if (options & TAT_PRINTF)
816 char *temp_buf = local_alloc (4096);
818 va_start (args, buf);
819 nvsprintf (temp_buf, buf, args);
824 if (options & TAT_FIX)
826 struct outp_driver *d;
828 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
831 d->class->open_page (d);
833 if (d->class->text_set_font_by_name != NULL)
834 d->class->text_set_font_by_name (d, "FIXED");
842 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
843 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
844 if (options & TAT_NOWRAP)
845 tab_dim (t, nowrap_dim);
847 tab_dim (t, wrap_dim);
850 if (options & TAT_FIX)
852 struct outp_driver *d;
854 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
855 if (d->class->text_set_font_by_name != NULL)
856 d->class->text_set_font_by_name (d, "PROP");
863 if (options & TAT_PRINTF)
867 /* Set table flags to FLAGS. */
869 tab_flags (struct tab_table *t, unsigned flags)
875 /* Easy, type-safe way to submit a tab table to som. */
877 tab_submit (struct tab_table *t)
882 s.class = &tab_table_class;
890 /* Set table row and column offsets for all functions that affect
893 tab_offset (struct tab_table *t, int col, int row)
899 if (row < -1 || row >= t->nr)
901 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
904 if (col < -1 || col >= t->nc)
906 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
912 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
914 diff += (col - t->col_ofs), t->col_ofs = col;
920 /* Increment the row offset by one. If the table is too small,
921 increase its size. */
923 tab_next_row (struct tab_table *t)
928 if (++t->row_ofs >= t->nr)
929 tab_realloc (t, -1, t->nr * 4 / 3);
932 static struct tab_table *t;
933 static struct outp_driver *d;
936 /* Set the current table to TABLE. */
938 tabi_table (struct som_table *table)
940 assert (table != NULL);
942 tab_offset (t, 0, 0);
944 assert (t->w == NULL && t->h == NULL);
945 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
946 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
949 /* Set the current output device to DRIVER. */
951 tabi_driver (struct outp_driver *driver)
955 assert (driver != NULL);
958 /* Figure out sizes of rules. */
959 for (t->hr_tot = i = 0; i <= t->nr; i++)
960 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
961 for (t->vr_tot = i = 0; i <= t->nc; i++)
962 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
965 for (i = 0; i < t->nr; i++)
967 for (i = 0; i < t->nc; i++)
971 assert (t->dim != NULL);
978 for (i = 0; i < t->nr; i++)
982 printf ("Table row %d height not initialized.\n", i);
985 assert (t->h[i] > 0);
988 for (i = 0; i < t->nc; i++)
992 printf ("Table column %d width not initialized.\n", i);
995 assert (t->w[i] > 0);
1000 /* Add up header sizes. */
1001 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
1002 t->wl += t->w[i] + t->wrv[i + 1];
1003 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1004 t->ht += t->h[i] + t->hrh[i + 1];
1005 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1006 t->wr += t->w[i] + t->wrv[i + 1];
1007 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1008 t->hb += t->h[i] + t->hrh[i + 1];
1011 if (!(t->flags & SOMF_NO_TITLE))
1012 t->ht += d->font_height;
1015 /* Return the number of columns and rows in the table into N_COLUMNS
1016 and N_ROWS, respectively. */
1018 tabi_count (int *n_columns, int *n_rows)
1020 assert (n_columns != NULL && n_rows != NULL);
1025 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1027 /* Return the horizontal and vertical size of the entire table,
1028 including headers, for the current output device, into HORIZ and
1031 tabi_area (int *horiz, int *vert)
1033 assert (horiz != NULL && vert != NULL);
1038 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1039 c < t->nc - t->r; c++)
1040 w += t->w[c] + t->wrv[c];
1046 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1047 r < t->nr - t->b; r++)
1048 h += t->h[r] + t->hrh[r];
1053 /* Return the column style for this table into STYLE. */
1055 tabi_columns (int *style)
1057 assert (style != NULL);
1058 *style = t->col_style;
1061 /* Return the number of header rows/columns on the left, right, top,
1062 and bottom sides into HL, HR, HT, and HB, respectively. */
1064 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1066 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1073 /* Determines the number of rows or columns (including appropriate
1074 headers), depending on CUMTYPE, that will fit into the space
1075 specified. Takes rows/columns starting at index START and attempts
1076 to fill up available space MAX. Returns in END the index of the
1077 last row/column plus one; returns in ACTUAL the actual amount of
1078 space the selected rows/columns (including appropriate headers)
1081 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1088 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1089 if (cumtype == SOM_ROWS)
1091 assert (start >= 0 && start < t->nr);
1094 r = &t->hrh[start + 1];
1095 total = t->ht + t->hb;
1097 assert (start >= 0 && start < t->nc);
1100 r = &t->wrv[start + 1];
1101 total = t->wl + t->wr;
1117 for (x = start + 1; x < n; x++)
1119 int amt = *d++ + *r++;
1137 /* Return flags set for the current table into FLAGS. */
1139 tabi_flags (unsigned *flags)
1141 assert (flags != NULL);
1145 /* Render title for current table, with major index X and minor index
1146 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1149 tabi_title (int x, int y)
1154 if (t->flags & SOMF_NO_TITLE)
1157 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1159 cp = spprintf (cp, "(%d:%d)", x, y);
1161 cp = spprintf (cp, "(%d)", x);
1163 cp = spprintf (cp, " %s", cur_proc);
1164 cp = stpcpy (cp, ". ");
1165 if (!ls_empty_p (&t->title))
1167 memcpy (cp, ls_value (&t->title), ls_length (&t->title));
1168 cp += ls_length (&t->title);
1173 struct outp_text text;
1175 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1176 ls_init (&text.s, buf, cp - buf);
1178 text.v = d->font_height;
1181 d->class->text_draw (d, &text);
1185 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1187 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1188 X2 and row Y2 are not included in the rectangle, at the current
1189 position on the current output device. Draws headers as well. */
1191 tabi_render (int x1, int y1, int x2, int y2)
1199 if (!(t->flags & SOMF_NO_TITLE))
1200 y += d->font_height;
1204 ranges[0][1] = t->t * 2 + 1;
1206 /* Requested rows. */
1207 ranges[1][0] = y1 * 2 + 1;
1208 ranges[1][1] = y2 * 2;
1210 /* Bottom headers. */
1211 ranges[2][0] = (t->nr - t->b) * 2;
1212 ranges[2][1] = t->nr * 2 + 1;
1214 for (i = 0; i < 3; i++)
1218 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1221 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1222 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1223 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1224 t->nc * 2 + 1, y1, y2);
1225 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1230 struct som_table_class tab_table_class =
1253 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1254 on row R, at location (X,Y). Return width of the strip thus
1257 Renders joined cells, even those outside the strip, within the
1258 rendering region (C1,R1)-(C2,R2).
1260 For the purposes of counting rows and columns in this function
1261 only, horizontal rules are considered rows and vertical rules are
1264 FIXME: Doesn't use r1? Huh? */
1266 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1270 /* Horizontal rules. */
1273 int hrh = t->hrh[r / 2];
1276 for (c = c1; c < c2; c++)
1280 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1284 const struct color clr = {0, 0, 0, 0};
1289 rct.x2 = x + t->w[c / 2];
1291 d->class->line_horz (d, &rct, &clr, style);
1295 const struct color clr = {0, 0, 0, 0};
1297 struct outp_styles s;
1301 rct.x2 = x + t->wrv[c / 2];
1304 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1305 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1306 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1307 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1309 if (s.t | s.b | s.l | s.r)
1310 d->class->line_intersection (d, &rct, &clr, &s);
1318 for (c = c1; c < c2; c++)
1322 const int index = (c / 2) + (r / 2 * t->cf);
1324 if (!(t->ct[index] & TAB_JOIN))
1326 struct outp_text text;
1328 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1329 | OUTP_T_HORZ | OUTP_T_VERT);
1330 if ((t->ct[index] & TAB_EMPTY) == 0)
1332 text.s = t->cc[index];
1333 assert (!ls_null_p (&text.s));
1334 text.h = t->w[c / 2];
1335 text.v = t->h[r / 2];
1338 d->class->text_draw (d, &text);
1341 struct tab_joined_cell *j =
1342 (struct tab_joined_cell *) ls_value (&t->cc[index]);
1344 if (j->hit != tab_hit)
1348 if (j->x1 == c / 2 && j->y1 == r / 2)
1350 struct outp_text text;
1352 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1353 | OUTP_T_HORZ | OUTP_T_VERT);
1354 text.s = j->contents;
1361 for (c = j->x1, text.h = -t->wrv[j->x2];
1362 c < j->x2 && c < c2 / 2; c++)
1363 text.h += t->w[c] + t->wrv[c + 1];
1369 for (r = j->y1, text.v = -t->hrh[j->y2];
1370 r < j->y2 && r < r2 / 2; r++)
1371 text.v += t->h[r] + t->hrh[r + 1];
1373 d->class->text_draw (d, &text);
1379 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1383 const struct color clr = {0, 0, 0, 0};
1388 rct.x2 = x + t->wrv[c / 2];
1389 rct.y2 = y + t->h[r / 2];
1390 d->class->line_vert (d, &rct, &clr, style);
1397 return x - x_origin;