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