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., 51 Franklin Street, Fifth Floor, Boston, MA
38 #define _(msgid) gettext (msgid)
40 #include "debug-print.h"
42 struct som_table_class tab_table_class;
44 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
45 nonzero then the table's size can be increased later; otherwise,
46 its size can only be reduced. */
48 tab_create (int nc, int nr, int reallocable)
50 void *(*alloc_func) (struct pool *, size_t);
55 struct pool *container = pool_create ();
56 t = pool_alloc (container, sizeof *t);
57 t->container = container;
60 t->col_style = TAB_COL_NONE;
66 t->l = t->r = t->t = t->b = 0;
68 alloc_func = reallocable ? pool_malloc : pool_alloc;
70 t->reallocable = reallocable;
73 t->cc = alloc_func (t->container, nr * nc * sizeof *t->cc);
74 t->ct = alloc_func (t->container, nr * nc);
75 memset (t->ct, TAB_EMPTY, nc * nr);
77 t->rh = alloc_func (t->container, nc * (nr + 1));
78 memset (t->rh, 0, nc * (nr + 1));
80 t->hrh = alloc_func (t->container, sizeof *t->hrh * (nr + 1));
81 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
83 t->trh = alloc_func (t->container, nr + 1);
84 memset (t->trh, 0, nr + 1);
86 t->rv = alloc_func (t->container, (nc + 1) * nr);
87 memset (t->rv, 0, (nc + 1) * nr);
89 t->wrv = alloc_func (t->container, sizeof *t->wrv * (nc + 1));
90 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
92 t->trv = alloc_func (t->container, nc + 1);
93 memset (t->trv, 0, nc + 1);
97 t->col_ofs = t->row_ofs = 0;
102 /* Destroys table T. */
104 tab_destroy (struct tab_table *t)
107 pool_destroy (t->container);
111 /* Sets the width and height of a table, in columns and rows,
112 respectively. Use only to reduce the size of a table, since it
113 does not change the amount of allocated memory. */
115 tab_resize (struct tab_table *t, int nc, int nr)
120 assert (nc + t->col_ofs <= t->cf);
121 t->nc = nc + t->col_ofs;
125 assert (nr + t->row_ofs <= t->nr);
126 t->nr = nr + t->row_ofs;
130 /* Changes either or both dimensions of a table. Consider using the
131 above routine instead if it won't waste a lot of space.
133 Changing the number of columns in a table is particularly expensive
134 in space and time. Avoid doing such. FIXME: In fact, transferring
135 of rules isn't even implemented yet. */
137 tab_realloc (struct tab_table *t, int nc, int nr)
143 assert (t->reallocable);
148 tab_offset (t, 0, 0);
155 assert (nc == t->nc);
159 int mr1 = min (nr, t->nr);
160 int mc1 = min (nc, t->nc);
162 struct fixed_string *new_cc;
163 unsigned char *new_ct;
166 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
167 new_ct = pool_malloc (t->container, nr * nc);
168 for (r = 0; r < mr1; r++)
170 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
171 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
172 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
174 pool_free (t->container, t->cc);
175 pool_free (t->container, t->ct);
180 else if (nr != t->nr)
182 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
183 t->ct = pool_realloc (t->container, t->ct, nr * nc);
185 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
186 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
187 t->trh = pool_realloc (t->container, t->trh, nr + 1);
188 t->hrh = pool_realloc (t->container, t->hrh,
189 sizeof *t->hrh * (nr + 1));
193 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
194 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
195 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
199 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
205 tab_offset (t, co, ro);
208 /* Sets the number of header rows on each side of TABLE to L on the
209 left, R on the right, T on the top, B on the bottom. Header rows
210 are repeated when a table is broken across multiple columns or
213 tab_headers (struct tab_table *table, int l, int r, int t, int b)
215 assert (table != NULL);
216 assert (l < table->nc);
217 assert (r < table->nc);
218 assert (t < table->nr);
219 assert (b < table->nr);
228 /* Set up table T so that, when it is an appropriate size, it will be
229 displayed across the page in columns.
231 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
234 tab_columns (struct tab_table *t, int style, int group)
237 t->col_style = style;
238 t->col_group = group;
243 /* Draws a vertical line to the left of cells at horizontal position X
244 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
246 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
253 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
254 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
255 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
257 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
258 "table size (%d,%d)\n"),
259 x, t->col_ofs, x + t->col_ofs,
260 y1, t->row_ofs, y1 + t->row_ofs,
261 y2, t->row_ofs, y2 + t->row_ofs,
275 assert (y2 <= t->nr);
279 if ((style & TAL_SPACING) == 0)
280 for (y = y1; y <= y2; y++)
281 t->rv[x + (t->cf + 1) * y] = style;
282 t->trv[x] |= (1 << (style & ~TAL_SPACING));
286 /* Draws a horizontal line above cells at vertical position Y from X1
287 to X2 inclusive in style STYLE, if style is not -1. */
289 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
307 if ((style & TAL_SPACING) == 0)
308 for (x = x1; x <= x2; x++)
309 t->rh[x + t->cf * y] = style;
310 t->trh[y] |= (1 << (style & ~TAL_SPACING));
314 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
315 lines of style F_H and vertical lines of style F_V. Fills the
316 interior of the box with horizontal lines of style I_H and vertical
317 lines of style I_V. Any of the line styles may be -1 to avoid
318 drawing those lines. This is distinct from 0, which draws a null
321 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
322 int x1, int y1, int x2, int y2)
327 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
328 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
329 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
330 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
332 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
333 "in table size (%d,%d)\n"),
334 x1, t->col_ofs, x1 + t->col_ofs,
335 y1, t->row_ofs, y1 + t->row_ofs,
336 x2, t->col_ofs, x2 + t->col_ofs,
337 y2, t->row_ofs, y2 + t->row_ofs,
358 if ((f_h & TAL_SPACING) == 0)
359 for (x = x1; x <= x2; x++)
361 t->rh[x + t->cf * y1] = f_h;
362 t->rh[x + t->cf * (y2 + 1)] = f_h;
364 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
365 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
370 if ((f_v & TAL_SPACING) == 0)
371 for (y = y1; y <= y2; y++)
373 t->rv[x1 + (t->cf + 1) * y] = f_v;
374 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
376 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
377 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
384 for (y = y1 + 1; y <= y2; y++)
388 if ((i_h & TAL_SPACING) == 0)
389 for (x = x1; x <= x2; x++)
390 t->rh[x + t->cf * y] = i_h;
392 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
399 for (x = x1 + 1; x <= x2; x++)
403 if ((i_v & TAL_SPACING) == 0)
404 for (y = y1; y <= y2; y++)
405 t->rv[x + (t->cf + 1) * y] = i_v;
407 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
412 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
413 the resultant string into S in TABLE's pool. */
415 text_format (struct tab_table *table, int opt, const char *text, va_list args,
416 struct fixed_string *s)
420 assert (table != NULL && text != NULL && s != NULL);
422 if (opt & TAT_PRINTF)
424 char *temp_buf = local_alloc (1024);
426 len = nvsprintf (temp_buf, text, args);
432 ls_create_buffer (s, text, len);
433 pool_register (table->container, free, s->string);
435 if (opt & TAT_PRINTF)
439 /* Set the title of table T to TITLE, which is formatted with printf
440 if FORMAT is nonzero. */
442 tab_title (struct tab_table *t, int format, const char *title, ...)
446 assert (t != NULL && title != NULL);
447 va_start (args, title);
448 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
452 /* Set DIM_FUNC as the dimension function for table T. */
454 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
456 assert (t != NULL && t->dim == NULL);
460 /* Returns the natural width of column C in table T for driver D, that
461 is, the smallest width necessary to display all its cells without
462 wrapping. The width will be no larger than the page width minus
463 left and right rule widths. */
465 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
469 assert (t != NULL && c >= 0 && c < t->nc);
473 for (width = r = 0; r < t->nr; r++)
475 struct outp_text text;
476 unsigned char opt = t->ct[c + r * t->cf];
478 if (opt & (TAB_JOIN | TAB_EMPTY))
481 text.s = t->cc[c + r * t->cf];
482 assert (!ls_null_p (&text.s));
483 text.options = OUTP_T_JUST_LEFT;
485 d->class->text_metrics (d, &text);
493 width = d->prop_em_width * 8;
495 printf ("warning: table column %d contains no data.\n", c);
500 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
509 /* Returns the natural height of row R in table T for driver D, that
510 is, the minimum height necessary to display the information in the
511 cell at the widths set for each column. */
513 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
517 assert (t != NULL && r >= 0 && r < t->nr);
522 for (height = d->font_height, c = 0; c < t->nc; c++)
524 struct outp_text text;
525 unsigned char opt = t->ct[c + r * t->cf];
527 assert (t->w[c] != NOT_INT);
528 if (opt & (TAB_JOIN | TAB_EMPTY))
531 text.s = t->cc[c + r * t->cf];
532 assert (!ls_null_p (&text.s));
533 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
535 d->class->text_metrics (d, &text);
545 /* Callback function to set all columns and rows to their natural
546 dimensions. Not really meant to be called directly. */
548 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
554 for (i = 0; i < t->nc; i++)
555 t->w[i] = tab_natural_width (t, d, i);
557 for (i = 0; i < t->nr; i++)
558 t->h[i] = tab_natural_height (t, d, i);
564 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
565 from V, displayed with format spec F. */
567 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
568 const union value *v, const struct fmt_spec *f)
572 assert (table != NULL && v != NULL && f != NULL);
574 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
575 || c + table->col_ofs >= table->nc
576 || r + table->row_ofs >= table->nr)
578 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
580 c, table->col_ofs, c + table->col_ofs,
581 r, table->row_ofs, r + table->row_ofs,
582 table->nc, table->nr);
587 contents = pool_alloc (table->container, f->w);
588 ls_init (&table->cc[c + r * table->cf], contents, f->w);
589 table->ct[c + r * table->cf] = opt;
591 data_out (contents, f, v);
594 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
595 with NDEC decimal places. */
597 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
598 double val, int w, int d)
604 union value double_value;
606 assert (table != NULL && w <= 40);
609 assert (c < table->nc);
611 assert (r < table->nr);
613 f = make_output_format (FMT_F, w, d);
616 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
617 || c + table->col_ofs >= table->nc
618 || r + table->row_ofs >= table->nr)
620 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
622 c, table->col_ofs, c + table->col_ofs,
623 r, table->row_ofs, r + table->row_ofs,
624 table->nc, table->nr);
629 double_value.f = val;
630 data_out (buf, &f, &double_value);
633 while (isspace ((unsigned char) *cp) && cp < &buf[w])
635 f.w = w - (cp - buf);
637 contents = pool_alloc (table->container, f.w);
638 ls_init (&table->cc[c + r * table->cf], contents, f.w);
639 table->ct[c + r * table->cf] = opt;
640 memcpy (contents, cp, f.w);
643 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
646 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
650 assert (table != NULL && text != NULL);
654 assert (c < table->nc);
655 assert (r < table->nr);
659 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
660 || c + table->col_ofs >= table->nc
661 || r + table->row_ofs >= table->nr)
663 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
665 c, table->col_ofs, c + table->col_ofs,
666 r, table->row_ofs, r + table->row_ofs,
667 table->nc, table->nr);
672 va_start (args, text);
673 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
674 table->ct[c + r * table->cf] = opt;
678 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
679 options OPT to have text value TEXT. */
681 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
682 unsigned opt, const char *text, ...)
684 struct tab_joined_cell *j;
686 assert (table != NULL && text != NULL);
688 assert (x1 + table->col_ofs >= 0);
689 assert (y1 + table->row_ofs >= 0);
692 assert (y2 + table->row_ofs < table->nr);
693 assert (x2 + table->col_ofs < table->nc);
696 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
697 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
698 || x2 < x1 || x2 + table->col_ofs >= table->nc
699 || y2 < y2 || y2 + table->row_ofs >= table->nr)
701 printf ("tab_joint_text(): bad cell "
702 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
703 x1, table->col_ofs, x1 + table->col_ofs,
704 y1, table->row_ofs, y1 + table->row_ofs,
705 x2, table->col_ofs, x2 + table->col_ofs,
706 y2, table->row_ofs, y2 + table->row_ofs,
707 table->nc, table->nr);
712 j = pool_alloc (table->container, sizeof *j);
714 j->x1 = x1 + table->col_ofs;
715 j->y1 = y1 + table->row_ofs;
716 j->x2 = ++x2 + table->col_ofs;
717 j->y2 = ++y2 + table->row_ofs;
722 va_start (args, text);
723 text_format (table, opt, text, args, &j->contents);
730 struct fixed_string *cc = &table->cc[x1 + y1 * table->cf];
731 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
732 const int ofs = table->cf - (x2 - x1);
736 for (y = y1; y < y2; y++)
740 for (x = x1; x < x2; x++)
742 ls_init (cc++, (char *) j, 0);
752 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
754 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
755 struct fixed_string *string)
757 assert (table != NULL && string != NULL);
760 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
761 || c + table->col_ofs >= table->nc
762 || r + table->row_ofs >= table->nr)
764 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
766 c, table->col_ofs, c + table->col_ofs,
767 r, table->row_ofs, r + table->row_ofs,
768 table->nc, table->nr);
773 table->cc[c + r * table->cf] = *string;
774 table->ct[c + r * table->cf] = opt;
779 /* Sets the widths of all the columns and heights of all the rows in
780 table T for driver D. */
782 nowrap_dim (struct tab_table *t, struct outp_driver *d)
784 t->w[0] = tab_natural_width (t, d, 0);
785 t->h[0] = d->font_height;
788 /* Sets the widths of all the columns and heights of all the rows in
789 table T for driver D. */
791 wrap_dim (struct tab_table *t, struct outp_driver *d)
793 t->w[0] = tab_natural_width (t, d, 0);
794 t->h[0] = tab_natural_height (t, d, 0);
797 /* Outputs text BUF as a table with a single cell having cell options
798 OPTIONS, which is a combination of the TAB_* and TAT_*
801 tab_output_text (int options, const char *buf, ...)
803 struct tab_table *t = tab_create (1, 1, 0);
805 assert (buf != NULL);
806 if (options & TAT_PRINTF)
809 char *temp_buf = local_alloc (4096);
811 va_start (args, buf);
812 nvsprintf (temp_buf, buf, args);
817 if (options & TAT_FIX)
819 struct outp_driver *d;
821 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
824 d->class->open_page (d);
826 if (d->class->text_set_font_by_name != NULL)
827 d->class->text_set_font_by_name (d, "FIXED");
835 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
836 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
837 if (options & TAT_NOWRAP)
838 tab_dim (t, nowrap_dim);
840 tab_dim (t, wrap_dim);
843 if (options & TAT_FIX)
845 struct outp_driver *d;
847 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
848 if (d->class->text_set_font_by_name != NULL)
849 d->class->text_set_font_by_name (d, "PROP");
856 if (options & TAT_PRINTF)
860 /* Set table flags to FLAGS. */
862 tab_flags (struct tab_table *t, unsigned flags)
868 /* Easy, type-safe way to submit a tab table to som. */
870 tab_submit (struct tab_table *t)
875 s.class = &tab_table_class;
884 /* Set table row and column offsets for all functions that affect
887 tab_offset (struct tab_table *t, int col, int row)
893 if (row < -1 || row >= t->nr)
895 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
898 if (col < -1 || col >= t->nc)
900 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
906 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
908 diff += (col - t->col_ofs), t->col_ofs = col;
914 /* Increment the row offset by one. If the table is too small,
915 increase its size. */
917 tab_next_row (struct tab_table *t)
922 if (++t->row_ofs >= t->nr)
923 tab_realloc (t, -1, t->nr * 4 / 3);
926 static struct tab_table *t;
927 static struct outp_driver *d;
930 /* Set the current table to TABLE. */
932 tabi_table (struct som_entity *table)
934 assert (table != NULL);
935 assert (table->type == SOM_TABLE);
938 tab_offset (t, 0, 0);
940 assert (t->w == NULL && t->h == NULL);
941 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
942 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
945 /* Set the current output device to DRIVER. */
947 tabi_driver (struct outp_driver *driver)
951 assert (driver != NULL);
954 /* Figure out sizes of rules. */
955 for (t->hr_tot = i = 0; i <= t->nr; i++)
956 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
957 for (t->vr_tot = i = 0; i <= t->nc; i++)
958 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
961 for (i = 0; i < t->nr; i++)
963 for (i = 0; i < t->nc; i++)
967 assert (t->dim != NULL);
974 for (i = 0; i < t->nr; i++)
978 printf ("Table row %d height not initialized.\n", i);
981 assert (t->h[i] > 0);
984 for (i = 0; i < t->nc; i++)
988 printf ("Table column %d width not initialized.\n", i);
991 assert (t->w[i] > 0);
996 /* Add up header sizes. */
997 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
998 t->wl += t->w[i] + t->wrv[i + 1];
999 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1000 t->ht += t->h[i] + t->hrh[i + 1];
1001 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1002 t->wr += t->w[i] + t->wrv[i + 1];
1003 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1004 t->hb += t->h[i] + t->hrh[i + 1];
1007 if (!(t->flags & SOMF_NO_TITLE))
1008 t->ht += d->font_height;
1011 /* Return the number of columns and rows in the table into N_COLUMNS
1012 and N_ROWS, respectively. */
1014 tabi_count (int *n_columns, int *n_rows)
1016 assert (n_columns != NULL && n_rows != NULL);
1021 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1023 /* Return the horizontal and vertical size of the entire table,
1024 including headers, for the current output device, into HORIZ and
1027 tabi_area (int *horiz, int *vert)
1029 assert (horiz != NULL && vert != NULL);
1034 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1035 c < t->nc - t->r; c++)
1036 w += t->w[c] + t->wrv[c];
1042 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1043 r < t->nr - t->b; r++)
1044 h += t->h[r] + t->hrh[r];
1049 /* Return the column style for this table into STYLE. */
1051 tabi_columns (int *style)
1053 assert (style != NULL);
1054 *style = t->col_style;
1057 /* Return the number of header rows/columns on the left, right, top,
1058 and bottom sides into HL, HR, HT, and HB, respectively. */
1060 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1062 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1069 /* Determines the number of rows or columns (including appropriate
1070 headers), depending on CUMTYPE, that will fit into the space
1071 specified. Takes rows/columns starting at index START and attempts
1072 to fill up available space MAX. Returns in END the index of the
1073 last row/column plus one; returns in ACTUAL the actual amount of
1074 space the selected rows/columns (including appropriate headers)
1077 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1084 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1085 if (cumtype == SOM_ROWS)
1087 assert (start >= 0 && start < t->nr);
1090 r = &t->hrh[start + 1];
1091 total = t->ht + t->hb;
1093 assert (start >= 0 && start < t->nc);
1096 r = &t->wrv[start + 1];
1097 total = t->wl + t->wr;
1113 for (x = start + 1; x < n; x++)
1115 int amt = *d++ + *r++;
1133 /* Return flags set for the current table into FLAGS. */
1135 tabi_flags (unsigned *flags)
1137 assert (flags != NULL);
1141 /* Returns true if the table will fit in the given page WIDTH,
1144 tabi_fits_width (int width)
1148 for (i = t->l; i < t->nc - t->r; i++)
1149 if (t->wl + t->wr + t->w[i] > width)
1155 /* Returns true if the table will fit in the given page LENGTH,
1158 tabi_fits_length (int length)
1162 for (i = t->t; i < t->nr - t->b; i++)
1163 if (t->ht + t->hb + t->h[i] > length)
1169 /* Sets the number of header rows/columns on the left, right, top,
1170 and bottom sides to HL, HR, HT, and HB, respectively. */
1172 tabi_set_headers (int hl, int hr, int ht, int hb)
1180 /* Render title for current table, with major index X and minor index
1181 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1184 tabi_title (int x, int y)
1189 if (t->flags & SOMF_NO_TITLE)
1192 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1194 cp = spprintf (cp, "(%d:%d)", x, y);
1196 cp = spprintf (cp, "(%d)", x);
1198 cp = spprintf (cp, " %s", cur_proc);
1199 cp = stpcpy (cp, ". ");
1200 if (!ls_empty_p (&t->title))
1202 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1203 cp += ls_length (&t->title);
1208 struct outp_text text;
1210 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1211 ls_init (&text.s, buf, cp - buf);
1213 text.v = d->font_height;
1216 d->class->text_draw (d, &text);
1220 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1222 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1223 X2 and row Y2 are not included in the rectangle, at the current
1224 position on the current output device. Draws headers as well. */
1226 tabi_render (int x1, int y1, int x2, int y2)
1234 if (!(t->flags & SOMF_NO_TITLE))
1235 y += d->font_height;
1239 ranges[0][1] = t->t * 2 + 1;
1241 /* Requested rows. */
1242 ranges[1][0] = y1 * 2 + 1;
1243 ranges[1][1] = y2 * 2;
1245 /* Bottom headers. */
1246 ranges[2][0] = (t->nr - t->b) * 2;
1247 ranges[2][1] = t->nr * 2 + 1;
1249 for (i = 0; i < 3; i++)
1253 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1256 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1257 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1258 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1259 t->nc * 2 + 1, y1, y2);
1260 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1265 struct som_table_class tab_table_class =
1291 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1292 on row R, at location (X,Y). Return width of the strip thus
1295 Renders joined cells, even those outside the strip, within the
1296 rendering region (C1,R1)-(C2,R2).
1298 For the purposes of counting rows and columns in this function
1299 only, horizontal rules are considered rows and vertical rules are
1302 FIXME: Doesn't use r1? Huh? */
1304 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1308 /* Horizontal rules. */
1311 int hrh = t->hrh[r / 2];
1314 for (c = c1; c < c2; c++)
1318 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1322 const struct color clr = {0, 0, 0, 0};
1327 rct.x2 = x + t->w[c / 2];
1329 d->class->line_horz (d, &rct, &clr, style);
1333 const struct color clr = {0, 0, 0, 0};
1335 struct outp_styles s;
1339 rct.x2 = x + t->wrv[c / 2];
1342 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1343 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1344 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1345 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1347 if (s.t | s.b | s.l | s.r)
1348 d->class->line_intersection (d, &rct, &clr, &s);
1356 for (c = c1; c < c2; c++)
1360 const int index = (c / 2) + (r / 2 * t->cf);
1362 if (!(t->ct[index] & TAB_JOIN))
1364 struct outp_text text;
1366 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1367 | OUTP_T_HORZ | OUTP_T_VERT);
1368 if ((t->ct[index] & TAB_EMPTY) == 0)
1370 text.s = t->cc[index];
1371 assert (!ls_null_p (&text.s));
1372 text.h = t->w[c / 2];
1373 text.v = t->h[r / 2];
1376 d->class->text_draw (d, &text);
1379 struct tab_joined_cell *j =
1380 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1382 if (j->hit != tab_hit)
1386 if (j->x1 == c / 2 && j->y1 == r / 2)
1388 struct outp_text text;
1390 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1391 | OUTP_T_HORZ | OUTP_T_VERT);
1392 text.s = j->contents;
1399 for (c = j->x1, text.h = -t->wrv[j->x2];
1400 c < j->x2 && c < c2 / 2; c++)
1401 text.h += t->w[c] + t->wrv[c + 1];
1407 for (r = j->y1, text.v = -t->hrh[j->y2];
1408 r < j->y2 && r < r2 / 2; r++)
1409 text.v += t->h[r] + t->hrh[r + 1];
1411 d->class->text_draw (d, &text);
1417 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1421 const struct color clr = {0, 0, 0, 0};
1426 rct.x2 = x + t->wrv[c / 2];
1427 rct.y2 = y + t->h[r / 2];
1428 d->class->line_vert (d, &rct, &clr, style);
1435 return x - x_origin;