1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2004 3114402Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru#include "table.h" 23114402Sru 24114402Sru#define BAR_HEIGHT ".25m" 25114402Sru#define DOUBLE_LINE_SEP "2p" 26114402Sru#define HALF_DOUBLE_LINE_SEP "1p" 27114402Sru#define LINE_SEP "2p" 28114402Sru#define BODY_DEPTH ".25m" 29114402Sru 30114402Sruconst int DEFAULT_COLUMN_SEPARATION = 3; 31114402Sru 32114402Sru#define DELIMITER_CHAR "\\[tbl]" 33114402Sru#define SEPARATION_FACTOR_REG PREFIX "sep" 34114402Sru#define BOTTOM_REG PREFIX "bot" 35114402Sru#define RESET_MACRO_NAME PREFIX "init" 36114402Sru#define LINESIZE_REG PREFIX "lps" 37114402Sru#define TOP_REG PREFIX "top" 38114402Sru#define CURRENT_ROW_REG PREFIX "crow" 39114402Sru#define LAST_PASSED_ROW_REG PREFIX "passed" 40114402Sru#define TRANSPARENT_STRING_NAME PREFIX "trans" 41114402Sru#define QUOTE_STRING_NAME PREFIX "quote" 42114402Sru#define SECTION_DIVERSION_NAME PREFIX "section" 43114402Sru#define SECTION_DIVERSION_FLAG_REG PREFIX "sflag" 44114402Sru#define SAVED_VERTICAL_POS_REG PREFIX "vert" 45114402Sru#define NEED_BOTTOM_RULE_REG PREFIX "brule" 46114402Sru#define KEEP_MACRO_NAME PREFIX "keep" 47114402Sru#define RELEASE_MACRO_NAME PREFIX "release" 48114402Sru#define SAVED_FONT_REG PREFIX "fnt" 49114402Sru#define SAVED_SIZE_REG PREFIX "sz" 50114402Sru#define SAVED_FILL_REG PREFIX "fll" 51114402Sru#define SAVED_INDENT_REG PREFIX "ind" 52114402Sru#define SAVED_CENTER_REG PREFIX "cent" 53114402Sru#define TABLE_DIVERSION_NAME PREFIX "table" 54114402Sru#define TABLE_DIVERSION_FLAG_REG PREFIX "tflag" 55114402Sru#define TABLE_KEEP_MACRO_NAME PREFIX "tkeep" 56114402Sru#define TABLE_RELEASE_MACRO_NAME PREFIX "trelease" 57114402Sru#define NEEDED_REG PREFIX "needed" 58114402Sru#define REPEATED_MARK_MACRO PREFIX "rmk" 59114402Sru#define REPEATED_VPT_MACRO PREFIX "rvpt" 60114402Sru#define SUPPRESS_BOTTOM_REG PREFIX "supbot" 61114402Sru#define SAVED_DN_REG PREFIX "dn" 62114402Sru 63114402Sru// this must be one character 64114402Sru#define COMPATIBLE_REG PREFIX "c" 65114402Sru 66151497Sru#define LEADER_REG PREFIX LEADER 67151497Sru 68114402Sru#define BLOCK_WIDTH_PREFIX PREFIX "tbw" 69114402Sru#define BLOCK_DIVERSION_PREFIX PREFIX "tbd" 70114402Sru#define BLOCK_HEIGHT_PREFIX PREFIX "tbh" 71114402Sru#define SPAN_WIDTH_PREFIX PREFIX "w" 72114402Sru#define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw" 73114402Sru#define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw" 74114402Sru#define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw" 75114402Sru#define COLUMN_SEPARATION_PREFIX PREFIX "cs" 76114402Sru#define ROW_START_PREFIX PREFIX "rs" 77114402Sru#define COLUMN_START_PREFIX PREFIX "cl" 78114402Sru#define COLUMN_END_PREFIX PREFIX "ce" 79114402Sru#define COLUMN_DIVIDE_PREFIX PREFIX "cd" 80114402Sru#define ROW_TOP_PREFIX PREFIX "rt" 81114402Sru 82114402Srustring block_width_reg(int r, int c); 83114402Srustring block_diversion_name(int r, int c); 84114402Srustring block_height_reg(int r, int c); 85114402Srustring span_width_reg(int start_col, int end_col); 86114402Srustring span_left_numeric_width_reg(int start_col, int end_col); 87114402Srustring span_right_numeric_width_reg(int start_col, int end_col); 88114402Srustring span_alphabetic_width_reg(int start_col, int end_col); 89114402Srustring column_separation_reg(int col); 90114402Srustring row_start_reg(int r); 91114402Srustring column_start_reg(int c); 92114402Srustring column_end_reg(int c); 93114402Srustring column_divide_reg(int c); 94114402Srustring row_top_reg(int r); 95114402Sru 96114402Sruvoid set_inline_modifier(const entry_modifier *); 97114402Sruvoid restore_inline_modifier(const entry_modifier *m); 98114402Sruvoid set_modifier(const entry_modifier *); 99114402Sruint find_decimal_point(const char *s, char decimal_point_char, 100114402Sru const char *delim); 101114402Sru 102114402Srustring an_empty_string; 103114402Sruint location_force_filename = 0; 104114402Sru 105114402Sruvoid printfs(const char *, 106114402Sru const string &arg1 = an_empty_string, 107114402Sru const string &arg2 = an_empty_string, 108114402Sru const string &arg3 = an_empty_string, 109114402Sru const string &arg4 = an_empty_string, 110114402Sru const string &arg5 = an_empty_string); 111114402Sru 112114402Sruvoid prints(const string &); 113114402Sru 114114402Sruinline void prints(char c) 115114402Sru{ 116114402Sru putchar(c); 117114402Sru} 118114402Sru 119114402Sruinline void prints(const char *s) 120114402Sru{ 121114402Sru fputs(s, stdout); 122114402Sru} 123114402Sru 124114402Sruvoid prints(const string &s) 125114402Sru{ 126114402Sru if (!s.empty()) 127114402Sru fwrite(s.contents(), 1, s.length(), stdout); 128114402Sru} 129114402Sru 130114402Srustruct horizontal_span { 131114402Sru horizontal_span *next; 132151497Sru int start_col; 133151497Sru int end_col; 134114402Sru horizontal_span(int, int, horizontal_span *); 135114402Sru}; 136114402Sru 137151497Sruclass single_line_entry; 138151497Sruclass double_line_entry; 139151497Sruclass simple_entry; 140114402Sru 141114402Sruclass table_entry { 142114402Srufriend class table; 143114402Sru table_entry *next; 144114402Sru int input_lineno; 145114402Sru const char *input_filename; 146114402Sruprotected: 147114402Sru int start_row; 148114402Sru int end_row; 149151497Sru int start_col; 150151497Sru int end_col; 151114402Sru const entry_modifier *mod; 152114402Srupublic: 153114402Sru void set_location(); 154114402Sru table_entry(const entry_modifier *); 155114402Sru virtual ~table_entry(); 156114402Sru virtual int divert(int ncols, const string *mw, int *sep); 157114402Sru virtual void do_width(); 158114402Sru virtual void do_depth(); 159114402Sru virtual void print() = 0; 160114402Sru virtual void position_vertically() = 0; 161114402Sru virtual single_line_entry *to_single_line_entry(); 162114402Sru virtual double_line_entry *to_double_line_entry(); 163114402Sru virtual simple_entry *to_simple_entry(); 164114402Sru virtual int line_type(); 165114402Sru virtual void note_double_vrule_on_right(int); 166114402Sru virtual void note_double_vrule_on_left(int); 167114402Sru}; 168114402Sru 169114402Sruclass simple_entry : public table_entry { 170114402Srupublic: 171114402Sru simple_entry(const entry_modifier *); 172114402Sru void print(); 173114402Sru void position_vertically(); 174114402Sru simple_entry *to_simple_entry(); 175114402Sru virtual void add_tab(); 176114402Sru virtual void simple_print(int); 177114402Sru}; 178114402Sru 179114402Sruclass empty_entry : public simple_entry { 180114402Srupublic: 181114402Sru empty_entry(const entry_modifier *); 182114402Sru int line_type(); 183114402Sru}; 184114402Sru 185114402Sruclass text_entry : public simple_entry { 186114402Sruprotected: 187114402Sru char *contents; 188114402Sru void print_contents(); 189114402Srupublic: 190114402Sru text_entry(char *, const entry_modifier *); 191114402Sru ~text_entry(); 192114402Sru}; 193114402Sru 194114402Sruvoid text_entry::print_contents() 195114402Sru{ 196114402Sru set_inline_modifier(mod); 197114402Sru prints(contents); 198114402Sru restore_inline_modifier(mod); 199114402Sru} 200114402Sru 201114402Sruclass repeated_char_entry : public text_entry { 202114402Srupublic: 203114402Sru repeated_char_entry(char *s, const entry_modifier *m); 204114402Sru void simple_print(int); 205114402Sru}; 206114402Sru 207114402Sruclass simple_text_entry : public text_entry { 208114402Srupublic: 209114402Sru simple_text_entry(char *s, const entry_modifier *m); 210114402Sru void do_width(); 211114402Sru}; 212114402Sru 213114402Sruclass left_text_entry : public simple_text_entry { 214114402Srupublic: 215114402Sru left_text_entry(char *s, const entry_modifier *m); 216114402Sru void simple_print(int); 217114402Sru void add_tab(); 218114402Sru}; 219114402Sru 220114402Sruclass right_text_entry : public simple_text_entry { 221114402Srupublic: 222114402Sru right_text_entry(char *s, const entry_modifier *m); 223114402Sru void simple_print(int); 224114402Sru void add_tab(); 225114402Sru}; 226114402Sru 227114402Sruclass center_text_entry : public simple_text_entry { 228114402Srupublic: 229114402Sru center_text_entry(char *s, const entry_modifier *m); 230114402Sru void simple_print(int); 231114402Sru void add_tab(); 232114402Sru}; 233114402Sru 234114402Sruclass numeric_text_entry : public text_entry { 235114402Sru int dot_pos; 236114402Srupublic: 237114402Sru numeric_text_entry(char *s, const entry_modifier *m, int pos); 238114402Sru void do_width(); 239114402Sru void simple_print(int); 240114402Sru}; 241114402Sru 242114402Sruclass alphabetic_text_entry : public text_entry { 243114402Srupublic: 244114402Sru alphabetic_text_entry(char *s, const entry_modifier *m); 245114402Sru void do_width(); 246114402Sru void simple_print(int); 247114402Sru void add_tab(); 248114402Sru}; 249114402Sru 250114402Sruclass line_entry : public simple_entry { 251114402Sruprotected: 252114402Sru char double_vrule_on_right; 253114402Sru char double_vrule_on_left; 254114402Srupublic: 255114402Sru line_entry(const entry_modifier *); 256114402Sru void note_double_vrule_on_right(int); 257114402Sru void note_double_vrule_on_left(int); 258114402Sru void simple_print(int) = 0; 259114402Sru}; 260114402Sru 261114402Sruclass single_line_entry : public line_entry { 262114402Srupublic: 263114402Sru single_line_entry(const entry_modifier *m); 264114402Sru void simple_print(int); 265114402Sru single_line_entry *to_single_line_entry(); 266114402Sru int line_type(); 267114402Sru}; 268114402Sru 269114402Sruclass double_line_entry : public line_entry { 270114402Srupublic: 271114402Sru double_line_entry(const entry_modifier *m); 272114402Sru void simple_print(int); 273114402Sru double_line_entry *to_double_line_entry(); 274114402Sru int line_type(); 275114402Sru}; 276114402Sru 277114402Sruclass short_line_entry : public simple_entry { 278114402Srupublic: 279114402Sru short_line_entry(const entry_modifier *m); 280114402Sru void simple_print(int); 281114402Sru int line_type(); 282114402Sru}; 283114402Sru 284114402Sruclass short_double_line_entry : public simple_entry { 285114402Srupublic: 286114402Sru short_double_line_entry(const entry_modifier *m); 287114402Sru void simple_print(int); 288114402Sru int line_type(); 289114402Sru}; 290114402Sru 291114402Sruclass block_entry : public table_entry { 292114402Sru char *contents; 293114402Sruprotected: 294114402Sru void do_divert(int alphabetic, int ncols, const string *mw, int *sep); 295114402Srupublic: 296114402Sru block_entry(char *s, const entry_modifier *m); 297114402Sru ~block_entry(); 298114402Sru int divert(int ncols, const string *mw, int *sep); 299114402Sru void do_width(); 300114402Sru void do_depth(); 301114402Sru void position_vertically(); 302114402Sru void print() = 0; 303114402Sru}; 304114402Sru 305114402Sruclass left_block_entry : public block_entry { 306114402Srupublic: 307114402Sru left_block_entry(char *s, const entry_modifier *m); 308114402Sru void print(); 309114402Sru}; 310114402Sru 311114402Sruclass right_block_entry : public block_entry { 312114402Srupublic: 313114402Sru right_block_entry(char *s, const entry_modifier *m); 314114402Sru void print(); 315114402Sru}; 316114402Sru 317114402Sruclass center_block_entry : public block_entry { 318114402Srupublic: 319114402Sru center_block_entry(char *s, const entry_modifier *m); 320114402Sru void print(); 321114402Sru}; 322114402Sru 323114402Sruclass alphabetic_block_entry : public block_entry { 324114402Srupublic: 325114402Sru alphabetic_block_entry(char *s, const entry_modifier *m); 326114402Sru void print(); 327114402Sru int divert(int ncols, const string *mw, int *sep); 328114402Sru}; 329114402Sru 330114402Srutable_entry::table_entry(const entry_modifier *m) 331114402Sru: next(0), input_lineno(-1), input_filename(0), 332114402Sru start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m) 333114402Sru{ 334114402Sru} 335114402Sru 336114402Srutable_entry::~table_entry() 337114402Sru{ 338114402Sru} 339114402Sru 340114402Sruint table_entry::divert(int, const string *, int *) 341114402Sru{ 342114402Sru return 0; 343114402Sru} 344114402Sru 345114402Sruvoid table_entry::do_width() 346114402Sru{ 347114402Sru} 348114402Sru 349114402Srusingle_line_entry *table_entry::to_single_line_entry() 350114402Sru{ 351114402Sru return 0; 352114402Sru} 353114402Sru 354114402Srudouble_line_entry *table_entry::to_double_line_entry() 355114402Sru{ 356114402Sru return 0; 357114402Sru} 358114402Sru 359114402Srusimple_entry *table_entry::to_simple_entry() 360114402Sru{ 361114402Sru return 0; 362114402Sru} 363114402Sru 364114402Sruvoid table_entry::do_depth() 365114402Sru{ 366114402Sru} 367114402Sru 368114402Sruvoid table_entry::set_location() 369114402Sru{ 370114402Sru set_troff_location(input_filename, input_lineno); 371114402Sru} 372114402Sru 373114402Sruint table_entry::line_type() 374114402Sru{ 375114402Sru return -1; 376114402Sru} 377114402Sru 378114402Sruvoid table_entry::note_double_vrule_on_right(int) 379114402Sru{ 380114402Sru} 381114402Sru 382114402Sruvoid table_entry::note_double_vrule_on_left(int) 383114402Sru{ 384114402Sru} 385114402Sru 386114402Srusimple_entry::simple_entry(const entry_modifier *m) : table_entry(m) 387114402Sru{ 388114402Sru} 389114402Sru 390114402Sruvoid simple_entry::add_tab() 391114402Sru{ 392114402Sru // do nothing 393114402Sru} 394114402Sru 395114402Sruvoid simple_entry::simple_print(int) 396114402Sru{ 397114402Sru // do nothing 398114402Sru} 399114402Sru 400114402Sruvoid simple_entry::position_vertically() 401114402Sru{ 402114402Sru if (start_row != end_row) 403114402Sru switch (mod->vertical_alignment) { 404114402Sru case entry_modifier::TOP: 405114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); 406114402Sru break; 407114402Sru case entry_modifier::CENTER: 408114402Sru // Peform the motion in two stages so that the center is rounded 409114402Sru // vertically upwards even if net vertical motion is upwards. 410114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); 411114402Sru printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n", 412114402Sru row_start_reg(start_row)); 413114402Sru break; 414114402Sru case entry_modifier::BOTTOM: 415114402Sru printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n", 416114402Sru row_start_reg(start_row)); 417114402Sru break; 418114402Sru default: 419114402Sru assert(0); 420114402Sru } 421114402Sru} 422114402Sru 423114402Sruvoid simple_entry::print() 424114402Sru{ 425114402Sru prints(".ta"); 426114402Sru add_tab(); 427114402Sru prints('\n'); 428114402Sru set_location(); 429114402Sru prints("\\&"); 430114402Sru simple_print(0); 431114402Sru prints('\n'); 432114402Sru} 433114402Sru 434114402Srusimple_entry *simple_entry::to_simple_entry() 435114402Sru{ 436114402Sru return this; 437114402Sru} 438114402Sru 439114402Sruempty_entry::empty_entry(const entry_modifier *m) 440114402Sru: simple_entry(m) 441114402Sru{ 442114402Sru} 443114402Sru 444114402Sruint empty_entry::line_type() 445114402Sru{ 446114402Sru return 0; 447114402Sru} 448114402Sru 449114402Srutext_entry::text_entry(char *s, const entry_modifier *m) 450114402Sru: simple_entry(m), contents(s) 451114402Sru{ 452114402Sru} 453114402Sru 454114402Srutext_entry::~text_entry() 455114402Sru{ 456114402Sru a_delete contents; 457114402Sru} 458114402Sru 459114402Srurepeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m) 460114402Sru: text_entry(s, m) 461114402Sru{ 462114402Sru} 463114402Sru 464114402Sruvoid repeated_char_entry::simple_print(int) 465114402Sru{ 466114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 467114402Sru set_inline_modifier(mod); 468114402Sru printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&", 469114402Sru span_width_reg(start_col, end_col)); 470114402Sru prints(contents); 471114402Sru prints(DELIMITER_CHAR); 472114402Sru restore_inline_modifier(mod); 473114402Sru} 474114402Sru 475114402Srusimple_text_entry::simple_text_entry(char *s, const entry_modifier *m) 476114402Sru: text_entry(s, m) 477114402Sru{ 478114402Sru} 479114402Sru 480114402Sruvoid simple_text_entry::do_width() 481114402Sru{ 482114402Sru set_location(); 483114402Sru printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, 484114402Sru span_width_reg(start_col, end_col)); 485114402Sru print_contents(); 486114402Sru prints(DELIMITER_CHAR "\n"); 487114402Sru} 488114402Sru 489114402Sruleft_text_entry::left_text_entry(char *s, const entry_modifier *m) 490114402Sru: simple_text_entry(s, m) 491114402Sru{ 492114402Sru} 493114402Sru 494114402Sruvoid left_text_entry::simple_print(int) 495114402Sru{ 496114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 497114402Sru print_contents(); 498114402Sru} 499114402Sru 500114402Sru// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. 501114402Sru 502114402Sruvoid left_text_entry::add_tab() 503114402Sru{ 504114402Sru printfs(" \\n[%1]u", column_end_reg(end_col)); 505114402Sru} 506114402Sru 507114402Sruright_text_entry::right_text_entry(char *s, const entry_modifier *m) 508114402Sru: simple_text_entry(s, m) 509114402Sru{ 510114402Sru} 511114402Sru 512114402Sruvoid right_text_entry::simple_print(int) 513114402Sru{ 514114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 515114402Sru prints("\002\003"); 516114402Sru print_contents(); 517114402Sru prints("\002"); 518114402Sru} 519114402Sru 520114402Sruvoid right_text_entry::add_tab() 521114402Sru{ 522114402Sru printfs(" \\n[%1]u", column_end_reg(end_col)); 523114402Sru} 524114402Sru 525114402Srucenter_text_entry::center_text_entry(char *s, const entry_modifier *m) 526114402Sru: simple_text_entry(s, m) 527114402Sru{ 528114402Sru} 529114402Sru 530114402Sruvoid center_text_entry::simple_print(int) 531114402Sru{ 532114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 533114402Sru prints("\002\003"); 534114402Sru print_contents(); 535114402Sru prints("\003\002"); 536114402Sru} 537114402Sru 538114402Sruvoid center_text_entry::add_tab() 539114402Sru{ 540114402Sru printfs(" \\n[%1]u", column_end_reg(end_col)); 541114402Sru} 542114402Sru 543114402Srunumeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos) 544114402Sru: text_entry(s, m), dot_pos(pos) 545114402Sru{ 546114402Sru} 547114402Sru 548114402Sruvoid numeric_text_entry::do_width() 549114402Sru{ 550114402Sru if (dot_pos != 0) { 551114402Sru set_location(); 552114402Sru printfs(".nr %1 0\\w" DELIMITER_CHAR, 553114402Sru block_width_reg(start_row, start_col)); 554114402Sru set_inline_modifier(mod); 555114402Sru for (int i = 0; i < dot_pos; i++) 556114402Sru prints(contents[i]); 557114402Sru restore_inline_modifier(mod); 558114402Sru prints(DELIMITER_CHAR "\n"); 559114402Sru printfs(".nr %1 \\n[%1]>?\\n[%2]\n", 560114402Sru span_left_numeric_width_reg(start_col, end_col), 561114402Sru block_width_reg(start_row, start_col)); 562114402Sru } 563114402Sru else 564114402Sru printfs(".nr %1 0\n", block_width_reg(start_row, start_col)); 565114402Sru if (contents[dot_pos] != '\0') { 566114402Sru set_location(); 567114402Sru printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, 568114402Sru span_right_numeric_width_reg(start_col, end_col)); 569114402Sru set_inline_modifier(mod); 570114402Sru prints(contents + dot_pos); 571114402Sru restore_inline_modifier(mod); 572114402Sru prints(DELIMITER_CHAR "\n"); 573114402Sru } 574114402Sru} 575114402Sru 576114402Sruvoid numeric_text_entry::simple_print(int) 577114402Sru{ 578114402Sru printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'", 579114402Sru span_width_reg(start_col, end_col), 580114402Sru span_left_numeric_width_reg(start_col, end_col), 581114402Sru span_right_numeric_width_reg(start_col, end_col), 582114402Sru column_start_reg(start_col), 583114402Sru block_width_reg(start_row, start_col)); 584114402Sru print_contents(); 585114402Sru} 586114402Sru 587114402Srualphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m) 588114402Sru: text_entry(s, m) 589114402Sru{ 590114402Sru} 591114402Sru 592114402Sruvoid alphabetic_text_entry::do_width() 593114402Sru{ 594114402Sru set_location(); 595114402Sru printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR, 596114402Sru span_alphabetic_width_reg(start_col, end_col)); 597114402Sru print_contents(); 598114402Sru prints(DELIMITER_CHAR "\n"); 599114402Sru} 600114402Sru 601114402Sruvoid alphabetic_text_entry::simple_print(int) 602114402Sru{ 603114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 604114402Sru printfs("\\h'\\n[%1]u-\\n[%2]u/2u'", 605114402Sru span_width_reg(start_col, end_col), 606114402Sru span_alphabetic_width_reg(start_col, end_col)); 607114402Sru print_contents(); 608114402Sru} 609114402Sru 610114402Sru// The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr. 611114402Sru 612114402Sruvoid alphabetic_text_entry::add_tab() 613114402Sru{ 614114402Sru printfs(" \\n[%1]u", column_end_reg(end_col)); 615114402Sru} 616114402Sru 617114402Srublock_entry::block_entry(char *s, const entry_modifier *m) 618114402Sru: table_entry(m), contents(s) 619114402Sru{ 620114402Sru} 621114402Sru 622114402Srublock_entry::~block_entry() 623114402Sru{ 624114402Sru a_delete contents; 625114402Sru} 626114402Sru 627114402Sruvoid block_entry::position_vertically() 628114402Sru{ 629114402Sru if (start_row != end_row) 630114402Sru switch(mod->vertical_alignment) { 631114402Sru case entry_modifier::TOP: 632114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); 633114402Sru break; 634114402Sru case entry_modifier::CENTER: 635114402Sru // Peform the motion in two stages so that the center is rounded 636114402Sru // vertically upwards even if net vertical motion is upwards. 637114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(start_row)); 638114402Sru printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n", 639114402Sru row_start_reg(start_row), 640114402Sru block_height_reg(start_row, start_col)); 641114402Sru break; 642114402Sru case entry_modifier::BOTTOM: 643114402Sru printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n", 644114402Sru row_start_reg(start_row), 645114402Sru block_height_reg(start_row, start_col)); 646114402Sru break; 647114402Sru default: 648114402Sru assert(0); 649114402Sru } 650114402Sru if (mod->stagger) 651114402Sru prints(".sp -.5v\n"); 652114402Sru} 653114402Sru 654114402Sruint block_entry::divert(int ncols, const string *mw, int *sep) 655114402Sru{ 656114402Sru do_divert(0, ncols, mw, sep); 657114402Sru return 1; 658114402Sru} 659114402Sru 660114402Sruvoid block_entry::do_divert(int alphabetic, int ncols, const string *mw, 661114402Sru int *sep) 662114402Sru{ 663114402Sru printfs(".di %1\n", block_diversion_name(start_row, start_col)); 664114402Sru prints(".if \\n[" SAVED_FILL_REG "] .fi\n" 665114402Sru ".in 0\n"); 666114402Sru prints(".ll "); 667114402Sru int i; 668114402Sru for (i = start_col; i <= end_col; i++) 669114402Sru if (mw[i].empty()) 670114402Sru break; 671114402Sru if (i > end_col) { 672114402Sru // Every column spanned by this entry has a minimum width. 673114402Sru for (int j = start_col; j <= end_col; j++) { 674114402Sru if (j > start_col) { 675114402Sru if (sep) 676114402Sru printfs("+%1n", as_string(sep[j - 1])); 677114402Sru prints('+'); 678114402Sru } 679114402Sru printfs("(n;%1)", mw[j]); 680114402Sru } 681114402Sru printfs(">?\\n[%1]u", span_width_reg(start_col, end_col)); 682114402Sru } 683114402Sru else 684114402Sru printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))", 685114402Sru span_width_reg(start_col, end_col), 686114402Sru as_string(end_col - start_col + 1), 687114402Sru as_string(ncols + 1)); 688114402Sru if (alphabetic) 689114402Sru prints("-2n"); 690114402Sru prints("\n"); 691151497Sru prints(".cp \\n(" COMPATIBLE_REG "\n"); 692114402Sru set_modifier(mod); 693114402Sru set_location(); 694114402Sru prints(contents); 695114402Sru prints(".br\n.di\n.cp 0\n"); 696114402Sru if (!mod->zero_width) { 697114402Sru if (alphabetic) { 698114402Sru printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n", 699114402Sru span_width_reg(start_col, end_col)); 700114402Sru printfs(".nr %1 \\n[%1]>?\\n[dl]\n", 701114402Sru span_alphabetic_width_reg(start_col, end_col)); 702114402Sru } 703114402Sru else 704114402Sru printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col)); 705114402Sru } 706114402Sru printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col)); 707114402Sru printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col)); 708114402Sru prints("." RESET_MACRO_NAME "\n" 709114402Sru ".in \\n[" SAVED_INDENT_REG "]u\n" 710114402Sru ".nf\n"); 711114402Sru // the block might have contained .lf commands 712114402Sru location_force_filename = 1; 713114402Sru} 714114402Sru 715114402Sruvoid block_entry::do_width() 716114402Sru{ 717114402Sru // do nothing; the action happens in divert 718114402Sru} 719114402Sru 720114402Sruvoid block_entry::do_depth() 721114402Sru{ 722114402Sru printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n", 723114402Sru row_start_reg(start_row), 724114402Sru block_height_reg(start_row, start_col)); 725114402Sru} 726114402Sru 727114402Sruleft_block_entry::left_block_entry(char *s, const entry_modifier *m) 728114402Sru: block_entry(s, m) 729114402Sru{ 730114402Sru} 731114402Sru 732114402Sruvoid left_block_entry::print() 733114402Sru{ 734114402Sru printfs(".in +\\n[%1]u\n", column_start_reg(start_col)); 735114402Sru printfs(".%1\n", block_diversion_name(start_row, start_col)); 736114402Sru prints(".in\n"); 737114402Sru} 738114402Sru 739114402Sruright_block_entry::right_block_entry(char *s, const entry_modifier *m) 740114402Sru: block_entry(s, m) 741114402Sru{ 742114402Sru} 743114402Sru 744114402Sruvoid right_block_entry::print() 745114402Sru{ 746114402Sru printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n", 747114402Sru column_start_reg(start_col), 748114402Sru span_width_reg(start_col, end_col), 749114402Sru block_width_reg(start_row, start_col)); 750114402Sru printfs(".%1\n", block_diversion_name(start_row, start_col)); 751114402Sru prints(".in\n"); 752114402Sru} 753114402Sru 754114402Srucenter_block_entry::center_block_entry(char *s, const entry_modifier *m) 755114402Sru: block_entry(s, m) 756114402Sru{ 757114402Sru} 758114402Sru 759114402Sruvoid center_block_entry::print() 760114402Sru{ 761114402Sru printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", 762114402Sru column_start_reg(start_col), 763114402Sru span_width_reg(start_col, end_col), 764114402Sru block_width_reg(start_row, start_col)); 765114402Sru printfs(".%1\n", block_diversion_name(start_row, start_col)); 766114402Sru prints(".in\n"); 767114402Sru} 768114402Sru 769114402Srualphabetic_block_entry::alphabetic_block_entry(char *s, 770114402Sru const entry_modifier *m) 771114402Sru: block_entry(s, m) 772114402Sru{ 773114402Sru} 774114402Sru 775114402Sruint alphabetic_block_entry::divert(int ncols, const string *mw, int *sep) 776114402Sru{ 777114402Sru do_divert(1, ncols, mw, sep); 778114402Sru return 1; 779114402Sru} 780114402Sru 781114402Sruvoid alphabetic_block_entry::print() 782114402Sru{ 783114402Sru printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n", 784114402Sru column_start_reg(start_col), 785114402Sru span_width_reg(start_col, end_col), 786114402Sru span_alphabetic_width_reg(start_col, end_col)); 787114402Sru printfs(".%1\n", block_diversion_name(start_row, start_col)); 788114402Sru prints(".in\n"); 789114402Sru} 790114402Sru 791114402Sruline_entry::line_entry(const entry_modifier *m) 792114402Sru: simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0) 793114402Sru{ 794114402Sru} 795114402Sru 796114402Sruvoid line_entry::note_double_vrule_on_right(int is_corner) 797114402Sru{ 798114402Sru double_vrule_on_right = is_corner ? 1 : 2; 799114402Sru} 800114402Sru 801114402Sruvoid line_entry::note_double_vrule_on_left(int is_corner) 802114402Sru{ 803114402Sru double_vrule_on_left = is_corner ? 1 : 2; 804114402Sru} 805114402Sru 806114402Srusingle_line_entry::single_line_entry(const entry_modifier *m) 807114402Sru: line_entry(m) 808114402Sru{ 809114402Sru} 810114402Sru 811114402Sruint single_line_entry::line_type() 812114402Sru{ 813114402Sru return 1; 814114402Sru} 815114402Sru 816114402Sruvoid single_line_entry::simple_print(int dont_move) 817114402Sru{ 818114402Sru printfs("\\h'|\\n[%1]u", 819114402Sru column_divide_reg(start_col)); 820114402Sru if (double_vrule_on_left) { 821114402Sru prints(double_vrule_on_left == 1 ? "-" : "+"); 822114402Sru prints(HALF_DOUBLE_LINE_SEP); 823114402Sru } 824114402Sru prints("'"); 825114402Sru if (!dont_move) 826114402Sru prints("\\v'-" BAR_HEIGHT "'"); 827114402Sru printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u", 828114402Sru column_divide_reg(end_col+1)); 829114402Sru if (double_vrule_on_right) { 830114402Sru prints(double_vrule_on_left == 1 ? "+" : "-"); 831114402Sru prints(HALF_DOUBLE_LINE_SEP); 832114402Sru } 833114402Sru prints("0'\\s0"); 834114402Sru if (!dont_move) 835114402Sru prints("\\v'" BAR_HEIGHT "'"); 836114402Sru} 837114402Sru 838114402Srusingle_line_entry *single_line_entry::to_single_line_entry() 839114402Sru{ 840114402Sru return this; 841114402Sru} 842114402Sru 843114402Srudouble_line_entry::double_line_entry(const entry_modifier *m) 844114402Sru: line_entry(m) 845114402Sru{ 846114402Sru} 847114402Sru 848114402Sruint double_line_entry::line_type() 849114402Sru{ 850114402Sru return 2; 851114402Sru} 852114402Sru 853114402Sruvoid double_line_entry::simple_print(int dont_move) 854114402Sru{ 855114402Sru if (!dont_move) 856114402Sru prints("\\v'-" BAR_HEIGHT "'"); 857114402Sru printfs("\\h'|\\n[%1]u", 858114402Sru column_divide_reg(start_col)); 859114402Sru if (double_vrule_on_left) { 860114402Sru prints(double_vrule_on_left == 1 ? "-" : "+"); 861114402Sru prints(HALF_DOUBLE_LINE_SEP); 862114402Sru } 863114402Sru prints("'"); 864114402Sru printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'" 865114402Sru "\\s[\\n[" LINESIZE_REG "]]" 866114402Sru "\\D'l |\\n[%1]u", 867114402Sru column_divide_reg(end_col+1)); 868114402Sru if (double_vrule_on_right) 869114402Sru prints("-" HALF_DOUBLE_LINE_SEP); 870114402Sru prints(" 0'"); 871114402Sru printfs("\\v'" DOUBLE_LINE_SEP "'" 872114402Sru "\\D'l |\\n[%1]u", 873114402Sru column_divide_reg(start_col)); 874114402Sru if (double_vrule_on_right) { 875114402Sru prints(double_vrule_on_left == 1 ? "+" : "-"); 876114402Sru prints(HALF_DOUBLE_LINE_SEP); 877114402Sru } 878114402Sru prints(" 0'"); 879114402Sru prints("\\s0" 880114402Sru "\\v'-" HALF_DOUBLE_LINE_SEP "'"); 881114402Sru if (!dont_move) 882114402Sru prints("\\v'" BAR_HEIGHT "'"); 883114402Sru} 884114402Sru 885114402Srudouble_line_entry *double_line_entry::to_double_line_entry() 886114402Sru{ 887114402Sru return this; 888114402Sru} 889114402Sru 890114402Srushort_line_entry::short_line_entry(const entry_modifier *m) 891114402Sru: simple_entry(m) 892114402Sru{ 893114402Sru} 894114402Sru 895114402Sruint short_line_entry::line_type() 896114402Sru{ 897114402Sru return 1; 898114402Sru} 899114402Sru 900114402Sruvoid short_line_entry::simple_print(int dont_move) 901114402Sru{ 902114402Sru if (mod->stagger) 903114402Sru prints("\\v'-.5v'"); 904114402Sru if (!dont_move) 905114402Sru prints("\\v'-" BAR_HEIGHT "'"); 906114402Sru printfs("\\h'|\\n[%1]u'", column_start_reg(start_col)); 907114402Sru printfs("\\s[\\n[" LINESIZE_REG "]]" 908114402Sru "\\D'l \\n[%1]u 0'" 909114402Sru "\\s0", 910114402Sru span_width_reg(start_col, end_col)); 911114402Sru if (!dont_move) 912114402Sru prints("\\v'" BAR_HEIGHT "'"); 913114402Sru if (mod->stagger) 914114402Sru prints("\\v'.5v'"); 915114402Sru} 916114402Sru 917114402Srushort_double_line_entry::short_double_line_entry(const entry_modifier *m) 918114402Sru: simple_entry(m) 919114402Sru{ 920114402Sru} 921114402Sru 922114402Sruint short_double_line_entry::line_type() 923114402Sru{ 924114402Sru return 2; 925114402Sru} 926114402Sru 927114402Sruvoid short_double_line_entry::simple_print(int dont_move) 928114402Sru{ 929114402Sru if (mod->stagger) 930114402Sru prints("\\v'-.5v'"); 931114402Sru if (!dont_move) 932114402Sru prints("\\v'-" BAR_HEIGHT "'"); 933114402Sru printfs("\\h'|\\n[%2]u'" 934114402Sru "\\v'-" HALF_DOUBLE_LINE_SEP "'" 935114402Sru "\\s[\\n[" LINESIZE_REG "]]" 936114402Sru "\\D'l \\n[%1]u 0'" 937114402Sru "\\v'" DOUBLE_LINE_SEP "'" 938114402Sru "\\D'l |\\n[%2]u 0'" 939114402Sru "\\s0" 940114402Sru "\\v'-" HALF_DOUBLE_LINE_SEP "'", 941114402Sru span_width_reg(start_col, end_col), 942114402Sru column_start_reg(start_col)); 943114402Sru if (!dont_move) 944114402Sru prints("\\v'" BAR_HEIGHT "'"); 945114402Sru if (mod->stagger) 946114402Sru prints("\\v'.5v'"); 947114402Sru} 948114402Sru 949114402Sruvoid set_modifier(const entry_modifier *m) 950114402Sru{ 951114402Sru if (!m->font.empty()) 952114402Sru printfs(".ft %1\n", m->font); 953114402Sru if (m->point_size.val != 0) { 954114402Sru prints(".ps "); 955114402Sru if (m->point_size.inc > 0) 956114402Sru prints('+'); 957114402Sru else if (m->point_size.inc < 0) 958114402Sru prints('-'); 959114402Sru printfs("%1\n", as_string(m->point_size.val)); 960114402Sru } 961114402Sru if (m->vertical_spacing.val != 0) { 962114402Sru prints(".vs "); 963114402Sru if (m->vertical_spacing.inc > 0) 964114402Sru prints('+'); 965114402Sru else if (m->vertical_spacing.inc < 0) 966114402Sru prints('-'); 967114402Sru printfs("%1\n", as_string(m->vertical_spacing.val)); 968114402Sru } 969151497Sru if (!m->macro.empty()) 970151497Sru printfs(".%1\n", m->macro); 971114402Sru} 972114402Sru 973114402Sruvoid set_inline_modifier(const entry_modifier *m) 974114402Sru{ 975114402Sru if (!m->font.empty()) 976114402Sru printfs("\\f[%1]", m->font); 977114402Sru if (m->point_size.val != 0) { 978114402Sru prints("\\s["); 979114402Sru if (m->point_size.inc > 0) 980114402Sru prints('+'); 981114402Sru else if (m->point_size.inc < 0) 982114402Sru prints('-'); 983114402Sru printfs("%1]", as_string(m->point_size.val)); 984114402Sru } 985114402Sru if (m->stagger) 986114402Sru prints("\\v'-.5v'"); 987114402Sru} 988114402Sru 989114402Sruvoid restore_inline_modifier(const entry_modifier *m) 990114402Sru{ 991114402Sru if (!m->font.empty()) 992114402Sru prints("\\f[\\n[" SAVED_FONT_REG "]]"); 993114402Sru if (m->point_size.val != 0) 994114402Sru prints("\\s[\\n[" SAVED_SIZE_REG "]]"); 995114402Sru if (m->stagger) 996114402Sru prints("\\v'.5v'"); 997114402Sru} 998114402Sru 999114402Srustruct stuff { 1000114402Sru stuff *next; 1001114402Sru int row; // occurs before row `row' 1002114402Sru char printed; // has it been printed? 1003114402Sru 1004114402Sru stuff(int); 1005114402Sru virtual void print(table *) = 0; 1006114402Sru virtual ~stuff(); 1007114402Sru virtual int is_single_line() { return 0; }; 1008114402Sru virtual int is_double_line() { return 0; }; 1009114402Sru}; 1010114402Sru 1011114402Srustuff::stuff(int r) : next(0), row(r), printed(0) 1012114402Sru{ 1013114402Sru} 1014114402Sru 1015114402Srustuff::~stuff() 1016114402Sru{ 1017114402Sru} 1018114402Sru 1019114402Srustruct text_stuff : public stuff { 1020114402Sru string contents; 1021114402Sru const char *filename; 1022114402Sru int lineno; 1023114402Sru 1024114402Sru text_stuff(const string &, int r, const char *fn, int ln); 1025114402Sru ~text_stuff(); 1026114402Sru void print(table *); 1027114402Sru}; 1028114402Sru 1029114402Srutext_stuff::text_stuff(const string &s, int r, const char *fn, int ln) 1030114402Sru: stuff(r), contents(s), filename(fn), lineno(ln) 1031114402Sru{ 1032114402Sru} 1033114402Sru 1034114402Srutext_stuff::~text_stuff() 1035114402Sru{ 1036114402Sru} 1037114402Sru 1038114402Sruvoid text_stuff::print(table *) 1039114402Sru{ 1040114402Sru printed = 1; 1041114402Sru prints(".cp \\n(" COMPATIBLE_REG "\n"); 1042114402Sru set_troff_location(filename, lineno); 1043114402Sru prints(contents); 1044114402Sru prints(".cp 0\n"); 1045114402Sru location_force_filename = 1; // it might have been a .lf command 1046114402Sru} 1047114402Sru 1048114402Srustruct single_hline_stuff : public stuff { 1049114402Sru single_hline_stuff(int r); 1050114402Sru void print(table *); 1051114402Sru int is_single_line(); 1052114402Sru}; 1053114402Sru 1054114402Srusingle_hline_stuff::single_hline_stuff(int r) : stuff(r) 1055114402Sru{ 1056114402Sru} 1057114402Sru 1058114402Sruvoid single_hline_stuff::print(table *tbl) 1059114402Sru{ 1060114402Sru printed = 1; 1061114402Sru tbl->print_single_hline(row); 1062114402Sru} 1063114402Sru 1064114402Sruint single_hline_stuff::is_single_line() 1065114402Sru{ 1066114402Sru return 1; 1067114402Sru} 1068114402Sru 1069114402Srustruct double_hline_stuff : stuff { 1070114402Sru double_hline_stuff(int r); 1071114402Sru void print(table *); 1072114402Sru int is_double_line(); 1073114402Sru}; 1074114402Sru 1075114402Srudouble_hline_stuff::double_hline_stuff(int r) : stuff(r) 1076114402Sru{ 1077114402Sru} 1078114402Sru 1079114402Sruvoid double_hline_stuff::print(table *tbl) 1080114402Sru{ 1081114402Sru printed = 1; 1082114402Sru tbl->print_double_hline(row); 1083114402Sru} 1084114402Sru 1085114402Sruint double_hline_stuff::is_double_line() 1086114402Sru{ 1087114402Sru return 1; 1088114402Sru} 1089114402Sru 1090114402Srustruct vertical_rule { 1091114402Sru vertical_rule *next; 1092114402Sru int start_row; 1093114402Sru int end_row; 1094151497Sru int col; 1095114402Sru char is_double; 1096114402Sru string top_adjust; 1097114402Sru string bot_adjust; 1098114402Sru 1099114402Sru vertical_rule(int sr, int er, int c, int dbl, vertical_rule *); 1100114402Sru ~vertical_rule(); 1101114402Sru void contribute_to_bottom_macro(table *); 1102114402Sru void print(); 1103114402Sru}; 1104114402Sru 1105114402Sruvertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p) 1106114402Sru: next(p), start_row(sr), end_row(er), col(c), is_double(dbl) 1107114402Sru{ 1108114402Sru} 1109114402Sru 1110114402Sruvertical_rule::~vertical_rule() 1111114402Sru{ 1112114402Sru} 1113114402Sru 1114114402Sruvoid vertical_rule::contribute_to_bottom_macro(table *tbl) 1115114402Sru{ 1116114402Sru printfs(".if \\n[" CURRENT_ROW_REG "]>=%1", 1117114402Sru as_string(start_row)); 1118114402Sru if (end_row != tbl->get_nrows() - 1) 1119114402Sru printfs("&(\\n[" CURRENT_ROW_REG "]<%1)", 1120114402Sru as_string(end_row)); 1121114402Sru prints(" \\{"); 1122114402Sru printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n", 1123114402Sru as_string(start_row), 1124114402Sru row_top_reg(start_row)); 1125114402Sru const char *offset_table[3]; 1126114402Sru if (is_double) { 1127114402Sru offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; 1128114402Sru offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; 1129114402Sru offset_table[2] = 0; 1130114402Sru } 1131114402Sru else { 1132114402Sru offset_table[0] = ""; 1133114402Sru offset_table[1] = 0; 1134114402Sru } 1135114402Sru for (const char **offsetp = offset_table; *offsetp; offsetp++) { 1136114402Sru prints(".sp -1\n" 1137114402Sru "\\v'" BODY_DEPTH); 1138114402Sru if (!bot_adjust.empty()) 1139114402Sru printfs("+%1", bot_adjust); 1140114402Sru prints("'"); 1141114402Sru printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v", 1142114402Sru column_divide_reg(col), 1143114402Sru row_top_reg(start_row), 1144114402Sru *offsetp); 1145114402Sru if (!bot_adjust.empty()) 1146114402Sru printfs("-(%1)", bot_adjust); 1147114402Sru // don't perform the top adjustment if the top is actually #T 1148114402Sru if (!top_adjust.empty()) 1149114402Sru printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))", 1150114402Sru top_adjust, 1151114402Sru as_string(start_row)); 1152114402Sru prints("'\\s0\n"); 1153114402Sru } 1154114402Sru prints(".\\}\n"); 1155114402Sru} 1156114402Sru 1157114402Sruvoid vertical_rule::print() 1158114402Sru{ 1159114402Sru printfs("\\*[" TRANSPARENT_STRING_NAME "]" 1160114402Sru ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] " 1161114402Sru ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n", 1162114402Sru as_string(start_row), 1163114402Sru row_top_reg(start_row)); 1164114402Sru const char *offset_table[3]; 1165114402Sru if (is_double) { 1166114402Sru offset_table[0] = "-" HALF_DOUBLE_LINE_SEP; 1167114402Sru offset_table[1] = "+" HALF_DOUBLE_LINE_SEP; 1168114402Sru offset_table[2] = 0; 1169114402Sru } 1170114402Sru else { 1171114402Sru offset_table[0] = ""; 1172114402Sru offset_table[1] = 0; 1173114402Sru } 1174114402Sru for (const char **offsetp = offset_table; *offsetp; offsetp++) { 1175114402Sru prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n" 1176114402Sru "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH); 1177114402Sru if (!bot_adjust.empty()) 1178114402Sru printfs("+%1", bot_adjust); 1179114402Sru prints("'"); 1180114402Sru printfs("\\h'\\n[%1]u%3'" 1181114402Sru "\\s[\\n[" LINESIZE_REG "]]" 1182114402Sru "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v", 1183114402Sru column_divide_reg(col), 1184114402Sru row_top_reg(start_row), 1185114402Sru *offsetp); 1186114402Sru if (!bot_adjust.empty()) 1187114402Sru printfs("-(%1)", bot_adjust); 1188114402Sru // don't perform the top adjustment if the top is actually #T 1189114402Sru if (!top_adjust.empty()) 1190114402Sru printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n[" 1191114402Sru LAST_PASSED_ROW_REG "]))", 1192114402Sru top_adjust, 1193114402Sru as_string(start_row)); 1194114402Sru prints("'" 1195114402Sru "\\s0\n"); 1196114402Sru } 1197114402Sru} 1198114402Sru 1199114402Srutable::table(int nc, unsigned f, int ls, char dpc) 1200114402Sru: flags(f), nrows(0), ncolumns(nc), linesize(ls), decimal_point_char(dpc), 1201114402Sru vrule_list(0), stuff_list(0), span_list(0), 1202114402Sru entry_list(0), entry_list_tailp(&entry_list), entry(0), 1203114402Sru vline(0), row_is_all_lines(0), left_separation(0), right_separation(0), 1204114402Sru allocated_rows(0) 1205114402Sru{ 1206114402Sru minimum_width = new string[ncolumns]; 1207114402Sru column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0; 1208114402Sru equal = new char[ncolumns]; 1209114402Sru int i; 1210114402Sru for (i = 0; i < ncolumns; i++) 1211114402Sru equal[i] = 0; 1212114402Sru for (i = 0; i < ncolumns-1; i++) 1213114402Sru column_separation[i] = DEFAULT_COLUMN_SEPARATION; 1214114402Sru delim[0] = delim[1] = '\0'; 1215114402Sru} 1216114402Sru 1217114402Srutable::~table() 1218114402Sru{ 1219114402Sru for (int i = 0; i < nrows; i++) { 1220114402Sru a_delete entry[i]; 1221114402Sru a_delete vline[i]; 1222114402Sru } 1223114402Sru a_delete entry; 1224114402Sru a_delete vline; 1225114402Sru while (entry_list) { 1226114402Sru table_entry *tem = entry_list; 1227114402Sru entry_list = entry_list->next; 1228114402Sru delete tem; 1229114402Sru } 1230114402Sru ad_delete(ncolumns) minimum_width; 1231114402Sru a_delete column_separation; 1232114402Sru a_delete equal; 1233114402Sru while (stuff_list) { 1234114402Sru stuff *tem = stuff_list; 1235114402Sru stuff_list = stuff_list->next; 1236114402Sru delete tem; 1237114402Sru } 1238114402Sru while (vrule_list) { 1239114402Sru vertical_rule *tem = vrule_list; 1240114402Sru vrule_list = vrule_list->next; 1241114402Sru delete tem; 1242114402Sru } 1243114402Sru a_delete row_is_all_lines; 1244114402Sru while (span_list) { 1245114402Sru horizontal_span *tem = span_list; 1246114402Sru span_list = span_list->next; 1247114402Sru delete tem; 1248114402Sru } 1249114402Sru} 1250114402Sru 1251114402Sruvoid table::set_delim(char c1, char c2) 1252114402Sru{ 1253114402Sru delim[0] = c1; 1254114402Sru delim[1] = c2; 1255114402Sru} 1256114402Sru 1257114402Sruvoid table::set_minimum_width(int c, const string &w) 1258114402Sru{ 1259114402Sru assert(c >= 0 && c < ncolumns); 1260114402Sru minimum_width[c] = w; 1261114402Sru} 1262114402Sru 1263114402Sruvoid table::set_column_separation(int c, int n) 1264114402Sru{ 1265114402Sru assert(c >= 0 && c < ncolumns - 1); 1266114402Sru column_separation[c] = n; 1267114402Sru} 1268114402Sru 1269114402Sruvoid table::set_equal_column(int c) 1270114402Sru{ 1271114402Sru assert(c >= 0 && c < ncolumns); 1272114402Sru equal[c] = 1; 1273114402Sru} 1274114402Sru 1275114402Sruvoid table::add_stuff(stuff *p) 1276114402Sru{ 1277114402Sru stuff **pp; 1278114402Sru for (pp = &stuff_list; *pp; pp = &(*pp)->next) 1279114402Sru ; 1280114402Sru *pp = p; 1281114402Sru} 1282114402Sru 1283114402Sruvoid table::add_text_line(int r, const string &s, const char *filename, int lineno) 1284114402Sru{ 1285114402Sru add_stuff(new text_stuff(s, r, filename, lineno)); 1286114402Sru} 1287114402Sru 1288114402Sruvoid table::add_single_hline(int r) 1289114402Sru{ 1290114402Sru add_stuff(new single_hline_stuff(r)); 1291114402Sru} 1292114402Sru 1293114402Sruvoid table::add_double_hline(int r) 1294114402Sru{ 1295114402Sru add_stuff(new double_hline_stuff(r)); 1296114402Sru} 1297114402Sru 1298114402Sruvoid table::allocate(int r) 1299114402Sru{ 1300114402Sru if (r >= nrows) { 1301114402Sru typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug 1302114402Sru if (r >= allocated_rows) { 1303114402Sru if (allocated_rows == 0) { 1304114402Sru allocated_rows = 16; 1305114402Sru if (allocated_rows <= r) 1306114402Sru allocated_rows = r + 1; 1307114402Sru entry = new PPtable_entry[allocated_rows]; 1308114402Sru vline = new char*[allocated_rows]; 1309114402Sru } 1310114402Sru else { 1311114402Sru table_entry ***old_entry = entry; 1312114402Sru int old_allocated_rows = allocated_rows; 1313114402Sru allocated_rows *= 2; 1314114402Sru if (allocated_rows <= r) 1315114402Sru allocated_rows = r + 1; 1316114402Sru entry = new PPtable_entry[allocated_rows]; 1317114402Sru memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows); 1318114402Sru a_delete old_entry; 1319114402Sru char **old_vline = vline; 1320114402Sru vline = new char*[allocated_rows]; 1321114402Sru memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows); 1322114402Sru a_delete old_vline; 1323114402Sru } 1324114402Sru } 1325114402Sru assert(allocated_rows > r); 1326114402Sru while (nrows <= r) { 1327114402Sru entry[nrows] = new table_entry*[ncolumns]; 1328114402Sru int i; 1329114402Sru for (i = 0; i < ncolumns; i++) 1330114402Sru entry[nrows][i] = 0; 1331114402Sru vline[nrows] = new char[ncolumns+1]; 1332114402Sru for (i = 0; i < ncolumns+1; i++) 1333114402Sru vline[nrows][i] = 0; 1334114402Sru nrows++; 1335114402Sru } 1336114402Sru } 1337114402Sru} 1338114402Sru 1339114402Sruvoid table::do_hspan(int r, int c) 1340114402Sru{ 1341114402Sru assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); 1342114402Sru if (c == 0) { 1343114402Sru error("first column cannot be horizontally spanned"); 1344114402Sru return; 1345114402Sru } 1346114402Sru table_entry *e = entry[r][c]; 1347114402Sru if (e) { 1348114402Sru assert(e->start_row <= r && r <= e->end_row 1349114402Sru && e->start_col <= c && c <= e->end_col 1350114402Sru && e->end_row - e->start_row > 0 1351114402Sru && e->end_col - e->start_col > 0); 1352114402Sru return; 1353114402Sru } 1354114402Sru e = entry[r][c-1]; 1355114402Sru // e can be 0 if we had an empty entry or an error 1356114402Sru if (e == 0) 1357114402Sru return; 1358114402Sru if (e->start_row != r) { 1359114402Sru /* 1360114402Sru l l 1361114402Sru ^ s */ 1362114402Sru error("impossible horizontal span at row %1, column %2", r + 1, c + 1); 1363114402Sru } 1364114402Sru else { 1365114402Sru e->end_col = c; 1366114402Sru entry[r][c] = e; 1367114402Sru } 1368114402Sru} 1369114402Sru 1370114402Sruvoid table::do_vspan(int r, int c) 1371114402Sru{ 1372114402Sru assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns); 1373114402Sru if (r == 0) { 1374114402Sru error("first row cannot be vertically spanned"); 1375114402Sru return; 1376114402Sru } 1377114402Sru table_entry *e = entry[r][c]; 1378114402Sru if (e) { 1379114402Sru assert(e->start_row <= r && r <= e->end_row 1380114402Sru && e->start_col <= c && c <= e->end_col 1381114402Sru && e->end_row - e->start_row > 0 1382114402Sru && e->end_col - e->start_col > 0); 1383114402Sru return; 1384114402Sru } 1385114402Sru e = entry[r-1][c]; 1386114402Sru // e can be 0 if we had an empty entry or an error 1387114402Sru if (e == 0) 1388114402Sru return; 1389114402Sru if (e->start_col != c) { 1390114402Sru /* l s 1391114402Sru l ^ */ 1392114402Sru error("impossible vertical span at row %1, column %2", r + 1, c + 1); 1393114402Sru } 1394114402Sru else { 1395114402Sru for (int i = c; i <= e->end_col; i++) { 1396114402Sru assert(entry[r][i] == 0); 1397114402Sru entry[r][i] = e; 1398114402Sru } 1399114402Sru e->end_row = r; 1400114402Sru } 1401114402Sru} 1402114402Sru 1403114402Sruint find_decimal_point(const char *s, char decimal_point_char, 1404114402Sru const char *delim) 1405114402Sru{ 1406114402Sru if (s == 0 || *s == '\0') 1407114402Sru return -1; 1408114402Sru const char *p; 1409114402Sru int in_delim = 0; // is p within eqn delimiters? 1410114402Sru // tbl recognises \& even within eqn delimiters; I don't 1411114402Sru for (p = s; *p; p++) 1412114402Sru if (in_delim) { 1413114402Sru if (*p == delim[1]) 1414114402Sru in_delim = 0; 1415114402Sru } 1416114402Sru else if (*p == delim[0]) 1417114402Sru in_delim = 1; 1418114402Sru else if (p[0] == '\\' && p[1] == '&') 1419114402Sru return p - s; 1420114402Sru int possible_pos = -1; 1421114402Sru in_delim = 0; 1422114402Sru for (p = s; *p; p++) 1423114402Sru if (in_delim) { 1424114402Sru if (*p == delim[1]) 1425114402Sru in_delim = 0; 1426114402Sru } 1427114402Sru else if (*p == delim[0]) 1428114402Sru in_delim = 1; 1429114402Sru else if (p[0] == decimal_point_char && csdigit(p[1])) 1430114402Sru possible_pos = p - s; 1431114402Sru if (possible_pos >= 0) 1432114402Sru return possible_pos; 1433114402Sru in_delim = 0; 1434114402Sru for (p = s; *p; p++) 1435114402Sru if (in_delim) { 1436114402Sru if (*p == delim[1]) 1437114402Sru in_delim = 0; 1438114402Sru } 1439114402Sru else if (*p == delim[0]) 1440114402Sru in_delim = 1; 1441114402Sru else if (csdigit(*p)) 1442114402Sru possible_pos = p + 1 - s; 1443114402Sru return possible_pos; 1444114402Sru} 1445114402Sru 1446114402Sruvoid table::add_entry(int r, int c, const string &str, const entry_format *f, 1447114402Sru const char *fn, int ln) 1448114402Sru{ 1449114402Sru allocate(r); 1450114402Sru table_entry *e = 0; 1451114402Sru if (str == "\\_") { 1452114402Sru e = new short_line_entry(f); 1453114402Sru } 1454114402Sru else if (str == "\\=") { 1455114402Sru e = new short_double_line_entry(f); 1456114402Sru } 1457114402Sru else if (str == "_") { 1458114402Sru single_line_entry *lefte; 1459114402Sru if (c > 0 && entry[r][c-1] != 0 && 1460114402Sru (lefte = entry[r][c-1]->to_single_line_entry()) != 0 1461114402Sru && lefte->start_row == r 1462114402Sru && lefte->mod->stagger == f->stagger) { 1463114402Sru lefte->end_col = c; 1464114402Sru entry[r][c] = lefte; 1465114402Sru } 1466114402Sru else 1467114402Sru e = new single_line_entry(f); 1468114402Sru } 1469114402Sru else if (str == "=") { 1470114402Sru double_line_entry *lefte; 1471114402Sru if (c > 0 && entry[r][c-1] != 0 && 1472114402Sru (lefte = entry[r][c-1]->to_double_line_entry()) != 0 1473114402Sru && lefte->start_row == r 1474114402Sru && lefte->mod->stagger == f->stagger) { 1475114402Sru lefte->end_col = c; 1476114402Sru entry[r][c] = lefte; 1477114402Sru } 1478114402Sru else 1479114402Sru e = new double_line_entry(f); 1480114402Sru } 1481114402Sru else if (str == "\\^") { 1482114402Sru do_vspan(r, c); 1483114402Sru } 1484114402Sru else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') { 1485114402Sru if (str.search('\n') >= 0) 1486114402Sru error_with_file_and_line(fn, ln, "bad repeated character"); 1487114402Sru else { 1488114402Sru char *s = str.substring(2, str.length() - 2).extract(); 1489114402Sru e = new repeated_char_entry(s, f); 1490114402Sru } 1491114402Sru } 1492114402Sru else { 1493114402Sru int is_block = str.search('\n') >= 0; 1494114402Sru char *s; 1495114402Sru switch (f->type) { 1496114402Sru case FORMAT_SPAN: 1497114402Sru assert(str.empty()); 1498114402Sru do_hspan(r, c); 1499114402Sru break; 1500114402Sru case FORMAT_LEFT: 1501114402Sru if (!str.empty()) { 1502114402Sru s = str.extract(); 1503114402Sru if (is_block) 1504114402Sru e = new left_block_entry(s, f); 1505114402Sru else 1506114402Sru e = new left_text_entry(s, f); 1507114402Sru } 1508114402Sru else 1509114402Sru e = new empty_entry(f); 1510114402Sru break; 1511114402Sru case FORMAT_CENTER: 1512114402Sru if (!str.empty()) { 1513114402Sru s = str.extract(); 1514114402Sru if (is_block) 1515114402Sru e = new center_block_entry(s, f); 1516114402Sru else 1517114402Sru e = new center_text_entry(s, f); 1518114402Sru } 1519114402Sru else 1520114402Sru e = new empty_entry(f); 1521114402Sru break; 1522114402Sru case FORMAT_RIGHT: 1523114402Sru if (!str.empty()) { 1524114402Sru s = str.extract(); 1525114402Sru if (is_block) 1526114402Sru e = new right_block_entry(s, f); 1527114402Sru else 1528114402Sru e = new right_text_entry(s, f); 1529114402Sru } 1530114402Sru else 1531114402Sru e = new empty_entry(f); 1532114402Sru break; 1533114402Sru case FORMAT_NUMERIC: 1534114402Sru if (!str.empty()) { 1535114402Sru s = str.extract(); 1536114402Sru if (is_block) { 1537114402Sru error_with_file_and_line(fn, ln, "can't have numeric text block"); 1538114402Sru e = new left_block_entry(s, f); 1539114402Sru } 1540114402Sru else { 1541114402Sru int pos = find_decimal_point(s, decimal_point_char, delim); 1542114402Sru if (pos < 0) 1543114402Sru e = new center_text_entry(s, f); 1544114402Sru else 1545114402Sru e = new numeric_text_entry(s, f, pos); 1546114402Sru } 1547114402Sru } 1548114402Sru else 1549114402Sru e = new empty_entry(f); 1550114402Sru break; 1551114402Sru case FORMAT_ALPHABETIC: 1552114402Sru if (!str.empty()) { 1553114402Sru s = str.extract(); 1554114402Sru if (is_block) 1555114402Sru e = new alphabetic_block_entry(s, f); 1556114402Sru else 1557114402Sru e = new alphabetic_text_entry(s, f); 1558114402Sru } 1559114402Sru else 1560114402Sru e = new empty_entry(f); 1561114402Sru break; 1562114402Sru case FORMAT_VSPAN: 1563114402Sru do_vspan(r, c); 1564114402Sru break; 1565114402Sru case FORMAT_HLINE: 1566114402Sru if (str.length() != 0) 1567114402Sru error_with_file_and_line(fn, ln, 1568114402Sru "non-empty data entry for `_' format ignored"); 1569114402Sru e = new single_line_entry(f); 1570114402Sru break; 1571114402Sru case FORMAT_DOUBLE_HLINE: 1572114402Sru if (str.length() != 0) 1573114402Sru error_with_file_and_line(fn, ln, 1574114402Sru "non-empty data entry for `=' format ignored"); 1575114402Sru e = new double_line_entry(f); 1576114402Sru break; 1577114402Sru default: 1578114402Sru assert(0); 1579114402Sru } 1580114402Sru } 1581114402Sru if (e) { 1582114402Sru table_entry *preve = entry[r][c]; 1583114402Sru if (preve) { 1584114402Sru /* c s 1585114402Sru ^ l */ 1586114402Sru error_with_file_and_line(fn, ln, "row %1, column %2 already spanned", 1587114402Sru r + 1, c + 1); 1588114402Sru delete e; 1589114402Sru } 1590114402Sru else { 1591114402Sru e->input_lineno = ln; 1592114402Sru e->input_filename = fn; 1593114402Sru e->start_row = e->end_row = r; 1594114402Sru e->start_col = e->end_col = c; 1595114402Sru *entry_list_tailp = e; 1596114402Sru entry_list_tailp = &e->next; 1597114402Sru entry[r][c] = e; 1598114402Sru } 1599114402Sru } 1600114402Sru} 1601114402Sru 1602114402Sru// add vertical lines for row r 1603114402Sru 1604114402Sruvoid table::add_vlines(int r, const char *v) 1605114402Sru{ 1606114402Sru allocate(r); 1607114402Sru for (int i = 0; i < ncolumns+1; i++) 1608114402Sru vline[r][i] = v[i]; 1609114402Sru} 1610114402Sru 1611114402Sruvoid table::check() 1612114402Sru{ 1613114402Sru table_entry *p = entry_list; 1614114402Sru int i, j; 1615114402Sru while (p) { 1616114402Sru for (i = p->start_row; i <= p->end_row; i++) 1617114402Sru for (j = p->start_col; j <= p->end_col; j++) 1618114402Sru assert(entry[i][j] == p); 1619114402Sru p = p->next; 1620114402Sru } 1621114402Sru} 1622114402Sru 1623114402Sruvoid table::print() 1624114402Sru{ 1625114402Sru location_force_filename = 1; 1626114402Sru check(); 1627114402Sru init_output(); 1628114402Sru determine_row_type(); 1629114402Sru compute_widths(); 1630114402Sru if (!(flags & CENTER)) 1631114402Sru prints(".if \\n[" SAVED_CENTER_REG "] \\{"); 1632114402Sru prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2>?-\\n[.i])\n" 1633114402Sru ".nr " SAVED_INDENT_REG " \\n[.i]\n"); 1634114402Sru if (!(flags & CENTER)) 1635114402Sru prints(".\\}\n"); 1636114402Sru build_vrule_list(); 1637114402Sru define_bottom_macro(); 1638114402Sru do_top(); 1639114402Sru for (int i = 0; i < nrows; i++) 1640114402Sru do_row(i); 1641114402Sru do_bottom(); 1642114402Sru} 1643114402Sru 1644114402Sruvoid table::determine_row_type() 1645114402Sru{ 1646114402Sru row_is_all_lines = new char[nrows]; 1647114402Sru for (int i = 0; i < nrows; i++) { 1648114402Sru int had_single = 0; 1649114402Sru int had_double = 0; 1650114402Sru int had_non_line = 0; 1651114402Sru for (int c = 0; c < ncolumns; c++) { 1652114402Sru table_entry *e = entry[i][c]; 1653114402Sru if (e != 0) { 1654114402Sru if (e->start_row == e->end_row) { 1655114402Sru int t = e->line_type(); 1656114402Sru switch (t) { 1657114402Sru case -1: 1658114402Sru had_non_line = 1; 1659114402Sru break; 1660114402Sru case 0: 1661114402Sru // empty 1662114402Sru break; 1663114402Sru case 1: 1664114402Sru had_single = 1; 1665114402Sru break; 1666114402Sru case 2: 1667114402Sru had_double = 1; 1668114402Sru break; 1669114402Sru default: 1670114402Sru assert(0); 1671114402Sru } 1672114402Sru if (had_non_line) 1673114402Sru break; 1674114402Sru } 1675114402Sru c = e->end_col; 1676114402Sru } 1677114402Sru } 1678114402Sru if (had_non_line) 1679114402Sru row_is_all_lines[i] = 0; 1680114402Sru else if (had_double) 1681114402Sru row_is_all_lines[i] = 2; 1682114402Sru else if (had_single) 1683114402Sru row_is_all_lines[i] = 1; 1684114402Sru else 1685114402Sru row_is_all_lines[i] = 0; 1686114402Sru } 1687114402Sru} 1688114402Sru 1689114402Sruvoid table::init_output() 1690114402Sru{ 1691114402Sru prints(".nr " COMPATIBLE_REG " \\n(.C\n" 1692114402Sru ".cp 0\n"); 1693114402Sru if (linesize > 0) 1694114402Sru printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize)); 1695114402Sru else 1696114402Sru prints(".nr " LINESIZE_REG " \\n[.s]\n"); 1697114402Sru if (!(flags & CENTER)) 1698114402Sru prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n"); 1699151497Sru if (compatible_flag) 1700151497Sru prints(".ds " LEADER_REG " \\a\n"); 1701114402Sru prints(".de " RESET_MACRO_NAME "\n" 1702114402Sru ".ft \\n[.f]\n" 1703114402Sru ".ps \\n[.s]\n" 1704114402Sru ".vs \\n[.v]u\n" 1705114402Sru ".in \\n[.i]u\n" 1706114402Sru ".ll \\n[.l]u\n" 1707114402Sru ".ls \\n[.L]\n" 1708114402Sru ".ad \\n[.j]\n" 1709114402Sru ".ie \\n[.u] .fi\n" 1710114402Sru ".el .nf\n" 1711114402Sru ".ce \\n[.ce]\n" 1712114402Sru "..\n" 1713114402Sru ".nr " SAVED_INDENT_REG " \\n[.i]\n" 1714114402Sru ".nr " SAVED_FONT_REG " \\n[.f]\n" 1715114402Sru ".nr " SAVED_SIZE_REG " \\n[.s]\n" 1716114402Sru ".nr " SAVED_FILL_REG " \\n[.u]\n" 1717114402Sru ".nr T. 0\n" 1718114402Sru ".nr " CURRENT_ROW_REG " 0-1\n" 1719114402Sru ".nr " LAST_PASSED_ROW_REG " 0-1\n" 1720114402Sru ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" 1721114402Sru ".ds " TRANSPARENT_STRING_NAME "\n" 1722114402Sru ".ds " QUOTE_STRING_NAME "\n" 1723114402Sru ".nr " NEED_BOTTOM_RULE_REG " 1\n" 1724114402Sru ".nr " SUPPRESS_BOTTOM_REG " 0\n" 1725114402Sru ".eo\n" 1726114402Sru ".de " REPEATED_MARK_MACRO "\n" 1727114402Sru ".mk \\$1\n" 1728114402Sru ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n" 1729114402Sru "..\n" 1730114402Sru ".de " REPEATED_VPT_MACRO "\n" 1731114402Sru ".vpt \\$1\n" 1732114402Sru ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n" 1733114402Sru "..\n"); 1734114402Sru if (!(flags & NOKEEP)) 1735114402Sru prints(".de " KEEP_MACRO_NAME "\n" 1736114402Sru ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n" 1737114402Sru ".ds " TRANSPARENT_STRING_NAME " \\!\n" 1738114402Sru ".di " SECTION_DIVERSION_NAME "\n" 1739114402Sru ".nr " SECTION_DIVERSION_FLAG_REG " 1\n" 1740114402Sru ".in 0\n" 1741114402Sru ".\\}\n" 1742114402Sru "..\n" 1743114402Sru ".de " RELEASE_MACRO_NAME "\n" 1744114402Sru ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{" 1745114402Sru ".di\n" 1746114402Sru ".in \\n[" SAVED_INDENT_REG "]u\n" 1747114402Sru ".nr " SAVED_DN_REG " \\n[dn]\n" 1748114402Sru ".ds " QUOTE_STRING_NAME "\n" 1749114402Sru ".ds " TRANSPARENT_STRING_NAME "\n" 1750114402Sru ".nr " SECTION_DIVERSION_FLAG_REG " 0\n" 1751114402Sru ".if \\n[.t]<=\\n[dn] \\{" 1752114402Sru ".nr T. 1\n" 1753114402Sru ".T#\n" 1754114402Sru ".nr " SUPPRESS_BOTTOM_REG " 1\n" 1755114402Sru ".sp \\n[.t]u\n" 1756114402Sru ".nr " SUPPRESS_BOTTOM_REG " 0\n" 1757114402Sru ".mk #T\n" 1758114402Sru ".\\}\n" 1759114402Sru ".if \\n[.t]<=\\n[" SAVED_DN_REG "] " 1760114402Sru /* Since we turn off traps, it won't get into an infinite loop 1761114402Sru when we try and print it; it will just go off the bottom of the 1762114402Sru page. */ 1763114402Sru ".tm warning: page \\n%: table text block will not fit on one page\n" 1764114402Sru ".nf\n" 1765114402Sru ".ls 1\n" 1766114402Sru "." SECTION_DIVERSION_NAME "\n" 1767114402Sru ".ls\n" 1768114402Sru ".rm " SECTION_DIVERSION_NAME "\n" 1769114402Sru ".\\}\n" 1770114402Sru "..\n" 1771114402Sru ".nr " TABLE_DIVERSION_FLAG_REG " 0\n" 1772114402Sru ".de " TABLE_KEEP_MACRO_NAME "\n" 1773114402Sru ".if '\\n[.z]'' \\{" 1774114402Sru ".di " TABLE_DIVERSION_NAME "\n" 1775114402Sru ".nr " TABLE_DIVERSION_FLAG_REG " 1\n" 1776114402Sru ".\\}\n" 1777114402Sru "..\n" 1778114402Sru ".de " TABLE_RELEASE_MACRO_NAME "\n" 1779114402Sru ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n" 1780114402Sru ".di\n" 1781114402Sru ".nr " SAVED_DN_REG " \\n[dn]\n" 1782114402Sru ".ne \\n[dn]u+\\n[.V]u\n" 1783114402Sru ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] " 1784114402Sru ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n" 1785114402Sru ".el \\{" 1786114402Sru ".in 0\n" 1787114402Sru ".ls 1\n" 1788114402Sru ".nf\n" 1789114402Sru "." TABLE_DIVERSION_NAME "\n" 1790114402Sru ".\\}\n" 1791114402Sru ".rm " TABLE_DIVERSION_NAME "\n" 1792114402Sru ".\\}\n" 1793114402Sru "..\n"); 1794114402Sru prints(".ec\n" 1795114402Sru ".ce 0\n" 1796114402Sru ".nf\n"); 1797114402Sru} 1798114402Sru 1799114402Srustring block_width_reg(int r, int c) 1800114402Sru{ 1801114402Sru static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1802114402Sru sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c); 1803114402Sru return string(name); 1804114402Sru} 1805114402Sru 1806114402Srustring block_diversion_name(int r, int c) 1807114402Sru{ 1808114402Sru static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1809114402Sru sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c); 1810114402Sru return string(name); 1811114402Sru} 1812114402Sru 1813114402Srustring block_height_reg(int r, int c) 1814114402Sru{ 1815114402Sru static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1816114402Sru sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c); 1817114402Sru return string(name); 1818114402Sru} 1819114402Sru 1820114402Srustring span_width_reg(int start_col, int end_col) 1821114402Sru{ 1822114402Sru static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1823114402Sru sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col); 1824114402Sru if (end_col != start_col) 1825114402Sru sprintf(strchr(name, '\0'), ",%d", end_col); 1826114402Sru return string(name); 1827114402Sru} 1828114402Sru 1829114402Srustring span_left_numeric_width_reg(int start_col, int end_col) 1830114402Sru{ 1831114402Sru static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1832114402Sru sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col); 1833114402Sru if (end_col != start_col) 1834114402Sru sprintf(strchr(name, '\0'), ",%d", end_col); 1835114402Sru return string(name); 1836114402Sru} 1837114402Sru 1838114402Srustring span_right_numeric_width_reg(int start_col, int end_col) 1839114402Sru{ 1840114402Sru static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1841114402Sru sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col); 1842114402Sru if (end_col != start_col) 1843114402Sru sprintf(strchr(name, '\0'), ",%d", end_col); 1844114402Sru return string(name); 1845114402Sru} 1846114402Sru 1847114402Srustring span_alphabetic_width_reg(int start_col, int end_col) 1848114402Sru{ 1849114402Sru static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS]; 1850114402Sru sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col); 1851114402Sru if (end_col != start_col) 1852114402Sru sprintf(strchr(name, '\0'), ",%d", end_col); 1853114402Sru return string(name); 1854114402Sru} 1855114402Sru 1856114402Srustring column_separation_reg(int col) 1857114402Sru{ 1858114402Sru static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS]; 1859114402Sru sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col); 1860114402Sru return string(name); 1861114402Sru} 1862114402Sru 1863114402Srustring row_start_reg(int row) 1864114402Sru{ 1865114402Sru static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS]; 1866114402Sru sprintf(name, ROW_START_PREFIX "%d", row); 1867114402Sru return string(name); 1868114402Sru} 1869114402Sru 1870114402Srustring column_start_reg(int col) 1871114402Sru{ 1872114402Sru static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS]; 1873114402Sru sprintf(name, COLUMN_START_PREFIX "%d", col); 1874114402Sru return string(name); 1875114402Sru} 1876114402Sru 1877114402Srustring column_end_reg(int col) 1878114402Sru{ 1879114402Sru static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS]; 1880114402Sru sprintf(name, COLUMN_END_PREFIX "%d", col); 1881114402Sru return string(name); 1882114402Sru} 1883114402Sru 1884114402Srustring column_divide_reg(int col) 1885114402Sru{ 1886114402Sru static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS]; 1887114402Sru sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col); 1888114402Sru return string(name); 1889114402Sru} 1890114402Sru 1891114402Srustring row_top_reg(int row) 1892114402Sru{ 1893114402Sru static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS]; 1894114402Sru sprintf(name, ROW_TOP_PREFIX "%d", row); 1895114402Sru return string(name); 1896114402Sru} 1897114402Sru 1898114402Sruvoid init_span_reg(int start_col, int end_col) 1899114402Sru{ 1900114402Sru printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n", 1901114402Sru span_width_reg(start_col, end_col), 1902114402Sru span_alphabetic_width_reg(start_col, end_col), 1903114402Sru span_left_numeric_width_reg(start_col, end_col), 1904114402Sru span_right_numeric_width_reg(start_col, end_col)); 1905114402Sru} 1906114402Sru 1907114402Sruvoid compute_span_width(int start_col, int end_col) 1908114402Sru{ 1909114402Sru printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n" 1910114402Sru ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n", 1911114402Sru span_width_reg(start_col, end_col), 1912114402Sru span_left_numeric_width_reg(start_col, end_col), 1913114402Sru span_right_numeric_width_reg(start_col, end_col), 1914114402Sru span_alphabetic_width_reg(start_col, end_col)); 1915114402Sru} 1916114402Sru 1917114402Sru// Increase the widths of columns so that the width of any spanning entry 1918114402Sru// is not greater than the sum of the widths of the columns that it spans. 1919114402Sru// Ensure that the widths of columns remain equal. 1920114402Sru 1921114402Sruvoid table::divide_span(int start_col, int end_col) 1922114402Sru{ 1923114402Sru assert(end_col > start_col); 1924114402Sru printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]", 1925114402Sru span_width_reg(start_col, end_col), 1926114402Sru span_width_reg(start_col, start_col)); 1927114402Sru int i; 1928114402Sru for (i = start_col + 1; i <= end_col; i++) { 1929114402Sru // The column separation may shrink with the expand option. 1930114402Sru if (!(flags & EXPAND)) 1931114402Sru printfs("+%1n", as_string(column_separation[i - 1])); 1932114402Sru printfs("+\\n[%1]", span_width_reg(i, i)); 1933114402Sru } 1934114402Sru prints(")\n"); 1935114402Sru printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n", 1936114402Sru as_string(end_col - start_col + 1)); 1937114402Sru prints(".if \\n[" NEEDED_REG "] \\{"); 1938114402Sru for (i = start_col; i <= end_col; i++) 1939114402Sru printfs(".nr %1 +\\n[" NEEDED_REG "]\n", 1940114402Sru span_width_reg(i, i)); 1941114402Sru int equal_flag = 0; 1942114402Sru for (i = start_col; i <= end_col && !equal_flag; i++) 1943114402Sru if (equal[i]) 1944114402Sru equal_flag = 1; 1945114402Sru if (equal_flag) { 1946114402Sru for (i = 0; i < ncolumns; i++) 1947114402Sru if (i < start_col || i > end_col) 1948114402Sru printfs(".nr %1 +\\n[" NEEDED_REG "]\n", 1949114402Sru span_width_reg(i, i)); 1950114402Sru } 1951114402Sru prints(".\\}\n"); 1952114402Sru} 1953114402Sru 1954114402Sruvoid table::sum_columns(int start_col, int end_col) 1955114402Sru{ 1956114402Sru assert(end_col > start_col); 1957114402Sru printfs(".nr %1 \\n[%2]", 1958114402Sru span_width_reg(start_col, end_col), 1959114402Sru span_width_reg(start_col, start_col)); 1960114402Sru for (int i = start_col + 1; i <= end_col; i++) 1961114402Sru printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]", 1962114402Sru as_string(column_separation[i - 1]), 1963114402Sru span_width_reg(i, i)); 1964114402Sru prints('\n'); 1965114402Sru} 1966114402Sru 1967114402Sruhorizontal_span::horizontal_span(int sc, int ec, horizontal_span *p) 1968114402Sru: next(p), start_col(sc), end_col(ec) 1969114402Sru{ 1970114402Sru} 1971114402Sru 1972114402Sruvoid table::build_span_list() 1973114402Sru{ 1974114402Sru span_list = 0; 1975114402Sru table_entry *p = entry_list; 1976114402Sru while (p) { 1977114402Sru if (p->end_col != p->start_col) { 1978114402Sru horizontal_span *q; 1979114402Sru for (q = span_list; q; q = q->next) 1980114402Sru if (q->start_col == p->start_col 1981114402Sru && q->end_col == p->end_col) 1982114402Sru break; 1983114402Sru if (!q) 1984114402Sru span_list = new horizontal_span(p->start_col, p->end_col, span_list); 1985114402Sru } 1986114402Sru p = p->next; 1987114402Sru } 1988114402Sru // Now sort span_list primarily by order of end_row, and secondarily 1989114402Sru // by reverse order of start_row. This ensures that if we divide 1990114402Sru // spans using the order in span_list, we will get reasonable results. 1991114402Sru horizontal_span *unsorted = span_list; 1992114402Sru span_list = 0; 1993114402Sru while (unsorted) { 1994114402Sru horizontal_span **pp; 1995114402Sru for (pp = &span_list; *pp; pp = &(*pp)->next) 1996114402Sru if (unsorted->end_col < (*pp)->end_col 1997114402Sru || (unsorted->end_col == (*pp)->end_col 1998114402Sru && (unsorted->start_col > (*pp)->start_col))) 1999114402Sru break; 2000114402Sru horizontal_span *tem = unsorted->next; 2001114402Sru unsorted->next = *pp; 2002114402Sru *pp = unsorted; 2003114402Sru unsorted = tem; 2004114402Sru } 2005114402Sru} 2006114402Sru 2007114402Sruvoid table::compute_separation_factor() 2008114402Sru{ 2009114402Sru if (flags & (ALLBOX|BOX|DOUBLEBOX)) 2010114402Sru left_separation = right_separation = 1; 2011114402Sru else { 2012114402Sru for (int i = 0; i < nrows; i++) { 2013114402Sru if (vline[i][0] > 0) 2014114402Sru left_separation = 1; 2015114402Sru if (vline[i][ncolumns] > 0) 2016114402Sru right_separation = 1; 2017114402Sru } 2018114402Sru } 2019114402Sru if (flags & EXPAND) { 2020114402Sru int total_sep = left_separation + right_separation; 2021114402Sru int i; 2022114402Sru for (i = 0; i < ncolumns - 1; i++) 2023114402Sru total_sep += column_separation[i]; 2024114402Sru if (total_sep != 0) { 2025114402Sru // Don't let the separation factor be negative. 2026114402Sru prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]"); 2027114402Sru for (i = 0; i < ncolumns; i++) 2028114402Sru printfs("-\\n[%1]", span_width_reg(i, i)); 2029114402Sru printfs("/%1>?0\n", as_string(total_sep)); 2030114402Sru } 2031114402Sru } 2032114402Sru} 2033114402Sru 2034114402Sruvoid table::compute_column_positions() 2035114402Sru{ 2036114402Sru printfs(".nr %1 0\n", column_divide_reg(0)); 2037114402Sru printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n", 2038114402Sru column_start_reg(0), 2039114402Sru as_string(left_separation)); 2040114402Sru int i; 2041114402Sru for (i = 1;; i++) { 2042114402Sru printfs(".nr %1 \\n[%2]+\\n[%3]\n", 2043114402Sru column_end_reg(i-1), 2044114402Sru column_start_reg(i-1), 2045114402Sru span_width_reg(i-1, i-1)); 2046114402Sru if (i >= ncolumns) 2047114402Sru break; 2048114402Sru printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", 2049114402Sru column_start_reg(i), 2050114402Sru column_end_reg(i-1), 2051114402Sru as_string(column_separation[i-1])); 2052114402Sru printfs(".nr %1 \\n[%2]+\\n[%3]/2\n", 2053114402Sru column_divide_reg(i), 2054114402Sru column_end_reg(i-1), 2055114402Sru column_start_reg(i)); 2056114402Sru } 2057114402Sru printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n", 2058114402Sru column_divide_reg(ncolumns), 2059114402Sru column_end_reg(i-1), 2060114402Sru as_string(right_separation)); 2061114402Sru printfs(".nr TW \\n[%1]\n", 2062114402Sru column_divide_reg(ncolumns)); 2063114402Sru if (flags & DOUBLEBOX) { 2064114402Sru printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0)); 2065114402Sru printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns)); 2066114402Sru } 2067114402Sru} 2068114402Sru 2069114402Sruvoid table::make_columns_equal() 2070114402Sru{ 2071114402Sru int first = -1; // index of first equal column 2072114402Sru int i; 2073114402Sru for (i = 0; i < ncolumns; i++) 2074114402Sru if (equal[i]) { 2075114402Sru if (first < 0) { 2076114402Sru printfs(".nr %1 \\n[%1]", span_width_reg(i, i)); 2077114402Sru first = i; 2078114402Sru } 2079114402Sru else 2080114402Sru printfs(">?\\n[%1]", span_width_reg(i, i)); 2081114402Sru } 2082114402Sru if (first >= 0) { 2083114402Sru prints('\n'); 2084114402Sru for (i = first + 1; i < ncolumns; i++) 2085114402Sru if (equal[i]) 2086114402Sru printfs(".nr %1 \\n[%2]\n", 2087114402Sru span_width_reg(i, i), 2088114402Sru span_width_reg(first, first)); 2089114402Sru } 2090114402Sru} 2091114402Sru 2092114402Sruvoid table::compute_widths() 2093114402Sru{ 2094114402Sru build_span_list(); 2095114402Sru int i; 2096114402Sru horizontal_span *p; 2097114402Sru prints(".nr " SEPARATION_FACTOR_REG " 1n\n"); 2098114402Sru for (i = 0; i < ncolumns; i++) { 2099114402Sru init_span_reg(i, i); 2100114402Sru if (!minimum_width[i].empty()) 2101114402Sru printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]); 2102114402Sru } 2103114402Sru for (p = span_list; p; p = p->next) 2104114402Sru init_span_reg(p->start_col, p->end_col); 2105114402Sru table_entry *q; 2106114402Sru for (q = entry_list; q; q = q->next) 2107114402Sru if (!q->mod->zero_width) 2108114402Sru q->do_width(); 2109114402Sru for (i = 0; i < ncolumns; i++) 2110114402Sru compute_span_width(i, i); 2111114402Sru for (p = span_list; p; p = p->next) 2112114402Sru compute_span_width(p->start_col, p->end_col); 2113114402Sru make_columns_equal(); 2114114402Sru // Note that divide_span keeps equal width columns equal. 2115114402Sru for (p = span_list; p; p = p->next) 2116114402Sru divide_span(p->start_col, p->end_col); 2117114402Sru for (p = span_list; p; p = p->next) 2118114402Sru sum_columns(p->start_col, p->end_col); 2119114402Sru int had_spanning_block = 0; 2120114402Sru int had_equal_block = 0; 2121114402Sru for (q = entry_list; q; q = q->next) 2122114402Sru if (q->divert(ncolumns, minimum_width, 2123114402Sru (flags & EXPAND) ? column_separation : 0)) { 2124114402Sru if (q->end_col > q->start_col) 2125114402Sru had_spanning_block = 1; 2126114402Sru for (i = q->start_col; i <= q->end_col && !had_equal_block; i++) 2127114402Sru if (equal[i]) 2128114402Sru had_equal_block = 1; 2129114402Sru } 2130114402Sru if (had_equal_block) 2131114402Sru make_columns_equal(); 2132114402Sru if (had_spanning_block) 2133114402Sru for (p = span_list; p; p = p->next) 2134114402Sru divide_span(p->start_col, p->end_col); 2135114402Sru compute_separation_factor(); 2136114402Sru for (p = span_list; p; p = p->next) 2137114402Sru sum_columns(p->start_col, p->end_col); 2138114402Sru compute_column_positions(); 2139114402Sru} 2140114402Sru 2141114402Sruvoid table::print_single_hline(int r) 2142114402Sru{ 2143114402Sru prints(".vs " LINE_SEP ">?\\n[.V]u\n" 2144114402Sru ".ls 1\n" 2145114402Sru "\\v'" BODY_DEPTH "'" 2146114402Sru "\\s[\\n[" LINESIZE_REG "]]"); 2147114402Sru if (r > nrows - 1) 2148114402Sru prints("\\D'l |\\n[TW]u 0'"); 2149114402Sru else { 2150114402Sru int start_col = 0; 2151114402Sru for (;;) { 2152114402Sru while (start_col < ncolumns 2153114402Sru && entry[r][start_col] != 0 2154114402Sru && entry[r][start_col]->start_row != r) 2155114402Sru start_col++; 2156114402Sru int end_col; 2157114402Sru for (end_col = start_col; 2158114402Sru end_col < ncolumns 2159114402Sru && (entry[r][end_col] == 0 2160114402Sru || entry[r][end_col]->start_row == r); 2161114402Sru end_col++) 2162114402Sru ; 2163114402Sru if (end_col <= start_col) 2164114402Sru break; 2165114402Sru printfs("\\h'|\\n[%1]u", 2166114402Sru column_divide_reg(start_col)); 2167114402Sru if ((r > 0 && vline[r-1][start_col] == 2) 2168114402Sru || (r < nrows && vline[r][start_col] == 2)) 2169114402Sru prints("-" HALF_DOUBLE_LINE_SEP); 2170114402Sru prints("'"); 2171114402Sru printfs("\\D'l |\\n[%1]u", 2172114402Sru column_divide_reg(end_col)); 2173114402Sru if ((r > 0 && vline[r-1][end_col] == 2) 2174114402Sru || (r < nrows && vline[r][end_col] == 2)) 2175114402Sru prints("+" HALF_DOUBLE_LINE_SEP); 2176114402Sru prints(" 0'"); 2177114402Sru start_col = end_col; 2178114402Sru } 2179114402Sru } 2180114402Sru prints("\\s0\n"); 2181114402Sru prints(".ls\n" 2182114402Sru ".vs\n"); 2183114402Sru} 2184114402Sru 2185114402Sruvoid table::print_double_hline(int r) 2186114402Sru{ 2187114402Sru prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP 2188114402Sru ">?\\n[.V]u\n" 2189114402Sru ".ls 1\n" 2190114402Sru "\\v'" BODY_DEPTH "'" 2191114402Sru "\\s[\\n[" LINESIZE_REG "]]"); 2192114402Sru if (r > nrows - 1) 2193114402Sru prints("\\v'-" DOUBLE_LINE_SEP "'" 2194114402Sru "\\D'l |\\n[TW]u 0'" 2195114402Sru "\\v'" DOUBLE_LINE_SEP "'" 2196114402Sru "\\h'|0'" 2197114402Sru "\\D'l |\\n[TW]u 0'"); 2198114402Sru else { 2199114402Sru int start_col = 0; 2200114402Sru for (;;) { 2201114402Sru while (start_col < ncolumns 2202114402Sru && entry[r][start_col] != 0 2203114402Sru && entry[r][start_col]->start_row != r) 2204114402Sru start_col++; 2205114402Sru int end_col; 2206114402Sru for (end_col = start_col; 2207114402Sru end_col < ncolumns 2208114402Sru && (entry[r][end_col] == 0 2209114402Sru || entry[r][end_col]->start_row == r); 2210114402Sru end_col++) 2211114402Sru ; 2212114402Sru if (end_col <= start_col) 2213114402Sru break; 2214114402Sru const char *left_adjust = 0; 2215114402Sru if ((r > 0 && vline[r-1][start_col] == 2) 2216114402Sru || (r < nrows && vline[r][start_col] == 2)) 2217114402Sru left_adjust = "-" HALF_DOUBLE_LINE_SEP; 2218114402Sru const char *right_adjust = 0; 2219114402Sru if ((r > 0 && vline[r-1][end_col] == 2) 2220114402Sru || (r < nrows && vline[r][end_col] == 2)) 2221114402Sru right_adjust = "+" HALF_DOUBLE_LINE_SEP; 2222114402Sru printfs("\\v'-" DOUBLE_LINE_SEP "'" 2223114402Sru "\\h'|\\n[%1]u", 2224114402Sru column_divide_reg(start_col)); 2225114402Sru if (left_adjust) 2226114402Sru prints(left_adjust); 2227114402Sru prints("'"); 2228114402Sru printfs("\\D'l |\\n[%1]u", 2229114402Sru column_divide_reg(end_col)); 2230114402Sru if (right_adjust) 2231114402Sru prints(right_adjust); 2232114402Sru prints(" 0'"); 2233114402Sru printfs("\\v'" DOUBLE_LINE_SEP "'" 2234114402Sru "\\h'|\\n[%1]u", 2235114402Sru column_divide_reg(start_col)); 2236114402Sru if (left_adjust) 2237114402Sru prints(left_adjust); 2238114402Sru prints("'"); 2239114402Sru printfs("\\D'l |\\n[%1]u", 2240114402Sru column_divide_reg(end_col)); 2241114402Sru if (right_adjust) 2242114402Sru prints(right_adjust); 2243114402Sru prints(" 0'"); 2244114402Sru start_col = end_col; 2245114402Sru } 2246114402Sru } 2247114402Sru prints("\\s0\n" 2248114402Sru ".ls\n" 2249114402Sru ".vs\n"); 2250114402Sru} 2251114402Sru 2252114402Sruvoid table::compute_vrule_top_adjust(int start_row, int col, string &result) 2253114402Sru{ 2254114402Sru if (row_is_all_lines[start_row] && start_row < nrows - 1) { 2255114402Sru if (row_is_all_lines[start_row] == 2) 2256114402Sru result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP; 2257114402Sru else 2258114402Sru result = LINE_SEP ">?\\n[.V]u"; 2259114402Sru start_row++; 2260114402Sru } 2261114402Sru else { 2262114402Sru result = ""; 2263114402Sru if (start_row == 0) 2264114402Sru return; 2265114402Sru for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next) 2266114402Sru if (p->row == start_row 2267114402Sru && (p->is_single_line() || p->is_double_line())) 2268114402Sru return; 2269114402Sru } 2270114402Sru int left = 0; 2271114402Sru if (col > 0) { 2272114402Sru table_entry *e = entry[start_row-1][col-1]; 2273114402Sru if (e && e->start_row == e->end_row) { 2274114402Sru if (e->to_double_line_entry() != 0) 2275114402Sru left = 2; 2276114402Sru else if (e->to_single_line_entry() != 0) 2277114402Sru left = 1; 2278114402Sru } 2279114402Sru } 2280114402Sru int right = 0; 2281114402Sru if (col < ncolumns) { 2282114402Sru table_entry *e = entry[start_row-1][col]; 2283114402Sru if (e && e->start_row == e->end_row) { 2284114402Sru if (e->to_double_line_entry() != 0) 2285114402Sru right = 2; 2286114402Sru else if (e->to_single_line_entry() != 0) 2287114402Sru right = 1; 2288114402Sru } 2289114402Sru } 2290114402Sru if (row_is_all_lines[start_row-1] == 0) { 2291114402Sru if (left > 0 || right > 0) { 2292114402Sru result += "-" BODY_DEPTH "-" BAR_HEIGHT; 2293114402Sru if ((left == 2 && right != 2) || (right == 2 && left != 2)) 2294114402Sru result += "-" HALF_DOUBLE_LINE_SEP; 2295114402Sru else if (left == 2 && right == 2) 2296114402Sru result += "+" HALF_DOUBLE_LINE_SEP; 2297114402Sru } 2298114402Sru } 2299114402Sru else if (row_is_all_lines[start_row-1] == 2) { 2300114402Sru if ((left == 2 && right != 2) || (right == 2 && left != 2)) 2301114402Sru result += "-" DOUBLE_LINE_SEP; 2302114402Sru else if (left == 1 || right == 1) 2303114402Sru result += "-" HALF_DOUBLE_LINE_SEP; 2304114402Sru } 2305114402Sru} 2306114402Sru 2307114402Sruvoid table::compute_vrule_bot_adjust(int end_row, int col, string &result) 2308114402Sru{ 2309114402Sru if (row_is_all_lines[end_row] && end_row > 0) { 2310114402Sru end_row--; 2311114402Sru result = ""; 2312114402Sru } 2313114402Sru else { 2314114402Sru stuff *p; 2315114402Sru for (p = stuff_list; p && p->row < end_row + 1; p = p->next) 2316114402Sru ; 2317114402Sru if (p && p->row == end_row + 1 && p->is_double_line()) { 2318114402Sru result = "-" DOUBLE_LINE_SEP; 2319114402Sru return; 2320114402Sru } 2321114402Sru if ((p != 0 && p->row == end_row + 1) 2322114402Sru || end_row == nrows - 1) { 2323114402Sru result = ""; 2324114402Sru return; 2325114402Sru } 2326114402Sru if (row_is_all_lines[end_row+1] == 1) 2327114402Sru result = LINE_SEP; 2328114402Sru else if (row_is_all_lines[end_row+1] == 2) 2329114402Sru result = LINE_SEP "+" DOUBLE_LINE_SEP; 2330114402Sru else 2331114402Sru result = ""; 2332114402Sru } 2333114402Sru int left = 0; 2334114402Sru if (col > 0) { 2335114402Sru table_entry *e = entry[end_row+1][col-1]; 2336114402Sru if (e && e->start_row == e->end_row) { 2337114402Sru if (e->to_double_line_entry() != 0) 2338114402Sru left = 2; 2339114402Sru else if (e->to_single_line_entry() != 0) 2340114402Sru left = 1; 2341114402Sru } 2342114402Sru } 2343114402Sru int right = 0; 2344114402Sru if (col < ncolumns) { 2345114402Sru table_entry *e = entry[end_row+1][col]; 2346114402Sru if (e && e->start_row == e->end_row) { 2347114402Sru if (e->to_double_line_entry() != 0) 2348114402Sru right = 2; 2349114402Sru else if (e->to_single_line_entry() != 0) 2350114402Sru right = 1; 2351114402Sru } 2352114402Sru } 2353114402Sru if (row_is_all_lines[end_row+1] == 0) { 2354114402Sru if (left > 0 || right > 0) { 2355114402Sru result = "1v-" BODY_DEPTH "-" BAR_HEIGHT; 2356114402Sru if ((left == 2 && right != 2) || (right == 2 && left != 2)) 2357114402Sru result += "+" HALF_DOUBLE_LINE_SEP; 2358114402Sru else if (left == 2 && right == 2) 2359114402Sru result += "-" HALF_DOUBLE_LINE_SEP; 2360114402Sru } 2361114402Sru } 2362114402Sru else if (row_is_all_lines[end_row+1] == 2) { 2363114402Sru if (left == 2 && right == 2) 2364114402Sru result += "-" DOUBLE_LINE_SEP; 2365114402Sru else if (left != 2 && right != 2 && (left == 1 || right == 1)) 2366114402Sru result += "-" HALF_DOUBLE_LINE_SEP; 2367114402Sru } 2368114402Sru} 2369114402Sru 2370114402Sruvoid table::add_vertical_rule(int start_row, int end_row, int col, int is_double) 2371114402Sru{ 2372114402Sru vrule_list = new vertical_rule(start_row, end_row, col, is_double, 2373114402Sru vrule_list); 2374114402Sru compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust); 2375114402Sru compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust); 2376114402Sru} 2377114402Sru 2378114402Sruvoid table::build_vrule_list() 2379114402Sru{ 2380114402Sru int col; 2381114402Sru if (flags & ALLBOX) { 2382114402Sru for (col = 1; col < ncolumns; col++) { 2383114402Sru int start_row = 0; 2384114402Sru for (;;) { 2385114402Sru while (start_row < nrows && vline_spanned(start_row, col)) 2386114402Sru start_row++; 2387114402Sru if (start_row >= nrows) 2388114402Sru break; 2389114402Sru int end_row = start_row; 2390114402Sru while (end_row < nrows && !vline_spanned(end_row, col)) 2391114402Sru end_row++; 2392114402Sru end_row--; 2393114402Sru add_vertical_rule(start_row, end_row, col, 0); 2394114402Sru start_row = end_row + 1; 2395114402Sru } 2396114402Sru } 2397114402Sru } 2398114402Sru if (flags & (BOX|ALLBOX|DOUBLEBOX)) { 2399114402Sru add_vertical_rule(0, nrows - 1, 0, 0); 2400114402Sru add_vertical_rule(0, nrows - 1, ncolumns, 0); 2401114402Sru } 2402114402Sru for (int end_row = 0; end_row < nrows; end_row++) 2403114402Sru for (col = 0; col < ncolumns+1; col++) 2404114402Sru if (vline[end_row][col] > 0 2405114402Sru && !vline_spanned(end_row, col) 2406114402Sru && (end_row == nrows - 1 2407114402Sru || vline[end_row+1][col] != vline[end_row][col] 2408114402Sru || vline_spanned(end_row+1, col))) { 2409114402Sru int start_row; 2410114402Sru for (start_row = end_row - 1; 2411114402Sru start_row >= 0 2412114402Sru && vline[start_row][col] == vline[end_row][col] 2413114402Sru && !vline_spanned(start_row, col); 2414114402Sru start_row--) 2415114402Sru ; 2416114402Sru start_row++; 2417114402Sru add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1); 2418114402Sru } 2419114402Sru for (vertical_rule *p = vrule_list; p; p = p->next) 2420114402Sru if (p->is_double) 2421114402Sru for (int r = p->start_row; r <= p->end_row; r++) { 2422114402Sru if (p->col > 0 && entry[r][p->col-1] != 0 2423114402Sru && entry[r][p->col-1]->end_col == p->col-1) { 2424114402Sru int is_corner = r == p->start_row || r == p->end_row; 2425114402Sru entry[r][p->col-1]->note_double_vrule_on_right(is_corner); 2426114402Sru } 2427114402Sru if (p->col < ncolumns && entry[r][p->col] != 0 2428114402Sru && entry[r][p->col]->start_col == p->col) { 2429114402Sru int is_corner = r == p->start_row || r == p->end_row; 2430114402Sru entry[r][p->col]->note_double_vrule_on_left(is_corner); 2431114402Sru } 2432114402Sru } 2433114402Sru} 2434114402Sru 2435114402Sruvoid table::define_bottom_macro() 2436114402Sru{ 2437114402Sru prints(".eo\n" 2438114402Sru ".de T#\n" 2439114402Sru ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{" 2440114402Sru "." REPEATED_VPT_MACRO " 0\n" 2441114402Sru ".mk " SAVED_VERTICAL_POS_REG "\n"); 2442114402Sru if (flags & (BOX|ALLBOX|DOUBLEBOX)) { 2443114402Sru prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{"); 2444114402Sru print_single_hline(0); 2445114402Sru prints(".\\}\n"); 2446114402Sru } 2447114402Sru prints(".ls 1\n"); 2448114402Sru for (vertical_rule *p = vrule_list; p; p = p->next) 2449114402Sru p->contribute_to_bottom_macro(this); 2450114402Sru if (flags & DOUBLEBOX) 2451114402Sru prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n" 2452114402Sru "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" 2453114402Sru "\\D'l \\n[TW]u 0'\\s0\n" 2454114402Sru ".vs\n" 2455114402Sru ".\\}\n" 2456114402Sru ".if \\n[" LAST_PASSED_ROW_REG "]>=0 " 2457114402Sru ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n" 2458114402Sru ".sp -1\n" 2459114402Sru "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]" 2460114402Sru "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n" 2461114402Sru ".sp -1\n" 2462114402Sru "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]" 2463114402Sru "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"); 2464114402Sru prints(".ls\n"); 2465114402Sru prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n" 2466114402Sru ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n" 2467114402Sru "." REPEATED_VPT_MACRO " 1\n" 2468114402Sru ".\\}\n" 2469114402Sru "..\n" 2470114402Sru ".ec\n"); 2471114402Sru} 2472114402Sru 2473114402Sru// is the vertical line before column c in row r horizontally spanned? 2474114402Sru 2475114402Sruint table::vline_spanned(int r, int c) 2476114402Sru{ 2477114402Sru assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1); 2478114402Sru return (c != 0 && c != ncolumns && entry[r][c] != 0 2479114402Sru && entry[r][c]->start_col != c 2480114402Sru // horizontally spanning lines don't count 2481114402Sru && entry[r][c]->to_double_line_entry() == 0 2482114402Sru && entry[r][c]->to_single_line_entry() == 0); 2483114402Sru} 2484114402Sru 2485114402Sruint table::row_begins_section(int r) 2486114402Sru{ 2487114402Sru assert(r >= 0 && r < nrows); 2488114402Sru for (int i = 0; i < ncolumns; i++) 2489114402Sru if (entry[r][i] && entry[r][i]->start_row != r) 2490114402Sru return 0; 2491114402Sru return 1; 2492114402Sru} 2493114402Sru 2494114402Sruint table::row_ends_section(int r) 2495114402Sru{ 2496114402Sru assert(r >= 0 && r < nrows); 2497114402Sru for (int i = 0; i < ncolumns; i++) 2498114402Sru if (entry[r][i] && entry[r][i]->end_row != r) 2499114402Sru return 0; 2500114402Sru return 1; 2501114402Sru} 2502114402Sru 2503114402Sruvoid table::do_row(int r) 2504114402Sru{ 2505114402Sru if (!(flags & NOKEEP) && row_begins_section(r)) 2506114402Sru prints("." KEEP_MACRO_NAME "\n"); 2507114402Sru int had_line = 0; 2508114402Sru stuff *p; 2509114402Sru for (p = stuff_list; p && p->row < r; p = p->next) 2510114402Sru ; 2511114402Sru for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next) 2512114402Sru if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) { 2513114402Sru had_line = 1; 2514114402Sru break; 2515114402Sru } 2516114402Sru if (!had_line && !row_is_all_lines[r]) 2517114402Sru printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); 2518114402Sru had_line = 0; 2519114402Sru for (; p && p->row == r; p = p->next) 2520114402Sru if (!p->printed) { 2521114402Sru p->print(this); 2522114402Sru if (!had_line && (p->is_single_line() || p->is_double_line())) { 2523114402Sru printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); 2524114402Sru had_line = 1; 2525114402Sru } 2526114402Sru } 2527114402Sru // Change the row *after* printing the stuff list (which might contain .TH). 2528114402Sru printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n", 2529114402Sru as_string(r)); 2530114402Sru if (!had_line && row_is_all_lines[r]) 2531114402Sru printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r)); 2532114402Sru // we might have had a .TH, for example, since we last tried 2533114402Sru if (!(flags & NOKEEP) && row_begins_section(r)) 2534114402Sru prints("." KEEP_MACRO_NAME "\n"); 2535114402Sru printfs(".mk %1\n", row_start_reg(r)); 2536114402Sru prints(".mk " BOTTOM_REG "\n" 2537114402Sru "." REPEATED_VPT_MACRO " 0\n"); 2538114402Sru int c; 2539114402Sru int row_is_blank = 1; 2540114402Sru int first_start_row = r; 2541114402Sru for (c = 0; c < ncolumns; c++) { 2542114402Sru table_entry *e = entry[r][c]; 2543114402Sru if (e) { 2544114402Sru if (e->end_row == r) { 2545114402Sru e->do_depth(); 2546114402Sru if (e->start_row < first_start_row) 2547114402Sru first_start_row = e->start_row; 2548114402Sru row_is_blank = 0; 2549114402Sru } 2550114402Sru c = e->end_col; 2551114402Sru } 2552114402Sru } 2553114402Sru if (row_is_blank) 2554114402Sru prints(".nr " BOTTOM_REG " +1v\n"); 2555114402Sru if (row_is_all_lines[r]) { 2556114402Sru prints(".vs " LINE_SEP); 2557114402Sru if (row_is_all_lines[r] == 2) 2558114402Sru prints("+" DOUBLE_LINE_SEP); 2559114402Sru prints(">?\\n[.V]u\n.ls 1\n"); 2560114402Sru prints("\\&"); 2561114402Sru prints("\\v'" BODY_DEPTH); 2562114402Sru if (row_is_all_lines[r] == 2) 2563114402Sru prints("-" HALF_DOUBLE_LINE_SEP); 2564114402Sru prints("'"); 2565114402Sru for (c = 0; c < ncolumns; c++) { 2566114402Sru table_entry *e = entry[r][c]; 2567114402Sru if (e) { 2568114402Sru if (e->end_row == e->start_row) 2569114402Sru e->to_simple_entry()->simple_print(1); 2570114402Sru c = e->end_col; 2571114402Sru } 2572114402Sru } 2573114402Sru prints("\n"); 2574114402Sru prints(".ls\n" 2575114402Sru ".vs\n"); 2576114402Sru prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); 2577114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(r)); 2578114402Sru } 2579114402Sru for (int i = row_is_all_lines[r] ? r - 1 : r; 2580114402Sru i >= first_start_row; 2581114402Sru i--) { 2582114402Sru simple_entry *first = 0; 2583114402Sru for (c = 0; c < ncolumns; c++) { 2584114402Sru table_entry *e = entry[r][c]; 2585114402Sru if (e) { 2586114402Sru if (e->end_row == r && e->start_row == i) { 2587114402Sru simple_entry *simple = e->to_simple_entry(); 2588114402Sru if (simple) { 2589114402Sru if (!first) { 2590114402Sru prints(".ta"); 2591114402Sru first = simple; 2592114402Sru } 2593114402Sru simple->add_tab(); 2594114402Sru } 2595114402Sru } 2596114402Sru c = e->end_col; 2597114402Sru } 2598114402Sru } 2599114402Sru if (first) { 2600114402Sru prints('\n'); 2601114402Sru first->position_vertically(); 2602114402Sru first->set_location(); 2603114402Sru prints("\\&"); 2604114402Sru first->simple_print(0); 2605114402Sru for (c = first->end_col + 1; c < ncolumns; c++) { 2606114402Sru table_entry *e = entry[r][c]; 2607114402Sru if (e) { 2608114402Sru if (e->end_row == r && e->start_row == i) { 2609114402Sru simple_entry *simple = e->to_simple_entry(); 2610151497Sru if (simple) { 2611151497Sru if (e->end_row != e->start_row) { 2612151497Sru prints('\n'); 2613151497Sru simple->position_vertically(); 2614151497Sru prints("\\&"); 2615151497Sru } 2616114402Sru simple->simple_print(0); 2617151497Sru } 2618114402Sru } 2619114402Sru c = e->end_col; 2620114402Sru } 2621114402Sru } 2622114402Sru prints('\n'); 2623114402Sru prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); 2624114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(r)); 2625114402Sru } 2626114402Sru } 2627114402Sru for (c = 0; c < ncolumns; c++) { 2628114402Sru table_entry *e = entry[r][c]; 2629114402Sru if (e) { 2630114402Sru if (e->end_row == r && e->to_simple_entry() == 0) { 2631114402Sru e->position_vertically(); 2632114402Sru e->print(); 2633114402Sru prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n"); 2634114402Sru printfs(".sp |\\n[%1]u\n", row_start_reg(r)); 2635114402Sru } 2636114402Sru c = e->end_col; 2637114402Sru } 2638114402Sru } 2639114402Sru prints("." REPEATED_VPT_MACRO " 1\n" 2640114402Sru ".sp |\\n[" BOTTOM_REG "]u\n" 2641114402Sru "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n"); 2642114402Sru if (r != nrows - 1 && (flags & ALLBOX)) { 2643114402Sru print_single_hline(r + 1); 2644114402Sru prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n"); 2645114402Sru } 2646114402Sru if (r != nrows - 1) { 2647114402Sru if (p && p->row == r + 1 2648114402Sru && (p->is_single_line() || p->is_double_line())) { 2649114402Sru p->print(this); 2650114402Sru prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG 2651114402Sru " 0\n"); 2652114402Sru } 2653114402Sru int printed_one = 0; 2654114402Sru for (vertical_rule *vr = vrule_list; vr; vr = vr->next) 2655114402Sru if (vr->end_row == r) { 2656114402Sru if (!printed_one) { 2657114402Sru prints("." REPEATED_VPT_MACRO " 0\n"); 2658114402Sru printed_one = 1; 2659114402Sru } 2660114402Sru vr->print(); 2661114402Sru } 2662114402Sru if (printed_one) 2663114402Sru prints("." REPEATED_VPT_MACRO " 1\n"); 2664114402Sru if (!(flags & NOKEEP) && row_ends_section(r)) 2665114402Sru prints("." RELEASE_MACRO_NAME "\n"); 2666114402Sru } 2667114402Sru} 2668114402Sru 2669114402Sruvoid table::do_top() 2670114402Sru{ 2671114402Sru prints(".fc \002\003\n"); 2672114402Sru if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) 2673114402Sru prints("." TABLE_KEEP_MACRO_NAME "\n"); 2674114402Sru if (flags & DOUBLEBOX) { 2675114402Sru prints(".ls 1\n" 2676114402Sru ".vs " LINE_SEP ">?\\n[.V]u\n" 2677114402Sru "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n" 2678114402Sru ".vs\n" 2679114402Sru "." REPEATED_MARK_MACRO " " TOP_REG "\n" 2680114402Sru ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"); 2681114402Sru printfs("\\v'" BODY_DEPTH "'" 2682114402Sru "\\s[\\n[" LINESIZE_REG "]]" 2683114402Sru "\\h'\\n[%1]u'" 2684114402Sru "\\D'l |\\n[%2]u 0'" 2685114402Sru "\\s0" 2686114402Sru "\n", 2687114402Sru column_divide_reg(0), 2688114402Sru column_divide_reg(ncolumns)); 2689114402Sru prints(".ls\n" 2690114402Sru ".vs\n"); 2691114402Sru } 2692114402Sru else if (flags & (ALLBOX|BOX)) { 2693114402Sru print_single_hline(0); 2694114402Sru } 2695114402Sru //printfs(".mk %1\n", row_top_reg(0)); 2696114402Sru} 2697114402Sru 2698114402Sruvoid table::do_bottom() 2699114402Sru{ 2700114402Sru // print stuff after last row 2701114402Sru for (stuff *p = stuff_list; p; p = p->next) 2702114402Sru if (p->row > nrows - 1) 2703114402Sru p->print(this); 2704114402Sru if (!(flags & NOKEEP)) 2705114402Sru prints("." RELEASE_MACRO_NAME "\n"); 2706114402Sru printfs(".mk %1\n", row_top_reg(nrows)); 2707114402Sru prints(".nr " NEED_BOTTOM_RULE_REG " 1\n" 2708114402Sru ".nr T. 1\n" 2709114402Sru ".T#\n"); 2710114402Sru if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX))) 2711114402Sru prints("." TABLE_RELEASE_MACRO_NAME "\n"); 2712114402Sru if (flags & DOUBLEBOX) 2713114402Sru prints(".sp " DOUBLE_LINE_SEP "\n"); 2714114402Sru prints("." RESET_MACRO_NAME "\n" 2715114402Sru ".fc\n" 2716114402Sru ".cp \\n(" COMPATIBLE_REG "\n"); 2717114402Sru} 2718114402Sru 2719114402Sruint table::get_nrows() 2720114402Sru{ 2721114402Sru return nrows; 2722114402Sru} 2723114402Sru 2724114402Sruconst char *last_filename = 0; 2725114402Sru 2726114402Sruvoid set_troff_location(const char *fn, int ln) 2727114402Sru{ 2728114402Sru if (!location_force_filename && last_filename != 0 2729114402Sru && strcmp(fn, last_filename) == 0) 2730114402Sru printfs(".lf %1\n", as_string(ln)); 2731114402Sru else { 2732114402Sru printfs(".lf %1 %2\n", as_string(ln), fn); 2733114402Sru last_filename = fn; 2734114402Sru location_force_filename = 0; 2735114402Sru } 2736114402Sru} 2737114402Sru 2738114402Sruvoid printfs(const char *s, const string &arg1, const string &arg2, 2739114402Sru const string &arg3, const string &arg4, const string &arg5) 2740114402Sru{ 2741114402Sru if (s) { 2742114402Sru char c; 2743114402Sru while ((c = *s++) != '\0') { 2744114402Sru if (c == '%') { 2745114402Sru switch (*s++) { 2746114402Sru case '1': 2747114402Sru prints(arg1); 2748114402Sru break; 2749114402Sru case '2': 2750114402Sru prints(arg2); 2751114402Sru break; 2752114402Sru case '3': 2753114402Sru prints(arg3); 2754114402Sru break; 2755114402Sru case '4': 2756114402Sru prints(arg4); 2757114402Sru break; 2758114402Sru case '5': 2759114402Sru prints(arg5); 2760114402Sru break; 2761114402Sru case '6': 2762114402Sru case '7': 2763114402Sru case '8': 2764114402Sru case '9': 2765114402Sru break; 2766114402Sru case '%': 2767114402Sru prints('%'); 2768114402Sru break; 2769114402Sru default: 2770114402Sru assert(0); 2771114402Sru } 2772114402Sru } 2773114402Sru else 2774114402Sru prints(c); 2775114402Sru } 2776114402Sru } 2777114402Sru} 2778114402Sru 2779