* All affected files: Update postal address of FSF.
[s-roff.git] / src / devices / grotty / tty.cpp
bloba959461f922a05ead0cd3af6cbb36135be7b4464
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)
6 This file is part of groff.
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING. If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
22 #include "driver.h"
23 #include "device.h"
24 #include "ptable.h"
26 typedef signed char schar;
28 declare_ptable(schar)
29 implement_ptable(schar)
31 extern "C" const char *Version_string;
33 #define putstring(s) fputs(s, stdout)
35 #ifndef SHRT_MIN
36 #define SHRT_MIN (-32768)
37 #endif
39 #ifndef SHRT_MAX
40 #define SHRT_MAX 32767
41 #endif
43 #define TAB_WIDTH 8
45 static int horizontal_tab_flag = 0;
46 static int form_feed_flag = 0;
47 static int bold_flag_option = 1;
48 static int bold_flag;
49 static int underline_flag_option = 1;
50 static int underline_flag;
51 static int overstrike_flag = 1;
52 static int draw_flag = 1;
53 static int italic_flag_option = 0;
54 static int italic_flag;
55 static int reverse_flag_option = 0;
56 static int reverse_flag;
57 static int old_drawing_scheme = 0;
59 static void update_options();
60 static void usage(FILE *stream);
62 static int hline_char = '-';
63 static int vline_char = '|';
65 enum {
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
76 // Mode to use for bold-underlining.
77 static unsigned char bold_underline_mode_option = BOLD_MODE|UNDERLINE_MODE;
78 static unsigned char bold_underline_mode;
80 #ifndef IS_EBCDIC_HOST
81 #define CSI "\033["
82 #else
83 #define CSI "\047["
84 #endif
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"
100 #define DEFAULT_COLOR_IDX -1
102 class tty_font : public font {
103 tty_font(const char *);
104 unsigned char mode;
105 public:
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 *);
114 tty_font *tty_font::load_tty_font(const char *s)
116 tty_font *f = new tty_font(s);
117 if (!f->load()) {
118 delete f;
119 return 0;
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;
135 tty_font::tty_font(const char *nm)
136 : font(nm), mode(0)
140 tty_font::~tty_font()
144 #if 0
145 void tty_font::handle_x_command(int argc, const char **argv)
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;
152 #endif
154 class glyph {
155 static glyph *free_list;
156 public:
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); }
171 glyph *glyph::free_list = 0;
173 void *glyph::operator new(size_t)
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;
182 glyph *p = free_list;
183 free_list = free_list->next;
184 p->next = 0;
185 return p;
188 void glyph::operator delete(void *p)
190 if (p) {
191 ((glyph *)p)->next = free_list;
192 free_list = (glyph *)p;
196 class 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);
215 public:
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 *);
230 char *tty_printer::make_rgb_string(unsigned int r,
231 unsigned int g,
232 unsigned int b)
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;
249 return s;
252 int tty_printer::tty_color(unsigned int r,
253 unsigned int g,
254 unsigned int b, schar *idx, schar value)
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);
265 *idx = *i;
266 a_delete s;
267 return unknown_color;
270 tty_printer::tty_printer(const char *dev) : cached_v(0)
272 is_utf8 = !strcmp(dev, "utf8");
273 if (is_utf8) {
274 hline_char = 0x2500;
275 vline_char = 0x2502;
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;
298 tty_printer::~tty_printer()
300 a_delete lines;
303 void tty_printer::make_underline(int w)
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');
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);
325 is_underline = 1;
329 void tty_printer::make_bold(unsigned int c, int w)
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');
341 else {
342 if (!is_bold)
343 putstring(SGR_BOLD);
344 is_bold = 1;
348 schar tty_printer::color_to_idx(color *col)
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;
360 return idx;
363 void tty_printer::set_char(int i, font *f, const environment *env,
364 int w, const char *)
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());
374 void tty_printer::add_char(unsigned int c, int w,
375 int h, int v,
376 color *fore, color *back,
377 unsigned char mode)
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;
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;
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;
411 cached_v = v;
412 cached_vpos = vpos;
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;
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.
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;
436 void tty_printer::special(char *arg, const environment *env, char type)
438 if (type == 'u') {
439 add_char(*arg - '0', 0, env->hpos, env->vpos, env->col, env->fill,
440 CU_MODE);
441 return;
443 if (type != 'p')
444 return;
445 char *p;
446 for (p = arg; *p == ' ' || *p == '\n'; p++)
448 char *tag = p;
449 for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
451 if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) {
452 error("X command without `tty:' tag ignored");
453 return;
455 p++;
456 for (; *p == ' ' || *p == '\n'; p++)
458 char *command = p;
459 for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
461 if (*command == '\0') {
462 error("empty X command ignored");
463 return;
465 if (strncmp(command, "sgr", p - command) == 0) {
466 for (; *p == ' ' || *p == '\n'; p++)
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();
477 void tty_printer::change_color(const environment * const env)
479 add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
482 void tty_printer::change_fill_color(const environment * const env)
484 add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
487 void tty_printer::draw(int code, int *p, int np, const environment *env)
489 if (code != 'l' || !draw_flag)
490 return;
491 if (np != 2) {
492 error("2 arguments required for line");
493 return;
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;
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;
517 add_char(vline_char, font::hor, env->hpos, v, env->col, env->fill,
518 VDRAW_MODE|END_LINE);
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;
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;
543 add_char(hline_char, font::hor, h, env->vpos, env->col, env->fill,
544 HDRAW_MODE|END_LINE);
549 void tty_printer::put_char(unsigned int wc)
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);
572 else
573 putchar(wc);
576 void tty_printer::put_color(schar color_index, int back)
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);
591 // set other color again
592 back = !back;
593 color_index = back ? curr_back_idx : curr_fore_idx;
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');
606 // The possible Unicode combinations for crossing characters.
608 // ` ' = 0, ` -' = 4, `- ' = 8, `--' = 12,
610 // ` ' = 0, ` ' = 1, `|' = 2, `|' = 3
611 // | |
613 static int crossings[4*4] = {
614 0x0000, 0x2577, 0x2575, 0x2502,
615 0x2576, 0x250C, 0x2514, 0x251C,
616 0x2574, 0x2510, 0x2518, 0x2524,
617 0x2500, 0x252C, 0x2534, 0x253C
620 void tty_printer::end_page(int page_length)
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;
639 } while (last_line > lines_per_page);
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;
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;
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;
675 if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
676 nextp->code = p->code;
677 continue;
679 if (!overstrike_flag)
680 continue;
682 if (hpos > p->hpos) {
683 do {
684 putchar('\b');
685 hpos--;
686 } while (hpos > p->hpos);
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;
705 putchar('\t');
706 hpos = next_tab_pos;
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;
721 putchar(' ');
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;
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;
736 continue;
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;
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;
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;
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;
765 put_char(p->code);
766 hpos += p->w / font::hor;
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');
775 if (form_feed_flag) {
776 if (last_line < lines_per_page)
777 putchar('\f');
779 else {
780 for (; last_line < lines_per_page; last_line++)
781 putchar('\n');
785 font *tty_printer::make_font(const char *nm)
787 return tty_font::load_tty_font(nm);
790 printer *make_printer()
792 return new tty_printer(device);
795 static void update_options()
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;
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;
813 int main(int argc, char **argv)
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 }
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);
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]);
900 return 0;
903 static void usage(FILE *stream)
905 fprintf(stream, "usage: %s [-bBcdfhioruUv] [-F dir] [files ...]\n",
906 program_name);