1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989-2000, 2001, 2002, 2003, 2004, 2005 3151497Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru#include "driver.h" 23114402Sru#include "device.h" 24114402Sru#include "ptable.h" 25114402Sru 26151497Srutypedef signed char schar; 27114402Sru 28151497Srudeclare_ptable(schar) 29151497Sruimplement_ptable(schar) 30151497Sru 31114402Sruextern "C" const char *Version_string; 32114402Sru 33114402Sru#define putstring(s) fputs(s, stdout) 34114402Sru 35114402Sru#ifndef SHRT_MIN 36114402Sru#define SHRT_MIN (-32768) 37114402Sru#endif 38114402Sru 39114402Sru#ifndef SHRT_MAX 40114402Sru#define SHRT_MAX 32767 41114402Sru#endif 42114402Sru 43114402Sru#define TAB_WIDTH 8 44114402Sru 45114402Srustatic int horizontal_tab_flag = 0; 46114402Srustatic int form_feed_flag = 0; 47151497Srustatic int bold_flag_option = 1; 48151497Srustatic int bold_flag; 49151497Srustatic int underline_flag_option = 1; 50151497Srustatic int underline_flag; 51114402Srustatic int overstrike_flag = 1; 52114402Srustatic int draw_flag = 1; 53151497Srustatic int italic_flag_option = 0; 54151497Srustatic int italic_flag; 55151497Srustatic int reverse_flag_option = 0; 56151497Srustatic int reverse_flag; 57114402Srustatic int old_drawing_scheme = 0; 58114402Sru 59151497Srustatic void update_options(); 60151497Srustatic void usage(FILE *stream); 61151497Sru 62151497Srustatic int hline_char = '-'; 63151497Srustatic int vline_char = '|'; 64151497Sru 65114402Sruenum { 66114402Sru UNDERLINE_MODE = 0x01, 67114402Sru BOLD_MODE = 0x02, 68114402Sru VDRAW_MODE = 0x04, 69114402Sru HDRAW_MODE = 0x08, 70114402Sru CU_MODE = 0x10, 71151497Sru COLOR_CHANGE = 0x20, 72151497Sru START_LINE = 0x40, 73151497Sru END_LINE = 0x80 74114402Sru}; 75114402Sru 76114402Sru// Mode to use for bold-underlining. 77151497Srustatic unsigned char bold_underline_mode_option = BOLD_MODE|UNDERLINE_MODE; 78151497Srustatic unsigned char bold_underline_mode; 79114402Sru 80114402Sru#ifndef IS_EBCDIC_HOST 81114402Sru#define CSI "\033[" 82114402Sru#else 83114402Sru#define CSI "\047[" 84114402Sru#endif 85114402Sru 86114402Sru// SGR handling (ISO 6429) 87114402Sru#define SGR_BOLD CSI "1m" 88114402Sru#define SGR_NO_BOLD CSI "22m" 89114402Sru#define SGR_ITALIC CSI "3m" 90114402Sru#define SGR_NO_ITALIC CSI "23m" 91114402Sru#define SGR_UNDERLINE CSI "4m" 92114402Sru#define SGR_NO_UNDERLINE CSI "24m" 93114402Sru#define SGR_REVERSE CSI "7m" 94114402Sru#define SGR_NO_REVERSE CSI "27m" 95114402Sru// many terminals can't handle `CSI 39 m' and `CSI 49 m' to reset 96151497Sru// the foreground and background color, respectively; we thus use 97114402Sru// `CSI 0 m' exclusively 98114402Sru#define SGR_DEFAULT CSI "0m" 99114402Sru 100114402Sru#define DEFAULT_COLOR_IDX -1 101114402Sru 102114402Sruclass tty_font : public font { 103114402Sru tty_font(const char *); 104114402Sru unsigned char mode; 105114402Srupublic: 106114402Sru ~tty_font(); 107114402Sru unsigned char get_mode() { return mode; } 108114402Sru#if 0 109114402Sru void handle_x_command(int argc, const char **argv); 110114402Sru#endif 111114402Sru static tty_font *load_tty_font(const char *); 112114402Sru}; 113114402Sru 114114402Srutty_font *tty_font::load_tty_font(const char *s) 115114402Sru{ 116114402Sru tty_font *f = new tty_font(s); 117114402Sru if (!f->load()) { 118114402Sru delete f; 119114402Sru return 0; 120114402Sru } 121114402Sru const char *num = f->get_internal_name(); 122114402Sru long n; 123114402Sru if (num != 0 && (n = strtol(num, 0, 0)) != 0) 124151497Sru f->mode = (unsigned char)(n & (BOLD_MODE|UNDERLINE_MODE)); 125114402Sru if (!underline_flag) 126114402Sru f->mode &= ~UNDERLINE_MODE; 127114402Sru if (!bold_flag) 128114402Sru f->mode &= ~BOLD_MODE; 129114402Sru if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE)) 130151497Sru f->mode = (unsigned char)((f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) 131151497Sru | bold_underline_mode); 132114402Sru return f; 133114402Sru} 134114402Sru 135114402Srutty_font::tty_font(const char *nm) 136114402Sru: font(nm), mode(0) 137114402Sru{ 138114402Sru} 139114402Sru 140114402Srutty_font::~tty_font() 141114402Sru{ 142114402Sru} 143114402Sru 144114402Sru#if 0 145114402Sruvoid tty_font::handle_x_command(int argc, const char **argv) 146114402Sru{ 147114402Sru if (argc >= 1 && strcmp(argv[0], "bold") == 0) 148114402Sru mode |= BOLD_MODE; 149114402Sru else if (argc >= 1 && strcmp(argv[0], "underline") == 0) 150114402Sru mode |= UNDERLINE_MODE; 151114402Sru} 152114402Sru#endif 153114402Sru 154114402Sruclass glyph { 155114402Sru static glyph *free_list; 156114402Srupublic: 157114402Sru glyph *next; 158151497Sru int w; 159151497Sru int hpos; 160114402Sru unsigned int code; 161114402Sru unsigned char mode; 162151497Sru schar back_color_idx; 163151497Sru schar fore_color_idx; 164114402Sru void *operator new(size_t); 165114402Sru void operator delete(void *); 166114402Sru inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); } 167114402Sru inline int order() { 168114402Sru return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); } 169114402Sru}; 170114402Sru 171114402Sruglyph *glyph::free_list = 0; 172114402Sru 173114402Sruvoid *glyph::operator new(size_t) 174114402Sru{ 175114402Sru if (!free_list) { 176114402Sru const int BLOCK = 1024; 177114402Sru free_list = (glyph *)new char[sizeof(glyph) * BLOCK]; 178114402Sru for (int i = 0; i < BLOCK - 1; i++) 179114402Sru free_list[i].next = free_list + i + 1; 180114402Sru free_list[BLOCK - 1].next = 0; 181114402Sru } 182114402Sru glyph *p = free_list; 183114402Sru free_list = free_list->next; 184114402Sru p->next = 0; 185114402Sru return p; 186114402Sru} 187114402Sru 188114402Sruvoid glyph::operator delete(void *p) 189114402Sru{ 190114402Sru if (p) { 191114402Sru ((glyph *)p)->next = free_list; 192114402Sru free_list = (glyph *)p; 193114402Sru } 194114402Sru} 195114402Sru 196114402Sruclass tty_printer : public printer { 197114402Sru int is_utf8; 198114402Sru glyph **lines; 199114402Sru int nlines; 200114402Sru int cached_v; 201114402Sru int cached_vpos; 202151497Sru schar curr_fore_idx; 203151497Sru schar curr_back_idx; 204114402Sru int is_underline; 205114402Sru int is_bold; 206114402Sru int cu_flag; 207151497Sru PTABLE(schar) tty_colors; 208151497Sru void make_underline(int); 209151497Sru void make_bold(unsigned int, int); 210151497Sru schar color_to_idx(color *col); 211151497Sru void add_char(unsigned int, int, int, int, color *, color *, unsigned char); 212114402Sru char *make_rgb_string(unsigned int, unsigned int, unsigned int); 213151497Sru int tty_color(unsigned int, unsigned int, unsigned int, schar *, 214151497Sru schar = DEFAULT_COLOR_IDX); 215114402Srupublic: 216114402Sru tty_printer(const char *device); 217114402Sru ~tty_printer(); 218114402Sru void set_char(int, font *, const environment *, int, const char *name); 219114402Sru void draw(int code, int *p, int np, const environment *env); 220114402Sru void special(char *arg, const environment *env, char type); 221114402Sru void change_color(const environment * const env); 222114402Sru void change_fill_color(const environment * const env); 223114402Sru void put_char(unsigned int); 224151497Sru void put_color(schar, int); 225114402Sru void begin_page(int) { } 226114402Sru void end_page(int page_length); 227114402Sru font *make_font(const char *); 228114402Sru}; 229114402Sru 230114402Sruchar *tty_printer::make_rgb_string(unsigned int r, 231114402Sru unsigned int g, 232114402Sru unsigned int b) 233114402Sru{ 234114402Sru char *s = new char[8]; 235114402Sru s[0] = char(r >> 8); 236114402Sru s[1] = char(r & 0xff); 237114402Sru s[2] = char(g >> 8); 238114402Sru s[3] = char(g & 0xff); 239114402Sru s[4] = char(b >> 8); 240114402Sru s[5] = char(b & 0xff); 241114402Sru s[6] = char(0x80); 242114402Sru s[7] = 0; 243114402Sru // avoid null-bytes in string 244114402Sru for (int i = 0; i < 6; i++) 245114402Sru if (!s[i]) { 246114402Sru s[i] = 1; 247114402Sru s[6] |= 1 << i; 248114402Sru } 249114402Sru return s; 250114402Sru} 251114402Sru 252114402Sruint tty_printer::tty_color(unsigned int r, 253114402Sru unsigned int g, 254151497Sru unsigned int b, schar *idx, schar value) 255114402Sru{ 256114402Sru int unknown_color = 0; 257114402Sru char *s = make_rgb_string(r, g, b); 258151497Sru schar *i = tty_colors.lookup(s); 259114402Sru if (!i) { 260114402Sru unknown_color = 1; 261151497Sru i = new schar[1]; 262114402Sru *i = value; 263114402Sru tty_colors.define(s, i); 264114402Sru } 265114402Sru *idx = *i; 266114402Sru a_delete s; 267114402Sru return unknown_color; 268114402Sru} 269114402Sru 270151497Srutty_printer::tty_printer(const char *dev) : cached_v(0) 271114402Sru{ 272151497Sru is_utf8 = !strcmp(dev, "utf8"); 273151497Sru if (is_utf8) { 274151497Sru hline_char = 0x2500; 275151497Sru vline_char = 0x2502; 276151497Sru } 277151497Sru schar dummy; 278114402Sru // black, white 279114402Sru (void)tty_color(0, 0, 0, &dummy, 0); 280114402Sru (void)tty_color(color::MAX_COLOR_VAL, 281114402Sru color::MAX_COLOR_VAL, 282114402Sru color::MAX_COLOR_VAL, &dummy, 7); 283114402Sru // red, green, blue 284114402Sru (void)tty_color(color::MAX_COLOR_VAL, 0, 0, &dummy, 1); 285114402Sru (void)tty_color(0, color::MAX_COLOR_VAL, 0, &dummy, 2); 286114402Sru (void)tty_color(0, 0, color::MAX_COLOR_VAL, &dummy, 4); 287114402Sru // yellow, magenta, cyan 288114402Sru (void)tty_color(color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, 0, &dummy, 3); 289114402Sru (void)tty_color(color::MAX_COLOR_VAL, 0, color::MAX_COLOR_VAL, &dummy, 5); 290114402Sru (void)tty_color(0, color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, &dummy, 6); 291114402Sru nlines = 66; 292114402Sru lines = new glyph *[nlines]; 293114402Sru for (int i = 0; i < nlines; i++) 294114402Sru lines[i] = 0; 295114402Sru cu_flag = 0; 296114402Sru} 297114402Sru 298114402Srutty_printer::~tty_printer() 299114402Sru{ 300114402Sru a_delete lines; 301114402Sru} 302114402Sru 303151497Sruvoid tty_printer::make_underline(int w) 304114402Sru{ 305114402Sru if (old_drawing_scheme) { 306151497Sru if (!w) 307151497Sru warning("can't underline zero-width character"); 308151497Sru else { 309151497Sru int n = w / font::hor; 310151497Sru for (int i = 0; i < n; i++) 311151497Sru putchar('_'); 312151497Sru for (int j = 0; j < n; j++) 313151497Sru putchar('\b'); 314151497Sru } 315114402Sru } 316114402Sru else { 317114402Sru if (!is_underline) { 318114402Sru if (italic_flag) 319114402Sru putstring(SGR_ITALIC); 320114402Sru else if (reverse_flag) 321114402Sru putstring(SGR_REVERSE); 322114402Sru else 323114402Sru putstring(SGR_UNDERLINE); 324114402Sru } 325114402Sru is_underline = 1; 326114402Sru } 327114402Sru} 328114402Sru 329151497Sruvoid tty_printer::make_bold(unsigned int c, int w) 330114402Sru{ 331114402Sru if (old_drawing_scheme) { 332151497Sru if (!w) 333151497Sru warning("can't print zero-width character in bold"); 334151497Sru else { 335151497Sru int n = w / font::hor; 336151497Sru put_char(c); 337151497Sru for (int i = 0; i < n; i++) 338151497Sru putchar('\b'); 339151497Sru } 340114402Sru } 341114402Sru else { 342114402Sru if (!is_bold) 343114402Sru putstring(SGR_BOLD); 344114402Sru is_bold = 1; 345114402Sru } 346114402Sru} 347114402Sru 348151497Sruschar tty_printer::color_to_idx(color *col) 349114402Sru{ 350114402Sru if (col->is_default()) 351114402Sru return DEFAULT_COLOR_IDX; 352114402Sru unsigned int r, g, b; 353114402Sru col->get_rgb(&r, &g, &b); 354151497Sru schar idx; 355114402Sru if (tty_color(r, g, b, &idx)) { 356114402Sru char *s = col->print_color(); 357114402Sru error("Unknown color (%1) mapped to default", s); 358114402Sru a_delete s; 359114402Sru } 360114402Sru return idx; 361114402Sru} 362114402Sru 363114402Sruvoid tty_printer::set_char(int i, font *f, const environment *env, 364114402Sru int w, const char *) 365114402Sru{ 366151497Sru if (w % font::hor != 0) 367151497Sru fatal("width of character not a multiple of horizontal resolution"); 368151497Sru add_char(f->get_code(i), w, 369114402Sru env->hpos, env->vpos, 370114402Sru env->col, env->fill, 371114402Sru ((tty_font *)f)->get_mode()); 372114402Sru} 373114402Sru 374151497Sruvoid tty_printer::add_char(unsigned int c, int w, 375114402Sru int h, int v, 376114402Sru color *fore, color *back, 377114402Sru unsigned char mode) 378114402Sru{ 379114402Sru#if 0 380114402Sru // This is too expensive. 381114402Sru if (h % font::hor != 0) 382114402Sru fatal("horizontal position not a multiple of horizontal resolution"); 383114402Sru#endif 384114402Sru int hpos = h / font::hor; 385114402Sru if (hpos < SHRT_MIN || hpos > SHRT_MAX) { 386114402Sru error("character with ridiculous horizontal position discarded"); 387114402Sru return; 388114402Sru } 389114402Sru int vpos; 390114402Sru if (v == cached_v && cached_v != 0) 391114402Sru vpos = cached_vpos; 392114402Sru else { 393114402Sru if (v % font::vert != 0) 394114402Sru fatal("vertical position not a multiple of vertical resolution"); 395114402Sru vpos = v / font::vert; 396114402Sru if (vpos > nlines) { 397114402Sru glyph **old_lines = lines; 398114402Sru lines = new glyph *[vpos + 1]; 399114402Sru memcpy(lines, old_lines, nlines * sizeof(glyph *)); 400114402Sru for (int i = nlines; i <= vpos; i++) 401114402Sru lines[i] = 0; 402114402Sru a_delete old_lines; 403114402Sru nlines = vpos + 1; 404114402Sru } 405114402Sru // Note that the first output line corresponds to groff 406114402Sru // position font::vert. 407114402Sru if (vpos <= 0) { 408114402Sru error("character above first line discarded"); 409114402Sru return; 410114402Sru } 411114402Sru cached_v = v; 412114402Sru cached_vpos = vpos; 413114402Sru } 414114402Sru glyph *g = new glyph; 415151497Sru g->w = w; 416114402Sru g->hpos = hpos; 417114402Sru g->code = c; 418114402Sru g->fore_color_idx = color_to_idx(fore); 419114402Sru g->back_color_idx = color_to_idx(back); 420114402Sru g->mode = mode; 421114402Sru 422114402Sru // The list will be reversed later. After reversal, it must be in 423114402Sru // increasing order of hpos, with COLOR_CHANGE and CU specials before 424114402Sru // HDRAW characters before VDRAW characters before normal characters 425114402Sru // at each hpos, and otherwise in order of occurrence. 426114402Sru 427114402Sru glyph **pp; 428114402Sru for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next) 429114402Sru if ((*pp)->hpos < hpos 430114402Sru || ((*pp)->hpos == hpos && (*pp)->order() >= g->order())) 431114402Sru break; 432114402Sru g->next = *pp; 433114402Sru *pp = g; 434114402Sru} 435114402Sru 436114402Sruvoid tty_printer::special(char *arg, const environment *env, char type) 437114402Sru{ 438114402Sru if (type == 'u') { 439151497Sru add_char(*arg - '0', 0, env->hpos, env->vpos, env->col, env->fill, 440151497Sru CU_MODE); 441114402Sru return; 442114402Sru } 443114402Sru if (type != 'p') 444114402Sru return; 445114402Sru char *p; 446114402Sru for (p = arg; *p == ' ' || *p == '\n'; p++) 447114402Sru ; 448114402Sru char *tag = p; 449114402Sru for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++) 450114402Sru ; 451114402Sru if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) { 452114402Sru error("X command without `tty:' tag ignored"); 453114402Sru return; 454114402Sru } 455114402Sru p++; 456114402Sru for (; *p == ' ' || *p == '\n'; p++) 457114402Sru ; 458114402Sru char *command = p; 459114402Sru for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) 460114402Sru ; 461114402Sru if (*command == '\0') { 462114402Sru error("empty X command ignored"); 463114402Sru return; 464114402Sru } 465114402Sru if (strncmp(command, "sgr", p - command) == 0) { 466114402Sru for (; *p == ' ' || *p == '\n'; p++) 467114402Sru ; 468114402Sru int n; 469114402Sru if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0) 470114402Sru old_drawing_scheme = 1; 471114402Sru else 472114402Sru old_drawing_scheme = 0; 473151497Sru update_options(); 474114402Sru } 475114402Sru} 476114402Sru 477114402Sruvoid tty_printer::change_color(const environment * const env) 478114402Sru{ 479151497Sru add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE); 480114402Sru} 481114402Sru 482114402Sruvoid tty_printer::change_fill_color(const environment * const env) 483114402Sru{ 484151497Sru add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE); 485114402Sru} 486114402Sru 487114402Sruvoid tty_printer::draw(int code, int *p, int np, const environment *env) 488114402Sru{ 489114402Sru if (code != 'l' || !draw_flag) 490114402Sru return; 491114402Sru if (np != 2) { 492114402Sru error("2 arguments required for line"); 493114402Sru return; 494114402Sru } 495114402Sru if (p[0] == 0) { 496114402Sru // vertical line 497114402Sru int v = env->vpos; 498114402Sru int len = p[1]; 499114402Sru if (len < 0) { 500114402Sru v += len; 501114402Sru len = -len; 502114402Sru } 503151497Sru if (len >= 0 && len <= font::vert) 504151497Sru add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill, 505151497Sru VDRAW_MODE|START_LINE|END_LINE); 506151497Sru else { 507151497Sru add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill, 508151497Sru VDRAW_MODE|START_LINE); 509114402Sru len -= font::vert; 510114402Sru v += font::vert; 511151497Sru while (len > 0) { 512151497Sru add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill, 513151497Sru VDRAW_MODE|START_LINE|END_LINE); 514151497Sru len -= font::vert; 515151497Sru v += font::vert; 516151497Sru } 517151497Sru add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill, 518151497Sru VDRAW_MODE|END_LINE); 519114402Sru } 520114402Sru } 521114402Sru if (p[1] == 0) { 522114402Sru // horizontal line 523114402Sru int h = env->hpos; 524114402Sru int len = p[0]; 525114402Sru if (len < 0) { 526114402Sru h += len; 527114402Sru len = -len; 528114402Sru } 529151497Sru if (len >= 0 && len <= font::hor) 530151497Sru add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill, 531151497Sru HDRAW_MODE|START_LINE|END_LINE); 532151497Sru else { 533151497Sru add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill, 534151497Sru HDRAW_MODE|START_LINE); 535114402Sru len -= font::hor; 536114402Sru h += font::hor; 537151497Sru while (len > 0) { 538151497Sru add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill, 539151497Sru HDRAW_MODE|START_LINE|END_LINE); 540151497Sru len -= font::hor; 541151497Sru h += font::hor; 542151497Sru } 543151497Sru add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill, 544151497Sru HDRAW_MODE|END_LINE); 545114402Sru } 546114402Sru } 547114402Sru} 548114402Sru 549114402Sruvoid tty_printer::put_char(unsigned int wc) 550114402Sru{ 551114402Sru if (is_utf8 && wc >= 0x80) { 552114402Sru char buf[6 + 1]; 553114402Sru int count; 554114402Sru char *p = buf; 555114402Sru if (wc < 0x800) 556114402Sru count = 1, *p = (unsigned char)((wc >> 6) | 0xc0); 557114402Sru else if (wc < 0x10000) 558114402Sru count = 2, *p = (unsigned char)((wc >> 12) | 0xe0); 559114402Sru else if (wc < 0x200000) 560114402Sru count = 3, *p = (unsigned char)((wc >> 18) | 0xf0); 561114402Sru else if (wc < 0x4000000) 562114402Sru count = 4, *p = (unsigned char)((wc >> 24) | 0xf8); 563114402Sru else if (wc <= 0x7fffffff) 564114402Sru count = 5, *p = (unsigned char)((wc >> 30) | 0xfC); 565114402Sru else 566114402Sru return; 567114402Sru do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80); 568114402Sru while (count > 0); 569114402Sru *++p = '\0'; 570114402Sru putstring(buf); 571114402Sru } 572114402Sru else 573114402Sru putchar(wc); 574114402Sru} 575114402Sru 576151497Sruvoid tty_printer::put_color(schar color_index, int back) 577114402Sru{ 578114402Sru if (color_index == DEFAULT_COLOR_IDX) { 579114402Sru putstring(SGR_DEFAULT); 580114402Sru // set bold and underline again 581114402Sru if (is_bold) 582114402Sru putstring(SGR_BOLD); 583114402Sru if (is_underline) { 584114402Sru if (italic_flag) 585114402Sru putstring(SGR_ITALIC); 586114402Sru else if (reverse_flag) 587114402Sru putstring(SGR_REVERSE); 588114402Sru else 589114402Sru putstring(SGR_UNDERLINE); 590114402Sru } 591114402Sru // set other color again 592114402Sru back = !back; 593114402Sru color_index = back ? curr_back_idx : curr_fore_idx; 594114402Sru } 595114402Sru if (color_index != DEFAULT_COLOR_IDX) { 596114402Sru putstring(CSI); 597114402Sru if (back) 598114402Sru putchar('4'); 599114402Sru else 600114402Sru putchar('3'); 601114402Sru putchar(color_index + '0'); 602114402Sru putchar('m'); 603114402Sru } 604114402Sru} 605114402Sru 606151497Sru// The possible Unicode combinations for crossing characters. 607151497Sru// 608151497Sru// ` ' = 0, ` -' = 4, `- ' = 8, `--' = 12, 609151497Sru// 610151497Sru// ` ' = 0, ` ' = 1, `|' = 2, `|' = 3 611151497Sru// | | 612151497Sru 613151497Srustatic int crossings[4*4] = { 614151497Sru 0x0000, 0x2577, 0x2575, 0x2502, 615151497Sru 0x2576, 0x250C, 0x2514, 0x251C, 616151497Sru 0x2574, 0x2510, 0x2518, 0x2524, 617151497Sru 0x2500, 0x252C, 0x2534, 0x253C 618151497Sru}; 619151497Sru 620114402Sruvoid tty_printer::end_page(int page_length) 621114402Sru{ 622114402Sru if (page_length % font::vert != 0) 623114402Sru error("vertical position at end of page not multiple of vertical resolution"); 624114402Sru int lines_per_page = page_length / font::vert; 625114402Sru int last_line; 626114402Sru for (last_line = nlines; last_line > 0; last_line--) 627114402Sru if (lines[last_line - 1]) 628114402Sru break; 629114402Sru#if 0 630114402Sru if (last_line > lines_per_page) { 631114402Sru error("characters past last line discarded"); 632114402Sru do { 633114402Sru --last_line; 634114402Sru while (lines[last_line]) { 635114402Sru glyph *tem = lines[last_line]; 636114402Sru lines[last_line] = tem->next; 637114402Sru delete tem; 638114402Sru } 639114402Sru } while (last_line > lines_per_page); 640114402Sru } 641114402Sru#endif 642114402Sru for (int i = 0; i < last_line; i++) { 643114402Sru glyph *p = lines[i]; 644114402Sru lines[i] = 0; 645114402Sru glyph *g = 0; 646114402Sru while (p) { 647114402Sru glyph *tem = p->next; 648114402Sru p->next = g; 649114402Sru g = p; 650114402Sru p = tem; 651114402Sru } 652114402Sru int hpos = 0; 653114402Sru glyph *nextp; 654114402Sru curr_fore_idx = DEFAULT_COLOR_IDX; 655114402Sru curr_back_idx = DEFAULT_COLOR_IDX; 656114402Sru is_underline = 0; 657114402Sru is_bold = 0; 658114402Sru for (p = g; p; delete p, p = nextp) { 659114402Sru nextp = p->next; 660114402Sru if (p->mode & CU_MODE) { 661114402Sru cu_flag = p->code; 662114402Sru continue; 663114402Sru } 664114402Sru if (nextp && p->hpos == nextp->hpos) { 665114402Sru if (p->draw_mode() == HDRAW_MODE && 666114402Sru nextp->draw_mode() == VDRAW_MODE) { 667151497Sru if (is_utf8) 668151497Sru nextp->code = 669151497Sru crossings[((p->mode & (START_LINE|END_LINE)) >> 4) 670151497Sru + ((nextp->mode & (START_LINE|END_LINE)) >> 6)]; 671151497Sru else 672151497Sru nextp->code = '+'; 673114402Sru continue; 674114402Sru } 675114402Sru if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) { 676114402Sru nextp->code = p->code; 677114402Sru continue; 678114402Sru } 679114402Sru if (!overstrike_flag) 680114402Sru continue; 681114402Sru } 682114402Sru if (hpos > p->hpos) { 683114402Sru do { 684114402Sru putchar('\b'); 685114402Sru hpos--; 686114402Sru } while (hpos > p->hpos); 687114402Sru } 688114402Sru else { 689114402Sru if (horizontal_tab_flag) { 690114402Sru for (;;) { 691114402Sru int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH; 692114402Sru if (next_tab_pos > p->hpos) 693114402Sru break; 694114402Sru if (cu_flag) 695151497Sru make_underline(p->w); 696114402Sru else if (!old_drawing_scheme && is_underline) { 697114402Sru if (italic_flag) 698114402Sru putstring(SGR_NO_ITALIC); 699114402Sru else if (reverse_flag) 700114402Sru putstring(SGR_NO_REVERSE); 701114402Sru else 702114402Sru putstring(SGR_NO_UNDERLINE); 703114402Sru is_underline = 0; 704114402Sru } 705114402Sru putchar('\t'); 706114402Sru hpos = next_tab_pos; 707114402Sru } 708114402Sru } 709114402Sru for (; hpos < p->hpos; hpos++) { 710114402Sru if (cu_flag) 711151497Sru make_underline(p->w); 712114402Sru else if (!old_drawing_scheme && is_underline) { 713114402Sru if (italic_flag) 714114402Sru putstring(SGR_NO_ITALIC); 715114402Sru else if (reverse_flag) 716114402Sru putstring(SGR_NO_REVERSE); 717114402Sru else 718114402Sru putstring(SGR_NO_UNDERLINE); 719114402Sru is_underline = 0; 720114402Sru } 721114402Sru putchar(' '); 722114402Sru } 723114402Sru } 724114402Sru assert(hpos == p->hpos); 725114402Sru if (p->mode & COLOR_CHANGE) { 726114402Sru if (!old_drawing_scheme) { 727114402Sru if (p->fore_color_idx != curr_fore_idx) { 728114402Sru put_color(p->fore_color_idx, 0); 729114402Sru curr_fore_idx = p->fore_color_idx; 730114402Sru } 731114402Sru if (p->back_color_idx != curr_back_idx) { 732114402Sru put_color(p->back_color_idx, 1); 733114402Sru curr_back_idx = p->back_color_idx; 734114402Sru } 735114402Sru } 736114402Sru continue; 737114402Sru } 738114402Sru if (p->mode & UNDERLINE_MODE) 739151497Sru make_underline(p->w); 740114402Sru else if (!old_drawing_scheme && is_underline) { 741114402Sru if (italic_flag) 742114402Sru putstring(SGR_NO_ITALIC); 743114402Sru else if (reverse_flag) 744114402Sru putstring(SGR_NO_REVERSE); 745114402Sru else 746114402Sru putstring(SGR_NO_UNDERLINE); 747114402Sru is_underline = 0; 748114402Sru } 749114402Sru if (p->mode & BOLD_MODE) 750151497Sru make_bold(p->code, p->w); 751114402Sru else if (!old_drawing_scheme && is_bold) { 752114402Sru putstring(SGR_NO_BOLD); 753114402Sru is_bold = 0; 754114402Sru } 755114402Sru if (!old_drawing_scheme) { 756114402Sru if (p->fore_color_idx != curr_fore_idx) { 757114402Sru put_color(p->fore_color_idx, 0); 758114402Sru curr_fore_idx = p->fore_color_idx; 759114402Sru } 760114402Sru if (p->back_color_idx != curr_back_idx) { 761114402Sru put_color(p->back_color_idx, 1); 762114402Sru curr_back_idx = p->back_color_idx; 763114402Sru } 764114402Sru } 765114402Sru put_char(p->code); 766151497Sru hpos += p->w / font::hor; 767114402Sru } 768114402Sru if (!old_drawing_scheme 769114402Sru && (is_bold || is_underline 770114402Sru || curr_fore_idx != DEFAULT_COLOR_IDX 771114402Sru || curr_back_idx != DEFAULT_COLOR_IDX)) 772114402Sru putstring(SGR_DEFAULT); 773114402Sru putchar('\n'); 774114402Sru } 775114402Sru if (form_feed_flag) { 776114402Sru if (last_line < lines_per_page) 777114402Sru putchar('\f'); 778114402Sru } 779114402Sru else { 780114402Sru for (; last_line < lines_per_page; last_line++) 781114402Sru putchar('\n'); 782114402Sru } 783114402Sru} 784114402Sru 785114402Srufont *tty_printer::make_font(const char *nm) 786114402Sru{ 787114402Sru return tty_font::load_tty_font(nm); 788114402Sru} 789114402Sru 790114402Sruprinter *make_printer() 791114402Sru{ 792114402Sru return new tty_printer(device); 793114402Sru} 794114402Sru 795151497Srustatic void update_options() 796151497Sru{ 797151497Sru if (old_drawing_scheme) { 798151497Sru italic_flag = 0; 799151497Sru reverse_flag = 0; 800151497Sru bold_underline_mode = bold_underline_mode_option; 801151497Sru bold_flag = bold_flag_option; 802151497Sru underline_flag = underline_flag_option; 803151497Sru } 804151497Sru else { 805151497Sru italic_flag = italic_flag_option; 806151497Sru reverse_flag = reverse_flag_option; 807151497Sru bold_underline_mode = BOLD_MODE|UNDERLINE_MODE; 808151497Sru bold_flag = 1; 809151497Sru underline_flag = 1; 810151497Sru } 811151497Sru} 812114402Sru 813114402Sruint main(int argc, char **argv) 814114402Sru{ 815114402Sru program_name = argv[0]; 816114402Sru static char stderr_buf[BUFSIZ]; 817114402Sru if (getenv("GROFF_NO_SGR")) 818114402Sru old_drawing_scheme = 1; 819114402Sru setbuf(stderr, stderr_buf); 820114402Sru int c; 821114402Sru static const struct option long_options[] = { 822114402Sru { "help", no_argument, 0, CHAR_MAX + 1 }, 823114402Sru { "version", no_argument, 0, 'v' }, 824114402Sru { NULL, 0, 0, 0 } 825114402Sru }; 826151497Sru while ((c = getopt_long(argc, argv, "bBcdfF:hiI:oruUv", long_options, NULL)) 827114402Sru != EOF) 828114402Sru switch(c) { 829114402Sru case 'v': 830114402Sru printf("GNU grotty (groff) version %s\n", Version_string); 831114402Sru exit(0); 832114402Sru break; 833114402Sru case 'i': 834114402Sru // Use italic font instead of underlining. 835151497Sru italic_flag_option = 1; 836114402Sru break; 837151497Sru case 'I': 838151497Sru // ignore include search path 839151497Sru break; 840114402Sru case 'b': 841114402Sru // Do not embolden by overstriking. 842151497Sru bold_flag_option = 0; 843114402Sru break; 844114402Sru case 'c': 845114402Sru // Use old scheme for emboldening and underline. 846114402Sru old_drawing_scheme = 1; 847114402Sru break; 848114402Sru case 'u': 849114402Sru // Do not underline. 850151497Sru underline_flag_option = 0; 851114402Sru break; 852114402Sru case 'o': 853114402Sru // Do not overstrike (other than emboldening and underlining). 854114402Sru overstrike_flag = 0; 855114402Sru break; 856114402Sru case 'r': 857114402Sru // Use reverse mode instead of underlining. 858151497Sru reverse_flag_option = 1; 859114402Sru break; 860114402Sru case 'B': 861114402Sru // Do bold-underlining as bold. 862151497Sru bold_underline_mode_option = BOLD_MODE; 863114402Sru break; 864114402Sru case 'U': 865114402Sru // Do bold-underlining as underlining. 866151497Sru bold_underline_mode_option = UNDERLINE_MODE; 867114402Sru break; 868114402Sru case 'h': 869114402Sru // Use horizontal tabs. 870114402Sru horizontal_tab_flag = 1; 871114402Sru break; 872114402Sru case 'f': 873114402Sru form_feed_flag = 1; 874114402Sru break; 875114402Sru case 'F': 876114402Sru font::command_line_font_dir(optarg); 877114402Sru break; 878114402Sru case 'd': 879114402Sru // Ignore \D commands. 880114402Sru draw_flag = 0; 881114402Sru break; 882114402Sru case CHAR_MAX + 1: // --help 883114402Sru usage(stdout); 884114402Sru exit(0); 885114402Sru break; 886114402Sru case '?': 887114402Sru usage(stderr); 888114402Sru exit(1); 889114402Sru break; 890114402Sru default: 891114402Sru assert(0); 892114402Sru } 893151497Sru update_options(); 894114402Sru if (optind >= argc) 895114402Sru do_file("-"); 896114402Sru else { 897114402Sru for (int i = optind; i < argc; i++) 898114402Sru do_file(argv[i]); 899114402Sru } 900114402Sru return 0; 901114402Sru} 902114402Sru 903114402Srustatic void usage(FILE *stream) 904114402Sru{ 905114402Sru fprintf(stream, "usage: %s [-bBcdfhioruUv] [-F dir] [files ...]\n", 906114402Sru program_name); 907114402Sru} 908