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)
257 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
258 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
259 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
261 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
262 "table size (%d,%d)\n"),
263 x, t->col_ofs, x + t->col_ofs,
264 y1, t->row_ofs, y1 + t->row_ofs,
265 y2, t->row_ofs, y2 + t->row_ofs,
279 assert (y2 <= t->nr);
283 if ((style & TAL_SPACING) == 0)
284 for (y = y1; y <= y2; y++)
285 t->rv[x + (t->cf + 1) * y] = style;
286 t->trv[x] |= (1 << (style & ~TAL_SPACING));
290 /* Draws a horizontal line above cells at vertical position Y from X1
291 to X2 inclusive in style STYLE, if style is not -1. */
293 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
311 if ((style & TAL_SPACING) == 0)
312 for (x = x1; x <= x2; x++)
313 t->rh[x + t->cf * y] = style;
314 t->trh[y] |= (1 << (style & ~TAL_SPACING));
318 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
319 lines of style F_H and vertical lines of style F_V. Fills the
320 interior of the box with horizontal lines of style I_H and vertical
321 lines of style I_V. Any of the line styles may be -1 to avoid
322 drawing those lines. This is distinct from 0, which draws a null
325 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
326 int x1, int y1, int x2, int y2)
331 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
332 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
333 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
334 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
336 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
337 "in table size (%d,%d)\n"),
338 x1, t->col_ofs, x1 + t->col_ofs,
339 y1, t->row_ofs, y1 + t->row_ofs,
340 x2, t->col_ofs, x2 + t->col_ofs,
341 y2, t->row_ofs, y2 + t->row_ofs,
362 if ((f_h & TAL_SPACING) == 0)
363 for (x = x1; x <= x2; x++)
365 t->rh[x + t->cf * y1] = f_h;
366 t->rh[x + t->cf * (y2 + 1)] = f_h;
368 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
369 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
374 if ((f_v & TAL_SPACING) == 0)
375 for (y = y1; y <= y2; y++)
377 t->rv[x1 + (t->cf + 1) * y] = f_v;
378 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
380 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
381 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
388 for (y = y1 + 1; y <= y2; y++)
392 if ((i_h & TAL_SPACING) == 0)
393 for (x = x1; x <= x2; x++)
394 t->rh[x + t->cf * y] = i_h;
396 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
403 for (x = x1 + 1; x <= x2; x++)
407 if ((i_v & TAL_SPACING) == 0)
408 for (y = y1; y <= y2; y++)
409 t->rv[x + (t->cf + 1) * y] = i_v;
411 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
416 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
417 the resultant string into S in TABLE's pool. */
419 text_format (struct tab_table *table, int opt, const char *text, va_list args,
420 struct len_string *s)
424 assert (table != NULL && text != NULL && s != NULL);
426 if (opt & TAT_PRINTF)
428 char *temp_buf = local_alloc (1024);
430 len = nvsprintf (temp_buf, text, args);
436 ls_create_buffer (s, text, len);
437 pool_register (table->container, free, s->string);
439 if (opt & TAT_PRINTF)
443 /* Set the title of table T to TITLE, which is formatted with printf
444 if FORMAT is nonzero. */
446 tab_title (struct tab_table *t, int format, const char *title, ...)
450 assert (t != NULL && title != NULL);
451 va_start (args, title);
452 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
456 /* Set DIM_FUNC as the dimension function for table T. */
458 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
460 assert (t != NULL && t->dim == NULL);
464 /* Returns the natural width of column C in table T for driver D, that
465 is, the smallest width necessary to display all its cells without
466 wrapping. The width will be no larger than the page width minus
467 left and right rule widths. */
469 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
473 assert (t != NULL && c >= 0 && c < t->nc);
477 for (width = r = 0; r < t->nr; r++)
479 struct outp_text text;
480 unsigned char opt = t->ct[c + r * t->cf];
482 if (opt & (TAB_JOIN | TAB_EMPTY))
485 text.s = t->cc[c + r * t->cf];
486 assert (!ls_null_p (&text.s));
487 text.options = OUTP_T_JUST_LEFT;
489 d->class->text_metrics (d, &text);
497 width = d->prop_em_width * 8;
499 printf ("warning: table column %d contains no data.\n", c);
504 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
513 /* Returns the natural height of row R in table T for driver D, that
514 is, the minimum height necessary to display the information in the
515 cell at the widths set for each column. */
517 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
521 assert (t != NULL && r >= 0 && r < t->nr);
526 for (height = d->font_height, c = 0; c < t->nc; c++)
528 struct outp_text text;
529 unsigned char opt = t->ct[c + r * t->cf];
531 assert (t->w[c] != NOT_INT);
532 if (opt & (TAB_JOIN | TAB_EMPTY))
535 text.s = t->cc[c + r * t->cf];
536 assert (!ls_null_p (&text.s));
537 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
539 d->class->text_metrics (d, &text);
549 /* Callback function to set all columns and rows to their natural
550 dimensions. Not really meant to be called directly. */
552 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
558 for (i = 0; i < t->nc; i++)
559 t->w[i] = tab_natural_width (t, d, i);
561 for (i = 0; i < t->nr; i++)
562 t->h[i] = tab_natural_height (t, d, i);
568 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
569 from V, displayed with format spec F. */
571 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
572 const union value *v, const struct fmt_spec *f)
576 assert (table != NULL && v != NULL && f != NULL);
578 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
579 || c + table->col_ofs >= table->nc
580 || r + table->row_ofs >= table->nr)
582 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
584 c, table->col_ofs, c + table->col_ofs,
585 r, table->row_ofs, r + table->row_ofs,
586 table->nc, table->nr);
591 contents = pool_alloc (table->container, f->w);
592 ls_init (&table->cc[c + r * table->cf], contents, f->w);
593 table->ct[c + r * table->cf] = opt;
595 data_out (contents, f, v);
598 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
599 with NDEC decimal places. */
601 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
602 double val, int w, int d)
608 union value double_value;
610 assert (table != NULL && w <= 40);
613 assert (c < table->nc);
615 assert (r < table->nr);
622 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
623 || c + table->col_ofs >= table->nc
624 || r + table->row_ofs >= table->nr)
626 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
628 c, table->col_ofs, c + table->col_ofs,
629 r, table->row_ofs, r + table->row_ofs,
630 table->nc, table->nr);
635 double_value.f = val;
636 data_out (buf, &f, &double_value);
639 while (isspace ((unsigned char) *cp) && cp < &buf[w])
641 f.w = w - (cp - buf);
643 contents = pool_alloc (table->container, f.w);
644 ls_init (&table->cc[c + r * table->cf], contents, f.w);
645 table->ct[c + r * table->cf] = opt;
646 memcpy (contents, cp, f.w);
649 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
652 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
656 assert (table != NULL && text != NULL);
660 assert (c < table->nc);
661 assert (r < table->nr);
665 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
666 || c + table->col_ofs >= table->nc
667 || r + table->row_ofs >= table->nr)
669 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
671 c, table->col_ofs, c + table->col_ofs,
672 r, table->row_ofs, r + table->row_ofs,
673 table->nc, table->nr);
678 va_start (args, text);
679 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
680 table->ct[c + r * table->cf] = opt;
684 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
685 options OPT to have text value TEXT. */
687 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
688 unsigned opt, const char *text, ...)
690 struct tab_joined_cell *j;
692 assert (table != NULL && text != NULL);
694 assert (x1 + table->col_ofs >= 0);
695 assert (y1 + table->row_ofs >= 0);
698 assert (y2 + table->row_ofs < table->nr);
699 assert (x2 + table->col_ofs < table->nc);
702 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
703 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
704 || x2 < x1 || x2 + table->col_ofs >= table->nc
705 || y2 < y2 || y2 + table->row_ofs >= table->nr)
707 printf ("tab_joint_text(): bad cell "
708 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
709 x1, table->col_ofs, x1 + table->col_ofs,
710 y1, table->row_ofs, y1 + table->row_ofs,
711 x2, table->col_ofs, x2 + table->col_ofs,
712 y2, table->row_ofs, y2 + table->row_ofs,
713 table->nc, table->nr);
718 j = pool_alloc (table->container, sizeof *j);
720 j->x1 = x1 + table->col_ofs;
721 j->y1 = y1 + table->row_ofs;
722 j->x2 = ++x2 + table->col_ofs;
723 j->y2 = ++y2 + table->row_ofs;
728 va_start (args, text);
729 text_format (table, opt, text, args, &j->contents);
736 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
737 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
738 const int ofs = table->cf - (x2 - x1);
742 for (y = y1; y < y2; y++)
746 for (x = x1; x < x2; x++)
748 ls_init (cc++, (char *) j, 0);
758 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
760 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
761 struct len_string *string)
763 assert (table != NULL && string != NULL);
766 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
767 || c + table->col_ofs >= table->nc
768 || r + table->row_ofs >= table->nr)
770 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
772 c, table->col_ofs, c + table->col_ofs,
773 r, table->row_ofs, r + table->row_ofs,
774 table->nc, table->nr);
779 table->cc[c + r * table->cf] = *string;
780 table->ct[c + r * table->cf] = opt;
785 /* Sets the widths of all the columns and heights of all the rows in
786 table T for driver D. */
788 nowrap_dim (struct tab_table *t, struct outp_driver *d)
790 t->w[0] = tab_natural_width (t, d, 0);
791 t->h[0] = d->font_height;
794 /* Sets the widths of all the columns and heights of all the rows in
795 table T for driver D. */
797 wrap_dim (struct tab_table *t, struct outp_driver *d)
799 t->w[0] = tab_natural_width (t, d, 0);
800 t->h[0] = tab_natural_height (t, d, 0);
803 /* Outputs text BUF as a table with a single cell having cell options
804 OPTIONS, which is a combination of the TAB_* and TAT_*
807 tab_output_text (int options, const char *buf, ...)
809 struct tab_table *t = tab_create (1, 1, 0);
811 assert (buf != NULL);
812 if (options & TAT_PRINTF)
815 char *temp_buf = local_alloc (4096);
817 va_start (args, buf);
818 nvsprintf (temp_buf, buf, args);
823 if (options & TAT_FIX)
825 struct outp_driver *d;
827 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
830 d->class->open_page (d);
832 if (d->class->text_set_font_by_name != NULL)
833 d->class->text_set_font_by_name (d, "FIXED");
841 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
842 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
843 if (options & TAT_NOWRAP)
844 tab_dim (t, nowrap_dim);
846 tab_dim (t, wrap_dim);
849 if (options & TAT_FIX)
851 struct outp_driver *d;
853 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
854 if (d->class->text_set_font_by_name != NULL)
855 d->class->text_set_font_by_name (d, "PROP");
862 if (options & TAT_PRINTF)
866 /* Set table flags to FLAGS. */
868 tab_flags (struct tab_table *t, unsigned flags)
874 /* Easy, type-safe way to submit a tab table to som. */
876 tab_submit (struct tab_table *t)
881 s.class = &tab_table_class;
889 /* Set table row and column offsets for all functions that affect
892 tab_offset (struct tab_table *t, int col, int row)
898 if (row < -1 || row >= t->nr)
900 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
903 if (col < -1 || col >= t->nc)
905 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
911 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
913 diff += (col - t->col_ofs), t->col_ofs = col;
919 /* Increment the row offset by one. If the table is too small,
920 increase its size. */
922 tab_next_row (struct tab_table *t)
927 if (++t->row_ofs >= t->nr)
928 tab_realloc (t, -1, t->nr * 4 / 3);
931 static struct tab_table *t;
932 static struct outp_driver *d;
935 /* Set the current table to TABLE. */
937 tabi_table (struct som_table *table)
939 assert (table != NULL);
941 tab_offset (t, 0, 0);
943 assert (t->w == NULL && t->h == NULL);
944 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
945 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
948 /* Set the current output device to DRIVER. */
950 tabi_driver (struct outp_driver *driver)
954 assert (driver != NULL);
957 /* Figure out sizes of rules. */
958 for (t->hr_tot = i = 0; i <= t->nr; i++)
959 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
960 for (t->vr_tot = i = 0; i <= t->nc; i++)
961 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
964 for (i = 0; i < t->nr; i++)
966 for (i = 0; i < t->nc; i++)
970 assert (t->dim != NULL);
977 for (i = 0; i < t->nr; i++)
981 printf ("Table row %d height not initialized.\n", i);
984 assert (t->h[i] > 0);
987 for (i = 0; i < t->nc; i++)
991 printf ("Table column %d width not initialized.\n", i);
994 assert (t->w[i] > 0);
999 /* Add up header sizes. */
1000 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
1001 t->wl += t->w[i] + t->wrv[i + 1];
1002 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1003 t->ht += t->h[i] + t->hrh[i + 1];
1004 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1005 t->wr += t->w[i] + t->wrv[i + 1];
1006 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1007 t->hb += t->h[i] + t->hrh[i + 1];
1010 if (!(t->flags & SOMF_NO_TITLE))
1011 t->ht += d->font_height;
1014 /* Return the number of columns and rows in the table into N_COLUMNS
1015 and N_ROWS, respectively. */
1017 tabi_count (int *n_columns, int *n_rows)
1019 assert (n_columns != NULL && n_rows != NULL);
1024 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1026 /* Return the horizontal and vertical size of the entire table,
1027 including headers, for the current output device, into HORIZ and
1030 tabi_area (int *horiz, int *vert)
1032 assert (horiz != NULL && vert != NULL);
1037 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1038 c < t->nc - t->r; c++)
1039 w += t->w[c] + t->wrv[c];
1045 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1046 r < t->nr - t->b; r++)
1047 h += t->h[r] + t->hrh[r];
1052 /* Return the column style for this table into STYLE. */
1054 tabi_columns (int *style)
1056 assert (style != NULL);
1057 *style = t->col_style;
1060 /* Return the number of header rows/columns on the left, right, top,
1061 and bottom sides into HL, HR, HT, and HB, respectively. */
1063 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1065 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1072 /* Determines the number of rows or columns (including appropriate
1073 headers), depending on CUMTYPE, that will fit into the space
1074 specified. Takes rows/columns starting at index START and attempts
1075 to fill up available space MAX. Returns in END the index of the
1076 last row/column plus one; returns in ACTUAL the actual amount of
1077 space the selected rows/columns (including appropriate headers)
1080 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1087 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1088 if (cumtype == SOM_ROWS)
1090 assert (start >= 0 && start < t->nr);
1093 r = &t->hrh[start + 1];
1094 total = t->ht + t->hb;
1096 assert (start >= 0 && start < t->nc);
1099 r = &t->wrv[start + 1];
1100 total = t->wl + t->wr;
1116 for (x = start + 1; x < n; x++)
1118 int amt = *d++ + *r++;
1136 /* Return flags set for the current table into FLAGS. */
1138 tabi_flags (unsigned *flags)
1140 assert (flags != NULL);
1144 /* Render title for current table, with major index X and minor index
1145 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1148 tabi_title (int x, int y)
1153 if (t->flags & SOMF_NO_TITLE)
1156 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1158 cp = spprintf (cp, "(%d:%d)", x, y);
1160 cp = spprintf (cp, "(%d)", x);
1162 cp = spprintf (cp, " %s", cur_proc);
1163 cp = stpcpy (cp, ". ");
1164 if (!ls_empty_p (&t->title))
1166 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1167 cp += ls_length (&t->title);
1172 struct outp_text text;
1174 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1175 ls_init (&text.s, buf, cp - buf);
1177 text.v = d->font_height;
1180 d->class->text_draw (d, &text);
1184 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1186 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1187 X2 and row Y2 are not included in the rectangle, at the current
1188 position on the current output device. Draws headers as well. */
1190 tabi_render (int x1, int y1, int x2, int y2)
1198 if (!(t->flags & SOMF_NO_TITLE))
1199 y += d->font_height;
1203 ranges[0][1] = t->t * 2 + 1;
1205 /* Requested rows. */
1206 ranges[1][0] = y1 * 2 + 1;
1207 ranges[1][1] = y2 * 2;
1209 /* Bottom headers. */
1210 ranges[2][0] = (t->nr - t->b) * 2;
1211 ranges[2][1] = t->nr * 2 + 1;
1213 for (i = 0; i < 3; i++)
1217 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1220 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1221 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1222 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1223 t->nc * 2 + 1, y1, y2);
1224 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1229 struct som_table_class tab_table_class =
1252 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1253 on row R, at location (X,Y). Return width of the strip thus
1256 Renders joined cells, even those outside the strip, within the
1257 rendering region (C1,R1)-(C2,R2).
1259 For the purposes of counting rows and columns in this function
1260 only, horizontal rules are considered rows and vertical rules are
1263 FIXME: Doesn't use r1? Huh? */
1265 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1269 /* Horizontal rules. */
1272 int hrh = t->hrh[r / 2];
1275 for (c = c1; c < c2; c++)
1279 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1283 const struct color clr = {0, 0, 0, 0};
1288 rct.x2 = x + t->w[c / 2];
1290 d->class->line_horz (d, &rct, &clr, style);
1294 const struct color clr = {0, 0, 0, 0};
1296 struct outp_styles s;
1300 rct.x2 = x + t->wrv[c / 2];
1303 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1304 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1305 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1306 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1308 if (s.t | s.b | s.l | s.r)
1309 d->class->line_intersection (d, &rct, &clr, &s);
1317 for (c = c1; c < c2; c++)
1321 const int index = (c / 2) + (r / 2 * t->cf);
1323 if (!(t->ct[index] & TAB_JOIN))
1325 struct outp_text text;
1327 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1328 | OUTP_T_HORZ | OUTP_T_VERT);
1329 if ((t->ct[index] & TAB_EMPTY) == 0)
1331 text.s = t->cc[index];
1332 assert (!ls_null_p (&text.s));
1333 text.h = t->w[c / 2];
1334 text.v = t->h[r / 2];
1337 d->class->text_draw (d, &text);
1340 struct tab_joined_cell *j =
1341 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1343 if (j->hit != tab_hit)
1347 if (j->x1 == c / 2 && j->y1 == r / 2)
1349 struct outp_text text;
1351 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1352 | OUTP_T_HORZ | OUTP_T_VERT);
1353 text.s = j->contents;
1360 for (c = j->x1, text.h = -t->wrv[j->x2];
1361 c < j->x2 && c < c2 / 2; c++)
1362 text.h += t->w[c] + t->wrv[c + 1];
1368 for (r = j->y1, text.v = -t->hrh[j->y2];
1369 r < j->y2 && r < r2 / 2; r++)
1370 text.v += t->h[r] + t->hrh[r + 1];
1372 d->class->text_draw (d, &text);
1378 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1382 const struct color clr = {0, 0, 0, 0};
1387 rct.x2 = x + t->wrv[c / 2];
1388 rct.y2 = y + t->h[r / 2];
1389 d->class->line_vert (d, &rct, &clr, style);
1396 return x - x_origin;