2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #define BAR_HEIGHT ".25m"
24 #define DOUBLE_LINE_SEP "2p"
25 #define HALF_DOUBLE_LINE_SEP "1p"
26 #define BODY_DEPTH ".25m"
27 #define BODY_HEIGHT ".75m"
29 const int DEFAULT_COLUMN_SEPARATION
= 3;
31 #define DELIMITER_CHAR "\\[tbl]"
33 #define SEPARATION_FACTOR_REG PREFIX "sep"
34 #define BOTTOM_REG PREFIX "bot"
35 #define RESET_MACRO_NAME PREFIX "init"
36 #define LINESIZE_REG PREFIX "lps"
37 #define TOP_REG PREFIX "top"
38 #define CURRENT_ROW_REG PREFIX "crow"
39 #define LAST_PASSED_ROW_REG PREFIX "passed"
40 #define TRANSPARENT_STRING_NAME PREFIX "trans"
41 #define QUOTE_STRING_NAME PREFIX "quote"
42 #define SECTION_DIVERSION_NAME PREFIX "section"
43 #define SECTION_DIVERSION_FLAG_REG PREFIX "sflag"
44 #define SAVED_VERTICAL_POS_REG PREFIX "vert"
45 #define NEED_BOTTOM_RULE_REG PREFIX "brule"
46 #define KEEP_MACRO_NAME PREFIX "keep"
47 #define RELEASE_MACRO_NAME PREFIX "release"
48 #define SAVED_FONT_REG PREFIX "fnt"
49 #define SAVED_SIZE_REG PREFIX "sz"
50 #define SAVED_FILL_REG PREFIX "fll"
51 #define SAVED_INDENT_REG PREFIX "ind"
52 #define SAVED_CENTER_REG PREFIX "cent"
53 #define TABLE_DIVERSION_NAME PREFIX "table"
54 #define TABLE_DIVERSION_FLAG_REG PREFIX "tflag"
55 #define TABLE_KEEP_MACRO_NAME PREFIX "tkeep"
56 #define TABLE_RELEASE_MACRO_NAME PREFIX "trelease"
57 #define NEEDED_REG PREFIX "needed"
58 #define REPEATED_MARK_MACRO PREFIX "rmk"
59 #define REPEATED_VPT_MACRO PREFIX "rvpt"
60 #define SUPPRESS_BOTTOM_REG PREFIX "supbot"
61 #define SAVED_DN_REG PREFIX "dn"
63 // this must be one character
64 #define COMPATIBLE_REG PREFIX "c"
66 #define BLOCK_WIDTH_PREFIX PREFIX "tbw"
67 #define BLOCK_DIVERSION_PREFIX PREFIX "tbd"
68 #define BLOCK_HEIGHT_PREFIX PREFIX "tbh"
69 #define SPAN_WIDTH_PREFIX PREFIX "w"
70 #define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw"
71 #define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw"
72 #define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw"
73 #define COLUMN_SEPARATION_PREFIX PREFIX "cs"
74 #define ROW_START_PREFIX PREFIX "rs"
75 #define COLUMN_START_PREFIX PREFIX "cl"
76 #define COLUMN_END_PREFIX PREFIX "ce"
77 #define COLUMN_DIVIDE_PREFIX PREFIX "cd"
78 #define ROW_TOP_PREFIX PREFIX "rt"
79 #define TEXT_STRING_PREFIX PREFIX "s"
80 #define RIGHT_TEXT_STRING_PREFIX PREFIX "ss"
82 string
block_width_reg(int r
, int c
);
83 string
block_diversion_name(int r
, int c
);
84 string
block_height_reg(int r
, int c
);
85 string
span_width_reg(int start_col
, int end_col
);
86 string
span_left_numeric_width_reg(int start_col
, int end_col
);
87 string
span_right_numeric_width_reg(int start_col
, int end_col
);
88 string
span_alphabetic_width_reg(int start_col
, int end_col
);
89 string
column_separation_reg(int col
);
90 string
row_start_reg(int r
);
91 string
column_start_reg(int c
);
92 string
column_end_reg(int c
);
93 string
column_divide_reg(int c
);
94 string
row_top_reg(int r
);
95 string
text_string_name(int r
, int c
);
96 string
right_text_string_name(int r
, int c
);
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_dot(const char *s
, const char *delim
);
103 string an_empty_string
;
104 int location_force_filename
= 0;
106 void printfs(const char *,
107 const string
&arg1
= an_empty_string
,
108 const string
&arg2
= an_empty_string
,
109 const string
&arg3
= an_empty_string
,
110 const string
&arg4
= an_empty_string
,
111 const string
&arg5
= an_empty_string
);
113 void prints(const char *);
114 void prints(const string
&);
117 inline void prints(char c
)
122 inline void prints(const char *s
)
127 void prints(const string
&s
)
130 fwrite(s
.contents(), 1, s
.length(), stdout
);
133 struct horizontal_span
{
134 horizontal_span
*next
;
137 horizontal_span(int, int, horizontal_span
*);
140 struct single_line_entry
;
141 struct double_line_entry
;
148 const char *input_filename
;
154 const entry_modifier
*mod
;
157 table_entry(const entry_modifier
*);
158 virtual ~table_entry();
159 virtual int divert(int ncols
, const string
*mw
);
160 virtual void do_width();
161 virtual void do_depth();
162 virtual void print() = 0;
163 virtual void position_vertically() = 0;
164 virtual single_line_entry
*to_single_line_entry();
165 virtual double_line_entry
*to_double_line_entry();
166 virtual simple_entry
*to_simple_entry();
167 virtual int line_type();
168 virtual void note_double_vrule_on_right(int);
169 virtual void note_double_vrule_on_left(int);
172 class simple_entry
: public table_entry
{
174 simple_entry(const entry_modifier
*);
176 void position_vertically();
177 simple_entry
*to_simple_entry();
178 virtual void add_tab();
179 virtual void simple_print(int);
182 class empty_entry
: public simple_entry
{
184 empty_entry(const entry_modifier
*);
188 class text_entry
: public simple_entry
{
192 text_entry(char *, const entry_modifier
*);
196 class repeated_char_entry
: public text_entry
{
198 repeated_char_entry(char *s
, const entry_modifier
*m
);
199 void simple_print(int);
202 class simple_text_entry
: public text_entry
{
204 simple_text_entry(char *s
, const entry_modifier
*m
);
208 class left_text_entry
: public simple_text_entry
{
210 left_text_entry(char *s
, const entry_modifier
*m
);
211 void simple_print(int);
215 class right_text_entry
: public simple_text_entry
{
217 right_text_entry(char *s
, const entry_modifier
*m
);
218 void simple_print(int);
222 class center_text_entry
: public simple_text_entry
{
224 center_text_entry(char *s
, const entry_modifier
*m
);
225 void simple_print(int);
229 class numeric_text_entry
: public text_entry
{
232 numeric_text_entry(char *s
, const entry_modifier
*m
, int pos
);
234 void simple_print(int);
237 class alphabetic_text_entry
: public text_entry
{
239 alphabetic_text_entry(char *s
, const entry_modifier
*m
);
241 void simple_print(int);
245 class line_entry
: public simple_entry
{
247 char double_vrule_on_right
;
248 char double_vrule_on_left
;
250 line_entry(const entry_modifier
*);
251 void note_double_vrule_on_right(int);
252 void note_double_vrule_on_left(int);
253 void simple_print(int) = 0;
256 class single_line_entry
: public line_entry
{
258 single_line_entry(const entry_modifier
*m
);
259 void simple_print(int);
260 single_line_entry
*to_single_line_entry();
264 class double_line_entry
: public line_entry
{
266 double_line_entry(const entry_modifier
*m
);
267 void simple_print(int);
268 double_line_entry
*to_double_line_entry();
272 class short_line_entry
: public simple_entry
{
274 short_line_entry(const entry_modifier
*m
);
275 void simple_print(int);
279 class short_double_line_entry
: public simple_entry
{
281 short_double_line_entry(const entry_modifier
*m
);
282 void simple_print(int);
286 class block_entry
: public table_entry
{
289 void do_divert(int alphabetic
, int ncols
, const string
*mw
);
291 block_entry(char *s
, const entry_modifier
*m
);
293 int divert(int ncols
, const string
*mw
);
296 void position_vertically();
300 class left_block_entry
: public block_entry
{
302 left_block_entry(char *s
, const entry_modifier
*m
);
306 class right_block_entry
: public block_entry
{
308 right_block_entry(char *s
, const entry_modifier
*m
);
312 class center_block_entry
: public block_entry
{
314 center_block_entry(char *s
, const entry_modifier
*m
);
318 class alphabetic_block_entry
: public block_entry
{
320 alphabetic_block_entry(char *s
, const entry_modifier
*m
);
322 int divert(int ncols
, const string
*mw
);
325 table_entry::table_entry(const entry_modifier
*m
)
326 : next(0), start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m
),
327 input_lineno(-1), input_filename(0)
331 table_entry::~table_entry()
335 int table_entry::divert(int, const string
*)
340 void table_entry::do_width()
344 single_line_entry
*table_entry::to_single_line_entry()
349 double_line_entry
*table_entry::to_double_line_entry()
354 simple_entry
*table_entry::to_simple_entry()
359 void table_entry::do_depth()
363 void table_entry::set_location()
365 set_troff_location(input_filename
, input_lineno
);
368 int table_entry::line_type()
373 void table_entry::note_double_vrule_on_right(int)
377 void table_entry::note_double_vrule_on_left(int)
381 simple_entry::simple_entry(const entry_modifier
*m
) : table_entry(m
)
385 void simple_entry::add_tab()
390 void simple_entry::simple_print(int)
395 void simple_entry::position_vertically()
397 if (start_row
!= end_row
)
398 switch (mod
->vertical_alignment
) {
399 case entry_modifier::TOP
:
400 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
402 case entry_modifier::CENTER
:
403 // Peform the motion in two stages so that the center is rounded
404 // vertically upwards even if net vertical motion is upwards.
405 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
406 printfs(".sp \\n[" BOTTOM_REG
"]u-\\n[%1]u-1v/2u\n",
407 row_start_reg(start_row
));
409 case entry_modifier::BOTTOM
:
410 printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG
"]u-\\n[%1]u-1v\n",
411 row_start_reg(start_row
));
418 void simple_entry::print()
429 simple_entry
*simple_entry::to_simple_entry()
434 empty_entry::empty_entry(const entry_modifier
*m
)
439 int empty_entry::line_type()
444 text_entry::text_entry(char *s
, const entry_modifier
*m
)
445 : contents(s
), simple_entry(m
)
449 text_entry::~text_entry()
455 repeated_char_entry::repeated_char_entry(char *s
, const entry_modifier
*m
)
460 void repeated_char_entry::simple_print(int)
462 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
463 set_inline_modifier(mod
);
464 printfs("\\l" DELIMITER_CHAR
"\\n[%1]u\\&", span_width_reg(start_col
, end_col
));
466 prints(DELIMITER_CHAR
);
467 restore_inline_modifier(mod
);
470 simple_text_entry::simple_text_entry(char *s
, const entry_modifier
*m
)
475 void simple_text_entry::do_width()
477 printfs(".ds %1 \"", text_string_name(start_row
, start_col
));
478 set_inline_modifier(mod
);
480 restore_inline_modifier(mod
);
483 printfs(".nr %1 \\n[%1]>?\\w'\\*[%2]'\n",
484 span_width_reg(start_col
, end_col
),
485 text_string_name(start_row
, start_col
));
488 left_text_entry::left_text_entry(char *s
, const entry_modifier
*m
)
489 : simple_text_entry(s
, m
)
493 void left_text_entry::simple_print(int)
495 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
496 printfs("\\*[%1]", text_string_name(start_row
, start_col
));
499 // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
501 void left_text_entry::add_tab()
503 printfs(" \\n[%1]u", column_end_reg(end_col
));
506 right_text_entry::right_text_entry(char *s
, const entry_modifier
*m
)
507 : simple_text_entry(s
, m
)
511 void right_text_entry::simple_print(int)
513 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
514 printfs("\002\003\\*[%1]\002", text_string_name(start_row
, start_col
));
517 void right_text_entry::add_tab()
519 printfs(" \\n[%1]u", column_end_reg(end_col
));
522 center_text_entry::center_text_entry(char *s
, const entry_modifier
*m
)
523 : simple_text_entry(s
, m
)
527 void center_text_entry::simple_print(int)
529 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
530 printfs("\002\003\\*[%1]\003\002", text_string_name(start_row
, start_col
));
533 void center_text_entry::add_tab()
535 printfs(" \\n[%1]u", column_end_reg(end_col
));
538 numeric_text_entry::numeric_text_entry(char *s
, const entry_modifier
*m
, int pos
)
539 : text_entry(s
, m
), dot_pos(pos
)
543 void numeric_text_entry::do_width()
546 printfs(".ds %1 \"", text_string_name(start_row
, start_col
));
547 set_inline_modifier(mod
);
548 for (int i
= 0; i
< dot_pos
; i
++)
550 restore_inline_modifier(mod
);
553 printfs(".nr %1 0\\w'\\*[%2]'\n",
554 block_width_reg(start_row
, start_col
),
555 text_string_name(start_row
, start_col
));
556 printfs(".nr %1 \\n[%1]>?\\n[%2]\n",
557 span_left_numeric_width_reg(start_col
, end_col
),
558 block_width_reg(start_row
, start_col
));
561 printfs(".nr %1 0\n", block_width_reg(start_row
, start_col
));
562 if (contents
[dot_pos
] != '\0') {
563 printfs(".ds %1 \"", right_text_string_name(start_row
, start_col
));
564 set_inline_modifier(mod
);
565 prints(contents
+ dot_pos
);
566 restore_inline_modifier(mod
);
569 printfs(".nr %1 \\n[%1]>?\\w'\\*[%2]'\n",
570 span_right_numeric_width_reg(start_col
, end_col
),
571 right_text_string_name(start_row
, start_col
));
575 void numeric_text_entry::simple_print(int)
577 printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'",
578 span_width_reg(start_col
, end_col
),
579 span_left_numeric_width_reg(start_col
, end_col
),
580 span_right_numeric_width_reg(start_col
, end_col
),
581 column_start_reg(start_col
),
582 block_width_reg(start_row
, start_col
));
584 printfs("\\*[%1]", text_string_name(start_row
, start_col
));
586 if (contents
[dot_pos
] != '\0')
587 printfs("\\*[%1]", right_text_string_name(start_row
, start_col
));
590 alphabetic_text_entry::alphabetic_text_entry(char *s
, const entry_modifier
*m
)
595 void alphabetic_text_entry::do_width()
597 printfs(".ds %1 \"", text_string_name(start_row
, start_col
));
598 set_inline_modifier(mod
);
600 restore_inline_modifier(mod
);
603 printfs(".nr %1 \\n[%1]>?\\w'\\*[%2]'\n",
604 span_alphabetic_width_reg(start_col
, end_col
),
605 text_string_name(start_row
, start_col
));
608 void alphabetic_text_entry::simple_print(int)
610 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
611 printfs("\\h'\\n[%1]u-\\n[%2]u/2u'",
612 span_width_reg(start_col
, end_col
),
613 span_alphabetic_width_reg(start_col
, end_col
));
614 printfs("\\*[%1]", text_string_name(start_row
, start_col
));
617 // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
619 void alphabetic_text_entry::add_tab()
621 printfs(" \\n[%1]u", column_end_reg(end_col
));
624 block_entry::block_entry(char *s
, const entry_modifier
*m
)
625 : table_entry(m
), contents(s
)
629 block_entry::~block_entry()
634 void block_entry::position_vertically()
636 if (start_row
!= end_row
)
637 switch(mod
->vertical_alignment
) {
638 case entry_modifier::TOP
:
639 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
641 case entry_modifier::CENTER
:
642 // Peform the motion in two stages so that the center is rounded
643 // vertically upwards even if net vertical motion is upwards.
644 printfs(".sp |\\n[%1]u\n", row_start_reg(start_row
));
645 printfs(".sp \\n[" BOTTOM_REG
"]u-\\n[%1]u-\\n[%2]u/2u\n",
646 row_start_reg(start_row
),
647 block_height_reg(start_row
, start_col
));
649 case entry_modifier::BOTTOM
:
650 printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG
"]u-\\n[%1]u-\\n[%2]u\n",
651 row_start_reg(start_row
),
652 block_height_reg(start_row
, start_col
));
658 prints(".sp -.5v\n");
661 int block_entry::divert(int ncols
, const string
*mw
)
663 do_divert(0, ncols
, mw
);
667 void block_entry::do_divert(int alphabetic
, int ncols
, const string
*mw
)
669 printfs(".di %1\n", block_diversion_name(start_row
, start_col
));
670 prints(".if \\n[" SAVED_FILL_REG
"] .fi\n"
672 if (start_col
== end_col
&& !mw
[start_col
].empty())
673 printfs(".ll (n;%1)>?\\n[%2]u",
675 span_width_reg(start_col
, start_col
));
677 printfs(".ll (u;\\n[%1]>?(\\n[.l]*%2/%3))",
678 span_width_reg(start_col
, end_col
),
679 as_string(end_col
- start_col
+ 1),
680 as_string(ncols
+ 1));
685 prints(".cp \\n(" COMPATIBLE_REG
"\n");
688 prints(".br\n.di\n.cp 0\n");
689 if (!mod
->zero_width
) {
691 printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n",
692 span_width_reg(start_col
, end_col
));
693 printfs(".nr %1 \\n[%1]>?\\n[dl]\n",
694 span_alphabetic_width_reg(start_col
, end_col
));
697 printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col
, end_col
));
699 printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row
, start_col
));
700 printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row
, start_col
));
701 prints("." RESET_MACRO_NAME
"\n"
702 ".in \\n[" SAVED_INDENT_REG
"]u\n"
704 // the block might have contained .lf commands
705 location_force_filename
= 1;
708 void block_entry::do_width()
710 // do nothing; the action happens in divert
713 void block_entry::do_depth()
715 printfs(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?(\\n[%1]+\\n[%2])\n",
716 row_start_reg(start_row
),
717 block_height_reg(start_row
, start_col
));
720 left_block_entry::left_block_entry(char *s
, const entry_modifier
*m
)
725 void left_block_entry::print()
727 printfs(".in +\\n[%1]u\n", column_start_reg(start_col
));
728 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
734 right_block_entry::right_block_entry(char *s
, const entry_modifier
*m
)
739 void right_block_entry::print()
741 printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n",
742 column_start_reg(start_col
),
743 span_width_reg(start_col
, end_col
),
744 block_width_reg(start_row
, start_col
));
745 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
749 center_block_entry::center_block_entry(char *s
, const entry_modifier
*m
)
754 void center_block_entry::print()
756 printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
757 column_start_reg(start_col
),
758 span_width_reg(start_col
, end_col
),
759 block_width_reg(start_row
, start_col
));
760 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
764 alphabetic_block_entry::alphabetic_block_entry(char *s
,
765 const entry_modifier
*m
)
770 int alphabetic_block_entry::divert(int ncols
, const string
*mw
)
772 do_divert(1, ncols
, mw
);
776 void alphabetic_block_entry::print()
778 printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
779 column_start_reg(start_col
),
780 span_width_reg(start_col
, end_col
),
781 span_alphabetic_width_reg(start_row
, end_col
));
782 printfs(".%1\n", block_diversion_name(start_row
, start_col
));
786 line_entry::line_entry(const entry_modifier
*m
)
787 : simple_entry(m
), double_vrule_on_right(0), double_vrule_on_left(0)
791 void line_entry::note_double_vrule_on_right(int is_corner
)
793 double_vrule_on_right
= is_corner
? 1 : 2;
796 void line_entry::note_double_vrule_on_left(int is_corner
)
798 double_vrule_on_left
= is_corner
? 1 : 2;
802 single_line_entry::single_line_entry(const entry_modifier
*m
)
807 int single_line_entry::line_type()
812 void single_line_entry::simple_print(int dont_move
)
814 printfs("\\h'|\\n[%1]u",
815 column_divide_reg(start_col
));
816 if (double_vrule_on_left
) {
817 prints(double_vrule_on_left
== 1 ? "-" : "+");
818 prints(HALF_DOUBLE_LINE_SEP
);
822 prints("\\v'-" BAR_HEIGHT
"'");
823 printfs("\\s[\\n[" LINESIZE_REG
"]]" "\\D'l |\\n[%1]u",
824 column_divide_reg(end_col
+1));
825 if (double_vrule_on_right
) {
826 prints(double_vrule_on_left
== 1 ? "+" : "-");
827 prints(HALF_DOUBLE_LINE_SEP
);
831 prints("\\v'" BAR_HEIGHT
"'");
834 single_line_entry
*single_line_entry::to_single_line_entry()
839 double_line_entry::double_line_entry(const entry_modifier
*m
)
844 int double_line_entry::line_type()
849 void double_line_entry::simple_print(int dont_move
)
852 prints("\\v'-" BAR_HEIGHT
"'");
853 printfs("\\h'|\\n[%1]u",
854 column_divide_reg(start_col
));
855 if (double_vrule_on_left
) {
856 prints(double_vrule_on_left
== 1 ? "-" : "+");
857 prints(HALF_DOUBLE_LINE_SEP
);
860 printfs("\\v'-" HALF_DOUBLE_LINE_SEP
"'"
861 "\\s[\\n[" LINESIZE_REG
"]]"
863 column_divide_reg(end_col
+1));
864 if (double_vrule_on_right
)
865 prints("-" HALF_DOUBLE_LINE_SEP
);
867 printfs("\\v'" DOUBLE_LINE_SEP
"'"
869 column_divide_reg(start_col
));
870 if (double_vrule_on_right
) {
871 prints(double_vrule_on_left
== 1 ? "+" : "-");
872 prints(HALF_DOUBLE_LINE_SEP
);
876 "\\v'-" HALF_DOUBLE_LINE_SEP
"'");
878 prints("\\v'" BAR_HEIGHT
"'");
881 double_line_entry
*double_line_entry::to_double_line_entry()
886 short_line_entry::short_line_entry(const entry_modifier
*m
)
891 int short_line_entry::line_type()
896 void short_line_entry::simple_print(int dont_move
)
901 prints("\\v'-" BAR_HEIGHT
"'");
902 printfs("\\h'|\\n[%1]u'", column_start_reg(start_col
));
903 printfs("\\s[\\n[" LINESIZE_REG
"]]"
906 span_width_reg(start_col
, end_col
));
908 prints("\\v'" BAR_HEIGHT
"'");
913 short_double_line_entry::short_double_line_entry(const entry_modifier
*m
)
918 int short_double_line_entry::line_type()
923 void short_double_line_entry::simple_print(int dont_move
)
928 prints("\\v'-" BAR_HEIGHT
"'");
929 printfs("\\h'|\\n[%2]u'"
930 "\\v'-" HALF_DOUBLE_LINE_SEP
"'"
931 "\\s[\\n[" LINESIZE_REG
"]]"
933 "\\v'" DOUBLE_LINE_SEP
"'"
936 "\\v'-" HALF_DOUBLE_LINE_SEP
"'",
937 span_width_reg(start_col
, end_col
),
938 column_start_reg(start_col
));
940 prints("\\v'" BAR_HEIGHT
"'");
945 void set_modifier(const entry_modifier
*m
)
947 if (!m
->font
.empty())
948 printfs(".ft %1\n", m
->font
);
949 if (m
->point_size
.val
!= 0) {
951 if (m
->point_size
.inc
> 0)
953 else if (m
->point_size
.inc
< 0)
955 printfs("%1\n", as_string(m
->point_size
.val
));
957 if (m
->vertical_spacing
.val
!= 0) {
959 if (m
->vertical_spacing
.inc
> 0)
961 else if (m
->vertical_spacing
.inc
< 0)
963 printfs("%1\n", as_string(m
->vertical_spacing
.val
));
967 void set_inline_modifier(const entry_modifier
*m
)
969 if (!m
->font
.empty())
970 printfs("\\f[%1]", m
->font
);
971 if (m
->point_size
.val
!= 0) {
973 if (m
->point_size
.inc
> 0)
975 else if (m
->point_size
.inc
< 0)
977 printfs("%1]", as_string(m
->point_size
.val
));
983 void restore_inline_modifier(const entry_modifier
*m
)
985 if (!m
->font
.empty())
986 prints("\\f[\\n[" SAVED_FONT_REG
"]]");
987 if (m
->point_size
.val
!= 0)
988 prints("\\s[\\n[" SAVED_SIZE_REG
"]]");
996 int row
; // occurs before row `row'
997 char printed
; // has it been printed?
1000 virtual void print(table
*) = 0;
1002 virtual int is_single_line() { return 0; };
1003 virtual int is_double_line() { return 0; };
1006 stuff::stuff(int r
) : row(r
), next(0), printed(0)
1014 struct text_stuff
: stuff
{
1016 const char *filename
;
1019 text_stuff(const string
&, int r
, const char *fn
, int ln
);
1021 void print(table
*);
1025 text_stuff::text_stuff(const string
&s
, int r
, const char *fn
, int ln
)
1026 : contents(s
), stuff(r
), filename(fn
), lineno(ln
)
1030 text_stuff::~text_stuff()
1034 void text_stuff::print(table
*)
1037 prints(".cp \\n(" COMPATIBLE_REG
"\n");
1038 set_troff_location(filename
, lineno
);
1041 location_force_filename
= 1; // it might have been a .lf command
1044 struct single_hline_stuff
: stuff
{
1045 single_hline_stuff(int r
);
1046 void print(table
*);
1047 int is_single_line();
1050 single_hline_stuff::single_hline_stuff(int r
) : stuff(r
)
1054 void single_hline_stuff::print(table
*tbl
)
1057 tbl
->print_single_hline(row
);
1060 int single_hline_stuff::is_single_line()
1065 struct double_hline_stuff
: stuff
{
1066 double_hline_stuff(int r
);
1067 void print(table
*);
1068 int is_double_line();
1071 double_hline_stuff::double_hline_stuff(int r
) : stuff(r
)
1075 void double_hline_stuff::print(table
*tbl
)
1078 tbl
->print_double_hline(row
);
1081 int double_hline_stuff::is_double_line()
1086 struct vertical_rule
{
1087 vertical_rule
*next
;
1095 vertical_rule(int sr
, int er
, int c
, int dbl
, vertical_rule
*);
1097 void contribute_to_bottom_macro(table
*);
1101 vertical_rule::vertical_rule(int sr
, int er
, int c
, int dbl
, vertical_rule
*p
)
1102 : start_row(sr
), end_row(er
), col(c
), is_double(dbl
), next(p
)
1106 vertical_rule::~vertical_rule()
1110 void vertical_rule::contribute_to_bottom_macro(table
*tbl
)
1112 printfs(".if \\n[" CURRENT_ROW_REG
"]>=%1",
1113 as_string(start_row
));
1114 if (end_row
!= tbl
->get_nrows() - 1)
1115 printfs("&(\\n[" CURRENT_ROW_REG
"]<%1)",
1116 as_string(end_row
));
1118 printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG
"] .nr %2 \\n[#T]\n",
1119 as_string(start_row
),
1120 row_top_reg(start_row
));
1121 const char *offset_table
[3];
1123 offset_table
[0] = "-" HALF_DOUBLE_LINE_SEP
;
1124 offset_table
[1] = "+" HALF_DOUBLE_LINE_SEP
;
1125 offset_table
[2] = 0;
1128 offset_table
[0] = "";
1129 offset_table
[1] = 0;
1131 for (const char **offsetp
= offset_table
; *offsetp
; offsetp
++) {
1134 if (!bot_adjust
.empty())
1135 printfs("+%1", bot_adjust
);
1137 printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG
"]]\\D'l 0 |\\n[%2]u-1v",
1138 column_divide_reg(col
),
1139 row_top_reg(start_row
),
1141 if (!bot_adjust
.empty())
1142 printfs("-(%1)", bot_adjust
);
1143 // don't perform the top adjustment if the top is actually #T
1144 if (!top_adjust
.empty())
1145 printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG
"]))",
1147 as_string(start_row
));
1153 void vertical_rule::print()
1155 printfs("\\*[" TRANSPARENT_STRING_NAME
"]"
1156 ".if %1<=\\*[" QUOTE_STRING_NAME
"]\\n[" LAST_PASSED_ROW_REG
"] "
1157 ".nr %2 \\*[" QUOTE_STRING_NAME
"]\\n[#T]\n",
1158 as_string(start_row
),
1159 row_top_reg(start_row
));
1160 const char *offset_table
[3];
1162 offset_table
[0] = "-" HALF_DOUBLE_LINE_SEP
;
1163 offset_table
[1] = "+" HALF_DOUBLE_LINE_SEP
;
1164 offset_table
[2] = 0;
1167 offset_table
[0] = "";
1168 offset_table
[1] = 0;
1170 for (const char **offsetp
= offset_table
; *offsetp
; offsetp
++) {
1171 prints("\\*[" TRANSPARENT_STRING_NAME
"].sp -1\n"
1172 "\\*[" TRANSPARENT_STRING_NAME
"]\\v'" BODY_DEPTH
);
1173 if (!bot_adjust
.empty())
1174 printfs("+%1", bot_adjust
);
1176 printfs("\\h'\\n[%1]u%3'"
1177 "\\s[\\n[" LINESIZE_REG
"]]"
1178 "\\D'l 0 |\\*[" QUOTE_STRING_NAME
"]\\n[%2]u-1v",
1179 column_divide_reg(col
),
1180 row_top_reg(start_row
),
1182 if (!bot_adjust
.empty())
1183 printfs("-(%1)", bot_adjust
);
1184 // don't perform the top adjustment if the top is actually #T
1185 if (!top_adjust
.empty())
1186 printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME
"]\\n["
1187 LAST_PASSED_ROW_REG
"]))",
1189 as_string(start_row
));
1195 table::table(int nc
, unsigned f
, int ls
)
1196 : ncolumns(nc
), flags(f
), linesize(ls
),
1197 nrows(0), allocated_rows(0), entry(0), entry_list(0),
1198 left_separation(0), right_separation(0), stuff_list(0), vline(0),
1199 vrule_list(0), row_is_all_lines(0), span_list(0)
1201 minimum_width
= new string
[ncolumns
];
1202 column_separation
= new int[ncolumns
- 1];
1203 equal
= new char[ncolumns
];
1205 for (i
= 0; i
< ncolumns
; i
++)
1207 for (i
= 0; i
< ncolumns
-1; i
++)
1208 column_separation
[i
] = DEFAULT_COLUMN_SEPARATION
;
1209 delim
[0] = delim
[1] = '\0';
1214 for (int i
= 0; i
< nrows
; i
++) {
1220 while (entry_list
) {
1221 table_entry
*tem
= entry_list
;
1222 entry_list
= entry_list
->next
;
1225 ad_delete(ncolumns
) minimum_width
;
1226 a_delete column_separation
;
1228 while (stuff_list
) {
1229 stuff
*tem
= stuff_list
;
1230 stuff_list
= stuff_list
->next
;
1233 while (vrule_list
) {
1234 vertical_rule
*tem
= vrule_list
;
1235 vrule_list
= vrule_list
->next
;
1238 a_delete row_is_all_lines
;
1240 horizontal_span
*tem
= span_list
;
1241 span_list
= span_list
->next
;
1246 void table::set_delim(char c1
, char c2
)
1252 void table::set_minimum_width(int c
, const string
&w
)
1254 assert(c
>= 0 && c
< ncolumns
);
1255 minimum_width
[c
] = w
;
1258 void table::set_column_separation(int c
, int n
)
1260 assert(c
>= 0 && c
< ncolumns
- 1);
1261 column_separation
[c
] = n
;
1264 void table::set_equal_column(int c
)
1266 assert(c
>= 0 && c
< ncolumns
);
1270 void table::add_stuff(stuff
*p
)
1272 for (stuff
**pp
= &stuff_list
; *pp
; pp
= &(*pp
)->next
)
1277 void table::add_text_line(int r
, const string
&s
, const char *filename
, int lineno
)
1279 add_stuff(new text_stuff(s
, r
, filename
, lineno
));
1282 void table::add_single_hline(int r
)
1284 add_stuff(new single_hline_stuff(r
));
1287 void table::add_double_hline(int r
)
1289 add_stuff(new double_hline_stuff(r
));
1292 void table::allocate(int r
)
1295 typedef table_entry
**PPtable_entry
; // work around g++ 1.36.1 bug
1296 if (r
>= allocated_rows
) {
1297 if (allocated_rows
== 0) {
1298 allocated_rows
= 16;
1299 if (allocated_rows
<= r
)
1300 allocated_rows
= r
+ 1;
1301 entry
= new PPtable_entry
[allocated_rows
];
1302 vline
= new char*[allocated_rows
];
1305 table_entry
***old_entry
= entry
;
1306 int old_allocated_rows
= allocated_rows
;
1307 allocated_rows
*= 2;
1308 if (allocated_rows
<= r
)
1309 allocated_rows
= r
+ 1;
1310 entry
= new PPtable_entry
[allocated_rows
];
1311 memcpy(entry
, old_entry
, sizeof(table_entry
**)*old_allocated_rows
);
1313 char **old_vline
= vline
;
1314 vline
= new char*[allocated_rows
];
1315 memcpy(vline
, old_vline
, sizeof(char*)*old_allocated_rows
);
1319 assert(allocated_rows
> r
);
1320 while (nrows
<= r
) {
1321 entry
[nrows
] = new table_entry
*[ncolumns
];
1322 for (int i
= 0; i
< ncolumns
; i
++)
1323 entry
[nrows
][i
] = 0;
1324 vline
[nrows
] = new char[ncolumns
+1];
1325 for (i
= 0; i
< ncolumns
+1; i
++)
1326 vline
[nrows
][i
] = 0;
1332 void table::do_hspan(int r
, int c
)
1334 assert(r
>= 0 && c
>= 0 && r
< nrows
&& c
< ncolumns
);
1336 error("first column cannot be horizontally spanned");
1339 table_entry
*e
= entry
[r
][c
];
1341 assert(e
->start_row
<= r
&& r
<= e
->end_row
1342 && e
->start_col
<= c
&& c
<= e
->end_col
1343 && e
->end_row
- e
->start_row
> 0
1344 && e
->end_col
- e
->start_col
> 0);
1348 // e can be 0 if we had an empty entry or an error
1351 if (e
->start_row
!= r
) {
1355 error("impossible horizontal span at row %1, column %2", r
+ 1, c
+ 1);
1363 void table::do_vspan(int r
, int c
)
1365 assert(r
>= 0 && c
>= 0 && r
< nrows
&& c
< ncolumns
);
1367 error("first row cannot be vertically spanned");
1370 table_entry
*e
= entry
[r
][c
];
1372 assert(e
->start_row
<= r
&& r
<= e
->end_row
1373 && e
->start_col
<= c
&& c
<= e
->end_col
1374 && e
->end_row
- e
->start_row
> 0
1375 && e
->end_col
- e
->start_col
> 0);
1379 // e can be 0 if we had an empty entry or an error
1382 if (e
->start_col
!= c
) {
1385 error("impossible vertical span at row %1, column %2", r
+ 1, c
+ 1);
1388 for (int i
= c
; i
<= e
->end_col
; i
++) {
1389 assert(entry
[r
][i
] == 0);
1396 int find_dot(const char *s
, const char *delim
)
1398 if (s
== 0 || *s
== '\0')
1401 int in_delim
= 0; // is p within eqn delimiters?
1402 // tbl recognises \& even within eqn delimiters; I don't
1403 for (p
= s
; *p
; p
++)
1408 else if (*p
== delim
[0])
1410 else if (p
[0] == '\\' && p
[1] == '&')
1412 int possible_pos
= -1;
1414 for (p
= s
; *p
; p
++)
1419 else if (*p
== delim
[0])
1421 else if (p
[0] == '.' && csdigit(p
[1]))
1422 possible_pos
= p
- s
;
1423 if (possible_pos
>= 0)
1424 return possible_pos
;
1426 for (p
= s
; *p
; p
++)
1431 else if (*p
== delim
[0])
1433 else if (csdigit(*p
))
1434 possible_pos
= p
+ 1 - s
;
1435 return possible_pos
;
1438 void table::add_entry(int r
, int c
, const string
&str
, const entry_format
*f
,
1439 const char *fn
, int ln
)
1444 e
= new short_line_entry(f
);
1446 else if (str
== "\\=") {
1447 e
= new short_double_line_entry(f
);
1449 else if (str
== "_") {
1450 single_line_entry
*lefte
;
1451 if (c
> 0 && entry
[r
][c
-1] != 0 &&
1452 (lefte
= entry
[r
][c
-1]->to_single_line_entry()) != 0
1453 && lefte
->start_row
== r
1454 && lefte
->mod
->stagger
== f
->stagger
) {
1456 entry
[r
][c
] = lefte
;
1459 e
= new single_line_entry(f
);
1461 else if (str
== "=") {
1462 double_line_entry
*lefte
;
1463 if (c
> 0 && entry
[r
][c
-1] != 0 &&
1464 (lefte
= entry
[r
][c
-1]->to_double_line_entry()) != 0
1465 && lefte
->start_row
== r
1466 && lefte
->mod
->stagger
== f
->stagger
) {
1468 entry
[r
][c
] = lefte
;
1471 e
= new double_line_entry(f
);
1473 else if (str
== "\\^") {
1476 else if (str
.length() > 2 && str
[0] == '\\' && str
[1] == 'R') {
1477 if (str
.search('\n') >= 0)
1478 error_with_file_and_line(fn
, ln
, "bad repeated character");
1480 char *s
= str
.substring(2, str
.length() - 2).extract();
1481 e
= new repeated_char_entry(s
, f
);
1485 int is_block
= str
.search('\n') >= 0;
1489 assert(str
.empty());
1496 e
= new left_block_entry(s
, f
);
1498 e
= new left_text_entry(s
, f
);
1501 e
= new empty_entry(f
);
1507 e
= new center_block_entry(s
, f
);
1509 e
= new center_text_entry(s
, f
);
1512 e
= new empty_entry(f
);
1518 e
= new right_block_entry(s
, f
);
1520 e
= new right_text_entry(s
, f
);
1523 e
= new empty_entry(f
);
1525 case FORMAT_NUMERIC
:
1529 error_with_file_and_line(fn
, ln
, "can't have numeric text block");
1530 e
= new left_block_entry(s
, f
);
1533 int pos
= find_dot(s
, delim
);
1535 e
= new center_text_entry(s
, f
);
1537 e
= new numeric_text_entry(s
, f
, pos
);
1541 e
= new empty_entry(f
);
1543 case FORMAT_ALPHABETIC
:
1547 e
= new alphabetic_block_entry(s
, f
);
1549 e
= new alphabetic_text_entry(s
, f
);
1552 e
= new empty_entry(f
);
1558 if (str
.length() != 0)
1559 error_with_file_and_line(fn
, ln
,
1560 "non-empty data entry for `_' format ignored");
1561 e
= new single_line_entry(f
);
1563 case FORMAT_DOUBLE_HLINE
:
1564 if (str
.length() != 0)
1565 error_with_file_and_line(fn
, ln
,
1566 "non-empty data entry for `=' format ignored");
1567 e
= new double_line_entry(f
);
1574 table_entry
*preve
= entry
[r
][c
];
1578 error_with_file_and_line(fn
, ln
, "row %1, column %2 already spanned",
1583 e
->input_lineno
= ln
;
1584 e
->input_filename
= fn
;
1585 e
->start_row
= e
->end_row
= r
;
1586 e
->start_col
= e
->end_col
= c
;
1587 for (table_entry
**p
= &entry_list
; *p
; p
= &(*p
)->next
)
1595 // add vertical lines for row r
1597 void table::add_vlines(int r
, const char *v
)
1600 for (int i
= 0; i
< ncolumns
+1; i
++)
1606 table_entry
*p
= entry_list
;
1609 for (i
= p
->start_row
; i
<= p
->end_row
; i
++)
1610 for (j
= p
->start_col
; j
<= p
->end_col
; j
++)
1611 assert(entry
[i
][j
] == p
);
1618 location_force_filename
= 1;
1621 determine_row_type();
1623 if (!(flags
& CENTER
))
1624 prints(".if \\n[" SAVED_CENTER_REG
"] \\{");
1625 prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2)\n"
1626 ".nr " SAVED_INDENT_REG
" \\n[.i]\n");
1627 if (!(flags
& CENTER
))
1630 define_bottom_macro();
1632 for (int i
= 0; i
< nrows
; i
++)
1637 void table::determine_row_type()
1639 row_is_all_lines
= new char[nrows
];
1640 for (int i
= 0; i
< nrows
; i
++) {
1643 int had_non_line
= 0;
1644 for (int c
= 0; c
< ncolumns
; c
++) {
1645 table_entry
*e
= entry
[i
][c
];
1647 if (e
->start_row
== e
->end_row
) {
1648 int t
= e
->line_type();
1672 row_is_all_lines
[i
] = 0;
1673 else if (had_double
)
1674 row_is_all_lines
[i
] = 2;
1675 else if (had_single
)
1676 row_is_all_lines
[i
] = 1;
1678 row_is_all_lines
[i
] = 0;
1683 void table::init_output()
1685 prints(".nr " COMPATIBLE_REG
" \\n(.C\n"
1688 printfs(".nr " LINESIZE_REG
" %1\n", as_string(linesize
));
1690 prints(".nr " LINESIZE_REG
" \\n[.s]\n");
1691 if (!(flags
& CENTER
))
1692 prints(".nr " SAVED_CENTER_REG
" \\n[.ce]\n");
1693 prints(".de " RESET_MACRO_NAME
"\n"
1705 ".nr " SAVED_INDENT_REG
" \\n[.i]\n"
1706 ".nr " SAVED_FONT_REG
" \\n[.f]\n"
1707 ".nr " SAVED_SIZE_REG
" \\n[.s]\n"
1708 ".nr " SAVED_FILL_REG
" \\n[.u]\n"
1710 ".nr " CURRENT_ROW_REG
" 0-1\n"
1711 ".nr " LAST_PASSED_ROW_REG
" 0-1\n"
1712 ".nr " SECTION_DIVERSION_FLAG_REG
" 0\n"
1713 ".ds " TRANSPARENT_STRING_NAME
"\n"
1714 ".ds " QUOTE_STRING_NAME
"\n"
1715 ".nr " NEED_BOTTOM_RULE_REG
" 1\n"
1716 ".nr " SUPPRESS_BOTTOM_REG
" 0\n"
1718 ".de " KEEP_MACRO_NAME
"\n"
1719 ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME
" \\\\\n"
1720 ".ds " TRANSPARENT_STRING_NAME
" \\!\n"
1721 ".di " SECTION_DIVERSION_NAME
"\n"
1722 ".nr " SECTION_DIVERSION_FLAG_REG
" 1\n"
1726 ".de " RELEASE_MACRO_NAME
"\n"
1727 ".if \\n[" SECTION_DIVERSION_FLAG_REG
"] \\{"
1729 ".in \\n[" SAVED_INDENT_REG
"]u\n"
1730 ".nr " SAVED_DN_REG
" \\n[dn]\n"
1731 ".ds " QUOTE_STRING_NAME
"\n"
1732 ".ds " TRANSPARENT_STRING_NAME
"\n"
1733 ".nr " SECTION_DIVERSION_FLAG_REG
" 0\n"
1734 ".if \\n[.t]<=\\n[dn] \\{"
1737 ".nr " SUPPRESS_BOTTOM_REG
" 1\n"
1739 ".nr " SUPPRESS_BOTTOM_REG
" 0\n"
1742 ".if \\n[.t]<=\\n[" SAVED_DN_REG
"] "
1743 /* Since we turn off traps, it won't get into an infinite loop
1744 when we try and print it; it will just go off the bottom of the
1746 ".tm warning: page \\n%: table text block will not fit on one page\n"
1749 "." SECTION_DIVERSION_NAME
"\n"
1751 ".rm " SECTION_DIVERSION_NAME
"\n"
1754 ".nr " TABLE_DIVERSION_FLAG_REG
" 0\n"
1755 ".de " TABLE_KEEP_MACRO_NAME
"\n"
1756 ".if '\\n[.z]'' \\{"
1757 ".di " TABLE_DIVERSION_NAME
"\n"
1758 ".nr " TABLE_DIVERSION_FLAG_REG
" 1\n"
1761 ".de " TABLE_RELEASE_MACRO_NAME
"\n"
1762 ".if \\n[" TABLE_DIVERSION_FLAG_REG
"] \\{.br\n"
1764 ".nr " SAVED_DN_REG
" \\n[dn]\n"
1765 ".ne \\n[dn]u+\\n[.V]u\n"
1766 ".ie \\n[.t]<=\\n[" SAVED_DN_REG
"] "
1767 ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH\n"
1772 "." TABLE_DIVERSION_NAME
"\n"
1774 ".rm " TABLE_DIVERSION_NAME
"\n"
1777 ".de " REPEATED_MARK_MACRO
"\n"
1779 ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO
" \"\\$1\"\n"
1781 ".de " REPEATED_VPT_MACRO
"\n"
1783 ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO
" \"\\$1\"\n"
1790 string
block_width_reg(int r
, int c
)
1792 static char name
[sizeof(BLOCK_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1793 sprintf(name
, BLOCK_WIDTH_PREFIX
"%d,%d", r
, c
);
1794 return string(name
);
1797 string
block_diversion_name(int r
, int c
)
1799 static char name
[sizeof(BLOCK_DIVERSION_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1800 sprintf(name
, BLOCK_DIVERSION_PREFIX
"%d,%d", r
, c
);
1801 return string(name
);
1804 string
text_string_name(int r
, int c
)
1806 static char name
[sizeof(TEXT_STRING_PREFIX
) + INT_DIGITS
+ 1 + INT_DIGITS
];
1807 sprintf(name
, TEXT_STRING_PREFIX
"%d,%d", r
, c
);
1808 return string(name
);
1811 string
right_text_string_name(int r
, int c
)
1813 static char name
[sizeof(RIGHT_TEXT_STRING_PREFIX
)+INT_DIGITS
+ 1+INT_DIGITS
];
1814 sprintf(name
, RIGHT_TEXT_STRING_PREFIX
"%d,%d", r
, c
);
1815 return string(name
);
1818 string
block_height_reg(int r
, int c
)
1820 static char name
[sizeof(BLOCK_HEIGHT_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1821 sprintf(name
, BLOCK_HEIGHT_PREFIX
"%d,%d", r
, c
);
1822 return string(name
);
1825 string
span_width_reg(int start_col
, int end_col
)
1827 static char name
[sizeof(SPAN_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1828 sprintf(name
, SPAN_WIDTH_PREFIX
"%d", start_col
);
1829 if (end_col
!= start_col
)
1830 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1831 return string(name
);
1834 string
span_left_numeric_width_reg(int start_col
, int end_col
)
1836 static char name
[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1837 sprintf(name
, SPAN_LEFT_NUMERIC_WIDTH_PREFIX
"%d", start_col
);
1838 if (end_col
!= start_col
)
1839 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1840 return string(name
);
1843 string
span_right_numeric_width_reg(int start_col
, int end_col
)
1845 static char name
[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1846 sprintf(name
, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX
"%d", start_col
);
1847 if (end_col
!= start_col
)
1848 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1849 return string(name
);
1852 string
span_alphabetic_width_reg(int start_col
, int end_col
)
1854 static char name
[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX
)+INT_DIGITS
+1+INT_DIGITS
];
1855 sprintf(name
, SPAN_ALPHABETIC_WIDTH_PREFIX
"%d", start_col
);
1856 if (end_col
!= start_col
)
1857 sprintf(strchr(name
, '\0'), ",%d", end_col
);
1858 return string(name
);
1862 string
column_separation_reg(int col
)
1864 static char name
[sizeof(COLUMN_SEPARATION_PREFIX
)+INT_DIGITS
];
1865 sprintf(name
, COLUMN_SEPARATION_PREFIX
"%d", col
);
1866 return string(name
);
1869 string
row_start_reg(int row
)
1871 static char name
[sizeof(ROW_START_PREFIX
)+INT_DIGITS
];
1872 sprintf(name
, ROW_START_PREFIX
"%d", row
);
1873 return string(name
);
1876 string
column_start_reg(int col
)
1878 static char name
[sizeof(COLUMN_START_PREFIX
)+INT_DIGITS
];
1879 sprintf(name
, COLUMN_START_PREFIX
"%d", col
);
1880 return string(name
);
1883 string
column_end_reg(int col
)
1885 static char name
[sizeof(COLUMN_END_PREFIX
)+INT_DIGITS
];
1886 sprintf(name
, COLUMN_END_PREFIX
"%d", col
);
1887 return string(name
);
1890 string
column_divide_reg(int col
)
1892 static char name
[sizeof(COLUMN_DIVIDE_PREFIX
)+INT_DIGITS
];
1893 sprintf(name
, COLUMN_DIVIDE_PREFIX
"%d", col
);
1894 return string(name
);
1897 string
row_top_reg(int row
)
1899 static char name
[sizeof(ROW_TOP_PREFIX
)+INT_DIGITS
];
1900 sprintf(name
, ROW_TOP_PREFIX
"%d", row
);
1901 return string(name
);
1904 void init_span_reg(int start_col
, int end_col
)
1906 printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n",
1907 span_width_reg(start_col
, end_col
),
1908 span_alphabetic_width_reg(start_col
, end_col
),
1909 span_left_numeric_width_reg(start_col
, end_col
),
1910 span_right_numeric_width_reg(start_col
, end_col
));
1913 void compute_span_width(int start_col
, int end_col
)
1915 printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n"
1916 ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n",
1917 span_width_reg(start_col
, end_col
),
1918 span_left_numeric_width_reg(start_col
, end_col
),
1919 span_right_numeric_width_reg(start_col
, end_col
),
1920 span_alphabetic_width_reg(start_col
, end_col
));
1924 // Increase the widths of columns so that the width of any spanning entry
1925 // is no greater than the sum of the widths of the columns that it spans.
1926 // Ensure that the widths of columns remain equal.
1928 void table::divide_span(int start_col
, int end_col
)
1930 assert(end_col
> start_col
);
1931 printfs(".nr " NEEDED_REG
" \\n[%1]-(\\n[%2]",
1932 span_width_reg(start_col
, end_col
),
1933 span_width_reg(start_col
, start_col
));
1934 for (int i
= start_col
+ 1; i
<= end_col
; i
++) {
1935 // The column separation may shrink with the expand option.
1936 if (!(flags
& EXPAND
))
1937 printfs("+%1n", as_string(column_separation
[i
- 1]));
1938 printfs("+\\n[%1]", span_width_reg(i
, i
));
1941 printfs(".nr " NEEDED_REG
" \\n[" NEEDED_REG
"]/%1\n",
1942 as_string(end_col
- start_col
+ 1));
1943 prints(".if \\n[" NEEDED_REG
"] \\{");
1944 for (i
= start_col
; i
<= end_col
; i
++)
1945 printfs(".nr %1 +\\n[" NEEDED_REG
"]\n",
1946 span_width_reg(i
, i
));
1948 for (i
= start_col
; i
<= end_col
&& !equal_flag
; i
++)
1952 for (i
= 0; i
< ncolumns
; i
++)
1953 if (i
< start_col
|| i
> end_col
)
1954 printfs(".nr %1 +\\n[" NEEDED_REG
"]\n",
1955 span_width_reg(i
, i
));
1961 void table::sum_columns(int start_col
, int end_col
)
1963 assert(end_col
> start_col
);
1964 printfs(".nr %1 \\n[%2]",
1965 span_width_reg(start_col
, end_col
),
1966 span_width_reg(start_col
, start_col
));
1967 for (int i
= start_col
+ 1; i
<= end_col
; i
++)
1968 printfs("+(%1*\\n[" SEPARATION_FACTOR_REG
"])+\\n[%2]",
1969 as_string(column_separation
[i
- 1]),
1970 span_width_reg(i
, i
));
1974 horizontal_span::horizontal_span(int sc
, int ec
, horizontal_span
*p
)
1975 : start_col(sc
), end_col(ec
), next(p
)
1979 void table::build_span_list()
1982 table_entry
*p
= entry_list
;
1984 if (p
->end_col
!= p
->start_col
) {
1985 for (horizontal_span
*q
= span_list
; q
; q
= q
->next
)
1986 if (q
->start_col
== p
->start_col
1987 && q
->end_col
== p
->end_col
)
1990 span_list
= new horizontal_span(p
->start_col
, p
->end_col
, span_list
);
1994 // Now sort span_list primarily by order of end_row, and secondarily
1995 // by reverse order of start_row. This ensures that if we divide
1996 // spans using the order in span_list, we will get reasonable results.
1997 horizontal_span
*unsorted
= span_list
;
2000 for (horizontal_span
**pp
= &span_list
; *pp
; pp
= &(*pp
)->next
)
2001 if (unsorted
->end_col
< (*pp
)->end_col
2002 || (unsorted
->end_col
== (*pp
)->end_col
2003 && (unsorted
->start_col
> (*pp
)->start_col
)))
2005 horizontal_span
*tem
= unsorted
->next
;
2006 unsorted
->next
= *pp
;
2013 void table::compute_separation_factor()
2015 if (flags
& (ALLBOX
|BOX
|DOUBLEBOX
))
2016 left_separation
= right_separation
= 1;
2018 for (int i
= 0; i
< nrows
; i
++) {
2019 if (vline
[i
][0] > 0)
2020 left_separation
= 1;
2021 if (vline
[i
][ncolumns
] > 0)
2022 right_separation
= 1;
2025 if (flags
& EXPAND
) {
2026 int total_sep
= left_separation
+ right_separation
;
2027 for (int i
= 0; i
< ncolumns
- 1; i
++)
2028 total_sep
+= column_separation
[i
];
2029 if (total_sep
!= 0) {
2030 // Don't let the separation factor be negative.
2031 prints(".nr " SEPARATION_FACTOR_REG
" \\n[.l]-\\n[.i]");
2032 for (i
= 0; i
< ncolumns
; i
++)
2033 printfs("-\\n[%1]", span_width_reg(i
, i
));
2034 printfs("/%1>?0\n", as_string(total_sep
));
2039 void table::compute_column_positions()
2041 printfs(".nr %1 0\n", column_divide_reg(0));
2042 printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG
"]\n",
2043 column_start_reg(0),
2044 as_string(left_separation
));
2045 for (int i
= 1;; i
++) {
2046 printfs(".nr %1 \\n[%2]+\\n[%3]\n",
2047 column_end_reg(i
-1),
2048 column_start_reg(i
-1),
2049 span_width_reg(i
-1, i
-1));
2052 printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG
"])\n",
2053 column_start_reg(i
),
2054 column_end_reg(i
-1),
2055 as_string(column_separation
[i
-1]));
2056 printfs(".nr %1 \\n[%2]+\\n[%3]/2\n",
2057 column_divide_reg(i
),
2058 column_end_reg(i
-1),
2059 column_start_reg(i
));
2061 printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG
"])\n",
2062 column_divide_reg(ncolumns
),
2063 column_end_reg(i
-1),
2064 as_string(right_separation
));
2065 printfs(".nr TW \\n[%1]\n",
2066 column_divide_reg(ncolumns
));
2067 if (flags
& DOUBLEBOX
) {
2068 printfs(".nr %1 +" DOUBLE_LINE_SEP
"\n", column_divide_reg(0));
2069 printfs(".nr %1 -" DOUBLE_LINE_SEP
"\n", column_divide_reg(ncolumns
));
2073 void table::make_columns_equal()
2075 int first
= -1; // index of first equal column
2076 for (int i
= 0; i
< ncolumns
; i
++)
2079 printfs(".nr %1 \\n[%1]", span_width_reg(i
, i
));
2083 printfs(">?\\n[%1]", span_width_reg(i
, i
));
2087 for (i
= first
+ 1; i
< ncolumns
; i
++)
2089 printfs(".nr %1 \\n[%2]\n",
2090 span_width_reg(i
, i
),
2091 span_width_reg(first
, first
));
2095 void table::compute_widths()
2100 prints(".nr " SEPARATION_FACTOR_REG
" 1n\n");
2101 for (i
= 0; i
< ncolumns
; i
++) {
2102 init_span_reg(i
, i
);
2103 if (!minimum_width
[i
].empty())
2104 printfs(".nr %1 %2\n", span_width_reg(i
, i
), minimum_width
[i
]);
2106 for (p
= span_list
; p
; p
= p
->next
)
2107 init_span_reg(p
->start_col
, p
->end_col
);
2109 for (q
= entry_list
; q
; q
= q
->next
)
2110 if (!q
->mod
->zero_width
)
2112 for (i
= 0; i
< ncolumns
; i
++)
2113 compute_span_width(i
, i
);
2114 for (p
= span_list
; p
; p
= p
->next
)
2115 compute_span_width(p
->start_col
, p
->end_col
);
2116 make_columns_equal();
2117 // Note that divide_span keeps equal width columns equal.
2118 for (p
= span_list
; p
; p
= p
->next
)
2119 divide_span(p
->start_col
, p
->end_col
);
2120 for (p
= span_list
; p
; p
= p
->next
)
2121 sum_columns(p
->start_col
, p
->end_col
);
2122 int had_spanning_block
= 0;
2123 int had_equal_block
= 0;
2124 for (q
= entry_list
; q
; q
= q
->next
)
2125 if (q
->divert(ncolumns
, minimum_width
)) {
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 \\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
">?\\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
)
2158 for (int end_col
= start_col
;
2160 && (entry
[r
][end_col
] == 0
2161 || entry
[r
][end_col
]->start_row
== r
);
2164 if (end_col
<= start_col
)
2166 printfs("\\h'|\\n[%1]u",
2167 column_divide_reg(start_col
));
2168 if ((r
> 0 && vline
[r
-1][start_col
] == 2)
2169 || (r
< nrows
&& vline
[r
][start_col
] == 2))
2170 prints("-" HALF_DOUBLE_LINE_SEP
);
2172 printfs("\\D'l |\\n[%1]u",
2173 column_divide_reg(end_col
));
2174 if ((r
> 0 && vline
[r
-1][end_col
] == 2)
2175 || (r
< nrows
&& vline
[r
][end_col
] == 2))
2176 prints("+" HALF_DOUBLE_LINE_SEP
);
2178 start_col
= end_col
;
2186 void table::print_double_hline(int r
)
2188 prints(".vs \\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
"+" DOUBLE_LINE_SEP
2191 "\\v'" BODY_DEPTH
"'"
2192 "\\s[\\n[" LINESIZE_REG
"]]");
2194 prints("\\v'-" DOUBLE_LINE_SEP
"'"
2195 "\\D'l |\\n[TW]u 0'"
2196 "\\v'" DOUBLE_LINE_SEP
"'"
2198 "\\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
)
2207 for (int end_col
= start_col
;
2209 && (entry
[r
][end_col
] == 0
2210 || entry
[r
][end_col
]->start_row
== r
);
2213 if (end_col
<= start_col
)
2215 const char *left_adjust
= 0;
2216 if ((r
> 0 && vline
[r
-1][start_col
] == 2)
2217 || (r
< nrows
&& vline
[r
][start_col
] == 2))
2218 left_adjust
= "-" HALF_DOUBLE_LINE_SEP
;
2219 const char *right_adjust
= 0;
2220 if ((r
> 0 && vline
[r
-1][end_col
] == 2)
2221 || (r
< nrows
&& vline
[r
][end_col
] == 2))
2222 right_adjust
= "+" HALF_DOUBLE_LINE_SEP
;
2223 printfs("\\v'-" DOUBLE_LINE_SEP
"'"
2225 column_divide_reg(start_col
));
2227 prints(left_adjust
);
2229 printfs("\\D'l |\\n[%1]u",
2230 column_divide_reg(end_col
));
2232 prints(right_adjust
);
2234 printfs("\\v'" DOUBLE_LINE_SEP
"'"
2236 column_divide_reg(start_col
));
2238 prints(left_adjust
);
2240 printfs("\\D'l |\\n[%1]u",
2241 column_divide_reg(end_col
));
2243 prints(right_adjust
);
2245 start_col
= end_col
;
2253 void table::compute_vrule_top_adjust(int start_row
, int col
, string
&result
)
2255 if (row_is_all_lines
[start_row
] && start_row
< nrows
- 1) {
2256 if (row_is_all_lines
[start_row
] == 2)
2257 result
= "\\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
"+" DOUBLE_LINE_SEP
;
2259 result
= "\\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
;
2266 for (stuff
*p
= stuff_list
; p
&& p
->row
<= start_row
; p
= p
->next
)
2267 if (p
->row
== start_row
2268 && (p
->is_single_line() || p
->is_double_line()))
2273 table_entry
*e
= entry
[start_row
-1][col
-1];
2274 if (e
&& e
->start_row
== e
->end_row
) {
2275 if (e
->to_double_line_entry() != 0)
2277 else if (e
->to_single_line_entry() != 0)
2282 if (col
< ncolumns
) {
2283 table_entry
*e
= entry
[start_row
-1][col
];
2284 if (e
&& e
->start_row
== e
->end_row
) {
2285 if (e
->to_double_line_entry() != 0)
2287 else if (e
->to_single_line_entry() != 0)
2291 if (row_is_all_lines
[start_row
-1] == 0) {
2292 if (left
> 0 || right
> 0) {
2293 result
+= "-" BODY_DEPTH
"-" BAR_HEIGHT
;
2294 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2295 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2296 else if (left
== 2 && right
== 2)
2297 result
+= "+" HALF_DOUBLE_LINE_SEP
;
2300 else if (row_is_all_lines
[start_row
-1] == 2) {
2301 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2302 result
+= "-" DOUBLE_LINE_SEP
;
2303 else if (left
== 1 || right
== 1)
2304 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2308 void table::compute_vrule_bot_adjust(int end_row
, int col
, string
&result
)
2310 if (row_is_all_lines
[end_row
] && end_row
> 0) {
2315 for (stuff
*p
= stuff_list
; p
&& p
->row
< end_row
+ 1; p
= p
->next
)
2317 if (p
&& p
->row
== end_row
+ 1 && p
->is_double_line()) {
2318 result
= "-" DOUBLE_LINE_SEP
;
2321 if ((p
!= 0 && p
->row
== end_row
+ 1)
2322 || end_row
== nrows
- 1) {
2326 if (row_is_all_lines
[end_row
+1] == 1)
2327 result
= "\\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
;
2328 else if (row_is_all_lines
[end_row
+1] == 2)
2329 result
= "\\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
"+" DOUBLE_LINE_SEP
;
2335 table_entry
*e
= entry
[end_row
+1][col
-1];
2336 if (e
&& e
->start_row
== e
->end_row
) {
2337 if (e
->to_double_line_entry() != 0)
2339 else if (e
->to_single_line_entry() != 0)
2344 if (col
< ncolumns
) {
2345 table_entry
*e
= entry
[end_row
+1][col
];
2346 if (e
&& e
->start_row
== e
->end_row
) {
2347 if (e
->to_double_line_entry() != 0)
2349 else if (e
->to_single_line_entry() != 0)
2353 if (row_is_all_lines
[end_row
+1] == 0) {
2354 if (left
> 0 || right
> 0) {
2355 result
= "1v-" BODY_DEPTH
"-" BAR_HEIGHT
;
2356 if ((left
== 2 && right
!= 2) || (right
== 2 && left
!= 2))
2357 result
+= "+" HALF_DOUBLE_LINE_SEP
;
2358 else if (left
== 2 && right
== 2)
2359 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2362 else if (row_is_all_lines
[end_row
+1] == 2) {
2363 if (left
== 2 && right
== 2)
2364 result
+= "-" DOUBLE_LINE_SEP
;
2365 else if (left
!= 2 && right
!= 2 && (left
== 1 || right
== 1))
2366 result
+= "-" HALF_DOUBLE_LINE_SEP
;
2370 void table::add_vertical_rule(int start_row
, int end_row
, int col
, int is_double
)
2372 vrule_list
= new vertical_rule(start_row
, end_row
, col
, is_double
,
2374 compute_vrule_top_adjust(start_row
, col
, vrule_list
->top_adjust
);
2375 compute_vrule_bot_adjust(end_row
, col
, vrule_list
->bot_adjust
);
2378 void table::build_vrule_list()
2381 if (flags
& ALLBOX
) {
2382 for (col
= 1; col
< ncolumns
; col
++) {
2385 while (start_row
< nrows
&& vline_spanned(start_row
, col
))
2387 if (start_row
>= nrows
)
2389 int end_row
= start_row
;
2390 while (end_row
< nrows
&& !vline_spanned(end_row
, col
))
2393 add_vertical_rule(start_row
, end_row
, col
, 0);
2394 start_row
= end_row
+ 1;
2398 if (flags
& (BOX
|ALLBOX
|DOUBLEBOX
)) {
2399 add_vertical_rule(0, nrows
- 1, 0, 0);
2400 add_vertical_rule(0, nrows
- 1, ncolumns
, 0);
2402 for (int end_row
= 0; end_row
< nrows
; end_row
++)
2403 for (col
= 0; col
< ncolumns
+1; col
++)
2404 if (vline
[end_row
][col
] > 0
2405 && !vline_spanned(end_row
, col
)
2406 && (end_row
== nrows
- 1
2407 || vline
[end_row
+1][col
] != vline
[end_row
][col
]
2408 || vline_spanned(end_row
+1, col
))) {
2409 for (int start_row
= end_row
- 1;
2411 && vline
[start_row
][col
] == vline
[end_row
][col
]
2412 && !vline_spanned(start_row
, col
);
2416 add_vertical_rule(start_row
, end_row
, col
, vline
[end_row
][col
] > 1);
2418 for (vertical_rule
*p
= vrule_list
; p
; p
= p
->next
)
2420 for (int r
= p
->start_row
; r
<= p
->end_row
; r
++) {
2421 if (p
->col
> 0 && entry
[r
][p
->col
-1] != 0
2422 && entry
[r
][p
->col
-1]->end_col
== p
->col
-1) {
2423 int is_corner
= r
== p
->start_row
|| r
== p
->end_row
;
2424 entry
[r
][p
->col
-1]->note_double_vrule_on_right(is_corner
);
2426 if (p
->col
< ncolumns
&& entry
[r
][p
->col
] != 0
2427 && entry
[r
][p
->col
]->start_col
== p
->col
) {
2428 int is_corner
= r
== p
->start_row
|| r
== p
->end_row
;
2429 entry
[r
][p
->col
]->note_double_vrule_on_left(is_corner
);
2434 void table::define_bottom_macro()
2438 ".if !\\n[" SUPPRESS_BOTTOM_REG
"] \\{"
2439 "." REPEATED_VPT_MACRO
" 0\n"
2440 ".mk " SAVED_VERTICAL_POS_REG
"\n");
2441 if (flags
& (BOX
|ALLBOX
|DOUBLEBOX
)) {
2442 prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG
"] \\{");
2443 print_single_hline(0);
2447 for (vertical_rule
*p
= vrule_list
; p
; p
= p
->next
)
2448 p
->contribute_to_bottom_macro(this);
2449 if (flags
& DOUBLEBOX
)
2450 prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP
">?\\n[.V]u\n"
2451 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]"
2452 "\\D'l \\n[TW]u 0'\\s0\n"
2455 ".if \\n[" LAST_PASSED_ROW_REG
"]>=0 "
2456 ".nr " TOP_REG
" \\n[#T]-" DOUBLE_LINE_SEP
"\n"
2458 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]"
2459 "\\D'l 0 |\\n[" TOP_REG
"]u-1v'\\s0\n"
2461 "\\v'" BODY_DEPTH
"'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG
"]]"
2462 "\\D'l 0 |\\n[" TOP_REG
"]u-1v'\\s0\n");
2464 prints(".nr " LAST_PASSED_ROW_REG
" \\n[" CURRENT_ROW_REG
"]\n"
2465 ".sp |\\n[" SAVED_VERTICAL_POS_REG
"]u\n"
2466 "." REPEATED_VPT_MACRO
" 1\n"
2473 // is the vertical line before column c in row r horizontally spanned?
2475 int table::vline_spanned(int r
, int c
)
2477 assert(r
>= 0 && r
< nrows
&& c
>= 0 && c
< ncolumns
+ 1);
2478 return (c
!= 0 && c
!= ncolumns
&& entry
[r
][c
] != 0
2479 && entry
[r
][c
]->start_col
!= c
2480 // horizontally spanning lines don't count
2481 && entry
[r
][c
]->to_double_line_entry() == 0
2482 && entry
[r
][c
]->to_single_line_entry() == 0);
2485 int table::row_begins_section(int r
)
2487 assert(r
>= 0 && r
< nrows
);
2488 for (int i
= 0; i
< ncolumns
; i
++)
2489 if (entry
[r
][i
] && entry
[r
][i
]->start_row
!= r
)
2494 int table::row_ends_section(int r
)
2496 assert(r
>= 0 && r
< nrows
);
2497 for (int i
= 0; i
< ncolumns
; i
++)
2498 if (entry
[r
][i
] && entry
[r
][i
]->end_row
!= r
)
2503 void table::do_row(int r
)
2505 if (row_begins_section(r
))
2506 prints("." KEEP_MACRO_NAME
"\n");
2508 for (stuff
*p
= stuff_list
; p
&& p
->row
< r
; p
= p
->next
)
2510 for (stuff
*p1
= p
; p1
&& p1
->row
== r
; p1
= p1
->next
)
2511 if (!p1
->printed
&& (p1
->is_single_line() || p1
->is_double_line())) {
2515 if (!had_line
&& !row_is_all_lines
[r
])
2516 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2518 printfs("\\*[" TRANSPARENT_STRING_NAME
"].nr " CURRENT_ROW_REG
" %1\n",
2520 for (; p
&& p
->row
== r
; p
= p
->next
)
2523 if (!had_line
&& (p
->is_single_line() || p
->is_double_line())) {
2524 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2528 if (!had_line
&& row_is_all_lines
[r
])
2529 printfs("." REPEATED_MARK_MACRO
" %1\n", row_top_reg(r
));
2530 // we might have had a .TH, for example, since we last tried
2531 if (row_begins_section(r
))
2532 prints("." KEEP_MACRO_NAME
"\n");
2533 printfs(".mk %1\n", row_start_reg(r
));
2534 prints(".mk " BOTTOM_REG
"\n"
2535 "." REPEATED_VPT_MACRO
" 0\n");
2537 int row_is_blank
= 1;
2538 int first_start_row
= r
;
2539 for (c
= 0; c
< ncolumns
; c
++) {
2540 table_entry
*e
= entry
[r
][c
];
2542 if (e
->end_row
== r
) {
2544 if (e
->start_row
< first_start_row
)
2545 first_start_row
= e
->start_row
;
2552 prints(".nr " BOTTOM_REG
" +1v\n");
2553 if (row_is_all_lines
[r
]) {
2554 prints(".vs \\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
);
2555 if (row_is_all_lines
[r
] == 2)
2556 prints("+" DOUBLE_LINE_SEP
);
2557 prints(">?\\n[.V]u\n.ls 1\n");
2559 prints("\\v'" BODY_DEPTH
);
2560 if (row_is_all_lines
[r
] == 2)
2561 prints("-" HALF_DOUBLE_LINE_SEP
);
2563 for (c
= 0; c
< ncolumns
; c
++) {
2564 table_entry
*e
= entry
[r
][c
];
2566 if (e
->end_row
== e
->start_row
)
2567 e
->to_simple_entry()->simple_print(1);
2574 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2575 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2577 for (int i
= row_is_all_lines
[r
] ? r
- 1 : r
;
2578 i
>= first_start_row
;
2580 simple_entry
*first
= 0;
2581 for (c
= 0; c
< ncolumns
; c
++) {
2582 table_entry
*e
= entry
[r
][c
];
2584 if (e
->end_row
== r
&& e
->start_row
== i
) {
2585 simple_entry
*simple
= e
->to_simple_entry();
2599 first
->position_vertically();
2600 first
->set_location();
2602 first
->simple_print(0);
2603 for (c
= first
->end_col
+ 1; c
< ncolumns
; c
++) {
2604 table_entry
*e
= entry
[r
][c
];
2606 if (e
->end_row
== r
&& e
->start_row
== i
) {
2607 simple_entry
*simple
= e
->to_simple_entry();
2609 simple
->simple_print(0);
2615 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2616 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2619 for (c
= 0; c
< ncolumns
; c
++) {
2620 table_entry
*e
= entry
[r
][c
];
2622 if (e
->end_row
== r
&& e
->to_simple_entry() == 0) {
2623 e
->position_vertically();
2625 prints(".nr " BOTTOM_REG
" \\n[" BOTTOM_REG
"]>?\\n[.d]\n");
2626 printfs(".sp |\\n[%1]u\n", row_start_reg(r
));
2631 prints("." REPEATED_VPT_MACRO
" 1\n"
2632 ".sp |\\n[" BOTTOM_REG
"]u\n"
2633 "\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
" 1\n");
2634 if (r
!= nrows
- 1 && (flags
& ALLBOX
)) {
2635 print_single_hline(r
+ 1);
2636 prints("\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
" 0\n");
2638 if (r
!= nrows
- 1) {
2639 if (p
&& p
->row
== r
+ 1
2640 && (p
->is_single_line() || p
->is_double_line())) {
2642 prints("\\*[" TRANSPARENT_STRING_NAME
"].nr " NEED_BOTTOM_RULE_REG
2645 int printed_one
= 0;
2646 for (vertical_rule
*p
= vrule_list
; p
; p
= p
->next
)
2647 if (p
->end_row
== r
) {
2649 prints("." REPEATED_VPT_MACRO
" 0\n");
2655 prints("." REPEATED_VPT_MACRO
" 1\n");
2656 if (row_ends_section(r
))
2657 prints("." RELEASE_MACRO_NAME
"\n");
2661 void table::do_top()
2663 prints(".fc \002\003\n");
2664 if (flags
& (BOX
|DOUBLEBOX
|ALLBOX
))
2665 prints("." TABLE_KEEP_MACRO_NAME
"\n");
2666 if (flags
& DOUBLEBOX
) {
2668 ".vs \\n[.v]u-" BODY_HEIGHT
"-" BODY_DEPTH
">?\\n[.V]u\n"
2669 "\\v'" BODY_DEPTH
"'\\s[\\n[" LINESIZE_REG
"]]\\D'l \\n[TW]u 0'\n"
2671 "." REPEATED_MARK_MACRO
" " TOP_REG
"\n"
2672 ".vs " DOUBLE_LINE_SEP
">?\\n[.V]u\n");
2673 printfs("\\v'" BODY_DEPTH
"'"
2674 "\\s[\\n[" LINESIZE_REG
"]]"
2676 "\\D'l |\\n[%2]u 0'"
2679 column_divide_reg(0),
2680 column_divide_reg(ncolumns
));
2684 else if (flags
& (ALLBOX
|BOX
)) {
2685 print_single_hline(0);
2687 //printfs(".mk %1\n", row_top_reg(0));
2690 void table::do_bottom()
2692 // print stuff after last row
2693 for (stuff
*p
= stuff_list
; p
; p
= p
->next
)
2694 if (p
->row
> nrows
- 1)
2696 prints("." RELEASE_MACRO_NAME
"\n");
2697 printfs(".mk %1\n", row_top_reg(nrows
));
2698 prints(".nr " NEED_BOTTOM_RULE_REG
" 1\n"
2701 if (flags
& (BOX
|DOUBLEBOX
|ALLBOX
))
2702 prints("." TABLE_RELEASE_MACRO_NAME
"\n");
2703 if (flags
& DOUBLEBOX
)
2704 prints(".sp " DOUBLE_LINE_SEP
"\n");
2705 prints("." RESET_MACRO_NAME
"\n"
2707 ".cp \\n(" COMPATIBLE_REG
"\n");
2710 int table::get_nrows()
2715 const char *last_filename
= 0;
2717 void set_troff_location(const char *fn
, int ln
)
2719 if (!location_force_filename
&& last_filename
!= 0
2720 && strcmp(fn
, last_filename
) == 0)
2721 printfs(".lf %1\n", as_string(ln
));
2723 printfs(".lf %1 %2\n", as_string(ln
), fn
);
2725 location_force_filename
= 0;
2729 void printfs(const char *s
, const string
&arg1
, const string
&arg2
,
2730 const string
&arg3
, const string
&arg4
, const string
&arg5
)
2734 while ((c
= *s
++) != '\0') {