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);
137 /* Sets the width and height of a table, in columns and rows,
138 respectively. Use only to reduce the size of a table, since it
139 does not change the amount of allocated memory. */
141 tab_resize (struct tab_table *t, int nc, int nr)
146 assert (nc + t->col_ofs <= t->cf);
147 t->nc = nc + t->col_ofs;
151 assert (nr + t->row_ofs <= t->nr);
152 t->nr = nr + t->row_ofs;
156 /* Changes either or both dimensions of a table. Consider using the
157 above routine instead if it won't waste a lot of space.
159 Changing the number of columns in a table is particularly expensive
160 in space and time. Avoid doing such. FIXME: In fact, transferring
161 of rules isn't even implemented yet. */
163 tab_realloc (struct tab_table *t, int nc, int nr)
169 assert (t->reallocable);
174 tab_offset (t, 0, 0);
181 assert (nc == t->nc);
185 int mr1 = min (nr, t->nr);
186 int mc1 = min (nc, t->nc);
188 struct len_string *new_cc;
189 unsigned char *new_ct;
192 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
193 new_ct = pool_malloc (t->container, nr * nc);
194 for (r = 0; r < mr1; r++)
196 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
197 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
198 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
200 pool_free (t->container, t->cc);
201 pool_free (t->container, t->ct);
206 else if (nr != t->nr)
208 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
209 t->ct = pool_realloc (t->container, t->ct, nr * nc);
211 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
212 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
213 t->trh = pool_realloc (t->container, t->trh, nr + 1);
214 t->hrh = pool_realloc (t->container, t->hrh,
215 sizeof *t->hrh * (nr + 1));
219 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
220 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
221 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
225 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
231 tab_offset (t, co, ro);
234 /* Sets the number of header rows on each side of TABLE to L on the
235 left, R on the right, T on the top, B on the bottom. Header rows
236 are repeated when a table is broken across multiple columns or
239 tab_headers (struct tab_table *table, int l, int r, int t, int b)
241 assert (table != NULL);
248 /* Set up table T so that, when it is an appropriate size, it will be
249 displayed across the page in columns.
251 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
254 tab_columns (struct tab_table *t, int style, int group)
257 t->col_style = style;
258 t->col_group = group;
263 /* Draws a vertical line to the left of cells at horizontal position X
264 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
266 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
272 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
273 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
274 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
276 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
277 "table size (%d,%d)\n"),
278 x, t->col_ofs, x + t->col_ofs,
279 y1, t->row_ofs, y1 + t->row_ofs,
280 y2, t->row_ofs, y2 + t->row_ofs,
292 if ((style & TAL_SPACING) == 0)
293 for (y = y1; y <= y2; y++)
294 t->rv[x + (t->cf + 1) * y] = style;
295 t->trv[x] |= (1 << (style & ~TAL_SPACING));
299 /* Draws a horizontal line above cells at vertical position Y from X1
300 to X2 inclusive in style STYLE, if style is not -1. */
302 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
308 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
309 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
310 || y + t->row_ofs < 0 || y + t->row_ofs > t->nr)
312 printf (_("bad hline: x=(%d+%d=%d,%d+%d=%d) y=%d+%d=%d "
313 "in table size (%d,%d)\n"),
314 x1, t->col_ofs, x1 + t->col_ofs,
315 x2, t->col_ofs, x2 + t->col_ofs,
316 y, t->row_ofs, y + t->row_ofs,
328 if ((style & TAL_SPACING) == 0)
329 for (x = x1; x <= x2; x++)
330 t->rh[x + t->cf * y] = style;
331 t->trh[y] |= (1 << (style & ~TAL_SPACING));
335 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
336 lines of style F_H and vertical lines of style F_V. Fills the
337 interior of the box with horizontal lines of style I_H and vertical
338 lines of style I_V. Any of the line styles may be -1 to avoid
339 drawing those lines. This is distinct from 0, which draws a null
342 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
343 int x1, int y1, int x2, int y2)
347 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
348 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
349 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
350 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
352 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
353 "in table size (%d,%d)\n"),
354 x1, t->col_ofs, x1 + t->col_ofs,
355 y1, t->row_ofs, y1 + t->row_ofs,
356 x2, t->col_ofs, x2 + t->col_ofs,
357 y2, t->row_ofs, y2 + t->row_ofs,
371 if ((f_h & TAL_SPACING) == 0)
372 for (x = x1; x <= x2; x++)
374 t->rh[x + t->cf * y1] = f_h;
375 t->rh[x + t->cf * (y2 + 1)] = f_h;
377 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
378 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
383 if ((f_v & TAL_SPACING) == 0)
384 for (y = y1; y <= y2; y++)
386 t->rv[x1 + (t->cf + 1) * y] = f_v;
387 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
389 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
390 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
397 for (y = y1 + 1; y <= y2; y++)
401 if ((i_h & TAL_SPACING) == 0)
402 for (x = x1; x <= x2; x++)
403 t->rh[x + t->cf * y] = i_h;
405 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
412 for (x = x1 + 1; x <= x2; x++)
416 if ((i_v & TAL_SPACING) == 0)
417 for (y = y1; y <= y2; y++)
418 t->rv[x + (t->cf + 1) * y] = i_v;
420 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
425 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
426 the resultant string into S in TABLE's pool. */
428 text_format (struct tab_table *table, int opt, const char *text, va_list args,
429 struct len_string *s)
433 assert (table != NULL && text != NULL && s != NULL);
435 if (opt & TAT_PRINTF)
437 char *temp_buf = local_alloc (1024);
439 len = nvsprintf (temp_buf, text, args);
445 ls_create_buffer (table->container, s, text, len);
447 if (opt & TAT_PRINTF)
451 /* Set the title of table T to TITLE, which is formatted with printf
452 if FORMAT is nonzero. */
454 tab_title (struct tab_table *t, int format, const char *title, ...)
458 assert (t != NULL && title != NULL);
459 va_start (args, title);
460 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
464 /* Set DIM_FUNC as the dimension function for table T. */
466 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
468 assert (t != NULL && t->dim == NULL);
472 /* Returns the natural width of column C in table T for driver D, that
473 is, the smallest width necessary to display all its cells without
474 wrapping. The width will be no larger than the page width minus
475 left and right rule widths. */
477 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
481 assert (t != NULL && c >= 0 && c < t->nc);
485 for (width = r = 0; r < t->nr; r++)
487 struct outp_text text;
488 unsigned char opt = t->ct[c + r * t->cf];
490 if (opt & (TAB_JOIN | TAB_EMPTY))
493 text.s = t->cc[c + r * t->cf];
494 assert (!ls_null_p (&text.s));
495 text.options = OUTP_T_JUST_LEFT;
497 d->class->text_metrics (d, &text);
505 width = d->prop_em_width * 8;
507 printf ("warning: table column %d contains no data.\n", c);
512 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
521 /* Returns the natural height of row R in table T for driver D, that
522 is, the minimum height necessary to display the information in the
523 cell at the widths set for each column. */
525 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
529 assert (t != NULL && r >= 0 && r < t->nr);
534 for (height = d->font_height, c = 0; c < t->nc; c++)
536 struct outp_text text;
537 unsigned char opt = t->ct[c + r * t->cf];
539 assert (t->w[c] != NOT_INT);
540 if (opt & (TAB_JOIN | TAB_EMPTY))
543 text.s = t->cc[c + r * t->cf];
544 assert (!ls_null_p (&text.s));
545 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
547 d->class->text_metrics (d, &text);
557 /* Callback function to set all columns and rows to their natural
558 dimensions. Not really meant to be called directly. */
560 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
566 for (i = 0; i < t->nc; i++)
567 t->w[i] = tab_natural_width (t, d, i);
569 for (i = 0; i < t->nr; i++)
570 t->h[i] = tab_natural_height (t, d, i);
576 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
577 from V, displayed with format spec F. */
579 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
580 const union value *v, const struct fmt_spec *f)
583 union value temp_val;
585 assert (table != NULL && v != NULL && f != NULL);
587 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
588 || c + table->col_ofs >= table->nc
589 || r + table->row_ofs >= table->nr)
591 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
593 c, table->col_ofs, c + table->col_ofs,
594 r, table->row_ofs, r + table->row_ofs,
595 table->nc, table->nr);
600 contents = pool_alloc (table->container, f->w);
601 ls_init (&table->cc[c + r * table->cf], contents, f->w);
602 table->ct[c + r * table->cf] = opt;
604 if (formats[f->type].cat & FCAT_STRING)
606 temp_val.c = (char *) v->s;
609 data_out (contents, f, v);
612 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
613 with NDEC decimal places. */
615 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
616 double val, int w, int d)
623 assert (table != NULL && w <= 40);
630 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
631 || c + table->col_ofs >= table->nc
632 || r + table->row_ofs >= table->nr)
634 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
636 c, table->col_ofs, c + table->col_ofs,
637 r, table->row_ofs, r + table->row_ofs,
638 table->nc, table->nr);
643 data_out (buf, &f, (union value *) &val);
645 while (isspace ((unsigned char) *cp) && cp < &buf[w])
647 f.w = w - (cp - buf);
649 contents = pool_alloc (table->container, f.w);
650 ls_init (&table->cc[c + r * table->cf], contents, f.w);
651 table->ct[c + r * table->cf] = opt;
652 memcpy (contents, cp, f.w);
655 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
658 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
662 assert (table != NULL && text != NULL);
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 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
694 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
695 || x2 < x1 || x2 + table->col_ofs >= table->nc
696 || y2 < y2 || y2 + table->row_ofs >= table->nr)
698 printf ("tab_joint_text(): bad cell "
699 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
700 x1, table->col_ofs, x1 + table->col_ofs,
701 y1, table->row_ofs, y1 + table->row_ofs,
702 x2, table->col_ofs, x2 + table->col_ofs,
703 y2, table->row_ofs, y2 + table->row_ofs,
704 table->nc, table->nr);
709 j = pool_alloc (table->container, sizeof *j);
711 j->x1 = x1 + table->col_ofs;
712 j->y1 = y1 + table->row_ofs;
713 j->x2 = ++x2 + table->col_ofs;
714 j->y2 = ++y2 + table->row_ofs;
719 va_start (args, text);
720 text_format (table, opt, text, args, &j->contents);
727 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
728 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
729 const int ofs = table->cf - (x2 - x1);
733 for (y = y1; y < y2; y++)
737 for (x = x1; x < x2; x++)
739 ls_init (cc++, (char *) j, 0);
749 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
751 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
752 struct len_string *string)
754 assert (table != NULL && string != NULL);
757 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
758 || c + table->col_ofs >= table->nc
759 || r + table->row_ofs >= table->nr)
761 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
763 c, table->col_ofs, c + table->col_ofs,
764 r, table->row_ofs, r + table->row_ofs,
765 table->nc, table->nr);
770 table->cc[c + r * table->cf] = *string;
771 table->ct[c + r * table->cf] = opt;
776 /* Sets the widths of all the columns and heights of all the rows in
777 table T for driver D. */
779 nowrap_dim (struct tab_table *t, struct outp_driver *d)
781 t->w[0] = tab_natural_width (t, d, 0);
782 t->h[0] = d->font_height;
785 /* Sets the widths of all the columns and heights of all the rows in
786 table T for driver D. */
788 wrap_dim (struct tab_table *t, struct outp_driver *d)
790 t->w[0] = tab_natural_width (t, d, 0);
791 t->h[0] = tab_natural_height (t, d, 0);
794 /* Outputs text BUF as a table with a single cell having cell options
795 OPTIONS, which is a combination of the TAB_* and TAT_*
798 tab_output_text (int options, const char *buf, ...)
800 struct tab_table *t = tab_create (1, 1, 0);
802 assert (buf != NULL);
803 if (options & TAT_PRINTF)
806 char *temp_buf = local_alloc (4096);
808 va_start (args, buf);
809 nvsprintf (temp_buf, buf, args);
814 if (options & TAT_FIX)
816 struct outp_driver *d;
818 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
821 d->class->open_page (d);
823 d->class->text_set_font_by_name (d, "FIXED");
827 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
828 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
829 if (options & TAT_NOWRAP)
830 tab_dim (t, nowrap_dim);
832 tab_dim (t, wrap_dim);
835 if (options & TAT_FIX)
837 struct outp_driver *d;
839 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
840 d->class->text_set_font_by_name (d, "PROP");
843 if (options & TAT_PRINTF)
847 /* Set table flags to FLAGS. */
849 tab_flags (struct tab_table *t, unsigned flags)
855 /* Easy, type-safe way to submit a tab table to som. */
857 tab_submit (struct tab_table *t)
862 s.class = &tab_table_class;
870 /* Set table row and column offsets for all functions that affect
873 tab_offset (struct tab_table *t, int col, int row)
879 if (row < -1 || row >= t->nr)
881 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
884 if (col < -1 || col >= t->nc)
886 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
892 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
894 diff += (col - t->col_ofs), t->col_ofs = col;
900 /* Increment the row offset by one. If the table is too small,
901 increase its size. */
903 tab_next_row (struct tab_table *t)
908 if (++t->row_ofs >= t->nr)
909 tab_realloc (t, -1, t->nr * 4 / 3);
912 static struct tab_table *t;
913 static struct outp_driver *d;
916 /* Set the current table to TABLE. */
918 tabi_table (struct som_table *table)
920 assert (table != NULL);
922 tab_offset (t, 0, 0);
924 assert (t->w == NULL && t->h == NULL);
925 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
926 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
929 /* Set the current output device to DRIVER. */
931 tabi_driver (struct outp_driver *driver)
935 assert (driver != NULL);
938 /* Figure out sizes of rules. */
939 for (t->hr_tot = i = 0; i <= t->nr; i++)
940 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
941 for (t->vr_tot = i = 0; i <= t->nc; i++)
942 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
945 for (i = 0; i < t->nr; i++)
947 for (i = 0; i < t->nc; i++)
951 assert (t->dim != NULL);
958 for (i = 0; i < t->nr; i++)
962 printf ("Table row %d height not initialized.\n", i);
965 assert (t->h[i] > 0);
968 for (i = 0; i < t->nc; i++)
972 printf ("Table column %d width not initialized.\n", i);
975 assert (t->w[i] > 0);
980 /* Add up header sizes. */
981 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
982 t->wl += t->w[i] + t->wrv[i + 1];
983 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
984 t->ht += t->h[i] + t->hrh[i + 1];
985 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
986 t->wr += t->w[i] + t->wrv[i + 1];
987 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
988 t->hb += t->h[i] + t->hrh[i + 1];
991 if (!(t->flags & SOMF_NO_TITLE))
992 t->ht += d->font_height;
995 /* Return the number of columns and rows in the table into N_COLUMNS
996 and N_ROWS, respectively. */
998 tabi_count (int *n_columns, int *n_rows)
1000 assert (n_columns != NULL && n_rows != NULL);
1005 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1007 /* Return the horizontal and vertical size of the entire table,
1008 including headers, for the current output device, into HORIZ and
1011 tabi_area (int *horiz, int *vert)
1013 assert (horiz != NULL && vert != NULL);
1018 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1019 c < t->nc - t->r; c++)
1020 w += t->w[c] + t->wrv[c];
1026 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1027 r < t->nr - t->b; r++)
1028 h += t->h[r] + t->hrh[r];
1033 /* Return the column style for this table into STYLE. */
1035 tabi_columns (int *style)
1037 assert (style != NULL);
1038 *style = t->col_style;
1041 /* Return the number of header rows/columns on the left, right, top,
1042 and bottom sides into HL, HR, HT, and HB, respectively. */
1044 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1046 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1053 /* Determines the number of rows or columns (including appropriate
1054 headers), depending on CUMTYPE, that will fit into the space
1055 specified. Takes rows/columns starting at index START and attempts
1056 to fill up available space MAX. Returns in END the index of the
1057 last row/column plus one; returns in ACTUAL the actual amount of
1058 space the selected rows/columns (including appropriate headers)
1061 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1068 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1069 if (cumtype == SOM_ROWS)
1071 assert (start >= 0 && start < t->nr);
1074 r = &t->hrh[start + 1];
1075 total = t->ht + t->hb;
1077 assert (start >= 0 && start < t->nc);
1080 r = &t->wrv[start + 1];
1081 total = t->wl + t->wr;
1097 for (x = start + 1; x < n; x++)
1099 int amt = *d++ + *r++;
1117 /* Return flags set for the current table into FLAGS. */
1119 tabi_flags (unsigned *flags)
1121 assert (flags != NULL);
1125 /* Render title for current table, with major index X and minor index
1126 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1129 tabi_title (int x, int y)
1134 if (t->flags & SOMF_NO_TITLE)
1137 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1139 cp = spprintf (cp, "(%d:%d)", x, y);
1141 cp = spprintf (cp, "(%d)", x);
1143 cp = spprintf (cp, " %s", cur_proc);
1144 cp = stpcpy (cp, ". ");
1145 if (!ls_empty_p (&t->title))
1147 memcpy (cp, ls_value (&t->title), ls_length (&t->title));
1148 cp += ls_length (&t->title);
1153 struct outp_text text;
1155 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1156 ls_init (&text.s, buf, cp - buf);
1158 text.v = d->font_height;
1161 d->class->text_draw (d, &text);
1165 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1167 /* Execute BODY for each value of X from A to B exclusive. */
1168 #define UNROLL_LOOP(X, A, B, BODY) \
1171 for (X = A; X < B; X++) \
1178 /* Execute PREP, then BODY for each specified value of X: A1...A2, B1...B2,
1179 C1...C2, in each case not including the second value. */
1180 #define UNROLL_3_LOOPS(X, A1, A2, B1, B2, C1, C2, BODY) \
1183 UNROLL_LOOP (X, A1, A2, BODY); \
1184 UNROLL_LOOP (X, B1, B2, BODY); \
1185 UNROLL_LOOP (X, C1, C2, BODY); \
1189 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1190 X2 and row Y2 are not included in the rectangle, at the current
1191 position on the current output device. Draws headers as well. */
1193 tabi_render (int x1, int y1, int x2, int y2)
1199 if (!(t->flags & SOMF_NO_TITLE))
1200 y += d->font_height;
1201 UNROLL_3_LOOPS (r, 0, t->t * 2 + 1, y1 * 2 + 1, y2 * 2,
1202 (t->nr - t->b) * 2, t->nr * 2 + 1,
1205 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1206 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1207 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1208 t->nc * 2 + 1, y1, y2);
1209 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1213 struct som_table_class tab_table_class =
1236 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1237 on row R, at location (X,Y). Return width of the strip thus
1240 Renders joined cells, even those outside the strip, within the
1241 rendering region (C1,R1)-(C2,R2).
1243 For the purposes of counting rows and columns in this function
1244 only, horizontal rules are considered rows and vertical rules are
1247 FIXME: Doesn't use r1? Huh? */
1249 render_strip (int x, int y, int r, int c1, int c2, int r1 unused, int r2)
1253 /* Horizontal rules. */
1256 int hrh = t->hrh[r / 2];
1259 for (c = c1; c < c2; c++)
1263 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1267 const struct color clr = {0, 0, 0, 0};
1272 rct.x2 = x + t->w[c / 2];
1274 d->class->line_horz (d, &rct, &clr, style);
1278 const struct color clr = {0, 0, 0, 0};
1280 struct outp_styles s;
1284 rct.x2 = x + t->wrv[c / 2];
1287 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1288 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1289 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1290 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1292 if (s.t | s.b | s.l | s.r)
1293 d->class->line_intersection (d, &rct, &clr, &s);
1301 for (c = c1; c < c2; c++)
1305 const int index = (c / 2) + (r / 2 * t->cf);
1307 if (!(t->ct[index] & TAB_JOIN))
1309 struct outp_text text;
1311 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1312 | OUTP_T_HORZ | OUTP_T_VERT);
1313 if ((t->ct[index] & TAB_EMPTY) == 0)
1315 text.s = t->cc[index];
1316 assert (!ls_null_p (&text.s));
1317 text.h = t->w[c / 2];
1318 text.v = t->h[r / 2];
1321 d->class->text_draw (d, &text);
1324 struct tab_joined_cell *j =
1325 (struct tab_joined_cell *) ls_value (&t->cc[index]);
1327 if (j->hit != tab_hit)
1331 if (j->x1 == c / 2 && j->y1 == r / 2
1332 && j->x2 <= c2 && j->y2 <= r2)
1334 struct outp_text text;
1336 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1337 | OUTP_T_HORZ | OUTP_T_VERT);
1338 text.s = j->contents;
1345 for (c = j->x1, text.h = -t->wrv[j->x2];
1347 text.h += t->w[c] + t->wrv[c + 1];
1353 for (r = j->y1, text.v = -t->hrh[j->y2];
1355 text.v += t->h[r] + t->hrh[r + 1];
1357 d->class->text_draw (d, &text);
1363 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1367 const struct color clr = {0, 0, 0, 0};
1372 rct.x2 = x + t->wrv[c / 2];
1373 rct.y2 = y + t->h[r / 2];
1374 d->class->line_vert (d, &rct, &clr, style);
1381 return x - x_origin;