PageRenderTime 64ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/preproc/tbl/table.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 2778 lines | 2508 code | 206 blank | 64 comment | 689 complexity | 1207b28aa9e2b714dd0420b955f47f93 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2003, 2004
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. #include "table.h"
  18. #define BAR_HEIGHT ".25m"
  19. #define DOUBLE_LINE_SEP "2p"
  20. #define HALF_DOUBLE_LINE_SEP "1p"
  21. #define LINE_SEP "2p"
  22. #define BODY_DEPTH ".25m"
  23. const int DEFAULT_COLUMN_SEPARATION = 3;
  24. #define DELIMITER_CHAR "\\[tbl]"
  25. #define SEPARATION_FACTOR_REG PREFIX "sep"
  26. #define BOTTOM_REG PREFIX "bot"
  27. #define RESET_MACRO_NAME PREFIX "init"
  28. #define LINESIZE_REG PREFIX "lps"
  29. #define TOP_REG PREFIX "top"
  30. #define CURRENT_ROW_REG PREFIX "crow"
  31. #define LAST_PASSED_ROW_REG PREFIX "passed"
  32. #define TRANSPARENT_STRING_NAME PREFIX "trans"
  33. #define QUOTE_STRING_NAME PREFIX "quote"
  34. #define SECTION_DIVERSION_NAME PREFIX "section"
  35. #define SECTION_DIVERSION_FLAG_REG PREFIX "sflag"
  36. #define SAVED_VERTICAL_POS_REG PREFIX "vert"
  37. #define NEED_BOTTOM_RULE_REG PREFIX "brule"
  38. #define KEEP_MACRO_NAME PREFIX "keep"
  39. #define RELEASE_MACRO_NAME PREFIX "release"
  40. #define SAVED_FONT_REG PREFIX "fnt"
  41. #define SAVED_SIZE_REG PREFIX "sz"
  42. #define SAVED_FILL_REG PREFIX "fll"
  43. #define SAVED_INDENT_REG PREFIX "ind"
  44. #define SAVED_CENTER_REG PREFIX "cent"
  45. #define TABLE_DIVERSION_NAME PREFIX "table"
  46. #define TABLE_DIVERSION_FLAG_REG PREFIX "tflag"
  47. #define TABLE_KEEP_MACRO_NAME PREFIX "tkeep"
  48. #define TABLE_RELEASE_MACRO_NAME PREFIX "trelease"
  49. #define NEEDED_REG PREFIX "needed"
  50. #define REPEATED_MARK_MACRO PREFIX "rmk"
  51. #define REPEATED_VPT_MACRO PREFIX "rvpt"
  52. #define SUPPRESS_BOTTOM_REG PREFIX "supbot"
  53. #define SAVED_DN_REG PREFIX "dn"
  54. // this must be one character
  55. #define COMPATIBLE_REG PREFIX "c"
  56. #define LEADER_REG PREFIX LEADER
  57. #define BLOCK_WIDTH_PREFIX PREFIX "tbw"
  58. #define BLOCK_DIVERSION_PREFIX PREFIX "tbd"
  59. #define BLOCK_HEIGHT_PREFIX PREFIX "tbh"
  60. #define SPAN_WIDTH_PREFIX PREFIX "w"
  61. #define SPAN_LEFT_NUMERIC_WIDTH_PREFIX PREFIX "lnw"
  62. #define SPAN_RIGHT_NUMERIC_WIDTH_PREFIX PREFIX "rnw"
  63. #define SPAN_ALPHABETIC_WIDTH_PREFIX PREFIX "aw"
  64. #define COLUMN_SEPARATION_PREFIX PREFIX "cs"
  65. #define ROW_START_PREFIX PREFIX "rs"
  66. #define COLUMN_START_PREFIX PREFIX "cl"
  67. #define COLUMN_END_PREFIX PREFIX "ce"
  68. #define COLUMN_DIVIDE_PREFIX PREFIX "cd"
  69. #define ROW_TOP_PREFIX PREFIX "rt"
  70. string block_width_reg(int r, int c);
  71. string block_diversion_name(int r, int c);
  72. string block_height_reg(int r, int c);
  73. string span_width_reg(int start_col, int end_col);
  74. string span_left_numeric_width_reg(int start_col, int end_col);
  75. string span_right_numeric_width_reg(int start_col, int end_col);
  76. string span_alphabetic_width_reg(int start_col, int end_col);
  77. string column_separation_reg(int col);
  78. string row_start_reg(int r);
  79. string column_start_reg(int c);
  80. string column_end_reg(int c);
  81. string column_divide_reg(int c);
  82. string row_top_reg(int r);
  83. void set_inline_modifier(const entry_modifier *);
  84. void restore_inline_modifier(const entry_modifier *m);
  85. void set_modifier(const entry_modifier *);
  86. int find_decimal_point(const char *s, char decimal_point_char,
  87. const char *delim);
  88. string an_empty_string;
  89. int location_force_filename = 0;
  90. void printfs(const char *,
  91. const string &arg1 = an_empty_string,
  92. const string &arg2 = an_empty_string,
  93. const string &arg3 = an_empty_string,
  94. const string &arg4 = an_empty_string,
  95. const string &arg5 = an_empty_string);
  96. void prints(const string &);
  97. inline void prints(char c)
  98. {
  99. putchar(c);
  100. }
  101. inline void prints(const char *s)
  102. {
  103. fputs(s, stdout);
  104. }
  105. void prints(const string &s)
  106. {
  107. if (!s.empty())
  108. fwrite(s.contents(), 1, s.length(), stdout);
  109. }
  110. struct horizontal_span {
  111. horizontal_span *next;
  112. int start_col;
  113. int end_col;
  114. horizontal_span(int, int, horizontal_span *);
  115. };
  116. class single_line_entry;
  117. class double_line_entry;
  118. class simple_entry;
  119. class table_entry {
  120. friend class table;
  121. table_entry *next;
  122. int input_lineno;
  123. const char *input_filename;
  124. protected:
  125. int start_row;
  126. int end_row;
  127. int start_col;
  128. int end_col;
  129. const entry_modifier *mod;
  130. public:
  131. void set_location();
  132. table_entry(const entry_modifier *);
  133. virtual ~table_entry();
  134. virtual int divert(int ncols, const string *mw, int *sep);
  135. virtual void do_width();
  136. virtual void do_depth();
  137. virtual void print() = 0;
  138. virtual void position_vertically() = 0;
  139. virtual single_line_entry *to_single_line_entry();
  140. virtual double_line_entry *to_double_line_entry();
  141. virtual simple_entry *to_simple_entry();
  142. virtual int line_type();
  143. virtual void note_double_vrule_on_right(int);
  144. virtual void note_double_vrule_on_left(int);
  145. };
  146. class simple_entry : public table_entry {
  147. public:
  148. simple_entry(const entry_modifier *);
  149. void print();
  150. void position_vertically();
  151. simple_entry *to_simple_entry();
  152. virtual void add_tab();
  153. virtual void simple_print(int);
  154. };
  155. class empty_entry : public simple_entry {
  156. public:
  157. empty_entry(const entry_modifier *);
  158. int line_type();
  159. };
  160. class text_entry : public simple_entry {
  161. protected:
  162. char *contents;
  163. void print_contents();
  164. public:
  165. text_entry(char *, const entry_modifier *);
  166. ~text_entry();
  167. };
  168. void text_entry::print_contents()
  169. {
  170. set_inline_modifier(mod);
  171. prints(contents);
  172. restore_inline_modifier(mod);
  173. }
  174. class repeated_char_entry : public text_entry {
  175. public:
  176. repeated_char_entry(char *s, const entry_modifier *m);
  177. void simple_print(int);
  178. };
  179. class simple_text_entry : public text_entry {
  180. public:
  181. simple_text_entry(char *s, const entry_modifier *m);
  182. void do_width();
  183. };
  184. class left_text_entry : public simple_text_entry {
  185. public:
  186. left_text_entry(char *s, const entry_modifier *m);
  187. void simple_print(int);
  188. void add_tab();
  189. };
  190. class right_text_entry : public simple_text_entry {
  191. public:
  192. right_text_entry(char *s, const entry_modifier *m);
  193. void simple_print(int);
  194. void add_tab();
  195. };
  196. class center_text_entry : public simple_text_entry {
  197. public:
  198. center_text_entry(char *s, const entry_modifier *m);
  199. void simple_print(int);
  200. void add_tab();
  201. };
  202. class numeric_text_entry : public text_entry {
  203. int dot_pos;
  204. public:
  205. numeric_text_entry(char *s, const entry_modifier *m, int pos);
  206. void do_width();
  207. void simple_print(int);
  208. };
  209. class alphabetic_text_entry : public text_entry {
  210. public:
  211. alphabetic_text_entry(char *s, const entry_modifier *m);
  212. void do_width();
  213. void simple_print(int);
  214. void add_tab();
  215. };
  216. class line_entry : public simple_entry {
  217. protected:
  218. char double_vrule_on_right;
  219. char double_vrule_on_left;
  220. public:
  221. line_entry(const entry_modifier *);
  222. void note_double_vrule_on_right(int);
  223. void note_double_vrule_on_left(int);
  224. void simple_print(int) = 0;
  225. };
  226. class single_line_entry : public line_entry {
  227. public:
  228. single_line_entry(const entry_modifier *m);
  229. void simple_print(int);
  230. single_line_entry *to_single_line_entry();
  231. int line_type();
  232. };
  233. class double_line_entry : public line_entry {
  234. public:
  235. double_line_entry(const entry_modifier *m);
  236. void simple_print(int);
  237. double_line_entry *to_double_line_entry();
  238. int line_type();
  239. };
  240. class short_line_entry : public simple_entry {
  241. public:
  242. short_line_entry(const entry_modifier *m);
  243. void simple_print(int);
  244. int line_type();
  245. };
  246. class short_double_line_entry : public simple_entry {
  247. public:
  248. short_double_line_entry(const entry_modifier *m);
  249. void simple_print(int);
  250. int line_type();
  251. };
  252. class block_entry : public table_entry {
  253. char *contents;
  254. protected:
  255. void do_divert(int alphabetic, int ncols, const string *mw, int *sep);
  256. public:
  257. block_entry(char *s, const entry_modifier *m);
  258. ~block_entry();
  259. int divert(int ncols, const string *mw, int *sep);
  260. void do_width();
  261. void do_depth();
  262. void position_vertically();
  263. void print() = 0;
  264. };
  265. class left_block_entry : public block_entry {
  266. public:
  267. left_block_entry(char *s, const entry_modifier *m);
  268. void print();
  269. };
  270. class right_block_entry : public block_entry {
  271. public:
  272. right_block_entry(char *s, const entry_modifier *m);
  273. void print();
  274. };
  275. class center_block_entry : public block_entry {
  276. public:
  277. center_block_entry(char *s, const entry_modifier *m);
  278. void print();
  279. };
  280. class alphabetic_block_entry : public block_entry {
  281. public:
  282. alphabetic_block_entry(char *s, const entry_modifier *m);
  283. void print();
  284. int divert(int ncols, const string *mw, int *sep);
  285. };
  286. table_entry::table_entry(const entry_modifier *m)
  287. : next(0), input_lineno(-1), input_filename(0),
  288. start_row(-1), end_row(-1), start_col(-1), end_col(-1), mod(m)
  289. {
  290. }
  291. table_entry::~table_entry()
  292. {
  293. }
  294. int table_entry::divert(int, const string *, int *)
  295. {
  296. return 0;
  297. }
  298. void table_entry::do_width()
  299. {
  300. }
  301. single_line_entry *table_entry::to_single_line_entry()
  302. {
  303. return 0;
  304. }
  305. double_line_entry *table_entry::to_double_line_entry()
  306. {
  307. return 0;
  308. }
  309. simple_entry *table_entry::to_simple_entry()
  310. {
  311. return 0;
  312. }
  313. void table_entry::do_depth()
  314. {
  315. }
  316. void table_entry::set_location()
  317. {
  318. set_troff_location(input_filename, input_lineno);
  319. }
  320. int table_entry::line_type()
  321. {
  322. return -1;
  323. }
  324. void table_entry::note_double_vrule_on_right(int)
  325. {
  326. }
  327. void table_entry::note_double_vrule_on_left(int)
  328. {
  329. }
  330. simple_entry::simple_entry(const entry_modifier *m) : table_entry(m)
  331. {
  332. }
  333. void simple_entry::add_tab()
  334. {
  335. // do nothing
  336. }
  337. void simple_entry::simple_print(int)
  338. {
  339. // do nothing
  340. }
  341. void simple_entry::position_vertically()
  342. {
  343. if (start_row != end_row)
  344. switch (mod->vertical_alignment) {
  345. case entry_modifier::TOP:
  346. printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
  347. break;
  348. case entry_modifier::CENTER:
  349. // Peform the motion in two stages so that the center is rounded
  350. // vertically upwards even if net vertical motion is upwards.
  351. printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
  352. printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-1v/2u\n",
  353. row_start_reg(start_row));
  354. break;
  355. case entry_modifier::BOTTOM:
  356. printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-1v\n",
  357. row_start_reg(start_row));
  358. break;
  359. default:
  360. assert(0);
  361. }
  362. }
  363. void simple_entry::print()
  364. {
  365. prints(".ta");
  366. add_tab();
  367. prints('\n');
  368. set_location();
  369. prints("\\&");
  370. simple_print(0);
  371. prints('\n');
  372. }
  373. simple_entry *simple_entry::to_simple_entry()
  374. {
  375. return this;
  376. }
  377. empty_entry::empty_entry(const entry_modifier *m)
  378. : simple_entry(m)
  379. {
  380. }
  381. int empty_entry::line_type()
  382. {
  383. return 0;
  384. }
  385. text_entry::text_entry(char *s, const entry_modifier *m)
  386. : simple_entry(m), contents(s)
  387. {
  388. }
  389. text_entry::~text_entry()
  390. {
  391. a_delete contents;
  392. }
  393. repeated_char_entry::repeated_char_entry(char *s, const entry_modifier *m)
  394. : text_entry(s, m)
  395. {
  396. }
  397. void repeated_char_entry::simple_print(int)
  398. {
  399. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  400. set_inline_modifier(mod);
  401. printfs("\\l" DELIMITER_CHAR "\\n[%1]u\\&",
  402. span_width_reg(start_col, end_col));
  403. prints(contents);
  404. prints(DELIMITER_CHAR);
  405. restore_inline_modifier(mod);
  406. }
  407. simple_text_entry::simple_text_entry(char *s, const entry_modifier *m)
  408. : text_entry(s, m)
  409. {
  410. }
  411. void simple_text_entry::do_width()
  412. {
  413. set_location();
  414. printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
  415. span_width_reg(start_col, end_col));
  416. print_contents();
  417. prints(DELIMITER_CHAR "\n");
  418. }
  419. left_text_entry::left_text_entry(char *s, const entry_modifier *m)
  420. : simple_text_entry(s, m)
  421. {
  422. }
  423. void left_text_entry::simple_print(int)
  424. {
  425. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  426. print_contents();
  427. }
  428. // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
  429. void left_text_entry::add_tab()
  430. {
  431. printfs(" \\n[%1]u", column_end_reg(end_col));
  432. }
  433. right_text_entry::right_text_entry(char *s, const entry_modifier *m)
  434. : simple_text_entry(s, m)
  435. {
  436. }
  437. void right_text_entry::simple_print(int)
  438. {
  439. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  440. prints("\002\003");
  441. print_contents();
  442. prints("\002");
  443. }
  444. void right_text_entry::add_tab()
  445. {
  446. printfs(" \\n[%1]u", column_end_reg(end_col));
  447. }
  448. center_text_entry::center_text_entry(char *s, const entry_modifier *m)
  449. : simple_text_entry(s, m)
  450. {
  451. }
  452. void center_text_entry::simple_print(int)
  453. {
  454. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  455. prints("\002\003");
  456. print_contents();
  457. prints("\003\002");
  458. }
  459. void center_text_entry::add_tab()
  460. {
  461. printfs(" \\n[%1]u", column_end_reg(end_col));
  462. }
  463. numeric_text_entry::numeric_text_entry(char *s, const entry_modifier *m, int pos)
  464. : text_entry(s, m), dot_pos(pos)
  465. {
  466. }
  467. void numeric_text_entry::do_width()
  468. {
  469. if (dot_pos != 0) {
  470. set_location();
  471. printfs(".nr %1 0\\w" DELIMITER_CHAR,
  472. block_width_reg(start_row, start_col));
  473. set_inline_modifier(mod);
  474. for (int i = 0; i < dot_pos; i++)
  475. prints(contents[i]);
  476. restore_inline_modifier(mod);
  477. prints(DELIMITER_CHAR "\n");
  478. printfs(".nr %1 \\n[%1]>?\\n[%2]\n",
  479. span_left_numeric_width_reg(start_col, end_col),
  480. block_width_reg(start_row, start_col));
  481. }
  482. else
  483. printfs(".nr %1 0\n", block_width_reg(start_row, start_col));
  484. if (contents[dot_pos] != '\0') {
  485. set_location();
  486. printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
  487. span_right_numeric_width_reg(start_col, end_col));
  488. set_inline_modifier(mod);
  489. prints(contents + dot_pos);
  490. restore_inline_modifier(mod);
  491. prints(DELIMITER_CHAR "\n");
  492. }
  493. }
  494. void numeric_text_entry::simple_print(int)
  495. {
  496. printfs("\\h'|(\\n[%1]u-\\n[%2]u-\\n[%3]u/2u+\\n[%2]u+\\n[%4]u-\\n[%5]u)'",
  497. span_width_reg(start_col, end_col),
  498. span_left_numeric_width_reg(start_col, end_col),
  499. span_right_numeric_width_reg(start_col, end_col),
  500. column_start_reg(start_col),
  501. block_width_reg(start_row, start_col));
  502. print_contents();
  503. }
  504. alphabetic_text_entry::alphabetic_text_entry(char *s, const entry_modifier *m)
  505. : text_entry(s, m)
  506. {
  507. }
  508. void alphabetic_text_entry::do_width()
  509. {
  510. set_location();
  511. printfs(".nr %1 \\n[%1]>?\\w" DELIMITER_CHAR,
  512. span_alphabetic_width_reg(start_col, end_col));
  513. print_contents();
  514. prints(DELIMITER_CHAR "\n");
  515. }
  516. void alphabetic_text_entry::simple_print(int)
  517. {
  518. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  519. printfs("\\h'\\n[%1]u-\\n[%2]u/2u'",
  520. span_width_reg(start_col, end_col),
  521. span_alphabetic_width_reg(start_col, end_col));
  522. print_contents();
  523. }
  524. // The only point of this is to make `\a' ``work'' as in Unix tbl. Grrr.
  525. void alphabetic_text_entry::add_tab()
  526. {
  527. printfs(" \\n[%1]u", column_end_reg(end_col));
  528. }
  529. block_entry::block_entry(char *s, const entry_modifier *m)
  530. : table_entry(m), contents(s)
  531. {
  532. }
  533. block_entry::~block_entry()
  534. {
  535. a_delete contents;
  536. }
  537. void block_entry::position_vertically()
  538. {
  539. if (start_row != end_row)
  540. switch(mod->vertical_alignment) {
  541. case entry_modifier::TOP:
  542. printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
  543. break;
  544. case entry_modifier::CENTER:
  545. // Peform the motion in two stages so that the center is rounded
  546. // vertically upwards even if net vertical motion is upwards.
  547. printfs(".sp |\\n[%1]u\n", row_start_reg(start_row));
  548. printfs(".sp \\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u/2u\n",
  549. row_start_reg(start_row),
  550. block_height_reg(start_row, start_col));
  551. break;
  552. case entry_modifier::BOTTOM:
  553. printfs(".sp |\\n[%1]u+\\n[" BOTTOM_REG "]u-\\n[%1]u-\\n[%2]u\n",
  554. row_start_reg(start_row),
  555. block_height_reg(start_row, start_col));
  556. break;
  557. default:
  558. assert(0);
  559. }
  560. if (mod->stagger)
  561. prints(".sp -.5v\n");
  562. }
  563. int block_entry::divert(int ncols, const string *mw, int *sep)
  564. {
  565. do_divert(0, ncols, mw, sep);
  566. return 1;
  567. }
  568. void block_entry::do_divert(int alphabetic, int ncols, const string *mw,
  569. int *sep)
  570. {
  571. printfs(".di %1\n", block_diversion_name(start_row, start_col));
  572. prints(".if \\n[" SAVED_FILL_REG "] .fi\n"
  573. ".in 0\n");
  574. prints(".ll ");
  575. int i;
  576. for (i = start_col; i <= end_col; i++)
  577. if (mw[i].empty())
  578. break;
  579. if (i > end_col) {
  580. // Every column spanned by this entry has a minimum width.
  581. for (int j = start_col; j <= end_col; j++) {
  582. if (j > start_col) {
  583. if (sep)
  584. printfs("+%1n", as_string(sep[j - 1]));
  585. prints('+');
  586. }
  587. printfs("(n;%1)", mw[j]);
  588. }
  589. printfs(">?\\n[%1]u", span_width_reg(start_col, end_col));
  590. }
  591. else
  592. printfs("(u;\\n[%1]>?(\\n[.l]*%2/%3))",
  593. span_width_reg(start_col, end_col),
  594. as_string(end_col - start_col + 1),
  595. as_string(ncols + 1));
  596. if (alphabetic)
  597. prints("-2n");
  598. prints("\n");
  599. prints(".cp \\n(" COMPATIBLE_REG "\n");
  600. set_modifier(mod);
  601. set_location();
  602. prints(contents);
  603. prints(".br\n.di\n.cp 0\n");
  604. if (!mod->zero_width) {
  605. if (alphabetic) {
  606. printfs(".nr %1 \\n[%1]>?(\\n[dl]+2n)\n",
  607. span_width_reg(start_col, end_col));
  608. printfs(".nr %1 \\n[%1]>?\\n[dl]\n",
  609. span_alphabetic_width_reg(start_col, end_col));
  610. }
  611. else
  612. printfs(".nr %1 \\n[%1]>?\\n[dl]\n", span_width_reg(start_col, end_col));
  613. }
  614. printfs(".nr %1 \\n[dn]\n", block_height_reg(start_row, start_col));
  615. printfs(".nr %1 \\n[dl]\n", block_width_reg(start_row, start_col));
  616. prints("." RESET_MACRO_NAME "\n"
  617. ".in \\n[" SAVED_INDENT_REG "]u\n"
  618. ".nf\n");
  619. // the block might have contained .lf commands
  620. location_force_filename = 1;
  621. }
  622. void block_entry::do_width()
  623. {
  624. // do nothing; the action happens in divert
  625. }
  626. void block_entry::do_depth()
  627. {
  628. printfs(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?(\\n[%1]+\\n[%2])\n",
  629. row_start_reg(start_row),
  630. block_height_reg(start_row, start_col));
  631. }
  632. left_block_entry::left_block_entry(char *s, const entry_modifier *m)
  633. : block_entry(s, m)
  634. {
  635. }
  636. void left_block_entry::print()
  637. {
  638. printfs(".in +\\n[%1]u\n", column_start_reg(start_col));
  639. printfs(".%1\n", block_diversion_name(start_row, start_col));
  640. prints(".in\n");
  641. }
  642. right_block_entry::right_block_entry(char *s, const entry_modifier *m)
  643. : block_entry(s, m)
  644. {
  645. }
  646. void right_block_entry::print()
  647. {
  648. printfs(".in +\\n[%1]u+\\n[%2]u-\\n[%3]u\n",
  649. column_start_reg(start_col),
  650. span_width_reg(start_col, end_col),
  651. block_width_reg(start_row, start_col));
  652. printfs(".%1\n", block_diversion_name(start_row, start_col));
  653. prints(".in\n");
  654. }
  655. center_block_entry::center_block_entry(char *s, const entry_modifier *m)
  656. : block_entry(s, m)
  657. {
  658. }
  659. void center_block_entry::print()
  660. {
  661. printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
  662. column_start_reg(start_col),
  663. span_width_reg(start_col, end_col),
  664. block_width_reg(start_row, start_col));
  665. printfs(".%1\n", block_diversion_name(start_row, start_col));
  666. prints(".in\n");
  667. }
  668. alphabetic_block_entry::alphabetic_block_entry(char *s,
  669. const entry_modifier *m)
  670. : block_entry(s, m)
  671. {
  672. }
  673. int alphabetic_block_entry::divert(int ncols, const string *mw, int *sep)
  674. {
  675. do_divert(1, ncols, mw, sep);
  676. return 1;
  677. }
  678. void alphabetic_block_entry::print()
  679. {
  680. printfs(".in +\\n[%1]u+(\\n[%2]u-\\n[%3]u/2u)\n",
  681. column_start_reg(start_col),
  682. span_width_reg(start_col, end_col),
  683. span_alphabetic_width_reg(start_col, end_col));
  684. printfs(".%1\n", block_diversion_name(start_row, start_col));
  685. prints(".in\n");
  686. }
  687. line_entry::line_entry(const entry_modifier *m)
  688. : simple_entry(m), double_vrule_on_right(0), double_vrule_on_left(0)
  689. {
  690. }
  691. void line_entry::note_double_vrule_on_right(int is_corner)
  692. {
  693. double_vrule_on_right = is_corner ? 1 : 2;
  694. }
  695. void line_entry::note_double_vrule_on_left(int is_corner)
  696. {
  697. double_vrule_on_left = is_corner ? 1 : 2;
  698. }
  699. single_line_entry::single_line_entry(const entry_modifier *m)
  700. : line_entry(m)
  701. {
  702. }
  703. int single_line_entry::line_type()
  704. {
  705. return 1;
  706. }
  707. void single_line_entry::simple_print(int dont_move)
  708. {
  709. printfs("\\h'|\\n[%1]u",
  710. column_divide_reg(start_col));
  711. if (double_vrule_on_left) {
  712. prints(double_vrule_on_left == 1 ? "-" : "+");
  713. prints(HALF_DOUBLE_LINE_SEP);
  714. }
  715. prints("'");
  716. if (!dont_move)
  717. prints("\\v'-" BAR_HEIGHT "'");
  718. printfs("\\s[\\n[" LINESIZE_REG "]]" "\\D'l |\\n[%1]u",
  719. column_divide_reg(end_col+1));
  720. if (double_vrule_on_right) {
  721. prints(double_vrule_on_left == 1 ? "+" : "-");
  722. prints(HALF_DOUBLE_LINE_SEP);
  723. }
  724. prints("0'\\s0");
  725. if (!dont_move)
  726. prints("\\v'" BAR_HEIGHT "'");
  727. }
  728. single_line_entry *single_line_entry::to_single_line_entry()
  729. {
  730. return this;
  731. }
  732. double_line_entry::double_line_entry(const entry_modifier *m)
  733. : line_entry(m)
  734. {
  735. }
  736. int double_line_entry::line_type()
  737. {
  738. return 2;
  739. }
  740. void double_line_entry::simple_print(int dont_move)
  741. {
  742. if (!dont_move)
  743. prints("\\v'-" BAR_HEIGHT "'");
  744. printfs("\\h'|\\n[%1]u",
  745. column_divide_reg(start_col));
  746. if (double_vrule_on_left) {
  747. prints(double_vrule_on_left == 1 ? "-" : "+");
  748. prints(HALF_DOUBLE_LINE_SEP);
  749. }
  750. prints("'");
  751. printfs("\\v'-" HALF_DOUBLE_LINE_SEP "'"
  752. "\\s[\\n[" LINESIZE_REG "]]"
  753. "\\D'l |\\n[%1]u",
  754. column_divide_reg(end_col+1));
  755. if (double_vrule_on_right)
  756. prints("-" HALF_DOUBLE_LINE_SEP);
  757. prints(" 0'");
  758. printfs("\\v'" DOUBLE_LINE_SEP "'"
  759. "\\D'l |\\n[%1]u",
  760. column_divide_reg(start_col));
  761. if (double_vrule_on_right) {
  762. prints(double_vrule_on_left == 1 ? "+" : "-");
  763. prints(HALF_DOUBLE_LINE_SEP);
  764. }
  765. prints(" 0'");
  766. prints("\\s0"
  767. "\\v'-" HALF_DOUBLE_LINE_SEP "'");
  768. if (!dont_move)
  769. prints("\\v'" BAR_HEIGHT "'");
  770. }
  771. double_line_entry *double_line_entry::to_double_line_entry()
  772. {
  773. return this;
  774. }
  775. short_line_entry::short_line_entry(const entry_modifier *m)
  776. : simple_entry(m)
  777. {
  778. }
  779. int short_line_entry::line_type()
  780. {
  781. return 1;
  782. }
  783. void short_line_entry::simple_print(int dont_move)
  784. {
  785. if (mod->stagger)
  786. prints("\\v'-.5v'");
  787. if (!dont_move)
  788. prints("\\v'-" BAR_HEIGHT "'");
  789. printfs("\\h'|\\n[%1]u'", column_start_reg(start_col));
  790. printfs("\\s[\\n[" LINESIZE_REG "]]"
  791. "\\D'l \\n[%1]u 0'"
  792. "\\s0",
  793. span_width_reg(start_col, end_col));
  794. if (!dont_move)
  795. prints("\\v'" BAR_HEIGHT "'");
  796. if (mod->stagger)
  797. prints("\\v'.5v'");
  798. }
  799. short_double_line_entry::short_double_line_entry(const entry_modifier *m)
  800. : simple_entry(m)
  801. {
  802. }
  803. int short_double_line_entry::line_type()
  804. {
  805. return 2;
  806. }
  807. void short_double_line_entry::simple_print(int dont_move)
  808. {
  809. if (mod->stagger)
  810. prints("\\v'-.5v'");
  811. if (!dont_move)
  812. prints("\\v'-" BAR_HEIGHT "'");
  813. printfs("\\h'|\\n[%2]u'"
  814. "\\v'-" HALF_DOUBLE_LINE_SEP "'"
  815. "\\s[\\n[" LINESIZE_REG "]]"
  816. "\\D'l \\n[%1]u 0'"
  817. "\\v'" DOUBLE_LINE_SEP "'"
  818. "\\D'l |\\n[%2]u 0'"
  819. "\\s0"
  820. "\\v'-" HALF_DOUBLE_LINE_SEP "'",
  821. span_width_reg(start_col, end_col),
  822. column_start_reg(start_col));
  823. if (!dont_move)
  824. prints("\\v'" BAR_HEIGHT "'");
  825. if (mod->stagger)
  826. prints("\\v'.5v'");
  827. }
  828. void set_modifier(const entry_modifier *m)
  829. {
  830. if (!m->font.empty())
  831. printfs(".ft %1\n", m->font);
  832. if (m->point_size.val != 0) {
  833. prints(".ps ");
  834. if (m->point_size.inc > 0)
  835. prints('+');
  836. else if (m->point_size.inc < 0)
  837. prints('-');
  838. printfs("%1\n", as_string(m->point_size.val));
  839. }
  840. if (m->vertical_spacing.val != 0) {
  841. prints(".vs ");
  842. if (m->vertical_spacing.inc > 0)
  843. prints('+');
  844. else if (m->vertical_spacing.inc < 0)
  845. prints('-');
  846. printfs("%1\n", as_string(m->vertical_spacing.val));
  847. }
  848. if (!m->macro.empty())
  849. printfs(".%1\n", m->macro);
  850. }
  851. void set_inline_modifier(const entry_modifier *m)
  852. {
  853. if (!m->font.empty())
  854. printfs("\\f[%1]", m->font);
  855. if (m->point_size.val != 0) {
  856. prints("\\s[");
  857. if (m->point_size.inc > 0)
  858. prints('+');
  859. else if (m->point_size.inc < 0)
  860. prints('-');
  861. printfs("%1]", as_string(m->point_size.val));
  862. }
  863. if (m->stagger)
  864. prints("\\v'-.5v'");
  865. }
  866. void restore_inline_modifier(const entry_modifier *m)
  867. {
  868. if (!m->font.empty())
  869. prints("\\f[\\n[" SAVED_FONT_REG "]]");
  870. if (m->point_size.val != 0)
  871. prints("\\s[\\n[" SAVED_SIZE_REG "]]");
  872. if (m->stagger)
  873. prints("\\v'.5v'");
  874. }
  875. struct stuff {
  876. stuff *next;
  877. int row; // occurs before row `row'
  878. char printed; // has it been printed?
  879. stuff(int);
  880. virtual void print(table *) = 0;
  881. virtual ~stuff();
  882. virtual int is_single_line() { return 0; };
  883. virtual int is_double_line() { return 0; };
  884. };
  885. stuff::stuff(int r) : next(0), row(r), printed(0)
  886. {
  887. }
  888. stuff::~stuff()
  889. {
  890. }
  891. struct text_stuff : public stuff {
  892. string contents;
  893. const char *filename;
  894. int lineno;
  895. text_stuff(const string &, int r, const char *fn, int ln);
  896. ~text_stuff();
  897. void print(table *);
  898. };
  899. text_stuff::text_stuff(const string &s, int r, const char *fn, int ln)
  900. : stuff(r), contents(s), filename(fn), lineno(ln)
  901. {
  902. }
  903. text_stuff::~text_stuff()
  904. {
  905. }
  906. void text_stuff::print(table *)
  907. {
  908. printed = 1;
  909. prints(".cp \\n(" COMPATIBLE_REG "\n");
  910. set_troff_location(filename, lineno);
  911. prints(contents);
  912. prints(".cp 0\n");
  913. location_force_filename = 1; // it might have been a .lf command
  914. }
  915. struct single_hline_stuff : public stuff {
  916. single_hline_stuff(int r);
  917. void print(table *);
  918. int is_single_line();
  919. };
  920. single_hline_stuff::single_hline_stuff(int r) : stuff(r)
  921. {
  922. }
  923. void single_hline_stuff::print(table *tbl)
  924. {
  925. printed = 1;
  926. tbl->print_single_hline(row);
  927. }
  928. int single_hline_stuff::is_single_line()
  929. {
  930. return 1;
  931. }
  932. struct double_hline_stuff : stuff {
  933. double_hline_stuff(int r);
  934. void print(table *);
  935. int is_double_line();
  936. };
  937. double_hline_stuff::double_hline_stuff(int r) : stuff(r)
  938. {
  939. }
  940. void double_hline_stuff::print(table *tbl)
  941. {
  942. printed = 1;
  943. tbl->print_double_hline(row);
  944. }
  945. int double_hline_stuff::is_double_line()
  946. {
  947. return 1;
  948. }
  949. struct vertical_rule {
  950. vertical_rule *next;
  951. int start_row;
  952. int end_row;
  953. int col;
  954. char is_double;
  955. string top_adjust;
  956. string bot_adjust;
  957. vertical_rule(int sr, int er, int c, int dbl, vertical_rule *);
  958. ~vertical_rule();
  959. void contribute_to_bottom_macro(table *);
  960. void print();
  961. };
  962. vertical_rule::vertical_rule(int sr, int er, int c, int dbl, vertical_rule *p)
  963. : next(p), start_row(sr), end_row(er), col(c), is_double(dbl)
  964. {
  965. }
  966. vertical_rule::~vertical_rule()
  967. {
  968. }
  969. void vertical_rule::contribute_to_bottom_macro(table *tbl)
  970. {
  971. printfs(".if \\n[" CURRENT_ROW_REG "]>=%1",
  972. as_string(start_row));
  973. if (end_row != tbl->get_nrows() - 1)
  974. printfs("&(\\n[" CURRENT_ROW_REG "]<%1)",
  975. as_string(end_row));
  976. prints(" \\{");
  977. printfs(".if %1<=\\n[" LAST_PASSED_ROW_REG "] .nr %2 \\n[#T]\n",
  978. as_string(start_row),
  979. row_top_reg(start_row));
  980. const char *offset_table[3];
  981. if (is_double) {
  982. offset_table[0] = "-" HALF_DOUBLE_LINE_SEP;
  983. offset_table[1] = "+" HALF_DOUBLE_LINE_SEP;
  984. offset_table[2] = 0;
  985. }
  986. else {
  987. offset_table[0] = "";
  988. offset_table[1] = 0;
  989. }
  990. for (const char **offsetp = offset_table; *offsetp; offsetp++) {
  991. prints(".sp -1\n"
  992. "\\v'" BODY_DEPTH);
  993. if (!bot_adjust.empty())
  994. printfs("+%1", bot_adjust);
  995. prints("'");
  996. printfs("\\h'\\n[%1]u%3'\\s[\\n[" LINESIZE_REG "]]\\D'l 0 |\\n[%2]u-1v",
  997. column_divide_reg(col),
  998. row_top_reg(start_row),
  999. *offsetp);
  1000. if (!bot_adjust.empty())
  1001. printfs("-(%1)", bot_adjust);
  1002. // don't perform the top adjustment if the top is actually #T
  1003. if (!top_adjust.empty())
  1004. printfs("+((%1)*(%2>\\n[" LAST_PASSED_ROW_REG "]))",
  1005. top_adjust,
  1006. as_string(start_row));
  1007. prints("'\\s0\n");
  1008. }
  1009. prints(".\\}\n");
  1010. }
  1011. void vertical_rule::print()
  1012. {
  1013. printfs("\\*[" TRANSPARENT_STRING_NAME "]"
  1014. ".if %1<=\\*[" QUOTE_STRING_NAME "]\\n[" LAST_PASSED_ROW_REG "] "
  1015. ".nr %2 \\*[" QUOTE_STRING_NAME "]\\n[#T]\n",
  1016. as_string(start_row),
  1017. row_top_reg(start_row));
  1018. const char *offset_table[3];
  1019. if (is_double) {
  1020. offset_table[0] = "-" HALF_DOUBLE_LINE_SEP;
  1021. offset_table[1] = "+" HALF_DOUBLE_LINE_SEP;
  1022. offset_table[2] = 0;
  1023. }
  1024. else {
  1025. offset_table[0] = "";
  1026. offset_table[1] = 0;
  1027. }
  1028. for (const char **offsetp = offset_table; *offsetp; offsetp++) {
  1029. prints("\\*[" TRANSPARENT_STRING_NAME "].sp -1\n"
  1030. "\\*[" TRANSPARENT_STRING_NAME "]\\v'" BODY_DEPTH);
  1031. if (!bot_adjust.empty())
  1032. printfs("+%1", bot_adjust);
  1033. prints("'");
  1034. printfs("\\h'\\n[%1]u%3'"
  1035. "\\s[\\n[" LINESIZE_REG "]]"
  1036. "\\D'l 0 |\\*[" QUOTE_STRING_NAME "]\\n[%2]u-1v",
  1037. column_divide_reg(col),
  1038. row_top_reg(start_row),
  1039. *offsetp);
  1040. if (!bot_adjust.empty())
  1041. printfs("-(%1)", bot_adjust);
  1042. // don't perform the top adjustment if the top is actually #T
  1043. if (!top_adjust.empty())
  1044. printfs("+((%1)*(%2>\\*[" QUOTE_STRING_NAME "]\\n["
  1045. LAST_PASSED_ROW_REG "]))",
  1046. top_adjust,
  1047. as_string(start_row));
  1048. prints("'"
  1049. "\\s0\n");
  1050. }
  1051. }
  1052. table::table(int nc, unsigned f, int ls, char dpc)
  1053. : flags(f), nrows(0), ncolumns(nc), linesize(ls), decimal_point_char(dpc),
  1054. vrule_list(0), stuff_list(0), span_list(0),
  1055. entry_list(0), entry_list_tailp(&entry_list), entry(0),
  1056. vline(0), row_is_all_lines(0), left_separation(0), right_separation(0),
  1057. allocated_rows(0)
  1058. {
  1059. minimum_width = new string[ncolumns];
  1060. column_separation = ncolumns > 1 ? new int[ncolumns - 1] : 0;
  1061. equal = new char[ncolumns];
  1062. int i;
  1063. for (i = 0; i < ncolumns; i++)
  1064. equal[i] = 0;
  1065. for (i = 0; i < ncolumns-1; i++)
  1066. column_separation[i] = DEFAULT_COLUMN_SEPARATION;
  1067. delim[0] = delim[1] = '\0';
  1068. }
  1069. table::~table()
  1070. {
  1071. for (int i = 0; i < nrows; i++) {
  1072. a_delete entry[i];
  1073. a_delete vline[i];
  1074. }
  1075. a_delete entry;
  1076. a_delete vline;
  1077. while (entry_list) {
  1078. table_entry *tem = entry_list;
  1079. entry_list = entry_list->next;
  1080. delete tem;
  1081. }
  1082. ad_delete(ncolumns) minimum_width;
  1083. a_delete column_separation;
  1084. a_delete equal;
  1085. while (stuff_list) {
  1086. stuff *tem = stuff_list;
  1087. stuff_list = stuff_list->next;
  1088. delete tem;
  1089. }
  1090. while (vrule_list) {
  1091. vertical_rule *tem = vrule_list;
  1092. vrule_list = vrule_list->next;
  1093. delete tem;
  1094. }
  1095. a_delete row_is_all_lines;
  1096. while (span_list) {
  1097. horizontal_span *tem = span_list;
  1098. span_list = span_list->next;
  1099. delete tem;
  1100. }
  1101. }
  1102. void table::set_delim(char c1, char c2)
  1103. {
  1104. delim[0] = c1;
  1105. delim[1] = c2;
  1106. }
  1107. void table::set_minimum_width(int c, const string &w)
  1108. {
  1109. assert(c >= 0 && c < ncolumns);
  1110. minimum_width[c] = w;
  1111. }
  1112. void table::set_column_separation(int c, int n)
  1113. {
  1114. assert(c >= 0 && c < ncolumns - 1);
  1115. column_separation[c] = n;
  1116. }
  1117. void table::set_equal_column(int c)
  1118. {
  1119. assert(c >= 0 && c < ncolumns);
  1120. equal[c] = 1;
  1121. }
  1122. void table::add_stuff(stuff *p)
  1123. {
  1124. stuff **pp;
  1125. for (pp = &stuff_list; *pp; pp = &(*pp)->next)
  1126. ;
  1127. *pp = p;
  1128. }
  1129. void table::add_text_line(int r, const string &s, const char *filename, int lineno)
  1130. {
  1131. add_stuff(new text_stuff(s, r, filename, lineno));
  1132. }
  1133. void table::add_single_hline(int r)
  1134. {
  1135. add_stuff(new single_hline_stuff(r));
  1136. }
  1137. void table::add_double_hline(int r)
  1138. {
  1139. add_stuff(new double_hline_stuff(r));
  1140. }
  1141. void table::allocate(int r)
  1142. {
  1143. if (r >= nrows) {
  1144. typedef table_entry **PPtable_entry; // work around g++ 1.36.1 bug
  1145. if (r >= allocated_rows) {
  1146. if (allocated_rows == 0) {
  1147. allocated_rows = 16;
  1148. if (allocated_rows <= r)
  1149. allocated_rows = r + 1;
  1150. entry = new PPtable_entry[allocated_rows];
  1151. vline = new char*[allocated_rows];
  1152. }
  1153. else {
  1154. table_entry ***old_entry = entry;
  1155. int old_allocated_rows = allocated_rows;
  1156. allocated_rows *= 2;
  1157. if (allocated_rows <= r)
  1158. allocated_rows = r + 1;
  1159. entry = new PPtable_entry[allocated_rows];
  1160. memcpy(entry, old_entry, sizeof(table_entry**)*old_allocated_rows);
  1161. a_delete old_entry;
  1162. char **old_vline = vline;
  1163. vline = new char*[allocated_rows];
  1164. memcpy(vline, old_vline, sizeof(char*)*old_allocated_rows);
  1165. a_delete old_vline;
  1166. }
  1167. }
  1168. assert(allocated_rows > r);
  1169. while (nrows <= r) {
  1170. entry[nrows] = new table_entry*[ncolumns];
  1171. int i;
  1172. for (i = 0; i < ncolumns; i++)
  1173. entry[nrows][i] = 0;
  1174. vline[nrows] = new char[ncolumns+1];
  1175. for (i = 0; i < ncolumns+1; i++)
  1176. vline[nrows][i] = 0;
  1177. nrows++;
  1178. }
  1179. }
  1180. }
  1181. void table::do_hspan(int r, int c)
  1182. {
  1183. assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns);
  1184. if (c == 0) {
  1185. error("first column cannot be horizontally spanned");
  1186. return;
  1187. }
  1188. table_entry *e = entry[r][c];
  1189. if (e) {
  1190. assert(e->start_row <= r && r <= e->end_row
  1191. && e->start_col <= c && c <= e->end_col
  1192. && e->end_row - e->start_row > 0
  1193. && e->end_col - e->start_col > 0);
  1194. return;
  1195. }
  1196. e = entry[r][c-1];
  1197. // e can be 0 if we had an empty entry or an error
  1198. if (e == 0)
  1199. return;
  1200. if (e->start_row != r) {
  1201. /*
  1202. l l
  1203. ^ s */
  1204. error("impossible horizontal span at row %1, column %2", r + 1, c + 1);
  1205. }
  1206. else {
  1207. e->end_col = c;
  1208. entry[r][c] = e;
  1209. }
  1210. }
  1211. void table::do_vspan(int r, int c)
  1212. {
  1213. assert(r >= 0 && c >= 0 && r < nrows && c < ncolumns);
  1214. if (r == 0) {
  1215. error("first row cannot be vertically spanned");
  1216. return;
  1217. }
  1218. table_entry *e = entry[r][c];
  1219. if (e) {
  1220. assert(e->start_row <= r && r <= e->end_row
  1221. && e->start_col <= c && c <= e->end_col
  1222. && e->end_row - e->start_row > 0
  1223. && e->end_col - e->start_col > 0);
  1224. return;
  1225. }
  1226. e = entry[r-1][c];
  1227. // e can be 0 if we had an empty entry or an error
  1228. if (e == 0)
  1229. return;
  1230. if (e->start_col != c) {
  1231. /* l s
  1232. l ^ */
  1233. error("impossible vertical span at row %1, column %2", r + 1, c + 1);
  1234. }
  1235. else {
  1236. for (int i = c; i <= e->end_col; i++) {
  1237. assert(entry[r][i] == 0);
  1238. entry[r][i] = e;
  1239. }
  1240. e->end_row = r;
  1241. }
  1242. }
  1243. int find_decimal_point(const char *s, char decimal_point_char,
  1244. const char *delim)
  1245. {
  1246. if (s == 0 || *s == '\0')
  1247. return -1;
  1248. const char *p;
  1249. int in_delim = 0; // is p within eqn delimiters?
  1250. // tbl recognises \& even within eqn delimiters; I don't
  1251. for (p = s; *p; p++)
  1252. if (in_delim) {
  1253. if (*p == delim[1])
  1254. in_delim = 0;
  1255. }
  1256. else if (*p == delim[0])
  1257. in_delim = 1;
  1258. else if (p[0] == '\\' && p[1] == '&')
  1259. return p - s;
  1260. int possible_pos = -1;
  1261. in_delim = 0;
  1262. for (p = s; *p; p++)
  1263. if (in_delim) {
  1264. if (*p == delim[1])
  1265. in_delim = 0;
  1266. }
  1267. else if (*p == delim[0])
  1268. in_delim = 1;
  1269. else if (p[0] == decimal_point_char && csdigit(p[1]))
  1270. possible_pos = p - s;
  1271. if (possible_pos >= 0)
  1272. return possible_pos;
  1273. in_delim = 0;
  1274. for (p = s; *p; p++)
  1275. if (in_delim) {
  1276. if (*p == delim[1])
  1277. in_delim = 0;
  1278. }
  1279. else if (*p == delim[0])
  1280. in_delim = 1;
  1281. else if (csdigit(*p))
  1282. possible_pos = p + 1 - s;
  1283. return possible_pos;
  1284. }
  1285. void table::add_entry(int r, int c, const string &str, const entry_format *f,
  1286. const char *fn, int ln)
  1287. {
  1288. allocate(r);
  1289. table_entry *e = 0;
  1290. if (str == "\\_") {
  1291. e = new short_line_entry(f);
  1292. }
  1293. else if (str == "\\=") {
  1294. e = new short_double_line_entry(f);
  1295. }
  1296. else if (str == "_") {
  1297. single_line_entry *lefte;
  1298. if (c > 0 && entry[r][c-1] != 0 &&
  1299. (lefte = entry[r][c-1]->to_single_line_entry()) != 0
  1300. && lefte->start_row == r
  1301. && lefte->mod->stagger == f->stagger) {
  1302. lefte->end_col = c;
  1303. entry[r][c] = lefte;
  1304. }
  1305. else
  1306. e = new single_line_entry(f);
  1307. }
  1308. else if (str == "=") {
  1309. double_line_entry *lefte;
  1310. if (c > 0 && entry[r][c-1] != 0 &&
  1311. (lefte = entry[r][c-1]->to_double_line_entry()) != 0
  1312. && lefte->start_row == r
  1313. && lefte->mod->stagger == f->stagger) {
  1314. lefte->end_col = c;
  1315. entry[r][c] = lefte;
  1316. }
  1317. else
  1318. e = new double_line_entry(f);
  1319. }
  1320. else if (str == "\\^") {
  1321. do_vspan(r, c);
  1322. }
  1323. else if (str.length() > 2 && str[0] == '\\' && str[1] == 'R') {
  1324. if (str.search('\n') >= 0)
  1325. error_with_file_and_line(fn, ln, "bad repeated character");
  1326. else {
  1327. char *s = str.substring(2, str.length() - 2).extract();
  1328. e = new repeated_char_entry(s, f);
  1329. }
  1330. }
  1331. else {
  1332. int is_block = str.search('\n') >= 0;
  1333. char *s;
  1334. switch (f->type) {
  1335. case FORMAT_SPAN:
  1336. assert(str.empty());
  1337. do_hspan(r, c);
  1338. break;
  1339. case FORMAT_LEFT:
  1340. if (!str.empty()) {
  1341. s = str.extract();
  1342. if (is_block)
  1343. e = new left_block_entry(s, f);
  1344. else
  1345. e = new left_text_entry(s, f);
  1346. }
  1347. else
  1348. e = new empty_entry(f);
  1349. break;
  1350. case FORMAT_CENTER:
  1351. if (!str.empty()) {
  1352. s = str.extract();
  1353. if (is_block)
  1354. e = new center_block_entry(s, f);
  1355. else
  1356. e = new center_text_entry(s, f);
  1357. }
  1358. else
  1359. e = new empty_entry(f);
  1360. break;
  1361. case FORMAT_RIGHT:
  1362. if (!str.empty()) {
  1363. s = str.extract();
  1364. if (is_block)
  1365. e = new right_block_entry(s, f);
  1366. else
  1367. e = new right_text_entry(s, f);
  1368. }
  1369. else
  1370. e = new empty_entry(f);
  1371. break;
  1372. case FORMAT_NUMERIC:
  1373. if (!str.empty()) {
  1374. s = str.extract();
  1375. if (is_block) {
  1376. error_with_file_and_line(fn, ln, "can't have numeric text block");
  1377. e = new left_block_entry(s, f);
  1378. }
  1379. else {
  1380. int pos = find_decimal_point(s, decimal_point_char, delim);
  1381. if (pos < 0)
  1382. e = new center_text_entry(s, f);
  1383. else
  1384. e = new numeric_text_entry(s, f, pos);
  1385. }
  1386. }
  1387. else
  1388. e = new empty_entry(f);
  1389. break;
  1390. case FORMAT_ALPHABETIC:
  1391. if (!str.empty()) {
  1392. s = str.extract();
  1393. if (is_block)
  1394. e = new alphabetic_block_entry(s, f);
  1395. else
  1396. e = new alphabetic_text_entry(s, f);
  1397. }
  1398. else
  1399. e = new empty_entry(f);
  1400. break;
  1401. case FORMAT_VSPAN:
  1402. do_vspan(r, c);
  1403. break;
  1404. case FORMAT_HLINE:
  1405. if (str.length() != 0)
  1406. error_with_file_and_line(fn, ln,
  1407. "non-empty data entry for `_' format ignored");
  1408. e = new single_line_entry(f);
  1409. break;
  1410. case FORMAT_DOUBLE_HLINE:
  1411. if (str.length() != 0)
  1412. error_with_file_and_line(fn, ln,
  1413. "non-empty data entry for `=' format ignored");
  1414. e = new double_line_entry(f);
  1415. break;
  1416. default:
  1417. assert(0);
  1418. }
  1419. }
  1420. if (e) {
  1421. table_entry *preve = entry[r][c];
  1422. if (preve) {
  1423. /* c s
  1424. ^ l */
  1425. error_with_file_and_line(fn, ln, "row %1, column %2 already spanned",
  1426. r + 1, c + 1);
  1427. delete e;
  1428. }
  1429. else {
  1430. e->input_lineno = ln;
  1431. e->input_filename = fn;
  1432. e->start_row = e->end_row = r;
  1433. e->start_col = e->end_col = c;
  1434. *entry_list_tailp = e;
  1435. entry_list_tailp = &e->next;
  1436. entry[r][c] = e;
  1437. }
  1438. }
  1439. }
  1440. // add vertical lines for row r
  1441. void table::add_vlines(int r, const char *v)
  1442. {
  1443. allocate(r);
  1444. for (int i = 0; i < ncolumns+1; i++)
  1445. vline[r][i] = v[i];
  1446. }
  1447. void table::check()
  1448. {
  1449. table_entry *p = entry_list;
  1450. int i, j;
  1451. while (p) {
  1452. for (i = p->start_row; i <= p->end_row; i++)
  1453. for (j = p->start_col; j <= p->end_col; j++)
  1454. assert(entry[i][j] == p);
  1455. p = p->next;
  1456. }
  1457. }
  1458. void table::print()
  1459. {
  1460. location_force_filename = 1;
  1461. check();
  1462. init_output();
  1463. determine_row_type();
  1464. compute_widths();
  1465. if (!(flags & CENTER))
  1466. prints(".if \\n[" SAVED_CENTER_REG "] \\{");
  1467. prints(".in +(u;\\n[.l]-\\n[.i]-\\n[TW]/2>?-\\n[.i])\n"
  1468. ".nr " SAVED_INDENT_REG " \\n[.i]\n");
  1469. if (!(flags & CENTER))
  1470. prints(".\\}\n");
  1471. build_vrule_list();
  1472. define_bottom_macro();
  1473. do_top();
  1474. for (int i = 0; i < nrows; i++)
  1475. do_row(i);
  1476. do_bottom();
  1477. }
  1478. void table::determine_row_type()
  1479. {
  1480. row_is_all_lines = new char[nrows];
  1481. for (int i = 0; i < nrows; i++) {
  1482. int had_single = 0;
  1483. int had_double = 0;
  1484. int had_non_line = 0;
  1485. for (int c = 0; c < ncolumns; c++) {
  1486. table_entry *e = entry[i][c];
  1487. if (e != 0) {
  1488. if (e->start_row == e->end_row) {
  1489. int t = e->line_type();
  1490. switch (t) {
  1491. case -1:
  1492. had_non_line = 1;
  1493. break;
  1494. case 0:
  1495. // empty
  1496. break;
  1497. case 1:
  1498. had_single = 1;
  1499. break;
  1500. case 2:
  1501. had_double = 1;
  1502. break;
  1503. default:
  1504. assert(0);
  1505. }
  1506. if (had_non_line)
  1507. break;
  1508. }
  1509. c = e->end_col;
  1510. }
  1511. }
  1512. if (had_non_line)
  1513. row_is_all_lines[i] = 0;
  1514. else if (had_double)
  1515. row_is_all_lines[i] = 2;
  1516. else if (had_single)
  1517. row_is_all_lines[i] = 1;
  1518. else
  1519. row_is_all_lines[i] = 0;
  1520. }
  1521. }
  1522. void table::init_output()
  1523. {
  1524. prints(".nr " COMPATIBLE_REG " \\n(.C\n"
  1525. ".cp 0\n");
  1526. if (linesize > 0)
  1527. printfs(".nr " LINESIZE_REG " %1\n", as_string(linesize));
  1528. else
  1529. prints(".nr " LINESIZE_REG " \\n[.s]\n");
  1530. if (!(flags & CENTER))
  1531. prints(".nr " SAVED_CENTER_REG " \\n[.ce]\n");
  1532. if (compatible_flag)
  1533. prints(".ds " LEADER_REG " \\a\n");
  1534. prints(".de " RESET_MACRO_NAME "\n"
  1535. ".ft \\n[.f]\n"
  1536. ".ps \\n[.s]\n"
  1537. ".vs \\n[.v]u\n"
  1538. ".in \\n[.i]u\n"
  1539. ".ll \\n[.l]u\n"
  1540. ".ls \\n[.L]\n"
  1541. ".ad \\n[.j]\n"
  1542. ".ie \\n[.u] .fi\n"
  1543. ".el .nf\n"
  1544. ".ce \\n[.ce]\n"
  1545. "..\n"
  1546. ".nr " SAVED_INDENT_REG " \\n[.i]\n"
  1547. ".nr " SAVED_FONT_REG " \\n[.f]\n"
  1548. ".nr " SAVED_SIZE_REG " \\n[.s]\n"
  1549. ".nr " SAVED_FILL_REG " \\n[.u]\n"
  1550. ".nr T. 0\n"
  1551. ".nr " CURRENT_ROW_REG " 0-1\n"
  1552. ".nr " LAST_PASSED_ROW_REG " 0-1\n"
  1553. ".nr " SECTION_DIVERSION_FLAG_REG " 0\n"
  1554. ".ds " TRANSPARENT_STRING_NAME "\n"
  1555. ".ds " QUOTE_STRING_NAME "\n"
  1556. ".nr " NEED_BOTTOM_RULE_REG " 1\n"
  1557. ".nr " SUPPRESS_BOTTOM_REG " 0\n"
  1558. ".eo\n"
  1559. ".de " REPEATED_MARK_MACRO "\n"
  1560. ".mk \\$1\n"
  1561. ".if !'\\n(.z'' \\!." REPEATED_MARK_MACRO " \"\\$1\"\n"
  1562. "..\n"
  1563. ".de " REPEATED_VPT_MACRO "\n"
  1564. ".vpt \\$1\n"
  1565. ".if !'\\n(.z'' \\!." REPEATED_VPT_MACRO " \"\\$1\"\n"
  1566. "..\n");
  1567. if (!(flags & NOKEEP))
  1568. prints(".de " KEEP_MACRO_NAME "\n"
  1569. ".if '\\n[.z]'' \\{.ds " QUOTE_STRING_NAME " \\\\\n"
  1570. ".ds " TRANSPARENT_STRING_NAME " \\!\n"
  1571. ".di " SECTION_DIVERSION_NAME "\n"
  1572. ".nr " SECTION_DIVERSION_FLAG_REG " 1\n"
  1573. ".in 0\n"
  1574. ".\\}\n"
  1575. "..\n"
  1576. ".de " RELEASE_MACRO_NAME "\n"
  1577. ".if \\n[" SECTION_DIVERSION_FLAG_REG "] \\{"
  1578. ".di\n"
  1579. ".in \\n[" SAVED_INDENT_REG "]u\n"
  1580. ".nr " SAVED_DN_REG " \\n[dn]\n"
  1581. ".ds " QUOTE_STRING_NAME "\n"
  1582. ".ds " TRANSPARENT_STRING_NAME "\n"
  1583. ".nr " SECTION_DIVERSION_FLAG_REG " 0\n"
  1584. ".if \\n[.t]<=\\n[dn] \\{"
  1585. ".nr T. 1\n"
  1586. ".T#\n"
  1587. ".nr " SUPPRESS_BOTTOM_REG " 1\n"
  1588. ".sp \\n[.t]u\n"
  1589. ".nr " SUPPRESS_BOTTOM_REG " 0\n"
  1590. ".mk #T\n"
  1591. ".\\}\n"
  1592. ".if \\n[.t]<=\\n[" SAVED_DN_REG "] "
  1593. /* Since we turn off traps, it won't get into an infinite loop
  1594. when we try and print it; it will just go off the bottom of the
  1595. page. */
  1596. ".tm warning: page \\n%: table text block will not fit on one page\n"
  1597. ".nf\n"
  1598. ".ls 1\n"
  1599. "." SECTION_DIVERSION_NAME "\n"
  1600. ".ls\n"
  1601. ".rm " SECTION_DIVERSION_NAME "\n"
  1602. ".\\}\n"
  1603. "..\n"
  1604. ".nr " TABLE_DIVERSION_FLAG_REG " 0\n"
  1605. ".de " TABLE_KEEP_MACRO_NAME "\n"
  1606. ".if '\\n[.z]'' \\{"
  1607. ".di " TABLE_DIVERSION_NAME "\n"
  1608. ".nr " TABLE_DIVERSION_FLAG_REG " 1\n"
  1609. ".\\}\n"
  1610. "..\n"
  1611. ".de " TABLE_RELEASE_MACRO_NAME "\n"
  1612. ".if \\n[" TABLE_DIVERSION_FLAG_REG "] \\{.br\n"
  1613. ".di\n"
  1614. ".nr " SAVED_DN_REG " \\n[dn]\n"
  1615. ".ne \\n[dn]u+\\n[.V]u\n"
  1616. ".ie \\n[.t]<=\\n[" SAVED_DN_REG "] "
  1617. ".tm error: page \\n%: table will not fit on one page; use .TS H/.TH with a supporting macro package\n"
  1618. ".el \\{"
  1619. ".in 0\n"
  1620. ".ls 1\n"
  1621. ".nf\n"
  1622. "." TABLE_DIVERSION_NAME "\n"
  1623. ".\\}\n"
  1624. ".rm " TABLE_DIVERSION_NAME "\n"
  1625. ".\\}\n"
  1626. "..\n");
  1627. prints(".ec\n"
  1628. ".ce 0\n"
  1629. ".nf\n");
  1630. }
  1631. string block_width_reg(int r, int c)
  1632. {
  1633. static char name[sizeof(BLOCK_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1634. sprintf(name, BLOCK_WIDTH_PREFIX "%d,%d", r, c);
  1635. return string(name);
  1636. }
  1637. string block_diversion_name(int r, int c)
  1638. {
  1639. static char name[sizeof(BLOCK_DIVERSION_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1640. sprintf(name, BLOCK_DIVERSION_PREFIX "%d,%d", r, c);
  1641. return string(name);
  1642. }
  1643. string block_height_reg(int r, int c)
  1644. {
  1645. static char name[sizeof(BLOCK_HEIGHT_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1646. sprintf(name, BLOCK_HEIGHT_PREFIX "%d,%d", r, c);
  1647. return string(name);
  1648. }
  1649. string span_width_reg(int start_col, int end_col)
  1650. {
  1651. static char name[sizeof(SPAN_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1652. sprintf(name, SPAN_WIDTH_PREFIX "%d", start_col);
  1653. if (end_col != start_col)
  1654. sprintf(strchr(name, '\0'), ",%d", end_col);
  1655. return string(name);
  1656. }
  1657. string span_left_numeric_width_reg(int start_col, int end_col)
  1658. {
  1659. static char name[sizeof(SPAN_LEFT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1660. sprintf(name, SPAN_LEFT_NUMERIC_WIDTH_PREFIX "%d", start_col);
  1661. if (end_col != start_col)
  1662. sprintf(strchr(name, '\0'), ",%d", end_col);
  1663. return string(name);
  1664. }
  1665. string span_right_numeric_width_reg(int start_col, int end_col)
  1666. {
  1667. static char name[sizeof(SPAN_RIGHT_NUMERIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1668. sprintf(name, SPAN_RIGHT_NUMERIC_WIDTH_PREFIX "%d", start_col);
  1669. if (end_col != start_col)
  1670. sprintf(strchr(name, '\0'), ",%d", end_col);
  1671. return string(name);
  1672. }
  1673. string span_alphabetic_width_reg(int start_col, int end_col)
  1674. {
  1675. static char name[sizeof(SPAN_ALPHABETIC_WIDTH_PREFIX)+INT_DIGITS+1+INT_DIGITS];
  1676. sprintf(name, SPAN_ALPHABETIC_WIDTH_PREFIX "%d", start_col);
  1677. if (end_col != start_col)
  1678. sprintf(strchr(name, '\0'), ",%d", end_col);
  1679. return string(name);
  1680. }
  1681. string column_separation_reg(int col)
  1682. {
  1683. static char name[sizeof(COLUMN_SEPARATION_PREFIX)+INT_DIGITS];
  1684. sprintf(name, COLUMN_SEPARATION_PREFIX "%d", col);
  1685. return string(name);
  1686. }
  1687. string row_start_reg(int row)
  1688. {
  1689. static char name[sizeof(ROW_START_PREFIX)+INT_DIGITS];
  1690. sprintf(name, ROW_START_PREFIX "%d", row);
  1691. return string(name);
  1692. }
  1693. string column_start_reg(int col)
  1694. {
  1695. static char name[sizeof(COLUMN_START_PREFIX)+INT_DIGITS];
  1696. sprintf(name, COLUMN_START_PREFIX "%d", col);
  1697. return string(name);
  1698. }
  1699. string column_end_reg(int col)
  1700. {
  1701. static char name[sizeof(COLUMN_END_PREFIX)+INT_DIGITS];
  1702. sprintf(name, COLUMN_END_PREFIX "%d", col);
  1703. return string(name);
  1704. }
  1705. string column_divide_reg(int col)
  1706. {
  1707. static char name[sizeof(COLUMN_DIVIDE_PREFIX)+INT_DIGITS];
  1708. sprintf(name, COLUMN_DIVIDE_PREFIX "%d", col);
  1709. return string(name);
  1710. }
  1711. string row_top_reg(int row)
  1712. {
  1713. static char name[sizeof(ROW_TOP_PREFIX)+INT_DIGITS];
  1714. sprintf(name, ROW_TOP_PREFIX "%d", row);
  1715. return string(name);
  1716. }
  1717. void init_span_reg(int start_col, int end_col)
  1718. {
  1719. printfs(".nr %1 \\n(.H\n.nr %2 0\n.nr %3 0\n.nr %4 0\n",
  1720. span_width_reg(start_col, end_col),
  1721. span_alphabetic_width_reg(start_col, end_col),
  1722. span_left_numeric_width_reg(start_col, end_col),
  1723. span_right_numeric_width_reg(start_col, end_col));
  1724. }
  1725. void compute_span_width(int start_col, int end_col)
  1726. {
  1727. printfs(".nr %1 \\n[%1]>?(\\n[%2]+\\n[%3])\n"
  1728. ".if \\n[%4] .nr %1 \\n[%1]>?(\\n[%4]+2n)\n",
  1729. span_width_reg(start_col, end_col),
  1730. span_left_numeric_width_reg(start_col, end_col),
  1731. span_right_numeric_width_reg(start_col, end_col),
  1732. span_alphabetic_width_reg(start_col, end_col));
  1733. }
  1734. // Increase the widths of columns so that the width of any spanning entry
  1735. // is not greater than the sum of the widths of the columns that it spans.
  1736. // Ensure that the widths of columns remain equal.
  1737. void table::divide_span(int start_col, int end_col)
  1738. {
  1739. assert(end_col > start_col);
  1740. printfs(".nr " NEEDED_REG " \\n[%1]-(\\n[%2]",
  1741. span_width_reg(start_col, end_col),
  1742. span_width_reg(start_col, start_col));
  1743. int i;
  1744. for (i = start_col + 1; i <= end_col; i++) {
  1745. // The column separation may shrink with the expand option.
  1746. if (!(flags & EXPAND))
  1747. printfs("+%1n", as_string(column_separation[i - 1]));
  1748. printfs("+\\n[%1]", span_width_reg(i, i));
  1749. }
  1750. prints(")\n");
  1751. printfs(".nr " NEEDED_REG " \\n[" NEEDED_REG "]/%1\n",
  1752. as_string(end_col - start_col + 1));
  1753. prints(".if \\n[" NEEDED_REG "] \\{");
  1754. for (i = start_col; i <= end_col; i++)
  1755. printfs(".nr %1 +\\n[" NEEDED_REG "]\n",
  1756. span_width_reg(i, i));
  1757. int equal_flag = 0;
  1758. for (i = start_col; i <= end_col && !equal_flag; i++)
  1759. if (equal[i])
  1760. equal_flag = 1;
  1761. if (equal_flag) {
  1762. for (i = 0; i < ncolumns; i++)
  1763. if (i < start_col || i > end_col)
  1764. printfs(".nr %1 +\\n[" NEEDED_REG "]\n",
  1765. span_width_reg(i, i));
  1766. }
  1767. prints(".\\}\n");
  1768. }
  1769. void table::sum_columns(int start_col, int end_col)
  1770. {
  1771. assert(end_col > start_col);
  1772. printfs(".nr %1 \\n[%2]",
  1773. span_width_reg(start_col, end_col),
  1774. span_width_reg(start_col, start_col));
  1775. for (int i = start_col + 1; i <= end_col; i++)
  1776. printfs("+(%1*\\n[" SEPARATION_FACTOR_REG "])+\\n[%2]",
  1777. as_string(column_separation[i - 1]),
  1778. span_width_reg(i, i));
  1779. prints('\n');
  1780. }
  1781. horizontal_span::horizontal_span(int sc, int ec, horizontal_span *p)
  1782. : next(p), start_col(sc), end_col(ec)
  1783. {
  1784. }
  1785. void table::build_span_list()
  1786. {
  1787. span_list = 0;
  1788. table_entry *p = entry_list;
  1789. while (p) {
  1790. if (p->end_col != p->start_col) {
  1791. horizontal_span *q;
  1792. for (q = span_list; q; q = q->next)
  1793. if (q->start_col == p->start_col
  1794. && q->end_col == p->end_col)
  1795. break;
  1796. if (!q)
  1797. span_list = new horizontal_span(p->start_col, p->end_col, span_list);
  1798. }
  1799. p = p->next;
  1800. }
  1801. // Now sort span_list primarily by order of end_row, and secondarily
  1802. // by reverse order of start_row. This ensures that if we divide
  1803. // spans using the order in span_list, we will get reasonable results.
  1804. horizontal_span *unsorted = span_list;
  1805. span_list = 0;
  1806. while (unsorted) {
  1807. horizontal_span **pp;
  1808. for (pp = &span_list; *pp; pp = &(*pp)->next)
  1809. if (unsorted->end_col < (*pp)->end_col
  1810. || (unsorted->end_col == (*pp)->end_col
  1811. && (unsorted->start_col > (*pp)->start_col)))
  1812. break;
  1813. horizontal_span *tem = unsorted->next;
  1814. unsorted->next = *pp;
  1815. *pp = unsorted;
  1816. unsorted = tem;
  1817. }
  1818. }
  1819. void table::compute_separation_factor()
  1820. {
  1821. if (flags & (ALLBOX|BOX|DOUBLEBOX))
  1822. left_separation = right_separation = 1;
  1823. else {
  1824. for (int i = 0; i < nrows; i++) {
  1825. if (vline[i][0] > 0)
  1826. left_separation = 1;
  1827. if (vline[i][ncolumns] > 0)
  1828. right_separation = 1;
  1829. }
  1830. }
  1831. if (flags & EXPAND) {
  1832. int total_sep = left_separation + right_separation;
  1833. int i;
  1834. for (i = 0; i < ncolumns - 1; i++)
  1835. total_sep += column_separation[i];
  1836. if (total_sep != 0) {
  1837. // Don't let the separation factor be negative.
  1838. prints(".nr " SEPARATION_FACTOR_REG " \\n[.l]-\\n[.i]");
  1839. for (i = 0; i < ncolumns; i++)
  1840. printfs("-\\n[%1]", span_width_reg(i, i));
  1841. printfs("/%1>?0\n", as_string(total_sep));
  1842. }
  1843. }
  1844. }
  1845. void table::compute_column_positions()
  1846. {
  1847. printfs(".nr %1 0\n", column_divide_reg(0));
  1848. printfs(".nr %1 %2*\\n[" SEPARATION_FACTOR_REG "]\n",
  1849. column_start_reg(0),
  1850. as_string(left_separation));
  1851. int i;
  1852. for (i = 1;; i++) {
  1853. printfs(".nr %1 \\n[%2]+\\n[%3]\n",
  1854. column_end_reg(i-1),
  1855. column_start_reg(i-1),
  1856. span_width_reg(i-1, i-1));
  1857. if (i >= ncolumns)
  1858. break;
  1859. printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n",
  1860. column_start_reg(i),
  1861. column_end_reg(i-1),
  1862. as_string(column_separation[i-1]));
  1863. printfs(".nr %1 \\n[%2]+\\n[%3]/2\n",
  1864. column_divide_reg(i),
  1865. column_end_reg(i-1),
  1866. column_start_reg(i));
  1867. }
  1868. printfs(".nr %1 \\n[%2]+(%3*\\n[" SEPARATION_FACTOR_REG "])\n",
  1869. column_divide_reg(ncolumns),
  1870. column_end_reg(i-1),
  1871. as_string(right_separation));
  1872. printfs(".nr TW \\n[%1]\n",
  1873. column_divide_reg(ncolumns));
  1874. if (flags & DOUBLEBOX) {
  1875. printfs(".nr %1 +" DOUBLE_LINE_SEP "\n", column_divide_reg(0));
  1876. printfs(".nr %1 -" DOUBLE_LINE_SEP "\n", column_divide_reg(ncolumns));
  1877. }
  1878. }
  1879. void table::make_columns_equal()
  1880. {
  1881. int first = -1; // index of first equal column
  1882. int i;
  1883. for (i = 0; i < ncolumns; i++)
  1884. if (equal[i]) {
  1885. if (first < 0) {
  1886. printfs(".nr %1 \\n[%1]", span_width_reg(i, i));
  1887. first = i;
  1888. }
  1889. else
  1890. printfs(">?\\n[%1]", span_width_reg(i, i));
  1891. }
  1892. if (first >= 0) {
  1893. prints('\n');
  1894. for (i = first + 1; i < ncolumns; i++)
  1895. if (equal[i])
  1896. printfs(".nr %1 \\n[%2]\n",
  1897. span_width_reg(i, i),
  1898. span_width_reg(first, first));
  1899. }
  1900. }
  1901. void table::compute_widths()
  1902. {
  1903. build_span_list();
  1904. int i;
  1905. horizontal_span *p;
  1906. prints(".nr " SEPARATION_FACTOR_REG " 1n\n");
  1907. for (i = 0; i < ncolumns; i++) {
  1908. init_span_reg(i, i);
  1909. if (!minimum_width[i].empty())
  1910. printfs(".nr %1 %2\n", span_width_reg(i, i), minimum_width[i]);
  1911. }
  1912. for (p = span_list; p; p = p->next)
  1913. init_span_reg(p->start_col, p->end_col);
  1914. table_entry *q;
  1915. for (q = entry_list; q; q = q->next)
  1916. if (!q->mod->zero_width)
  1917. q->do_width();
  1918. for (i = 0; i < ncolumns; i++)
  1919. compute_span_width(i, i);
  1920. for (p = span_list; p; p = p->next)
  1921. compute_span_width(p->start_col, p->end_col);
  1922. make_columns_equal();
  1923. // Note that divide_span keeps equal width columns equal.
  1924. for (p = span_list; p; p = p->next)
  1925. divide_span(p->start_col, p->end_col);
  1926. for (p = span_list; p; p = p->next)
  1927. sum_columns(p->start_col, p->end_col);
  1928. int had_spanning_block = 0;
  1929. int had_equal_block = 0;
  1930. for (q = entry_list; q; q = q->next)
  1931. if (q->divert(ncolumns, minimum_width,
  1932. (flags & EXPAND) ? column_separation : 0)) {
  1933. if (q->end_col > q->start_col)
  1934. had_spanning_block = 1;
  1935. for (i = q->start_col; i <= q->end_col && !had_equal_block; i++)
  1936. if (equal[i])
  1937. had_equal_block = 1;
  1938. }
  1939. if (had_equal_block)
  1940. make_columns_equal();
  1941. if (had_spanning_block)
  1942. for (p = span_list; p; p = p->next)
  1943. divide_span(p->start_col, p->end_col);
  1944. compute_separation_factor();
  1945. for (p = span_list; p; p = p->next)
  1946. sum_columns(p->start_col, p->end_col);
  1947. compute_column_positions();
  1948. }
  1949. void table::print_single_hline(int r)
  1950. {
  1951. prints(".vs " LINE_SEP ">?\\n[.V]u\n"
  1952. ".ls 1\n"
  1953. "\\v'" BODY_DEPTH "'"
  1954. "\\s[\\n[" LINESIZE_REG "]]");
  1955. if (r > nrows - 1)
  1956. prints("\\D'l |\\n[TW]u 0'");
  1957. else {
  1958. int start_col = 0;
  1959. for (;;) {
  1960. while (start_col < ncolumns
  1961. && entry[r][start_col] != 0
  1962. && entry[r][start_col]->start_row != r)
  1963. start_col++;
  1964. int end_col;
  1965. for (end_col = start_col;
  1966. end_col < ncolumns
  1967. && (entry[r][end_col] == 0
  1968. || entry[r][end_col]->start_row == r);
  1969. end_col++)
  1970. ;
  1971. if (end_col <= start_col)
  1972. break;
  1973. printfs("\\h'|\\n[%1]u",
  1974. column_divide_reg(start_col));
  1975. if ((r > 0 && vline[r-1][start_col] == 2)
  1976. || (r < nrows && vline[r][start_col] == 2))
  1977. prints("-" HALF_DOUBLE_LINE_SEP);
  1978. prints("'");
  1979. printfs("\\D'l |\\n[%1]u",
  1980. column_divide_reg(end_col));
  1981. if ((r > 0 && vline[r-1][end_col] == 2)
  1982. || (r < nrows && vline[r][end_col] == 2))
  1983. prints("+" HALF_DOUBLE_LINE_SEP);
  1984. prints(" 0'");
  1985. start_col = end_col;
  1986. }
  1987. }
  1988. prints("\\s0\n");
  1989. prints(".ls\n"
  1990. ".vs\n");
  1991. }
  1992. void table::print_double_hline(int r)
  1993. {
  1994. prints(".vs " LINE_SEP "+" DOUBLE_LINE_SEP
  1995. ">?\\n[.V]u\n"
  1996. ".ls 1\n"
  1997. "\\v'" BODY_DEPTH "'"
  1998. "\\s[\\n[" LINESIZE_REG "]]");
  1999. if (r > nrows - 1)
  2000. prints("\\v'-" DOUBLE_LINE_SEP "'"
  2001. "\\D'l |\\n[TW]u 0'"
  2002. "\\v'" DOUBLE_LINE_SEP "'"
  2003. "\\h'|0'"
  2004. "\\D'l |\\n[TW]u 0'");
  2005. else {
  2006. int start_col = 0;
  2007. for (;;) {
  2008. while (start_col < ncolumns
  2009. && entry[r][start_col] != 0
  2010. && entry[r][start_col]->start_row != r)
  2011. start_col++;
  2012. int end_col;
  2013. for (end_col = start_col;
  2014. end_col < ncolumns
  2015. && (entry[r][end_col] == 0
  2016. || entry[r][end_col]->start_row == r);
  2017. end_col++)
  2018. ;
  2019. if (end_col <= start_col)
  2020. break;
  2021. const char *left_adjust = 0;
  2022. if ((r > 0 && vline[r-1][start_col] == 2)
  2023. || (r < nrows && vline[r][start_col] == 2))
  2024. left_adjust = "-" HALF_DOUBLE_LINE_SEP;
  2025. const char *right_adjust = 0;
  2026. if ((r > 0 && vline[r-1][end_col] == 2)
  2027. || (r < nrows && vline[r][end_col] == 2))
  2028. right_adjust = "+" HALF_DOUBLE_LINE_SEP;
  2029. printfs("\\v'-" DOUBLE_LINE_SEP "'"
  2030. "\\h'|\\n[%1]u",
  2031. column_divide_reg(start_col));
  2032. if (left_adjust)
  2033. prints(left_adjust);
  2034. prints("'");
  2035. printfs("\\D'l |\\n[%1]u",
  2036. column_divide_reg(end_col));
  2037. if (right_adjust)
  2038. prints(right_adjust);
  2039. prints(" 0'");
  2040. printfs("\\v'" DOUBLE_LINE_SEP "'"
  2041. "\\h'|\\n[%1]u",
  2042. column_divide_reg(start_col));
  2043. if (left_adjust)
  2044. prints(left_adjust);
  2045. prints("'");
  2046. printfs("\\D'l |\\n[%1]u",
  2047. column_divide_reg(end_col));
  2048. if (right_adjust)
  2049. prints(right_adjust);
  2050. prints(" 0'");
  2051. start_col = end_col;
  2052. }
  2053. }
  2054. prints("\\s0\n"
  2055. ".ls\n"
  2056. ".vs\n");
  2057. }
  2058. void table::compute_vrule_top_adjust(int start_row, int col, string &result)
  2059. {
  2060. if (row_is_all_lines[start_row] && start_row < nrows - 1) {
  2061. if (row_is_all_lines[start_row] == 2)
  2062. result = LINE_SEP ">?\\n[.V]u" "+" DOUBLE_LINE_SEP;
  2063. else
  2064. result = LINE_SEP ">?\\n[.V]u";
  2065. start_row++;
  2066. }
  2067. else {
  2068. result = "";
  2069. if (start_row == 0)
  2070. return;
  2071. for (stuff *p = stuff_list; p && p->row <= start_row; p = p->next)
  2072. if (p->row == start_row
  2073. && (p->is_single_line() || p->is_double_line()))
  2074. return;
  2075. }
  2076. int left = 0;
  2077. if (col > 0) {
  2078. table_entry *e = entry[start_row-1][col-1];
  2079. if (e && e->start_row == e->end_row) {
  2080. if (e->to_double_line_entry() != 0)
  2081. left = 2;
  2082. else if (e->to_single_line_entry() != 0)
  2083. left = 1;
  2084. }
  2085. }
  2086. int right = 0;
  2087. if (col < ncolumns) {
  2088. table_entry *e = entry[start_row-1][col];
  2089. if (e && e->start_row == e->end_row) {
  2090. if (e->to_double_line_entry() != 0)
  2091. right = 2;
  2092. else if (e->to_single_line_entry() != 0)
  2093. right = 1;
  2094. }
  2095. }
  2096. if (row_is_all_lines[start_row-1] == 0) {
  2097. if (left > 0 || right > 0) {
  2098. result += "-" BODY_DEPTH "-" BAR_HEIGHT;
  2099. if ((left == 2 && right != 2) || (right == 2 && left != 2))
  2100. result += "-" HALF_DOUBLE_LINE_SEP;
  2101. else if (left == 2 && right == 2)
  2102. result += "+" HALF_DOUBLE_LINE_SEP;
  2103. }
  2104. }
  2105. else if (row_is_all_lines[start_row-1] == 2) {
  2106. if ((left == 2 && right != 2) || (right == 2 && left != 2))
  2107. result += "-" DOUBLE_LINE_SEP;
  2108. else if (left == 1 || right == 1)
  2109. result += "-" HALF_DOUBLE_LINE_SEP;
  2110. }
  2111. }
  2112. void table::compute_vrule_bot_adjust(int end_row, int col, string &result)
  2113. {
  2114. if (row_is_all_lines[end_row] && end_row > 0) {
  2115. end_row--;
  2116. result = "";
  2117. }
  2118. else {
  2119. stuff *p;
  2120. for (p = stuff_list; p && p->row < end_row + 1; p = p->next)
  2121. ;
  2122. if (p && p->row == end_row + 1 && p->is_double_line()) {
  2123. result = "-" DOUBLE_LINE_SEP;
  2124. return;
  2125. }
  2126. if ((p != 0 && p->row == end_row + 1)
  2127. || end_row == nrows - 1) {
  2128. result = "";
  2129. return;
  2130. }
  2131. if (row_is_all_lines[end_row+1] == 1)
  2132. result = LINE_SEP;
  2133. else if (row_is_all_lines[end_row+1] == 2)
  2134. result = LINE_SEP "+" DOUBLE_LINE_SEP;
  2135. else
  2136. result = "";
  2137. }
  2138. int left = 0;
  2139. if (col > 0) {
  2140. table_entry *e = entry[end_row+1][col-1];
  2141. if (e && e->start_row == e->end_row) {
  2142. if (e->to_double_line_entry() != 0)
  2143. left = 2;
  2144. else if (e->to_single_line_entry() != 0)
  2145. left = 1;
  2146. }
  2147. }
  2148. int right = 0;
  2149. if (col < ncolumns) {
  2150. table_entry *e = entry[end_row+1][col];
  2151. if (e && e->start_row == e->end_row) {
  2152. if (e->to_double_line_entry() != 0)
  2153. right = 2;
  2154. else if (e->to_single_line_entry() != 0)
  2155. right = 1;
  2156. }
  2157. }
  2158. if (row_is_all_lines[end_row+1] == 0) {
  2159. if (left > 0 || right > 0) {
  2160. result = "1v-" BODY_DEPTH "-" BAR_HEIGHT;
  2161. if ((left == 2 && right != 2) || (right == 2 && left != 2))
  2162. result += "+" HALF_DOUBLE_LINE_SEP;
  2163. else if (left == 2 && right == 2)
  2164. result += "-" HALF_DOUBLE_LINE_SEP;
  2165. }
  2166. }
  2167. else if (row_is_all_lines[end_row+1] == 2) {
  2168. if (left == 2 && right == 2)
  2169. result += "-" DOUBLE_LINE_SEP;
  2170. else if (left != 2 && right != 2 && (left == 1 || right == 1))
  2171. result += "-" HALF_DOUBLE_LINE_SEP;
  2172. }
  2173. }
  2174. void table::add_vertical_rule(int start_row, int end_row, int col, int is_double)
  2175. {
  2176. vrule_list = new vertical_rule(start_row, end_row, col, is_double,
  2177. vrule_list);
  2178. compute_vrule_top_adjust(start_row, col, vrule_list->top_adjust);
  2179. compute_vrule_bot_adjust(end_row, col, vrule_list->bot_adjust);
  2180. }
  2181. void table::build_vrule_list()
  2182. {
  2183. int col;
  2184. if (flags & ALLBOX) {
  2185. for (col = 1; col < ncolumns; col++) {
  2186. int start_row = 0;
  2187. for (;;) {
  2188. while (start_row < nrows && vline_spanned(start_row, col))
  2189. start_row++;
  2190. if (start_row >= nrows)
  2191. break;
  2192. int end_row = start_row;
  2193. while (end_row < nrows && !vline_spanned(end_row, col))
  2194. end_row++;
  2195. end_row--;
  2196. add_vertical_rule(start_row, end_row, col, 0);
  2197. start_row = end_row + 1;
  2198. }
  2199. }
  2200. }
  2201. if (flags & (BOX|ALLBOX|DOUBLEBOX)) {
  2202. add_vertical_rule(0, nrows - 1, 0, 0);
  2203. add_vertical_rule(0, nrows - 1, ncolumns, 0);
  2204. }
  2205. for (int end_row = 0; end_row < nrows; end_row++)
  2206. for (col = 0; col < ncolumns+1; col++)
  2207. if (vline[end_row][col] > 0
  2208. && !vline_spanned(end_row, col)
  2209. && (end_row == nrows - 1
  2210. || vline[end_row+1][col] != vline[end_row][col]
  2211. || vline_spanned(end_row+1, col))) {
  2212. int start_row;
  2213. for (start_row = end_row - 1;
  2214. start_row >= 0
  2215. && vline[start_row][col] == vline[end_row][col]
  2216. && !vline_spanned(start_row, col);
  2217. start_row--)
  2218. ;
  2219. start_row++;
  2220. add_vertical_rule(start_row, end_row, col, vline[end_row][col] > 1);
  2221. }
  2222. for (vertical_rule *p = vrule_list; p; p = p->next)
  2223. if (p->is_double)
  2224. for (int r = p->start_row; r <= p->end_row; r++) {
  2225. if (p->col > 0 && entry[r][p->col-1] != 0
  2226. && entry[r][p->col-1]->end_col == p->col-1) {
  2227. int is_corner = r == p->start_row || r == p->end_row;
  2228. entry[r][p->col-1]->note_double_vrule_on_right(is_corner);
  2229. }
  2230. if (p->col < ncolumns && entry[r][p->col] != 0
  2231. && entry[r][p->col]->start_col == p->col) {
  2232. int is_corner = r == p->start_row || r == p->end_row;
  2233. entry[r][p->col]->note_double_vrule_on_left(is_corner);
  2234. }
  2235. }
  2236. }
  2237. void table::define_bottom_macro()
  2238. {
  2239. prints(".eo\n"
  2240. ".de T#\n"
  2241. ".if !\\n[" SUPPRESS_BOTTOM_REG "] \\{"
  2242. "." REPEATED_VPT_MACRO " 0\n"
  2243. ".mk " SAVED_VERTICAL_POS_REG "\n");
  2244. if (flags & (BOX|ALLBOX|DOUBLEBOX)) {
  2245. prints(".if \\n[T.]&\\n[" NEED_BOTTOM_RULE_REG "] \\{");
  2246. print_single_hline(0);
  2247. prints(".\\}\n");
  2248. }
  2249. prints(".ls 1\n");
  2250. for (vertical_rule *p = vrule_list; p; p = p->next)
  2251. p->contribute_to_bottom_macro(this);
  2252. if (flags & DOUBLEBOX)
  2253. prints(".if \\n[T.] \\{.vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n"
  2254. "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]"
  2255. "\\D'l \\n[TW]u 0'\\s0\n"
  2256. ".vs\n"
  2257. ".\\}\n"
  2258. ".if \\n[" LAST_PASSED_ROW_REG "]>=0 "
  2259. ".nr " TOP_REG " \\n[#T]-" DOUBLE_LINE_SEP "\n"
  2260. ".sp -1\n"
  2261. "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]"
  2262. "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n"
  2263. ".sp -1\n"
  2264. "\\v'" BODY_DEPTH "'\\h'|\\n[TW]u'\\s[\\n[" LINESIZE_REG "]]"
  2265. "\\D'l 0 |\\n[" TOP_REG "]u-1v'\\s0\n");
  2266. prints(".ls\n");
  2267. prints(".nr " LAST_PASSED_ROW_REG " \\n[" CURRENT_ROW_REG "]\n"
  2268. ".sp |\\n[" SAVED_VERTICAL_POS_REG "]u\n"
  2269. "." REPEATED_VPT_MACRO " 1\n"
  2270. ".\\}\n"
  2271. "..\n"
  2272. ".ec\n");
  2273. }
  2274. // is the vertical line before column c in row r horizontally spanned?
  2275. int table::vline_spanned(int r, int c)
  2276. {
  2277. assert(r >= 0 && r < nrows && c >= 0 && c < ncolumns + 1);
  2278. return (c != 0 && c != ncolumns && entry[r][c] != 0
  2279. && entry[r][c]->start_col != c
  2280. // horizontally spanning lines don't count
  2281. && entry[r][c]->to_double_line_entry() == 0
  2282. && entry[r][c]->to_single_line_entry() == 0);
  2283. }
  2284. int table::row_begins_section(int r)
  2285. {
  2286. assert(r >= 0 && r < nrows);
  2287. for (int i = 0; i < ncolumns; i++)
  2288. if (entry[r][i] && entry[r][i]->start_row != r)
  2289. return 0;
  2290. return 1;
  2291. }
  2292. int table::row_ends_section(int r)
  2293. {
  2294. assert(r >= 0 && r < nrows);
  2295. for (int i = 0; i < ncolumns; i++)
  2296. if (entry[r][i] && entry[r][i]->end_row != r)
  2297. return 0;
  2298. return 1;
  2299. }
  2300. void table::do_row(int r)
  2301. {
  2302. if (!(flags & NOKEEP) && row_begins_section(r))
  2303. prints("." KEEP_MACRO_NAME "\n");
  2304. int had_line = 0;
  2305. stuff *p;
  2306. for (p = stuff_list; p && p->row < r; p = p->next)
  2307. ;
  2308. for (stuff *p1 = p; p1 && p1->row == r; p1 = p1->next)
  2309. if (!p1->printed && (p1->is_single_line() || p1->is_double_line())) {
  2310. had_line = 1;
  2311. break;
  2312. }
  2313. if (!had_line && !row_is_all_lines[r])
  2314. printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
  2315. had_line = 0;
  2316. for (; p && p->row == r; p = p->next)
  2317. if (!p->printed) {
  2318. p->print(this);
  2319. if (!had_line && (p->is_single_line() || p->is_double_line())) {
  2320. printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
  2321. had_line = 1;
  2322. }
  2323. }
  2324. // Change the row *after* printing the stuff list (which might contain .TH).
  2325. printfs("\\*[" TRANSPARENT_STRING_NAME "].nr " CURRENT_ROW_REG " %1\n",
  2326. as_string(r));
  2327. if (!had_line && row_is_all_lines[r])
  2328. printfs("." REPEATED_MARK_MACRO " %1\n", row_top_reg(r));
  2329. // we might have had a .TH, for example, since we last tried
  2330. if (!(flags & NOKEEP) && row_begins_section(r))
  2331. prints("." KEEP_MACRO_NAME "\n");
  2332. printfs(".mk %1\n", row_start_reg(r));
  2333. prints(".mk " BOTTOM_REG "\n"
  2334. "." REPEATED_VPT_MACRO " 0\n");
  2335. int c;
  2336. int row_is_blank = 1;
  2337. int first_start_row = r;
  2338. for (c = 0; c < ncolumns; c++) {
  2339. table_entry *e = entry[r][c];
  2340. if (e) {
  2341. if (e->end_row == r) {
  2342. e->do_depth();
  2343. if (e->start_row < first_start_row)
  2344. first_start_row = e->start_row;
  2345. row_is_blank = 0;
  2346. }
  2347. c = e->end_col;
  2348. }
  2349. }
  2350. if (row_is_blank)
  2351. prints(".nr " BOTTOM_REG " +1v\n");
  2352. if (row_is_all_lines[r]) {
  2353. prints(".vs " LINE_SEP);
  2354. if (row_is_all_lines[r] == 2)
  2355. prints("+" DOUBLE_LINE_SEP);
  2356. prints(">?\\n[.V]u\n.ls 1\n");
  2357. prints("\\&");
  2358. prints("\\v'" BODY_DEPTH);
  2359. if (row_is_all_lines[r] == 2)
  2360. prints("-" HALF_DOUBLE_LINE_SEP);
  2361. prints("'");
  2362. for (c = 0; c < ncolumns; c++) {
  2363. table_entry *e = entry[r][c];
  2364. if (e) {
  2365. if (e->end_row == e->start_row)
  2366. e->to_simple_entry()->simple_print(1);
  2367. c = e->end_col;
  2368. }
  2369. }
  2370. prints("\n");
  2371. prints(".ls\n"
  2372. ".vs\n");
  2373. prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
  2374. printfs(".sp |\\n[%1]u\n", row_start_reg(r));
  2375. }
  2376. for (int i = row_is_all_lines[r] ? r - 1 : r;
  2377. i >= first_start_row;
  2378. i--) {
  2379. simple_entry *first = 0;
  2380. for (c = 0; c < ncolumns; c++) {
  2381. table_entry *e = entry[r][c];
  2382. if (e) {
  2383. if (e->end_row == r && e->start_row == i) {
  2384. simple_entry *simple = e->to_simple_entry();
  2385. if (simple) {
  2386. if (!first) {
  2387. prints(".ta");
  2388. first = simple;
  2389. }
  2390. simple->add_tab();
  2391. }
  2392. }
  2393. c = e->end_col;
  2394. }
  2395. }
  2396. if (first) {
  2397. prints('\n');
  2398. first->position_vertically();
  2399. first->set_location();
  2400. prints("\\&");
  2401. first->simple_print(0);
  2402. for (c = first->end_col + 1; c < ncolumns; c++) {
  2403. table_entry *e = entry[r][c];
  2404. if (e) {
  2405. if (e->end_row == r && e->start_row == i) {
  2406. simple_entry *simple = e->to_simple_entry();
  2407. if (simple) {
  2408. if (e->end_row != e->start_row) {
  2409. prints('\n');
  2410. simple->position_vertically();
  2411. prints("\\&");
  2412. }
  2413. simple->simple_print(0);
  2414. }
  2415. }
  2416. c = e->end_col;
  2417. }
  2418. }
  2419. prints('\n');
  2420. prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
  2421. printfs(".sp |\\n[%1]u\n", row_start_reg(r));
  2422. }
  2423. }
  2424. for (c = 0; c < ncolumns; c++) {
  2425. table_entry *e = entry[r][c];
  2426. if (e) {
  2427. if (e->end_row == r && e->to_simple_entry() == 0) {
  2428. e->position_vertically();
  2429. e->print();
  2430. prints(".nr " BOTTOM_REG " \\n[" BOTTOM_REG "]>?\\n[.d]\n");
  2431. printfs(".sp |\\n[%1]u\n", row_start_reg(r));
  2432. }
  2433. c = e->end_col;
  2434. }
  2435. }
  2436. prints("." REPEATED_VPT_MACRO " 1\n"
  2437. ".sp |\\n[" BOTTOM_REG "]u\n"
  2438. "\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 1\n");
  2439. if (r != nrows - 1 && (flags & ALLBOX)) {
  2440. print_single_hline(r + 1);
  2441. prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG " 0\n");
  2442. }
  2443. if (r != nrows - 1) {
  2444. if (p && p->row == r + 1
  2445. && (p->is_single_line() || p->is_double_line())) {
  2446. p->print(this);
  2447. prints("\\*[" TRANSPARENT_STRING_NAME "].nr " NEED_BOTTOM_RULE_REG
  2448. " 0\n");
  2449. }
  2450. int printed_one = 0;
  2451. for (vertical_rule *vr = vrule_list; vr; vr = vr->next)
  2452. if (vr->end_row == r) {
  2453. if (!printed_one) {
  2454. prints("." REPEATED_VPT_MACRO " 0\n");
  2455. printed_one = 1;
  2456. }
  2457. vr->print();
  2458. }
  2459. if (printed_one)
  2460. prints("." REPEATED_VPT_MACRO " 1\n");
  2461. if (!(flags & NOKEEP) && row_ends_section(r))
  2462. prints("." RELEASE_MACRO_NAME "\n");
  2463. }
  2464. }
  2465. void table::do_top()
  2466. {
  2467. prints(".fc \002\003\n");
  2468. if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX)))
  2469. prints("." TABLE_KEEP_MACRO_NAME "\n");
  2470. if (flags & DOUBLEBOX) {
  2471. prints(".ls 1\n"
  2472. ".vs " LINE_SEP ">?\\n[.V]u\n"
  2473. "\\v'" BODY_DEPTH "'\\s[\\n[" LINESIZE_REG "]]\\D'l \\n[TW]u 0'\\s0\n"
  2474. ".vs\n"
  2475. "." REPEATED_MARK_MACRO " " TOP_REG "\n"
  2476. ".vs " DOUBLE_LINE_SEP ">?\\n[.V]u\n");
  2477. printfs("\\v'" BODY_DEPTH "'"
  2478. "\\s[\\n[" LINESIZE_REG "]]"
  2479. "\\h'\\n[%1]u'"
  2480. "\\D'l |\\n[%2]u 0'"
  2481. "\\s0"
  2482. "\n",
  2483. column_divide_reg(0),
  2484. column_divide_reg(ncolumns));
  2485. prints(".ls\n"
  2486. ".vs\n");
  2487. }
  2488. else if (flags & (ALLBOX|BOX)) {
  2489. print_single_hline(0);
  2490. }
  2491. //printfs(".mk %1\n", row_top_reg(0));
  2492. }
  2493. void table::do_bottom()
  2494. {
  2495. // print stuff after last row
  2496. for (stuff *p = stuff_list; p; p = p->next)
  2497. if (p->row > nrows - 1)
  2498. p->print(this);
  2499. if (!(flags & NOKEEP))
  2500. prints("." RELEASE_MACRO_NAME "\n");
  2501. printfs(".mk %1\n", row_top_reg(nrows));
  2502. prints(".nr " NEED_BOTTOM_RULE_REG " 1\n"
  2503. ".nr T. 1\n"
  2504. ".T#\n");
  2505. if (!(flags & NOKEEP) && (flags & (BOX|DOUBLEBOX|ALLBOX)))
  2506. prints("." TABLE_RELEASE_MACRO_NAME "\n");
  2507. if (flags & DOUBLEBOX)
  2508. prints(".sp " DOUBLE_LINE_SEP "\n");
  2509. prints("." RESET_MACRO_NAME "\n"
  2510. ".fc\n"
  2511. ".cp \\n(" COMPATIBLE_REG "\n");
  2512. }
  2513. int table::get_nrows()
  2514. {
  2515. return nrows;
  2516. }
  2517. const char *last_filename = 0;
  2518. void set_troff_location(const char *fn, int ln)
  2519. {
  2520. if (!location_force_filename && last_filename != 0
  2521. && strcmp(fn, last_filename) == 0)
  2522. printfs(".lf %1\n", as_string(ln));
  2523. else {
  2524. printfs(".lf %1 %2\n", as_string(ln), fn);
  2525. last_filename = fn;
  2526. location_force_filename = 0;
  2527. }
  2528. }
  2529. void printfs(const char *s, const string &arg1, const string &arg2,
  2530. const string &arg3, const string &arg4, const string &arg5)
  2531. {
  2532. if (s) {
  2533. char c;
  2534. while ((c = *s++) != '\0') {
  2535. if (c == '%') {
  2536. switch (*s++) {
  2537. case '1':
  2538. prints(arg1);
  2539. break;
  2540. case '2':
  2541. prints(arg2);
  2542. break;
  2543. case '3':
  2544. prints(arg3);
  2545. break;
  2546. case '4':
  2547. prints(arg4);
  2548. break;
  2549. case '5':
  2550. prints(arg5);
  2551. break;
  2552. case '6':
  2553. case '7':
  2554. case '8':
  2555. case '9':
  2556. break;
  2557. case '%':
  2558. prints('%');
  2559. break;
  2560. default:
  2561. assert(0);
  2562. }
  2563. }
  2564. else
  2565. prints(c);
  2566. }
  2567. }
  2568. }