Sync-to-go: update copyright for 2015
[s-roff.git] / src / dev-tty / tty.cpp
blob4367f59f711fde9c218ad4e1b6b438edc2c14818
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 2006
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
23 #include "config.h"
24 #include "tty-config.h"
26 #include "device.h"
27 #include "driver.h"
28 #include "ptable.h"
30 typedef signed char schar;
32 declare_ptable(schar) /* TODO */
33 implement_ptable(schar) /* TODO */
35 #define putstring(s) fputs(s, stdout)
37 // A character of the output device fits in a 32-bit word.
38 typedef unsigned int output_character;
40 static int horizontal_tab_flag = 0;
41 static int form_feed_flag = 0;
42 static int bold_flag_option = 1;
43 static int bold_flag;
44 static int underline_flag_option = 1;
45 static int underline_flag;
46 static int overstrike_flag = 1;
47 static int draw_flag = 1;
48 static int italic_flag_option = 0;
49 static int italic_flag;
50 static int reverse_flag_option = 0;
51 static int reverse_flag;
52 static int old_drawing_scheme = 0;
54 static void update_options();
55 static void usage(FILE *stream);
57 static int hline_char = '-';
58 static int vline_char = '|';
60 enum {
61 UNDERLINE_MODE = 0x01,
62 BOLD_MODE = 0x02,
63 VDRAW_MODE = 0x04,
64 HDRAW_MODE = 0x08,
65 CU_MODE = 0x10,
66 COLOR_CHANGE = 0x20,
67 START_LINE = 0x40,
68 END_LINE = 0x80
71 // Mode to use for bold-underlining.
72 static unsigned char bold_underline_mode_option = BOLD_MODE|UNDERLINE_MODE;
73 static unsigned char bold_underline_mode;
75 class tty_font
76 : public font
78 tty_font(const char *);
79 unsigned char mode;
81 public:
82 ~tty_font();
83 unsigned char get_mode() { return mode; }
84 #if 0
85 void handle_x_command(int argc, const char **argv);
86 #endif
87 static tty_font *load_tty_font(const char *);
90 tty_font *tty_font::load_tty_font(const char *s)
92 tty_font *f = new tty_font(s);
93 if (!f->load()) {
94 delete f;
95 return 0;
97 const char *num = f->get_internal_name();
98 long n;
99 if (num != 0 && (n = strtol(num, 0, 0)) != 0)
100 f->mode = (unsigned char)(n & (BOLD_MODE|UNDERLINE_MODE));
101 if (!underline_flag)
102 f->mode &= ~UNDERLINE_MODE;
103 if (!bold_flag)
104 f->mode &= ~BOLD_MODE;
105 if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
106 f->mode = (unsigned char)((f->mode & ~(BOLD_MODE|UNDERLINE_MODE))
107 | bold_underline_mode);
108 return f;
111 tty_font::tty_font(const char *nm)
112 : font(nm), mode(0)
116 tty_font::~tty_font()
120 #if 0
121 void tty_font::handle_x_command(int argc, const char **argv)
123 if (argc >= 1 && strcmp(argv[0], "bold") == 0)
124 mode |= BOLD_MODE;
125 else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
126 mode |= UNDERLINE_MODE;
128 #endif
130 class tty_glyph
132 static tty_glyph *free_list;
134 public:
135 tty_glyph *next;
136 int w;
137 int hpos;
138 unsigned int code;
139 unsigned char mode;
140 schar back_color_idx;
141 schar fore_color_idx;
142 void *operator new(size_t);
143 void operator delete(void *);
144 inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
145 inline int order() {
146 return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); }
149 tty_glyph *tty_glyph::free_list = 0;
151 void *tty_glyph::operator new(size_t)
153 if (!free_list) {
154 const int BLOCK = 1024;
155 free_list = (tty_glyph *)new char[sizeof(tty_glyph) * BLOCK];
156 for (int i = 0; i < BLOCK - 1; i++)
157 free_list[i].next = free_list + i + 1;
158 free_list[BLOCK - 1].next = 0;
160 tty_glyph *p = free_list;
161 free_list = free_list->next;
162 p->next = 0;
163 return p;
166 void tty_glyph::operator delete(void *p)
168 if (p) {
169 ((tty_glyph *)p)->next = free_list;
170 free_list = (tty_glyph *)p;
174 class tty_printer
175 : public printer
177 int is_utf8;
178 tty_glyph **lines;
179 int nlines;
180 int cached_v;
181 int cached_vpos;
182 schar curr_fore_idx;
183 schar curr_back_idx;
184 int is_underline;
185 int is_bold;
186 int cu_flag;
187 PTABLE(schar) tty_colors;
188 void make_underline(int);
189 void make_bold(output_character, int);
190 schar color_to_idx(color *);
191 void add_char(output_character, int, int, int, color *, color *,
192 unsigned char);
193 char *make_rgb_string(unsigned int, unsigned int, unsigned int);
194 int tty_color(unsigned int, unsigned int, unsigned int, schar *,
195 schar = DEFAULT_COLOR_IDX);
196 void line(int, int, int, int, color *, color *);
197 void draw_line(int *, int, const environment *);
198 void draw_polygon(int *, int, const environment *);
200 public:
201 tty_printer(const char *);
202 ~tty_printer();
203 void set_char(glyph *, font *, const environment *, int, const char *);
204 void draw(int, int *, int, const environment *);
205 void special(char *, const environment *, char);
206 void change_color(const environment * const);
207 void change_fill_color(const environment * const);
208 void put_char(output_character);
209 void put_color(schar, int);
210 void begin_page(int) { }
211 void end_page(int);
212 font *make_font(const char *);
215 char *tty_printer::make_rgb_string(unsigned int r,
216 unsigned int g,
217 unsigned int b)
219 char *s = new char[8];
220 s[0] = char(r >> 8);
221 s[1] = char(r & 0xff);
222 s[2] = char(g >> 8);
223 s[3] = char(g & 0xff);
224 s[4] = char(b >> 8);
225 s[5] = char(b & 0xff);
226 s[6] = char(0x80);
227 s[7] = 0;
228 // avoid null-bytes in string
229 for (int i = 0; i < 6; i++)
230 if (!s[i]) {
231 s[i] = 1;
232 s[6] |= 1 << i;
234 return s;
237 int tty_printer::tty_color(unsigned int r,
238 unsigned int g,
239 unsigned int b, schar *idx, schar value)
241 int unknown_color = 0;
242 char *s = make_rgb_string(r, g, b);
243 schar *i = tty_colors.lookup(s);
244 if (!i) {
245 unknown_color = 1;
246 i = new schar[1];
247 *i = value;
248 tty_colors.define(s, i);
250 *idx = *i;
251 a_delete s;
252 return unknown_color;
255 tty_printer::tty_printer(const char *dev) : cached_v(0)
257 is_utf8 = !strcmp(dev, "utf8");
258 if (is_utf8) {
259 hline_char = 0x2500;
260 vline_char = 0x2502;
262 schar dummy;
263 // black, white
264 (void)tty_color(0, 0, 0, &dummy, 0);
265 (void)tty_color(color::MAX_COLOR_VAL,
266 color::MAX_COLOR_VAL,
267 color::MAX_COLOR_VAL, &dummy, 7);
268 // red, green, blue
269 (void)tty_color(color::MAX_COLOR_VAL, 0, 0, &dummy, 1);
270 (void)tty_color(0, color::MAX_COLOR_VAL, 0, &dummy, 2);
271 (void)tty_color(0, 0, color::MAX_COLOR_VAL, &dummy, 4);
272 // yellow, magenta, cyan
273 (void)tty_color(color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, 0, &dummy, 3);
274 (void)tty_color(color::MAX_COLOR_VAL, 0, color::MAX_COLOR_VAL, &dummy, 5);
275 (void)tty_color(0, color::MAX_COLOR_VAL, color::MAX_COLOR_VAL, &dummy, 6);
276 nlines = 66;
277 lines = new tty_glyph *[nlines];
278 for (int i = 0; i < nlines; i++)
279 lines[i] = 0;
280 cu_flag = 0;
283 tty_printer::~tty_printer()
285 a_delete lines;
288 void tty_printer::make_underline(int w)
290 if (old_drawing_scheme) {
291 if (!w)
292 warning("can't underline zero-width character");
293 else {
294 int n = w / font::hor;
295 for (int i = 0; i < n; i++)
296 putchar('_');
297 for (int j = 0; j < n; j++)
298 putchar('\b');
301 else {
302 if (!is_underline) {
303 if (italic_flag)
304 putstring(SGR_ITALIC);
305 else if (reverse_flag)
306 putstring(SGR_REVERSE);
307 else
308 putstring(SGR_UNDERLINE);
310 is_underline = 1;
314 void tty_printer::make_bold(output_character c, int w)
316 if (old_drawing_scheme) {
317 if (!w)
318 warning("can't print zero-width character in bold");
319 else {
320 int n = w / font::hor;
321 put_char(c);
322 for (int i = 0; i < n; i++)
323 putchar('\b');
326 else {
327 if (!is_bold)
328 putstring(SGR_BOLD);
329 is_bold = 1;
333 schar tty_printer::color_to_idx(color *col)
335 if (col->is_default())
336 return DEFAULT_COLOR_IDX;
337 unsigned int r, g, b;
338 col->get_rgb(&r, &g, &b);
339 schar idx;
340 if (tty_color(r, g, b, &idx)) {
341 char *s = col->print_color();
342 error("Unknown color (%1) mapped to default", s);
343 a_delete s;
345 return idx;
348 void tty_printer::set_char(glyph *g, font *f, const environment *env,
349 int w, const char *)
351 if (w % font::hor != 0)
352 fatal("width of character not a multiple of horizontal resolution");
353 add_char(f->get_code(g), w,
354 env->hpos, env->vpos,
355 env->col, env->fill,
356 ((tty_font *)f)->get_mode());
359 void tty_printer::add_char(output_character c, int w,
360 int h, int v,
361 color *fore, color *back,
362 unsigned char mode)
364 #if 0
365 // This is too expensive.
366 if (h % font::hor != 0)
367 fatal("horizontal position not a multiple of horizontal resolution");
368 #endif
369 int hpos = h / font::hor;
370 if (hpos < HPOS_MIN || hpos > HPOS_MAX) {
371 error("character with ridiculous horizontal position discarded");
372 return;
374 int vpos;
375 if (v == cached_v && cached_v != 0)
376 vpos = cached_vpos;
377 else {
378 if (v % font::vert != 0)
379 fatal("vertical position not a multiple of vertical resolution");
380 vpos = v / font::vert;
381 if (vpos > nlines) {
382 tty_glyph **old_lines = lines;
383 lines = new tty_glyph *[vpos + 1];
384 memcpy(lines, old_lines, nlines * sizeof(tty_glyph *));
385 for (int i = nlines; i <= vpos; i++)
386 lines[i] = 0;
387 a_delete old_lines;
388 nlines = vpos + 1;
390 // Note that the first output line corresponds to groff
391 // position font::vert.
392 if (vpos <= 0) {
393 error("character above first line discarded");
394 return;
396 cached_v = v;
397 cached_vpos = vpos;
399 tty_glyph *g = new tty_glyph;
400 g->w = w;
401 g->hpos = hpos;
402 g->code = c;
403 g->fore_color_idx = color_to_idx(fore);
404 g->back_color_idx = color_to_idx(back);
405 g->mode = mode;
407 // The list will be reversed later. After reversal, it must be in
408 // increasing order of hpos, with COLOR_CHANGE and CU specials before
409 // HDRAW characters before VDRAW characters before normal characters
410 // at each hpos, and otherwise in order of occurrence.
412 tty_glyph **pp;
413 for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
414 if ((*pp)->hpos < hpos
415 || ((*pp)->hpos == hpos && (*pp)->order() >= g->order()))
416 break;
417 g->next = *pp;
418 *pp = g;
421 void tty_printer::special(char *arg, const environment *env, char type)
423 if (type == 'u') {
424 add_char(*arg - '0', 0, env->hpos, env->vpos, env->col, env->fill,
425 CU_MODE);
426 return;
428 if (type != 'p')
429 return;
430 char *p;
431 for (p = arg; *p == ' ' || *p == '\n'; p++)
433 char *tag = p;
434 for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
436 if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) {
437 error("X command without `tty:' tag ignored");
438 return;
440 p++;
441 for (; *p == ' ' || *p == '\n'; p++)
443 char *command = p;
444 for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
446 if (*command == '\0') {
447 error("empty X command ignored");
448 return;
450 if (strncmp(command, "sgr", p - command) == 0) {
451 for (; *p == ' ' || *p == '\n'; p++)
453 int n;
454 if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0)
455 old_drawing_scheme = 1;
456 else
457 old_drawing_scheme = 0;
458 update_options();
462 void tty_printer::change_color(const environment * const env)
464 add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
467 void tty_printer::change_fill_color(const environment * const env)
469 add_char(0, 0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
472 void tty_printer::draw(int code, int *p, int np, const environment *env)
474 if (!draw_flag)
475 return;
476 if (code == 'l')
477 draw_line(p, np, env);
478 if (code == 'p')
479 draw_polygon(p, np, env);
482 void tty_printer::draw_polygon(int *p, int np, const environment *env)
484 if (np & 1) {
485 error("even number of arguments required for polygon");
486 return;
488 if (np == 0) {
489 error("no arguments for polygon");
490 return;
492 // We only draw polygons which consist entirely of horizontal and
493 // vertical lines.
494 int hpos = 0;
495 int vpos = 0;
496 for (int i = 0; i < np; i += 2) {
497 if (!(p[i] == 0 || p[i + 1] == 0))
498 return;
499 hpos += p[i];
500 vpos += p[i + 1];
502 if (!(hpos == 0 || vpos == 0))
503 return;
504 int start_hpos = env->hpos;
505 int start_vpos = env->vpos;
506 hpos = start_hpos;
507 vpos = start_vpos;
508 for (int i = 0; i < np; i += 2) {
509 line(hpos, vpos, p[i], p[i + 1], env->col, env->fill);
510 hpos += p[i];
511 vpos += p[i + 1];
513 line(hpos, vpos, start_hpos - hpos, start_vpos - vpos,
514 env->col, env->fill);
517 void tty_printer::draw_line(int *p, int np, const environment *env)
519 if (np != 2) {
520 error("2 arguments required for line");
521 return;
523 line(env->hpos, env->vpos, p[0], p[1], env->col, env->fill);
526 void tty_printer::line(int hpos, int vpos, int dx, int dy,
527 color *col, color *fill)
529 if (dx == 0) {
530 // vertical line
531 int v = vpos;
532 int len = dy;
533 if (len < 0) {
534 v += len;
535 len = -len;
537 if (len == 0)
538 add_char(vline_char, font::hor, hpos, v, col, fill,
539 VDRAW_MODE|START_LINE|END_LINE);
540 else {
541 add_char(vline_char, font::hor, hpos, v, col, fill,
542 VDRAW_MODE|START_LINE);
543 len -= font::vert;
544 v += font::vert;
545 while (len > 0) {
546 add_char(vline_char, font::hor, hpos, v, col, fill,
547 VDRAW_MODE|START_LINE|END_LINE);
548 len -= font::vert;
549 v += font::vert;
551 add_char(vline_char, font::hor, hpos, v, col, fill,
552 VDRAW_MODE|END_LINE);
555 if (dy == 0) {
556 // horizontal line
557 int h = hpos;
558 int len = dx;
559 if (len < 0) {
560 h += len;
561 len = -len;
563 if (len == 0)
564 add_char(hline_char, font::hor, h, vpos, col, fill,
565 HDRAW_MODE|START_LINE|END_LINE);
566 else {
567 add_char(hline_char, font::hor, h, vpos, col, fill,
568 HDRAW_MODE|START_LINE);
569 len -= font::hor;
570 h += font::hor;
571 while (len > 0) {
572 add_char(hline_char, font::hor, h, vpos, col, fill,
573 HDRAW_MODE|START_LINE|END_LINE);
574 len -= font::hor;
575 h += font::hor;
577 add_char(hline_char, font::hor, h, vpos, col, fill,
578 HDRAW_MODE|END_LINE);
583 void tty_printer::put_char(output_character wc)
585 if (is_utf8 && wc >= 0x80) {
586 char buf[6 + 1];
587 int count;
588 char *p = buf;
589 if (wc < 0x800)
590 count = 1, *p = (unsigned char)((wc >> 6) | 0xc0);
591 else if (wc < 0x10000)
592 count = 2, *p = (unsigned char)((wc >> 12) | 0xe0);
593 else if (wc < 0x200000)
594 count = 3, *p = (unsigned char)((wc >> 18) | 0xf0);
595 else if (wc < 0x4000000)
596 count = 4, *p = (unsigned char)((wc >> 24) | 0xf8);
597 else if (wc <= 0x7fffffff)
598 count = 5, *p = (unsigned char)((wc >> 30) | 0xfC);
599 else
600 return;
601 do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80);
602 while (count > 0);
603 *++p = '\0';
604 putstring(buf);
606 else
607 putchar(wc);
610 void tty_printer::put_color(schar color_index, int back)
612 if (color_index == DEFAULT_COLOR_IDX) {
613 putstring(SGR_DEFAULT);
614 // set bold and underline again
615 if (is_bold)
616 putstring(SGR_BOLD);
617 if (is_underline) {
618 if (italic_flag)
619 putstring(SGR_ITALIC);
620 else if (reverse_flag)
621 putstring(SGR_REVERSE);
622 else
623 putstring(SGR_UNDERLINE);
625 // set other color again
626 back = !back;
627 color_index = back ? curr_back_idx : curr_fore_idx;
629 if (color_index != DEFAULT_COLOR_IDX) {
630 putstring(CSI);
631 if (back)
632 putchar('4');
633 else
634 putchar('3');
635 putchar(color_index + '0');
636 putchar('m');
640 // The possible Unicode combinations for crossing characters.
642 // ` ' = 0, ` -' = 4, `- ' = 8, `--' = 12,
644 // ` ' = 0, ` ' = 1, `|' = 2, `|' = 3
645 // | |
647 static output_character crossings[4*4] = {
648 0x0000, 0x2577, 0x2575, 0x2502,
649 0x2576, 0x250C, 0x2514, 0x251C,
650 0x2574, 0x2510, 0x2518, 0x2524,
651 0x2500, 0x252C, 0x2534, 0x253C
654 void tty_printer::end_page(int page_length)
656 if (page_length % font::vert != 0)
657 error("vertical position at end of page not multiple of vertical resolution");
658 int lines_per_page = page_length / font::vert;
659 int last_line;
660 for (last_line = nlines; last_line > 0; last_line--)
661 if (lines[last_line - 1])
662 break;
663 #if 0
664 if (last_line > lines_per_page) {
665 error("characters past last line discarded");
666 do {
667 --last_line;
668 while (lines[last_line]) {
669 tty_glyph *tem = lines[last_line];
670 lines[last_line] = tem->next;
671 delete tem;
673 } while (last_line > lines_per_page);
675 #endif
676 for (int i = 0; i < last_line; i++) {
677 tty_glyph *p = lines[i];
678 lines[i] = 0;
679 tty_glyph *g = 0;
680 while (p) {
681 tty_glyph *tem = p->next;
682 p->next = g;
683 g = p;
684 p = tem;
686 int hpos = 0;
687 tty_glyph *nextp;
688 curr_fore_idx = DEFAULT_COLOR_IDX;
689 curr_back_idx = DEFAULT_COLOR_IDX;
690 is_underline = 0;
691 is_bold = 0;
692 for (p = g; p; delete p, p = nextp) {
693 nextp = p->next;
694 if (p->mode & CU_MODE) {
695 cu_flag = (p->code != 0);
696 continue;
698 if (nextp && p->hpos == nextp->hpos) {
699 if (p->draw_mode() == HDRAW_MODE &&
700 nextp->draw_mode() == VDRAW_MODE) {
701 if (is_utf8)
702 nextp->code =
703 crossings[((p->mode & (START_LINE|END_LINE)) >> 4)
704 + ((nextp->mode & (START_LINE|END_LINE)) >> 6)];
705 else
706 nextp->code = '+';
707 continue;
709 if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
710 nextp->code = p->code;
711 continue;
713 if (!overstrike_flag)
714 continue;
716 if (hpos > p->hpos) {
717 do {
718 putchar('\b');
719 hpos--;
720 } while (hpos > p->hpos);
722 else {
723 if (horizontal_tab_flag) {
724 for (;;) {
725 int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
726 if (next_tab_pos > p->hpos)
727 break;
728 if (cu_flag)
729 make_underline(p->w);
730 else if (!old_drawing_scheme && is_underline) {
731 if (italic_flag)
732 putstring(SGR_NO_ITALIC);
733 else if (reverse_flag)
734 putstring(SGR_NO_REVERSE);
735 else
736 putstring(SGR_NO_UNDERLINE);
737 is_underline = 0;
739 putchar('\t');
740 hpos = next_tab_pos;
743 for (; hpos < p->hpos; hpos++) {
744 if (cu_flag)
745 make_underline(p->w);
746 else if (!old_drawing_scheme && is_underline) {
747 if (italic_flag)
748 putstring(SGR_NO_ITALIC);
749 else if (reverse_flag)
750 putstring(SGR_NO_REVERSE);
751 else
752 putstring(SGR_NO_UNDERLINE);
753 is_underline = 0;
755 putchar(' ');
758 assert(hpos == p->hpos);
759 if (p->mode & COLOR_CHANGE) {
760 if (!old_drawing_scheme) {
761 if (p->fore_color_idx != curr_fore_idx) {
762 put_color(p->fore_color_idx, 0);
763 curr_fore_idx = p->fore_color_idx;
765 if (p->back_color_idx != curr_back_idx) {
766 put_color(p->back_color_idx, 1);
767 curr_back_idx = p->back_color_idx;
770 continue;
772 if (p->mode & UNDERLINE_MODE)
773 make_underline(p->w);
774 else if (!old_drawing_scheme && is_underline) {
775 if (italic_flag)
776 putstring(SGR_NO_ITALIC);
777 else if (reverse_flag)
778 putstring(SGR_NO_REVERSE);
779 else
780 putstring(SGR_NO_UNDERLINE);
781 is_underline = 0;
783 if (p->mode & BOLD_MODE)
784 make_bold(p->code, p->w);
785 else if (!old_drawing_scheme && is_bold) {
786 putstring(SGR_NO_BOLD);
787 is_bold = 0;
789 if (!old_drawing_scheme) {
790 if (p->fore_color_idx != curr_fore_idx) {
791 put_color(p->fore_color_idx, 0);
792 curr_fore_idx = p->fore_color_idx;
794 if (p->back_color_idx != curr_back_idx) {
795 put_color(p->back_color_idx, 1);
796 curr_back_idx = p->back_color_idx;
799 put_char(p->code);
800 hpos += p->w / font::hor;
802 if (!old_drawing_scheme
803 && (is_bold || is_underline
804 || curr_fore_idx != DEFAULT_COLOR_IDX
805 || curr_back_idx != DEFAULT_COLOR_IDX))
806 putstring(SGR_DEFAULT);
807 putchar('\n');
809 if (form_feed_flag) {
810 if (last_line < lines_per_page)
811 putchar('\f');
813 else {
814 for (; last_line < lines_per_page; last_line++)
815 putchar('\n');
819 font *tty_printer::make_font(const char *nm)
821 return tty_font::load_tty_font(nm);
824 printer *make_printer()
826 return new tty_printer(device);
829 static void update_options()
831 if (old_drawing_scheme) {
832 italic_flag = 0;
833 reverse_flag = 0;
834 bold_underline_mode = bold_underline_mode_option;
835 bold_flag = bold_flag_option;
836 underline_flag = underline_flag_option;
838 else {
839 italic_flag = italic_flag_option;
840 reverse_flag = reverse_flag_option;
841 bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
842 bold_flag = 1;
843 underline_flag = 1;
847 int main(int argc, char **argv)
849 program_name = argv[0];
850 static char stderr_buf[BUFSIZ];
851 if (getenv(U_ROFF_NO_SGR))
852 old_drawing_scheme = 1;
853 setbuf(stderr, stderr_buf);
854 int c;
855 static const struct option long_options[] = {
856 { "help", no_argument, 0, CHAR_MAX + 1 },
857 { "version", no_argument, 0, 'v' },
858 { NULL, 0, 0, 0 }
860 while ((c = getopt_long(argc, argv, "bBcdfF:hiI:oruUv", long_options, NULL))
861 != EOF)
862 switch(c) {
863 case 'v':
864 puts(L_D_TTY " (" T_ROFF ") v" VERSION);
865 exit(0);
866 break;
867 case 'i':
868 // Use italic font instead of underlining.
869 italic_flag_option = 1;
870 break;
871 case 'I':
872 // ignore include search path
873 break;
874 case 'b':
875 // Do not embolden by overstriking.
876 bold_flag_option = 0;
877 break;
878 case 'c':
879 // Use old scheme for emboldening and underline.
880 old_drawing_scheme = 1;
881 break;
882 case 'u':
883 // Do not underline.
884 underline_flag_option = 0;
885 break;
886 case 'o':
887 // Do not overstrike (other than emboldening and underlining).
888 overstrike_flag = 0;
889 break;
890 case 'r':
891 // Use reverse mode instead of underlining.
892 reverse_flag_option = 1;
893 break;
894 case 'B':
895 // Do bold-underlining as bold.
896 bold_underline_mode_option = BOLD_MODE;
897 break;
898 case 'U':
899 // Do bold-underlining as underlining.
900 bold_underline_mode_option = UNDERLINE_MODE;
901 break;
902 case 'h':
903 // Use horizontal tabs.
904 horizontal_tab_flag = 1;
905 break;
906 case 'f':
907 form_feed_flag = 1;
908 break;
909 case 'F':
910 font::command_line_font_dir(optarg);
911 break;
912 case 'd':
913 // Ignore \D commands.
914 draw_flag = 0;
915 break;
916 case CHAR_MAX + 1: // --help
917 usage(stdout);
918 exit(0);
919 break;
920 case '?':
921 usage(stderr);
922 exit(1);
923 break;
924 default:
925 assert(0);
927 update_options();
928 if (optind >= argc)
929 do_file("-");
930 else {
931 for (int i = optind; i < argc; i++)
932 do_file(argv[i]);
934 return 0;
937 static void usage(FILE *stream)
939 fprintf(stream, "Synopsis: %s [-bBcdfhioruUv] [-F dir] [files ...]\n",
940 program_name);
943 // s-it2-mode