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 #define _(msgid) gettext (msgid)
39 #include "debug-print.h"
41 struct som_table_class tab_table_class;
42 static char *command_name;
44 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
45 nonzero then the table's size can be increased later; otherwise,
46 its size can only be reduced. */
48 tab_create (int nc, int nr, int reallocable)
50 void *(*alloc_func) (struct pool *, size_t n);
51 void *(*nalloc_func) (struct pool *, size_t n, size_t s);
56 struct pool *container = pool_create ();
57 t = pool_alloc (container, sizeof *t);
58 t->container = container;
61 t->col_style = TAB_COL_NONE;
67 t->l = t->r = t->t = t->b = 0;
69 nalloc_func = reallocable ? pool_nmalloc : pool_nalloc;
70 alloc_func = reallocable ? pool_malloc : pool_alloc;
72 t->reallocable = reallocable;
75 t->cc = nalloc_func (t->container, nr * nc, sizeof *t->cc);
76 t->ct = alloc_func (t->container, nr * nc);
77 memset (t->ct, TAB_EMPTY, nc * nr);
79 t->rh = nalloc_func (t->container, nc, nr + 1);
80 memset (t->rh, 0, nc * (nr + 1));
82 t->hrh = nalloc_func (t->container, nr + 1, sizeof *t->hrh);
83 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
85 t->trh = alloc_func (t->container, nr + 1);
86 memset (t->trh, 0, nr + 1);
88 t->rv = nalloc_func (t->container, nr, nc + 1);
89 memset (t->rv, 0, (nc + 1) * nr);
91 t->wrv = nalloc_func (t->container, nc + 1, sizeof *t->wrv);
92 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
94 t->trv = alloc_func (t->container, nc + 1);
95 memset (t->trv, 0, nc + 1);
99 t->col_ofs = t->row_ofs = 0;
104 /* Destroys table T. */
106 tab_destroy (struct tab_table *t)
109 pool_destroy (t->container);
113 /* Sets the width and height of a table, in columns and rows,
114 respectively. Use only to reduce the size of a table, since it
115 does not change the amount of allocated memory. */
117 tab_resize (struct tab_table *t, int nc, int nr)
122 assert (nc + t->col_ofs <= t->cf);
123 t->nc = nc + t->col_ofs;
127 assert (nr + t->row_ofs <= t->nr);
128 t->nr = nr + t->row_ofs;
132 /* Changes either or both dimensions of a table. Consider using the
133 above routine instead if it won't waste a lot of space.
135 Changing the number of columns in a table is particularly expensive
136 in space and time. Avoid doing such. FIXME: In fact, transferring
137 of rules isn't even implemented yet. */
139 tab_realloc (struct tab_table *t, int nc, int nr)
145 assert (t->reallocable);
150 tab_offset (t, 0, 0);
157 assert (nc == t->nc);
161 int mr1 = min (nr, t->nr);
162 int mc1 = min (nc, t->nc);
164 struct fixed_string *new_cc;
165 unsigned char *new_ct;
168 new_cc = pool_nmalloc (t->container, nr * nc, sizeof *new_cc);
169 new_ct = pool_malloc (t->container, nr * nc);
170 for (r = 0; r < mr1; r++)
172 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
173 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
174 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
176 pool_free (t->container, t->cc);
177 pool_free (t->container, t->ct);
182 else if (nr != t->nr)
184 t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
185 t->ct = pool_realloc (t->container, t->ct, nr * nc);
187 t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
188 t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
189 t->trh = pool_realloc (t->container, t->trh, nr + 1);
190 t->hrh = pool_nrealloc (t->container, t->hrh, nr + 1, sizeof *t->hrh);
194 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
195 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
196 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
200 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
206 tab_offset (t, co, ro);
209 /* Sets the number of header rows on each side of TABLE to L on the
210 left, R on the right, T on the top, B on the bottom. Header rows
211 are repeated when a table is broken across multiple columns or
214 tab_headers (struct tab_table *table, int l, int r, int t, int b)
216 assert (table != NULL);
217 assert (l < table->nc);
218 assert (r < table->nc);
219 assert (t < table->nr);
220 assert (b < table->nr);
229 /* Set up table T so that, when it is an appropriate size, it will be
230 displayed across the page in columns.
232 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
235 tab_columns (struct tab_table *t, int style, int group)
238 t->col_style = style;
239 t->col_group = group;
244 /* Draws a vertical line to the left of cells at horizontal position X
245 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
247 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
254 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
255 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
256 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
258 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
259 "table size (%d,%d)\n"),
260 x, t->col_ofs, x + t->col_ofs,
261 y1, t->row_ofs, y1 + t->row_ofs,
262 y2, t->row_ofs, y2 + t->row_ofs,
276 assert (y2 <= t->nr);
280 if ((style & TAL_SPACING) == 0)
281 for (y = y1; y <= y2; y++)
282 t->rv[x + (t->cf + 1) * y] = style;
283 t->trv[x] |= (1 << (style & ~TAL_SPACING));
287 /* Draws a horizontal line above cells at vertical position Y from X1
288 to X2 inclusive in style STYLE, if style is not -1. */
290 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
308 if ((style & TAL_SPACING) == 0)
309 for (x = x1; x <= x2; x++)
310 t->rh[x + t->cf * y] = style;
311 t->trh[y] |= (1 << (style & ~TAL_SPACING));
315 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
316 lines of style F_H and vertical lines of style F_V. Fills the
317 interior of the box with horizontal lines of style I_H and vertical
318 lines of style I_V. Any of the line styles may be -1 to avoid
319 drawing those lines. This is distinct from 0, which draws a null
322 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
323 int x1, int y1, int x2, int y2)
328 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
329 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
330 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
331 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
333 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
334 "in table size (%d,%d)\n"),
335 x1, t->col_ofs, x1 + t->col_ofs,
336 y1, t->row_ofs, y1 + t->row_ofs,
337 x2, t->col_ofs, x2 + t->col_ofs,
338 y2, t->row_ofs, y2 + t->row_ofs,
359 if ((f_h & TAL_SPACING) == 0)
360 for (x = x1; x <= x2; x++)
362 t->rh[x + t->cf * y1] = f_h;
363 t->rh[x + t->cf * (y2 + 1)] = f_h;
365 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
366 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
371 if ((f_v & TAL_SPACING) == 0)
372 for (y = y1; y <= y2; y++)
374 t->rv[x1 + (t->cf + 1) * y] = f_v;
375 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
377 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
378 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
385 for (y = y1 + 1; y <= y2; y++)
389 if ((i_h & TAL_SPACING) == 0)
390 for (x = x1; x <= x2; x++)
391 t->rh[x + t->cf * y] = i_h;
393 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
400 for (x = x1 + 1; x <= x2; x++)
404 if ((i_v & TAL_SPACING) == 0)
405 for (y = y1; y <= y2; y++)
406 t->rv[x + (t->cf + 1) * y] = i_v;
408 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
413 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
414 the resultant string into S in TABLE's pool. */
416 text_format (struct tab_table *table, int opt, const char *text, va_list args,
417 struct fixed_string *s)
421 assert (table != NULL && text != NULL && s != NULL);
423 if (opt & TAT_PRINTF)
425 char *temp_buf = local_alloc (1024);
427 len = nvsprintf (temp_buf, text, args);
433 ls_create_buffer (s, text, len);
434 pool_register (table->container, free, s->string);
436 if (opt & TAT_PRINTF)
440 /* Set the title of table T to TITLE, which is formatted with printf
441 if FORMAT is nonzero. */
443 tab_title (struct tab_table *t, int format, const char *title, ...)
447 assert (t != NULL && title != NULL);
448 va_start (args, title);
449 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
453 /* Set DIM_FUNC as the dimension function for table T. */
455 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
457 assert (t != NULL && t->dim == NULL);
461 /* Returns the natural width of column C in table T for driver D, that
462 is, the smallest width necessary to display all its cells without
463 wrapping. The width will be no larger than the page width minus
464 left and right rule widths. */
466 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
470 assert (t != NULL && c >= 0 && c < t->nc);
474 for (width = r = 0; r < t->nr; r++)
476 struct outp_text text;
477 unsigned char opt = t->ct[c + r * t->cf];
479 if (opt & (TAB_JOIN | TAB_EMPTY))
482 text.s = t->cc[c + r * t->cf];
483 assert (!ls_null_p (&text.s));
484 text.options = OUTP_T_JUST_LEFT;
486 d->class->text_metrics (d, &text);
494 width = d->prop_em_width * 8;
496 printf ("warning: table column %d contains no data.\n", c);
501 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
510 /* Returns the natural height of row R in table T for driver D, that
511 is, the minimum height necessary to display the information in the
512 cell at the widths set for each column. */
514 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
518 assert (t != NULL && r >= 0 && r < t->nr);
523 for (height = d->font_height, c = 0; c < t->nc; c++)
525 struct outp_text text;
526 unsigned char opt = t->ct[c + r * t->cf];
528 assert (t->w[c] != NOT_INT);
529 if (opt & (TAB_JOIN | TAB_EMPTY))
532 text.s = t->cc[c + r * t->cf];
533 assert (!ls_null_p (&text.s));
534 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
536 d->class->text_metrics (d, &text);
546 /* Callback function to set all columns and rows to their natural
547 dimensions. Not really meant to be called directly. */
549 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
555 for (i = 0; i < t->nc; i++)
556 t->w[i] = tab_natural_width (t, d, i);
558 for (i = 0; i < t->nr; i++)
559 t->h[i] = tab_natural_height (t, d, i);
565 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
566 from V, displayed with format spec F. */
568 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
569 const union value *v, const struct fmt_spec *f)
573 assert (table != NULL && v != NULL && f != NULL);
575 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
576 || c + table->col_ofs >= table->nc
577 || r + table->row_ofs >= table->nr)
579 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
581 c, table->col_ofs, c + table->col_ofs,
582 r, table->row_ofs, r + table->row_ofs,
583 table->nc, table->nr);
588 contents = pool_alloc (table->container, f->w);
589 ls_init (&table->cc[c + r * table->cf], contents, f->w);
590 table->ct[c + r * table->cf] = opt;
592 data_out (contents, f, v);
595 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
596 with NDEC decimal places. */
598 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
599 double val, int w, int d)
605 union value double_value;
607 assert (table != NULL && w <= 40);
610 assert (c < table->nc);
612 assert (r < table->nr);
614 f = make_output_format (FMT_F, w, d);
617 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
618 || c + table->col_ofs >= table->nc
619 || r + table->row_ofs >= table->nr)
621 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
623 c, table->col_ofs, c + table->col_ofs,
624 r, table->row_ofs, r + table->row_ofs,
625 table->nc, table->nr);
630 double_value.f = val;
631 data_out (buf, &f, &double_value);
634 while (isspace ((unsigned char) *cp) && cp < &buf[w])
636 f.w = w - (cp - buf);
638 contents = pool_alloc (table->container, f.w);
639 ls_init (&table->cc[c + r * table->cf], contents, f.w);
640 table->ct[c + r * table->cf] = opt;
641 memcpy (contents, cp, f.w);
644 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
647 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
651 assert (table != NULL && text != NULL);
655 assert (c < table->nc);
656 assert (r < table->nr);
660 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
661 || c + table->col_ofs >= table->nc
662 || r + table->row_ofs >= table->nr)
664 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
666 c, table->col_ofs, c + table->col_ofs,
667 r, table->row_ofs, r + table->row_ofs,
668 table->nc, table->nr);
673 va_start (args, text);
674 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
675 table->ct[c + r * table->cf] = opt;
679 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
680 options OPT to have text value TEXT. */
682 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
683 unsigned opt, const char *text, ...)
685 struct tab_joined_cell *j;
687 assert (table != NULL && text != NULL);
689 assert (x1 + table->col_ofs >= 0);
690 assert (y1 + table->row_ofs >= 0);
693 assert (y2 + table->row_ofs < table->nr);
694 assert (x2 + table->col_ofs < table->nc);
697 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
698 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
699 || x2 < x1 || x2 + table->col_ofs >= table->nc
700 || y2 < y2 || y2 + table->row_ofs >= table->nr)
702 printf ("tab_joint_text(): bad cell "
703 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
704 x1, table->col_ofs, x1 + table->col_ofs,
705 y1, table->row_ofs, y1 + table->row_ofs,
706 x2, table->col_ofs, x2 + table->col_ofs,
707 y2, table->row_ofs, y2 + table->row_ofs,
708 table->nc, table->nr);
713 j = pool_alloc (table->container, sizeof *j);
715 j->x1 = x1 + table->col_ofs;
716 j->y1 = y1 + table->row_ofs;
717 j->x2 = ++x2 + table->col_ofs;
718 j->y2 = ++y2 + table->row_ofs;
723 va_start (args, text);
724 text_format (table, opt, text, args, &j->contents);
731 struct fixed_string *cc = &table->cc[x1 + y1 * table->cf];
732 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
733 const int ofs = table->cf - (x2 - x1);
737 for (y = y1; y < y2; y++)
741 for (x = x1; x < x2; x++)
743 ls_init (cc++, (char *) j, 0);
753 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
755 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
756 struct fixed_string *string)
758 assert (table != NULL && string != NULL);
761 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
762 || c + table->col_ofs >= table->nc
763 || r + table->row_ofs >= table->nr)
765 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
767 c, table->col_ofs, c + table->col_ofs,
768 r, table->row_ofs, r + table->row_ofs,
769 table->nc, table->nr);
774 table->cc[c + r * table->cf] = *string;
775 table->ct[c + r * table->cf] = opt;
780 /* Sets the widths of all the columns and heights of all the rows in
781 table T for driver D. */
783 nowrap_dim (struct tab_table *t, struct outp_driver *d)
785 t->w[0] = tab_natural_width (t, d, 0);
786 t->h[0] = d->font_height;
789 /* Sets the widths of all the columns and heights of all the rows in
790 table T for driver D. */
792 wrap_dim (struct tab_table *t, struct outp_driver *d)
794 t->w[0] = tab_natural_width (t, d, 0);
795 t->h[0] = tab_natural_height (t, d, 0);
798 /* Outputs text BUF as a table with a single cell having cell options
799 OPTIONS, which is a combination of the TAB_* and TAT_*
802 tab_output_text (int options, const char *buf, ...)
804 struct tab_table *t = tab_create (1, 1, 0);
806 assert (buf != NULL);
807 if (options & TAT_PRINTF)
810 char *temp_buf = local_alloc (4096);
812 va_start (args, buf);
813 nvsprintf (temp_buf, buf, args);
818 if (options & TAT_FIX)
820 struct outp_driver *d;
822 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
825 d->class->open_page (d);
827 if (d->class->text_set_font_by_name != NULL)
828 d->class->text_set_font_by_name (d, "FIXED");
836 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
837 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
838 if (options & TAT_NOWRAP)
839 tab_dim (t, nowrap_dim);
841 tab_dim (t, wrap_dim);
844 if (options & TAT_FIX)
846 struct outp_driver *d;
848 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
849 if (d->class->text_set_font_by_name != NULL)
850 d->class->text_set_font_by_name (d, "PROP");
857 if (options & TAT_PRINTF)
861 /* Set table flags to FLAGS. */
863 tab_flags (struct tab_table *t, unsigned flags)
869 /* Easy, type-safe way to submit a tab table to som. */
871 tab_submit (struct tab_table *t)
876 s.class = &tab_table_class;
885 /* Set table row and column offsets for all functions that affect
888 tab_offset (struct tab_table *t, int col, int row)
894 if (row < -1 || row >= t->nr)
896 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
899 if (col < -1 || col >= t->nc)
901 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
907 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
909 diff += (col - t->col_ofs), t->col_ofs = col;
915 /* Increment the row offset by one. If the table is too small,
916 increase its size. */
918 tab_next_row (struct tab_table *t)
923 if (++t->row_ofs >= t->nr)
924 tab_realloc (t, -1, t->nr * 4 / 3);
927 static struct tab_table *t;
928 static struct outp_driver *d;
931 /* Set the current table to TABLE. */
933 tabi_table (struct som_entity *table)
935 assert (table != NULL);
936 assert (table->type == SOM_TABLE);
939 tab_offset (t, 0, 0);
941 assert (t->w == NULL && t->h == NULL);
942 t->w = pool_nalloc (t->container, t->nc, sizeof *t->w);
943 t->h = pool_nalloc (t->container, t->nr, sizeof *t->h);
946 /* Set the current output device to DRIVER. */
948 tabi_driver (struct outp_driver *driver)
952 assert (driver != NULL);
955 /* Figure out sizes of rules. */
956 for (t->hr_tot = i = 0; i <= t->nr; i++)
957 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
958 for (t->vr_tot = i = 0; i <= t->nc; i++)
959 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
962 for (i = 0; i < t->nr; i++)
964 for (i = 0; i < t->nc; i++)
968 assert (t->dim != NULL);
975 for (i = 0; i < t->nr; i++)
979 printf ("Table row %d height not initialized.\n", i);
982 assert (t->h[i] > 0);
985 for (i = 0; i < t->nc; i++)
989 printf ("Table column %d width not initialized.\n", i);
992 assert (t->w[i] > 0);
997 /* Add up header sizes. */
998 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
999 t->wl += t->w[i] + t->wrv[i + 1];
1000 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1001 t->ht += t->h[i] + t->hrh[i + 1];
1002 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1003 t->wr += t->w[i] + t->wrv[i + 1];
1004 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1005 t->hb += t->h[i] + t->hrh[i + 1];
1008 if (!(t->flags & SOMF_NO_TITLE))
1009 t->ht += d->font_height;
1012 /* Return the number of columns and rows in the table into N_COLUMNS
1013 and N_ROWS, respectively. */
1015 tabi_count (int *n_columns, int *n_rows)
1017 assert (n_columns != NULL && n_rows != NULL);
1022 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1024 /* Return the horizontal and vertical size of the entire table,
1025 including headers, for the current output device, into HORIZ and
1028 tabi_area (int *horiz, int *vert)
1030 assert (horiz != NULL && vert != NULL);
1035 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1036 c < t->nc - t->r; c++)
1037 w += t->w[c] + t->wrv[c];
1043 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1044 r < t->nr - t->b; r++)
1045 h += t->h[r] + t->hrh[r];
1050 /* Return the column style for this table into STYLE. */
1052 tabi_columns (int *style)
1054 assert (style != NULL);
1055 *style = t->col_style;
1058 /* Return the number of header rows/columns on the left, right, top,
1059 and bottom sides into HL, HR, HT, and HB, respectively. */
1061 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1063 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1070 /* Determines the number of rows or columns (including appropriate
1071 headers), depending on CUMTYPE, that will fit into the space
1072 specified. Takes rows/columns starting at index START and attempts
1073 to fill up available space MAX. Returns in END the index of the
1074 last row/column plus one; returns in ACTUAL the actual amount of
1075 space the selected rows/columns (including appropriate headers)
1078 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1085 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1086 if (cumtype == SOM_ROWS)
1088 assert (start >= 0 && start < t->nr);
1091 r = &t->hrh[start + 1];
1092 total = t->ht + t->hb;
1094 assert (start >= 0 && start < t->nc);
1097 r = &t->wrv[start + 1];
1098 total = t->wl + t->wr;
1114 for (x = start + 1; x < n; x++)
1116 int amt = *d++ + *r++;
1134 /* Return flags set for the current table into FLAGS. */
1136 tabi_flags (unsigned *flags)
1138 assert (flags != NULL);
1142 /* Returns true if the table will fit in the given page WIDTH,
1145 tabi_fits_width (int width)
1149 for (i = t->l; i < t->nc - t->r; i++)
1150 if (t->wl + t->wr + t->w[i] > width)
1156 /* Returns true if the table will fit in the given page LENGTH,
1159 tabi_fits_length (int length)
1163 for (i = t->t; i < t->nr - t->b; i++)
1164 if (t->ht + t->hb + t->h[i] > length)
1170 /* Sets the number of header rows/columns on the left, right, top,
1171 and bottom sides to HL, HR, HT, and HB, respectively. */
1173 tabi_set_headers (int hl, int hr, int ht, int hb)
1181 /* Render title for current table, with major index X and minor index
1182 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1185 tabi_title (int x, int y)
1190 if (t->flags & SOMF_NO_TITLE)
1193 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1195 cp = spprintf (cp, "(%d:%d)", x, y);
1197 cp = spprintf (cp, "(%d)", x);
1198 if (command_name != NULL)
1199 cp = spprintf (cp, " %s", command_name);
1200 cp = stpcpy (cp, ". ");
1201 if (!ls_empty_p (&t->title))
1203 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1204 cp += ls_length (&t->title);
1209 struct outp_text text;
1211 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1212 ls_init (&text.s, buf, cp - buf);
1214 text.v = d->font_height;
1217 d->class->text_draw (d, &text);
1221 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1223 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1224 X2 and row Y2 are not included in the rectangle, at the current
1225 position on the current output device. Draws headers as well. */
1227 tabi_render (int x1, int y1, int x2, int y2)
1235 if (!(t->flags & SOMF_NO_TITLE))
1236 y += d->font_height;
1240 ranges[0][1] = t->t * 2 + 1;
1242 /* Requested rows. */
1243 ranges[1][0] = y1 * 2 + 1;
1244 ranges[1][1] = y2 * 2;
1246 /* Bottom headers. */
1247 ranges[2][0] = (t->nr - t->b) * 2;
1248 ranges[2][1] = t->nr * 2 + 1;
1250 for (i = 0; i < 3; i++)
1254 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1257 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1258 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1259 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1260 t->nc * 2 + 1, y1, y2);
1261 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1266 struct som_table_class tab_table_class =
1292 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1293 on row R, at location (X,Y). Return width of the strip thus
1296 Renders joined cells, even those outside the strip, within the
1297 rendering region (C1,R1)-(C2,R2).
1299 For the purposes of counting rows and columns in this function
1300 only, horizontal rules are considered rows and vertical rules are
1303 FIXME: Doesn't use r1? Huh? */
1305 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1309 /* Horizontal rules. */
1312 int hrh = t->hrh[r / 2];
1315 for (c = c1; c < c2; c++)
1319 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1323 const struct color clr = {0, 0, 0, 0};
1328 rct.x2 = x + t->w[c / 2];
1330 d->class->line_horz (d, &rct, &clr, style);
1334 const struct color clr = {0, 0, 0, 0};
1336 struct outp_styles s;
1340 rct.x2 = x + t->wrv[c / 2];
1343 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1344 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1345 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1346 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1348 if (s.t | s.b | s.l | s.r)
1349 d->class->line_intersection (d, &rct, &clr, &s);
1357 for (c = c1; c < c2; c++)
1361 const int index = (c / 2) + (r / 2 * t->cf);
1363 if (!(t->ct[index] & TAB_JOIN))
1365 struct outp_text text;
1367 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1368 | OUTP_T_HORZ | OUTP_T_VERT);
1369 if ((t->ct[index] & TAB_EMPTY) == 0)
1371 text.s = t->cc[index];
1372 assert (!ls_null_p (&text.s));
1373 text.h = t->w[c / 2];
1374 text.v = t->h[r / 2];
1377 d->class->text_draw (d, &text);
1380 struct tab_joined_cell *j =
1381 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1383 if (j->hit != tab_hit)
1387 if (j->x1 == c / 2 && j->y1 == r / 2)
1389 struct outp_text text;
1391 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1392 | OUTP_T_HORZ | OUTP_T_VERT);
1393 text.s = j->contents;
1400 for (c = j->x1, text.h = -t->wrv[j->x2];
1401 c < j->x2 && c < c2 / 2; c++)
1402 text.h += t->w[c] + t->wrv[c + 1];
1408 for (r = j->y1, text.v = -t->hrh[j->y2];
1409 r < j->y2 && r < r2 / 2; r++)
1410 text.v += t->h[r] + t->hrh[r + 1];
1412 d->class->text_draw (d, &text);
1418 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1422 const struct color clr = {0, 0, 0, 0};
1427 rct.x2 = x + t->wrv[c / 2];
1428 rct.y2 = y + t->h[r / 2];
1429 d->class->line_vert (d, &rct, &clr, style);
1436 return x - x_origin;
1439 /* Sets COMMAND_NAME as the name of the current command,
1440 for embedding in output. */
1442 tab_set_command_name (const char *command_name_)
1444 free (command_name);
1445 command_name = command_name_ ? xstrdup (command_name_) : NULL;