/contrib/groff/src/preproc/tbl/table.cpp
https://bitbucket.org/freebsd/freebsd-head/ · C++ · 2778 lines · 2508 code · 206 blank · 64 comment · 690 complexity · 1207b28aa9e2b714dd0420b955f47f93 MD5 · raw file
Large files are truncated click here to view the full file
- // -*- C++ -*-
- /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2004
- 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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 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 LEADER_REG PREFIX LEADER
- #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;
- int start_col;
- int end_col;
- horizontal_span(int, int, horizontal_span *);
- };
- class single_line_entry;
- class double_line_entry;
- class simple_entry;
- class table_entry {
- friend class table;
- table_entry *next;
- int input_lineno;
- const char *input_filename;
- protected:
- int start_row;
- int end_row;
- int start_col;
- int 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), input_lineno(-1), input_filename(0),
- start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m)
- {
- }
- 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)
- : simple_entry(m), contents(s)
- {
- }
- 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 ");
- int i;
- for (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 j = start_col; j <= end_col; j++) {
- if (j > start_col) {
- if (sep)
- printfs("+%1n", as_string(sep[j - 1]));
- prints('+');
- }
- printfs("(n;%1)", mw[j]);
- }
- 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");
- prints(".cp \\n(" COMPATIBLE_REG "\n");
- set_modifier(mod);
- 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));
- }
- if (!m->macro.empty())
- printfs(".%1\n", m->macro);
- }
- 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) : next(0), row(r), printed(0)
- {
- }
- stuff::~stuff()
- {
- }
- struct text_stuff : public 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)
- : stuff(r), contents(s), 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 : public 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;
- int start_row;
- int end_row;
- int 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)
- : next(p), start_row(sr), end_row(er), col(c), is_double(dbl)
- {
- }
- 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)
- : flags(f), nrows(0), ncolumns(nc), linesize(ls), decimal_point_char(dpc),
- vrule_list(0), stuff_list(0), span_list(0),
- entry_list(0), entry_list_tailp(&entry_list), entry(0),
- vline(0), row_is_all_lines(0), left_separation(0), right_separation(0),
- allocated_rows(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)
- {
- stuff **pp;
- for (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];
- int i;
- for (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;
- *entry_list_tailp = e;
- entry_list_tailp = &e->next;
- 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[.i])\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");
- if (compatible_flag)
- prints(".ds " LEADER_REG " \\a\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 not 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));
- int i;
- for (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)
- : next(p), start_col(sc), end_col(ec)
- {
- }
- void table::build_span_list()
- {
- span_list = 0;
- table_entry *p = entry_list;
- while (p) {
- if (p->end_col != p->start_col) {
- horizontal_span *q;
- for (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) {
- horizontal_span **pp;
- for (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;
- int i;
- for (i = 0; i < ncolumns - 1; i++)
- total_sep += column_separatio…