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 (table->container, s, text, len);
438 if (opt & TAT_PRINTF)
442 /* Set the title of table T to TITLE, which is formatted with printf
443 if FORMAT is nonzero. */
445 tab_title (struct tab_table *t, int format, const char *title, ...)
449 assert (t != NULL && title != NULL);
450 va_start (args, title);
451 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
455 /* Set DIM_FUNC as the dimension function for table T. */
457 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
459 assert (t != NULL && t->dim == NULL);
463 /* Returns the natural width of column C in table T for driver D, that
464 is, the smallest width necessary to display all its cells without
465 wrapping. The width will be no larger than the page width minus
466 left and right rule widths. */
468 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
472 assert (t != NULL && c >= 0 && c < t->nc);
476 for (width = r = 0; r < t->nr; r++)
478 struct outp_text text;
479 unsigned char opt = t->ct[c + r * t->cf];
481 if (opt & (TAB_JOIN | TAB_EMPTY))
484 text.s = t->cc[c + r * t->cf];
485 assert (!ls_null_p (&text.s));
486 text.options = OUTP_T_JUST_LEFT;
488 d->class->text_metrics (d, &text);
496 width = d->prop_em_width * 8;
498 printf ("warning: table column %d contains no data.\n", c);
503 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
512 /* Returns the natural height of row R in table T for driver D, that
513 is, the minimum height necessary to display the information in the
514 cell at the widths set for each column. */
516 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
520 assert (t != NULL && r >= 0 && r < t->nr);
525 for (height = d->font_height, c = 0; c < t->nc; c++)
527 struct outp_text text;
528 unsigned char opt = t->ct[c + r * t->cf];
530 assert (t->w[c] != NOT_INT);
531 if (opt & (TAB_JOIN | TAB_EMPTY))
534 text.s = t->cc[c + r * t->cf];
535 assert (!ls_null_p (&text.s));
536 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
538 d->class->text_metrics (d, &text);
548 /* Callback function to set all columns and rows to their natural
549 dimensions. Not really meant to be called directly. */
551 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
557 for (i = 0; i < t->nc; i++)
558 t->w[i] = tab_natural_width (t, d, i);
560 for (i = 0; i < t->nr; i++)
561 t->h[i] = tab_natural_height (t, d, i);
567 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
568 from V, displayed with format spec F. */
570 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
571 const union value *v, const struct fmt_spec *f)
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 data_out (contents, f, v);
597 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
598 with NDEC decimal places. */
600 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
601 double val, int w, int d)
607 union value double_value;
609 assert (table != NULL && w <= 40);
612 assert (c < table->nc);
614 assert (r < table->nr);
621 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
622 || c + table->col_ofs >= table->nc
623 || r + table->row_ofs >= table->nr)
625 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
627 c, table->col_ofs, c + table->col_ofs,
628 r, table->row_ofs, r + table->row_ofs,
629 table->nc, table->nr);
634 double_value.f = val;
635 data_out (buf, &f, &double_value);
638 while (isspace ((unsigned char) *cp) && cp < &buf[w])
640 f.w = w - (cp - buf);
642 contents = pool_alloc (table->container, f.w);
643 ls_init (&table->cc[c + r * table->cf], contents, f.w);
644 table->ct[c + r * table->cf] = opt;
645 memcpy (contents, cp, f.w);
648 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
651 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
655 assert (table != NULL && text != NULL);
659 assert (c < table->nc);
660 assert (r < table->nr);
664 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
665 || c + table->col_ofs >= table->nc
666 || r + table->row_ofs >= table->nr)
668 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
670 c, table->col_ofs, c + table->col_ofs,
671 r, table->row_ofs, r + table->row_ofs,
672 table->nc, table->nr);
677 va_start (args, text);
678 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
679 table->ct[c + r * table->cf] = opt;
683 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
684 options OPT to have text value TEXT. */
686 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
687 unsigned opt, const char *text, ...)
689 struct tab_joined_cell *j;
691 assert (table != NULL && text != NULL);
693 assert (x1 + table->col_ofs >= 0);
694 assert (y1 + table->row_ofs >= 0);
697 assert (y2 + table->row_ofs < table->nr);
698 assert (x2 + table->col_ofs < table->nc);
701 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
702 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
703 || x2 < x1 || x2 + table->col_ofs >= table->nc
704 || y2 < y2 || y2 + table->row_ofs >= table->nr)
706 printf ("tab_joint_text(): bad cell "
707 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
708 x1, table->col_ofs, x1 + table->col_ofs,
709 y1, table->row_ofs, y1 + table->row_ofs,
710 x2, table->col_ofs, x2 + table->col_ofs,
711 y2, table->row_ofs, y2 + table->row_ofs,
712 table->nc, table->nr);
717 j = pool_alloc (table->container, sizeof *j);
719 j->x1 = x1 + table->col_ofs;
720 j->y1 = y1 + table->row_ofs;
721 j->x2 = ++x2 + table->col_ofs;
722 j->y2 = ++y2 + table->row_ofs;
727 va_start (args, text);
728 text_format (table, opt, text, args, &j->contents);
735 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
736 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
737 const int ofs = table->cf - (x2 - x1);
741 for (y = y1; y < y2; y++)
745 for (x = x1; x < x2; x++)
747 ls_init (cc++, (char *) j, 0);
757 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
759 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
760 struct len_string *string)
762 assert (table != NULL && string != NULL);
765 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
766 || c + table->col_ofs >= table->nc
767 || r + table->row_ofs >= table->nr)
769 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
771 c, table->col_ofs, c + table->col_ofs,
772 r, table->row_ofs, r + table->row_ofs,
773 table->nc, table->nr);
778 table->cc[c + r * table->cf] = *string;
779 table->ct[c + r * table->cf] = opt;
784 /* Sets the widths of all the columns and heights of all the rows in
785 table T for driver D. */
787 nowrap_dim (struct tab_table *t, struct outp_driver *d)
789 t->w[0] = tab_natural_width (t, d, 0);
790 t->h[0] = d->font_height;
793 /* Sets the widths of all the columns and heights of all the rows in
794 table T for driver D. */
796 wrap_dim (struct tab_table *t, struct outp_driver *d)
798 t->w[0] = tab_natural_width (t, d, 0);
799 t->h[0] = tab_natural_height (t, d, 0);
802 /* Outputs text BUF as a table with a single cell having cell options
803 OPTIONS, which is a combination of the TAB_* and TAT_*
806 tab_output_text (int options, const char *buf, ...)
808 struct tab_table *t = tab_create (1, 1, 0);
810 assert (buf != NULL);
811 if (options & TAT_PRINTF)
814 char *temp_buf = local_alloc (4096);
816 va_start (args, buf);
817 nvsprintf (temp_buf, buf, args);
822 if (options & TAT_FIX)
824 struct outp_driver *d;
826 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
829 d->class->open_page (d);
831 if (d->class->text_set_font_by_name != NULL)
832 d->class->text_set_font_by_name (d, "FIXED");
840 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
841 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
842 if (options & TAT_NOWRAP)
843 tab_dim (t, nowrap_dim);
845 tab_dim (t, wrap_dim);
848 if (options & TAT_FIX)
850 struct outp_driver *d;
852 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
853 if (d->class->text_set_font_by_name != NULL)
854 d->class->text_set_font_by_name (d, "PROP");
861 if (options & TAT_PRINTF)
865 /* Set table flags to FLAGS. */
867 tab_flags (struct tab_table *t, unsigned flags)
873 /* Easy, type-safe way to submit a tab table to som. */
875 tab_submit (struct tab_table *t)
880 s.class = &tab_table_class;
888 /* Set table row and column offsets for all functions that affect
891 tab_offset (struct tab_table *t, int col, int row)
897 if (row < -1 || row >= t->nr)
899 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
902 if (col < -1 || col >= t->nc)
904 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
910 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
912 diff += (col - t->col_ofs), t->col_ofs = col;
918 /* Increment the row offset by one. If the table is too small,
919 increase its size. */
921 tab_next_row (struct tab_table *t)
926 if (++t->row_ofs >= t->nr)
927 tab_realloc (t, -1, t->nr * 4 / 3);
930 static struct tab_table *t;
931 static struct outp_driver *d;
934 /* Set the current table to TABLE. */
936 tabi_table (struct som_table *table)
938 assert (table != NULL);
940 tab_offset (t, 0, 0);
942 assert (t->w == NULL && t->h == NULL);
943 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
944 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
947 /* Set the current output device to DRIVER. */
949 tabi_driver (struct outp_driver *driver)
953 assert (driver != NULL);
956 /* Figure out sizes of rules. */
957 for (t->hr_tot = i = 0; i <= t->nr; i++)
958 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
959 for (t->vr_tot = i = 0; i <= t->nc; i++)
960 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
963 for (i = 0; i < t->nr; i++)
965 for (i = 0; i < t->nc; i++)
969 assert (t->dim != NULL);
976 for (i = 0; i < t->nr; i++)
980 printf ("Table row %d height not initialized.\n", i);
983 assert (t->h[i] > 0);
986 for (i = 0; i < t->nc; i++)
990 printf ("Table column %d width not initialized.\n", i);
993 assert (t->w[i] > 0);
998 /* Add up header sizes. */
999 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
1000 t->wl += t->w[i] + t->wrv[i + 1];
1001 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1002 t->ht += t->h[i] + t->hrh[i + 1];
1003 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1004 t->wr += t->w[i] + t->wrv[i + 1];
1005 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1006 t->hb += t->h[i] + t->hrh[i + 1];
1009 if (!(t->flags & SOMF_NO_TITLE))
1010 t->ht += d->font_height;
1013 /* Return the number of columns and rows in the table into N_COLUMNS
1014 and N_ROWS, respectively. */
1016 tabi_count (int *n_columns, int *n_rows)
1018 assert (n_columns != NULL && n_rows != NULL);
1023 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1025 /* Return the horizontal and vertical size of the entire table,
1026 including headers, for the current output device, into HORIZ and
1029 tabi_area (int *horiz, int *vert)
1031 assert (horiz != NULL && vert != NULL);
1036 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1037 c < t->nc - t->r; c++)
1038 w += t->w[c] + t->wrv[c];
1044 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1045 r < t->nr - t->b; r++)
1046 h += t->h[r] + t->hrh[r];
1051 /* Return the column style for this table into STYLE. */
1053 tabi_columns (int *style)
1055 assert (style != NULL);
1056 *style = t->col_style;
1059 /* Return the number of header rows/columns on the left, right, top,
1060 and bottom sides into HL, HR, HT, and HB, respectively. */
1062 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1064 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1071 /* Determines the number of rows or columns (including appropriate
1072 headers), depending on CUMTYPE, that will fit into the space
1073 specified. Takes rows/columns starting at index START and attempts
1074 to fill up available space MAX. Returns in END the index of the
1075 last row/column plus one; returns in ACTUAL the actual amount of
1076 space the selected rows/columns (including appropriate headers)
1079 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1086 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1087 if (cumtype == SOM_ROWS)
1089 assert (start >= 0 && start < t->nr);
1092 r = &t->hrh[start + 1];
1093 total = t->ht + t->hb;
1095 assert (start >= 0 && start < t->nc);
1098 r = &t->wrv[start + 1];
1099 total = t->wl + t->wr;
1115 for (x = start + 1; x < n; x++)
1117 int amt = *d++ + *r++;
1135 /* Return flags set for the current table into FLAGS. */
1137 tabi_flags (unsigned *flags)
1139 assert (flags != NULL);
1143 /* Render title for current table, with major index X and minor index
1144 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1147 tabi_title (int x, int y)
1152 if (t->flags & SOMF_NO_TITLE)
1155 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1157 cp = spprintf (cp, "(%d:%d)", x, y);
1159 cp = spprintf (cp, "(%d)", x);
1161 cp = spprintf (cp, " %s", cur_proc);
1162 cp = stpcpy (cp, ". ");
1163 if (!ls_empty_p (&t->title))
1165 memcpy (cp, ls_value (&t->title), ls_length (&t->title));
1166 cp += ls_length (&t->title);
1171 struct outp_text text;
1173 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1174 ls_init (&text.s, buf, cp - buf);
1176 text.v = d->font_height;
1179 d->class->text_draw (d, &text);
1183 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1185 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1186 X2 and row Y2 are not included in the rectangle, at the current
1187 position on the current output device. Draws headers as well. */
1189 tabi_render (int x1, int y1, int x2, int y2)
1197 if (!(t->flags & SOMF_NO_TITLE))
1198 y += d->font_height;
1202 ranges[0][1] = t->t * 2 + 1;
1204 /* Requested rows. */
1205 ranges[1][0] = y1 * 2 + 1;
1206 ranges[1][1] = y2 * 2;
1208 /* Bottom headers. */
1209 ranges[2][0] = (t->nr - t->b) * 2;
1210 ranges[2][1] = t->nr * 2 + 1;
1212 for (i = 0; i < 3; i++)
1216 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1219 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1220 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1221 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1222 t->nc * 2 + 1, y1, y2);
1223 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1228 struct som_table_class tab_table_class =
1251 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1252 on row R, at location (X,Y). Return width of the strip thus
1255 Renders joined cells, even those outside the strip, within the
1256 rendering region (C1,R1)-(C2,R2).
1258 For the purposes of counting rows and columns in this function
1259 only, horizontal rules are considered rows and vertical rules are
1262 FIXME: Doesn't use r1? Huh? */
1264 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1268 /* Horizontal rules. */
1271 int hrh = t->hrh[r / 2];
1274 for (c = c1; c < c2; c++)
1278 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1282 const struct color clr = {0, 0, 0, 0};
1287 rct.x2 = x + t->w[c / 2];
1289 d->class->line_horz (d, &rct, &clr, style);
1293 const struct color clr = {0, 0, 0, 0};
1295 struct outp_styles s;
1299 rct.x2 = x + t->wrv[c / 2];
1302 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1303 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1304 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1305 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1307 if (s.t | s.b | s.l | s.r)
1308 d->class->line_intersection (d, &rct, &clr, &s);
1316 for (c = c1; c < c2; c++)
1320 const int index = (c / 2) + (r / 2 * t->cf);
1322 if (!(t->ct[index] & TAB_JOIN))
1324 struct outp_text text;
1326 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1327 | OUTP_T_HORZ | OUTP_T_VERT);
1328 if ((t->ct[index] & TAB_EMPTY) == 0)
1330 text.s = t->cc[index];
1331 assert (!ls_null_p (&text.s));
1332 text.h = t->w[c / 2];
1333 text.v = t->h[r / 2];
1336 d->class->text_draw (d, &text);
1339 struct tab_joined_cell *j =
1340 (struct tab_joined_cell *) ls_value (&t->cc[index]);
1342 if (j->hit != tab_hit)
1346 if (j->x1 == c / 2 && j->y1 == r / 2)
1348 struct outp_text text;
1350 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1351 | OUTP_T_HORZ | OUTP_T_VERT);
1352 text.s = j->contents;
1359 for (c = j->x1, text.h = -t->wrv[j->x2];
1360 c < j->x2 && c < c2 / 2; c++)
1361 text.h += t->w[c] + t->wrv[c + 1];
1367 for (r = j->y1, text.v = -t->hrh[j->y2];
1368 r < j->y2 && r < r2 / 2; r++)
1369 text.v += t->h[r] + t->hrh[r + 1];
1371 d->class->text_draw (d, &text);
1377 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1381 const struct color clr = {0, 0, 0, 0};
1386 rct.x2 = x + t->wrv[c / 2];
1387 rct.y2 = y + t->h[r / 2];
1388 d->class->line_vert (d, &rct, &clr, style);
1395 return x - x_origin;