diff options
Diffstat (limited to 'gnu/groff/tbl/table.cc')
| -rw-r--r-- | gnu/groff/tbl/table.cc | 2764 |
1 files changed, 0 insertions, 2764 deletions
diff --git a/gnu/groff/tbl/table.cc b/gnu/groff/tbl/table.cc deleted file mode 100644 index 76c7cd74a9c6..000000000000 --- a/gnu/groff/tbl/table.cc +++ /dev/null @@ -1,2764 +0,0 @@ -// -*- C++ -*- -/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. - Written by James Clark (jjc@jclark.com) - -This file is part of groff. - -groff is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later -version. - -groff is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License along -with groff; see the file COPYING. If not, write to the Free Software -Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "table.h" - -#define BAR_HEIGHT ".25m" -#define DOUBLE_LINE_SEP "2p" -#define HALF_DOUBLE_LINE_SEP "1p" -#define LINE_SEP "2p" -#define BODY_DEPTH ".25m" - -const int DEFAULT_COLUMN_SEPARATION = 3; - -#define DELIMITER_CHAR "\\[tbl]" -#define PREFIX "3" -#define SEPARATION_FACTOR_REG PREFIX "sep" -#define BOTTOM_REG PREFIX "bot" -#define RESET_MACRO_NAME PREFIX "init" -#define LINESIZE_REG PREFIX "lps" -#define TOP_REG PREFIX "top" -#define CURRENT_ROW_REG PREFIX "crow" -#define LAST_PASSED_ROW_REG PREFIX "passed" -#define TRANSPARENT_STRING_NAME PREFIX "trans" -#define QUOTE_STRING_NAME PREFIX "quote" -#define SECTION_DIVERSION_NAME PREFIX "section" -#define SECTION_DIVERSION_FLAG_REG PREFIX "sflag" -#define SAVED_VERTICAL_POS_REG PREFIX "vert" -#define NEED_BOTTOM_RULE_REG PREFIX "brule" -#define KEEP_MACRO_NAME PREFIX "keep" -#define RELEASE_MACRO_NAME PREFIX "release" -#define SAVED_FONT_REG PREFIX "fnt" -#define SAVED_SIZE_REG PREFIX "sz" -#define SAVED_FILL_REG PREFIX "fll" -#define SAVED_INDENT_REG PREFIX "ind" -#define SAVED_CENTER_REG PREFIX "cent" -#define TABLE_DIVERSION_NAME PREFIX "table" -#define TABLE_DIVERSION_FLAG_REG PREFIX "tflag" -#define TABLE_KEEP_MACRO_NAME PREFIX "tkeep" -#define TABLE_RELEASE_MACRO_NAME PREFIX "trelease" -#define NEEDED_REG PREFIX "needed" -#define REPEATED_MARK_MACRO PREFIX "rmk" -#define REPEATED_VPT_MACRO PREFIX "rvpt" -#define SUPPRESS_BOTTOM_REG PREFIX "supbot" -#define SAVED_DN_REG PREFIX "dn" - -// this must be one character -#define COMPATIBLE_REG PREFIX "c" - -#define BLOCK_WIDTH_PREFIX PREFIX "tbw" -#define BLOCK_DIVERSION_PREFIX PREFIX "tbd" -#define BLOCK_HEIGHT_PREFIX PREFIX "tbh" -#define SPAN_WIDTH_PREFIX PREFIX "w" -#define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw" -#define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw" -#define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw" -#define COLUMN_SEPARATION_PREFIX PREFIX "cs" -#define ROW_START_PREFIX PREFIX "rs" -#define COLUMN_START_PREFIX PREFIX "cl" -#define COLUMN_END_PREFIX PREFIX "ce" -#define COLUMN_DIVIDE_PREFIX PREFIX "cd" -#define ROW_TOP_PREFIX PREFIX "rt" - -string block_width_reg(int r, int c); -string block_diversion_name(int r, int c); -string block_height_reg(int r, int c); -string span_width_reg(int start_col, int end_col); -string span_left_numeric_width_reg(int start_col, int end_col); -string span_right_numeric_width_reg(int start_col, int end_col); -string span_alphabetic_width_reg(int start_col, int end_col); -string column_separation_reg(int col); -string row_start_reg(int r); -string column_start_reg(int c); -string column_end_reg(int c); -string column_divide_reg(int c); -string row_top_reg(int r); - -void set_inline_modifier(const entry_modifier *); -void restore_inline_modifier(const entry_modifier *m); -void set_modifier(const entry_modifier *); -int find_decimal_point(const char *s, char decimal_point_char, - const char *delim); - -string an_empty_string; -int location_force_filename = 0; - -void printfs(const char *, - const string &arg1 = an_empty_string, - const string &arg2 = an_empty_string, - const string &arg3 = an_empty_string, - const string &arg4 = an_empty_string, - const string &arg5 = an_empty_string); - -void prints(const string &); - -inline void prints(char c) -{ - putchar(c); -} - -inline void prints(const char *s) -{ - fputs(s, stdout); -} - -void prints(const string &s) -{ - if (!s.empty()) - fwrite(s.contents(), 1, s.length(), stdout); -} - -struct horizontal_span { - horizontal_span *next; - short start_col; - short end_col; - horizontal_span(int, int, horizontal_span *); -}; - -struct single_line_entry; -struct double_line_entry; -struct simple_entry; - -class table_entry { -friend class table; - table_entry *next; - int input_lineno; - const char *input_filename; -protected: - short start_row; - short start_col; - short end_row; - short end_col; - const entry_modifier *mod; -public: - void set_location(); - table_entry(const entry_modifier *); - virtual ~table_entry(); - virtual int divert(int ncols, const string *mw, int *sep); - virtual void do_width(); - virtual void do_depth(); - virtual void print() = 0; - virtual void position_vertically() = 0; - virtual single_line_entry *to_single_line_entry(); - virtual double_line_entry *to_double_line_entry(); - virtual simple_entry *to_simple_entry(); - virtual int line_type(); - virtual void note_double_vrule_on_right(int); - virtual void note_double_vrule_on_left(int); -}; - -class simple_entry : public table_entry { -public: - simple_entry(const entry_modifier *); - void print(); - void position_vertically(); - simple_entry *to_simple_entry(); - virtual void add_tab(); - virtual void simple_print(int); -}; - -class empty_entry : public simple_entry { -public: - empty_entry(const entry_modifier *); - int line_type(); -}; - -class text_entry : public simple_entry { -protected: - char *contents; - void print_contents(); -public: - text_entry(char *, const entry_modifier *); - ~text_entry(); -}; - -void text_entry::print_contents() -{ - set_inline_modifier(mod); - prints(contents); - restore_inline_modifier(mod); -} - -class repeated_char_entry : public text_entry { -public: - repeated_char_entry(char *s, const entry_modifier *m); - void simple_print(int); -}; - -class simple_text_entry : public text_entry { -public: - simple_text_entry(char *s, const entry_modifier *m); - void do_width(); -}; - -class left_text_entry : public simple_text_entry { -public: - left_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class right_text_entry : public simple_text_entry { -public: - right_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class center_text_entry : public simple_text_entry { -public: - center_text_entry(char *s, const entry_modifier *m); - void simple_print(int); - void add_tab(); -}; - -class numeric_text_entry : public text_entry { - int dot_pos; -public: - numeric_text_entry(char *s, const entry_modifier *m, int pos); - void do_width(); - void simple_print(int); -}; - -class alphabetic_text_entry : public text_entry { -public: - alphabetic_text_entry(char *s, const entry_modifier *m); - void do_width(); - void simple_print(int); - void add_tab(); -}; - -class line_entry : public simple_entry { -protected: - char double_vrule_on_right; - char double_vrule_on_left; -public: - line_entry(const entry_modifier *); - void note_double_vrule_on_right(int); - void note_double_vrule_on_left(int); - void simple_print(int) = 0; -}; - -class single_line_entry : public line_entry { -public: - single_line_entry(const entry_modifier *m); - void simple_print(int); - single_line_entry *to_single_line_entry(); - int line_type(); -}; - -class double_line_entry : public line_entry { -public: - double_line_entry(const entry_modifier *m); - void simple_print(int); - double_line_entry *to_double_line_entry(); - int line_type(); -}; - -class short_line_entry : public simple_entry { -public: - short_line_entry(const entry_modifier *m); - void simple_print(int); - int line_type(); -}; - -class short_double_line_entry : public simple_entry { -public: - short_double_line_entry(const entry_modifier *m); - void simple_print(int); - int line_type(); -}; - -class block_entry : public table_entry { - char *contents; -protected: - void do_divert(int alphabetic, int ncols, const string *mw, int *sep); -public: - block_entry(char *s, const entry_modifier *m); - ~block_entry(); - int divert(int ncols, const string *mw, int *sep); - void do_width(); - void do_depth(); - void position_vertically(); - void print() = 0; -}; - -class left_block_entry : public block_entry { -public: - left_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class right_block_entry : public block_entry { -public: - right_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class center_block_entry : public block_entry { -public: - center_block_entry(char *s, const entry_modifier *m); - void print(); -}; - -class alphabetic_block_entry : public block_entry { -public: - alphabetic_block_entry(char *s, const entry_modifier *m); - void print(); - int divert(int ncols, const string *mw, int *sep); -}; - -table_entry::table_entry(const entry_modifier *m) -: next(0), start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m), - input_lineno(-1), input_filename(0) -{ -} - -table_entry::~table_entry() -{ -} - -int table_entry::divert(int, const string *, int *) -{ - return 0; -} - -void table_entry::do_width() -{ -} - -single_line_entry *table_entry::to_single_line_entry() -{ - return 0; -} - -double_line_entry *table_entry::to_double_line_entry() -{ - return 0; -} - -simple_entry *table_entry::to_simple_entry() -{ - return 0; -} - -void table_entry::do_depth() -{ -} - -void table_entry::set_location() -{ - set_troff_location(input_filename, input_lineno); -} - -int table_entry::line_type() -{ - return -1; -} - -void table_entry::note_double_vrule_on_right(int) -{ -} - -void table_entry::note_double_vrule_on_left(int) -{ -} - -simple_entry::simple_entry(const entry_modifier *m) : table_entry(m) -{ -} - -void simple_entry::add_tab() -{ - // do nothing -} - -void simple_entry::simple_print(int) -{ - // do nothing -} - -void simple_entry::position_vertically() -{ - if (start_row != end_row) - switch (mod->vertical_alignment) { - case entry_modifier::TOP: - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - break; - case entry_modifier::CENTER: - // Peform the motion in two stages so that the center is rounded - // vertically upwards even if net vertical motion is upwards. - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n", - row_start_reg(start_row)); - break; - case entry_modifier::BOTTOM: - printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n", - row_start_reg(start_row)); - break; - default: - assert(0); - } -} - -void simple_entry::print() -{ - prints(".ta"); - add_tab(); - prints('\n'); - set_location(); - prints("\\&"); - simple_print(0); - prints('\n'); -} - -simple_entry *simple_entry::to_simple_entry() -{ - return this; -} - -empty_entry::empty_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int empty_entry::line_type() -{ - return 0; -} - -text_entry::text_entry(char *s, const entry_modifier *m) -: contents(s), simple_entry(m) -{ -} - -text_entry::~text_entry() -{ - a_delete contents; -} - - -repeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void repeated_char_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - set_inline_modifier(mod); - printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&", - span_width_reg(start_col, end_col)); - prints(contents); - prints(DELIMITER_CHAR); - restore_inline_modifier(mod); -} - -simple_text_entry::simple_text_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void simple_text_entry::do_width() -{ - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_width_reg(start_col, end_col)); - print_contents(); - prints(DELIMITER_CHAR "\n"); -} - -left_text_entry::left_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void left_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - print_contents(); -} - -// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. - -void left_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -right_text_entry::right_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void right_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - prints("\002\003"); - print_contents(); - prints("\002"); -} - -void right_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -center_text_entry::center_text_entry(char *s, const entry_modifier *m) -: simple_text_entry(s, m) -{ -} - -void center_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - prints("\002\003"); - print_contents(); - prints("\003\002"); -} - -void center_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -numeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos) -: text_entry(s, m), dot_pos(pos) -{ -} - -void numeric_text_entry::do_width() -{ - if (dot_pos != 0) { - set_location(); - printfs(".nr %1 0\\w" DELIMITER_CHAR, - block_width_reg(start_row, start_col)); - set_inline_modifier(mod); - for (int i = 0; i < dot_pos; i++) - prints(contents[i]); - restore_inline_modifier(mod); - prints(DELIMITER_CHAR "\n"); - printfs(".nr %1 \\n[%1]>?\\n[%2]\n", - span_left_numeric_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - } - else - printfs(".nr %1 0\n", block_width_reg(start_row, start_col)); - if (contents[dot_pos] != '\0') { - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_right_numeric_width_reg(start_col, end_col)); - set_inline_modifier(mod); - prints(contents + dot_pos); - restore_inline_modifier(mod); - prints(DELIMITER_CHAR "\n"); - } -} - -void numeric_text_entry::simple_print(int) -{ - printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'", - span_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col), - column_start_reg(start_col), - block_width_reg(start_row, start_col)); - print_contents(); -} - -alphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m) -: text_entry(s, m) -{ -} - -void alphabetic_text_entry::do_width() -{ - set_location(); - printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, - span_alphabetic_width_reg(start_col, end_col)); - print_contents(); - prints(DELIMITER_CHAR "\n"); -} - -void alphabetic_text_entry::simple_print(int) -{ - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - printfs("\\h'\\n[%1]u-\\n[%2]u/2u'", - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - print_contents(); -} - -// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. - -void alphabetic_text_entry::add_tab() -{ - printfs(" \\n[%1]u", column_end_reg(end_col)); -} - -block_entry::block_entry(char *s, const entry_modifier *m) -: table_entry(m), contents(s) -{ -} - -block_entry::~block_entry() -{ - a_delete contents; -} - -void block_entry::position_vertically() -{ - if (start_row != end_row) - switch(mod->vertical_alignment) { - case entry_modifier::TOP: - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - break; - case entry_modifier::CENTER: - // Peform the motion in two stages so that the center is rounded - // vertically upwards even if net vertical motion is upwards. - printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); - printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); - break; - case entry_modifier::BOTTOM: - printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); - break; - default: - assert(0); - } - if (mod->stagger) - prints(".sp -.5v\n"); -} - -int block_entry::divert(int ncols, const string *mw, int *sep) -{ - do_divert(0, ncols, mw, sep); - return 1; -} - -void block_entry::do_divert(int alphabetic, int ncols, const string *mw, - int *sep) -{ - printfs(".di %1\n", block_diversion_name(start_row, start_col)); - prints(".if \\n[" SAVED_FILL_REG "] .fi\n" - ".in 0\n"); - prints(".ll "); - for (int i = start_col; i <= end_col; i++) - if (mw[i].empty()) - break; - if (i > end_col) { - // Every column spanned by this entry has a minimum width. - for (int i = start_col; i <= end_col; i++) { - if (i > start_col) { - if (sep) - printfs("+%1n", as_string(sep[i - 1])); - prints('+'); - } - printfs("(n;%1)", mw[i]); - } - printfs(">?\\n[%1]u", span_width_reg(start_col, end_col)); - } - else - printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))", - span_width_reg(start_col, end_col), - as_string(end_col - start_col + 1), - as_string(ncols + 1)); - if (alphabetic) - prints("-2n"); - prints("\n"); - set_modifier(mod); - prints(".cp \\n(" COMPATIBLE_REG "\n"); - set_location(); - prints(contents); - prints(".br\n.di\n.cp 0\n"); - if (!mod->zero_width) { - if (alphabetic) { - printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n", - span_width_reg(start_col, end_col)); - printfs(".nr %1 \\n[%1]>?\\n[dl]\n", - span_alphabetic_width_reg(start_col, end_col)); - } - else - printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col)); - } - printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col)); - printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col)); - prints("." RESET_MACRO_NAME "\n" - ".in \\n[" SAVED_INDENT_REG "]u\n" - ".nf\n"); - // the block might have contained .lf commands - location_force_filename = 1; -} - -void block_entry::do_width() -{ - // do nothing; the action happens in divert -} - -void block_entry::do_depth() -{ - printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n", - row_start_reg(start_row), - block_height_reg(start_row, start_col)); -} - -left_block_entry::left_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void left_block_entry::print() -{ - printfs(".in +\\n[%1]u\n", column_start_reg(start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - - - -right_block_entry::right_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void right_block_entry::print() -{ - printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -center_block_entry::center_block_entry(char *s, const entry_modifier *m) -: block_entry(s, m) -{ -} - -void center_block_entry::print() -{ - printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - block_width_reg(start_row, start_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -alphabetic_block_entry::alphabetic_block_entry(char *s, - const entry_modifier *m) -: block_entry(s, m) -{ -} - -int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep) -{ - do_divert(1, ncols, mw, sep); - return 1; -} - -void alphabetic_block_entry::print() -{ - printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", - column_start_reg(start_col), - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - printfs(".%1\n", block_diversion_name(start_row, start_col)); - prints(".in\n"); -} - -line_entry::line_entry(const entry_modifier *m) -: simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0) -{ -} - -void line_entry::note_double_vrule_on_right(int is_corner) -{ - double_vrule_on_right = is_corner ? 1 : 2; -} - -void line_entry::note_double_vrule_on_left(int is_corner) -{ - double_vrule_on_left = is_corner ? 1 : 2; -} - - -single_line_entry::single_line_entry(const entry_modifier *m) -: line_entry(m) -{ -} - -int single_line_entry::line_type() -{ - return 1; -} - -void single_line_entry::simple_print(int dont_move) -{ - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_left) { - prints(double_vrule_on_left == 1 ? "-" : "+"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u", - column_divide_reg(end_col+1)); - if (double_vrule_on_right) { - prints(double_vrule_on_left == 1 ? "+" : "-"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("0'\\s0"); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); -} - -single_line_entry *single_line_entry::to_single_line_entry() -{ - return this; -} - -double_line_entry::double_line_entry(const entry_modifier *m) -: line_entry(m) -{ -} - -int double_line_entry::line_type() -{ - return 2; -} - -void double_line_entry::simple_print(int dont_move) -{ - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_left) { - prints(double_vrule_on_left == 1 ? "-" : "+"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints("'"); - printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l |\\n[%1]u", - column_divide_reg(end_col+1)); - if (double_vrule_on_right) - prints("-" HALF_DOUBLE_LINE_SEP); - prints(" 0'"); - printfs("\\v'" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[%1]u", - column_divide_reg(start_col)); - if (double_vrule_on_right) { - prints(double_vrule_on_left == 1 ? "+" : "-"); - prints(HALF_DOUBLE_LINE_SEP); - } - prints(" 0'"); - prints("\\s0" - "\\v'-" HALF_DOUBLE_LINE_SEP "'"); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); -} - -double_line_entry *double_line_entry::to_double_line_entry() -{ - return this; -} - -short_line_entry::short_line_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int short_line_entry::line_type() -{ - return 1; -} - -void short_line_entry::simple_print(int dont_move) -{ - if (mod->stagger) - prints("\\v'-.5v'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); - printfs("\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[%1]u 0'" - "\\s0", - span_width_reg(start_col, end_col)); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); - if (mod->stagger) - prints("\\v'.5v'"); -} - -short_double_line_entry::short_double_line_entry(const entry_modifier *m) -: simple_entry(m) -{ -} - -int short_double_line_entry::line_type() -{ - return 2; -} - -void short_double_line_entry::simple_print(int dont_move) -{ - if (mod->stagger) - prints("\\v'-.5v'"); - if (!dont_move) - prints("\\v'-" BAR_HEIGHT "'"); - printfs("\\h'|\\n[%2]u'" - "\\v'-" HALF_DOUBLE_LINE_SEP "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[%1]u 0'" - "\\v'" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[%2]u 0'" - "\\s0" - "\\v'-" HALF_DOUBLE_LINE_SEP "'", - span_width_reg(start_col, end_col), - column_start_reg(start_col)); - if (!dont_move) - prints("\\v'" BAR_HEIGHT "'"); - if (mod->stagger) - prints("\\v'.5v'"); -} - -void set_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - printfs(".ft %1\n", m->font); - if (m->point_size.val != 0) { - prints(".ps "); - if (m->point_size.inc > 0) - prints('+'); - else if (m->point_size.inc < 0) - prints('-'); - printfs("%1\n", as_string(m->point_size.val)); - } - if (m->vertical_spacing.val != 0) { - prints(".vs "); - if (m->vertical_spacing.inc > 0) - prints('+'); - else if (m->vertical_spacing.inc < 0) - prints('-'); - printfs("%1\n", as_string(m->vertical_spacing.val)); - } -} - -void set_inline_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - printfs("\\f[%1]", m->font); - if (m->point_size.val != 0) { - prints("\\s["); - if (m->point_size.inc > 0) - prints('+'); - else if (m->point_size.inc < 0) - prints('-'); - printfs("%1]", as_string(m->point_size.val)); - } - if (m->stagger) - prints("\\v'-.5v'"); -} - -void restore_inline_modifier(const entry_modifier *m) -{ - if (!m->font.empty()) - prints("\\f[\\n[" SAVED_FONT_REG "]]"); - if (m->point_size.val != 0) - prints("\\s[\\n[" SAVED_SIZE_REG "]]"); - if (m->stagger) - prints("\\v'.5v'"); -} - - -struct stuff { - stuff *next; - int row; // occurs before row `row' - char printed; // has it been printed? - - stuff(int); - virtual void print(table *) = 0; - virtual ~stuff(); - virtual int is_single_line() { return 0; }; - virtual int is_double_line() { return 0; }; -}; - -stuff::stuff(int r) : row(r), next(0), printed(0) -{ -} - -stuff::~stuff() -{ -} - -struct text_stuff : stuff { - string contents; - const char *filename; - int lineno; - - text_stuff(const string &, int r, const char *fn, int ln); - ~text_stuff(); - void print(table *); -}; - - -text_stuff::text_stuff(const string &s, int r, const char *fn, int ln) -: contents(s), stuff(r), filename(fn), lineno(ln) -{ -} - -text_stuff::~text_stuff() -{ -} - -void text_stuff::print(table *) -{ - printed = 1; - prints(".cp \\n(" COMPATIBLE_REG "\n"); - set_troff_location(filename, lineno); - prints(contents); - prints(".cp 0\n"); - location_force_filename = 1; // it might have been a .lf command -} - -struct single_hline_stuff : stuff { - single_hline_stuff(int r); - void print(table *); - int is_single_line(); -}; - -single_hline_stuff::single_hline_stuff(int r) : stuff(r) -{ -} - -void single_hline_stuff::print(table *tbl) -{ - printed = 1; - tbl->print_single_hline(row); -} - -int single_hline_stuff::is_single_line() -{ - return 1; -} - -struct double_hline_stuff : stuff { - double_hline_stuff(int r); - void print(table *); - int is_double_line(); -}; - -double_hline_stuff::double_hline_stuff(int r) : stuff(r) -{ -} - -void double_hline_stuff::print(table *tbl) -{ - printed = 1; - tbl->print_double_hline(row); -} - -int double_hline_stuff::is_double_line() -{ - return 1; -} - -struct vertical_rule { - vertical_rule *next; - short start_row; - short end_row; - short col; - char is_double; - string top_adjust; - string bot_adjust; - - vertical_rule(int sr, int er, int c, int dbl, vertical_rule *); - ~vertical_rule(); - void contribute_to_bottom_macro(table *); - void print(); -}; - -vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p) -: start_row(sr), end_row(er), col(c), is_double(dbl), next(p) -{ -} - -vertical_rule::~vertical_rule() -{ -} - -void vertical_rule::contribute_to_bottom_macro(table *tbl) -{ - printfs(".if \\n[" CURRENT_ROW_REG "]>=%1", - as_string(start_row)); - if (end_row != tbl->get_nrows() - 1) - printfs("&(\\n[" CURRENT_ROW_REG "]<%1)", - as_string(end_row)); - prints(" \\{"); - printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n", - as_string(start_row), - row_top_reg(start_row)); - const char *offset_table[3]; - if (is_double) { - offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; - offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; - offset_table[2] = 0; - } - else { - offset_table[0] = ""; - offset_table[1] = 0; - } - for (const char **offsetp = offset_table; *offsetp; offsetp++) { - prints(".sp -1\n" - "\\v'" BODY_DEPTH); - if (!bot_adjust.empty()) - printfs("+%1", bot_adjust); - prints("'"); - printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v", - column_divide_reg(col), - row_top_reg(start_row), - *offsetp); - if (!bot_adjust.empty()) - printfs("-(%1)", bot_adjust); - // don't perform the top adjustment if the top is actually #T - if (!top_adjust.empty()) - printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))", - top_adjust, - as_string(start_row)); - prints("'\\s0\n"); - } - prints(".\\}\n"); -} - -void vertical_rule::print() -{ - printfs("\\*[" TRANSPARENT_STRING_NAME "]" - ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] " - ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n", - as_string(start_row), - row_top_reg(start_row)); - const char *offset_table[3]; - if (is_double) { - offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; - offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; - offset_table[2] = 0; - } - else { - offset_table[0] = ""; - offset_table[1] = 0; - } - for (const char **offsetp = offset_table; *offsetp; offsetp++) { - prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n" - "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH); - if (!bot_adjust.empty()) - printfs("+%1", bot_adjust); - prints("'"); - printfs("\\h'\\n[%1]u%3'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v", - column_divide_reg(col), - row_top_reg(start_row), - *offsetp); - if (!bot_adjust.empty()) - printfs("-(%1)", bot_adjust); - // don't perform the top adjustment if the top is actually #T - if (!top_adjust.empty()) - printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n[" - LAST_PASSED_ROW_REG "]))", - top_adjust, - as_string(start_row)); - prints("'" - "\\s0\n"); - } -} - -table::table(int nc, unsigned f, int ls, char dpc) -: ncolumns(nc), flags(f), linesize(ls), decimal_point_char(dpc), - nrows(0), allocated_rows(0), entry(0), entry_list(0), - left_separation(0), right_separation(0), stuff_list(0), vline(0), - vrule_list(0), row_is_all_lines(0), span_list(0) -{ - minimum_width = new string[ncolumns]; - column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; - equal = new char[ncolumns]; - int i; - for (i = 0; i < ncolumns; i++) - equal[i] = 0; - for (i = 0; i < ncolumns-1; i++) - column_separation[i] = DEFAULT_COLUMN_SEPARATION; - delim[0] = delim[1] = '\0'; -} - -table::~table() -{ - for (int i = 0; i < nrows; i++) { - a_delete entry[i]; - a_delete vline[i]; - } - a_delete entry; - a_delete vline; - while (entry_list) { - table_entry *tem = entry_list; - entry_list = entry_list->next; - delete tem; - } - ad_delete(ncolumns) minimum_width; - a_delete column_separation; - a_delete equal; - while (stuff_list) { - stuff *tem = stuff_list; - stuff_list = stuff_list->next; - delete tem; - } - while (vrule_list) { - vertical_rule *tem = vrule_list; - vrule_list = vrule_list->next; - delete tem; - } - a_delete row_is_all_lines; - while (span_list) { - horizontal_span *tem = span_list; - span_list = span_list->next; - delete tem; - } -} - -void table::set_delim(char c1, char c2) -{ - delim[0] = c1; - delim[1] = c2; -} - -void table::set_minimum_width(int c, const string &w) -{ - assert(c >= 0 && c < ncolumns); - minimum_width[c] = w; -} - -void table::set_column_separation(int c, int n) -{ - assert(c >= 0 && c < ncolumns - 1); - column_separation[c] = n; -} - -void table::set_equal_column(int c) -{ - assert(c >= 0 && c < ncolumns); - equal[c] = 1; -} - -void table::add_stuff(stuff *p) -{ - for (stuff **pp = &stuff_list; *pp; pp = &(*pp)->next) - ; - *pp = p; -} - -void table::add_text_line(int r, const string &s, const char *filename, int lineno) -{ - add_stuff(new text_stuff(s, r, filename, lineno)); -} - -void table::add_single_hline(int r) -{ - add_stuff(new single_hline_stuff(r)); -} - -void table::add_double_hline(int r) -{ - add_stuff(new double_hline_stuff(r)); -} - -void table::allocate(int r) -{ - if (r >= nrows) { - typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug - if (r >= allocated_rows) { - if (allocated_rows == 0) { - allocated_rows = 16; - if (allocated_rows <= r) - allocated_rows = r + 1; - entry = new PPtable_entry[allocated_rows]; - vline = new char*[allocated_rows]; - } - else { - table_entry ***old_entry = entry; - int old_allocated_rows = allocated_rows; - allocated_rows *= 2; - if (allocated_rows <= r) - allocated_rows = r + 1; - entry = new PPtable_entry[allocated_rows]; - memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows); - a_delete old_entry; - char **old_vline = vline; - vline = new char*[allocated_rows]; - memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows); - a_delete old_vline; - } - } - assert(allocated_rows > r); - while (nrows <= r) { - entry[nrows] = new table_entry*[ncolumns]; - for (int i = 0; i < ncolumns; i++) - entry[nrows][i] = 0; - vline[nrows] = new char[ncolumns+1]; - for (i = 0; i < ncolumns+1; i++) - vline[nrows][i] = 0; - nrows++; - } - } -} - -void table::do_hspan(int r, int c) -{ - assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); - if (c == 0) { - error("first column cannot be horizontally spanned"); - return; - } - table_entry *e = entry[r][c]; - if (e) { - assert(e->start_row <= r && r <= e->end_row - && e->start_col <= c && c <= e->end_col - && e->end_row - e->start_row > 0 - && e->end_col - e->start_col > 0); - return; - } - e = entry[r][c-1]; - // e can be 0 if we had an empty entry or an error - if (e == 0) - return; - if (e->start_row != r) { - /* - l l - ^ s */ - error("impossible horizontal span at row %1, column %2", r + 1, c + 1); - } - else { - e->end_col = c; - entry[r][c] = e; - } -} - -void table::do_vspan(int r, int c) -{ - assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); - if (r == 0) { - error("first row cannot be vertically spanned"); - return; - } - table_entry *e = entry[r][c]; - if (e) { - assert(e->start_row <= r && r <= e->end_row - && e->start_col <= c && c <= e->end_col - && e->end_row - e->start_row > 0 - && e->end_col - e->start_col > 0); - return; - } - e = entry[r-1][c]; - // e can be 0 if we had an empty entry or an error - if (e == 0) - return; - if (e->start_col != c) { - /* l s - l ^ */ - error("impossible vertical span at row %1, column %2", r + 1, c + 1); - } - else { - for (int i = c; i <= e->end_col; i++) { - assert(entry[r][i] == 0); - entry[r][i] = e; - } - e->end_row = r; - } -} - -int find_decimal_point(const char *s, char decimal_point_char, - const char *delim) -{ - if (s == 0 || *s == '\0') - return -1; - const char *p; - int in_delim = 0; // is p within eqn delimiters? - // tbl recognises \& even within eqn delimiters; I don't - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (p[0] == '\\' && p[1] == '&') - return p - s; - int possible_pos = -1; - in_delim = 0; - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (p[0] == decimal_point_char && csdigit(p[1])) - possible_pos = p - s; - if (possible_pos >= 0) - return possible_pos; - in_delim = 0; - for (p = s; *p; p++) - if (in_delim) { - if (*p == delim[1]) - in_delim = 0; - } - else if (*p == delim[0]) - in_delim = 1; - else if (csdigit(*p)) - possible_pos = p + 1 - s; - return possible_pos; -} - -void table::add_entry(int r, int c, const string &str, const entry_format *f, - const char *fn, int ln) -{ - allocate(r); - table_entry *e = 0; - if (str == "\\_") { - e = new short_line_entry(f); - } - else if (str == "\\=") { - e = new short_double_line_entry(f); - } - else if (str == "_") { - single_line_entry *lefte; - if (c > 0 && entry[r][c-1] != 0 && - (lefte = entry[r][c-1]->to_single_line_entry()) != 0 - && lefte->start_row == r - && lefte->mod->stagger == f->stagger) { - lefte->end_col = c; - entry[r][c] = lefte; - } - else - e = new single_line_entry(f); - } - else if (str == "=") { - double_line_entry *lefte; - if (c > 0 && entry[r][c-1] != 0 && - (lefte = entry[r][c-1]->to_double_line_entry()) != 0 - && lefte->start_row == r - && lefte->mod->stagger == f->stagger) { - lefte->end_col = c; - entry[r][c] = lefte; - } - else - e = new double_line_entry(f); - } - else if (str == "\\^") { - do_vspan(r, c); - } - else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') { - if (str.search('\n') >= 0) - error_with_file_and_line(fn, ln, "bad repeated character"); - else { - char *s = str.substring(2, str.length() - 2).extract(); - e = new repeated_char_entry(s, f); - } - } - else { - int is_block = str.search('\n') >= 0; - char *s; - switch (f->type) { - case FORMAT_SPAN: - assert(str.empty()); - do_hspan(r, c); - break; - case FORMAT_LEFT: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new left_block_entry(s, f); - else - e = new left_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_CENTER: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new center_block_entry(s, f); - else - e = new center_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_RIGHT: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new right_block_entry(s, f); - else - e = new right_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_NUMERIC: - if (!str.empty()) { - s = str.extract(); - if (is_block) { - error_with_file_and_line(fn, ln, "can't have numeric text block"); - e = new left_block_entry(s, f); - } - else { - int pos = find_decimal_point(s, decimal_point_char, delim); - if (pos < 0) - e = new center_text_entry(s, f); - else - e = new numeric_text_entry(s, f, pos); - } - } - else - e = new empty_entry(f); - break; - case FORMAT_ALPHABETIC: - if (!str.empty()) { - s = str.extract(); - if (is_block) - e = new alphabetic_block_entry(s, f); - else - e = new alphabetic_text_entry(s, f); - } - else - e = new empty_entry(f); - break; - case FORMAT_VSPAN: - do_vspan(r, c); - break; - case FORMAT_HLINE: - if (str.length() != 0) - error_with_file_and_line(fn, ln, - "non-empty data entry for `_' format ignored"); - e = new single_line_entry(f); - break; - case FORMAT_DOUBLE_HLINE: - if (str.length() != 0) - error_with_file_and_line(fn, ln, - "non-empty data entry for `=' format ignored"); - e = new double_line_entry(f); - break; - default: - assert(0); - } - } - if (e) { - table_entry *preve = entry[r][c]; - if (preve) { - /* c s - ^ l */ - error_with_file_and_line(fn, ln, "row %1, column %2 already spanned", - r + 1, c + 1); - delete e; - } - else { - e->input_lineno = ln; - e->input_filename = fn; - e->start_row = e->end_row = r; - e->start_col = e->end_col = c; - for (table_entry **p = &entry_list; *p; p = &(*p)->next) - ; - *p = e; - entry[r][c] = e; - } - } -} - -// add vertical lines for row r - -void table::add_vlines(int r, const char *v) -{ - allocate(r); - for (int i = 0; i < ncolumns+1; i++) - vline[r][i] = v[i]; -} - -void table::check() -{ - table_entry *p = entry_list; - int i, j; - while (p) { - for (i = p->start_row; i <= p->end_row; i++) - for (j = p->start_col; j <= p->end_col; j++) - assert(entry[i][j] == p); - p = p->next; - } -} - -void table::print() -{ - location_force_filename = 1; - check(); - init_output(); - determine_row_type(); - compute_widths(); - if (!(flags & CENTER)) - prints(".if \\n[" SAVED_CENTER_REG "] \\{"); - prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2)\n" - ".nr " SAVED_INDENT_REG " \\n[.i]\n"); - if (!(flags & CENTER)) - prints(".\\}\n"); - build_vrule_list(); - define_bottom_macro(); - do_top(); - for (int i = 0; i < nrows; i++) - do_row(i); - do_bottom(); -} - -void table::determine_row_type() -{ - row_is_all_lines = new char[nrows]; - for (int i = 0; i < nrows; i++) { - int had_single = 0; - int had_double = 0; - int had_non_line = 0; - for (int c = 0; c < ncolumns; c++) { - table_entry *e = entry[i][c]; - if (e != 0) { - if (e->start_row == e->end_row) { - int t = e->line_type(); - switch (t) { - case -1: - had_non_line = 1; - break; - case 0: - // empty - break; - case 1: - had_single = 1; - break; - case 2: - had_double = 1; - break; - default: - assert(0); - } - if (had_non_line) - break; - } - c = e->end_col; - } - } - if (had_non_line) - row_is_all_lines[i] = 0; - else if (had_double) - row_is_all_lines[i] = 2; - else if (had_single) - row_is_all_lines[i] = 1; - else - row_is_all_lines[i] = 0; - } -} - - -void table::init_output() -{ - prints(".nr " COMPATIBLE_REG " \\n(.C\n" - ".cp 0\n"); - if (linesize > 0) - printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize)); - else - prints(".nr " LINESIZE_REG " \\n[.s]\n"); - if (!(flags & CENTER)) - prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n"); - prints(".de " RESET_MACRO_NAME "\n" - ".ft \\n[.f]\n" - ".ps \\n[.s]\n" - ".vs \\n[.v]u\n" - ".in \\n[.i]u\n" - ".ll \\n[.l]u\n" - ".ls \\n[.L]\n" - ".ad \\n[.j]\n" - ".ie \\n[.u] .fi\n" - ".el .nf\n" - ".ce \\n[.ce]\n" - "..\n" - ".nr " SAVED_INDENT_REG " \\n[.i]\n" - ".nr " SAVED_FONT_REG " \\n[.f]\n" - ".nr " SAVED_SIZE_REG " \\n[.s]\n" - ".nr " SAVED_FILL_REG " \\n[.u]\n" - ".nr T. 0\n" - ".nr " CURRENT_ROW_REG " 0-1\n" - ".nr " LAST_PASSED_ROW_REG " 0-1\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" - ".ds " TRANSPARENT_STRING_NAME "\n" - ".ds " QUOTE_STRING_NAME "\n" - ".nr " NEED_BOTTOM_RULE_REG " 1\n" - ".nr " SUPPRESS_BOTTOM_REG " 0\n" - ".eo\n" - ".de " REPEATED_MARK_MACRO "\n" - ".mk \\$1\n" - ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n" - "..\n" - ".de " REPEATED_VPT_MACRO "\n" - ".vpt \\$1\n" - ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n" - "..\n"); - if (!(flags & NOKEEP)) - prints(".de " KEEP_MACRO_NAME "\n" - ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n" - ".ds " TRANSPARENT_STRING_NAME " \\!\n" - ".di " SECTION_DIVERSION_NAME "\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 1\n" - ".in 0\n" - ".\\}\n" - "..\n" - ".de " RELEASE_MACRO_NAME "\n" - ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{" - ".di\n" - ".in \\n[" SAVED_INDENT_REG "]u\n" - ".nr " SAVED_DN_REG " \\n[dn]\n" - ".ds " QUOTE_STRING_NAME "\n" - ".ds " TRANSPARENT_STRING_NAME "\n" - ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" - ".if \\n[.t]<=\\n[dn] \\{" - ".nr T. 1\n" - ".T#\n" - ".nr " SUPPRESS_BOTTOM_REG " 1\n" - ".sp \\n[.t]u\n" - ".nr " SUPPRESS_BOTTOM_REG " 0\n" - ".mk #T\n" - ".\\}\n" - ".if \\n[.t]<=\\n[" SAVED_DN_REG "] " - /* Since we turn off traps, it won't get into an infinite loop - when we try and print it; it will just go off the bottom of the - page. */ - ".tm warning: page \\n%: table text block will not fit on one page\n" - ".nf\n" - ".ls 1\n" - "." SECTION_DIVERSION_NAME "\n" - ".ls\n" - ".rm " SECTION_DIVERSION_NAME "\n" - ".\\}\n" - "..\n" - ".nr " TABLE_DIVERSION_FLAG_REG " 0\n" - ".de " TABLE_KEEP_MACRO_NAME "\n" - ".if '\\n[.z]'' \\{" - ".di " TABLE_DIVERSION_NAME "\n" - ".nr " TABLE_DIVERSION_FLAG_REG " 1\n" - ".\\}\n" - "..\n" - ".de " TABLE_RELEASE_MACRO_NAME "\n" - ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n" - ".di\n" - ".nr " SAVED_DN_REG " \\n[dn]\n" - ".ne \\n[dn]u+\\n[.V]u\n" - ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] " - ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n" - ".el \\{" - ".in 0\n" - ".ls 1\n" - ".nf\n" - "." TABLE_DIVERSION_NAME "\n" - ".\\}\n" - ".rm " TABLE_DIVERSION_NAME "\n" - ".\\}\n" - "..\n"); - prints(".ec\n" - ".ce 0\n" - ".nf\n"); -} - -string block_width_reg(int r, int c) -{ - static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c); - return string(name); -} - -string block_diversion_name(int r, int c) -{ - static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c); - return string(name); -} - -string block_height_reg(int r, int c) -{ - static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c); - return string(name); -} - -string span_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_left_numeric_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_right_numeric_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - -string span_alphabetic_width_reg(int start_col, int end_col) -{ - static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; - sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col); - if (end_col != start_col) - sprintf(strchr(name, '\0'), ",%d", end_col); - return string(name); -} - - -string column_separation_reg(int col) -{ - static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col); - return string(name); -} - -string row_start_reg(int row) -{ - static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS]; - sprintf(name, ROW_START_PREFIX "%d", row); - return string(name); -} - -string column_start_reg(int col) -{ - static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_START_PREFIX "%d", col); - return string(name); -} - -string column_end_reg(int col) -{ - static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_END_PREFIX "%d", col); - return string(name); -} - -string column_divide_reg(int col) -{ - static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS]; - sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col); - return string(name); -} - -string row_top_reg(int row) -{ - static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS]; - sprintf(name, ROW_TOP_PREFIX "%d", row); - return string(name); -} - -void init_span_reg(int start_col, int end_col) -{ - printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n", - span_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col)); -} - -void compute_span_width(int start_col, int end_col) -{ - printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n" - ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n", - span_width_reg(start_col, end_col), - span_left_numeric_width_reg(start_col, end_col), - span_right_numeric_width_reg(start_col, end_col), - span_alphabetic_width_reg(start_col, end_col)); - -} - -// Increase the widths of columns so that the width of any spanning entry -// is no greater than the sum of the widths of the columns that it spans. -// Ensure that the widths of columns remain equal. - -void table::divide_span(int start_col, int end_col) -{ - assert(end_col > start_col); - printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]", - span_width_reg(start_col, end_col), - span_width_reg(start_col, start_col)); - for (int i = start_col + 1; i <= end_col; i++) { - // The column separation may shrink with the expand option. - if (!(flags & EXPAND)) - printfs("+%1n", as_string(column_separation[i - 1])); - printfs("+\\n[%1]", span_width_reg(i, i)); - } - prints(")\n"); - printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n", - as_string(end_col - start_col + 1)); - prints(".if \\n[" NEEDED_REG "] \\{"); - for (i = start_col; i <= end_col; i++) - printfs(".nr %1 +\\n[" NEEDED_REG "]\n", - span_width_reg(i, i)); - int equal_flag = 0; - for (i = start_col; i <= end_col && !equal_flag; i++) - if (equal[i]) - equal_flag = 1; - if (equal_flag) { - for (i = 0; i < ncolumns; i++) - if (i < start_col || i > end_col) - printfs(".nr %1 +\\n[" NEEDED_REG "]\n", - span_width_reg(i, i)); - } - prints(".\\}\n"); -} - - -void table::sum_columns(int start_col, int end_col) -{ - assert(end_col > start_col); - printfs(".nr %1 \\n[%2]", - span_width_reg(start_col, end_col), - span_width_reg(start_col, start_col)); - for (int i = start_col + 1; i <= end_col; i++) - printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]", - as_string(column_separation[i - 1]), - span_width_reg(i, i)); - prints('\n'); -} - -horizontal_span::horizontal_span(int sc, int ec, horizontal_span *p) -: start_col(sc), end_col(ec), next(p) -{ -} - -void table::build_span_list() -{ - span_list = 0; - table_entry *p = entry_list; - while (p) { - if (p->end_col != p->start_col) { - for (horizontal_span *q = span_list; q; q = q->next) - if (q->start_col == p->start_col - && q->end_col == p->end_col) - break; - if (!q) - span_list = new horizontal_span(p->start_col, p->end_col, span_list); - } - p = p->next; - } - // Now sort span_list primarily by order of end_row, and secondarily - // by reverse order of start_row. This ensures that if we divide - // spans using the order in span_list, we will get reasonable results. - horizontal_span *unsorted = span_list; - span_list = 0; - while (unsorted) { - for (horizontal_span **pp = &span_list; *pp; pp = &(*pp)->next) - if (unsorted->end_col < (*pp)->end_col - || (unsorted->end_col == (*pp)->end_col - && (unsorted->start_col > (*pp)->start_col))) - break; - horizontal_span *tem = unsorted->next; - unsorted->next = *pp; - *pp = unsorted; - unsorted = tem; - } -} - - -void table::compute_separation_factor() -{ - if (flags & (ALLBOX|BOX|DOUBLEBOX)) - left_separation = right_separation = 1; - else { - for (int i = 0; i < nrows; i++) { - if (vline[i][0] > 0) - left_separation = 1; - if (vline[i][ncolumns] > 0) - right_separation = 1; - } - } - if (flags & EXPAND) { - int total_sep = left_separation + right_separation; - for (int i = 0; i < ncolumns - 1; i++) - total_sep += column_separation[i]; - if (total_sep != 0) { - // Don't let the separation factor be negative. - prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]"); - for (i = 0; i < ncolumns; i++) - printfs("-\\n[%1]", span_width_reg(i, i)); - printfs("/%1>?0\n", as_string(total_sep)); - } - } -} - -void table::compute_column_positions() -{ - printfs(".nr %1 0\n", column_divide_reg(0)); - printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n", - column_start_reg(0), - as_string(left_separation)); - for (int i = 1;; i++) { - printfs(".nr %1 \\n[%2]+\\n[%3]\n", - column_end_reg(i-1), - column_start_reg(i-1), - span_width_reg(i-1, i-1)); - if (i >= ncolumns) - break; - printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", - column_start_reg(i), - column_end_reg(i-1), - as_string(column_separation[i-1])); - printfs(".nr %1 \\n[%2]+\\n[%3]/2\n", - column_divide_reg(i), - column_end_reg(i-1), - column_start_reg(i)); - } - printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", - column_divide_reg(ncolumns), - column_end_reg(i-1), - as_string(right_separation)); - printfs(".nr TW \\n[%1]\n", - column_divide_reg(ncolumns)); - if (flags & DOUBLEBOX) { - printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0)); - printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns)); - } -} - -void table::make_columns_equal() -{ - int first = -1; // index of first equal column - for (int i = 0; i < ncolumns; i++) - if (equal[i]) { - if (first < 0) { - printfs(".nr %1 \\n[%1]", span_width_reg(i, i)); - first = i; - } - else - printfs(">?\\n[%1]", span_width_reg(i, i)); - } - if (first >= 0) { - prints('\n'); - for (i = first + 1; i < ncolumns; i++) - if (equal[i]) - printfs(".nr %1 \\n[%2]\n", - span_width_reg(i, i), - span_width_reg(first, first)); - } -} - -void table::compute_widths() -{ - build_span_list(); - int i; - horizontal_span *p; - prints(".nr " SEPARATION_FACTOR_REG " 1n\n"); - for (i = 0; i < ncolumns; i++) { - init_span_reg(i, i); - if (!minimum_width[i].empty()) - printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]); - } - for (p = span_list; p; p = p->next) - init_span_reg(p->start_col, p->end_col); - table_entry *q; - for (q = entry_list; q; q = q->next) - if (!q->mod->zero_width) - q->do_width(); - for (i = 0; i < ncolumns; i++) - compute_span_width(i, i); - for (p = span_list; p; p = p->next) - compute_span_width(p->start_col, p->end_col); - make_columns_equal(); - // Note that divide_span keeps equal width columns equal. - for (p = span_list; p; p = p->next) - divide_span(p->start_col, p->end_col); - for (p = span_list; p; p = p->next) - sum_columns(p->start_col, p->end_col); - int had_spanning_block = 0; - int had_equal_block = 0; - for (q = entry_list; q; q = q->next) - if (q->divert(ncolumns, minimum_width, - (flags & EXPAND) ? column_separation : 0)) { - if (q->end_col > q->start_col) - had_spanning_block = 1; - for (i = q->start_col; i <= q->end_col && !had_equal_block; i++) - if (equal[i]) - had_equal_block = 1; - } - if (had_equal_block) - make_columns_equal(); - if (had_spanning_block) - for (p = span_list; p; p = p->next) - divide_span(p->start_col, p->end_col); - compute_separation_factor(); - for (p = span_list; p; p = p->next) - sum_columns(p->start_col, p->end_col); - compute_column_positions(); -} - -void table::print_single_hline(int r) -{ - prints(".vs " LINE_SEP ">?\\n[.V]u\n" - ".ls 1\n" - "\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]"); - if (r > nrows - 1) - prints("\\D'l |\\n[TW]u 0'"); - else { - int start_col = 0; - for (;;) { - while (start_col < ncolumns - && entry[r][start_col] != 0 - && entry[r][start_col]->start_row != r) - start_col++; - for (int end_col = start_col; - end_col < ncolumns - && (entry[r][end_col] == 0 - || entry[r][end_col]->start_row == r); - end_col++) - ; - if (end_col <= start_col) - break; - printfs("\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if ((r > 0 && vline[r-1][start_col] == 2) - || (r < nrows && vline[r][start_col] == 2)) - prints("-" HALF_DOUBLE_LINE_SEP); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if ((r > 0 && vline[r-1][end_col] == 2) - || (r < nrows && vline[r][end_col] == 2)) - prints("+" HALF_DOUBLE_LINE_SEP); - prints(" 0'"); - start_col = end_col; - } - } - prints("\\s0\n"); - prints(".ls\n" - ".vs\n"); -} - -void table::print_double_hline(int r) -{ - prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP - ">?\\n[.V]u\n" - ".ls 1\n" - "\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]"); - if (r > nrows - 1) - prints("\\v'-" DOUBLE_LINE_SEP "'" - "\\D'l |\\n[TW]u 0'" - "\\v'" DOUBLE_LINE_SEP "'" - "\\h'|0'" - "\\D'l |\\n[TW]u 0'"); - else { - int start_col = 0; - for (;;) { - while (start_col < ncolumns - && entry[r][start_col] != 0 - && entry[r][start_col]->start_row != r) - start_col++; - for (int end_col = start_col; - end_col < ncolumns - && (entry[r][end_col] == 0 - || entry[r][end_col]->start_row == r); - end_col++) - ; - if (end_col <= start_col) - break; - const char *left_adjust = 0; - if ((r > 0 && vline[r-1][start_col] == 2) - || (r < nrows && vline[r][start_col] == 2)) - left_adjust = "-" HALF_DOUBLE_LINE_SEP; - const char *right_adjust = 0; - if ((r > 0 && vline[r-1][end_col] == 2) - || (r < nrows && vline[r][end_col] == 2)) - right_adjust = "+" HALF_DOUBLE_LINE_SEP; - printfs("\\v'-" DOUBLE_LINE_SEP "'" - "\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (left_adjust) - prints(left_adjust); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if (right_adjust) - prints(right_adjust); - prints(" 0'"); - printfs("\\v'" DOUBLE_LINE_SEP "'" - "\\h'|\\n[%1]u", - column_divide_reg(start_col)); - if (left_adjust) - prints(left_adjust); - prints("'"); - printfs("\\D'l |\\n[%1]u", - column_divide_reg(end_col)); - if (right_adjust) - prints(right_adjust); - prints(" 0'"); - start_col = end_col; - } - } - prints("\\s0\n" - ".ls\n" - ".vs\n"); -} - -void table::compute_vrule_top_adjust(int start_row, int col, string &result) -{ - if (row_is_all_lines[start_row] && start_row < nrows - 1) { - if (row_is_all_lines[start_row] == 2) - result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP; - else - result = LINE_SEP ">?\\n[.V]u"; - start_row++; - } - else { - result = ""; - if (start_row == 0) - return; - for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next) - if (p->row == start_row - && (p->is_single_line() || p->is_double_line())) - return; - } - int left = 0; - if (col > 0) { - table_entry *e = entry[start_row-1][col-1]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - left = 2; - else if (e->to_single_line_entry() != 0) - left = 1; - } - } - int right = 0; - if (col < ncolumns) { - table_entry *e = entry[start_row-1][col]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - right = 2; - else if (e->to_single_line_entry() != 0) - right = 1; - } - } - if (row_is_all_lines[start_row-1] == 0) { - if (left > 0 || right > 0) { - result += "-" BODY_DEPTH "-" BAR_HEIGHT; - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "-" HALF_DOUBLE_LINE_SEP; - else if (left == 2 && right == 2) - result += "+" HALF_DOUBLE_LINE_SEP; - } - } - else if (row_is_all_lines[start_row-1] == 2) { - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "-" DOUBLE_LINE_SEP; - else if (left == 1 || right == 1) - result += "-" HALF_DOUBLE_LINE_SEP; - } -} - -void table::compute_vrule_bot_adjust(int end_row, int col, string &result) -{ - if (row_is_all_lines[end_row] && end_row > 0) { - end_row--; - result = ""; - } - else { - for (stuff *p = stuff_list; p && p->row < end_row + 1; p = p->next) - ; - if (p && p->row == end_row + 1 && p->is_double_line()) { - result = "-" DOUBLE_LINE_SEP; - return; - } - if ((p != 0 && p->row == end_row + 1) - || end_row == nrows - 1) { - result = ""; - return; - } - if (row_is_all_lines[end_row+1] == 1) - result = LINE_SEP; - else if (row_is_all_lines[end_row+1] == 2) - result = LINE_SEP "+" DOUBLE_LINE_SEP; - else - result = ""; - } - int left = 0; - if (col > 0) { - table_entry *e = entry[end_row+1][col-1]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - left = 2; - else if (e->to_single_line_entry() != 0) - left = 1; - } - } - int right = 0; - if (col < ncolumns) { - table_entry *e = entry[end_row+1][col]; - if (e && e->start_row == e->end_row) { - if (e->to_double_line_entry() != 0) - right = 2; - else if (e->to_single_line_entry() != 0) - right = 1; - } - } - if (row_is_all_lines[end_row+1] == 0) { - if (left > 0 || right > 0) { - result = "1v-" BODY_DEPTH "-" BAR_HEIGHT; - if ((left == 2 && right != 2) || (right == 2 && left != 2)) - result += "+" HALF_DOUBLE_LINE_SEP; - else if (left == 2 && right == 2) - result += "-" HALF_DOUBLE_LINE_SEP; - } - } - else if (row_is_all_lines[end_row+1] == 2) { - if (left == 2 && right == 2) - result += "-" DOUBLE_LINE_SEP; - else if (left != 2 && right != 2 && (left == 1 || right == 1)) - result += "-" HALF_DOUBLE_LINE_SEP; - } -} - -void table::add_vertical_rule(int start_row, int end_row, int col, int is_double) -{ - vrule_list = new vertical_rule(start_row, end_row, col, is_double, - vrule_list); - compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust); - compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust); -} - -void table::build_vrule_list() -{ - int col; - if (flags & ALLBOX) { - for (col = 1; col < ncolumns; col++) { - int start_row = 0; - for (;;) { - while (start_row < nrows && vline_spanned(start_row, col)) - start_row++; - if (start_row >= nrows) - break; - int end_row = start_row; - while (end_row < nrows && !vline_spanned(end_row, col)) - end_row++; - end_row--; - add_vertical_rule(start_row, end_row, col, 0); - start_row = end_row + 1; - } - } - } - if (flags & (BOX|ALLBOX|DOUBLEBOX)) { - add_vertical_rule(0, nrows - 1, 0, 0); - add_vertical_rule(0, nrows - 1, ncolumns, 0); - } - for (int end_row = 0; end_row < nrows; end_row++) - for (col = 0; col < ncolumns+1; col++) - if (vline[end_row][col] > 0 - && !vline_spanned(end_row, col) - && (end_row == nrows - 1 - || vline[end_row+1][col] != vline[end_row][col] - || vline_spanned(end_row+1, col))) { - for (int start_row = end_row - 1; - start_row >= 0 - && vline[start_row][col] == vline[end_row][col] - && !vline_spanned(start_row, col); - start_row--) - ; - start_row++; - add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1); - } - for (vertical_rule *p = vrule_list; p; p = p->next) - if (p->is_double) - for (int r = p->start_row; r <= p->end_row; r++) { - if (p->col > 0 && entry[r][p->col-1] != 0 - && entry[r][p->col-1]->end_col == p->col-1) { - int is_corner = r == p->start_row || r == p->end_row; - entry[r][p->col-1]->note_double_vrule_on_right(is_corner); - } - if (p->col < ncolumns && entry[r][p->col] != 0 - && entry[r][p->col]->start_col == p->col) { - int is_corner = r == p->start_row || r == p->end_row; - entry[r][p->col]->note_double_vrule_on_left(is_corner); - } - } -} - -void table::define_bottom_macro() -{ - prints(".eo\n" - ".de T#\n" - ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{" - "." REPEATED_VPT_MACRO " 0\n" - ".mk " SAVED_VERTICAL_POS_REG "\n"); - if (flags & (BOX|ALLBOX|DOUBLEBOX)) { - prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{"); - print_single_hline(0); - prints(".\\}\n"); - } - prints(".ls 1\n"); - for (vertical_rule *p = vrule_list; p; p = p->next) - p->contribute_to_bottom_macro(this); - if (flags & DOUBLEBOX) - prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l \\n[TW]u 0'\\s0\n" - ".vs\n" - ".\\}\n" - ".if \\n[" LAST_PASSED_ROW_REG "]>=0 " - ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n" - ".sp -1\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n" - ".sp -1\n" - "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]" - "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"); - prints(".ls\n"); - prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n" - ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n" - "." REPEATED_VPT_MACRO " 1\n" - ".\\}\n" - "..\n" - ".ec\n"); -} - - -// is the vertical line before column c in row r horizontally spanned? - -int table::vline_spanned(int r, int c) -{ - assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1); - return (c != 0 && c != ncolumns && entry[r][c] != 0 - && entry[r][c]->start_col != c - // horizontally spanning lines don't count - && entry[r][c]->to_double_line_entry() == 0 - && entry[r][c]->to_single_line_entry() == 0); -} - -int table::row_begins_section(int r) -{ - assert(r >= 0 && r < nrows); - for (int i = 0; i < ncolumns; i++) - if (entry[r][i] && entry[r][i]->start_row != r) - return 0; - return 1; -} - -int table::row_ends_section(int r) -{ - assert(r >= 0 && r < nrows); - for (int i = 0; i < ncolumns; i++) - if (entry[r][i] && entry[r][i]->end_row != r) - return 0; - return 1; -} - -void table::do_row(int r) -{ - if (!(flags & NOKEEP) && row_begins_section(r)) - prints("." KEEP_MACRO_NAME "\n"); - int had_line = 0; - for (stuff *p = stuff_list; p && p->row < r; p = p->next) - ; - for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next) - if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) { - had_line = 1; - break; - } - if (!had_line && !row_is_all_lines[r]) - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - had_line = 0; - for (; p && p->row == r; p = p->next) - if (!p->printed) { - p->print(this); - if (!had_line && (p->is_single_line() || p->is_double_line())) { - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - had_line = 1; - } - } - // Change the row *after* printing the stuff list (which might contain .TH). - printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n", - as_string(r)); - if (!had_line && row_is_all_lines[r]) - printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); - // we might have had a .TH, for example, since we last tried - if (!(flags & NOKEEP) && row_begins_section(r)) - prints("." KEEP_MACRO_NAME "\n"); - printfs(".mk %1\n", row_start_reg(r)); - prints(".mk " BOTTOM_REG "\n" - "." REPEATED_VPT_MACRO " 0\n"); - int c; - int row_is_blank = 1; - int first_start_row = r; - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r) { - e->do_depth(); - if (e->start_row < first_start_row) - first_start_row = e->start_row; - row_is_blank = 0; - } - c = e->end_col; - } - } - if (row_is_blank) - prints(".nr " BOTTOM_REG " +1v\n"); - if (row_is_all_lines[r]) { - prints(".vs " LINE_SEP); - if (row_is_all_lines[r] == 2) - prints("+" DOUBLE_LINE_SEP); - prints(">?\\n[.V]u\n.ls 1\n"); - prints("\\&"); - prints("\\v'" BODY_DEPTH); - if (row_is_all_lines[r] == 2) - prints("-" HALF_DOUBLE_LINE_SEP); - prints("'"); - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == e->start_row) - e->to_simple_entry()->simple_print(1); - c = e->end_col; - } - } - prints("\n"); - prints(".ls\n" - ".vs\n"); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - for (int i = row_is_all_lines[r] ? r - 1 : r; - i >= first_start_row; - i--) { - simple_entry *first = 0; - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->start_row == i) { - simple_entry *simple = e->to_simple_entry(); - if (simple) { - if (!first) { - prints(".ta"); - first = simple; - } - simple->add_tab(); - } - } - c = e->end_col; - } - } - if (first) { - prints('\n'); - first->position_vertically(); - first->set_location(); - prints("\\&"); - first->simple_print(0); - for (c = first->end_col + 1; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->start_row == i) { - simple_entry *simple = e->to_simple_entry(); - if (simple) - simple->simple_print(0); - } - c = e->end_col; - } - } - prints('\n'); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - } - for (c = 0; c < ncolumns; c++) { - table_entry *e = entry[r][c]; - if (e) { - if (e->end_row == r && e->to_simple_entry() == 0) { - e->position_vertically(); - e->print(); - prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); - printfs(".sp |\\n[%1]u\n", row_start_reg(r)); - } - c = e->end_col; - } - } - prints("." REPEATED_VPT_MACRO " 1\n" - ".sp |\\n[" BOTTOM_REG "]u\n" - "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n"); - if (r != nrows - 1 && (flags & ALLBOX)) { - print_single_hline(r + 1); - prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n"); - } - if (r != nrows - 1) { - if (p && p->row == r + 1 - && (p->is_single_line() || p->is_double_line())) { - p->print(this); - prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG - " 0\n"); - } - int printed_one = 0; - for (vertical_rule *p = vrule_list; p; p = p->next) - if (p->end_row == r) { - if (!printed_one) { - prints("." REPEATED_VPT_MACRO " 0\n"); - printed_one = 1; - } - p->print(); - } - if (printed_one) - prints("." REPEATED_VPT_MACRO " 1\n"); - if (!(flags & NOKEEP) && row_ends_section(r)) - prints("." RELEASE_MACRO_NAME "\n"); - } -} - -void table::do_top() -{ - prints(".fc \002\003\n"); - if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) - prints("." TABLE_KEEP_MACRO_NAME "\n"); - if (flags & DOUBLEBOX) { - prints(".ls 1\n" - ".vs " LINE_SEP ">?\\n[.V]u\n" - "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n" - ".vs\n" - "." REPEATED_MARK_MACRO " " TOP_REG "\n" - ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"); - printfs("\\v'" BODY_DEPTH "'" - "\\s[\\n[" LINESIZE_REG "]]" - "\\h'\\n[%1]u'" - "\\D'l |\\n[%2]u 0'" - "\\s0" - "\n", - column_divide_reg(0), - column_divide_reg(ncolumns)); - prints(".ls\n" - ".vs\n"); - } - else if (flags & (ALLBOX|BOX)) { - print_single_hline(0); - } - //printfs(".mk %1\n", row_top_reg(0)); -} - -void table::do_bottom() -{ - // print stuff after last row - for (stuff *p = stuff_list; p; p = p->next) - if (p->row > nrows - 1) - p->print(this); - if (!(flags & NOKEEP)) - prints("." RELEASE_MACRO_NAME "\n"); - printfs(".mk %1\n", row_top_reg(nrows)); - prints(".nr " NEED_BOTTOM_RULE_REG " 1\n" - ".nr T. 1\n" - ".T#\n"); - if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) - prints("." TABLE_RELEASE_MACRO_NAME "\n"); - if (flags & DOUBLEBOX) - prints(".sp " DOUBLE_LINE_SEP "\n"); - prints("." RESET_MACRO_NAME "\n" - ".fc\n" - ".cp \\n(" COMPATIBLE_REG "\n"); -} - -int table::get_nrows() -{ - return nrows; -} - -const char *last_filename = 0; - -void set_troff_location(const char *fn, int ln) -{ - if (!location_force_filename && last_filename != 0 - && strcmp(fn, last_filename) == 0) - printfs(".lf %1\n", as_string(ln)); - else { - printfs(".lf %1 %2\n", as_string(ln), fn); - last_filename = fn; - location_force_filename = 0; - } -} - -void printfs(const char *s, const string &arg1, const string &arg2, - const string &arg3, const string &arg4, const string &arg5) -{ - if (s) { - char c; - while ((c = *s++) != '\0') { - if (c == '%') { - switch (*s++) { - case '1': - prints(arg1); - break; - case '2': - prints(arg2); - break; - case '3': - prints(arg3); - break; - case '4': - prints(arg4); - break; - case '5': - prints(arg5); - break; - case '6': - case '7': - case '8': - case '9': - break; - case '%': - prints('%'); - break; - default: - assert(0); - } - } - else - prints(c); - } - } -} - |
