/contrib/groff/src/roff/troff/node.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 6482 lines · 5629 code · 741 blank · 112 comment · 944 complexity · e517a17900a0b49bc72513e34d6fdf9d MD5 · raw file

Large files are truncated click here to view the full file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
  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. extern int debug_state;
  18. #include "troff.h"
  19. #ifdef HAVE_UNISTD_H
  20. #include <unistd.h>
  21. #endif
  22. #include "dictionary.h"
  23. #include "hvunits.h"
  24. #include "stringclass.h"
  25. #include "mtsm.h"
  26. #include "env.h"
  27. #include "request.h"
  28. #include "node.h"
  29. #include "token.h"
  30. #include "div.h"
  31. #include "reg.h"
  32. #include "charinfo.h"
  33. #include "font.h"
  34. #include "input.h"
  35. #include "geometry.h"
  36. #include "nonposix.h"
  37. #ifdef _POSIX_VERSION
  38. #include <sys/wait.h>
  39. #else /* not _POSIX_VERSION */
  40. /* traditional Unix */
  41. #define WIFEXITED(s) (((s) & 0377) == 0)
  42. #define WEXITSTATUS(s) (((s) >> 8) & 0377)
  43. #define WTERMSIG(s) ((s) & 0177)
  44. #define WIFSTOPPED(s) (((s) & 0377) == 0177)
  45. #define WSTOPSIG(s) (((s) >> 8) & 0377)
  46. #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
  47. #endif /* not _POSIX_VERSION */
  48. // declarations to avoid friend name injections
  49. class tfont;
  50. class tfont_spec;
  51. tfont *make_tfont(tfont_spec &);
  52. /*
  53. * how many boundaries of images have been written? Useful for
  54. * debugging grohtml
  55. */
  56. int image_no = 0;
  57. static int suppress_start_page = 0;
  58. #define STORE_WIDTH 1
  59. symbol HYPHEN_SYMBOL("hy");
  60. // Character used when a hyphen is inserted at a line break.
  61. static charinfo *soft_hyphen_char;
  62. enum constant_space_type {
  63. CONSTANT_SPACE_NONE,
  64. CONSTANT_SPACE_RELATIVE,
  65. CONSTANT_SPACE_ABSOLUTE
  66. };
  67. struct special_font_list {
  68. int n;
  69. special_font_list *next;
  70. };
  71. special_font_list *global_special_fonts;
  72. static int global_ligature_mode = 1;
  73. static int global_kern_mode = 1;
  74. class track_kerning_function {
  75. int non_zero;
  76. units min_size;
  77. hunits min_amount;
  78. units max_size;
  79. hunits max_amount;
  80. public:
  81. track_kerning_function();
  82. track_kerning_function(units, hunits, units, hunits);
  83. int operator==(const track_kerning_function &);
  84. int operator!=(const track_kerning_function &);
  85. hunits compute(int point_size);
  86. };
  87. // embolden fontno when this is the current font
  88. struct conditional_bold {
  89. conditional_bold *next;
  90. int fontno;
  91. hunits offset;
  92. conditional_bold(int, hunits, conditional_bold * = 0);
  93. };
  94. class font_info {
  95. tfont *last_tfont;
  96. int number;
  97. font_size last_size;
  98. int last_height;
  99. int last_slant;
  100. symbol internal_name;
  101. symbol external_name;
  102. font *fm;
  103. char is_bold;
  104. hunits bold_offset;
  105. track_kerning_function track_kern;
  106. constant_space_type is_constant_spaced;
  107. units constant_space;
  108. int last_ligature_mode;
  109. int last_kern_mode;
  110. conditional_bold *cond_bold_list;
  111. void flush();
  112. public:
  113. special_font_list *sf;
  114. font_info(symbol, int, symbol, font *);
  115. int contains(charinfo *);
  116. void set_bold(hunits);
  117. void unbold();
  118. void set_conditional_bold(int, hunits);
  119. void conditional_unbold(int);
  120. void set_track_kern(track_kerning_function &);
  121. void set_constant_space(constant_space_type, units = 0);
  122. int is_named(symbol);
  123. symbol get_name();
  124. tfont *get_tfont(font_size, int, int, int);
  125. hunits get_space_width(font_size, int);
  126. hunits get_narrow_space_width(font_size);
  127. hunits get_half_narrow_space_width(font_size);
  128. int get_bold(hunits *);
  129. int is_special();
  130. int is_style();
  131. friend symbol get_font_name(int, environment *);
  132. friend symbol get_style_name(int);
  133. };
  134. class tfont_spec {
  135. protected:
  136. symbol name;
  137. int input_position;
  138. font *fm;
  139. font_size size;
  140. char is_bold;
  141. char is_constant_spaced;
  142. int ligature_mode;
  143. int kern_mode;
  144. hunits bold_offset;
  145. hunits track_kern; // add this to the width
  146. hunits constant_space_width;
  147. int height;
  148. int slant;
  149. public:
  150. tfont_spec(symbol, int, font *, font_size, int, int);
  151. tfont_spec(const tfont_spec &spec) { *this = spec; }
  152. tfont_spec plain();
  153. int operator==(const tfont_spec &);
  154. friend tfont *font_info::get_tfont(font_size fs, int, int, int);
  155. };
  156. class tfont : public tfont_spec {
  157. static tfont *tfont_list;
  158. tfont *next;
  159. tfont *plain_version;
  160. public:
  161. tfont(tfont_spec &);
  162. int contains(charinfo *);
  163. hunits get_width(charinfo *c);
  164. int get_bold(hunits *);
  165. int get_constant_space(hunits *);
  166. hunits get_track_kern();
  167. tfont *get_plain();
  168. font_size get_size();
  169. symbol get_name();
  170. charinfo *get_lig(charinfo *c1, charinfo *c2);
  171. int get_kern(charinfo *c1, charinfo *c2, hunits *res);
  172. int get_input_position();
  173. int get_character_type(charinfo *);
  174. int get_height();
  175. int get_slant();
  176. vunits get_char_height(charinfo *);
  177. vunits get_char_depth(charinfo *);
  178. hunits get_char_skew(charinfo *);
  179. hunits get_italic_correction(charinfo *);
  180. hunits get_left_italic_correction(charinfo *);
  181. hunits get_subscript_correction(charinfo *);
  182. friend tfont *make_tfont(tfont_spec &);
  183. };
  184. inline int env_definite_font(environment *env)
  185. {
  186. return env->get_family()->make_definite(env->get_font());
  187. }
  188. /* font_info functions */
  189. static font_info **font_table = 0;
  190. static int font_table_size = 0;
  191. font_info::font_info(symbol nm, int n, symbol enm, font *f)
  192. : last_tfont(0), number(n), last_size(0),
  193. internal_name(nm), external_name(enm), fm(f),
  194. is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
  195. last_kern_mode(1), cond_bold_list(0), sf(0)
  196. {
  197. }
  198. inline int font_info::contains(charinfo *ci)
  199. {
  200. return fm != 0 && fm->contains(ci->get_index());
  201. }
  202. inline int font_info::is_special()
  203. {
  204. return fm != 0 && fm->is_special();
  205. }
  206. inline int font_info::is_style()
  207. {
  208. return fm == 0;
  209. }
  210. tfont *make_tfont(tfont_spec &spec)
  211. {
  212. for (tfont *p = tfont::tfont_list; p; p = p->next)
  213. if (*p == spec)
  214. return p;
  215. return new tfont(spec);
  216. }
  217. // this is the current_font, fontno is where we found the character,
  218. // presumably a special font
  219. tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
  220. {
  221. if (last_tfont == 0 || fs != last_size
  222. || height != last_height || slant != last_slant
  223. || global_ligature_mode != last_ligature_mode
  224. || global_kern_mode != last_kern_mode
  225. || fontno != number) {
  226. font_info *f = font_table[fontno];
  227. tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
  228. for (conditional_bold *p = cond_bold_list; p; p = p->next)
  229. if (p->fontno == fontno) {
  230. spec.is_bold = 1;
  231. spec.bold_offset = p->offset;
  232. break;
  233. }
  234. if (!spec.is_bold && is_bold) {
  235. spec.is_bold = 1;
  236. spec.bold_offset = bold_offset;
  237. }
  238. spec.track_kern = track_kern.compute(fs.to_scaled_points());
  239. spec.ligature_mode = global_ligature_mode;
  240. spec.kern_mode = global_kern_mode;
  241. switch (is_constant_spaced) {
  242. case CONSTANT_SPACE_NONE:
  243. break;
  244. case CONSTANT_SPACE_ABSOLUTE:
  245. spec.is_constant_spaced = 1;
  246. spec.constant_space_width = constant_space;
  247. break;
  248. case CONSTANT_SPACE_RELATIVE:
  249. spec.is_constant_spaced = 1;
  250. spec.constant_space_width
  251. = scale(constant_space*fs.to_scaled_points(),
  252. units_per_inch,
  253. 36*72*sizescale);
  254. break;
  255. default:
  256. assert(0);
  257. }
  258. if (fontno != number)
  259. return make_tfont(spec);
  260. last_tfont = make_tfont(spec);
  261. last_size = fs;
  262. last_height = height;
  263. last_slant = slant;
  264. last_ligature_mode = global_ligature_mode;
  265. last_kern_mode = global_kern_mode;
  266. }
  267. return last_tfont;
  268. }
  269. int font_info::get_bold(hunits *res)
  270. {
  271. if (is_bold) {
  272. *res = bold_offset;
  273. return 1;
  274. }
  275. else
  276. return 0;
  277. }
  278. void font_info::unbold()
  279. {
  280. if (is_bold) {
  281. is_bold = 0;
  282. flush();
  283. }
  284. }
  285. void font_info::set_bold(hunits offset)
  286. {
  287. if (!is_bold || offset != bold_offset) {
  288. is_bold = 1;
  289. bold_offset = offset;
  290. flush();
  291. }
  292. }
  293. void font_info::set_conditional_bold(int fontno, hunits offset)
  294. {
  295. for (conditional_bold *p = cond_bold_list; p; p = p->next)
  296. if (p->fontno == fontno) {
  297. if (offset != p->offset) {
  298. p->offset = offset;
  299. flush();
  300. }
  301. return;
  302. }
  303. cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
  304. }
  305. conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
  306. : next(x), fontno(f), offset(h)
  307. {
  308. }
  309. void font_info::conditional_unbold(int fontno)
  310. {
  311. for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
  312. if ((*p)->fontno == fontno) {
  313. conditional_bold *tem = *p;
  314. *p = (*p)->next;
  315. delete tem;
  316. flush();
  317. return;
  318. }
  319. }
  320. void font_info::set_constant_space(constant_space_type type, units x)
  321. {
  322. if (type != is_constant_spaced
  323. || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
  324. flush();
  325. is_constant_spaced = type;
  326. constant_space = x;
  327. }
  328. }
  329. void font_info::set_track_kern(track_kerning_function &tk)
  330. {
  331. if (track_kern != tk) {
  332. track_kern = tk;
  333. flush();
  334. }
  335. }
  336. void font_info::flush()
  337. {
  338. last_tfont = 0;
  339. }
  340. int font_info::is_named(symbol s)
  341. {
  342. return internal_name == s;
  343. }
  344. symbol font_info::get_name()
  345. {
  346. return internal_name;
  347. }
  348. symbol get_font_name(int fontno, environment *env)
  349. {
  350. symbol f = font_table[fontno]->get_name();
  351. if (font_table[fontno]->is_style()) {
  352. return concat(env->get_family()->nm, f);
  353. }
  354. return f;
  355. }
  356. symbol get_style_name(int fontno)
  357. {
  358. if (font_table[fontno]->is_style())
  359. return font_table[fontno]->get_name();
  360. else
  361. return EMPTY_SYMBOL;
  362. }
  363. hunits font_info::get_space_width(font_size fs, int space_sz)
  364. {
  365. if (is_constant_spaced == CONSTANT_SPACE_NONE)
  366. return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
  367. space_sz, 12);
  368. else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
  369. return constant_space;
  370. else
  371. return scale(constant_space*fs.to_scaled_points(),
  372. units_per_inch, 36*72*sizescale);
  373. }
  374. hunits font_info::get_narrow_space_width(font_size fs)
  375. {
  376. charinfo *ci = get_charinfo(symbol("|"));
  377. if (fm->contains(ci->get_index()))
  378. return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
  379. else
  380. return hunits(fs.to_units()/6);
  381. }
  382. hunits font_info::get_half_narrow_space_width(font_size fs)
  383. {
  384. charinfo *ci = get_charinfo(symbol("^"));
  385. if (fm->contains(ci->get_index()))
  386. return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
  387. else
  388. return hunits(fs.to_units()/12);
  389. }
  390. /* tfont */
  391. tfont_spec::tfont_spec(symbol nm, int n, font *f,
  392. font_size s, int h, int sl)
  393. : name(nm), input_position(n), fm(f), size(s),
  394. is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
  395. height(h), slant(sl)
  396. {
  397. if (height == size.to_scaled_points())
  398. height = 0;
  399. }
  400. int tfont_spec::operator==(const tfont_spec &spec)
  401. {
  402. if (fm == spec.fm
  403. && size == spec.size
  404. && input_position == spec.input_position
  405. && name == spec.name
  406. && height == spec.height
  407. && slant == spec.slant
  408. && (is_bold
  409. ? (spec.is_bold && bold_offset == spec.bold_offset)
  410. : !spec.is_bold)
  411. && track_kern == spec.track_kern
  412. && (is_constant_spaced
  413. ? (spec.is_constant_spaced
  414. && constant_space_width == spec.constant_space_width)
  415. : !spec.is_constant_spaced)
  416. && ligature_mode == spec.ligature_mode
  417. && kern_mode == spec.kern_mode)
  418. return 1;
  419. else
  420. return 0;
  421. }
  422. tfont_spec tfont_spec::plain()
  423. {
  424. return tfont_spec(name, input_position, fm, size, height, slant);
  425. }
  426. hunits tfont::get_width(charinfo *c)
  427. {
  428. if (is_constant_spaced)
  429. return constant_space_width;
  430. else if (is_bold)
  431. return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
  432. + track_kern + bold_offset);
  433. else
  434. return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
  435. + track_kern);
  436. }
  437. vunits tfont::get_char_height(charinfo *c)
  438. {
  439. vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
  440. if (height != 0 && height != size.to_scaled_points())
  441. return scale(v, height, size.to_scaled_points());
  442. else
  443. return v;
  444. }
  445. vunits tfont::get_char_depth(charinfo *c)
  446. {
  447. vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
  448. if (height != 0 && height != size.to_scaled_points())
  449. return scale(v, height, size.to_scaled_points());
  450. else
  451. return v;
  452. }
  453. hunits tfont::get_char_skew(charinfo *c)
  454. {
  455. return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
  456. }
  457. hunits tfont::get_italic_correction(charinfo *c)
  458. {
  459. return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
  460. }
  461. hunits tfont::get_left_italic_correction(charinfo *c)
  462. {
  463. return hunits(fm->get_left_italic_correction(c->get_index(),
  464. size.to_scaled_points()));
  465. }
  466. hunits tfont::get_subscript_correction(charinfo *c)
  467. {
  468. return hunits(fm->get_subscript_correction(c->get_index(),
  469. size.to_scaled_points()));
  470. }
  471. inline int tfont::get_input_position()
  472. {
  473. return input_position;
  474. }
  475. inline int tfont::contains(charinfo *ci)
  476. {
  477. return fm->contains(ci->get_index());
  478. }
  479. inline int tfont::get_character_type(charinfo *ci)
  480. {
  481. return fm->get_character_type(ci->get_index());
  482. }
  483. inline int tfont::get_bold(hunits *res)
  484. {
  485. if (is_bold) {
  486. *res = bold_offset;
  487. return 1;
  488. }
  489. else
  490. return 0;
  491. }
  492. inline int tfont::get_constant_space(hunits *res)
  493. {
  494. if (is_constant_spaced) {
  495. *res = constant_space_width;
  496. return 1;
  497. }
  498. else
  499. return 0;
  500. }
  501. inline hunits tfont::get_track_kern()
  502. {
  503. return track_kern;
  504. }
  505. inline tfont *tfont::get_plain()
  506. {
  507. return plain_version;
  508. }
  509. inline font_size tfont::get_size()
  510. {
  511. return size;
  512. }
  513. inline symbol tfont::get_name()
  514. {
  515. return name;
  516. }
  517. inline int tfont::get_height()
  518. {
  519. return height;
  520. }
  521. inline int tfont::get_slant()
  522. {
  523. return slant;
  524. }
  525. symbol SYMBOL_ff("ff");
  526. symbol SYMBOL_fi("fi");
  527. symbol SYMBOL_fl("fl");
  528. symbol SYMBOL_Fi("Fi");
  529. symbol SYMBOL_Fl("Fl");
  530. charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
  531. {
  532. if (ligature_mode == 0)
  533. return 0;
  534. charinfo *ci = 0;
  535. if (c1->get_ascii_code() == 'f') {
  536. switch (c2->get_ascii_code()) {
  537. case 'f':
  538. if (fm->has_ligature(font::LIG_ff))
  539. ci = get_charinfo(SYMBOL_ff);
  540. break;
  541. case 'i':
  542. if (fm->has_ligature(font::LIG_fi))
  543. ci = get_charinfo(SYMBOL_fi);
  544. break;
  545. case 'l':
  546. if (fm->has_ligature(font::LIG_fl))
  547. ci = get_charinfo(SYMBOL_fl);
  548. break;
  549. }
  550. }
  551. else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
  552. switch (c2->get_ascii_code()) {
  553. case 'i':
  554. if (fm->has_ligature(font::LIG_ffi))
  555. ci = get_charinfo(SYMBOL_Fi);
  556. break;
  557. case 'l':
  558. if (fm->has_ligature(font::LIG_ffl))
  559. ci = get_charinfo(SYMBOL_Fl);
  560. break;
  561. }
  562. }
  563. if (ci != 0 && fm->contains(ci->get_index()))
  564. return ci;
  565. return 0;
  566. }
  567. inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
  568. {
  569. if (kern_mode == 0)
  570. return 0;
  571. else {
  572. int n = fm->get_kern(c1->get_index(),
  573. c2->get_index(),
  574. size.to_scaled_points());
  575. if (n) {
  576. *res = hunits(n);
  577. return 1;
  578. }
  579. else
  580. return 0;
  581. }
  582. }
  583. tfont *tfont::tfont_list = 0;
  584. tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
  585. {
  586. next = tfont_list;
  587. tfont_list = this;
  588. tfont_spec plain_spec = plain();
  589. tfont *p;
  590. for (p = tfont_list; p; p = p->next)
  591. if (*p == plain_spec) {
  592. plain_version = p;
  593. break;
  594. }
  595. if (!p)
  596. plain_version = new tfont(plain_spec);
  597. }
  598. /* output_file */
  599. class real_output_file : public output_file {
  600. #ifndef POPEN_MISSING
  601. int piped;
  602. #endif
  603. int printing; // decision via optional page list
  604. int output_on; // \O[0] or \O[1] escape calls
  605. virtual void really_transparent_char(unsigned char) = 0;
  606. virtual void really_print_line(hunits x, vunits y, node *n,
  607. vunits before, vunits after, hunits width) = 0;
  608. virtual void really_begin_page(int pageno, vunits page_length) = 0;
  609. virtual void really_copy_file(hunits x, vunits y, const char *filename);
  610. virtual void really_put_filename(const char *filename);
  611. virtual void really_on();
  612. virtual void really_off();
  613. public:
  614. FILE *fp;
  615. real_output_file();
  616. ~real_output_file();
  617. void flush();
  618. void transparent_char(unsigned char);
  619. void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
  620. void begin_page(int pageno, vunits page_length);
  621. void put_filename(const char *filename);
  622. void on();
  623. void off();
  624. int is_on();
  625. int is_printing();
  626. void copy_file(hunits x, vunits y, const char *filename);
  627. };
  628. class suppress_output_file : public real_output_file {
  629. public:
  630. suppress_output_file();
  631. void really_transparent_char(unsigned char);
  632. void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
  633. void really_begin_page(int pageno, vunits page_length);
  634. };
  635. class ascii_output_file : public real_output_file {
  636. public:
  637. ascii_output_file();
  638. void really_transparent_char(unsigned char);
  639. void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
  640. void really_begin_page(int pageno, vunits page_length);
  641. void outc(unsigned char c);
  642. void outs(const char *s);
  643. };
  644. void ascii_output_file::outc(unsigned char c)
  645. {
  646. fputc(c, fp);
  647. }
  648. void ascii_output_file::outs(const char *s)
  649. {
  650. fputc('<', fp);
  651. if (s)
  652. fputs(s, fp);
  653. fputc('>', fp);
  654. }
  655. struct hvpair;
  656. class troff_output_file : public real_output_file {
  657. units hpos;
  658. units vpos;
  659. units output_vpos;
  660. units output_hpos;
  661. int force_motion;
  662. int current_size;
  663. int current_slant;
  664. int current_height;
  665. tfont *current_tfont;
  666. color *current_fill_color;
  667. color *current_glyph_color;
  668. int current_font_number;
  669. symbol *font_position;
  670. int nfont_positions;
  671. enum { TBUF_SIZE = 256 };
  672. char tbuf[TBUF_SIZE];
  673. int tbuf_len;
  674. int tbuf_kern;
  675. int begun_page;
  676. int cur_div_level;
  677. string tag_list;
  678. void do_motion();
  679. void put(char c);
  680. void put(unsigned char c);
  681. void put(int i);
  682. void put(unsigned int i);
  683. void put(const char *s);
  684. void set_font(tfont *tf);
  685. void flush_tbuf();
  686. public:
  687. troff_output_file();
  688. ~troff_output_file();
  689. void trailer(vunits page_length);
  690. void put_char(charinfo *, tfont *, color *, color *);
  691. void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
  692. void right(hunits);
  693. void down(vunits);
  694. void moveto(hunits, vunits);
  695. void start_special(tfont *, color *, color *, int = 0);
  696. void start_special();
  697. void special_char(unsigned char c);
  698. void end_special();
  699. void word_marker();
  700. void really_transparent_char(unsigned char c);
  701. void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
  702. void really_begin_page(int pageno, vunits page_length);
  703. void really_copy_file(hunits x, vunits y, const char *filename);
  704. void really_put_filename(const char *filename);
  705. void really_on();
  706. void really_off();
  707. void draw(char, hvpair *, int, font_size, color *, color *);
  708. void determine_line_limits (char code, hvpair *point, int npoints);
  709. void check_charinfo(tfont *tf, charinfo *ci);
  710. void glyph_color(color *c);
  711. void fill_color(color *c);
  712. int get_hpos() { return hpos; }
  713. int get_vpos() { return vpos; }
  714. void add_to_tag_list(string s);
  715. friend void space_char_hmotion_node::tprint(troff_output_file *);
  716. friend void unbreakable_space_node::tprint(troff_output_file *);
  717. };
  718. static void put_string(const char *s, FILE *fp)
  719. {
  720. for (; *s != '\0'; ++s)
  721. putc(*s, fp);
  722. }
  723. inline void troff_output_file::put(char c)
  724. {
  725. putc(c, fp);
  726. }
  727. inline void troff_output_file::put(unsigned char c)
  728. {
  729. putc(c, fp);
  730. }
  731. inline void troff_output_file::put(const char *s)
  732. {
  733. put_string(s, fp);
  734. }
  735. inline void troff_output_file::put(int i)
  736. {
  737. put_string(i_to_a(i), fp);
  738. }
  739. inline void troff_output_file::put(unsigned int i)
  740. {
  741. put_string(ui_to_a(i), fp);
  742. }
  743. void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
  744. int no_init_string)
  745. {
  746. set_font(tf);
  747. glyph_color(gcol);
  748. fill_color(fcol);
  749. flush_tbuf();
  750. do_motion();
  751. if (!no_init_string)
  752. put("x X ");
  753. }
  754. void troff_output_file::start_special()
  755. {
  756. flush_tbuf();
  757. do_motion();
  758. put("x X ");
  759. }
  760. void troff_output_file::special_char(unsigned char c)
  761. {
  762. put(c);
  763. if (c == '\n')
  764. put('+');
  765. }
  766. void troff_output_file::end_special()
  767. {
  768. put('\n');
  769. }
  770. inline void troff_output_file::moveto(hunits h, vunits v)
  771. {
  772. hpos = h.to_units();
  773. vpos = v.to_units();
  774. }
  775. void troff_output_file::really_print_line(hunits x, vunits y, node *n,
  776. vunits before, vunits after, hunits)
  777. {
  778. moveto(x, y);
  779. while (n != 0) {
  780. // Check whether we should push the current troff state and use
  781. // the state at the start of the invocation of this diversion.
  782. if (n->div_nest_level > cur_div_level && n->push_state) {
  783. state.push_state(n->push_state);
  784. cur_div_level = n->div_nest_level;
  785. }
  786. // Has the current diversion level decreased? Then we must pop the
  787. // troff state.
  788. while (n->div_nest_level < cur_div_level) {
  789. state.pop_state();
  790. cur_div_level = n->div_nest_level;
  791. }
  792. // Now check whether the state has changed.
  793. if ((is_on() || n->force_tprint())
  794. && (state.changed(n->state) || n->is_tag() || n->is_special)) {
  795. flush_tbuf();
  796. do_motion();
  797. force_motion = 1;
  798. flush();
  799. state.flush(fp, n->state, tag_list);
  800. tag_list = string("");
  801. flush();
  802. }
  803. n->tprint(this);
  804. n = n->next;
  805. }
  806. flush_tbuf();
  807. // This ensures that transparent throughput will have a more predictable
  808. // position.
  809. do_motion();
  810. force_motion = 1;
  811. hpos = 0;
  812. put('n');
  813. put(before.to_units());
  814. put(' ');
  815. put(after.to_units());
  816. put('\n');
  817. }
  818. inline void troff_output_file::word_marker()
  819. {
  820. flush_tbuf();
  821. if (is_on())
  822. put('w');
  823. }
  824. inline void troff_output_file::right(hunits n)
  825. {
  826. hpos += n.to_units();
  827. }
  828. inline void troff_output_file::down(vunits n)
  829. {
  830. vpos += n.to_units();
  831. }
  832. void troff_output_file::do_motion()
  833. {
  834. if (force_motion) {
  835. put('V');
  836. put(vpos);
  837. put('\n');
  838. put('H');
  839. put(hpos);
  840. put('\n');
  841. }
  842. else {
  843. if (hpos != output_hpos) {
  844. units n = hpos - output_hpos;
  845. if (n > 0 && n < hpos) {
  846. put('h');
  847. put(n);
  848. }
  849. else {
  850. put('H');
  851. put(hpos);
  852. }
  853. put('\n');
  854. }
  855. if (vpos != output_vpos) {
  856. units n = vpos - output_vpos;
  857. if (n > 0 && n < vpos) {
  858. put('v');
  859. put(n);
  860. }
  861. else {
  862. put('V');
  863. put(vpos);
  864. }
  865. put('\n');
  866. }
  867. }
  868. output_vpos = vpos;
  869. output_hpos = hpos;
  870. force_motion = 0;
  871. }
  872. void troff_output_file::flush_tbuf()
  873. {
  874. if (!is_on()) {
  875. tbuf_len = 0;
  876. return;
  877. }
  878. if (tbuf_len == 0)
  879. return;
  880. if (tbuf_kern == 0)
  881. put('t');
  882. else {
  883. put('u');
  884. put(tbuf_kern);
  885. put(' ');
  886. }
  887. check_output_limits(hpos, vpos);
  888. check_output_limits(hpos, vpos - current_size);
  889. for (int i = 0; i < tbuf_len; i++)
  890. put(tbuf[i]);
  891. put('\n');
  892. tbuf_len = 0;
  893. }
  894. void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
  895. {
  896. if (!is_on())
  897. return;
  898. int height = tf->get_char_height(ci).to_units();
  899. int width = tf->get_width(ci).to_units()
  900. + tf->get_italic_correction(ci).to_units();
  901. int depth = tf->get_char_depth(ci).to_units();
  902. check_output_limits(output_hpos, output_vpos - height);
  903. check_output_limits(output_hpos + width, output_vpos + depth);
  904. }
  905. void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
  906. color *gcol, color *fcol,
  907. hunits w, hunits k)
  908. {
  909. int kk = k.to_units();
  910. if (!is_on()) {
  911. flush_tbuf();
  912. hpos += w.to_units() + kk;
  913. return;
  914. }
  915. set_font(tf);
  916. unsigned char c = ci->get_ascii_code();
  917. if (c == '\0') {
  918. glyph_color(gcol);
  919. fill_color(fcol);
  920. flush_tbuf();
  921. do_motion();
  922. check_charinfo(tf, ci);
  923. if (ci->numbered()) {
  924. put('N');
  925. put(ci->get_number());
  926. }
  927. else {
  928. put('C');
  929. const char *s = ci->nm.contents();
  930. if (s[1] == 0) {
  931. put('\\');
  932. put(s[0]);
  933. }
  934. else
  935. put(s);
  936. }
  937. put('\n');
  938. hpos += w.to_units() + kk;
  939. }
  940. else if (tcommand_flag) {
  941. if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
  942. && (!gcol || gcol == current_glyph_color)
  943. && (!fcol || fcol == current_fill_color)
  944. && kk == tbuf_kern
  945. && tbuf_len < TBUF_SIZE) {
  946. check_charinfo(tf, ci);
  947. tbuf[tbuf_len++] = c;
  948. output_hpos += w.to_units() + kk;
  949. hpos = output_hpos;
  950. return;
  951. }
  952. glyph_color(gcol);
  953. fill_color(fcol);
  954. flush_tbuf();
  955. do_motion();
  956. check_charinfo(tf, ci);
  957. tbuf[tbuf_len++] = c;
  958. output_hpos += w.to_units() + kk;
  959. tbuf_kern = kk;
  960. hpos = output_hpos;
  961. }
  962. else {
  963. // flush_tbuf();
  964. int n = hpos - output_hpos;
  965. check_charinfo(tf, ci);
  966. // check_output_limits(output_hpos, output_vpos);
  967. if (vpos == output_vpos
  968. && (!gcol || gcol == current_glyph_color)
  969. && (!fcol || fcol == current_fill_color)
  970. && n > 0 && n < 100 && !force_motion) {
  971. put(char(n/10 + '0'));
  972. put(char(n%10 + '0'));
  973. put(c);
  974. output_hpos = hpos;
  975. }
  976. else {
  977. glyph_color(gcol);
  978. fill_color(fcol);
  979. do_motion();
  980. put('c');
  981. put(c);
  982. }
  983. hpos += w.to_units() + kk;
  984. }
  985. }
  986. void troff_output_file::put_char(charinfo *ci, tfont *tf,
  987. color *gcol, color *fcol)
  988. {
  989. flush_tbuf();
  990. if (!is_on())
  991. return;
  992. set_font(tf);
  993. unsigned char c = ci->get_ascii_code();
  994. if (c == '\0') {
  995. glyph_color(gcol);
  996. fill_color(fcol);
  997. flush_tbuf();
  998. do_motion();
  999. if (ci->numbered()) {
  1000. put('N');
  1001. put(ci->get_number());
  1002. }
  1003. else {
  1004. put('C');
  1005. const char *s = ci->nm.contents();
  1006. if (s[1] == 0) {
  1007. put('\\');
  1008. put(s[0]);
  1009. }
  1010. else
  1011. put(s);
  1012. }
  1013. put('\n');
  1014. }
  1015. else {
  1016. int n = hpos - output_hpos;
  1017. if (vpos == output_vpos
  1018. && (!gcol || gcol == current_glyph_color)
  1019. && (!fcol || fcol == current_fill_color)
  1020. && n > 0 && n < 100) {
  1021. put(char(n/10 + '0'));
  1022. put(char(n%10 + '0'));
  1023. put(c);
  1024. output_hpos = hpos;
  1025. }
  1026. else {
  1027. glyph_color(gcol);
  1028. fill_color(fcol);
  1029. flush_tbuf();
  1030. do_motion();
  1031. put('c');
  1032. put(c);
  1033. }
  1034. }
  1035. }
  1036. // set_font calls `flush_tbuf' if necessary.
  1037. void troff_output_file::set_font(tfont *tf)
  1038. {
  1039. if (current_tfont == tf)
  1040. return;
  1041. flush_tbuf();
  1042. int n = tf->get_input_position();
  1043. symbol nm = tf->get_name();
  1044. if (n >= nfont_positions || font_position[n] != nm) {
  1045. put("x font ");
  1046. put(n);
  1047. put(' ');
  1048. put(nm.contents());
  1049. put('\n');
  1050. if (n >= nfont_positions) {
  1051. int old_nfont_positions = nfont_positions;
  1052. symbol *old_font_position = font_position;
  1053. nfont_positions *= 3;
  1054. nfont_positions /= 2;
  1055. if (nfont_positions <= n)
  1056. nfont_positions = n + 10;
  1057. font_position = new symbol[nfont_positions];
  1058. memcpy(font_position, old_font_position,
  1059. old_nfont_positions*sizeof(symbol));
  1060. a_delete old_font_position;
  1061. }
  1062. font_position[n] = nm;
  1063. }
  1064. if (current_font_number != n) {
  1065. put('f');
  1066. put(n);
  1067. put('\n');
  1068. current_font_number = n;
  1069. }
  1070. int size = tf->get_size().to_scaled_points();
  1071. if (current_size != size) {
  1072. put('s');
  1073. put(size);
  1074. put('\n');
  1075. current_size = size;
  1076. }
  1077. int slant = tf->get_slant();
  1078. if (current_slant != slant) {
  1079. put("x Slant ");
  1080. put(slant);
  1081. put('\n');
  1082. current_slant = slant;
  1083. }
  1084. int height = tf->get_height();
  1085. if (current_height != height) {
  1086. put("x Height ");
  1087. put(height == 0 ? current_size : height);
  1088. put('\n');
  1089. current_height = height;
  1090. }
  1091. current_tfont = tf;
  1092. }
  1093. // fill_color calls `flush_tbuf' and `do_motion' if necessary.
  1094. void troff_output_file::fill_color(color *col)
  1095. {
  1096. if (!col || current_fill_color == col)
  1097. return;
  1098. current_fill_color = col;
  1099. if (!color_flag)
  1100. return;
  1101. flush_tbuf();
  1102. do_motion();
  1103. put("DF");
  1104. unsigned int components[4];
  1105. color_scheme cs;
  1106. cs = col->get_components(components);
  1107. switch (cs) {
  1108. case DEFAULT:
  1109. put('d');
  1110. break;
  1111. case RGB:
  1112. put("r ");
  1113. put(Red);
  1114. put(' ');
  1115. put(Green);
  1116. put(' ');
  1117. put(Blue);
  1118. break;
  1119. case CMY:
  1120. put("c ");
  1121. put(Cyan);
  1122. put(' ');
  1123. put(Magenta);
  1124. put(' ');
  1125. put(Yellow);
  1126. break;
  1127. case CMYK:
  1128. put("k ");
  1129. put(Cyan);
  1130. put(' ');
  1131. put(Magenta);
  1132. put(' ');
  1133. put(Yellow);
  1134. put(' ');
  1135. put(Black);
  1136. break;
  1137. case GRAY:
  1138. put("g ");
  1139. put(Gray);
  1140. break;
  1141. }
  1142. put('\n');
  1143. }
  1144. // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
  1145. void troff_output_file::glyph_color(color *col)
  1146. {
  1147. if (!col || current_glyph_color == col)
  1148. return;
  1149. current_glyph_color = col;
  1150. if (!color_flag)
  1151. return;
  1152. flush_tbuf();
  1153. // grotty doesn't like a color command if the vertical position is zero.
  1154. do_motion();
  1155. put("m");
  1156. unsigned int components[4];
  1157. color_scheme cs;
  1158. cs = col->get_components(components);
  1159. switch (cs) {
  1160. case DEFAULT:
  1161. put('d');
  1162. break;
  1163. case RGB:
  1164. put("r ");
  1165. put(Red);
  1166. put(' ');
  1167. put(Green);
  1168. put(' ');
  1169. put(Blue);
  1170. break;
  1171. case CMY:
  1172. put("c ");
  1173. put(Cyan);
  1174. put(' ');
  1175. put(Magenta);
  1176. put(' ');
  1177. put(Yellow);
  1178. break;
  1179. case CMYK:
  1180. put("k ");
  1181. put(Cyan);
  1182. put(' ');
  1183. put(Magenta);
  1184. put(' ');
  1185. put(Yellow);
  1186. put(' ');
  1187. put(Black);
  1188. break;
  1189. case GRAY:
  1190. put("g ");
  1191. put(Gray);
  1192. break;
  1193. }
  1194. put('\n');
  1195. }
  1196. void troff_output_file::add_to_tag_list(string s)
  1197. {
  1198. if (tag_list == string(""))
  1199. tag_list = s;
  1200. else {
  1201. tag_list += string("\n");
  1202. tag_list += s;
  1203. }
  1204. }
  1205. // determine_line_limits - works out the smallest box which will contain
  1206. // the entity, code, built from the point array.
  1207. void troff_output_file::determine_line_limits(char code, hvpair *point,
  1208. int npoints)
  1209. {
  1210. int i, x, y;
  1211. if (!is_on())
  1212. return;
  1213. switch (code) {
  1214. case 'c':
  1215. case 'C':
  1216. // only the h field is used when defining a circle
  1217. check_output_limits(output_hpos,
  1218. output_vpos - point[0].h.to_units()/2);
  1219. check_output_limits(output_hpos + point[0].h.to_units(),
  1220. output_vpos + point[0].h.to_units()/2);
  1221. break;
  1222. case 'E':
  1223. case 'e':
  1224. check_output_limits(output_hpos,
  1225. output_vpos - point[0].v.to_units()/2);
  1226. check_output_limits(output_hpos + point[0].h.to_units(),
  1227. output_vpos + point[0].v.to_units()/2);
  1228. break;
  1229. case 'P':
  1230. case 'p':
  1231. x = output_hpos;
  1232. y = output_vpos;
  1233. check_output_limits(x, y);
  1234. for (i = 0; i < npoints; i++) {
  1235. x += point[i].h.to_units();
  1236. y += point[i].v.to_units();
  1237. check_output_limits(x, y);
  1238. }
  1239. break;
  1240. case 't':
  1241. x = output_hpos;
  1242. y = output_vpos;
  1243. for (i = 0; i < npoints; i++) {
  1244. x += point[i].h.to_units();
  1245. y += point[i].v.to_units();
  1246. check_output_limits(x, y);
  1247. }
  1248. break;
  1249. case 'a':
  1250. double c[2];
  1251. int p[4];
  1252. int minx, miny, maxx, maxy;
  1253. x = output_hpos;
  1254. y = output_vpos;
  1255. p[0] = point[0].h.to_units();
  1256. p[1] = point[0].v.to_units();
  1257. p[2] = point[1].h.to_units();
  1258. p[3] = point[1].v.to_units();
  1259. if (adjust_arc_center(p, c)) {
  1260. check_output_arc_limits(x, y,
  1261. p[0], p[1], p[2], p[3],
  1262. c[0], c[1],
  1263. &minx, &maxx, &miny, &maxy);
  1264. check_output_limits(minx, miny);
  1265. check_output_limits(maxx, maxy);
  1266. break;
  1267. }
  1268. // fall through
  1269. case 'l':
  1270. x = output_hpos;
  1271. y = output_vpos;
  1272. check_output_limits(x, y);
  1273. for (i = 0; i < npoints; i++) {
  1274. x += point[i].h.to_units();
  1275. y += point[i].v.to_units();
  1276. check_output_limits(x, y);
  1277. }
  1278. break;
  1279. default:
  1280. x = output_hpos;
  1281. y = output_vpos;
  1282. for (i = 0; i < npoints; i++) {
  1283. x += point[i].h.to_units();
  1284. y += point[i].v.to_units();
  1285. check_output_limits(x, y);
  1286. }
  1287. }
  1288. }
  1289. void troff_output_file::draw(char code, hvpair *point, int npoints,
  1290. font_size fsize, color *gcol, color *fcol)
  1291. {
  1292. int i;
  1293. glyph_color(gcol);
  1294. fill_color(fcol);
  1295. flush_tbuf();
  1296. do_motion();
  1297. if (is_on()) {
  1298. int size = fsize.to_scaled_points();
  1299. if (current_size != size) {
  1300. put('s');
  1301. put(size);
  1302. put('\n');
  1303. current_size = size;
  1304. current_tfont = 0;
  1305. }
  1306. put('D');
  1307. put(code);
  1308. if (code == 'c') {
  1309. put(' ');
  1310. put(point[0].h.to_units());
  1311. }
  1312. else
  1313. for (i = 0; i < npoints; i++) {
  1314. put(' ');
  1315. put(point[i].h.to_units());
  1316. put(' ');
  1317. put(point[i].v.to_units());
  1318. }
  1319. determine_line_limits(code, point, npoints);
  1320. }
  1321. for (i = 0; i < npoints; i++)
  1322. output_hpos += point[i].h.to_units();
  1323. hpos = output_hpos;
  1324. if (code != 'e') {
  1325. for (i = 0; i < npoints; i++)
  1326. output_vpos += point[i].v.to_units();
  1327. vpos = output_vpos;
  1328. }
  1329. if (is_on())
  1330. put('\n');
  1331. }
  1332. void troff_output_file::really_on()
  1333. {
  1334. flush_tbuf();
  1335. force_motion = 1;
  1336. do_motion();
  1337. }
  1338. void troff_output_file::really_off()
  1339. {
  1340. flush_tbuf();
  1341. }
  1342. void troff_output_file::really_put_filename(const char *filename)
  1343. {
  1344. flush_tbuf();
  1345. put("F ");
  1346. put(filename);
  1347. put('\n');
  1348. }
  1349. void troff_output_file::really_begin_page(int pageno, vunits page_length)
  1350. {
  1351. flush_tbuf();
  1352. if (begun_page) {
  1353. if (page_length > V0) {
  1354. put('V');
  1355. put(page_length.to_units());
  1356. put('\n');
  1357. }
  1358. }
  1359. else
  1360. begun_page = 1;
  1361. current_tfont = 0;
  1362. current_font_number = -1;
  1363. current_size = 0;
  1364. // current_height = 0;
  1365. // current_slant = 0;
  1366. hpos = 0;
  1367. vpos = 0;
  1368. output_hpos = 0;
  1369. output_vpos = 0;
  1370. force_motion = 1;
  1371. for (int i = 0; i < nfont_positions; i++)
  1372. font_position[i] = NULL_SYMBOL;
  1373. put('p');
  1374. put(pageno);
  1375. put('\n');
  1376. }
  1377. void troff_output_file::really_copy_file(hunits x, vunits y,
  1378. const char *filename)
  1379. {
  1380. moveto(x, y);
  1381. flush_tbuf();
  1382. do_motion();
  1383. errno = 0;
  1384. FILE *ifp = include_search_path.open_file_cautious(filename);
  1385. if (ifp == 0)
  1386. error("can't open `%1': %2", filename, strerror(errno));
  1387. else {
  1388. int c;
  1389. while ((c = getc(ifp)) != EOF)
  1390. put(char(c));
  1391. fclose(ifp);
  1392. }
  1393. force_motion = 1;
  1394. current_size = 0;
  1395. current_tfont = 0;
  1396. current_font_number = -1;
  1397. for (int i = 0; i < nfont_positions; i++)
  1398. font_position[i] = NULL_SYMBOL;
  1399. }
  1400. void troff_output_file::really_transparent_char(unsigned char c)
  1401. {
  1402. put(c);
  1403. }
  1404. troff_output_file::~troff_output_file()
  1405. {
  1406. a_delete font_position;
  1407. }
  1408. void troff_output_file::trailer(vunits page_length)
  1409. {
  1410. flush_tbuf();
  1411. if (page_length > V0) {
  1412. put("x trailer\n");
  1413. put('V');
  1414. put(page_length.to_units());
  1415. put('\n');
  1416. }
  1417. put("x stop\n");
  1418. }
  1419. troff_output_file::troff_output_file()
  1420. : current_slant(0), current_height(0), current_fill_color(0),
  1421. current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
  1422. cur_div_level(0)
  1423. {
  1424. font_position = new symbol[nfont_positions];
  1425. put("x T ");
  1426. put(device);
  1427. put('\n');
  1428. put("x res ");
  1429. put(units_per_inch);
  1430. put(' ');
  1431. put(hresolution);
  1432. put(' ');
  1433. put(vresolution);
  1434. put('\n');
  1435. put("x init\n");
  1436. }
  1437. /* output_file */
  1438. output_file *the_output = 0;
  1439. output_file::output_file()
  1440. {
  1441. }
  1442. output_file::~output_file()
  1443. {
  1444. }
  1445. void output_file::trailer(vunits)
  1446. {
  1447. }
  1448. void output_file::put_filename(const char *)
  1449. {
  1450. }
  1451. void output_file::on()
  1452. {
  1453. }
  1454. void output_file::off()
  1455. {
  1456. }
  1457. real_output_file::real_output_file()
  1458. : printing(0), output_on(1)
  1459. {
  1460. #ifndef POPEN_MISSING
  1461. if (pipe_command) {
  1462. if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
  1463. piped = 1;
  1464. return;
  1465. }
  1466. error("pipe open failed: %1", strerror(errno));
  1467. }
  1468. piped = 0;
  1469. #endif /* not POPEN_MISSING */
  1470. fp = stdout;
  1471. }
  1472. real_output_file::~real_output_file()
  1473. {
  1474. if (!fp)
  1475. return;
  1476. // To avoid looping, set fp to 0 before calling fatal().
  1477. if (ferror(fp) || fflush(fp) < 0) {
  1478. fp = 0;
  1479. fatal("error writing output file");
  1480. }
  1481. #ifndef POPEN_MISSING
  1482. if (piped) {
  1483. int result = pclose(fp);
  1484. fp = 0;
  1485. if (result < 0)
  1486. fatal("pclose failed");
  1487. if (!WIFEXITED(result))
  1488. error("output process `%1' got fatal signal %2",
  1489. pipe_command,
  1490. WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
  1491. else {
  1492. int exit_status = WEXITSTATUS(result);
  1493. if (exit_status != 0)
  1494. error("output process `%1' exited with status %2",
  1495. pipe_command, exit_status);
  1496. }
  1497. }
  1498. else
  1499. #endif /* not POPEN MISSING */
  1500. if (fclose(fp) < 0) {
  1501. fp = 0;
  1502. fatal("error closing output file");
  1503. }
  1504. }
  1505. void real_output_file::flush()
  1506. {
  1507. if (fflush(fp) < 0)
  1508. fatal("error writing output file");
  1509. }
  1510. int real_output_file::is_printing()
  1511. {
  1512. return printing;
  1513. }
  1514. void real_output_file::begin_page(int pageno, vunits page_length)
  1515. {
  1516. printing = in_output_page_list(pageno);
  1517. if (printing)
  1518. really_begin_page(pageno, page_length);
  1519. }
  1520. void real_output_file::copy_file(hunits x, vunits y, const char *filename)
  1521. {
  1522. if (printing && output_on)
  1523. really_copy_file(x, y, filename);
  1524. check_output_limits(x.to_units(), y.to_units());
  1525. }
  1526. void real_output_file::transparent_char(unsigned char c)
  1527. {
  1528. if (printing && output_on)
  1529. really_transparent_char(c);
  1530. }
  1531. void real_output_file::print_line(hunits x, vunits y, node *n,
  1532. vunits before, vunits after, hunits width)
  1533. {
  1534. if (printing)
  1535. really_print_line(x, y, n, before, after, width);
  1536. delete_node_list(n);
  1537. }
  1538. void real_output_file::really_copy_file(hunits, vunits, const char *)
  1539. {
  1540. // do nothing
  1541. }
  1542. void real_output_file::put_filename(const char *filename)
  1543. {
  1544. really_put_filename(filename);
  1545. }
  1546. void real_output_file::really_put_filename(const char *)
  1547. {
  1548. }
  1549. void real_output_file::on()
  1550. {
  1551. really_on();
  1552. if (output_on == 0)
  1553. output_on = 1;
  1554. }
  1555. void real_output_file::off()
  1556. {
  1557. really_off();
  1558. output_on = 0;
  1559. }
  1560. int real_output_file::is_on()
  1561. {
  1562. return output_on;
  1563. }
  1564. void real_output_file::really_on()
  1565. {
  1566. }
  1567. void real_output_file::really_off()
  1568. {
  1569. }
  1570. /* ascii_output_file */
  1571. void ascii_output_file::really_transparent_char(unsigned char c)
  1572. {
  1573. putc(c, fp);
  1574. }
  1575. void ascii_output_file::really_print_line(hunits, vunits, node *n,
  1576. vunits, vunits, hunits)
  1577. {
  1578. while (n != 0) {
  1579. n->ascii_print(this);
  1580. n = n->next;
  1581. }
  1582. fputc('\n', fp);
  1583. }
  1584. void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
  1585. {
  1586. fputs("<beginning of page>\n", fp);
  1587. }
  1588. ascii_output_file::ascii_output_file()
  1589. {
  1590. }
  1591. /* suppress_output_file */
  1592. suppress_output_file::suppress_output_file()
  1593. {
  1594. }
  1595. void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
  1596. {
  1597. }
  1598. void suppress_output_file::really_begin_page(int, vunits)
  1599. {
  1600. }
  1601. void suppress_output_file::really_transparent_char(unsigned char)
  1602. {
  1603. }
  1604. /* glyphs, ligatures, kerns, discretionary breaks */
  1605. class charinfo_node : public node {
  1606. protected:
  1607. charinfo *ci;
  1608. public:
  1609. charinfo_node(charinfo *, statem *, int, node * = 0);
  1610. int ends_sentence();
  1611. int overlaps_vertically();
  1612. int overlaps_horizontally();
  1613. };
  1614. charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x)
  1615. : node(x, s, pop), ci(c)
  1616. {
  1617. }
  1618. int charinfo_node::ends_sentence()
  1619. {
  1620. if (ci->ends_sentence())
  1621. return 1;
  1622. else if (ci->transparent())
  1623. return 2;
  1624. else
  1625. return 0;
  1626. }
  1627. int charinfo_node::overlaps_horizontally()
  1628. {
  1629. return ci->overlaps_horizontally();
  1630. }
  1631. int charinfo_node::overlaps_vertically()
  1632. {
  1633. return ci->overlaps_vertically();
  1634. }
  1635. class glyph_node : public charinfo_node {
  1636. static glyph_node *free_list;
  1637. protected:
  1638. tfont *tf;
  1639. color *gcol;
  1640. color *fcol; /* this is needed for grotty */
  1641. #ifdef STORE_WIDTH
  1642. hunits wid;
  1643. glyph_node(charinfo *, tfont *, color *, color *, hunits,
  1644. statem *, int, node * = 0);
  1645. #endif
  1646. public:
  1647. void *operator new(size_t);
  1648. void operator delete(void *);
  1649. glyph_node(charinfo *, tfont *, color *, color *,
  1650. statem *, int, node * = 0);
  1651. ~glyph_node() {}
  1652. node *copy();
  1653. node *merge_glyph_node(glyph_node *);
  1654. node *merge_self(node *);
  1655. hunits width();
  1656. node *last_char_node();
  1657. units size();
  1658. void vertical_extent(vunits *, vunits *);
  1659. hunits subscript_correction();
  1660. hunits italic_correction();
  1661. hunits left_italic_correction();
  1662. hunits skew();
  1663. hyphenation_type get_hyphenation_type();
  1664. tfont *get_tfont();
  1665. color *get_glyph_color();
  1666. color *get_fill_color();
  1667. void tprint(troff_output_file *);
  1668. void zero_width_tprint(troff_output_file *);
  1669. hyphen_list *get_hyphen_list(hyphen_list *, int *);
  1670. node *add_self(node *, hyphen_list **);
  1671. void ascii_print(ascii_output_file *);
  1672. void asciify(macro *);
  1673. int character_type();
  1674. int same(node *);
  1675. const char *type();
  1676. int force_tprint();
  1677. int is_tag();
  1678. void debug_node();
  1679. };
  1680. glyph_node *glyph_node::free_list = 0;
  1681. class ligature_node : public glyph_node {
  1682. node *n1;
  1683. node *n2;
  1684. #ifdef STORE_WIDTH
  1685. ligature_node(charinfo *, tfont *, color *, color *, hunits,
  1686. node *, node *, statem *, int, node * = 0);
  1687. #endif
  1688. public:
  1689. void *operator new(size_t);
  1690. void operator delete(void *);
  1691. ligature_node(charinfo *, tfont *, color *, color *,
  1692. node *, node *, statem *, int, node * = 0);
  1693. ~ligature_node();
  1694. node *copy();
  1695. node *add_self(node *, hyphen_list **);
  1696. hyphen_list *get_hyphen_list(hyphen_list *, int *);
  1697. void ascii_print(ascii_output_file *);
  1698. void asciify(macro *);
  1699. int same(node *);
  1700. const char *type();
  1701. int force_tprint();
  1702. int is_tag();
  1703. };
  1704. class kern_pair_node : public node {
  1705. hunits amount;
  1706. node *n1;
  1707. node *n2;
  1708. public:
  1709. kern_pair_node(hunits, node *, node *, statem *, int, node * = 0);
  1710. ~kern_pair_node();
  1711. node *copy();
  1712. node *merge_glyph_node(glyph_node *);
  1713. node *add_self(node *, hyphen_list **);
  1714. hyphen_list *get_hyphen_list(hyphen_list *, int *);
  1715. node *add_discretionary_hyphen();
  1716. hunits width();
  1717. node *last_char_node();
  1718. hunits italic_correction();
  1719. hunits subscript_correction();
  1720. void tprint(troff_output_file *);
  1721. hyphenation_type get_hyphenation_type();
  1722. int ends_sentence();
  1723. void ascii_print(ascii_output_file *);
  1724. void asciify(macro *);
  1725. int same(node *);
  1726. const char *type();
  1727. int force_tprint();
  1728. int is_tag();
  1729. void vertical_extent(vunits *, vunits *);
  1730. };
  1731. class dbreak_node : public node {
  1732. node *none;
  1733. node *pre;
  1734. node *post;
  1735. public:
  1736. dbreak_node(node *, node *, statem *, int, node * = 0);
  1737. ~dbreak_node();
  1738. node *copy();
  1739. node *merge_glyph_node(glyph_node *);
  1740. node *add_discretionary_hyphen();
  1741. hunits width();
  1742. node *last_char_node();
  1743. hunits italic_correction();
  1744. hunits subscript_correction();
  1745. void tprint(troff_output_file *);
  1746. breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
  1747. int is_inner = 0);
  1748. int nbreaks();
  1749. int ends_sentence();
  1750. void split(int, node **, node **);
  1751. hyphenation_type get_hyphenation_type();
  1752. void ascii_print(ascii_output_file *);
  1753. void asciify(macro *);
  1754. int same(node *);
  1755. const char *type();
  1756. int force_tprint();
  1757. int is_tag();
  1758. };
  1759. void *glyph_node::operator new(size_t n)
  1760. {
  1761. assert(n == sizeof(glyph_node));
  1762. if (!free_list) {
  1763. const int BLOCK = 1024;
  1764. free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
  1765. for (int i = 0; i < BLOCK - 1; i++)
  1766. free_list[i].next = free_list + i + 1;
  1767. free_list[BLOCK-1].next = 0;
  1768. }
  1769. glyph_node *p = free_list;
  1770. free_list = (glyph_node *)(free_list->next);
  1771. p->next = 0;
  1772. return p;
  1773. }
  1774. void *ligature_node::operator new(size_t n)
  1775. {
  1776. return new char[n];
  1777. }
  1778. void glyph_node::operator delete(void *p)
  1779. {
  1780. if (p) {
  1781. ((glyph_node *)p)->next = free_list;
  1782. free_list = (glyph_node *)p;
  1783. }
  1784. }
  1785. void ligature_node::operator delete(void *p)
  1786. {
  1787. delete[] (char *)p;
  1788. }
  1789. glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc,
  1790. statem *s, int pop, node *x)
  1791. : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc)
  1792. {
  1793. #ifdef STORE_WIDTH
  1794. wid = tf->get_width(ci);
  1795. #endif
  1796. }
  1797. #ifdef STORE_WIDTH
  1798. glyph_node::glyph_node(charinfo *c, tfont *t,
  1799. color *gc, color *fc, hunits w,
  1800. statem *s, int pop, node *x)
  1801. : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w)
  1802. {
  1803. }
  1804. #endif
  1805. node *glyph_node::copy()
  1806. {
  1807. #ifdef STORE_WIDTH
  1808. return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level);
  1809. #else
  1810. return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level);
  1811. #endif
  1812. }
  1813. node *glyph_node::merge_self(node *nd)
  1814. {
  1815. return nd->merge_glyph_node(this);
  1816. }
  1817. int glyph_node::character_type()
  1818. {
  1819. return tf->get_character_type(ci);
  1820. }
  1821. node *glyph_node::add_self(node *n, hyphen_list **p)
  1822. {
  1823. assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
  1824. next = 0;
  1825. node *nn;
  1826. if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
  1827. next = n;
  1828. nn = this;
  1829. }
  1830. if ((*p)->hyphen)
  1831. nn = nn->add_discretionary_hyphen();
  1832. hyphen_list *pp = *p;
  1833. *p = (*p)->next;
  1834. delete pp;
  1835. return nn;
  1836. }
  1837. units glyph_node::size()
  1838. {
  1839. return tf->get_size().to_units();
  1840. }
  1841. hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count)
  1842. {
  1843. (*count)++;
  1844. return new hyphen_list(ci->get_hyphenation_code(), tail);
  1845. }
  1846. tfont *node::get_tfont()
  1847. {
  1848. return 0;
  1849. }
  1850. tfont *glyph_node::get_tfont()
  1851. {
  1852. return tf;
  1853. }
  1854. color *node::get_glyph_color()
  1855. {
  1856. return 0;
  1857. }
  1858. color *glyph_node::get_glyph_color()
  1859. {
  1860. return gcol;
  1861. }
  1862. color *node::get_fill_color()
  1863. {
  1864. return 0;
  1865. }
  1866. color *glyph_node::get_fill_color()
  1867. {
  1868. return fcol;
  1869. }
  1870. node *node::merge_glyph_node(glyph_node *)
  1871. {
  1872. return 0;
  1873. }
  1874. node *glyph_node::merge_glyph_node(glyph_node *gn)
  1875. {
  1876. if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
  1877. charinfo *lig;
  1878. if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
  1879. node *next1 = next;
  1880. next = 0;
  1881. return new ligature_node(lig, tf, gcol, fcol, this, gn, state,
  1882. gn->div_nest_level, next1);
  1883. }
  1884. hunits kern;
  1885. if (tf->get_kern(ci, gn->ci, &kern)) {
  1886. node *next1 = next;
  1887. next = 0;
  1888. return new kern_pair_node(kern, this, gn, state,
  1889. gn->div_nest_level, next1);
  1890. }
  1891. }
  1892. return 0;
  1893. }
  1894. #ifdef STORE_WIDTH
  1895. inline
  1896. #endif
  1897. hunits glyph_node::width()
  1898. {
  1899. #ifdef STORE_WIDTH
  1900. return wid;
  1901. #else
  1902. return tf->get_width(ci);
  1903. #endif
  1904. }
  1905. node *glyph_node::last_char_node()
  1906. {
  1907. return this;
  1908. }
  1909. void glyph_node::vertical_extent(vunits *min, vunits *max)
  1910. {
  1911. *min = -tf->get_char_height(ci);
  1912. *max = tf->get_char_depth(ci);
  1913. }
  1914. hunits glyph_node::skew()
  1915. {
  1916. return tf->get_char_skew(ci);
  1917. }
  1918. hunits glyph_node::subscript_correction()
  1919. {
  1920. return tf->get_subscript_correction(ci);
  1921. }
  1922. hunits glyph_node::italic_correction()
  1923. {
  1924. return tf->get_italic_correction(ci);
  1925. }
  1926. hunits glyph_node::left_italic_correction()
  1927. {
  1928. return tf->get_left_italic_correction(ci);
  1929. }
  1930. hyphenation_type glyph_node::get_hyphenation_type()
  1931. {
  1932. return HYPHEN_MIDDLE;
  1933. }
  1934. void glyph_node::ascii_print(ascii_output_file *ascii)
  1935. {
  1936. unsigned char c = ci->get_ascii_code();
  1937. if (c != 0)
  1938. ascii->outc(c);
  1939. else
  1940. ascii->outs(ci->nm.contents());
  1941. }
  1942. void glyph_node::debug_node()
  1943. {
  1944. unsigned char c = ci->get_ascii_code();
  1945. fprintf(stderr, "{ %s [", type());
  1946. if (c)
  1947. fprintf(stderr, "%c", c);
  1948. else
  1949. fputs(ci->nm.contents(), stderr);
  1950. if (push_state)
  1951. fprintf(stderr, " <push_state>");
  1952. if (state)
  1953. state->display_state();
  1954. fprintf(stderr, " nest level %d", div_nest_level);
  1955. fprintf(stderr, "]}\n");
  1956. fflush(stderr);
  1957. }
  1958. ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
  1959. node *gn1, node *gn2, statem *s,
  1960. int pop, node *x)
  1961. : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2)
  1962. {
  1963. }
  1964. #ifdef STORE_WIDTH
  1965. ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
  1966. hunits w, node *gn1, node *gn2, statem *s,
  1967. int pop, node *x)
  1968. : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2)
  1969. {
  1970. }
  1971. #endif
  1972. ligature_node::~ligature_node()
  1973. {
  1974. delete n1;
  1975. delete n2;
  1976. }
  1977. node *ligature_node::copy()
  1978. {
  1979. #ifdef STORE_WIDTH
  1980. return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(),
  1981. state, div_nest_level);
  1982. #else
  1983. return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(),
  1984. state, div_nest_level);
  1985. #endif
  1986. }
  1987. void ligature_node::ascii_print(ascii_output_file *ascii)
  1988. {
  1989. n1->ascii_print(ascii);
  1990. n2->ascii_print(ascii);
  1991. }
  1992. hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count)
  1993. {
  1994. hyphen_list *hl = n2->get_hyphen_list(tail, count);
  1995. return n1->get_hyphen_list(hl, count);
  1996. }
  1997. node *ligature_node::add_self(node *n, hyphen_list **p)
  1998. {
  1999. n = n1->add_self(n, p);
  2000. n = n2->add_self(n, p);
  2001. n1 = n2 = 0;
  2002. delete this;
  2003. return n;
  2004. }
  2005. kern_pair_node::kern_pair_node(hunits n, node *first, node *second,
  2006. statem* s, int pop, node *x)
  2007. : node(x, s, pop), amount(n), n1(first), n2(second)
  2008. {
  2009. }
  2010. dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x)
  2011. : node(x, s, pop), none(n), pre(p), post(0)
  2012. {
  2013. }
  2014. node *dbreak_node::merge_glyph_node(glyph_node *gn)
  2015. {
  2016. glyph_node *gn2 = (glyph_node *)gn->copy();
  2017. node *new_none = none ? none->merge_glyph_node(gn) : 0;
  2018. node *new_post = post ? post->merge_glyph_node(gn2) : 0;
  2019. if (new_none == 0 && new_post == 0) {
  2020. delete gn2;
  2021. return 0;
  2022. }
  2023. if (new_none != 0)
  2024. none = new_none;
  2025. else {
  2026. gn->next = none;
  2027. none = gn;
  2028. }
  2029. if (new_post != 0)
  2030. post = new_post;
  2031. else {
  2032. gn2->next = post;
  2033. post = gn2;
  2034. }
  2035. return this;
  2036. }
  2037. node *kern_pair_node::merge_glyph_node(glyph_node *gn)
  2038. {
  2039. node *nd = n2->merge_glyph_node(gn);
  2040. if (nd == 0)
  2041. return 0;
  2042. n2 = nd;
  2043. nd = n2->merge_self(n1);
  2044. if (nd) {
  2045. nd->next = next;
  2046. n1 = 0;
  2047. n2 = 0;
  2048. delete this;
  2049. return nd;
  2050. }
  2051. return this;
  2052. }
  2053. hunits kern_pair_node::italic_correction()
  2054. {
  2055. return n2->italic_correction();
  2056. }
  2057. hunits kern_pair_node::subscript_correction()
  2058. {
  2059. return n2->subscript_correction();
  2060. }
  2061. void kern_pair_node::vertical_extent(vunits *min, vunits *max)
  2062. {
  2063. n1->vertical_extent(min, max);
  2064. vunits min2, max2;
  2065. n2->vertical_extent(&min2, &max2);
  2066. if (min2 < *min)
  2067. *min = min2;
  2068. if (max2 > *max)
  2069. *max = max2;
  2070. }
  2071. node *kern_pair_node::add_discretionary_hyphen()
  2072. {
  2073. tfont *tf = n2->get_tfo