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
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
55 /*#define DEBUGGING 1 */
56 #include "debug-print.h"
58 extern struct som_table_class tab_table_class;
61 #define DEFFIRST(NAME, LABEL) LABEL,
62 #define DEFTAB(NAME, LABEL) LABEL,
63 static const char *tab_names[] =
71 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
72 nonzero then the table's size can be increased later; otherwise,
73 its size can only be reduced. */
75 tab_create (int nc, int nr, int reallocable)
77 void *(*alloc_func) (struct pool *, size_t);
82 struct pool *container = pool_create ();
83 t = pool_alloc (container, sizeof *t);
84 t->container = container;
87 t->col_style = TAB_COL_NONE;
93 t->l = t->r = t->t = t->b = 0;
95 alloc_func = reallocable ? pool_malloc : pool_alloc;
97 t->reallocable = reallocable;
100 t->cc = alloc_func (t->container, nr * nc * sizeof *t->cc);
101 t->ct = alloc_func (t->container, nr * nc);
102 memset (t->ct, TAB_EMPTY, nc * nr);
104 t->rh = alloc_func (t->container, nc * (nr + 1));
105 memset (t->rh, 0, nc * (nr + 1));
107 t->hrh = alloc_func (t->container, sizeof *t->hrh * (nr + 1));
108 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
110 t->trh = alloc_func (t->container, nr + 1);
111 memset (t->trh, 0, nr + 1);
113 t->rv = alloc_func (t->container, (nc + 1) * nr);
114 memset (t->rv, 0, (nc + 1) * nr);
116 t->wrv = alloc_func (t->container, sizeof *t->wrv * (nc + 1));
117 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
119 t->trv = alloc_func (t->container, nc + 1);
120 memset (t->trv, 0, nc + 1);
124 t->col_ofs = t->row_ofs = 0;
129 /* Destroys table T. */
131 tab_destroy (struct tab_table *t)
134 pool_destroy (t->container);
138 /* Sets the width and height of a table, in columns and rows,
139 respectively. Use only to reduce the size of a table, since it
140 does not change the amount of allocated memory. */
142 tab_resize (struct tab_table *t, int nc, int nr)
147 assert (nc + t->col_ofs <= t->cf);
148 t->nc = nc + t->col_ofs;
152 assert (nr + t->row_ofs <= t->nr);
153 t->nr = nr + t->row_ofs;
157 /* Changes either or both dimensions of a table. Consider using the
158 above routine instead if it won't waste a lot of space.
160 Changing the number of columns in a table is particularly expensive
161 in space and time. Avoid doing such. FIXME: In fact, transferring
162 of rules isn't even implemented yet. */
164 tab_realloc (struct tab_table *t, int nc, int nr)
170 assert (t->reallocable);
175 tab_offset (t, 0, 0);
182 assert (nc == t->nc);
186 int mr1 = min (nr, t->nr);
187 int mc1 = min (nc, t->nc);
189 struct len_string *new_cc;
190 unsigned char *new_ct;
193 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
194 new_ct = pool_malloc (t->container, nr * nc);
195 for (r = 0; r < mr1; r++)
197 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
198 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
199 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
201 pool_free (t->container, t->cc);
202 pool_free (t->container, t->ct);
207 else if (nr != t->nr)
209 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
210 t->ct = pool_realloc (t->container, t->ct, nr * nc);
212 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
213 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
214 t->trh = pool_realloc (t->container, t->trh, nr + 1);
215 t->hrh = pool_realloc (t->container, t->hrh,
216 sizeof *t->hrh * (nr + 1));
220 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
221 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
222 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
226 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
232 tab_offset (t, co, ro);
235 /* Sets the number of header rows on each side of TABLE to L on the
236 left, R on the right, T on the top, B on the bottom. Header rows
237 are repeated when a table is broken across multiple columns or
240 tab_headers (struct tab_table *table, int l, int r, int t, int b)
242 assert (table != NULL);
249 /* Set up table T so that, when it is an appropriate size, it will be
250 displayed across the page in columns.
252 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
255 tab_columns (struct tab_table *t, int style, int group)
258 t->col_style = style;
259 t->col_group = group;
264 /* Draws a vertical line to the left of cells at horizontal position X
265 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
267 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
273 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
274 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
275 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
277 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
278 "table size (%d,%d)\n"),
279 x, t->col_ofs, x + t->col_ofs,
280 y1, t->row_ofs, y1 + t->row_ofs,
281 y2, t->row_ofs, y2 + t->row_ofs,
293 if ((style & TAL_SPACING) == 0)
294 for (y = y1; y <= y2; y++)
295 t->rv[x + (t->cf + 1) * y] = style;
296 t->trv[x] |= (1 << (style & ~TAL_SPACING));
300 /* Draws a horizontal line above cells at vertical position Y from X1
301 to X2 inclusive in style STYLE, if style is not -1. */
303 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
309 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
310 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
311 || y + t->row_ofs < 0 || y + t->row_ofs > t->nr)
313 printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d "
314 "in table size (%d,%d)\n"),
315 x1, t->col_ofs, x1 + t->col_ofs,
316 x2, t->col_ofs, x2 + t->col_ofs,
317 y, t->row_ofs, y + t->row_ofs,
329 if ((style & TAL_SPACING) == 0)
330 for (x = x1; x <= x2; x++)
331 t->rh[x + t->cf * y] = style;
332 t->trh[y] |= (1 << (style & ~TAL_SPACING));
336 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
337 lines of style F_H and vertical lines of style F_V. Fills the
338 interior of the box with horizontal lines of style I_H and vertical
339 lines of style I_V. Any of the line styles may be -1 to avoid
340 drawing those lines. This is distinct from 0, which draws a null
343 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
344 int x1, int y1, int x2, int y2)
348 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
349 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
350 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
351 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
353 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
354 "in table size (%d,%d)\n"),
355 x1, t->col_ofs, x1 + t->col_ofs,
356 y1, t->row_ofs, y1 + t->row_ofs,
357 x2, t->col_ofs, x2 + t->col_ofs,
358 y2, t->row_ofs, y2 + t->row_ofs,
372 if ((f_h & TAL_SPACING) == 0)
373 for (x = x1; x <= x2; x++)
375 t->rh[x + t->cf * y1] = f_h;
376 t->rh[x + t->cf * (y2 + 1)] = f_h;
378 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
379 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
384 if ((f_v & TAL_SPACING) == 0)
385 for (y = y1; y <= y2; y++)
387 t->rv[x1 + (t->cf + 1) * y] = f_v;
388 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
390 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
391 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
398 for (y = y1 + 1; y <= y2; y++)
402 if ((i_h & TAL_SPACING) == 0)
403 for (x = x1; x <= x2; x++)
404 t->rh[x + t->cf * y] = i_h;
406 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
413 for (x = x1 + 1; x <= x2; x++)
417 if ((i_v & TAL_SPACING) == 0)
418 for (y = y1; y <= y2; y++)
419 t->rv[x + (t->cf + 1) * y] = i_v;
421 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
426 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
427 the resultant string into S in TABLE's pool. */
429 text_format (struct tab_table *table, int opt, const char *text, va_list args,
430 struct len_string *s)
434 assert (table != NULL && text != NULL && s != NULL);
436 if (opt & TAT_PRINTF)
438 char *temp_buf = local_alloc (1024);
440 len = nvsprintf (temp_buf, text, args);
446 ls_create_buffer (table->container, s, text, len);
448 if (opt & TAT_PRINTF)
452 /* Set the title of table T to TITLE, which is formatted with printf
453 if FORMAT is nonzero. */
455 tab_title (struct tab_table *t, int format, const char *title, ...)
459 assert (t != NULL && title != NULL);
460 va_start (args, title);
461 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
465 /* Set DIM_FUNC as the dimension function for table T. */
467 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
469 assert (t != NULL && t->dim == NULL);
473 /* Returns the natural width of column C in table T for driver D, that
474 is, the smallest width necessary to display all its cells without
475 wrapping. The width will be no larger than the page width minus
476 left and right rule widths. */
478 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
482 assert (t != NULL && c >= 0 && c < t->nc);
486 for (width = r = 0; r < t->nr; r++)
488 struct outp_text text;
489 unsigned char opt = t->ct[c + r * t->cf];
491 if (opt & (TAB_JOIN | TAB_EMPTY))
494 text.s = t->cc[c + r * t->cf];
495 assert (!ls_null_p (&text.s));
496 text.options = OUTP_T_JUST_LEFT;
498 d->class->text_metrics (d, &text);
506 width = d->prop_em_width * 8;
508 printf ("warning: table column %d contains no data.\n", c);
513 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
522 /* Returns the natural height of row R in table T for driver D, that
523 is, the minimum height necessary to display the information in the
524 cell at the widths set for each column. */
526 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
530 assert (t != NULL && r >= 0 && r < t->nr);
535 for (height = d->font_height, c = 0; c < t->nc; c++)
537 struct outp_text text;
538 unsigned char opt = t->ct[c + r * t->cf];
540 assert (t->w[c] != NOT_INT);
541 if (opt & (TAB_JOIN | TAB_EMPTY))
544 text.s = t->cc[c + r * t->cf];
545 assert (!ls_null_p (&text.s));
546 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
548 d->class->text_metrics (d, &text);
558 /* Callback function to set all columns and rows to their natural
559 dimensions. Not really meant to be called directly. */
561 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
567 for (i = 0; i < t->nc; i++)
568 t->w[i] = tab_natural_width (t, d, i);
570 for (i = 0; i < t->nr; i++)
571 t->h[i] = tab_natural_height (t, d, i);
577 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
578 from V, displayed with format spec F. */
580 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
581 const union value *v, const struct fmt_spec *f)
584 union value temp_val;
586 assert (table != NULL && v != NULL && f != NULL);
588 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
589 || c + table->col_ofs >= table->nc
590 || r + table->row_ofs >= table->nr)
592 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
594 c, table->col_ofs, c + table->col_ofs,
595 r, table->row_ofs, r + table->row_ofs,
596 table->nc, table->nr);
601 contents = pool_alloc (table->container, f->w);
602 ls_init (&table->cc[c + r * table->cf], contents, f->w);
603 table->ct[c + r * table->cf] = opt;
605 if (formats[f->type].cat & FCAT_STRING)
607 temp_val.c = (char *) v->s;
610 data_out (contents, f, v);
613 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
614 with NDEC decimal places. */
616 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
617 double val, int w, int d)
624 assert (table != NULL && w <= 40);
631 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
632 || c + table->col_ofs >= table->nc
633 || r + table->row_ofs >= table->nr)
635 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
637 c, table->col_ofs, c + table->col_ofs,
638 r, table->row_ofs, r + table->row_ofs,
639 table->nc, table->nr);
644 data_out (buf, &f, (union value *) &val);
646 while (isspace ((unsigned char) *cp) && cp < &buf[w])
648 f.w = w - (cp - buf);
650 contents = pool_alloc (table->container, f.w);
651 ls_init (&table->cc[c + r * table->cf], contents, f.w);
652 table->ct[c + r * table->cf] = opt;
653 memcpy (contents, cp, f.w);
656 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
659 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
663 assert (table != NULL && text != NULL);
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 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
695 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
696 || x2 < x1 || x2 + table->col_ofs >= table->nc
697 || y2 < y2 || y2 + table->row_ofs >= table->nr)
699 printf ("tab_joint_text(): bad cell "
700 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
701 x1, table->col_ofs, x1 + table->col_ofs,
702 y1, table->row_ofs, y1 + table->row_ofs,
703 x2, table->col_ofs, x2 + table->col_ofs,
704 y2, table->row_ofs, y2 + table->row_ofs,
705 table->nc, table->nr);
710 j = pool_alloc (table->container, sizeof *j);
712 j->x1 = x1 + table->col_ofs;
713 j->y1 = y1 + table->row_ofs;
714 j->x2 = ++x2 + table->col_ofs;
715 j->y2 = ++y2 + table->row_ofs;
720 va_start (args, text);
721 text_format (table, opt, text, args, &j->contents);
728 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
729 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
730 const int ofs = table->cf - (x2 - x1);
734 for (y = y1; y < y2; y++)
738 for (x = x1; x < x2; x++)
740 ls_init (cc++, (char *) j, 0);
750 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
752 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
753 struct len_string *string)
755 assert (table != NULL && string != NULL);
758 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
759 || c + table->col_ofs >= table->nc
760 || r + table->row_ofs >= table->nr)
762 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
764 c, table->col_ofs, c + table->col_ofs,
765 r, table->row_ofs, r + table->row_ofs,
766 table->nc, table->nr);
771 table->cc[c + r * table->cf] = *string;
772 table->ct[c + r * table->cf] = opt;
777 /* Sets the widths of all the columns and heights of all the rows in
778 table T for driver D. */
780 nowrap_dim (struct tab_table *t, struct outp_driver *d)
782 t->w[0] = tab_natural_width (t, d, 0);
783 t->h[0] = d->font_height;
786 /* Sets the widths of all the columns and heights of all the rows in
787 table T for driver D. */
789 wrap_dim (struct tab_table *t, struct outp_driver *d)
791 t->w[0] = tab_natural_width (t, d, 0);
792 t->h[0] = tab_natural_height (t, d, 0);
795 /* Outputs text BUF as a table with a single cell having cell options
796 OPTIONS, which is a combination of the TAB_* and TAT_*
799 tab_output_text (int options, const char *buf, ...)
801 struct tab_table *t = tab_create (1, 1, 0);
803 assert (buf != NULL);
804 if (options & TAT_PRINTF)
807 char *temp_buf = local_alloc (4096);
809 va_start (args, buf);
810 nvsprintf (temp_buf, buf, args);
815 if (options & TAT_FIX)
817 struct outp_driver *d;
819 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
822 d->class->open_page (d);
824 d->class->text_set_font_by_name (d, "FIXED");
828 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
829 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
830 if (options & TAT_NOWRAP)
831 tab_dim (t, nowrap_dim);
833 tab_dim (t, wrap_dim);
836 if (options & TAT_FIX)
838 struct outp_driver *d;
840 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
841 d->class->text_set_font_by_name (d, "PROP");
844 if (options & TAT_PRINTF)
848 /* Set table flags to FLAGS. */
850 tab_flags (struct tab_table *t, unsigned flags)
856 /* Easy, type-safe way to submit a tab table to som. */
858 tab_submit (struct tab_table *t)
863 s.class = &tab_table_class;
871 /* Set table row and column offsets for all functions that affect
874 tab_offset (struct tab_table *t, int col, int row)
880 if (row < -1 || row >= t->nr)
882 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
885 if (col < -1 || col >= t->nc)
887 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
893 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
895 diff += (col - t->col_ofs), t->col_ofs = col;
901 /* Increment the row offset by one. If the table is too small,
902 increase its size. */
904 tab_next_row (struct tab_table *t)
909 if (++t->row_ofs >= t->nr)
910 tab_realloc (t, -1, t->nr * 4 / 3);
913 static struct tab_table *t;
914 static struct outp_driver *d;
917 /* Set the current table to TABLE. */
919 tabi_table (struct som_table *table)
921 assert (table != NULL);
923 tab_offset (t, 0, 0);
925 assert (t->w == NULL && t->h == NULL);
926 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
927 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
930 /* Set the current output device to DRIVER. */
932 tabi_driver (struct outp_driver *driver)
936 assert (driver != NULL);
939 /* Figure out sizes of rules. */
940 for (t->hr_tot = i = 0; i <= t->nr; i++)
941 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
942 for (t->vr_tot = i = 0; i <= t->nc; i++)
943 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
946 for (i = 0; i < t->nr; i++)
948 for (i = 0; i < t->nc; i++)
952 assert (t->dim != NULL);
959 for (i = 0; i < t->nr; i++)
963 printf ("Table row %d height not initialized.\n", i);
966 assert (t->h[i] > 0);
969 for (i = 0; i < t->nc; i++)
973 printf ("Table column %d width not initialized.\n", i);
976 assert (t->w[i] > 0);
981 /* Add up header sizes. */
982 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
983 t->wl += t->w[i] + t->wrv[i + 1];
984 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
985 t->ht += t->h[i] + t->hrh[i + 1];
986 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
987 t->wr += t->w[i] + t->wrv[i + 1];
988 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
989 t->hb += t->h[i] + t->hrh[i + 1];
992 if (!(t->flags & SOMF_NO_TITLE))
993 t->ht += d->font_height;
996 /* Return the number of columns and rows in the table into N_COLUMNS
997 and N_ROWS, respectively. */
999 tabi_count (int *n_columns, int *n_rows)
1001 assert (n_columns != NULL && n_rows != NULL);
1006 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1008 /* Return the horizontal and vertical size of the entire table,
1009 including headers, for the current output device, into HORIZ and
1012 tabi_area (int *horiz, int *vert)
1014 assert (horiz != NULL && vert != NULL);
1019 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1020 c < t->nc - t->r; c++)
1021 w += t->w[c] + t->wrv[c];
1027 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1028 r < t->nr - t->b; r++)
1029 h += t->h[r] + t->hrh[r];
1034 /* Return the column style for this table into STYLE. */
1036 tabi_columns (int *style)
1038 assert (style != NULL);
1039 *style = t->col_style;
1042 /* Return the number of header rows/columns on the left, right, top,
1043 and bottom sides into HL, HR, HT, and HB, respectively. */
1045 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1047 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1054 /* Determines the number of rows or columns (including appropriate
1055 headers), depending on CUMTYPE, that will fit into the space
1056 specified. Takes rows/columns starting at index START and attempts
1057 to fill up available space MAX. Returns in END the index of the
1058 last row/column plus one; returns in ACTUAL the actual amount of
1059 space the selected rows/columns (including appropriate headers)
1062 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1069 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1070 if (cumtype == SOM_ROWS)
1072 assert (start >= 0 && start < t->nr);
1075 r = &t->hrh[start + 1];
1076 total = t->ht + t->hb;
1078 assert (start >= 0 && start < t->nc);
1081 r = &t->wrv[start + 1];
1082 total = t->wl + t->wr;
1098 for (x = start + 1; x < n; x++)
1100 int amt = *d++ + *r++;
1118 /* Return flags set for the current table into FLAGS. */
1120 tabi_flags (unsigned *flags)
1122 assert (flags != NULL);
1126 /* Render title for current table, with major index X and minor index
1127 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1130 tabi_title (int x, int y)
1135 if (t->flags & SOMF_NO_TITLE)
1138 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1140 cp = spprintf (cp, "(%d:%d)", x, y);
1142 cp = spprintf (cp, "(%d)", x);
1144 cp = spprintf (cp, " %s", cur_proc);
1145 cp = stpcpy (cp, ". ");
1146 if (!ls_empty_p (&t->title))
1148 memcpy (cp, ls_value (&t->title), ls_length (&t->title));
1149 cp += ls_length (&t->title);
1154 struct outp_text text;
1156 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1157 ls_init (&text.s, buf, cp - buf);
1159 text.v = d->font_height;
1162 d->class->text_draw (d, &text);
1166 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1168 /* Execute BODY for each value of X from A to B exclusive. */
1169 #define UNROLL_LOOP(X, A, B, BODY) \
1172 for (X = A; X < B; X++) \
1179 /* Execute PREP, then BODY for each specified value of X: A1...A2, B1...B2,
1180 C1...C2, in each case not including the second value. */
1181 #define UNROLL_3_LOOPS(X, A1, A2, B1, B2, C1, C2, BODY) \
1184 UNROLL_LOOP (X, A1, A2, BODY); \
1185 UNROLL_LOOP (X, B1, B2, BODY); \
1186 UNROLL_LOOP (X, C1, C2, BODY); \
1190 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1191 X2 and row Y2 are not included in the rectangle, at the current
1192 position on the current output device. Draws headers as well. */
1194 tabi_render (int x1, int y1, int x2, int y2)
1200 if (!(t->flags & SOMF_NO_TITLE))
1201 y += d->font_height;
1202 UNROLL_3_LOOPS (r, 0, t->t * 2 + 1, y1 * 2 + 1, y2 * 2,
1203 (t->nr - t->b) * 2, t->nr * 2 + 1,
1206 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1207 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1208 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1209 t->nc * 2 + 1, y1, y2);
1210 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1214 struct som_table_class tab_table_class =
1237 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1238 on row R, at location (X,Y). Return width of the strip thus
1241 Renders joined cells, even those outside the strip, within the
1242 rendering region (C1,R1)-(C2,R2).
1244 For the purposes of counting rows and columns in this function
1245 only, horizontal rules are considered rows and vertical rules are
1248 FIXME: Doesn't use r1? Huh? */
1250 render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
1254 /* Horizontal rules. */
1257 int hrh = t->hrh[r / 2];
1260 for (c = c1; c < c2; c++)
1264 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1268 const struct color clr = {0, 0, 0, 0};
1273 rct.x2 = x + t->w[c / 2];
1275 d->class->line_horz (d, &rct, &clr, style);
1279 const struct color clr = {0, 0, 0, 0};
1281 struct outp_styles s;
1285 rct.x2 = x + t->wrv[c / 2];
1288 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1289 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1290 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1291 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1293 if (s.t | s.b | s.l | s.r)
1294 d->class->line_intersection (d, &rct, &clr, &s);
1302 for (c = c1; c < c2; c++)
1306 const int index = (c / 2) + (r / 2 * t->cf);
1308 if (!(t->ct[index] & TAB_JOIN))
1310 struct outp_text text;
1312 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1313 | OUTP_T_HORZ | OUTP_T_VERT);
1314 if ((t->ct[index] & TAB_EMPTY) == 0)
1316 text.s = t->cc[index];
1317 assert (!ls_null_p (&text.s));
1318 text.h = t->w[c / 2];
1319 text.v = t->h[r / 2];
1322 d->class->text_draw (d, &text);
1325 struct tab_joined_cell *j =
1326 (struct tab_joined_cell *) ls_value (&t->cc[index]);
1328 if (j->hit != tab_hit)
1332 if (j->x1 == c / 2 && j->y1 == r / 2
1333 && j->x2 <= c2 && j->y2 <= r2)
1335 struct outp_text text;
1337 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1338 | OUTP_T_HORZ | OUTP_T_VERT);
1339 text.s = j->contents;
1346 for (c = j->x1, text.h = -t->wrv[j->x2];
1348 text.h += t->w[c] + t->wrv[c + 1];
1354 for (r = j->y1, text.v = -t->hrh[j->y2];
1356 text.v += t->h[r] + t->hrh[r + 1];
1358 d->class->text_draw (d, &text);
1364 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1368 const struct color clr = {0, 0, 0, 0};
1373 rct.x2 = x + t->wrv[c / 2];
1374 rct.y2 = y + t->h[r / 2];
1375 d->class->line_vert (d, &rct, &clr, style);
1382 return x - x_origin;