4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2004
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
26 #define BAR_HEIGHT ".25m"
27 #define DOUBLE_LINE_SEP "2p"
28 #define HALF_DOUBLE_LINE_SEP "1p"
30 #define BODY_DEPTH ".25m"
32 const int DEFAULT_COLUMN_SEPARATION
= 3;
34 #define DELIMITER_CHAR "\\[tbl]"
35 #define SEPARATION_FACTOR_REG PREFIX "sep"
36 #define BOTTOM_REG PREFIX "bot"
37 #define RESET_MACRO_NAME PREFIX "init"
38 #define LINESIZE_REG PREFIX "lps"
39 #define TOP_REG PREFIX "top"
40 #define CURRENT_ROW_REG PREFIX "crow"
41 #define LAST_PASSED_ROW_REG PREFIX "passed"
42 #define TRANSPARENT_STRING_NAME PREFIX "trans"
43 #define QUOTE_STRING_NAME PREFIX "quote"
44 #define SECTION_DIVERSION_NAME PREFIX "section"
45 #define SECTION_DIVERSION_FLAG_REG PREFIX "sflag"
46 #define SAVED_VERTICAL_POS_REG PREFIX "vert"
47 #define NEED_BOTTOM_RULE_REG PREFIX "brule"
48 #define KEEP_MACRO_NAME PREFIX "keep"
49 #define RELEASE_MACRO_NAME PREFIX "release"
50 #define SAVED_FONT_REG PREFIX "fnt"
51 #define SAVED_SIZE_REG PREFIX "sz"
52 #define SAVED_FILL_REG PREFIX "fll"
53 #define SAVED_INDENT_REG PREFIX "ind"
54 #define SAVED_CENTER_REG PREFIX "cent"
55 #define TABLE_DIVERSION_NAME PREFIX "table"
56 #define TABLE_DIVERSION_FLAG_REG PREFIX "tflag"
57 #define TABLE_KEEP_MACRO_NAME PREFIX "tkeep"
58 #define TABLE_RELEASE_MACRO_NAME PREFIX "trelease"
59 #define NEEDED_REG PREFIX "needed"
60 #define REPEATED_MARK_MACRO PREFIX "rmk"
61 #define REPEATED_VPT_MACRO PREFIX "rvpt"
62 #define SUPPRESS_BOTTOM_REG PREFIX "supbot"
63 #define SAVED_DN_REG PREFIX "dn"
65 // this must be one character
66 #define COMPATIBLE_REG PREFIX "c"
68 #define LEADER_REG PREFIX LEADER
70 #define BLOCK_WIDTH_PREFIX PREFIX "tbw"
71 #define BLOCK_DIVERSION_PREFIX PREFIX "tbd"
72 #define BLOCK_HEIGHT_PREFIX PREFIX "tbh"
73 #define SPAN_WIDTH_PREFIX PREFIX "w"
74 #define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw"
75 #define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw"
76 #define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw"
77 #define COLUMN_SEPARATION_PREFIX PREFIX "cs"
78 #define ROW_START_PREFIX PREFIX "rs"
79 #define COLUMN_START_PREFIX PREFIX "cl"
80 #define COLUMN_END_PREFIX PREFIX "ce"
81 #define COLUMN_DIVIDE_PREFIX PREFIX "cd"
82 #define ROW_TOP_PREFIX PREFIX "rt"
84 string
block_width_reg(int r
, int c
);
85 string
block_diversion_name(int r
, int c
);
86 string
block_height_reg(int r
, int c
);
87 string
span_width_reg(int start_col
, int end_col
);
88 string
span_left_numeric_width_reg(int start_col
, int end_col
);
89 string
span_right_numeric_width_reg(int start_col
, int end_col
);
90 string
span_alphabetic_width_reg(int start_col
, int end_col
);
91 string
column_separation_reg(int col
);
92 string
row_start_reg(int r
);
93 string
column_start_reg(int c
);
94 string
column_end_reg(int c
);
95 string
column_divide_reg(int c
);
96 string
row_top_reg(int r
);
98 void set_inline_modifier(const entry_modifier
*);
99 void restore_inline_modifier(const entry_modifier
*m
);
100 void set_modifier(const entry_modifier
*);
101 int find_decimal_point(const char *s
, char decimal_point_char
,
104 string an_empty_string
;
105 int location_force_filename
= 0;
107 void printfs(const char *,
108 const string
&arg1
= an_empty_string
,
109 const string
&arg2
= an_empty_string
,
110 const string
&arg3
= an_empty_string
,
111 const string
&arg4
= an_empty_string
,
112 const string
&arg5
= an_empty_string
);
114 void prints(const string
&);
116 inline void prints(char c
)
121 inline void prints(const char *s
)
126 void prints(const string
&s
)
129 fwrite(s
.contents(), 1, s
.length(), stdout
);
132 struct horizontal_span
{
133 horizontal_span
*next
;
136 horizontal_span(int, int, horizontal_span
*);
139 class single_line_entry
;
140 class double_line_entry
;
147 const char *input_filename
;
153 const entry_modifier
*mod
;
156 table_entry(const entry_modifier
*);
157 virtual ~table_entry();
158 virtual int divert(int ncols
, const string
*mw
, int *sep
);
159 virtual void do_width();
160 virtual void do_depth();
161 virtual void print() = 0;
162 virtual void position_vertically() = 0;
163 virtual single_line_entry
*to_single_line_entry();
164 virtual double_line_entry
*to_double_line_entry();
165 virtual simple_entry
*to_simple_entry();
166 virtual int line_type();
167 virtual void note_double_vrule_on_right(int);
168 virtual void note_double_vrule_on_left(int);
171 class simple_entry
: public table_entry
{
173 simple_entry(const entry_modifier
*);
175 void position_vertically();
176 simple_entry
*to_simple_entry();
177 virtual void add_tab();
178 virtual void simple_print(int);
181 class empty_entry
: public simple_entry
{
183 empty_entry(const entry_modifier
*);
187 class text_entry
: public simple_entry
{
190 void print_contents();
192 text_entry(char *, const entry_modifier
*);
196 void text_entry::print_contents()
198 set_inline_modifier(mod
);
200 restore_inline_modifier(mod
);
203 class repeated_char_entry
: public text_entry
{
205 repeated_char_entry(char *s
, const entry_modifier
*m
);
206 void simple_print(int);
209 class simple_text_entry
: public text_entry
{
211 simple_text_entry(char *s
, const entry_modifier
*m
);
215 class left_text_entry
: public simple_text_entry
{
217 left_text_entry(char *s
, const entry_modifier
*m
);
218 void simple_print(int);
222 class right_text_entry
: public simple_text_entry
{
224 right_text_entry(char *s
, const entry_modifier
*m
);
225 void simple_print(int);
229 class center_text_entry
: public simple_text_entry
{
231 center_text_entry(char *s
, const entry_modifier
*m
);
232 void simple_print(int);
236 class numeric_text_entry
: public text_entry
{
239 numeric_text_entry(char *s
, const entry_modifier
*m
, int pos
);
241 void simple_print(int);
244 class alphabetic_text_entry
: public text_entry
{
246 alphabetic_text_entry(char *s
, const entry_modifier
*m
);
248 void simple_print(int);
252 class line_entry
: public simple_entry
{
254 char double_vrule_on_right
;
255 char double_vrule_on_left
;
257 line_entry(const entry_modifier
*);
258 void note_double_vrule_on_right(int);
259 void note_double_vrule_on_left(int);
260 void simple_print(int) = 0;
263 class single_line_entry
: public line_entry
{
265 single_line_entry(const entry_modifier
*m
);
266 void simple_print(int);
267 single_line_entry
*to_single_line_entry();
271 class double_line_entry
: public line_entry
{
273 double_line_entry(const entry_modifier
*m
);
274 void simple_print(int);
275 double_line_entry
*to_double_line_entry();
279 class short_line_entry
: public simple_entry
{
281 short_line_entry(const entry_modifier
*m
);
282 void simple_print(int);
286 class short_double_line_entry
: public simple_entry
{
288 short_double_line_entry(const entry_modifier
*m
);
289 void simple_print(int);
293 class block_entry
: public table_entry
{
296 void do_divert(int alphabetic
, int ncols
, const string
*mw
, int *sep
);
298 block_entry(char *s
, const entry_modifier
*m
);
300 int divert(int ncols
, const string
*mw
, int *sep
);
303 void position_vertically();
307 class left_block_entry
: public block_entry
{
309 left_block_entry(char *s
, const entry_modifier
*m
);
313 class right_block_entry
: public block_entry
{
315 right_block_entry(char *s
, const entry_modifier
*m
);
319 class center_block_entry
: public block_entry
{
321 center_block_entry(char *s
, const entry_modifier
*m
);
325 class alphabetic_block_entry
: public block_entry
{
327 alphabetic_block_entry(char *s
, const entry_modifier
*m
);
329 int divert(int ncols
, const string
*mw
, int *sep
);
332 table_entry::table_entry(const entry_modifier
*m
)
333 : next(0), input_lineno(-1), input_filename(0),
334 start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m
)
338 table_entry::~table_entry()
342 int table_entry::divert(int, const string
*, int *)
347 void table_entry::do_width()
351 single_line_entry
*table_entry::to_single_line_entry()
356 double_line_entry
*table_entry::to_double_line_entry()
361 simple_entry
*table_entry::to_simple_entry()
366 void table_entry::do_depth()
370 void table_entry::set_location()
372 set_troff_location(input_filename
, input_lineno
);
375 int table_entry::line_type()
380 void table_entry::note_double_vrule_on_right(int)
384 void table_entry::note_double_vrule_on_left(int)
388 simple_entry::simple_entry(const entry_modifier
*m
) : table_entry(m
)
392 void simple_entry::add_tab()
397 void simple_entry::simple_print(int)
402 void simple_entry::position_vertically()
404 if (start_row
!= end_row
)
405 switch (mod
->vertical_alignment
) {
406 case entry_modifier::TOP
:
407 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
409 case entry_modifier::CENTER
:
410 // Peform the motion in two stages so that the center is rounded
411 // vertically upwards even if net vertical motion is upwards.
412 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
413 printfs(".sp \\n[" BOTTOM_REG
"]u-\\n[%1]u-1v/2u\n",
414 row_start_reg(start_row
));
416 case entry_modifier::BOTTOM
:
417 printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG
"]u-\\n[%1]u-1v\n",
418 row_start_reg(start_row
));
425 void simple_entry::print()
436 simple_entry
*simple_entry::to_simple_entry()
441 empty_entry::empty_entry(const entry_modifier
*m
)
446 int empty_entry::line_type()
451 text_entry::text_entry(char *s
, const entry_modifier
*m
)
452 : simple_entry(m
), contents(s
)
456 text_entry::~text_entry()
461 repeated_char_entry::repeated_char_entry(char *s
, const entry_modifier
*m
)
466 void repeated_char_entry::simple_print(int)
468 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
469 set_inline_modifier(mod
);
470 printfs("\\l" DELIMITER_CHAR
"\\n[%1]u\\&",
471 span_width_reg(start_col
, end_col
));
473 prints(DELIMITER_CHAR
);
474 restore_inline_modifier(mod
);
477 simple_text_entry::simple_text_entry(char *s
, const entry_modifier
*m
)
482 void simple_text_entry::do_width()
485 printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR
,
486 span_width_reg(start_col
, end_col
));
488 prints(DELIMITER_CHAR
"\n");
491 left_text_entry::left_text_entry(char *s
, const entry_modifier
*m
)
492 : simple_text_entry(s
, m
)
496 void left_text_entry::simple_print(int)
498 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
502 // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
504 void left_text_entry::add_tab()
506 printfs(" \\n[%1]u", column_end_reg(end_col
));
509 right_text_entry::right_text_entry(char *s
, const entry_modifier
*m
)
510 : simple_text_entry(s
, m
)
514 void right_text_entry::simple_print(int)
516 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
522 void right_text_entry::add_tab()
524 printfs(" \\n[%1]u", column_end_reg(end_col
));
527 center_text_entry::center_text_entry(char *s
, const entry_modifier
*m
)
528 : simple_text_entry(s
, m
)
532 void center_text_entry::simple_print(int)
534 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
540 void center_text_entry::add_tab()
542 printfs(" \\n[%1]u", column_end_reg(end_col
));
545 numeric_text_entry::numeric_text_entry(char *s
, const entry_modifier
*m
, int pos
)
546 : text_entry(s
, m
), dot_pos(pos
)
550 void numeric_text_entry::do_width()
554 printfs(".nr %1 0\\w" DELIMITER_CHAR
,
555 block_width_reg(start_row
, start_col
));
556 set_inline_modifier(mod
);
557 for (int i
= 0; i
< dot_pos
; i
++)
559 restore_inline_modifier(mod
);
560 prints(DELIMITER_CHAR
"\n");
561 printfs(".nr %1 \\n[%1]>?\\n[%2]\n",
562 span_left_numeric_width_reg(start_col
, end_col
),
563 block_width_reg(start_row
, start_col
));
566 printfs(".nr %1 0\n", block_width_reg(start_row
, start_col
));
567 if (contents
[dot_pos
] != '\0') {
569 printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR
,
570 span_right_numeric_width_reg(start_col
, end_col
));
571 set_inline_modifier(mod
);
572 prints(contents
+ dot_pos
);
573 restore_inline_modifier(mod
);
574 prints(DELIMITER_CHAR
"\n");
578 void numeric_text_entry::simple_print(int)
580 printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'",
581 span_width_reg(start_col
, end_col
),
582 span_left_numeric_width_reg(start_col
, end_col
),
583 span_right_numeric_width_reg(start_col
, end_col
),
584 column_start_reg(start_col
),
585 block_width_reg(start_row
, start_col
));
589 alphabetic_text_entry::alphabetic_text_entry(char *s
, const entry_modifier
*m
)
594 void alphabetic_text_entry::do_width()
597 printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR
,
598 span_alphabetic_width_reg(start_col
, end_col
));
600 prints(DELIMITER_CHAR
"\n");
603 void alphabetic_text_entry::simple_print(int)
605 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
606 printfs("\\h'\\n[%1]u-\\n[%2]u/2u'",
607 span_width_reg(start_col
, end_col
),
608 span_alphabetic_width_reg(start_col
, end_col
));
612 // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
614 void alphabetic_text_entry::add_tab()
616 printfs(" \\n[%1]u", column_end_reg(end_col
));
619 block_entry::block_entry(char *s
, const entry_modifier
*m
)
620 : table_entry(m
), contents(s
)
624 block_entry::~block_entry()
629 void block_entry::position_vertically()
631 if (start_row
!= end_row
)
632 switch(mod
->vertical_alignment
) {
633 case entry_modifier::TOP
:
634 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
636 case entry_modifier::CENTER
:
637 // Peform the motion in two stages so that the center is rounded
638 // vertically upwards even if net vertical motion is upwards.
639 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
640 printfs(".sp \\n[" BOTTOM_REG
"]u-\\n[%1]u-\\n[%2]u/2u\n",
641 row_start_reg(start_row
),
642 block_height_reg(start_row
, start_col
));
644 case entry_modifier::BOTTOM
:
645 printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG
"]u-\\n[%1]u-\\n[%2]u\n",
646 row_start_reg(start_row
),
647 block_height_reg(start_row
, start_col
));
653 prints(".sp -.5v\n");
656 int block_entry::divert(int ncols
, const string
*mw
, int *sep
)
658 do_divert(0, ncols
, mw
, sep
);
662 void block_entry::do_divert(int alphabetic
, int ncols
, const string
*mw
,
665 printfs(".di %1\n", block_diversion_name(start_row
, start_col
));
666 prints(".if \\n[" SAVED_FILL_REG
"] .fi\n"
670 for (i
= start_col
; i
<= end_col
; i
++)
674 // Every column spanned by this entry has a minimum width.
675 for (int j
= start_col
; j
<= end_col
; j
++) {
678 printfs("+%1n", as_string(sep
[j
- 1]));
681 printfs("(n;%1)", mw
[j
]);
683 printfs(">?\\n[%1]u", span_width_reg(start_col
, end_col
));
686 printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))",
687 span_width_reg(start_col
, end_col
),
688 as_string(end_col
- start_col
+ 1),
689 as_string(ncols
+ 1));
693 prints(".cp \\n(" COMPATIBLE_REG
"\n");
697 prints(".br\n.di\n.cp 0\n");
698 if (!mod
->zero_width
) {
700 printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n",
701 span_width_reg(start_col
, end_col
));
702 printfs(".nr %1 \\n[%1]>?\\n[dl]\n",
703 span_alphabetic_width_reg(start_col
, end_col
));
706 printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col
, end_col
));
708 printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row
, start_col
));
709 printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row
, start_col
));
710 prints("." RESET_MACRO_NAME
"\n"
711 ".in \\n[" SAVED_INDENT_REG
"]u\n"
713 // the block might have contained .lf commands
714 location_force_filename
= 1;
717 void block_entry::do_width()
719 // do nothing; the action happens in divert
722 void block_entry::do_depth()
724 printfs(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?(\\n[%1]+\\n[%2])\n",
725 row_start_reg(start_row
),
726 block_height_reg(start_row
, start_col
));
729 left_block_entry::left_block_entry(char *s
, const entry_modifier
*m
)
734 void left_block_entry::print()
736 printfs(".in +\\n[%1]u\n", column_start_reg(start_col
));
737 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
741 right_block_entry::right_block_entry(char *s
, const entry_modifier
*m
)
746 void right_block_entry::print()
748 printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n",
749 column_start_reg(start_col
),
750 span_width_reg(start_col
, end_col
),
751 block_width_reg(start_row
, start_col
));
752 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
756 center_block_entry::center_block_entry(char *s
, const entry_modifier
*m
)
761 void center_block_entry::print()
763 printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
764 column_start_reg(start_col
),
765 span_width_reg(start_col
, end_col
),
766 block_width_reg(start_row
, start_col
));
767 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
771 alphabetic_block_entry::alphabetic_block_entry(char *s
,
772 const entry_modifier
*m
)
777 int alphabetic_block_entry::divert(int ncols
, const string
*mw
, int *sep
)
779 do_divert(1, ncols
, mw
, sep
);
783 void alphabetic_block_entry::print()
785 printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
786 column_start_reg(start_col
),
787 span_width_reg(start_col
, end_col
),
788 span_alphabetic_width_reg(start_col
, end_col
));
789 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
793 line_entry::line_entry(const entry_modifier
*m
)
794 : simple_entry(m
), double_vrule_on_right(0), double_vrule_on_left(0)
798 void line_entry::note_double_vrule_on_right(int is_corner
)
800 double_vrule_on_right
= is_corner
? 1 : 2;
803 void line_entry::note_double_vrule_on_left(int is_corner
)
805 double_vrule_on_left
= is_corner
? 1 : 2;
808 single_line_entry::single_line_entry(const entry_modifier
*m
)
813 int single_line_entry::line_type()
818 void single_line_entry::simple_print(int dont_move
)
820 printfs("\\h'|\\n[%1]u",
821 column_divide_reg(start_col
));
822 if (double_vrule_on_left
) {
823 prints(double_vrule_on_left
== 1 ? "-" : "+");
824 prints(HALF_DOUBLE_LINE_SEP
);
828 prints("\\v'-" BAR_HEIGHT
"'");
829 printfs("\\s[\\n[" LINESIZE_REG
"]]" "\\D'l |\\n[%1]u",
830 column_divide_reg(end_col
+1));
831 if (double_vrule_on_right
) {
832 prints(double_vrule_on_left
== 1 ? "+" : "-");
833 prints(HALF_DOUBLE_LINE_SEP
);
837 prints("\\v'" BAR_HEIGHT
"'");
840 single_line_entry
*single_line_entry::to_single_line_entry()
845 double_line_entry::double_line_entry(const entry_modifier
*m
)
850 int double_line_entry::line_type()
855 void double_line_entry::simple_print(int dont_move
)
858 prints("\\v'-" BAR_HEIGHT
"'");
859 printfs("\\h'|\\n[%1]u",
860 column_divide_reg(start_col
));
861 if (double_vrule_on_left
) {
862 prints(double_vrule_on_left
== 1 ? "-" : "+");
863 prints(HALF_DOUBLE_LINE_SEP
);
866 printfs("\\v'-" HALF_DOUBLE_LINE_SEP
"'"
867 "\\s[\\n[" LINESIZE_REG
"]]"
869 column_divide_reg(end_col
+1));
870 if (double_vrule_on_right
)
871 prints("-" HALF_DOUBLE_LINE_SEP
);
873 printfs("\\v'" DOUBLE_LINE_SEP
"'"
875 column_divide_reg(start_col
));
876 if (double_vrule_on_right
) {
877 prints(double_vrule_on_left
== 1 ? "+" : "-");
878 prints(HALF_DOUBLE_LINE_SEP
);
882 "\\v'-" HALF_DOUBLE_LINE_SEP
"'");
884 prints("\\v'" BAR_HEIGHT
"'");
887 double_line_entry
*double_line_entry::to_double_line_entry()
892 short_line_entry::short_line_entry(const entry_modifier
*m
)
897 int short_line_entry::line_type()
902 void short_line_entry::simple_print(int dont_move
)
907 prints("\\v'-" BAR_HEIGHT
"'");
908 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
909 printfs("\\s[\\n[" LINESIZE_REG
"]]"
912 span_width_reg(start_col
, end_col
));
914 prints("\\v'" BAR_HEIGHT
"'");
919 short_double_line_entry::short_double_line_entry(const entry_modifier
*m
)
924 int short_double_line_entry::line_type()
929 void short_double_line_entry::simple_print(int dont_move
)
934 prints("\\v'-" BAR_HEIGHT
"'");
935 printfs("\\h'|\\n[%2]u'"
936 "\\v'-" HALF_DOUBLE_LINE_SEP
"'"
937 "\\s[\\n[" LINESIZE_REG
"]]"
939 "\\v'" DOUBLE_LINE_SEP
"'"
942 "\\v'-" HALF_DOUBLE_LINE_SEP
"'",
943 span_width_reg(start_col
, end_col
),
944 column_start_reg(start_col
));
946 prints("\\v'" BAR_HEIGHT
"'");
951 void set_modifier(const entry_modifier
*m
)
953 if (!m
->font
.empty())
954 printfs(".ft %1\n", m
->font
);
955 if (m
->point_size
.val
!= 0) {
957 if (m
->point_size
.inc
> 0)
959 else if (m
->point_size
.inc
< 0)
961 printfs("%1\n", as_string(m
->point_size
.val
));
963 if (m
->vertical_spacing
.val
!= 0) {
965 if (m
->vertical_spacing
.inc
> 0)
967 else if (m
->vertical_spacing
.inc
< 0)
969 printfs("%1\n", as_string(m
->vertical_spacing
.val
));
971 if (!m
->macro
.empty())
972 printfs(".%1\n", m
->macro
);
975 void set_inline_modifier(const entry_modifier
*m
)
977 if (!m
->font
.empty())
978 printfs("\\f[%1]", m
->font
);
979 if (m
->point_size
.val
!= 0) {
981 if (m
->point_size
.inc
> 0)
983 else if (m
->point_size
.inc
< 0)
985 printfs("%1]", as_string(m
->point_size
.val
));
991 void restore_inline_modifier(const entry_modifier
*m
)
993 if (!m
->font
.empty())
994 prints("\\f[\\n[" SAVED_FONT_REG
"]]");
995 if (m
->point_size
.val
!= 0)
996 prints("\\s[\\n[" SAVED_SIZE_REG
"]]");
1003 int row
; // occurs before row `row'
1004 char printed
; // has it been printed?
1007 virtual void print(table
*) = 0;
1009 virtual int is_single_line() { return 0; };
1010 virtual int is_double_line() { return 0; };
1013 stuff::stuff(int r
) : next(0), row(r
), printed(0)
1021 struct text_stuff
: public stuff
{
1023 const char *filename
;
1026 text_stuff(const string
&, int r
, const char *fn
, int ln
);
1028 void print(table
*);
1031 text_stuff::text_stuff(const string
&s
, int r
, const char *fn
, int ln
)
1032 : stuff(r
), contents(s
), filename(fn
), lineno(ln
)
1036 text_stuff::~text_stuff()
1040 void text_stuff::print(table
*)
1043 prints(".cp \\n(" COMPATIBLE_REG
"\n");
1044 set_troff_location(filename
, lineno
);
1047 location_force_filename
= 1; // it might have been a .lf command
1050 struct single_hline_stuff
: public stuff
{
1051 single_hline_stuff(int r
);
1052 void print(table
*);
1053 int is_single_line();
1056 single_hline_stuff::single_hline_stuff(int r
) : stuff(r
)
1060 void single_hline_stuff::print(table
*tbl
)
1063 tbl
->print_single_hline(row
);
1066 int single_hline_stuff::is_single_line()
1071 struct double_hline_stuff
: stuff
{
1072 double_hline_stuff(int r
);
1073 void print(table
*);
1074 int is_double_line();
1077 double_hline_stuff::double_hline_stuff(int r
) : stuff(r
)
1081 void double_hline_stuff::print(table
*tbl
)
1084 tbl
->print_double_hline(row
);
1087 int double_hline_stuff::is_double_line()
1092 struct vertical_rule
{
1093 vertical_rule
*next
;
1101 vertical_rule(int sr
, int er
, int c
, int dbl
, vertical_rule
*);
1103 void contribute_to_bottom_macro(table
*);
1107 vertical_rule::vertical_rule(int sr
, int er
, int c
, int dbl
, vertical_rule
*p
)
1108 : next(p
), start_row(sr
), end_row(er
), col(c
), is_double(dbl
)
1112 vertical_rule::~vertical_rule()
1116 void vertical_rule::contribute_to_bottom_macro(table
*tbl
)
1118 printfs(".if \\n[" CURRENT_ROW_REG
"]>=%1",
1119 as_string(start_row
));
1120 if (end_row
!= tbl
->get_nrows() - 1)
1121 printfs("&(\\n[" CURRENT_ROW_REG
"]<%1)",
1122 as_string(end_row
));
1124 printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG
"] .nr %2 \\n[#T]\n",
1125 as_string(start_row
),
1126 row_top_reg(start_row
));
1127 const char *offset_table
[3];
1129 offset_table
[0] = "-" HALF_DOUBLE_LINE_SEP
;
1130 offset_table
[1] = "+" HALF_DOUBLE_LINE_SEP
;
1131 offset_table
[2] = 0;
1134 offset_table
[0] = "";
1135 offset_table
[1] = 0;
1137 for (const char **offsetp
= offset_table
; *offsetp
; offsetp
++) {
1140 if (!bot_adjust
.empty())
1141 printfs("+%1", bot_adjust
);
1143 printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG
"]]\\D'l 0 |\\n[%2]u-1v",
1144 column_divide_reg(col
),
1145 row_top_reg(start_row
),
1147 if (!bot_adjust
.empty())
1148 printfs("-(%1)", bot_adjust
);
1149 // don't perform the top adjustment if the top is actually #T
1150 if (!top_adjust
.empty())
1151 printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG
"]))",
1153 as_string(start_row
));
1159 void vertical_rule::print()
1161 printfs("\\*[" TRANSPARENT_STRING_NAME
"]"
1162 ".if %1<=\\*[" QUOTE_STRING_NAME
"]\\n[" LAST_PASSED_ROW_REG
"] "
1163 ".nr %2 \\*[" QUOTE_STRING_NAME
"]\\n[#T]\n",
1164 as_string(start_row
),
1165 row_top_reg(start_row
));
1166 const char *offset_table
[3];
1168 offset_table
[0] = "-" HALF_DOUBLE_LINE_SEP
;
1169 offset_table
[1] = "+" HALF_DOUBLE_LINE_SEP
;
1170 offset_table
[2] = 0;
1173 offset_table
[0] = "";
1174 offset_table
[1] = 0;
1176 for (const char **offsetp
= offset_table
; *offsetp
; offsetp
++) {
1177 prints("\\*[" TRANSPARENT_STRING_NAME
"].sp -1\n"
1178 "\\*[" TRANSPARENT_STRING_NAME
"]\\v'" BODY_DEPTH
);
1179 if (!bot_adjust
.empty())
1180 printfs("+%1", bot_adjust
);
1182 printfs("\\h'\\n[%1]u%3'"
1183 "\\s[\\n[" LINESIZE_REG
"]]"
1184 "\\D'l 0 |\\*[" QUOTE_STRING_NAME
"]\\n[%2]u-1v",
1185 column_divide_reg(col
),
1186 row_top_reg(start_row
),
1188 if (!bot_adjust
.empty())
1189 printfs("-(%1)", bot_adjust
);
1190 // don't perform the top adjustment if the top is actually #T
1191 if (!top_adjust
.empty())
1192 printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME
"]\\n["
1193 LAST_PASSED_ROW_REG
"]))",
1195 as_string(start_row
));
1201 table::table(int nc
, unsigned f
, int ls
, char dpc
)
1202 : flags(f
), nrows(0), ncolumns(nc
), linesize(ls
), decimal_point_char(dpc
),
1203 vrule_list(0), stuff_list(0), span_list(0),
1204 entry_list(0), entry_list_tailp(&entry_list
), entry(0),
1205 vline(0), row_is_all_lines(0), left_separation(0), right_separation(0),
1208 minimum_width
= new string
[ncolumns
];
1209 column_separation
= ncolumns
> 1 ? new int[ncolumns
- 1] : 0;
1210 equal
= new char[ncolumns
];
1212 for (i
= 0; i
< ncolumns
; i
++)
1214 for (i
= 0; i
< ncolumns
-1; i
++)
1215 column_separation
[i
] = DEFAULT_COLUMN_SEPARATION
;
1216 delim
[0] = delim
[1] = '\0';
1221 for (int i
= 0; i
< nrows
; i
++) {
1227 while (entry_list
) {
1228 table_entry
*tem
= entry_list
;
1229 entry_list
= entry_list
->next
;
1232 ad_delete(ncolumns
) minimum_width
;
1233 a_delete column_separation
;
1235 while (stuff_list
) {
1236 stuff
*tem
= stuff_list
;
1237 stuff_list
= stuff_list
->next
;
1240 while (vrule_list
) {
1241 vertical_rule
*tem
= vrule_list
;
1242 vrule_list
= vrule_list
->next
;
1245 a_delete row_is_all_lines
;
1247 horizontal_span
*tem
= span_list
;
1248 span_list
= span_list
->next
;
1253 void table::set_delim(char c1
, char c2
)
1259 void table::set_minimum_width(int c
, const string
&w
)
1261 assert(c
>= 0 && c
< ncolumns
);
1262 minimum_width
[c
] = w
;
1265 void table::set_column_separation(int c
, int n
)
1267 assert(c
>= 0 && c
< ncolumns
- 1);
1268 column_separation
[c
] = n
;
1271 void table::set_equal_column(int c
)
1273 assert(c
>= 0 && c
< ncolumns
);
1277 void table::add_stuff(stuff
*p
)
1280 for (pp
= &stuff_list
; *pp
; pp
= &(*pp
)->next
)
1285 void table::add_text_line(int r
, const string
&s
, const char *filename
, int lineno
)
1287 add_stuff(new text_stuff(s
, r
, filename
, lineno
));
1290 void table::add_single_hline(int r
)
1292 add_stuff(new single_hline_stuff(r
));
1295 void table::add_double_hline(int r
)
1297 add_stuff(new double_hline_stuff(r
));
1300 void table::allocate(int r
)
1303 typedef table_entry
**PPtable_entry
; // work around g++ 1.36.1 bug
1304 if (r
>= allocated_rows
) {
1305 if (allocated_rows
== 0) {
1306 allocated_rows
= 16;
1307 if (allocated_rows
<= r
)
1308 allocated_rows
= r
+ 1;
1309 entry
= new PPtable_entry
[allocated_rows
];
1310 vline
= new char*[allocated_rows
];
1313 table_entry
***old_entry
= entry
;
1314 int old_allocated_rows
= allocated_rows
;
1315 allocated_rows
*= 2;
1316 if (allocated_rows
<= r
)
1317 allocated_rows
= r
+ 1;
1318 entry
= new PPtable_entry
[allocated_rows
];
1319 memcpy(entry
, old_entry
, sizeof(table_entry
**)*old_allocated_rows
);
1321 char **old_vline
= vline
;
1322 vline
= new char*[allocated_rows
];
1323 memcpy(vline
, old_vline
, sizeof(char*)*old_allocated_rows
);
1327 assert(allocated_rows
> r
);
1328 while (nrows
<= r
) {
1329 entry
[nrows
] = new table_entry
*[ncolumns
];
1331 for (i
= 0; i
< ncolumns
; i
++)
1332 entry
[nrows
][i
] = 0;
1333 vline
[nrows
] = new char[ncolumns
+1];
1334 for (i
= 0; i
< ncolumns
+1; i
++)
1335 vline
[nrows
][i
] = 0;
1341 void table::do_hspan(int r
, int c
)
1343 assert(r
>= 0 && c
>= 0 && r
< nrows
&& c
< ncolumns
);
1345 error("first column cannot be horizontally spanned");
1348 table_entry
*e
= entry
[r
][c
];
1350 assert(e
->start_row
<= r
&& r
<= e
->end_row
1351 && e
->start_col
<= c
&& c
<= e
->end_col
1352 && e
->end_row
- e
->start_row
> 0
1353 && e
->end_col
- e
->start_col
> 0);
1357 // e can be 0 if we had an empty entry or an error
1360 if (e
->start_row
!= r
) {
1364 error("impossible horizontal span at row %1, column %2", r
+ 1, c
+ 1);
1372 void table::do_vspan(int r
, int c
)
1374 assert(r
>= 0 && c
>= 0 && r
< nrows
&& c
< ncolumns
);
1376 error("first row cannot be vertically spanned");
1379 table_entry
*e
= entry
[r
][c
];
1381 assert(e
->start_row
<= r
&& r
<= e
->end_row
1382 && e
->start_col
<= c
&& c
<= e
->end_col
1383 && e
->end_row
- e
->start_row
> 0
1384 && e
->end_col
- e
->start_col
> 0);
1388 // e can be 0 if we had an empty entry or an error
1391 if (e
->start_col
!= c
) {
1394 error("impossible vertical span at row %1, column %2", r
+ 1, c
+ 1);
1397 for (int i
= c
; i
<= e
->end_col
; i
++) {
1398 assert(entry
[r
][i
] == 0);
1405 int find_decimal_point(const char *s
, char decimal_point_char
,
1408 if (s
== 0 || *s
== '\0')
1411 int in_delim
= 0; // is p within eqn delimiters?
1412 // tbl recognises \& even within eqn delimiters; I don't
1413 for (p
= s
; *p
; p
++)
1418 else if (*p
== delim
[0])
1420 else if (p
[0] == '\\' && p
[1] == '&')
1422 int possible_pos
= -1;
1424 for (p
= s
; *p
; p
++)
1429 else if (*p
== delim
[0])
1431 else if (p
[0] == decimal_point_char
&& csdigit(p
[1]))
1432 possible_pos
= p
- s
;
1433 if (possible_pos
>= 0)
1434 return possible_pos
;
1436 for (p
= s
; *p
; p
++)
1441 else if (*p
== delim
[0])
1443 else if (csdigit(*p
))
1444 possible_pos
= p
+ 1 - s
;
1445 return possible_pos
;
1448 void table::add_entry(int r
, int c
, const string
&str
, const entry_format
*f
,
1449 const char *fn
, int ln
)
1454 e
= new short_line_entry(f
);
1456 else if (str
== "\\=") {
1457 e
= new short_double_line_entry(f
);
1459 else if (str
== "_") {
1460 single_line_entry
*lefte
;
1461 if (c
> 0 && entry
[r
][c
-1] != 0 &&
1462 (lefte
= entry
[r
][c
-1]->to_single_line_entry()) != 0
1463 && lefte
->start_row
== r
1464 && lefte
->mod
->stagger
== f
->stagger
) {
1466 entry
[r
][c
] = lefte
;
1469 e
= new single_line_entry(f
);
1471 else if (str
== "=") {
1472 double_line_entry
*lefte
;
1473 if (c
> 0 && entry
[r
][c
-1] != 0 &&
1474 (lefte
= entry
[r
][c
-1]->to_double_line_entry()) != 0
1475 && lefte
->start_row
== r
1476 && lefte
->mod
->stagger
== f
->stagger
) {
1478 entry
[r
][c
] = lefte
;
1481 e
= new double_line_entry(f
);
1483 else if (str
== "\\^") {
1486 else if (str
.length() > 2 && str
[0] == '\\' && str
[1] == 'R') {
1487 if (str
.search('\n') >= 0)
1488 error_with_file_and_line(fn
, ln
, "bad repeated character");
1490 char *s
= str
.substring(2, str
.length() - 2).extract();
1491 e
= new repeated_char_entry(s
, f
);
1495 int is_block
= str
.search('\n') >= 0;
1499 assert(str
.empty());
1506 e
= new left_block_entry(s
, f
);
1508 e
= new left_text_entry(s
, f
);
1511 e
= new empty_entry(f
);
1517 e
= new center_block_entry(s
, f
);
1519 e
= new center_text_entry(s
, f
);
1522 e
= new empty_entry(f
);
1528 e
= new right_block_entry(s
, f
);
1530 e
= new right_text_entry(s
, f
);
1533 e
= new empty_entry(f
);
1535 case FORMAT_NUMERIC
:
1539 error_with_file_and_line(fn
, ln
, "can't have numeric text block");
1540 e
= new left_block_entry(s
, f
);
1543 int pos
= find_decimal_point(s
, decimal_point_char
, delim
);
1545 e
= new center_text_entry(s
, f
);
1547 e
= new numeric_text_entry(s
, f
, pos
);
1551 e
= new empty_entry(f
);
1553 case FORMAT_ALPHABETIC
:
1557 e
= new alphabetic_block_entry(s
, f
);
1559 e
= new alphabetic_text_entry(s
, f
);
1562 e
= new empty_entry(f
);
1568 if (str
.length() != 0)
1569 error_with_file_and_line(fn
, ln
,
1570 "non-empty data entry for `_' format ignored");
1571 e
= new single_line_entry(f
);
1573 case FORMAT_DOUBLE_HLINE
:
1574 if (str
.length() != 0)
1575 error_with_file_and_line(fn
, ln
,
1576 "non-empty data entry for `=' format ignored");
1577 e
= new double_line_entry(f
);
1584 table_entry
*preve
= entry
[r
][c
];
1588 error_with_file_and_line(fn
, ln
, "row %1, column %2 already spanned",
1593 e
->input_lineno
= ln
;
1594 e
->input_filename
= fn
;
1595 e
->start_row
= e
->end_row
= r
;
1596 e
->start_col
= e
->end_col
= c
;
1597 *entry_list_tailp
= e
;
1598 entry_list_tailp
= &e
->next
;
1604 // add vertical lines for row r
1606 void table::add_vlines(int r
, const char *v
)
1609 for (int i
= 0; i
< ncolumns
+1; i
++)
1615 table_entry
*p
= entry_list
;
1618 for (i
= p
->start_row
; i
<= p
->end_row
; i
++)
1619 for (j
= p
->start_col
; j
<= p
->end_col
; j
++)
1620 assert(entry
[i
][j
] == p
);
1627 location_force_filename
= 1;
1630 determine_row_type();
1632 if (!(flags
& CENTER
))
1633 prints(".if \\n[" SAVED_CENTER_REG
"] \\{");
1634 prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2>?-\\n[.i])\n"
1635 ".nr " SAVED_INDENT_REG
" \\n[.i]\n");
1636 if (!(flags
& CENTER
))
1639 define_bottom_macro();
1641 for (int i
= 0; i
< nrows
; i
++)
1646 void table::determine_row_type()
1648 row_is_all_lines
= new char[nrows
];
1649 for (int i
= 0; i
< nrows
; i
++) {
1652 int had_non_line
= 0;
1653 for (int c
= 0; c
< ncolumns
; c
++) {
1654 table_entry
*e
= entry
[i
][c
];
1656 if (e
->start_row
== e
->end_row
) {
1657 int t
= e
->line_type();
1681 row_is_all_lines
[i
] = 0;
1682 else if (had_double
)
1683 row_is_all_lines
[i
] = 2;
1684 else if (had_single
)
1685 row_is_all_lines
[i
] = 1;
1687 row_is_all_lines
[i
] = 0;
1691 void table::init_output()
1693 prints(".nr " COMPATIBLE_REG
" \\n(.C\n"
1696 printfs(".nr " LINESIZE_REG
" %1\n", as_string(linesize
));
1698 prints(".nr " LINESIZE_REG
" \\n[.s]\n");
1699 if (!(flags
& CENTER
))
1700 prints(".nr " SAVED_CENTER_REG
" \\n[.ce]\n");
1701 if (compatible_flag
)
1702 prints(".ds " LEADER_REG
" \\a\n");
1703 prints(".de " RESET_MACRO_NAME
"\n"
1715 ".nr " SAVED_INDENT_REG
" \\n[.i]\n"
1716 ".nr " SAVED_FONT_REG
" \\n[.f]\n"
1717 ".nr " SAVED_SIZE_REG
" \\n[.s]\n"
1718 ".nr " SAVED_FILL_REG
" \\n[.u]\n"
1720 ".nr " CURRENT_ROW_REG
" 0-1\n"
1721 ".nr " LAST_PASSED_ROW_REG
" 0-1\n"
1722 ".nr " SECTION_DIVERSION_FLAG_REG
" 0\n"
1723 ".ds " TRANSPARENT_STRING_NAME
"\n"
1724 ".ds " QUOTE_STRING_NAME
"\n"
1725 ".nr " NEED_BOTTOM_RULE_REG
" 1\n"
1726 ".nr " SUPPRESS_BOTTOM_REG
" 0\n"
1728 ".de " REPEATED_MARK_MACRO
"\n"
1730 ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO
" \"\\$1\"\n"
1732 ".de " REPEATED_VPT_MACRO
"\n"
1734 ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO
" \"\\$1\"\n"
1736 if (!(flags
& NOKEEP
))
1737 prints(".de " KEEP_MACRO_NAME
"\n"
1738 ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME
" \\\\\n"
1739 ".ds " TRANSPARENT_STRING_NAME
" \\!\n"
1740 ".di " SECTION_DIVERSION_NAME
"\n"
1741 ".nr " SECTION_DIVERSION_FLAG_REG
" 1\n"
1745 ".de " RELEASE_MACRO_NAME
"\n"
1746 ".if \\n[" SECTION_DIVERSION_FLAG_REG
"] \\{"
1748 ".in \\n[" SAVED_INDENT_REG
"]u\n"
1749 ".nr " SAVED_DN_REG
" \\n[dn]\n"
1750 ".ds " QUOTE_STRING_NAME
"\n"
1751 ".ds " TRANSPARENT_STRING_NAME
"\n"
1752 ".nr " SECTION_DIVERSION_FLAG_REG
" 0\n"
1753 ".if \\n[.t]<=\\n[dn] \\{"
1756 ".nr " SUPPRESS_BOTTOM_REG
" 1\n"
1758 ".nr " SUPPRESS_BOTTOM_REG
" 0\n"
1761 ".if \\n[.t]<=\\n[" SAVED_DN_REG
"] "
1762 /* Since we turn off traps, it won't get into an infinite loop
1763 when we try and print it; it will just go off the bottom of the
1765 ".tm warning: page \\n%: table text block will not fit on one page\n"
1768 "." SECTION_DIVERSION_NAME
"\n"
1770 ".rm " SECTION_DIVERSION_NAME
"\n"
1773 ".nr " TABLE_DIVERSION_FLAG_REG
" 0\n"
1774 ".de " TABLE_KEEP_MACRO_NAME
"\n"
1775 ".if '\\n[.z]'' \\{"
1776 ".di " TABLE_DIVERSION_NAME
"\n"
1777 ".nr " TABLE_DIVERSION_FLAG_REG
" 1\n"
1780 ".de " TABLE_RELEASE_MACRO_NAME
"\n"
1781 ".if \\n[" TABLE_DIVERSION_FLAG_REG
"] \\{.br\n"
1783 ".nr " SAVED_DN_REG
" \\n[dn]\n"
1784 ".ne \\n[dn]u+\\n[.V]u\n"
1785 ".ie \\n[.t]<=\\n[" SAVED_DN_REG
"] "
1786 ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n"
1791 "." TABLE_DIVERSION_NAME
"\n"
1793 ".rm " TABLE_DIVERSION_NAME
"\n"
1801 string
block_width_reg(int r
, int c
)
1803 static char name
[sizeof(BLOCK_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1804 sprintf(name
, BLOCK_WIDTH_PREFIX
"%d,%d", r
, c
);
1805 return string(name
);
1808 string
block_diversion_name(int r
, int c
)
1810 static char name
[sizeof(BLOCK_DIVERSION_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1811 sprintf(name
, BLOCK_DIVERSION_PREFIX
"%d,%d", r
, c
);
1812 return string(name
);
1815 string
block_height_reg(int r
, int c
)
1817 static char name
[sizeof(BLOCK_HEIGHT_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1818 sprintf(name
, BLOCK_HEIGHT_PREFIX
"%d,%d", r
, c
);
1819 return string(name
);
1822 string
span_width_reg(int start_col
, int end_col
)
1824 static char name
[sizeof(SPAN_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1825 sprintf(name
, SPAN_WIDTH_PREFIX
"%d", start_col
);
1826 if (end_col
!= start_col
)
1827 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1828 return string(name
);
1831 string
span_left_numeric_width_reg(int start_col
, int end_col
)
1833 static char name
[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1834 sprintf(name
, SPAN_LEFT_NUMERIC_WIDTH_PREFIX
"%d", start_col
);
1835 if (end_col
!= start_col
)
1836 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1837 return string(name
);
1840 string
span_right_numeric_width_reg(int start_col
, int end_col
)
1842 static char name
[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1843 sprintf(name
, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX
"%d", start_col
);
1844 if (end_col
!= start_col
)
1845 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1846 return string(name
);
1849 string
span_alphabetic_width_reg(int start_col
, int end_col
)
1851 static char name
[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1852 sprintf(name
, SPAN_ALPHABETIC_WIDTH_PREFIX
"%d", start_col
);
1853 if (end_col
!= start_col
)
1854 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1855 return string(name
);
1858 string
column_separation_reg(int col
)
1860 static char name
[sizeof(COLUMN_SEPARATION_PREFIX
)+INT_DIGITS
];
1861 sprintf(name
, COLUMN_SEPARATION_PREFIX
"%d", col
);
1862 return string(name
);
1865 string
row_start_reg(int row
)
1867 static char name
[sizeof(ROW_START_PREFIX
)+INT_DIGITS
];
1868 sprintf(name
, ROW_START_PREFIX
"%d", row
);
1869 return string(name
);
1872 string
column_start_reg(int col
)
1874 static char name
[sizeof(COLUMN_START_PREFIX
)+INT_DIGITS
];
1875 sprintf(name
, COLUMN_START_PREFIX
"%d", col
);
1876 return string(name
);
1879 string
column_end_reg(int col
)
1881 static char name
[sizeof(COLUMN_END_PREFIX
)+INT_DIGITS
];
1882 sprintf(name
, COLUMN_END_PREFIX
"%d", col
);
1883 return string(name
);
1886 string
column_divide_reg(int col
)
1888 static char name
[sizeof(COLUMN_DIVIDE_PREFIX
)+INT_DIGITS
];
1889 sprintf(name
, COLUMN_DIVIDE_PREFIX
"%d", col
);
1890 return string(name
);
1893 string
row_top_reg(int row
)
1895 static char name
[sizeof(ROW_TOP_PREFIX
)+INT_DIGITS
];
1896 sprintf(name
, ROW_TOP_PREFIX
"%d", row
);
1897 return string(name
);
1900 void init_span_reg(int start_col
, int end_col
)
1902 printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n",
1903 span_width_reg(start_col
, end_col
),
1904 span_alphabetic_width_reg(start_col
, end_col
),
1905 span_left_numeric_width_reg(start_col
, end_col
),
1906 span_right_numeric_width_reg(start_col
, end_col
));
1909 void compute_span_width(int start_col
, int end_col
)
1911 printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n"
1912 ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n",
1913 span_width_reg(start_col
, end_col
),
1914 span_left_numeric_width_reg(start_col
, end_col
),
1915 span_right_numeric_width_reg(start_col
, end_col
),
1916 span_alphabetic_width_reg(start_col
, end_col
));
1919 // Increase the widths of columns so that the width of any spanning entry
1920 // is not greater than the sum of the widths of the columns that it spans.
1921 // Ensure that the widths of columns remain equal.
1923 void table::divide_span(int start_col
, int end_col
)
1925 assert(end_col
> start_col
);
1926 printfs(".nr " NEEDED_REG
" \\n[%1]-(\\n[%2]",
1927 span_width_reg(start_col
, end_col
),
1928 span_width_reg(start_col
, start_col
));
1930 for (i
= start_col
+ 1; i
<= end_col
; i
++) {
1931 // The column separation may shrink with the expand option.
1932 if (!(flags
& EXPAND
))
1933 printfs("+%1n", as_string(column_separation
[i
- 1]));
1934 printfs("+\\n[%1]", span_width_reg(i
, i
));
1937 printfs(".nr " NEEDED_REG
" \\n[" NEEDED_REG
"]/%1\n",
1938 as_string(end_col
- start_col
+ 1));
1939 prints(".if \\n[" NEEDED_REG
"] \\{");
1940 for (i
= start_col
; i
<= end_col
; i
++)
1941 printfs(".nr %1 +\\n[" NEEDED_REG
"]\n",
1942 span_width_reg(i
, i
));
1944 for (i
= start_col
; i
<= end_col
&& !equal_flag
; i
++)
1948 for (i
= 0; i
< ncolumns
; i
++)
1949 if (i
< start_col
|| i
> end_col
)
1950 printfs(".nr %1 +\\n[" NEEDED_REG
"]\n",
1951 span_width_reg(i
, i
));
1956 void table::sum_columns(int start_col
, int end_col
)
1958 assert(end_col
> start_col
);
1959 printfs(".nr %1 \\n[%2]",
1960 span_width_reg(start_col
, end_col
),
1961 span_width_reg(start_col
, start_col
));
1962 for (int i
= start_col
+ 1; i
<= end_col
; i
++)
1963 printfs("+(%1*\\n[" SEPARATION_FACTOR_REG
"])+\\n[%2]",
1964 as_string(column_separation
[i
- 1]),
1965 span_width_reg(i
, i
));
1969 horizontal_span::horizontal_span(int sc
, int ec
, horizontal_span
*p
)
1970 : next(p
), start_col(sc
), end_col(ec
)
1974 void table::build_span_list()
1977 table_entry
*p
= entry_list
;
1979 if (p
->end_col
!= p
->start_col
) {
1981 for (q
= span_list
; q
; q
= q
->next
)
1982 if (q
->start_col
== p
->start_col
1983 && q
->end_col
== p
->end_col
)
1986 span_list
= new horizontal_span(p
->start_col
, p
->end_col
, span_list
);
1990 // Now sort span_list primarily by order of end_row, and secondarily
1991 // by reverse order of start_row. This ensures that if we divide
1992 // spans using the order in span_list, we will get reasonable results.
1993 horizontal_span
*unsorted
= span_list
;
1996 horizontal_span
**pp
;
1997 for (pp
= &span_list
; *pp
; pp
= &(*pp
)->next
)
1998 if (unsorted
->end_col
< (*pp
)->end_col
1999 || (unsorted
->end_col
== (*pp
)->end_col
2000 && (unsorted
->start_col
> (*pp
)->start_col
)))
2002 horizontal_span
*tem
= unsorted
->next
;
2003 unsorted
->next
= *pp
;
2009 void table::compute_separation_factor()
2011 if (flags
& (ALLBOX
|BOX
|DOUBLEBOX
))
2012 left_separation
= right_separation
= 1;
2014 for (int i
= 0; i
< nrows
; i
++) {
2015 if (vline
[i
][0] > 0)
2016 left_separation
= 1;
2017 if (vline
[i
][ncolumns
] > 0)
2018 right_separation
= 1;
2021 if (flags
& EXPAND
) {
2022 int total_sep
= left_separation
+ right_separation
;
2024 for (i
= 0; i
< ncolumns
- 1; i
++)
2025 total_sep
+= column_separation
[i
];
2026 if (total_sep
!= 0) {
2027 // Don't let the separation factor be negative.
2028 prints(".nr " SEPARATION_FACTOR_REG
" \\n[.l]-\\n[.i]");
2029 for (i
= 0; i
< ncolumns
; i
++)
2030 printfs("-\\n[%1]", span_width_reg(i
, i
));
2031 printfs("/%1>?0\n", as_string(total_sep
));
2036 void table::compute_column_positions()
2038 printfs(".nr %1 0\n", column_divide_reg(0));
2039 printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG
"]\n",
2040 column_start_reg(0),
2041 as_string(left_separation
));
2044 printfs(".nr %1 \\n[%2]+\\n[%3]\n",
2045 column_end_reg(i
-1),
2046 column_start_reg(i
-1),
2047 span_width_reg(i
-1, i
-1));
2050 printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG
"])\n",
2051 column_start_reg(i
),
2052 column_end_reg(i
-1),
2053 as_string(column_separation
[i
-1]));
2054 printfs(".nr %1 \\n[%2]+\\n[%3]/2\n",
2055 column_divide_reg(i
),
2056 column_end_reg(i
-1),
2057 column_start_reg(i
));
2059 printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG
"])\n",
2060 column_divide_reg(ncolumns
),
2061 column_end_reg(i
-1),
2062 as_string(right_separation
));
2063 printfs(".nr TW \\n[%1]\n",
2064 column_divide_reg(ncolumns
));
2065 if (flags
& DOUBLEBOX
) {
2066 printfs(".nr %1 +" DOUBLE_LINE_SEP
"\n", column_divide_reg(0));
2067 printfs(".nr %1 -" DOUBLE_LINE_SEP
"\n", column_divide_reg(ncolumns
));
2071 void table::make_columns_equal()
2073 int first
= -1; // index of first equal column
2075 for (i
= 0; i
< ncolumns
; i
++)
2078 printfs(".nr %1 \\n[%1]", span_width_reg(i
, i
));
2082 printfs(">?\\n[%1]", span_width_reg(i
, i
));
2086 for (i
= first
+ 1; i
< ncolumns
; i
++)
2088 printfs(".nr %1 \\n[%2]\n",
2089 span_width_reg(i
, i
),
2090 span_width_reg(first
, first
));
2094 void table::compute_widths()
2099 prints(".nr " SEPARATION_FACTOR_REG
" 1n\n");
2100 for (i
= 0; i
< ncolumns
; i
++) {
2101 init_span_reg(i
, i
);
2102 if (!minimum_width
[i
].empty())
2103 printfs(".nr %1 %2\n", span_width_reg(i
, i
), minimum_width
[i
]);
2105 for (p
= span_list
; p
; p
= p
->next
)
2106 init_span_reg(p
->start_col
, p
->end_col
);
2108 for (q
= entry_list
; q
; q
= q
->next
)
2109 if (!q
->mod
->zero_width
)
2111 for (i
= 0; i
< ncolumns
; i
++)
2112 compute_span_width(i
, i
);
2113 for (p
= span_list
; p
; p
= p
->next
)
2114 compute_span_width(p
->start_col
, p
->end_col
);
2115 make_columns_equal();
2116 // Note that divide_span keeps equal width columns equal.
2117 for (p
= span_list
; p
; p
= p
->next
)
2118 divide_span(p
->start_col
, p
->end_col
);
2119 for (p
= span_list
; p
; p
= p
->next
)
2120 sum_columns(p
->start_col
, p
->end_col
);
2121 int had_spanning_block
= 0;
2122 int had_equal_block
= 0;
2123 for (q
= entry_list
; q
; q
= q
->next
)
2124 if (q
->divert(ncolumns
, minimum_width
,
2125 (flags
& EXPAND
) ? column_separation
: 0)) {
2126 if (q
->end_col
> q
->start_col
)
2127 had_spanning_block
= 1;
2128 for (i
= q
->start_col
; i
<= q
->end_col
&& !had_equal_block
; i
++)
2130 had_equal_block
= 1;
2132 if (had_equal_block
)
2133 make_columns_equal();
2134 if (had_spanning_block
)
2135 for (p
= span_list
; p
; p
= p
->next
)
2136 divide_span(p
->start_col
, p
->end_col
);
2137 compute_separation_factor();
2138 for (p
= span_list
; p
; p
= p
->next
)
2139 sum_columns(p
->start_col
, p
->end_col
);
2140 compute_column_positions();
2143 void table::print_single_hline(int r
)
2145 prints(".vs " LINE_SEP
">?\\n[.V]u\n"
2147 "\\v'" BODY_DEPTH
"'"
2148 "\\s[\\n[" LINESIZE_REG
"]]");
2150 prints("\\D'l |\\n[TW]u 0'");
2154 while (start_col
< ncolumns
2155 && entry
[r
][start_col
] != 0
2156 && entry
[r
][start_col
]->start_row
!= r
)
2159 for (end_col
= start_col
;
2161 && (entry
[r
][end_col
] == 0
2162 || entry
[r
][end_col
]->start_row
== r
);
2165 if (end_col
<= start_col
)
2167 printfs("\\h'|\\n[%1]u",
2168 column_divide_reg(start_col
));
2169 if ((r
> 0 && vline
[r
-1][start_col
] == 2)
2170 || (r
< nrows
&& vline
[r
][start_col
] == 2))
2171 prints("-" HALF_DOUBLE_LINE_SEP
);
2173 printfs("\\D'l |\\n[%1]u",
2174 column_divide_reg(end_col
));
2175 if ((r
> 0 && vline
[r
-1][end_col
] == 2)
2176 || (r
< nrows
&& vline
[r
][end_col
] == 2))
2177 prints("+" HALF_DOUBLE_LINE_SEP
);
2179 start_col
= end_col
;
2187 void table::print_double_hline(int r
)
2189 prints(".vs " LINE_SEP
"+" DOUBLE_LINE_SEP
2192 "\\v'" BODY_DEPTH
"'"
2193 "\\s[\\n[" LINESIZE_REG
"]]");
2195 prints("\\v'-" DOUBLE_LINE_SEP
"'"
2196 "\\D'l |\\n[TW]u 0'"
2197 "\\v'" DOUBLE_LINE_SEP
"'"
2199 "\\D'l |\\n[TW]u 0'");
2203 while (start_col
< ncolumns
2204 && entry
[r
][start_col
] != 0
2205 && entry
[r
][start_col
]->start_row
!= r
)
2208 for (end_col
= start_col
;
2210 && (entry
[r
][end_col
] == 0
2211 || entry
[r
][end_col
]->start_row
== r
);
2214 if (end_col
<= start_col
)
2216 const char *left_adjust
= 0;
2217 if ((r
> 0 && vline
[r
-1][start_col
] == 2)
2218 || (r
< nrows
&& vline
[r
][start_col
] == 2))
2219 left_adjust
= "-" HALF_DOUBLE_LINE_SEP
;
2220 const char *right_adjust
= 0;
2221 if ((r
> 0 && vline
[r
-1][end_col
] == 2)
2222 || (r
< nrows
&& vline
[r
][end_col
] == 2))
2223 right_adjust
= "+" HALF_DOUBLE_LINE_SEP
;
2224 printfs("\\v'-" DOUBLE_LINE_SEP
"'"
2226 column_divide_reg(start_col
));
2228 prints(left_adjust
);
2230 printfs("\\D'l |\\n[%1]u",
2231 column_divide_reg(end_col
));
2233 prints(right_adjust
);
2235 printfs("\\v'" DOUBLE_LINE_SEP
"'"
2237 column_divide_reg(start_col
));
2239 prints(left_adjust
);
2241 printfs("\\D'l |\\n[%1]u",
2242 column_divide_reg(end_col
));
2244 prints(right_adjust
);
2246 start_col
= end_col
;
2254 void table::compute_vrule_top_adjust(int start_row
, int col
, string
&result
)
2256 if (row_is_all_lines
[start_row
] && start_row
< nrows
- 1) {
2257 if (row_is_all_lines
[start_row
] == 2)
2258 result
= LINE_SEP
">?\\n[.V]u" "+" DOUBLE_LINE_SEP
;
2260 result
= LINE_SEP
">?\\n[.V]u";
2267 for (stuff
*p
= stuff_list
; p
&& p
->row
<= start_row
; p
= p
->next
)
2268 if (p
->row
== start_row
2269 && (p
->is_single_line() || p
->is_double_line()))
2274 table_entry
*e
= entry
[start_row
-1][col
-1];
2275 if (e
&& e
->start_row
== e
->end_row
) {
2276 if (e
->to_double_line_entry() != 0)
2278 else if (e
->to_single_line_entry() != 0)
2283 if (col
< ncolumns
) {
2284 table_entry
*e
= entry
[start_row
-1][col
];
2285 if (e
&& e
->start_row
== e
->end_row
) {
2286 if (e
->to_double_line_entry() != 0)
2288 else if (e
->to_single_line_entry() != 0)
2292 if (row_is_all_lines
[start_row
-1] == 0) {
2293 if (left
> 0 || right
> 0) {
2294 result
+= "-" BODY_DEPTH
"-" BAR_HEIGHT
;
2295 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2296 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2297 else if (left
== 2 && right
== 2)
2298 result
+= "+" HALF_DOUBLE_LINE_SEP
;
2301 else if (row_is_all_lines
[start_row
-1] == 2) {
2302 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2303 result
+= "-" DOUBLE_LINE_SEP
;
2304 else if (left
== 1 || right
== 1)
2305 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2309 void table::compute_vrule_bot_adjust(int end_row
, int col
, string
&result
)
2311 if (row_is_all_lines
[end_row
] && end_row
> 0) {
2317 for (p
= stuff_list
; p
&& p
->row
< end_row
+ 1; p
= p
->next
)
2319 if (p
&& p
->row
== end_row
+ 1 && p
->is_double_line()) {
2320 result
= "-" DOUBLE_LINE_SEP
;
2323 if ((p
!= 0 && p
->row
== end_row
+ 1)
2324 || end_row
== nrows
- 1) {
2328 if (row_is_all_lines
[end_row
+1] == 1)
2330 else if (row_is_all_lines
[end_row
+1] == 2)
2331 result
= LINE_SEP
"+" DOUBLE_LINE_SEP
;
2337 table_entry
*e
= entry
[end_row
+1][col
-1];
2338 if (e
&& e
->start_row
== e
->end_row
) {
2339 if (e
->to_double_line_entry() != 0)
2341 else if (e
->to_single_line_entry() != 0)
2346 if (col
< ncolumns
) {
2347 table_entry
*e
= entry
[end_row
+1][col
];
2348 if (e
&& e
->start_row
== e
->end_row
) {
2349 if (e
->to_double_line_entry() != 0)
2351 else if (e
->to_single_line_entry() != 0)
2355 if (row_is_all_lines
[end_row
+1] == 0) {
2356 if (left
> 0 || right
> 0) {
2357 result
= "1v-" BODY_DEPTH
"-" BAR_HEIGHT
;
2358 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2359 result
+= "+" HALF_DOUBLE_LINE_SEP
;
2360 else if (left
== 2 && right
== 2)
2361 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2364 else if (row_is_all_lines
[end_row
+1] == 2) {
2365 if (left
== 2 && right
== 2)
2366 result
+= "-" DOUBLE_LINE_SEP
;
2367 else if (left
!= 2 && right
!= 2 && (left
== 1 || right
== 1))
2368 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2372 void table::add_vertical_rule(int start_row
, int end_row
, int col
, int is_double
)
2374 vrule_list
= new vertical_rule(start_row
, end_row
, col
, is_double
,
2376 compute_vrule_top_adjust(start_row
, col
, vrule_list
->top_adjust
);
2377 compute_vrule_bot_adjust(end_row
, col
, vrule_list
->bot_adjust
);
2380 void table::build_vrule_list()
2383 if (flags
& ALLBOX
) {
2384 for (col
= 1; col
< ncolumns
; col
++) {
2387 while (start_row
< nrows
&& vline_spanned(start_row
, col
))
2389 if (start_row
>= nrows
)
2391 int end_row
= start_row
;
2392 while (end_row
< nrows
&& !vline_spanned(end_row
, col
))
2395 add_vertical_rule(start_row
, end_row
, col
, 0);
2396 start_row
= end_row
+ 1;
2400 if (flags
& (BOX
|ALLBOX
|DOUBLEBOX
)) {
2401 add_vertical_rule(0, nrows
- 1, 0, 0);
2402 add_vertical_rule(0, nrows
- 1, ncolumns
, 0);
2404 for (int end_row
= 0; end_row
< nrows
; end_row
++)
2405 for (col
= 0; col
< ncolumns
+1; col
++)
2406 if (vline
[end_row
][col
] > 0
2407 && !vline_spanned(end_row
, col
)
2408 && (end_row
== nrows
- 1
2409 || vline
[end_row
+1][col
] != vline
[end_row
][col
]
2410 || vline_spanned(end_row
+1, col
))) {
2412 for (start_row
= end_row
- 1;
2414 && vline
[start_row
][col
] == vline
[end_row
][col
]
2415 && !vline_spanned(start_row
, col
);
2419 add_vertical_rule(start_row
, end_row
, col
, vline
[end_row
][col
] > 1);
2421 for (vertical_rule
*p
= vrule_list
; p
; p
= p
->next
)
2423 for (int r
= p
->start_row
; r
<= p
->end_row
; r
++) {
2424 if (p
->col
> 0 && entry
[r
][p
->col
-1] != 0
2425 && entry
[r
][p
->col
-1]->end_col
== p
->col
-1) {
2426 int is_corner
= r
== p
->start_row
|| r
== p
->end_row
;
2427 entry
[r
][p
->col
-1]->note_double_vrule_on_right(is_corner
);
2429 if (p
->col
< ncolumns
&& entry
[r
][p
->col
] != 0
2430 && entry
[r
][p
->col
]->start_col
== p
->col
) {
2431 int is_corner
= r
== p
->start_row
|| r
== p
->end_row
;
2432 entry
[r
][p
->col
]->note_double_vrule_on_left(is_corner
);
2437 void table::define_bottom_macro()
2441 ".if !\\n[" SUPPRESS_BOTTOM_REG
"] \\{"
2442 "." REPEATED_VPT_MACRO
" 0\n"
2443 ".mk " SAVED_VERTICAL_POS_REG
"\n");
2444 if (flags
& (BOX
|ALLBOX
|DOUBLEBOX
)) {
2445 prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG
"] \\{");
2446 print_single_hline(0);
2450 for (vertical_rule
*p
= vrule_list
; p
; p
= p
->next
)
2451 p
->contribute_to_bottom_macro(this);
2452 if (flags
& DOUBLEBOX
)
2453 prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP
">?\\n[.V]u\n"
2454 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]"
2455 "\\D'l \\n[TW]u 0'\\s0\n"
2458 ".if \\n[" LAST_PASSED_ROW_REG
"]>=0 "
2459 ".nr " TOP_REG
" \\n[#T]-" DOUBLE_LINE_SEP
"\n"
2461 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]"
2462 "\\D'l 0 |\\n[" TOP_REG
"]u-1v'\\s0\n"
2464 "\\v'" BODY_DEPTH
"'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG
"]]"
2465 "\\D'l 0 |\\n[" TOP_REG
"]u-1v'\\s0\n");
2467 prints(".nr " LAST_PASSED_ROW_REG
" \\n[" CURRENT_ROW_REG
"]\n"
2468 ".sp |\\n[" SAVED_VERTICAL_POS_REG
"]u\n"
2469 "." REPEATED_VPT_MACRO
" 1\n"
2475 // is the vertical line before column c in row r horizontally spanned?
2477 int table::vline_spanned(int r
, int c
)
2479 assert(r
>= 0 && r
< nrows
&& c
>= 0 && c
< ncolumns
+ 1);
2480 return (c
!= 0 && c
!= ncolumns
&& entry
[r
][c
] != 0
2481 && entry
[r
][c
]->start_col
!= c
2482 // horizontally spanning lines don't count
2483 && entry
[r
][c
]->to_double_line_entry() == 0
2484 && entry
[r
][c
]->to_single_line_entry() == 0);
2487 int table::row_begins_section(int r
)
2489 assert(r
>= 0 && r
< nrows
);
2490 for (int i
= 0; i
< ncolumns
; i
++)
2491 if (entry
[r
][i
] && entry
[r
][i
]->start_row
!= r
)
2496 int table::row_ends_section(int r
)
2498 assert(r
>= 0 && r
< nrows
);
2499 for (int i
= 0; i
< ncolumns
; i
++)
2500 if (entry
[r
][i
] && entry
[r
][i
]->end_row
!= r
)
2505 void table::do_row(int r
)
2507 if (!(flags
& NOKEEP
) && row_begins_section(r
))
2508 prints("." KEEP_MACRO_NAME
"\n");
2511 for (p
= stuff_list
; p
&& p
->row
< r
; p
= p
->next
)
2513 for (stuff
*p1
= p
; p1
&& p1
->row
== r
; p1
= p1
->next
)
2514 if (!p1
->printed
&& (p1
->is_single_line() || p1
->is_double_line())) {
2518 if (!had_line
&& !row_is_all_lines
[r
])
2519 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2521 for (; p
&& p
->row
== r
; p
= p
->next
)
2524 if (!had_line
&& (p
->is_single_line() || p
->is_double_line())) {
2525 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2529 // Change the row *after* printing the stuff list (which might contain .TH).
2530 printfs("\\*[" TRANSPARENT_STRING_NAME
"].nr " CURRENT_ROW_REG
" %1\n",
2532 if (!had_line
&& row_is_all_lines
[r
])
2533 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2534 // we might have had a .TH, for example, since we last tried
2535 if (!(flags
& NOKEEP
) && row_begins_section(r
))
2536 prints("." KEEP_MACRO_NAME
"\n");
2537 printfs(".mk %1\n", row_start_reg(r
));
2538 prints(".mk " BOTTOM_REG
"\n"
2539 "." REPEATED_VPT_MACRO
" 0\n");
2541 int row_is_blank
= 1;
2542 int first_start_row
= r
;
2543 for (c
= 0; c
< ncolumns
; c
++) {
2544 table_entry
*e
= entry
[r
][c
];
2546 if (e
->end_row
== r
) {
2548 if (e
->start_row
< first_start_row
)
2549 first_start_row
= e
->start_row
;
2556 prints(".nr " BOTTOM_REG
" +1v\n");
2557 if (row_is_all_lines
[r
]) {
2558 prints(".vs " LINE_SEP
);
2559 if (row_is_all_lines
[r
] == 2)
2560 prints("+" DOUBLE_LINE_SEP
);
2561 prints(">?\\n[.V]u\n.ls 1\n");
2563 prints("\\v'" BODY_DEPTH
);
2564 if (row_is_all_lines
[r
] == 2)
2565 prints("-" HALF_DOUBLE_LINE_SEP
);
2567 for (c
= 0; c
< ncolumns
; c
++) {
2568 table_entry
*e
= entry
[r
][c
];
2570 if (e
->end_row
== e
->start_row
)
2571 e
->to_simple_entry()->simple_print(1);
2578 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2579 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2581 for (int i
= row_is_all_lines
[r
] ? r
- 1 : r
;
2582 i
>= first_start_row
;
2584 simple_entry
*first
= 0;
2585 for (c
= 0; c
< ncolumns
; c
++) {
2586 table_entry
*e
= entry
[r
][c
];
2588 if (e
->end_row
== r
&& e
->start_row
== i
) {
2589 simple_entry
*simple
= e
->to_simple_entry();
2603 first
->position_vertically();
2604 first
->set_location();
2606 first
->simple_print(0);
2607 for (c
= first
->end_col
+ 1; c
< ncolumns
; c
++) {
2608 table_entry
*e
= entry
[r
][c
];
2610 if (e
->end_row
== r
&& e
->start_row
== i
) {
2611 simple_entry
*simple
= e
->to_simple_entry();
2613 if (e
->end_row
!= e
->start_row
) {
2615 simple
->position_vertically();
2618 simple
->simple_print(0);
2625 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2626 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2629 for (c
= 0; c
< ncolumns
; c
++) {
2630 table_entry
*e
= entry
[r
][c
];
2632 if (e
->end_row
== r
&& e
->to_simple_entry() == 0) {
2633 e
->position_vertically();
2635 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2636 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2641 prints("." REPEATED_VPT_MACRO
" 1\n"
2642 ".sp |\\n[" BOTTOM_REG
"]u\n"
2643 "\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
" 1\n");
2644 if (r
!= nrows
- 1 && (flags
& ALLBOX
)) {
2645 print_single_hline(r
+ 1);
2646 prints("\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
" 0\n");
2648 if (r
!= nrows
- 1) {
2649 if (p
&& p
->row
== r
+ 1
2650 && (p
->is_single_line() || p
->is_double_line())) {
2652 prints("\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
2655 int printed_one
= 0;
2656 for (vertical_rule
*vr
= vrule_list
; vr
; vr
= vr
->next
)
2657 if (vr
->end_row
== r
) {
2659 prints("." REPEATED_VPT_MACRO
" 0\n");
2665 prints("." REPEATED_VPT_MACRO
" 1\n");
2666 if (!(flags
& NOKEEP
) && row_ends_section(r
))
2667 prints("." RELEASE_MACRO_NAME
"\n");
2671 void table::do_top()
2673 prints(".fc \002\003\n");
2674 if (!(flags
& NOKEEP
) && (flags
& (BOX
|DOUBLEBOX
|ALLBOX
)))
2675 prints("." TABLE_KEEP_MACRO_NAME
"\n");
2676 if (flags
& DOUBLEBOX
) {
2678 ".vs " LINE_SEP
">?\\n[.V]u\n"
2679 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]\\D'l \\n[TW]u 0'\\s0\n"
2681 "." REPEATED_MARK_MACRO
" " TOP_REG
"\n"
2682 ".vs " DOUBLE_LINE_SEP
">?\\n[.V]u\n");
2683 printfs("\\v'" BODY_DEPTH
"'"
2684 "\\s[\\n[" LINESIZE_REG
"]]"
2686 "\\D'l |\\n[%2]u 0'"
2689 column_divide_reg(0),
2690 column_divide_reg(ncolumns
));
2694 else if (flags
& (ALLBOX
|BOX
)) {
2695 print_single_hline(0);
2697 //printfs(".mk %1\n", row_top_reg(0));
2700 void table::do_bottom()
2702 // print stuff after last row
2703 for (stuff
*p
= stuff_list
; p
; p
= p
->next
)
2704 if (p
->row
> nrows
- 1)
2706 if (!(flags
& NOKEEP
))
2707 prints("." RELEASE_MACRO_NAME
"\n");
2708 printfs(".mk %1\n", row_top_reg(nrows
));
2709 prints(".nr " NEED_BOTTOM_RULE_REG
" 1\n"
2712 if (!(flags
& NOKEEP
) && (flags
& (BOX
|DOUBLEBOX
|ALLBOX
)))
2713 prints("." TABLE_RELEASE_MACRO_NAME
"\n");
2714 if (flags
& DOUBLEBOX
)
2715 prints(".sp " DOUBLE_LINE_SEP
"\n");
2716 prints("." RESET_MACRO_NAME
"\n"
2718 ".cp \\n(" COMPATIBLE_REG
"\n");
2721 int table::get_nrows()
2726 const char *last_filename
= 0;
2728 void set_troff_location(const char *fn
, int ln
)
2730 if (!location_force_filename
&& last_filename
!= 0
2731 && strcmp(fn
, last_filename
) == 0)
2732 printfs(".lf %1\n", as_string(ln
));
2734 printfs(".lf %1 %2\n", as_string(ln
), fn
);
2736 location_force_filename
= 0;
2740 void printfs(const char *s
, const string
&arg1
, const string
&arg2
,
2741 const string
&arg3
, const string
&arg4
, const string
&arg5
)
2745 while ((c
= *s
++) != '\0') {