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;
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 len_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);
219 /* Set up table T so that, when it is an appropriate size, it will be
220 displayed across the page in columns.
222 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
225 tab_columns (struct tab_table *t, int style, int group)
228 t->col_style = style;
229 t->col_group = group;
234 /* Draws a vertical line to the left of cells at horizontal position X
235 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
237 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
244 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
245 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
246 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
248 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
249 "table size (%d,%d)\n"),
250 x, t->col_ofs, x + t->col_ofs,
251 y1, t->row_ofs, y1 + t->row_ofs,
252 y2, t->row_ofs, y2 + t->row_ofs,
266 assert (y2 <= t->nr);
270 if ((style & TAL_SPACING) == 0)
271 for (y = y1; y <= y2; y++)
272 t->rv[x + (t->cf + 1) * y] = style;
273 t->trv[x] |= (1 << (style & ~TAL_SPACING));
277 /* Draws a horizontal line above cells at vertical position Y from X1
278 to X2 inclusive in style STYLE, if style is not -1. */
280 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
298 if ((style & TAL_SPACING) == 0)
299 for (x = x1; x <= x2; x++)
300 t->rh[x + t->cf * y] = style;
301 t->trh[y] |= (1 << (style & ~TAL_SPACING));
305 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
306 lines of style F_H and vertical lines of style F_V. Fills the
307 interior of the box with horizontal lines of style I_H and vertical
308 lines of style I_V. Any of the line styles may be -1 to avoid
309 drawing those lines. This is distinct from 0, which draws a null
312 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
313 int x1, int y1, int x2, int y2)
318 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
319 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
320 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
321 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
323 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
324 "in table size (%d,%d)\n"),
325 x1, t->col_ofs, x1 + t->col_ofs,
326 y1, t->row_ofs, y1 + t->row_ofs,
327 x2, t->col_ofs, x2 + t->col_ofs,
328 y2, t->row_ofs, y2 + t->row_ofs,
349 if ((f_h & TAL_SPACING) == 0)
350 for (x = x1; x <= x2; x++)
352 t->rh[x + t->cf * y1] = f_h;
353 t->rh[x + t->cf * (y2 + 1)] = f_h;
355 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
356 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
361 if ((f_v & TAL_SPACING) == 0)
362 for (y = y1; y <= y2; y++)
364 t->rv[x1 + (t->cf + 1) * y] = f_v;
365 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
367 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
368 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
375 for (y = y1 + 1; y <= y2; y++)
379 if ((i_h & TAL_SPACING) == 0)
380 for (x = x1; x <= x2; x++)
381 t->rh[x + t->cf * y] = i_h;
383 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
390 for (x = x1 + 1; x <= x2; x++)
394 if ((i_v & TAL_SPACING) == 0)
395 for (y = y1; y <= y2; y++)
396 t->rv[x + (t->cf + 1) * y] = i_v;
398 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
403 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
404 the resultant string into S in TABLE's pool. */
406 text_format (struct tab_table *table, int opt, const char *text, va_list args,
407 struct len_string *s)
411 assert (table != NULL && text != NULL && s != NULL);
413 if (opt & TAT_PRINTF)
415 char *temp_buf = local_alloc (1024);
417 len = nvsprintf (temp_buf, text, args);
423 ls_create_buffer (s, text, len);
424 pool_register (table->container, free, s->string);
426 if (opt & TAT_PRINTF)
430 /* Set the title of table T to TITLE, which is formatted with printf
431 if FORMAT is nonzero. */
433 tab_title (struct tab_table *t, int format, const char *title, ...)
437 assert (t != NULL && title != NULL);
438 va_start (args, title);
439 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
443 /* Set DIM_FUNC as the dimension function for table T. */
445 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
447 assert (t != NULL && t->dim == NULL);
451 /* Returns the natural width of column C in table T for driver D, that
452 is, the smallest width necessary to display all its cells without
453 wrapping. The width will be no larger than the page width minus
454 left and right rule widths. */
456 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
460 assert (t != NULL && c >= 0 && c < t->nc);
464 for (width = r = 0; r < t->nr; r++)
466 struct outp_text text;
467 unsigned char opt = t->ct[c + r * t->cf];
469 if (opt & (TAB_JOIN | TAB_EMPTY))
472 text.s = t->cc[c + r * t->cf];
473 assert (!ls_null_p (&text.s));
474 text.options = OUTP_T_JUST_LEFT;
476 d->class->text_metrics (d, &text);
484 width = d->prop_em_width * 8;
486 printf ("warning: table column %d contains no data.\n", c);
491 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
500 /* Returns the natural height of row R in table T for driver D, that
501 is, the minimum height necessary to display the information in the
502 cell at the widths set for each column. */
504 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
508 assert (t != NULL && r >= 0 && r < t->nr);
513 for (height = d->font_height, c = 0; c < t->nc; c++)
515 struct outp_text text;
516 unsigned char opt = t->ct[c + r * t->cf];
518 assert (t->w[c] != NOT_INT);
519 if (opt & (TAB_JOIN | TAB_EMPTY))
522 text.s = t->cc[c + r * t->cf];
523 assert (!ls_null_p (&text.s));
524 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
526 d->class->text_metrics (d, &text);
536 /* Callback function to set all columns and rows to their natural
537 dimensions. Not really meant to be called directly. */
539 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
545 for (i = 0; i < t->nc; i++)
546 t->w[i] = tab_natural_width (t, d, i);
548 for (i = 0; i < t->nr; i++)
549 t->h[i] = tab_natural_height (t, d, i);
555 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
556 from V, displayed with format spec F. */
558 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
559 const union value *v, const struct fmt_spec *f)
563 assert (table != NULL && v != NULL && f != NULL);
565 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
566 || c + table->col_ofs >= table->nc
567 || r + table->row_ofs >= table->nr)
569 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
571 c, table->col_ofs, c + table->col_ofs,
572 r, table->row_ofs, r + table->row_ofs,
573 table->nc, table->nr);
578 contents = pool_alloc (table->container, f->w);
579 ls_init (&table->cc[c + r * table->cf], contents, f->w);
580 table->ct[c + r * table->cf] = opt;
582 data_out (contents, f, v);
585 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
586 with NDEC decimal places. */
588 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
589 double val, int w, int d)
595 union value double_value;
597 assert (table != NULL && w <= 40);
600 assert (c < table->nc);
602 assert (r < table->nr);
609 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
610 || c + table->col_ofs >= table->nc
611 || r + table->row_ofs >= table->nr)
613 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
615 c, table->col_ofs, c + table->col_ofs,
616 r, table->row_ofs, r + table->row_ofs,
617 table->nc, table->nr);
622 double_value.f = val;
623 data_out (buf, &f, &double_value);
626 while (isspace ((unsigned char) *cp) && cp < &buf[w])
628 f.w = w - (cp - buf);
630 contents = pool_alloc (table->container, f.w);
631 ls_init (&table->cc[c + r * table->cf], contents, f.w);
632 table->ct[c + r * table->cf] = opt;
633 memcpy (contents, cp, f.w);
636 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
639 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
643 assert (table != NULL && text != NULL);
647 assert (c < table->nc);
648 assert (r < table->nr);
652 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
653 || c + table->col_ofs >= table->nc
654 || r + table->row_ofs >= table->nr)
656 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
658 c, table->col_ofs, c + table->col_ofs,
659 r, table->row_ofs, r + table->row_ofs,
660 table->nc, table->nr);
665 va_start (args, text);
666 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
667 table->ct[c + r * table->cf] = opt;
671 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
672 options OPT to have text value TEXT. */
674 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
675 unsigned opt, const char *text, ...)
677 struct tab_joined_cell *j;
679 assert (table != NULL && text != NULL);
681 assert (x1 + table->col_ofs >= 0);
682 assert (y1 + table->row_ofs >= 0);
685 assert (y2 + table->row_ofs < table->nr);
686 assert (x2 + table->col_ofs < table->nc);
689 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
690 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
691 || x2 < x1 || x2 + table->col_ofs >= table->nc
692 || y2 < y2 || y2 + table->row_ofs >= table->nr)
694 printf ("tab_joint_text(): bad cell "
695 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
696 x1, table->col_ofs, x1 + table->col_ofs,
697 y1, table->row_ofs, y1 + table->row_ofs,
698 x2, table->col_ofs, x2 + table->col_ofs,
699 y2, table->row_ofs, y2 + table->row_ofs,
700 table->nc, table->nr);
705 j = pool_alloc (table->container, sizeof *j);
707 j->x1 = x1 + table->col_ofs;
708 j->y1 = y1 + table->row_ofs;
709 j->x2 = ++x2 + table->col_ofs;
710 j->y2 = ++y2 + table->row_ofs;
715 va_start (args, text);
716 text_format (table, opt, text, args, &j->contents);
723 struct len_string *cc = &table->cc[x1 + y1 * table->cf];
724 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
725 const int ofs = table->cf - (x2 - x1);
729 for (y = y1; y < y2; y++)
733 for (x = x1; x < x2; x++)
735 ls_init (cc++, (char *) j, 0);
745 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
747 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
748 struct len_string *string)
750 assert (table != NULL && string != NULL);
753 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
754 || c + table->col_ofs >= table->nc
755 || r + table->row_ofs >= table->nr)
757 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
759 c, table->col_ofs, c + table->col_ofs,
760 r, table->row_ofs, r + table->row_ofs,
761 table->nc, table->nr);
766 table->cc[c + r * table->cf] = *string;
767 table->ct[c + r * table->cf] = opt;
772 /* Sets the widths of all the columns and heights of all the rows in
773 table T for driver D. */
775 nowrap_dim (struct tab_table *t, struct outp_driver *d)
777 t->w[0] = tab_natural_width (t, d, 0);
778 t->h[0] = d->font_height;
781 /* Sets the widths of all the columns and heights of all the rows in
782 table T for driver D. */
784 wrap_dim (struct tab_table *t, struct outp_driver *d)
786 t->w[0] = tab_natural_width (t, d, 0);
787 t->h[0] = tab_natural_height (t, d, 0);
790 /* Outputs text BUF as a table with a single cell having cell options
791 OPTIONS, which is a combination of the TAB_* and TAT_*
794 tab_output_text (int options, const char *buf, ...)
796 struct tab_table *t = tab_create (1, 1, 0);
798 assert (buf != NULL);
799 if (options & TAT_PRINTF)
802 char *temp_buf = local_alloc (4096);
804 va_start (args, buf);
805 nvsprintf (temp_buf, buf, args);
810 if (options & TAT_FIX)
812 struct outp_driver *d;
814 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
817 d->class->open_page (d);
819 if (d->class->text_set_font_by_name != NULL)
820 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 if (d->class->text_set_font_by_name != NULL)
842 d->class->text_set_font_by_name (d, "PROP");
849 if (options & TAT_PRINTF)
853 /* Set table flags to FLAGS. */
855 tab_flags (struct tab_table *t, unsigned flags)
861 /* Easy, type-safe way to submit a tab table to som. */
863 tab_submit (struct tab_table *t)
868 s.class = &tab_table_class;
876 /* Set table row and column offsets for all functions that affect
879 tab_offset (struct tab_table *t, int col, int row)
885 if (row < -1 || row >= t->nr)
887 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
890 if (col < -1 || col >= t->nc)
892 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
898 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
900 diff += (col - t->col_ofs), t->col_ofs = col;
906 /* Increment the row offset by one. If the table is too small,
907 increase its size. */
909 tab_next_row (struct tab_table *t)
914 if (++t->row_ofs >= t->nr)
915 tab_realloc (t, -1, t->nr * 4 / 3);
918 static struct tab_table *t;
919 static struct outp_driver *d;
922 /* Set the current table to TABLE. */
924 tabi_table (struct som_table *table)
926 assert (table != NULL);
928 tab_offset (t, 0, 0);
930 assert (t->w == NULL && t->h == NULL);
931 t->w = pool_alloc (t->container, sizeof *t->w * t->nc);
932 t->h = pool_alloc (t->container, sizeof *t->h * t->nr);
935 /* Set the current output device to DRIVER. */
937 tabi_driver (struct outp_driver *driver)
941 assert (driver != NULL);
944 /* Figure out sizes of rules. */
945 for (t->hr_tot = i = 0; i <= t->nr; i++)
946 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
947 for (t->vr_tot = i = 0; i <= t->nc; i++)
948 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
951 for (i = 0; i < t->nr; i++)
953 for (i = 0; i < t->nc; i++)
957 assert (t->dim != NULL);
964 for (i = 0; i < t->nr; i++)
968 printf ("Table row %d height not initialized.\n", i);
971 assert (t->h[i] > 0);
974 for (i = 0; i < t->nc; i++)
978 printf ("Table column %d width not initialized.\n", i);
981 assert (t->w[i] > 0);
986 /* Add up header sizes. */
987 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
988 t->wl += t->w[i] + t->wrv[i + 1];
989 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
990 t->ht += t->h[i] + t->hrh[i + 1];
991 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
992 t->wr += t->w[i] + t->wrv[i + 1];
993 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
994 t->hb += t->h[i] + t->hrh[i + 1];
997 if (!(t->flags & SOMF_NO_TITLE))
998 t->ht += d->font_height;
1001 /* Return the number of columns and rows in the table into N_COLUMNS
1002 and N_ROWS, respectively. */
1004 tabi_count (int *n_columns, int *n_rows)
1006 assert (n_columns != NULL && n_rows != NULL);
1011 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1013 /* Return the horizontal and vertical size of the entire table,
1014 including headers, for the current output device, into HORIZ and
1017 tabi_area (int *horiz, int *vert)
1019 assert (horiz != NULL && vert != NULL);
1024 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1025 c < t->nc - t->r; c++)
1026 w += t->w[c] + t->wrv[c];
1032 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1033 r < t->nr - t->b; r++)
1034 h += t->h[r] + t->hrh[r];
1039 /* Return the column style for this table into STYLE. */
1041 tabi_columns (int *style)
1043 assert (style != NULL);
1044 *style = t->col_style;
1047 /* Return the number of header rows/columns on the left, right, top,
1048 and bottom sides into HL, HR, HT, and HB, respectively. */
1050 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1052 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1059 /* Determines the number of rows or columns (including appropriate
1060 headers), depending on CUMTYPE, that will fit into the space
1061 specified. Takes rows/columns starting at index START and attempts
1062 to fill up available space MAX. Returns in END the index of the
1063 last row/column plus one; returns in ACTUAL the actual amount of
1064 space the selected rows/columns (including appropriate headers)
1067 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1074 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1075 if (cumtype == SOM_ROWS)
1077 assert (start >= 0 && start < t->nr);
1080 r = &t->hrh[start + 1];
1081 total = t->ht + t->hb;
1083 assert (start >= 0 && start < t->nc);
1086 r = &t->wrv[start + 1];
1087 total = t->wl + t->wr;
1103 for (x = start + 1; x < n; x++)
1105 int amt = *d++ + *r++;
1123 /* Return flags set for the current table into FLAGS. */
1125 tabi_flags (unsigned *flags)
1127 assert (flags != NULL);
1131 /* Render title for current table, with major index X and minor index
1132 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1135 tabi_title (int x, int y)
1140 if (t->flags & SOMF_NO_TITLE)
1143 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1145 cp = spprintf (cp, "(%d:%d)", x, y);
1147 cp = spprintf (cp, "(%d)", x);
1149 cp = spprintf (cp, " %s", cur_proc);
1150 cp = stpcpy (cp, ". ");
1151 if (!ls_empty_p (&t->title))
1153 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1154 cp += ls_length (&t->title);
1159 struct outp_text text;
1161 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1162 ls_init (&text.s, buf, cp - buf);
1164 text.v = d->font_height;
1167 d->class->text_draw (d, &text);
1171 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1173 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1174 X2 and row Y2 are not included in the rectangle, at the current
1175 position on the current output device. Draws headers as well. */
1177 tabi_render (int x1, int y1, int x2, int y2)
1185 if (!(t->flags & SOMF_NO_TITLE))
1186 y += d->font_height;
1190 ranges[0][1] = t->t * 2 + 1;
1192 /* Requested rows. */
1193 ranges[1][0] = y1 * 2 + 1;
1194 ranges[1][1] = y2 * 2;
1196 /* Bottom headers. */
1197 ranges[2][0] = (t->nr - t->b) * 2;
1198 ranges[2][1] = t->nr * 2 + 1;
1200 for (i = 0; i < 3; i++)
1204 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1207 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1208 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1209 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1210 t->nc * 2 + 1, y1, y2);
1211 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1216 struct som_table_class tab_table_class =
1239 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1240 on row R, at location (X,Y). Return width of the strip thus
1243 Renders joined cells, even those outside the strip, within the
1244 rendering region (C1,R1)-(C2,R2).
1246 For the purposes of counting rows and columns in this function
1247 only, horizontal rules are considered rows and vertical rules are
1250 FIXME: Doesn't use r1? Huh? */
1252 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1256 /* Horizontal rules. */
1259 int hrh = t->hrh[r / 2];
1262 for (c = c1; c < c2; c++)
1266 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1270 const struct color clr = {0, 0, 0, 0};
1275 rct.x2 = x + t->w[c / 2];
1277 d->class->line_horz (d, &rct, &clr, style);
1281 const struct color clr = {0, 0, 0, 0};
1283 struct outp_styles s;
1287 rct.x2 = x + t->wrv[c / 2];
1290 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1291 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1292 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1293 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1295 if (s.t | s.b | s.l | s.r)
1296 d->class->line_intersection (d, &rct, &clr, &s);
1304 for (c = c1; c < c2; c++)
1308 const int index = (c / 2) + (r / 2 * t->cf);
1310 if (!(t->ct[index] & TAB_JOIN))
1312 struct outp_text text;
1314 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1315 | OUTP_T_HORZ | OUTP_T_VERT);
1316 if ((t->ct[index] & TAB_EMPTY) == 0)
1318 text.s = t->cc[index];
1319 assert (!ls_null_p (&text.s));
1320 text.h = t->w[c / 2];
1321 text.v = t->h[r / 2];
1324 d->class->text_draw (d, &text);
1327 struct tab_joined_cell *j =
1328 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1330 if (j->hit != tab_hit)
1334 if (j->x1 == c / 2 && j->y1 == r / 2)
1336 struct outp_text text;
1338 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1339 | OUTP_T_HORZ | OUTP_T_VERT);
1340 text.s = j->contents;
1347 for (c = j->x1, text.h = -t->wrv[j->x2];
1348 c < j->x2 && c < c2 / 2; c++)
1349 text.h += t->w[c] + t->wrv[c + 1];
1355 for (r = j->y1, text.v = -t->hrh[j->y2];
1356 r < j->y2 && r < r2 / 2; r++)
1357 text.v += t->h[r] + t->hrh[r + 1];
1359 d->class->text_draw (d, &text);
1365 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1369 const struct color clr = {0, 0, 0, 0};
1374 rct.x2 = x + t->wrv[c / 2];
1375 rct.y2 = y + t->h[r / 2];
1376 d->class->line_vert (d, &rct, &clr, style);
1383 return x - x_origin;