/contrib/groff/src/devices/grotty/tty.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 907 lines · 799 code · 51 blank · 57 comment · 235 complexity · dd3d2f83d63e6cde53395a93436f5efd MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989-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. #include "driver.h"
  18. #include "device.h"
  19. #include "ptable.h"
  20. typedef signed char schar;
  21. declare_ptable(schar)
  22. implement_ptable(schar)
  23. extern "C" const char *Version_string;
  24. #define putstring(s) fputs(s, stdout)
  25. #ifndef SHRT_MIN
  26. #define SHRT_MIN (-32768)
  27. #endif
  28. #ifndef SHRT_MAX
  29. #define SHRT_MAX 32767
  30. #endif
  31. #define TAB_WIDTH 8
  32. static int horizontal_tab_flag = 0;
  33. static int form_feed_flag = 0;
  34. static int bold_flag_option = 1;
  35. static int bold_flag;
  36. static int underline_flag_option = 1;
  37. static int underline_flag;
  38. static int overstrike_flag = 1;
  39. static int draw_flag = 1;
  40. static int italic_flag_option = 0;
  41. static int italic_flag;
  42. static int reverse_flag_option = 0;
  43. static int reverse_flag;
  44. static int old_drawing_scheme = 0;
  45. static void update_options();
  46. static void usage(FILE *stream);
  47. static int hline_char = '-';
  48. static int vline_char = '|';
  49. enum {
  50. UNDERLINE_MODE = 0x01,
  51. BOLD_MODE = 0x02,
  52. VDRAW_MODE = 0x04,
  53. HDRAW_MODE = 0x08,
  54. CU_MODE = 0x10,
  55. COLOR_CHANGE = 0x20,
  56. START_LINE = 0x40,
  57. END_LINE = 0x80
  58. };
  59. // Mode to use for bold-underlining.
  60. static unsigned char bold_underline_mode_option = BOLD_MODE|UNDERLINE_MODE;
  61. static unsigned char bold_underline_mode;
  62. #ifndef IS_EBCDIC_HOST
  63. #define CSI "\033["
  64. #else
  65. #define CSI "\047["
  66. #endif
  67. // SGR handling (ISO 6429)
  68. #define SGR_BOLD CSI "1m"
  69. #define SGR_NO_BOLD CSI "22m"
  70. #define SGR_ITALIC CSI "3m"
  71. #define SGR_NO_ITALIC CSI "23m"
  72. #define SGR_UNDERLINE CSI "4m"
  73. #define SGR_NO_UNDERLINE CSI "24m"
  74. #define SGR_REVERSE CSI "7m"
  75. #define SGR_NO_REVERSE CSI "27m"
  76. // many terminals can't handle `CSI 39 m' and `CSI 49 m' to reset
  77. // the foreground and background color, respectively; we thus use
  78. // `CSI 0 m' exclusively
  79. #define SGR_DEFAULT CSI "0m"
  80. #define DEFAULT_COLOR_IDX -1
  81. class tty_font : public font {
  82. tty_font(const char *);
  83. unsigned char mode;
  84. public:
  85. ~tty_font();
  86. unsigned char get_mode() { return mode; }
  87. #if 0
  88. void handle_x_command(int argc, const char **argv);
  89. #endif
  90. static tty_font *load_tty_font(const char *);
  91. };
  92. tty_font *tty_font::load_tty_font(const char *s)
  93. {
  94. tty_font *f = new tty_font(s);
  95. if (!f->load()) {
  96. delete f;
  97. return 0;
  98. }
  99. const char *num = f->get_internal_name();
  100. long n;
  101. if (num != 0 && (n = strtol(num, 0, 0)) != 0)
  102. f->mode = (unsigned char)(n & (BOLD_MODE|UNDERLINE_MODE));
  103. if (!underline_flag)
  104. f->mode &= ~UNDERLINE_MODE;
  105. if (!bold_flag)
  106. f->mode &= ~BOLD_MODE;
  107. if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
  108. f->mode = (unsigned char)((f->mode & ~(BOLD_MODE|UNDERLINE_MODE))
  109. | bold_underline_mode);
  110. return f;
  111. }
  112. tty_font::tty_font(const char *nm)
  113. : font(nm), mode(0)
  114. {
  115. }
  116. tty_font::~tty_font()
  117. {
  118. }
  119. #if 0
  120. void tty_font::handle_x_command(int argc, const char **argv)
  121. {
  122. if (argc >= 1 && strcmp(argv[0], "bold") == 0)
  123. mode |= BOLD_MODE;
  124. else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
  125. mode |= UNDERLINE_MODE;
  126. }
  127. #endif
  128. class glyph {
  129. static glyph *free_list;
  130. public:
  131. glyph *next;
  132. int w;
  133. int hpos;
  134. unsigned int code;
  135. unsigned char mode;
  136. schar back_color_idx;
  137. schar fore_color_idx;
  138. void *operator new(size_t);
  139. void operator delete(void *);
  140. inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
  141. inline int order() {
  142. return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); }
  143. };
  144. glyph *glyph::free_list = 0;
  145. void *glyph::operator new(size_t)
  146. {
  147. if (!free_list) {
  148. const int BLOCK = 1024;
  149. free_list = (glyph *)new char[sizeof(glyph) * BLOCK];
  150. for (int i = 0; i < BLOCK - 1; i++)
  151. free_list[i].next = free_list + i + 1;
  152. free_list[BLOCK - 1].next = 0;
  153. }
  154. glyph *p = free_list;
  155. free_list = free_list->next;
  156. p->next = 0;
  157. return p;
  158. }
  159. void glyph::operator delete(void *p)
  160. {
  161. if (p) {
  162. ((glyph *)p)->next = free_list;
  163. free_list = (glyph *)p;
  164. }
  165. }
  166. class tty_printer : public printer {
  167. int is_utf8;
  168. glyph **lines;
  169. int nlines;
  170. int cached_v;
  171. int cached_vpos;
  172. schar curr_fore_idx;
  173. schar curr_back_idx;
  174. int is_underline;
  175. int is_bold;
  176. int cu_flag;
  177. PTABLE(schar) tty_colors;
  178. void make_underline(int);
  179. void make_bold(unsigned int, int);
  180. schar color_to_idx(color *col);
  181. void add_char(unsigned int, int, int, int, color *, color *, unsigned char);
  182. char *make_rgb_string(unsigned int, unsigned int, unsigned int);
  183. int tty_color(unsigned int, unsigned int, unsigned int, schar *,
  184. schar = DEFAULT_COLOR_IDX);
  185. public:
  186. tty_printer(const char *device);
  187. ~tty_printer();
  188. void set_char(int, font *, const environment *, int, const char *name);
  189. void draw(int code, int *p, int np, const environment *env);
  190. void special(char *arg, const environment *env, char type);
  191. void change_color(const environment * const env);
  192. void change_fill_color(const environment * const env);
  193. void put_char(unsigned int);
  194. void put_color(schar, int);
  195. void begin_page(int) { }
  196. void end_page(int page_length);
  197. font *make_font(const char *);
  198. };
  199. char *tty_printer::make_rgb_string(unsigned int r,
  200. unsigned int g,
  201. unsigned int b)
  202. {
  203. char *s = new char[8];
  204. s[0] = char(r >> 8);
  205. s[1] = char(r & 0xff);
  206. s[2] = char(g >> 8);
  207. s[3] = char(g & 0xff);
  208. s[4] = char(b >> 8);
  209. s[5] = char(b & 0xff);
  210. s[6] = char(0x80);
  211. s[7] = 0;
  212. // avoid null-bytes in string
  213. for (int i = 0; i < 6; i++)
  214. if (!s[i]) {
  215. s[i] = 1;
  216. s[6] |= 1 << i;
  217. }
  218. return s;
  219. }
  220. int tty_printer::tty_color(unsigned int r,
  221. unsigned int g,
  222. unsigned int b, schar *idx, schar value)
  223. {
  224. int unknown_color = 0;
  225. char *s = make_rgb_string(r, g, b);
  226. schar *i = tty_colors.lookup(s);
  227. if (!i) {
  228. unknown_color = 1;
  229. i = new schar[1];
  230. *i = value;
  231. tty_colors.define(s, i);
  232. }
  233. *idx = *i;
  234. a_delete s;
  235. return unknown_color;
  236. }
  237. tty_printer::tty_printer(const char *dev) : cached_v(0)
  238. {
  239. is_utf8 = !strcmp(dev, "utf8");
  240. if (is_utf8) {
  241. hline_char = 0x2500;
  242. vline_char = 0x2502;
  243. }
  244. schar dummy;
  245. // black, white
  246. (void)tty_color(0, 0, 0, &dummy, 0);
  247. (void)tty_color(color::MAX_COLOR_VAL,
  248. color::MAX_COLOR_VAL,
  249. color::MAX_COLOR_VAL, &dummy, 7);
  250. // red, green, blue
  251. (void)tty_color(color::MAX_COLOR_VAL, 0, 0, &dummy, 1);
  252. (void)tty_color(0, color::MAX_COLOR_VAL, 0, &dummy, 2);
  253. (void)tty_color(0, 0, color::MAX_COLOR_VAL, &dummy, 4);
  254. // yellow, magenta, cyan
  255. (void)tty_color(color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, 0, &dummy, 3);
  256. (void)tty_color(color::MAX_COLOR_VAL, 0, color::MAX_COLOR_VAL, &dummy, 5);
  257. (void)tty_color(0, color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, &dummy, 6);
  258. nlines = 66;
  259. lines = new glyph *[nlines];
  260. for (int i = 0; i < nlines; i++)
  261. lines[i] = 0;
  262. cu_flag = 0;
  263. }
  264. tty_printer::~tty_printer()
  265. {
  266. a_delete lines;
  267. }
  268. void tty_printer::make_underline(int w)
  269. {
  270. if (old_drawing_scheme) {
  271. if (!w)
  272. warning("can't underline zero-width character");
  273. else {
  274. int n = w / font::hor;
  275. for (int i = 0; i < n; i++)
  276. putchar('_');
  277. for (int j = 0; j < n; j++)
  278. putchar('\b');
  279. }
  280. }
  281. else {
  282. if (!is_underline) {
  283. if (italic_flag)
  284. putstring(SGR_ITALIC);
  285. else if (reverse_flag)
  286. putstring(SGR_REVERSE);
  287. else
  288. putstring(SGR_UNDERLINE);
  289. }
  290. is_underline = 1;
  291. }
  292. }
  293. void tty_printer::make_bold(unsigned int c, int w)
  294. {
  295. if (old_drawing_scheme) {
  296. if (!w)
  297. warning("can't print zero-width character in bold");
  298. else {
  299. int n = w / font::hor;
  300. put_char(c);
  301. for (int i = 0; i < n; i++)
  302. putchar('\b');
  303. }
  304. }
  305. else {
  306. if (!is_bold)
  307. putstring(SGR_BOLD);
  308. is_bold = 1;
  309. }
  310. }
  311. schar tty_printer::color_to_idx(color *col)
  312. {
  313. if (col->is_default())
  314. return DEFAULT_COLOR_IDX;
  315. unsigned int r, g, b;
  316. col->get_rgb(&r, &g, &b);
  317. schar idx;
  318. if (tty_color(r, g, b, &idx)) {
  319. char *s = col->print_color();
  320. error("Unknown color (%1) mapped to default", s);
  321. a_delete s;
  322. }
  323. return idx;
  324. }
  325. void tty_printer::set_char(int i, font *f, const environment *env,
  326. int w, const char *)
  327. {
  328. if (w % font::hor != 0)
  329. fatal("width of character not a multiple of horizontal resolution");
  330. add_char(f->get_code(i), w,
  331. env->hpos, env->vpos,
  332. env->col, env->fill,
  333. ((tty_font *)f)->get_mode());
  334. }
  335. void tty_printer::add_char(unsigned int c, int w,
  336. int h, int v,
  337. color *fore, color *back,
  338. unsigned char mode)
  339. {
  340. #if 0
  341. // This is too expensive.
  342. if (h % font::hor != 0)
  343. fatal("horizontal position not a multiple of horizontal resolution");
  344. #endif
  345. int hpos = h / font::hor;
  346. if (hpos < SHRT_MIN || hpos > SHRT_MAX) {
  347. error("character with ridiculous horizontal position discarded");
  348. return;
  349. }
  350. int vpos;
  351. if (v == cached_v && cached_v != 0)
  352. vpos = cached_vpos;
  353. else {
  354. if (v % font::vert != 0)
  355. fatal("vertical position not a multiple of vertical resolution");
  356. vpos = v / font::vert;
  357. if (vpos > nlines) {
  358. glyph **old_lines = lines;
  359. lines = new glyph *[vpos + 1];
  360. memcpy(lines, old_lines, nlines * sizeof(glyph *));
  361. for (int i = nlines; i <= vpos; i++)
  362. lines[i] = 0;
  363. a_delete old_lines;
  364. nlines = vpos + 1;
  365. }
  366. // Note that the first output line corresponds to groff
  367. // position font::vert.
  368. if (vpos <= 0) {
  369. error("character above first line discarded");
  370. return;
  371. }
  372. cached_v = v;
  373. cached_vpos = vpos;
  374. }
  375. glyph *g = new glyph;
  376. g->w = w;
  377. g->hpos = hpos;
  378. g->code = c;
  379. g->fore_color_idx = color_to_idx(fore);
  380. g->back_color_idx = color_to_idx(back);
  381. g->mode = mode;
  382. // The list will be reversed later. After reversal, it must be in
  383. // increasing order of hpos, with COLOR_CHANGE and CU specials before
  384. // HDRAW characters before VDRAW characters before normal characters
  385. // at each hpos, and otherwise in order of occurrence.
  386. glyph **pp;
  387. for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
  388. if ((*pp)->hpos < hpos
  389. || ((*pp)->hpos == hpos && (*pp)->order() >= g->order()))
  390. break;
  391. g->next = *pp;
  392. *pp = g;
  393. }
  394. void tty_printer::special(char *arg, const environment *env, char type)
  395. {
  396. if (type == 'u') {
  397. add_char(*arg - '0', 0, env->hpos, env->vpos, env->col, env->fill,
  398. CU_MODE);
  399. return;
  400. }
  401. if (type != 'p')
  402. return;
  403. char *p;
  404. for (p = arg; *p == ' ' || *p == '\n'; p++)
  405. ;
  406. char *tag = p;
  407. for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
  408. ;
  409. if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) {
  410. error("X command without `tty:' tag ignored");
  411. return;
  412. }
  413. p++;
  414. for (; *p == ' ' || *p == '\n'; p++)
  415. ;
  416. char *command = p;
  417. for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
  418. ;
  419. if (*command == '\0') {
  420. error("empty X command ignored");
  421. return;
  422. }
  423. if (strncmp(command, "sgr", p - command) == 0) {
  424. for (; *p == ' ' || *p == '\n'; p++)
  425. ;
  426. int n;
  427. if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0)
  428. old_drawing_scheme = 1;
  429. else
  430. old_drawing_scheme = 0;
  431. update_options();
  432. }
  433. }
  434. void tty_printer::change_color(const environment * const env)
  435. {
  436. add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
  437. }
  438. void tty_printer::change_fill_color(const environment * const env)
  439. {
  440. add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
  441. }
  442. void tty_printer::draw(int code, int *p, int np, const environment *env)
  443. {
  444. if (code != 'l' || !draw_flag)
  445. return;
  446. if (np != 2) {
  447. error("2 arguments required for line");
  448. return;
  449. }
  450. if (p[0] == 0) {
  451. // vertical line
  452. int v = env->vpos;
  453. int len = p[1];
  454. if (len < 0) {
  455. v += len;
  456. len = -len;
  457. }
  458. if (len >= 0 && len <= font::vert)
  459. add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill,
  460. VDRAW_MODE|START_LINE|END_LINE);
  461. else {
  462. add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill,
  463. VDRAW_MODE|START_LINE);
  464. len -= font::vert;
  465. v += font::vert;
  466. while (len > 0) {
  467. add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill,
  468. VDRAW_MODE|START_LINE|END_LINE);
  469. len -= font::vert;
  470. v += font::vert;
  471. }
  472. add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill,
  473. VDRAW_MODE|END_LINE);
  474. }
  475. }
  476. if (p[1] == 0) {
  477. // horizontal line
  478. int h = env->hpos;
  479. int len = p[0];
  480. if (len < 0) {
  481. h += len;
  482. len = -len;
  483. }
  484. if (len >= 0 && len <= font::hor)
  485. add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill,
  486. HDRAW_MODE|START_LINE|END_LINE);
  487. else {
  488. add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill,
  489. HDRAW_MODE|START_LINE);
  490. len -= font::hor;
  491. h += font::hor;
  492. while (len > 0) {
  493. add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill,
  494. HDRAW_MODE|START_LINE|END_LINE);
  495. len -= font::hor;
  496. h += font::hor;
  497. }
  498. add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill,
  499. HDRAW_MODE|END_LINE);
  500. }
  501. }
  502. }
  503. void tty_printer::put_char(unsigned int wc)
  504. {
  505. if (is_utf8 && wc >= 0x80) {
  506. char buf[6 + 1];
  507. int count;
  508. char *p = buf;
  509. if (wc < 0x800)
  510. count = 1, *p = (unsigned char)((wc >> 6) | 0xc0);
  511. else if (wc < 0x10000)
  512. count = 2, *p = (unsigned char)((wc >> 12) | 0xe0);
  513. else if (wc < 0x200000)
  514. count = 3, *p = (unsigned char)((wc >> 18) | 0xf0);
  515. else if (wc < 0x4000000)
  516. count = 4, *p = (unsigned char)((wc >> 24) | 0xf8);
  517. else if (wc <= 0x7fffffff)
  518. count = 5, *p = (unsigned char)((wc >> 30) | 0xfC);
  519. else
  520. return;
  521. do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80);
  522. while (count > 0);
  523. *++p = '\0';
  524. putstring(buf);
  525. }
  526. else
  527. putchar(wc);
  528. }
  529. void tty_printer::put_color(schar color_index, int back)
  530. {
  531. if (color_index == DEFAULT_COLOR_IDX) {
  532. putstring(SGR_DEFAULT);
  533. // set bold and underline again
  534. if (is_bold)
  535. putstring(SGR_BOLD);
  536. if (is_underline) {
  537. if (italic_flag)
  538. putstring(SGR_ITALIC);
  539. else if (reverse_flag)
  540. putstring(SGR_REVERSE);
  541. else
  542. putstring(SGR_UNDERLINE);
  543. }
  544. // set other color again
  545. back = !back;
  546. color_index = back ? curr_back_idx : curr_fore_idx;
  547. }
  548. if (color_index != DEFAULT_COLOR_IDX) {
  549. putstring(CSI);
  550. if (back)
  551. putchar('4');
  552. else
  553. putchar('3');
  554. putchar(color_index + '0');
  555. putchar('m');
  556. }
  557. }
  558. // The possible Unicode combinations for crossing characters.
  559. //
  560. // ` ' = 0, ` -' = 4, `- ' = 8, `--' = 12,
  561. //
  562. // ` ' = 0, ` ' = 1, `|' = 2, `|' = 3
  563. // | |
  564. static int crossings[4*4] = {
  565. 0x0000, 0x2577, 0x2575, 0x2502,
  566. 0x2576, 0x250C, 0x2514, 0x251C,
  567. 0x2574, 0x2510, 0x2518, 0x2524,
  568. 0x2500, 0x252C, 0x2534, 0x253C
  569. };
  570. void tty_printer::end_page(int page_length)
  571. {
  572. if (page_length % font::vert != 0)
  573. error("vertical position at end of page not multiple of vertical resolution");
  574. int lines_per_page = page_length / font::vert;
  575. int last_line;
  576. for (last_line = nlines; last_line > 0; last_line--)
  577. if (lines[last_line - 1])
  578. break;
  579. #if 0
  580. if (last_line > lines_per_page) {
  581. error("characters past last line discarded");
  582. do {
  583. --last_line;
  584. while (lines[last_line]) {
  585. glyph *tem = lines[last_line];
  586. lines[last_line] = tem->next;
  587. delete tem;
  588. }
  589. } while (last_line > lines_per_page);
  590. }
  591. #endif
  592. for (int i = 0; i < last_line; i++) {
  593. glyph *p = lines[i];
  594. lines[i] = 0;
  595. glyph *g = 0;
  596. while (p) {
  597. glyph *tem = p->next;
  598. p->next = g;
  599. g = p;
  600. p = tem;
  601. }
  602. int hpos = 0;
  603. glyph *nextp;
  604. curr_fore_idx = DEFAULT_COLOR_IDX;
  605. curr_back_idx = DEFAULT_COLOR_IDX;
  606. is_underline = 0;
  607. is_bold = 0;
  608. for (p = g; p; delete p, p = nextp) {
  609. nextp = p->next;
  610. if (p->mode & CU_MODE) {
  611. cu_flag = p->code;
  612. continue;
  613. }
  614. if (nextp && p->hpos == nextp->hpos) {
  615. if (p->draw_mode() == HDRAW_MODE &&
  616. nextp->draw_mode() == VDRAW_MODE) {
  617. if (is_utf8)
  618. nextp->code =
  619. crossings[((p->mode & (START_LINE|END_LINE)) >> 4)
  620. + ((nextp->mode & (START_LINE|END_LINE)) >> 6)];
  621. else
  622. nextp->code = '+';
  623. continue;
  624. }
  625. if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
  626. nextp->code = p->code;
  627. continue;
  628. }
  629. if (!overstrike_flag)
  630. continue;
  631. }
  632. if (hpos > p->hpos) {
  633. do {
  634. putchar('\b');
  635. hpos--;
  636. } while (hpos > p->hpos);
  637. }
  638. else {
  639. if (horizontal_tab_flag) {
  640. for (;;) {
  641. int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
  642. if (next_tab_pos > p->hpos)
  643. break;
  644. if (cu_flag)
  645. make_underline(p->w);
  646. else if (!old_drawing_scheme && is_underline) {
  647. if (italic_flag)
  648. putstring(SGR_NO_ITALIC);
  649. else if (reverse_flag)
  650. putstring(SGR_NO_REVERSE);
  651. else
  652. putstring(SGR_NO_UNDERLINE);
  653. is_underline = 0;
  654. }
  655. putchar('\t');
  656. hpos = next_tab_pos;
  657. }
  658. }
  659. for (; hpos < p->hpos; hpos++) {
  660. if (cu_flag)
  661. make_underline(p->w);
  662. else if (!old_drawing_scheme && is_underline) {
  663. if (italic_flag)
  664. putstring(SGR_NO_ITALIC);
  665. else if (reverse_flag)
  666. putstring(SGR_NO_REVERSE);
  667. else
  668. putstring(SGR_NO_UNDERLINE);
  669. is_underline = 0;
  670. }
  671. putchar(' ');
  672. }
  673. }
  674. assert(hpos == p->hpos);
  675. if (p->mode & COLOR_CHANGE) {
  676. if (!old_drawing_scheme) {
  677. if (p->fore_color_idx != curr_fore_idx) {
  678. put_color(p->fore_color_idx, 0);
  679. curr_fore_idx = p->fore_color_idx;
  680. }
  681. if (p->back_color_idx != curr_back_idx) {
  682. put_color(p->back_color_idx, 1);
  683. curr_back_idx = p->back_color_idx;
  684. }
  685. }
  686. continue;
  687. }
  688. if (p->mode & UNDERLINE_MODE)
  689. make_underline(p->w);
  690. else if (!old_drawing_scheme && is_underline) {
  691. if (italic_flag)
  692. putstring(SGR_NO_ITALIC);
  693. else if (reverse_flag)
  694. putstring(SGR_NO_REVERSE);
  695. else
  696. putstring(SGR_NO_UNDERLINE);
  697. is_underline = 0;
  698. }
  699. if (p->mode & BOLD_MODE)
  700. make_bold(p->code, p->w);
  701. else if (!old_drawing_scheme && is_bold) {
  702. putstring(SGR_NO_BOLD);
  703. is_bold = 0;
  704. }
  705. if (!old_drawing_scheme) {
  706. if (p->fore_color_idx != curr_fore_idx) {
  707. put_color(p->fore_color_idx, 0);
  708. curr_fore_idx = p->fore_color_idx;
  709. }
  710. if (p->back_color_idx != curr_back_idx) {
  711. put_color(p->back_color_idx, 1);
  712. curr_back_idx = p->back_color_idx;
  713. }
  714. }
  715. put_char(p->code);
  716. hpos += p->w / font::hor;
  717. }
  718. if (!old_drawing_scheme
  719. && (is_bold || is_underline
  720. || curr_fore_idx != DEFAULT_COLOR_IDX
  721. || curr_back_idx != DEFAULT_COLOR_IDX))
  722. putstring(SGR_DEFAULT);
  723. putchar('\n');
  724. }
  725. if (form_feed_flag) {
  726. if (last_line < lines_per_page)
  727. putchar('\f');
  728. }
  729. else {
  730. for (; last_line < lines_per_page; last_line++)
  731. putchar('\n');
  732. }
  733. }
  734. font *tty_printer::make_font(const char *nm)
  735. {
  736. return tty_font::load_tty_font(nm);
  737. }
  738. printer *make_printer()
  739. {
  740. return new tty_printer(device);
  741. }
  742. static void update_options()
  743. {
  744. if (old_drawing_scheme) {
  745. italic_flag = 0;
  746. reverse_flag = 0;
  747. bold_underline_mode = bold_underline_mode_option;
  748. bold_flag = bold_flag_option;
  749. underline_flag = underline_flag_option;
  750. }
  751. else {
  752. italic_flag = italic_flag_option;
  753. reverse_flag = reverse_flag_option;
  754. bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
  755. bold_flag = 1;
  756. underline_flag = 1;
  757. }
  758. }
  759. int main(int argc, char **argv)
  760. {
  761. program_name = argv[0];
  762. static char stderr_buf[BUFSIZ];
  763. if (getenv("GROFF_NO_SGR"))
  764. old_drawing_scheme = 1;
  765. setbuf(stderr, stderr_buf);
  766. int c;
  767. static const struct option long_options[] = {
  768. { "help", no_argument, 0, CHAR_MAX + 1 },
  769. { "version", no_argument, 0, 'v' },
  770. { NULL, 0, 0, 0 }
  771. };
  772. while ((c = getopt_long(argc, argv, "bBcdfF:hiI:oruUv", long_options, NULL))
  773. != EOF)
  774. switch(c) {
  775. case 'v':
  776. printf("GNU grotty (groff) version %s\n", Version_string);
  777. exit(0);
  778. break;
  779. case 'i':
  780. // Use italic font instead of underlining.
  781. italic_flag_option = 1;
  782. break;
  783. case 'I':
  784. // ignore include search path
  785. break;
  786. case 'b':
  787. // Do not embolden by overstriking.
  788. bold_flag_option = 0;
  789. break;
  790. case 'c':
  791. // Use old scheme for emboldening and underline.
  792. old_drawing_scheme = 1;
  793. break;
  794. case 'u':
  795. // Do not underline.
  796. underline_flag_option = 0;
  797. break;
  798. case 'o':
  799. // Do not overstrike (other than emboldening and underlining).
  800. overstrike_flag = 0;
  801. break;
  802. case 'r':
  803. // Use reverse mode instead of underlining.
  804. reverse_flag_option = 1;
  805. break;
  806. case 'B':
  807. // Do bold-underlining as bold.
  808. bold_underline_mode_option = BOLD_MODE;
  809. break;
  810. case 'U':
  811. // Do bold-underlining as underlining.
  812. bold_underline_mode_option = UNDERLINE_MODE;
  813. break;
  814. case 'h':
  815. // Use horizontal tabs.
  816. horizontal_tab_flag = 1;
  817. break;
  818. case 'f':
  819. form_feed_flag = 1;
  820. break;
  821. case 'F':
  822. font::command_line_font_dir(optarg);
  823. break;
  824. case 'd':
  825. // Ignore \D commands.
  826. draw_flag = 0;
  827. break;
  828. case CHAR_MAX + 1: // --help
  829. usage(stdout);
  830. exit(0);
  831. break;
  832. case '?':
  833. usage(stderr);
  834. exit(1);
  835. break;
  836. default:
  837. assert(0);
  838. }
  839. update_options();
  840. if (optind >= argc)
  841. do_file("-");
  842. else {
  843. for (int i = optind; i < argc; i++)
  844. do_file(argv[i]);
  845. }
  846. return 0;
  847. }
  848. static void usage(FILE *stream)
  849. {
  850. fprintf(stream, "usage: %s [-bBcdfhioruUv] [-F dir] [files ...]\n",
  851. program_name);
  852. }