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