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);
120 /* Sets the width and height of a table, in columns and rows,
121 respectively. Use only to reduce the size of a table, since it
122 does not change the amount of allocated memory. */
124 tab_resize (struct tab_table *t, int nc, int nr)
129 assert (nc + t->col_ofs <= t->cf);
130 t->nc = nc + t->col_ofs;
134 assert (nr + t->row_ofs <= t->nr);
135 t->nr = nr + t->row_ofs;
139 /* Changes either or both dimensions of a table. Consider using the
140 above routine instead if it won't waste a lot of space.
142 Changing the number of columns in a table is particularly expensive
143 in space and time. Avoid doing such. FIXME: In fact, transferring
144 of rules isn't even implemented yet. */
146 tab_realloc (struct tab_table *t, int nc, int nr)
152 assert (t->reallocable);
157 tab_offset (t, 0, 0);
164 assert (nc == t->nc);
168 int mr1 = min (nr, t->nr);
169 int mc1 = min (nc, t->nc);
171 struct len_string *new_cc;
172 unsigned char *new_ct;
175 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
176 new_ct = pool_malloc (t->container, nr * nc);
177 for (r = 0; r < mr1; r++)
179 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
180 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
181 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
183 pool_free (t->container, t->cc);
184 pool_free (t->container, t->ct);
189 else if (nr != t->nr)
191 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
192 t->ct = pool_realloc (t->container, t->ct, nr * nc);
194 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
195 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
196 t->trh = pool_realloc (t->container, t->trh, nr + 1);
197 t->hrh = pool_realloc (t->container, t->hrh,
198 sizeof *t->hrh * (nr + 1));
202 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
203 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
204 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
208 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
214 tab_offset (t, co, ro);
217 /* Sets the number of header rows on each side of TABLE to L on the
218 left, R on the right, T on the top, B on the bottom. Header rows
219 are repeated when a table is broken across multiple columns or
222 tab_headers (struct tab_table *table, int l, int r, int t, int b)
224 assert (table != NULL);
231 /* Set up table T so that, when it is an appropriate size, it will be
232 displayed across the page in columns.
234 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
237 tab_columns (struct tab_table *t, int style, int group)
240 t->col_style = style;
241 t->col_group = group;
246 /* Draws a vertical line to the left of cells at horizontal position X
247 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
249 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
255 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
256 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
257 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
259 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
260 "table size (%d,%d)\n"),
261 x, t->col_ofs, x + t->col_ofs,
262 y1, t->row_ofs, y1 + t->row_ofs,
263 y2, t->row_ofs, y2 + t->row_ofs,
275 if ((style & TAL_SPACING) == 0)
276 for (y = y1; y <= y2; y++)
277 t->rv[x + (t->cf + 1) * y] = style;
278 t->trv[x] |= (1 << (style & ~TAL_SPACING));
282 /* Draws a horizontal line above cells at vertical position Y from X1
283 to X2 inclusive in style STYLE, if style is not -1. */
285 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
291 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
292 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
293 || y + t->row_ofs < 0 || y + t->row_ofs > t->nr)
295 printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d "
296 "in table size (%d,%d)\n"),
297 x1, t->col_ofs, x1 + t->col_ofs,
298 x2, t->col_ofs, x2 + t->col_ofs,
299 y, t->row_ofs, y + t->row_ofs,
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)
330 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
331 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
332 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
333 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
335 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
336 "in table size (%d,%d)\n"),
337 x1, t->col_ofs, x1 + t->col_ofs,
338 y1, t->row_ofs, y1 + t->row_ofs,
339 x2, t->col_ofs, x2 + t->col_ofs,
340 y2, t->row_ofs, y2 + t->row_ofs,
354 if ((f_h & TAL_SPACING) == 0)
355 for (x = x1; x <= x2; x++)
357 t->rh[x + t->cf * y1] = f_h;
358 t->rh[x + t->cf * (y2 + 1)] = f_h;
360 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
361 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
366 if ((f_v & TAL_SPACING) == 0)
367 for (y = y1; y <= y2; y++)
369 t->rv[x1 + (t->cf + 1) * y] = f_v;
370 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
372 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
373 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
380 for (y = y1 + 1; y <= y2; y++)
384 if ((i_h & TAL_SPACING) == 0)
385 for (x = x1; x <= x2; x++)
386 t->rh[x + t->cf * y] = i_h;
388 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
395 for (x = x1 + 1; x <= x2; x++)
399 if ((i_v & TAL_SPACING) == 0)
400 for (y = y1; y <= y2; y++)
401 t->rv[x + (t->cf + 1) * y] = i_v;
403 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
408 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
409 the resultant string into S in TABLE's pool. */
411 text_format (struct tab_table *table, int opt, const char *text, va_list args,
412 struct len_string *s)
416 assert (table != NULL && text != NULL && s != NULL);
418 if (opt & TAT_PRINTF)
420 char *temp_buf = local_alloc (1024);
422 len = nvsprintf (temp_buf, text, args);
428 ls_create_buffer (table->container, s, text, len);
430 if (opt & TAT_PRINTF)
434 /* Set the title of table T to TITLE, which is formatted with printf
435 if FORMAT is nonzero. */
437 tab_title (struct tab_table *t, int format, const char *title, ...)
441 assert (t != NULL && title != NULL);
442 va_start (args, title);
443 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
447 /* Set DIM_FUNC as the dimension function for table T. */
449 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
451 assert (t != NULL && t->dim == NULL);
455 /* Returns the natural width of column C in table T for driver D, that
456 is, the smallest width necessary to display all its cells without
457 wrapping. The width will be no larger than the page width minus
458 left and right rule widths. */
460 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
464 assert (t != NULL && c >= 0 && c < t->nc);
468 for (width = r = 0; r < t->nr; r++)
470 struct outp_text text;
471 unsigned char opt = t->ct[c + r * t->cf];
473 if (opt & (TAB_JOIN | TAB_EMPTY))
476 text.s = t->cc[c + r * t->cf];
477 assert (!ls_null_p (&text.s));
478 text.options = OUTP_T_JUST_LEFT;
480 d->class->text_metrics (d, &text);
488 width = d->prop_em_width * 8;
490 printf ("warning: table column %d contains no data.\n", c);
495 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
504 /* Returns the natural height of row R in table T for driver D, that
505 is, the minimum height necessary to display the information in the
506 cell at the widths set for each column. */
508 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
512 assert (t != NULL && r >= 0 && r < t->nr);
517 for (height = d->font_height, c = 0; c < t->nc; c++)
519 struct outp_text text;
520 unsigned char opt = t->ct[c + r * t->cf];
522 assert (t->w[c] != NOT_INT);
523 if (opt & (TAB_JOIN | TAB_EMPTY))
526 text.s = t->cc[c + r * t->cf];
527 assert (!ls_null_p (&text.s));
528 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
530 d->class->text_metrics (d, &text);
540 /* Callback function to set all columns and rows to their natural
541 dimensions. Not really meant to be called directly. */
543 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
549 for (i = 0; i < t->nc; i++)
550 t->w[i] = tab_natural_width (t, d, i);
552 for (i = 0; i < t->nr; i++)
553 t->h[i] = tab_natural_height (t, d, i);
559 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
560 from V, displayed with format spec F. */
562 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
563 const union value *v, const struct fmt_spec *f)
566 union value temp_val;
568 assert (table != NULL && v != NULL && f != NULL);
570 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
571 || c + table->col_ofs >= table->nc
572 || r + table->row_ofs >= table->nr)
574 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
576 c, table->col_ofs, c + table->col_ofs,
577 r, table->row_ofs, r + table->row_ofs,
578 table->nc, table->nr);
583 contents = pool_alloc (table->container, f->w);
584 ls_init (&table->cc[c + r * table->cf], contents, f->w);
585 table->ct[c + r * table->cf] = opt;
587 if (formats[f->type].cat & FCAT_STRING)
589 temp_val.c = (char *) v->s;
592 data_out (contents, f, v);
595 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
596 with NDEC decimal places. */
598 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
599 double val, int w, int d)
606 assert (table != NULL && w <= 40);
613 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
614 || c + table->col_ofs >= table->nc
615 || r + table->row_ofs >= table->nr)
617 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
619 c, table->col_ofs, c + table->col_ofs,
620 r, table->row_ofs, r + table->row_ofs,
621 table->nc, table->nr);
626 data_out (buf, &f, (union value *) &val);
628 while (isspace ((unsigned char) *cp) && cp < &buf[w])
630 f.w = w - (cp - buf);
632 contents = pool_alloc (table->container, f.w);
633 ls_init (&table->cc[c + r * table->cf], contents, f.w);
634 table->ct[c + r * table->cf] = opt;
635 memcpy (contents, cp, f.w);
638 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
641 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
645 assert (table != NULL && text != NULL);
647 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
648 || c + table->col_ofs >= table->nc
649 || r + table->row_ofs >= table->nr)
651 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
653 c, table->col_ofs, c + table->col_ofs,
654 r, table->row_ofs, r + table->row_ofs,
655 table->nc, table->nr);
660 va_start (args, text);
661 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
662 table->ct[c + r * table->cf] = opt;
666 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
667 options OPT to have text value TEXT. */
669 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
670 unsigned opt, const char *text, ...)
672 struct tab_joined_cell *j;
674 assert (table != NULL && text != NULL);
676 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
677 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
678 || x2 < x1 || x2 + table->col_ofs >= table->nc
679 || y2 < y2 || y2 + table->row_ofs >= table->nr)
681 printf ("tab_joint_text(): bad cell "
682 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
683 x1, table->col_ofs, x1 + table->col_ofs,
684 y1, table->row_ofs, y1 + table->row_ofs,
685 x2, table->col_ofs, x2 + table->col_ofs,
686 y2, table->row_ofs, y2 + table->row_ofs,
687 table->nc, table->nr);
692 j = pool_alloc (table->container, sizeof *j);
694 j->x1 = x1 + table->col_ofs;
695 j->y1 = y1 + table->row_ofs;
696 j->x2 = ++x2 + table->col_ofs;
697 j->y2 = ++y2 + table->row_ofs;
702 va_start (args, text);
703 text_format (table, opt, text, args, &j->contents);
710 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
711 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
712 const int ofs = table->cf - (x2 - x1);
716 for (y = y1; y < y2; y++)
720 for (x = x1; x < x2; x++)
722 ls_init (cc++, (char *) j, 0);
732 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
734 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
735 struct len_string *string)
737 assert (table != NULL && string != NULL);
740 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
741 || c + table->col_ofs >= table->nc
742 || r + table->row_ofs >= table->nr)
744 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
746 c, table->col_ofs, c + table->col_ofs,
747 r, table->row_ofs, r + table->row_ofs,
748 table->nc, table->nr);
753 table->cc[c + r * table->cf] = *string;
754 table->ct[c + r * table->cf] = opt;
759 /* Sets the widths of all the columns and heights of all the rows in
760 table T for driver D. */
762 nowrap_dim (struct tab_table *t, struct outp_driver *d)
764 t->w[0] = tab_natural_width (t, d, 0);
765 t->h[0] = d->font_height;
768 /* Sets the widths of all the columns and heights of all the rows in
769 table T for driver D. */
771 wrap_dim (struct tab_table *t, struct outp_driver *d)
773 t->w[0] = tab_natural_width (t, d, 0);
774 t->h[0] = tab_natural_height (t, d, 0);
777 /* Outputs text BUF as a table with a single cell having cell options
778 OPTIONS, which is a combination of the TAB_* and TAT_*
781 tab_output_text (int options, const char *buf, ...)
783 struct tab_table *t = tab_create (1, 1, 0);
785 assert (buf != NULL);
786 if (options & TAT_PRINTF)
789 char *temp_buf = local_alloc (4096);
791 va_start (args, buf);
792 nvsprintf (temp_buf, buf, args);
797 if (options & TAT_FIX)
799 struct outp_driver *d;
801 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
804 d->class->open_page (d);
806 d->class->text_set_font_by_name (d, "FIXED");
810 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
811 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
812 if (options & TAT_NOWRAP)
813 tab_dim (t, nowrap_dim);
815 tab_dim (t, wrap_dim);
818 if (options & TAT_FIX)
820 struct outp_driver *d;
822 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
823 d->class->text_set_font_by_name (d, "PROP");
826 if (options & TAT_PRINTF)
830 /* Set table flags to FLAGS. */
832 tab_flags (struct tab_table *t, unsigned flags)
838 /* Easy, type-safe way to submit a tab table to som. */
840 tab_submit (struct tab_table *t)
845 s.class = &tab_table_class;
853 /* Set table row and column offsets for all functions that affect
856 tab_offset (struct tab_table *t, int col, int row)
862 if (row < -1 || row >= t->nr)
864 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
867 if (col < -1 || col >= t->nc)
869 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
875 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
877 diff += (col - t->col_ofs), t->col_ofs = col;
883 /* Increment the row offset by one. If the table is too small,
884 increase its size. */
886 tab_next_row (struct tab_table *t)
891 if (++t->row_ofs >= t->nr)
892 tab_realloc (t, -1, t->nr * 4 / 3);
895 static struct tab_table *t;
896 static struct outp_driver *d;
899 /* Set the current table to TABLE. */
901 tabi_table (struct som_table *table)
903 assert (table != NULL);
905 tab_offset (t, 0, 0);
907 assert (t->w == NULL && t->h == NULL);
908 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
909 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
912 /* Set the current output device to DRIVER. */
914 tabi_driver (struct outp_driver *driver)
918 assert (driver != NULL);
921 /* Figure out sizes of rules. */
922 for (t->hr_tot = i = 0; i <= t->nr; i++)
923 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
924 for (t->vr_tot = i = 0; i <= t->nc; i++)
925 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
928 for (i = 0; i < t->nr; i++)
930 for (i = 0; i < t->nc; i++)
934 assert (t->dim != NULL);
941 for (i = 0; i < t->nr; i++)
945 printf ("Table row %d height not initialized.\n", i);
948 assert (t->h[i] > 0);
951 for (i = 0; i < t->nc; i++)
955 printf ("Table column %d width not initialized.\n", i);
958 assert (t->w[i] > 0);
963 /* Add up header sizes. */
964 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
965 t->wl += t->w[i] + t->wrv[i + 1];
966 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
967 t->ht += t->h[i] + t->hrh[i + 1];
968 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
969 t->wr += t->w[i] + t->wrv[i + 1];
970 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
971 t->hb += t->h[i] + t->hrh[i + 1];
974 if (!(t->flags & SOMF_NO_TITLE))
975 t->ht += d->font_height;
978 /* Return the number of columns and rows in the table into N_COLUMNS
979 and N_ROWS, respectively. */
981 tabi_count (int *n_columns, int *n_rows)
983 assert (n_columns != NULL && n_rows != NULL);
988 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
990 /* Return the horizontal and vertical size of the entire table,
991 including headers, for the current output device, into HORIZ and
994 tabi_area (int *horiz, int *vert)
996 assert (horiz != NULL && vert != NULL);
1001 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1002 c < t->nc - t->r; c++)
1003 w += t->w[c] + t->wrv[c];
1009 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1010 r < t->nr - t->b; r++)
1011 h += t->h[r] + t->hrh[r];
1016 /* Return the column style for this table into STYLE. */
1018 tabi_columns (int *style)
1020 assert (style != NULL);
1021 *style = t->col_style;
1024 /* Return the number of header rows/columns on the left, right, top,
1025 and bottom sides into HL, HR, HT, and HB, respectively. */
1027 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1029 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1036 /* Determines the number of rows or columns (including appropriate
1037 headers), depending on CUMTYPE, that will fit into the space
1038 specified. Takes rows/columns starting at index START and attempts
1039 to fill up available space MAX. Returns in END the index of the
1040 last row/column plus one; returns in ACTUAL the actual amount of
1041 space the selected rows/columns (including appropriate headers)
1044 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1051 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1052 if (cumtype == SOM_ROWS)
1054 assert (start >= 0 && start < t->nr);
1057 r = &t->hrh[start + 1];
1058 total = t->ht + t->hb;
1060 assert (start >= 0 && start < t->nc);
1063 r = &t->wrv[start + 1];
1064 total = t->wl + t->wr;
1080 for (x = start + 1; x < n; x++)
1082 int amt = *d++ + *r++;
1100 /* Return flags set for the current table into FLAGS. */
1102 tabi_flags (unsigned *flags)
1104 assert (flags != NULL);
1108 /* Render title for current table, with major index X and minor index
1109 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1112 tabi_title (int x, int y)
1117 if (t->flags & SOMF_NO_TITLE)
1120 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1122 cp = spprintf (cp, "(%d:%d)", x, y);
1124 cp = spprintf (cp, "(%d)", x);
1126 cp = spprintf (cp, " %s", cur_proc);
1127 cp = stpcpy (cp, ". ");
1128 if (!ls_empty_p (&t->title))
1130 memcpy (cp, ls_value (&t->title), ls_length (&t->title));
1131 cp += ls_length (&t->title);
1136 struct outp_text text;
1138 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1139 ls_init (&text.s, buf, cp - buf);
1141 text.v = d->font_height;
1144 d->class->text_draw (d, &text);
1148 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1150 /* Execute BODY for each value of X from A to B exclusive. */
1151 #define UNROLL_LOOP(X, A, B, BODY) \
1154 for (X = A; X < B; X++) \
1161 /* Execute PREP, then BODY for each specified value of X: A1...A2, B1...B2,
1162 C1...C2, in each case not including the second value. */
1163 #define UNROLL_3_LOOPS(X, A1, A2, B1, B2, C1, C2, BODY) \
1166 UNROLL_LOOP (X, A1, A2, BODY); \
1167 UNROLL_LOOP (X, B1, B2, BODY); \
1168 UNROLL_LOOP (X, C1, C2, BODY); \
1172 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1173 X2 and row Y2 are not included in the rectangle, at the current
1174 position on the current output device. Draws headers as well. */
1176 tabi_render (int x1, int y1, int x2, int y2)
1182 if (!(t->flags & SOMF_NO_TITLE))
1183 y += d->font_height;
1184 UNROLL_3_LOOPS (r, 0, t->t * 2 + 1, y1 * 2 + 1, y2 * 2,
1185 (t->nr - t->b) * 2, t->nr * 2 + 1,
1188 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1189 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1190 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1191 t->nc * 2 + 1, y1, y2);
1192 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1196 struct som_table_class tab_table_class =
1219 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1220 on row R, at location (X,Y). Return width of the strip thus
1223 Renders joined cells, even those outside the strip, within the
1224 rendering region (C1,R1)-(C2,R2).
1226 For the purposes of counting rows and columns in this function
1227 only, horizontal rules are considered rows and vertical rules are
1230 FIXME: Doesn't use r1? Huh? */
1232 render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
1236 /* Horizontal rules. */
1239 int hrh = t->hrh[r / 2];
1242 for (c = c1; c < c2; c++)
1246 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1250 const struct color clr = {0, 0, 0, 0};
1255 rct.x2 = x + t->w[c / 2];
1257 d->class->line_horz (d, &rct, &clr, style);
1261 const struct color clr = {0, 0, 0, 0};
1263 struct outp_styles s;
1267 rct.x2 = x + t->wrv[c / 2];
1270 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1271 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1272 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1273 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1275 if (s.t | s.b | s.l | s.r)
1276 d->class->line_intersection (d, &rct, &clr, &s);
1284 for (c = c1; c < c2; c++)
1288 const int index = (c / 2) + (r / 2 * t->cf);
1290 if (!(t->ct[index] & TAB_JOIN))
1292 struct outp_text text;
1294 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1295 | OUTP_T_HORZ | OUTP_T_VERT);
1296 if ((t->ct[index] & TAB_EMPTY) == 0)
1298 text.s = t->cc[index];
1299 assert (!ls_null_p (&text.s));
1300 text.h = t->w[c / 2];
1301 text.v = t->h[r / 2];
1304 d->class->text_draw (d, &text);
1307 struct tab_joined_cell *j =
1308 (struct tab_joined_cell *) ls_value (&t->cc[index]);
1310 if (j->hit != tab_hit)
1314 if (j->x1 == c / 2 && j->y1 == r / 2
1315 && j->x2 <= c2 && j->y2 <= r2)
1317 struct outp_text text;
1319 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1320 | OUTP_T_HORZ | OUTP_T_VERT);
1321 text.s = j->contents;
1328 for (c = j->x1, text.h = -t->wrv[j->x2];
1330 text.h += t->w[c] + t->wrv[c + 1];
1336 for (r = j->y1, text.v = -t->hrh[j->y2];
1338 text.v += t->h[r] + t->hrh[r + 1];
1340 d->class->text_draw (d, &text);
1346 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1350 const struct color clr = {0, 0, 0, 0};
1355 rct.x2 = x + t->wrv[c / 2];
1356 rct.y2 = y + t->h[r / 2];
1357 d->class->line_vert (d, &rct, &clr, style);
1364 return x - x_origin;