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
37 #include "debug-print.h"
39 struct som_table_class tab_table_class;
41 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
42 nonzero then the table's size can be increased later; otherwise,
43 its size can only be reduced. */
45 tab_create (int nc, int nr, int reallocable)
47 void *(*alloc_func) (struct pool *, size_t);
52 struct pool *container = pool_create ();
53 t = pool_alloc (container, sizeof *t);
54 t->container = container;
57 t->col_style = TAB_COL_NONE;
63 t->l = t->r = t->t = t->b = 0;
65 alloc_func = reallocable ? pool_malloc : pool_alloc;
67 t->reallocable = reallocable;
70 t->cc = alloc_func (t->container, nr * nc * sizeof *t->cc);
71 t->ct = alloc_func (t->container, nr * nc);
72 memset (t->ct, TAB_EMPTY, nc * nr);
74 t->rh = alloc_func (t->container, nc * (nr + 1));
75 memset (t->rh, 0, nc * (nr + 1));
77 t->hrh = alloc_func (t->container, sizeof *t->hrh * (nr + 1));
78 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
80 t->trh = alloc_func (t->container, nr + 1);
81 memset (t->trh, 0, nr + 1);
83 t->rv = alloc_func (t->container, (nc + 1) * nr);
84 memset (t->rv, 0, (nc + 1) * nr);
86 t->wrv = alloc_func (t->container, sizeof *t->wrv * (nc + 1));
87 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
89 t->trv = alloc_func (t->container, nc + 1);
90 memset (t->trv, 0, nc + 1);
94 t->col_ofs = t->row_ofs = 0;
99 /* Destroys table T. */
101 tab_destroy (struct tab_table *t)
104 pool_destroy (t->container);
108 /* Sets the width and height of a table, in columns and rows,
109 respectively. Use only to reduce the size of a table, since it
110 does not change the amount of allocated memory. */
112 tab_resize (struct tab_table *t, int nc, int nr)
117 assert (nc + t->col_ofs <= t->cf);
118 t->nc = nc + t->col_ofs;
122 assert (nr + t->row_ofs <= t->nr);
123 t->nr = nr + t->row_ofs;
127 /* Changes either or both dimensions of a table. Consider using the
128 above routine instead if it won't waste a lot of space.
130 Changing the number of columns in a table is particularly expensive
131 in space and time. Avoid doing such. FIXME: In fact, transferring
132 of rules isn't even implemented yet. */
134 tab_realloc (struct tab_table *t, int nc, int nr)
140 assert (t->reallocable);
145 tab_offset (t, 0, 0);
152 assert (nc == t->nc);
156 int mr1 = min (nr, t->nr);
157 int mc1 = min (nc, t->nc);
159 struct fixed_string *new_cc;
160 unsigned char *new_ct;
163 new_cc = pool_malloc (t->container, nr * nc * sizeof *new_cc);
164 new_ct = pool_malloc (t->container, nr * nc);
165 for (r = 0; r < mr1; r++)
167 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
168 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
169 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
171 pool_free (t->container, t->cc);
172 pool_free (t->container, t->ct);
177 else if (nr != t->nr)
179 t->cc = pool_realloc (t->container, t->cc, nr * nc * sizeof *t->cc);
180 t->ct = pool_realloc (t->container, t->ct, nr * nc);
182 t->rh = pool_realloc (t->container, t->rh, nc * (nr + 1));
183 t->rv = pool_realloc (t->container, t->rv, (nc + 1) * nr);
184 t->trh = pool_realloc (t->container, t->trh, nr + 1);
185 t->hrh = pool_realloc (t->container, t->hrh,
186 sizeof *t->hrh * (nr + 1));
190 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
191 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
192 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
196 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
202 tab_offset (t, co, ro);
205 /* Sets the number of header rows on each side of TABLE to L on the
206 left, R on the right, T on the top, B on the bottom. Header rows
207 are repeated when a table is broken across multiple columns or
210 tab_headers (struct tab_table *table, int l, int r, int t, int b)
212 assert (table != NULL);
213 assert (l < table->nc);
214 assert (r < table->nc);
215 assert (t < table->nr);
216 assert (b < table->nr);
225 /* Set up table T so that, when it is an appropriate size, it will be
226 displayed across the page in columns.
228 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
231 tab_columns (struct tab_table *t, int style, int group)
234 t->col_style = style;
235 t->col_group = group;
240 /* Draws a vertical line to the left of cells at horizontal position X
241 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
243 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
250 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
251 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
252 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
254 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
255 "table size (%d,%d)\n"),
256 x, t->col_ofs, x + t->col_ofs,
257 y1, t->row_ofs, y1 + t->row_ofs,
258 y2, t->row_ofs, y2 + t->row_ofs,
272 assert (y2 <= t->nr);
276 if ((style & TAL_SPACING) == 0)
277 for (y = y1; y <= y2; y++)
278 t->rv[x + (t->cf + 1) * y] = style;
279 t->trv[x] |= (1 << (style & ~TAL_SPACING));
283 /* Draws a horizontal line above cells at vertical position Y from X1
284 to X2 inclusive in style STYLE, if style is not -1. */
286 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
304 if ((style & TAL_SPACING) == 0)
305 for (x = x1; x <= x2; x++)
306 t->rh[x + t->cf * y] = style;
307 t->trh[y] |= (1 << (style & ~TAL_SPACING));
311 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
312 lines of style F_H and vertical lines of style F_V. Fills the
313 interior of the box with horizontal lines of style I_H and vertical
314 lines of style I_V. Any of the line styles may be -1 to avoid
315 drawing those lines. This is distinct from 0, which draws a null
318 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
319 int x1, int y1, int x2, int y2)
324 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
325 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
326 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
327 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
329 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
330 "in table size (%d,%d)\n"),
331 x1, t->col_ofs, x1 + t->col_ofs,
332 y1, t->row_ofs, y1 + t->row_ofs,
333 x2, t->col_ofs, x2 + t->col_ofs,
334 y2, t->row_ofs, y2 + t->row_ofs,
355 if ((f_h & TAL_SPACING) == 0)
356 for (x = x1; x <= x2; x++)
358 t->rh[x + t->cf * y1] = f_h;
359 t->rh[x + t->cf * (y2 + 1)] = f_h;
361 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
362 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
367 if ((f_v & TAL_SPACING) == 0)
368 for (y = y1; y <= y2; y++)
370 t->rv[x1 + (t->cf + 1) * y] = f_v;
371 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
373 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
374 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
381 for (y = y1 + 1; y <= y2; y++)
385 if ((i_h & TAL_SPACING) == 0)
386 for (x = x1; x <= x2; x++)
387 t->rh[x + t->cf * y] = i_h;
389 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
396 for (x = x1 + 1; x <= x2; x++)
400 if ((i_v & TAL_SPACING) == 0)
401 for (y = y1; y <= y2; y++)
402 t->rv[x + (t->cf + 1) * y] = i_v;
404 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
409 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
410 the resultant string into S in TABLE's pool. */
412 text_format (struct tab_table *table, int opt, const char *text, va_list args,
413 struct fixed_string *s)
417 assert (table != NULL && text != NULL && s != NULL);
419 if (opt & TAT_PRINTF)
421 char *temp_buf = local_alloc (1024);
423 len = nvsprintf (temp_buf, text, args);
429 ls_create_buffer (s, text, len);
430 pool_register (table->container, free, s->string);
432 if (opt & TAT_PRINTF)
436 /* Set the title of table T to TITLE, which is formatted with printf
437 if FORMAT is nonzero. */
439 tab_title (struct tab_table *t, int format, const char *title, ...)
443 assert (t != NULL && title != NULL);
444 va_start (args, title);
445 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
449 /* Set DIM_FUNC as the dimension function for table T. */
451 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
453 assert (t != NULL && t->dim == NULL);
457 /* Returns the natural width of column C in table T for driver D, that
458 is, the smallest width necessary to display all its cells without
459 wrapping. The width will be no larger than the page width minus
460 left and right rule widths. */
462 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
466 assert (t != NULL && c >= 0 && c < t->nc);
470 for (width = r = 0; r < t->nr; r++)
472 struct outp_text text;
473 unsigned char opt = t->ct[c + r * t->cf];
475 if (opt & (TAB_JOIN | TAB_EMPTY))
478 text.s = t->cc[c + r * t->cf];
479 assert (!ls_null_p (&text.s));
480 text.options = OUTP_T_JUST_LEFT;
482 d->class->text_metrics (d, &text);
490 width = d->prop_em_width * 8;
492 printf ("warning: table column %d contains no data.\n", c);
497 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
506 /* Returns the natural height of row R in table T for driver D, that
507 is, the minimum height necessary to display the information in the
508 cell at the widths set for each column. */
510 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
514 assert (t != NULL && r >= 0 && r < t->nr);
519 for (height = d->font_height, c = 0; c < t->nc; c++)
521 struct outp_text text;
522 unsigned char opt = t->ct[c + r * t->cf];
524 assert (t->w[c] != NOT_INT);
525 if (opt & (TAB_JOIN | TAB_EMPTY))
528 text.s = t->cc[c + r * t->cf];
529 assert (!ls_null_p (&text.s));
530 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
532 d->class->text_metrics (d, &text);
542 /* Callback function to set all columns and rows to their natural
543 dimensions. Not really meant to be called directly. */
545 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
551 for (i = 0; i < t->nc; i++)
552 t->w[i] = tab_natural_width (t, d, i);
554 for (i = 0; i < t->nr; i++)
555 t->h[i] = tab_natural_height (t, d, i);
561 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
562 from V, displayed with format spec F. */
564 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
565 const union value *v, const struct fmt_spec *f)
569 assert (table != NULL && v != NULL && f != NULL);
571 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
572 || c + table->col_ofs >= table->nc
573 || r + table->row_ofs >= table->nr)
575 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
577 c, table->col_ofs, c + table->col_ofs,
578 r, table->row_ofs, r + table->row_ofs,
579 table->nc, table->nr);
584 contents = pool_alloc (table->container, f->w);
585 ls_init (&table->cc[c + r * table->cf], contents, f->w);
586 table->ct[c + r * table->cf] = opt;
588 data_out (contents, f, v);
591 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
592 with NDEC decimal places. */
594 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
595 double val, int w, int d)
601 union value double_value;
603 assert (table != NULL && w <= 40);
606 assert (c < table->nc);
608 assert (r < table->nr);
610 f = make_output_format (FMT_F, w, d);
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 double_value.f = val;
627 data_out (buf, &f, &double_value);
630 while (isspace ((unsigned char) *cp) && cp < &buf[w])
632 f.w = w - (cp - buf);
634 contents = pool_alloc (table->container, f.w);
635 ls_init (&table->cc[c + r * table->cf], contents, f.w);
636 table->ct[c + r * table->cf] = opt;
637 memcpy (contents, cp, f.w);
640 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
643 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
647 assert (table != NULL && text != NULL);
651 assert (c < table->nc);
652 assert (r < table->nr);
656 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
657 || c + table->col_ofs >= table->nc
658 || r + table->row_ofs >= table->nr)
660 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
662 c, table->col_ofs, c + table->col_ofs,
663 r, table->row_ofs, r + table->row_ofs,
664 table->nc, table->nr);
669 va_start (args, text);
670 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
671 table->ct[c + r * table->cf] = opt;
675 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
676 options OPT to have text value TEXT. */
678 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
679 unsigned opt, const char *text, ...)
681 struct tab_joined_cell *j;
683 assert (table != NULL && text != NULL);
685 assert (x1 + table->col_ofs >= 0);
686 assert (y1 + table->row_ofs >= 0);
689 assert (y2 + table->row_ofs < table->nr);
690 assert (x2 + table->col_ofs < table->nc);
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 fixed_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 fixed_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 if (d->class->text_set_font_by_name != NULL)
824 d->class->text_set_font_by_name (d, "FIXED");
832 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
833 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
834 if (options & TAT_NOWRAP)
835 tab_dim (t, nowrap_dim);
837 tab_dim (t, wrap_dim);
840 if (options & TAT_FIX)
842 struct outp_driver *d;
844 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
845 if (d->class->text_set_font_by_name != NULL)
846 d->class->text_set_font_by_name (d, "PROP");
853 if (options & TAT_PRINTF)
857 /* Set table flags to FLAGS. */
859 tab_flags (struct tab_table *t, unsigned flags)
865 /* Easy, type-safe way to submit a tab table to som. */
867 tab_submit (struct tab_table *t)
872 s.class = &tab_table_class;
881 /* Set table row and column offsets for all functions that affect
884 tab_offset (struct tab_table *t, int col, int row)
890 if (row < -1 || row >= t->nr)
892 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
895 if (col < -1 || col >= t->nc)
897 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
903 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
905 diff += (col - t->col_ofs), t->col_ofs = col;
911 /* Increment the row offset by one. If the table is too small,
912 increase its size. */
914 tab_next_row (struct tab_table *t)
919 if (++t->row_ofs >= t->nr)
920 tab_realloc (t, -1, t->nr * 4 / 3);
923 static struct tab_table *t;
924 static struct outp_driver *d;
927 /* Set the current table to TABLE. */
929 tabi_table (struct som_entity *table)
931 assert (table != NULL);
932 assert (table->type == SOM_TABLE);
935 tab_offset (t, 0, 0);
937 assert (t->w == NULL && t->h == NULL);
938 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
939 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
942 /* Set the current output device to DRIVER. */
944 tabi_driver (struct outp_driver *driver)
948 assert (driver != NULL);
951 /* Figure out sizes of rules. */
952 for (t->hr_tot = i = 0; i <= t->nr; i++)
953 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
954 for (t->vr_tot = i = 0; i <= t->nc; i++)
955 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
958 for (i = 0; i < t->nr; i++)
960 for (i = 0; i < t->nc; i++)
964 assert (t->dim != NULL);
971 for (i = 0; i < t->nr; i++)
975 printf ("Table row %d height not initialized.\n", i);
978 assert (t->h[i] > 0);
981 for (i = 0; i < t->nc; i++)
985 printf ("Table column %d width not initialized.\n", i);
988 assert (t->w[i] > 0);
993 /* Add up header sizes. */
994 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
995 t->wl += t->w[i] + t->wrv[i + 1];
996 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
997 t->ht += t->h[i] + t->hrh[i + 1];
998 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
999 t->wr += t->w[i] + t->wrv[i + 1];
1000 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1001 t->hb += t->h[i] + t->hrh[i + 1];
1004 if (!(t->flags & SOMF_NO_TITLE))
1005 t->ht += d->font_height;
1008 /* Return the number of columns and rows in the table into N_COLUMNS
1009 and N_ROWS, respectively. */
1011 tabi_count (int *n_columns, int *n_rows)
1013 assert (n_columns != NULL && n_rows != NULL);
1018 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1020 /* Return the horizontal and vertical size of the entire table,
1021 including headers, for the current output device, into HORIZ and
1024 tabi_area (int *horiz, int *vert)
1026 assert (horiz != NULL && vert != NULL);
1031 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1032 c < t->nc - t->r; c++)
1033 w += t->w[c] + t->wrv[c];
1039 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1040 r < t->nr - t->b; r++)
1041 h += t->h[r] + t->hrh[r];
1046 /* Return the column style for this table into STYLE. */
1048 tabi_columns (int *style)
1050 assert (style != NULL);
1051 *style = t->col_style;
1054 /* Return the number of header rows/columns on the left, right, top,
1055 and bottom sides into HL, HR, HT, and HB, respectively. */
1057 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1059 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1066 /* Determines the number of rows or columns (including appropriate
1067 headers), depending on CUMTYPE, that will fit into the space
1068 specified. Takes rows/columns starting at index START and attempts
1069 to fill up available space MAX. Returns in END the index of the
1070 last row/column plus one; returns in ACTUAL the actual amount of
1071 space the selected rows/columns (including appropriate headers)
1074 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1081 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1082 if (cumtype == SOM_ROWS)
1084 assert (start >= 0 && start < t->nr);
1087 r = &t->hrh[start + 1];
1088 total = t->ht + t->hb;
1090 assert (start >= 0 && start < t->nc);
1093 r = &t->wrv[start + 1];
1094 total = t->wl + t->wr;
1110 for (x = start + 1; x < n; x++)
1112 int amt = *d++ + *r++;
1130 /* Return flags set for the current table into FLAGS. */
1132 tabi_flags (unsigned *flags)
1134 assert (flags != NULL);
1138 /* Returns true if the table will fit in the given page WIDTH,
1141 tabi_fits_width (int width)
1145 for (i = t->l; i < t->nc - t->r; i++)
1146 if (t->wl + t->wr + t->w[i] > width)
1152 /* Returns true if the table will fit in the given page LENGTH,
1155 tabi_fits_length (int length)
1159 for (i = t->t; i < t->nr - t->b; i++)
1160 if (t->ht + t->hb + t->h[i] > length)
1166 /* Sets the number of header rows/columns on the left, right, top,
1167 and bottom sides to HL, HR, HT, and HB, respectively. */
1169 tabi_set_headers (int hl, int hr, int ht, int hb)
1177 /* Render title for current table, with major index X and minor index
1178 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1181 tabi_title (int x, int y)
1186 if (t->flags & SOMF_NO_TITLE)
1189 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1191 cp = spprintf (cp, "(%d:%d)", x, y);
1193 cp = spprintf (cp, "(%d)", x);
1195 cp = spprintf (cp, " %s", cur_proc);
1196 cp = stpcpy (cp, ". ");
1197 if (!ls_empty_p (&t->title))
1199 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1200 cp += ls_length (&t->title);
1205 struct outp_text text;
1207 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1208 ls_init (&text.s, buf, cp - buf);
1210 text.v = d->font_height;
1213 d->class->text_draw (d, &text);
1217 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1219 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1220 X2 and row Y2 are not included in the rectangle, at the current
1221 position on the current output device. Draws headers as well. */
1223 tabi_render (int x1, int y1, int x2, int y2)
1231 if (!(t->flags & SOMF_NO_TITLE))
1232 y += d->font_height;
1236 ranges[0][1] = t->t * 2 + 1;
1238 /* Requested rows. */
1239 ranges[1][0] = y1 * 2 + 1;
1240 ranges[1][1] = y2 * 2;
1242 /* Bottom headers. */
1243 ranges[2][0] = (t->nr - t->b) * 2;
1244 ranges[2][1] = t->nr * 2 + 1;
1246 for (i = 0; i < 3; i++)
1250 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1253 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1254 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1255 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1256 t->nc * 2 + 1, y1, y2);
1257 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1262 struct som_table_class tab_table_class =
1288 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1289 on row R, at location (X,Y). Return width of the strip thus
1292 Renders joined cells, even those outside the strip, within the
1293 rendering region (C1,R1)-(C2,R2).
1295 For the purposes of counting rows and columns in this function
1296 only, horizontal rules are considered rows and vertical rules are
1299 FIXME: Doesn't use r1? Huh? */
1301 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1305 /* Horizontal rules. */
1308 int hrh = t->hrh[r / 2];
1311 for (c = c1; c < c2; c++)
1315 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1319 const struct color clr = {0, 0, 0, 0};
1324 rct.x2 = x + t->w[c / 2];
1326 d->class->line_horz (d, &rct, &clr, style);
1330 const struct color clr = {0, 0, 0, 0};
1332 struct outp_styles s;
1336 rct.x2 = x + t->wrv[c / 2];
1339 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1340 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1341 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1342 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1344 if (s.t | s.b | s.l | s.r)
1345 d->class->line_intersection (d, &rct, &clr, &s);
1353 for (c = c1; c < c2; c++)
1357 const int index = (c / 2) + (r / 2 * t->cf);
1359 if (!(t->ct[index] & TAB_JOIN))
1361 struct outp_text text;
1363 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1364 | OUTP_T_HORZ | OUTP_T_VERT);
1365 if ((t->ct[index] & TAB_EMPTY) == 0)
1367 text.s = t->cc[index];
1368 assert (!ls_null_p (&text.s));
1369 text.h = t->w[c / 2];
1370 text.v = t->h[r / 2];
1373 d->class->text_draw (d, &text);
1376 struct tab_joined_cell *j =
1377 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1379 if (j->hit != tab_hit)
1383 if (j->x1 == c / 2 && j->y1 == r / 2)
1385 struct outp_text text;
1387 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1388 | OUTP_T_HORZ | OUTP_T_VERT);
1389 text.s = j->contents;
1396 for (c = j->x1, text.h = -t->wrv[j->x2];
1397 c < j->x2 && c < c2 / 2; c++)
1398 text.h += t->w[c] + t->wrv[c + 1];
1404 for (r = j->y1, text.v = -t->hrh[j->y2];
1405 r < j->y2 && r < r2 / 2; r++)
1406 text.v += t->h[r] + t->hrh[r + 1];
1408 d->class->text_draw (d, &text);
1414 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1418 const struct color clr = {0, 0, 0, 0};
1423 rct.x2 = x + t->wrv[c / 2];
1424 rct.y2 = y + t->h[r / 2];
1425 d->class->line_vert (d, &rct, &clr, style);
1432 return x - x_origin;