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
26 #include <libpspp/message.h>
27 #include <libpspp/alloc.h>
28 #include <libpspp/compiler.h>
29 #include <data/format.h>
30 #include <libpspp/magic.h>
31 #include <libpspp/misc.h>
33 #include <libpspp/pool.h>
35 #include <data/variable.h>
38 #define _(msgid) gettext (msgid)
40 #include <libpspp/debug-print.h>
42 struct som_table_class tab_table_class;
43 static char *command_name;
45 /* Creates a table with NC columns and NR rows. If REALLOCABLE is
46 nonzero then the table's size can be increased later; otherwise,
47 its size can only be reduced. */
49 tab_create (int nc, int nr, int reallocable)
51 void *(*alloc_func) (struct pool *, size_t n);
52 void *(*nalloc_func) (struct pool *, size_t n, size_t s);
57 struct pool *container = pool_create ();
58 t = pool_alloc (container, sizeof *t);
59 t->container = container;
62 t->col_style = TAB_COL_NONE;
68 t->l = t->r = t->t = t->b = 0;
70 nalloc_func = reallocable ? pool_nmalloc : pool_nalloc;
71 alloc_func = reallocable ? pool_malloc : pool_alloc;
73 t->reallocable = reallocable;
76 t->cc = nalloc_func (t->container, nr * nc, sizeof *t->cc);
77 t->ct = alloc_func (t->container, nr * nc);
78 memset (t->ct, TAB_EMPTY, nc * nr);
80 t->rh = nalloc_func (t->container, nc, nr + 1);
81 memset (t->rh, 0, nc * (nr + 1));
83 t->hrh = nalloc_func (t->container, nr + 1, sizeof *t->hrh);
84 memset (t->hrh, 0, sizeof *t->hrh * (nr + 1));
86 t->trh = alloc_func (t->container, nr + 1);
87 memset (t->trh, 0, nr + 1);
89 t->rv = nalloc_func (t->container, nr, nc + 1);
90 memset (t->rv, 0, (nc + 1) * nr);
92 t->wrv = nalloc_func (t->container, nc + 1, sizeof *t->wrv);
93 memset (t->wrv, 0, sizeof *t->wrv * (nc + 1));
95 t->trv = alloc_func (t->container, nc + 1);
96 memset (t->trv, 0, nc + 1);
100 t->col_ofs = t->row_ofs = 0;
105 /* Destroys table T. */
107 tab_destroy (struct tab_table *t)
110 pool_destroy (t->container);
114 /* Sets the width and height of a table, in columns and rows,
115 respectively. Use only to reduce the size of a table, since it
116 does not change the amount of allocated memory. */
118 tab_resize (struct tab_table *t, int nc, int nr)
123 assert (nc + t->col_ofs <= t->cf);
124 t->nc = nc + t->col_ofs;
128 assert (nr + t->row_ofs <= t->nr);
129 t->nr = nr + t->row_ofs;
133 /* Changes either or both dimensions of a table. Consider using the
134 above routine instead if it won't waste a lot of space.
136 Changing the number of columns in a table is particularly expensive
137 in space and time. Avoid doing such. FIXME: In fact, transferring
138 of rules isn't even implemented yet. */
140 tab_realloc (struct tab_table *t, int nc, int nr)
146 assert (t->reallocable);
151 tab_offset (t, 0, 0);
158 assert (nc == t->nc);
162 int mr1 = min (nr, t->nr);
163 int mc1 = min (nc, t->nc);
165 struct fixed_string *new_cc;
166 unsigned char *new_ct;
169 new_cc = pool_nmalloc (t->container, nr * nc, sizeof *new_cc);
170 new_ct = pool_malloc (t->container, nr * nc);
171 for (r = 0; r < mr1; r++)
173 memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
174 memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
175 memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
177 pool_free (t->container, t->cc);
178 pool_free (t->container, t->ct);
183 else if (nr != t->nr)
185 t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
186 t->ct = pool_realloc (t->container, t->ct, nr * nc);
188 t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
189 t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
190 t->trh = pool_realloc (t->container, t->trh, nr + 1);
191 t->hrh = pool_nrealloc (t->container, t->hrh, nr + 1, sizeof *t->hrh);
195 memset (&t->rh[nc * (t->nr + 1)], 0, (nr - t->nr) * nc);
196 memset (&t->rv[(nc + 1) * t->nr], 0, (nr - t->nr) * (nc + 1));
197 memset (&t->trh[t->nr + 1], 0, nr - t->nr);
201 memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
207 tab_offset (t, co, ro);
210 /* Sets the number of header rows on each side of TABLE to L on the
211 left, R on the right, T on the top, B on the bottom. Header rows
212 are repeated when a table is broken across multiple columns or
215 tab_headers (struct tab_table *table, int l, int r, int t, int b)
217 assert (table != NULL);
218 assert (l < table->nc);
219 assert (r < table->nc);
220 assert (t < table->nr);
221 assert (b < table->nr);
230 /* Set up table T so that, when it is an appropriate size, it will be
231 displayed across the page in columns.
233 STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
236 tab_columns (struct tab_table *t, int style, int group)
239 t->col_style = style;
240 t->col_group = group;
245 /* Draws a vertical line to the left of cells at horizontal position X
246 from Y1 to Y2 inclusive in style STYLE, if style is not -1. */
248 tab_vline (struct tab_table *t, int style, int x, int y1, int y2)
255 if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
256 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
257 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
259 printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
260 "table size (%d,%d)\n"),
261 x, t->col_ofs, x + t->col_ofs,
262 y1, t->row_ofs, y1 + t->row_ofs,
263 y2, t->row_ofs, y2 + t->row_ofs,
277 assert (y2 <= t->nr);
281 if ((style & TAL_SPACING) == 0)
282 for (y = y1; y <= y2; y++)
283 t->rv[x + (t->cf + 1) * y] = style;
284 t->trv[x] |= (1 << (style & ~TAL_SPACING));
288 /* Draws a horizontal line above cells at vertical position Y from X1
289 to X2 inclusive in style STYLE, if style is not -1. */
291 tab_hline (struct tab_table * t, int style, int x1, int x2, int y)
309 if ((style & TAL_SPACING) == 0)
310 for (x = x1; x <= x2; x++)
311 t->rh[x + t->cf * y] = style;
312 t->trh[y] |= (1 << (style & ~TAL_SPACING));
316 /* Draws a box around cells (X1,Y1)-(X2,Y2) inclusive with horizontal
317 lines of style F_H and vertical lines of style F_V. Fills the
318 interior of the box with horizontal lines of style I_H and vertical
319 lines of style I_V. Any of the line styles may be -1 to avoid
320 drawing those lines. This is distinct from 0, which draws a null
323 tab_box (struct tab_table *t, int f_h, int f_v, int i_h, int i_v,
324 int x1, int y1, int x2, int y2)
329 if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
330 || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
331 || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
332 || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
334 printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
335 "in table size (%d,%d)\n"),
336 x1, t->col_ofs, x1 + t->col_ofs,
337 y1, t->row_ofs, y1 + t->row_ofs,
338 x2, t->col_ofs, x2 + t->col_ofs,
339 y2, t->row_ofs, y2 + t->row_ofs,
360 if ((f_h & TAL_SPACING) == 0)
361 for (x = x1; x <= x2; x++)
363 t->rh[x + t->cf * y1] = f_h;
364 t->rh[x + t->cf * (y2 + 1)] = f_h;
366 t->trh[y1] |= (1 << (f_h & ~TAL_SPACING));
367 t->trh[y2 + 1] |= (1 << (f_h & ~TAL_SPACING));
372 if ((f_v & TAL_SPACING) == 0)
373 for (y = y1; y <= y2; y++)
375 t->rv[x1 + (t->cf + 1) * y] = f_v;
376 t->rv[(x2 + 1) + (t->cf + 1) * y] = f_v;
378 t->trv[x1] |= (1 << (f_v & ~TAL_SPACING));
379 t->trv[x2 + 1] |= (1 << (f_v & ~TAL_SPACING));
386 for (y = y1 + 1; y <= y2; y++)
390 if ((i_h & TAL_SPACING) == 0)
391 for (x = x1; x <= x2; x++)
392 t->rh[x + t->cf * y] = i_h;
394 t->trh[y] |= (1 << (i_h & ~TAL_SPACING));
401 for (x = x1 + 1; x <= x2; x++)
405 if ((i_v & TAL_SPACING) == 0)
406 for (y = y1; y <= y2; y++)
407 t->rv[x + (t->cf + 1) * y] = i_v;
409 t->trv[x] |= (1 << (i_v & ~TAL_SPACING));
414 /* Formats text TEXT and arguments ARGS as indicated in OPT and sets
415 the resultant string into S in TABLE's pool. */
417 text_format (struct tab_table *table, int opt, const char *text, va_list args,
418 struct fixed_string *s)
422 assert (table != NULL && text != NULL && s != NULL);
424 if (opt & TAT_PRINTF)
426 char *temp_buf = local_alloc (1024);
428 len = nvsprintf (temp_buf, text, args);
434 ls_create_buffer (s, text, len);
435 pool_register (table->container, free, s->string);
437 if (opt & TAT_PRINTF)
441 /* Set the title of table T to TITLE, which is formatted with printf
442 if FORMAT is nonzero. */
444 tab_title (struct tab_table *t, int format, const char *title, ...)
448 assert (t != NULL && title != NULL);
449 va_start (args, title);
450 text_format (t, format ? TAT_PRINTF : TAT_NONE, title, args, &t->title);
454 /* Set DIM_FUNC as the dimension function for table T. */
456 tab_dim (struct tab_table *t, tab_dim_func *dim_func)
458 assert (t != NULL && t->dim == NULL);
462 /* Returns the natural width of column C in table T for driver D, that
463 is, the smallest width necessary to display all its cells without
464 wrapping. The width will be no larger than the page width minus
465 left and right rule widths. */
467 tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
471 assert (t != NULL && c >= 0 && c < t->nc);
475 for (width = r = 0; r < t->nr; r++)
477 struct outp_text text;
478 unsigned char opt = t->ct[c + r * t->cf];
480 if (opt & (TAB_JOIN | TAB_EMPTY))
483 text.s = t->cc[c + r * t->cf];
484 assert (!ls_null_p (&text.s));
485 text.options = OUTP_T_JUST_LEFT;
487 d->class->text_metrics (d, &text);
495 width = d->prop_em_width * 8;
497 printf ("warning: table column %d contains no data.\n", c);
502 const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
511 /* Returns the natural height of row R in table T for driver D, that
512 is, the minimum height necessary to display the information in the
513 cell at the widths set for each column. */
515 tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
519 assert (t != NULL && r >= 0 && r < t->nr);
524 for (height = d->font_height, c = 0; c < t->nc; c++)
526 struct outp_text text;
527 unsigned char opt = t->ct[c + r * t->cf];
529 assert (t->w[c] != NOT_INT);
530 if (opt & (TAB_JOIN | TAB_EMPTY))
533 text.s = t->cc[c + r * t->cf];
534 assert (!ls_null_p (&text.s));
535 text.options = OUTP_T_HORZ | OUTP_T_JUST_LEFT;
537 d->class->text_metrics (d, &text);
547 /* Callback function to set all columns and rows to their natural
548 dimensions. Not really meant to be called directly. */
550 tab_natural_dimensions (struct tab_table *t, struct outp_driver *d)
556 for (i = 0; i < t->nc; i++)
557 t->w[i] = tab_natural_width (t, d, i);
559 for (i = 0; i < t->nr; i++)
560 t->h[i] = tab_natural_height (t, d, i);
566 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
567 from V, displayed with format spec F. */
569 tab_value (struct tab_table *table, int c, int r, unsigned char opt,
570 const union value *v, const struct fmt_spec *f)
574 assert (table != NULL && v != NULL && f != NULL);
576 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
577 || c + table->col_ofs >= table->nc
578 || r + table->row_ofs >= table->nr)
580 printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
582 c, table->col_ofs, c + table->col_ofs,
583 r, table->row_ofs, r + table->row_ofs,
584 table->nc, table->nr);
589 contents = pool_alloc (table->container, f->w);
590 ls_init (&table->cc[c + r * table->cf], contents, f->w);
591 table->ct[c + r * table->cf] = opt;
593 data_out (contents, f, v);
596 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
597 with NDEC decimal places. */
599 tab_float (struct tab_table *table, int c, int r, unsigned char opt,
600 double val, int w, int d)
606 union value double_value;
608 assert (table != NULL && w <= 40);
611 assert (c < table->nc);
613 assert (r < table->nr);
615 f = make_output_format (FMT_F, w, d);
618 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
619 || c + table->col_ofs >= table->nc
620 || r + table->row_ofs >= table->nr)
622 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
624 c, table->col_ofs, c + table->col_ofs,
625 r, table->row_ofs, r + table->row_ofs,
626 table->nc, table->nr);
631 double_value.f = val;
632 data_out (buf, &f, &double_value);
635 while (isspace ((unsigned char) *cp) && cp < &buf[w])
637 f.w = w - (cp - buf);
639 contents = pool_alloc (table->container, f.w);
640 ls_init (&table->cc[c + r * table->cf], contents, f.w);
641 table->ct[c + r * table->cf] = opt;
642 memcpy (contents, cp, f.w);
645 /* Sets cell (C,R) in TABLE, with options OPT, to have text value
648 tab_text (struct tab_table *table, int c, int r, unsigned opt, const char *text, ...)
652 assert (table != NULL && text != NULL);
656 assert (c < table->nc);
657 assert (r < table->nr);
661 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
662 || c + table->col_ofs >= table->nc
663 || r + table->row_ofs >= table->nr)
665 printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
667 c, table->col_ofs, c + table->col_ofs,
668 r, table->row_ofs, r + table->row_ofs,
669 table->nc, table->nr);
674 va_start (args, text);
675 text_format (table, opt, text, args, &table->cc[c + r * table->cf]);
676 table->ct[c + r * table->cf] = opt;
680 /* Joins cells (X1,X2)-(Y1,Y2) inclusive in TABLE, and sets them with
681 options OPT to have text value TEXT. */
683 tab_joint_text (struct tab_table *table, int x1, int y1, int x2, int y2,
684 unsigned opt, const char *text, ...)
686 struct tab_joined_cell *j;
688 assert (table != NULL && text != NULL);
690 assert (x1 + table->col_ofs >= 0);
691 assert (y1 + table->row_ofs >= 0);
694 assert (y2 + table->row_ofs < table->nr);
695 assert (x2 + table->col_ofs < table->nc);
698 if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
699 || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
700 || x2 < x1 || x2 + table->col_ofs >= table->nc
701 || y2 < y2 || y2 + table->row_ofs >= table->nr)
703 printf ("tab_joint_text(): bad cell "
704 "(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
705 x1, table->col_ofs, x1 + table->col_ofs,
706 y1, table->row_ofs, y1 + table->row_ofs,
707 x2, table->col_ofs, x2 + table->col_ofs,
708 y2, table->row_ofs, y2 + table->row_ofs,
709 table->nc, table->nr);
714 j = pool_alloc (table->container, sizeof *j);
716 j->x1 = x1 + table->col_ofs;
717 j->y1 = y1 + table->row_ofs;
718 j->x2 = ++x2 + table->col_ofs;
719 j->y2 = ++y2 + table->row_ofs;
724 va_start (args, text);
725 text_format (table, opt, text, args, &j->contents);
732 struct fixed_string *cc = &table->cc[x1 + y1 * table->cf];
733 unsigned char *ct = &table->ct[x1 + y1 * table->cf];
734 const int ofs = table->cf - (x2 - x1);
738 for (y = y1; y < y2; y++)
742 for (x = x1; x < x2; x++)
744 ls_init (cc++, (char *) j, 0);
754 /* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
756 tab_raw (struct tab_table *table, int c, int r, unsigned opt,
757 struct fixed_string *string)
759 assert (table != NULL && string != NULL);
762 if (c + table->col_ofs < 0 || r + table->row_ofs < 0
763 || c + table->col_ofs >= table->nc
764 || r + table->row_ofs >= table->nr)
766 printf ("tab_float(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
768 c, table->col_ofs, c + table->col_ofs,
769 r, table->row_ofs, r + table->row_ofs,
770 table->nc, table->nr);
775 table->cc[c + r * table->cf] = *string;
776 table->ct[c + r * table->cf] = opt;
781 /* Sets the widths of all the columns and heights of all the rows in
782 table T for driver D. */
784 nowrap_dim (struct tab_table *t, struct outp_driver *d)
786 t->w[0] = tab_natural_width (t, d, 0);
787 t->h[0] = d->font_height;
790 /* Sets the widths of all the columns and heights of all the rows in
791 table T for driver D. */
793 wrap_dim (struct tab_table *t, struct outp_driver *d)
795 t->w[0] = tab_natural_width (t, d, 0);
796 t->h[0] = tab_natural_height (t, d, 0);
799 /* Outputs text BUF as a table with a single cell having cell options
800 OPTIONS, which is a combination of the TAB_* and TAT_*
803 tab_output_text (int options, const char *buf, ...)
805 struct tab_table *t = tab_create (1, 1, 0);
807 assert (buf != NULL);
808 if (options & TAT_PRINTF)
811 char *temp_buf = local_alloc (4096);
813 va_start (args, buf);
814 nvsprintf (temp_buf, buf, args);
819 if (options & TAT_FIX)
821 struct outp_driver *d;
823 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
826 d->class->open_page (d);
828 if (d->class->text_set_font_by_name != NULL)
829 d->class->text_set_font_by_name (d, "FIXED");
837 tab_text (t, 0, 0, options &~ TAT_PRINTF, buf);
838 tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
839 if (options & TAT_NOWRAP)
840 tab_dim (t, nowrap_dim);
842 tab_dim (t, wrap_dim);
845 if (options & TAT_FIX)
847 struct outp_driver *d;
849 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
850 if (d->class->text_set_font_by_name != NULL)
851 d->class->text_set_font_by_name (d, "PROP");
858 if (options & TAT_PRINTF)
862 /* Set table flags to FLAGS. */
864 tab_flags (struct tab_table *t, unsigned flags)
870 /* Easy, type-safe way to submit a tab table to som. */
872 tab_submit (struct tab_table *t)
877 s.class = &tab_table_class;
886 /* Set table row and column offsets for all functions that affect
889 tab_offset (struct tab_table *t, int col, int row)
895 if (row < -1 || row >= t->nr)
897 printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
900 if (col < -1 || col >= t->nc)
902 printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
908 diff += (row - t->row_ofs) * t->cf, t->row_ofs = row;
910 diff += (col - t->col_ofs), t->col_ofs = col;
916 /* Increment the row offset by one. If the table is too small,
917 increase its size. */
919 tab_next_row (struct tab_table *t)
924 if (++t->row_ofs >= t->nr)
925 tab_realloc (t, -1, t->nr * 4 / 3);
928 static struct tab_table *t;
929 static struct outp_driver *d;
932 /* Set the current table to TABLE. */
934 tabi_table (struct som_entity *table)
936 assert (table != NULL);
937 assert (table->type == SOM_TABLE);
940 tab_offset (t, 0, 0);
942 assert (t->w == NULL && t->h == NULL);
943 t->w = pool_nalloc (t->container, t->nc, sizeof *t->w);
944 t->h = pool_nalloc (t->container, t->nr, sizeof *t->h);
947 /* Set the current output device to DRIVER. */
949 tabi_driver (struct outp_driver *driver)
953 assert (driver != NULL);
956 /* Figure out sizes of rules. */
957 for (t->hr_tot = i = 0; i <= t->nr; i++)
958 t->hr_tot += t->hrh[i] = d->horiz_line_spacing[t->trh[i]];
959 for (t->vr_tot = i = 0; i <= t->nc; i++)
960 t->vr_tot += t->wrv[i] = d->vert_line_spacing[t->trv[i]];
963 for (i = 0; i < t->nr; i++)
965 for (i = 0; i < t->nc; i++)
969 assert (t->dim != NULL);
976 for (i = 0; i < t->nr; i++)
980 printf ("Table row %d height not initialized.\n", i);
983 assert (t->h[i] > 0);
986 for (i = 0; i < t->nc; i++)
990 printf ("Table column %d width not initialized.\n", i);
993 assert (t->w[i] > 0);
998 /* Add up header sizes. */
999 for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
1000 t->wl += t->w[i] + t->wrv[i + 1];
1001 for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
1002 t->ht += t->h[i] + t->hrh[i + 1];
1003 for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
1004 t->wr += t->w[i] + t->wrv[i + 1];
1005 for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
1006 t->hb += t->h[i] + t->hrh[i + 1];
1009 if (!(t->flags & SOMF_NO_TITLE))
1010 t->ht += d->font_height;
1013 /* Return the number of columns and rows in the table into N_COLUMNS
1014 and N_ROWS, respectively. */
1016 tabi_count (int *n_columns, int *n_rows)
1018 assert (n_columns != NULL && n_rows != NULL);
1023 static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
1025 /* Return the horizontal and vertical size of the entire table,
1026 including headers, for the current output device, into HORIZ and
1029 tabi_area (int *horiz, int *vert)
1031 assert (horiz != NULL && vert != NULL);
1036 for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
1037 c < t->nc - t->r; c++)
1038 w += t->w[c] + t->wrv[c];
1044 for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
1045 r < t->nr - t->b; r++)
1046 h += t->h[r] + t->hrh[r];
1051 /* Return the column style for this table into STYLE. */
1053 tabi_columns (int *style)
1055 assert (style != NULL);
1056 *style = t->col_style;
1059 /* Return the number of header rows/columns on the left, right, top,
1060 and bottom sides into HL, HR, HT, and HB, respectively. */
1062 tabi_headers (int *hl, int *hr, int *ht, int *hb)
1064 assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
1071 /* Determines the number of rows or columns (including appropriate
1072 headers), depending on CUMTYPE, that will fit into the space
1073 specified. Takes rows/columns starting at index START and attempts
1074 to fill up available space MAX. Returns in END the index of the
1075 last row/column plus one; returns in ACTUAL the actual amount of
1076 space the selected rows/columns (including appropriate headers)
1079 tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
1086 assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
1087 if (cumtype == SOM_ROWS)
1089 assert (start >= 0 && start < t->nr);
1092 r = &t->hrh[start + 1];
1093 total = t->ht + t->hb;
1095 assert (start >= 0 && start < t->nc);
1098 r = &t->wrv[start + 1];
1099 total = t->wl + t->wr;
1115 for (x = start + 1; x < n; x++)
1117 int amt = *d++ + *r++;
1135 /* Return flags set for the current table into FLAGS. */
1137 tabi_flags (unsigned *flags)
1139 assert (flags != NULL);
1143 /* Returns true if the table will fit in the given page WIDTH,
1146 tabi_fits_width (int width)
1150 for (i = t->l; i < t->nc - t->r; i++)
1151 if (t->wl + t->wr + t->w[i] > width)
1157 /* Returns true if the table will fit in the given page LENGTH,
1160 tabi_fits_length (int length)
1164 for (i = t->t; i < t->nr - t->b; i++)
1165 if (t->ht + t->hb + t->h[i] > length)
1171 /* Sets the number of header rows/columns on the left, right, top,
1172 and bottom sides to HL, HR, HT, and HB, respectively. */
1174 tabi_set_headers (int hl, int hr, int ht, int hb)
1182 /* Render title for current table, with major index X and minor index
1183 Y. Y may be zero, or X and Y may be zero, but X should be nonzero
1186 tabi_title (int x, int y)
1191 if (t->flags & SOMF_NO_TITLE)
1194 cp = spprintf (buf, "%d.%d", table_num, subtable_num);
1196 cp = spprintf (cp, "(%d:%d)", x, y);
1198 cp = spprintf (cp, "(%d)", x);
1199 if (command_name != NULL)
1200 cp = spprintf (cp, " %s", command_name);
1201 cp = stpcpy (cp, ". ");
1202 if (!ls_empty_p (&t->title))
1204 memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
1205 cp += ls_length (&t->title);
1210 struct outp_text text;
1212 text.options = OUTP_T_JUST_LEFT | OUTP_T_HORZ | OUTP_T_VERT;
1213 ls_init (&text.s, buf, cp - buf);
1215 text.v = d->font_height;
1218 d->class->text_draw (d, &text);
1222 static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
1224 /* Draws the table region in rectangle (X1,Y1)-(X2,Y2), where column
1225 X2 and row Y2 are not included in the rectangle, at the current
1226 position on the current output device. Draws headers as well. */
1228 tabi_render (int x1, int y1, int x2, int y2)
1236 if (!(t->flags & SOMF_NO_TITLE))
1237 y += d->font_height;
1241 ranges[0][1] = t->t * 2 + 1;
1243 /* Requested rows. */
1244 ranges[1][0] = y1 * 2 + 1;
1245 ranges[1][1] = y2 * 2;
1247 /* Bottom headers. */
1248 ranges[2][0] = (t->nr - t->b) * 2;
1249 ranges[2][1] = t->nr * 2 + 1;
1251 for (i = 0; i < 3; i++)
1255 for (r = ranges[i][0]; r < ranges[i][1]; r++)
1258 x += render_strip (x, y, r, 0, t->l * 2 + 1, y1, y2);
1259 x += render_strip (x, y, r, x1 * 2 + 1, x2 * 2, y1, y2);
1260 x += render_strip (x, y, r, (t->nc - t->r) * 2,
1261 t->nc * 2 + 1, y1, y2);
1262 y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
1267 struct som_table_class tab_table_class =
1293 /* Render contiguous strip consisting of columns C1...C2, exclusive,
1294 on row R, at location (X,Y). Return width of the strip thus
1297 Renders joined cells, even those outside the strip, within the
1298 rendering region (C1,R1)-(C2,R2).
1300 For the purposes of counting rows and columns in this function
1301 only, horizontal rules are considered rows and vertical rules are
1304 FIXME: Doesn't use r1? Huh? */
1306 render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
1310 /* Horizontal rules. */
1313 int hrh = t->hrh[r / 2];
1316 for (c = c1; c < c2; c++)
1320 int style = t->rh[(c / 2) + (r / 2 * t->cf)];
1324 const struct color clr = {0, 0, 0, 0};
1329 rct.x2 = x + t->w[c / 2];
1331 d->class->line_horz (d, &rct, &clr, style);
1335 const struct color clr = {0, 0, 0, 0};
1337 struct outp_styles s;
1341 rct.x2 = x + t->wrv[c / 2];
1344 s.t = r > 0 ? t->rv[(c / 2) + (t->cf + 1) * (r / 2 - 1)] : 0;
1345 s.b = r < 2 * t->nr ? t->rv[(c / 2) + (t->cf + 1) * (r / 2)] : 0;
1346 s.l = c > 0 ? t->rh[(c / 2 - 1) + t->cf * (r / 2)] : 0;
1347 s.r = c < 2 * t->nc ? t->rh[(c / 2) + t->cf * (r / 2)] : 0;
1349 if (s.t | s.b | s.l | s.r)
1350 d->class->line_intersection (d, &rct, &clr, &s);
1358 for (c = c1; c < c2; c++)
1362 const int index = (c / 2) + (r / 2 * t->cf);
1364 if (!(t->ct[index] & TAB_JOIN))
1366 struct outp_text text;
1368 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1369 | OUTP_T_HORZ | OUTP_T_VERT);
1370 if ((t->ct[index] & TAB_EMPTY) == 0)
1372 text.s = t->cc[index];
1373 assert (!ls_null_p (&text.s));
1374 text.h = t->w[c / 2];
1375 text.v = t->h[r / 2];
1378 d->class->text_draw (d, &text);
1381 struct tab_joined_cell *j =
1382 (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
1384 if (j->hit != tab_hit)
1388 if (j->x1 == c / 2 && j->y1 == r / 2)
1390 struct outp_text text;
1392 text.options = ((t->ct[index] & OUTP_T_JUST_MASK)
1393 | OUTP_T_HORZ | OUTP_T_VERT);
1394 text.s = j->contents;
1401 for (c = j->x1, text.h = -t->wrv[j->x2];
1402 c < j->x2 && c < c2 / 2; c++)
1403 text.h += t->w[c] + t->wrv[c + 1];
1409 for (r = j->y1, text.v = -t->hrh[j->y2];
1410 r < j->y2 && r < r2 / 2; r++)
1411 text.v += t->h[r] + t->hrh[r + 1];
1413 d->class->text_draw (d, &text);
1419 int style = t->rv[(c / 2) + (r / 2 * (t->cf + 1))];
1423 const struct color clr = {0, 0, 0, 0};
1428 rct.x2 = x + t->wrv[c / 2];
1429 rct.y2 = y + t->h[r / 2];
1430 d->class->line_vert (d, &rct, &clr, style);
1437 return x - x_origin;
1440 /* Sets COMMAND_NAME as the name of the current command,
1441 for embedding in output. */
1443 tab_set_command_name (const char *command_name_)
1445 free (command_name);
1446 command_name = command_name_ ? xstrdup (command_name_) : NULL;