2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #define SHRT_MIN (-32768)
28 #define SHRT_MAX 32767
33 static int horizontal_tab_flag = 0;
34 static int form_feed_flag = 0;
35 static int bold_flag = 1;
36 static int underline_flag = 1;
37 static int overstrike_flag = 1;
38 static int draw_flag = 1;
47 // Mode to use for bold-underlining.
48 static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
50 class tty_font : public font {
51 tty_font(const char *);
55 unsigned char get_mode() { return mode; }
57 void handle_x_command(int argc, const char **argv);
59 static tty_font *load_tty_font(const char *);
62 tty_font *tty_font::load_tty_font(const char *s)
64 tty_font *f = new tty_font(s);
69 const char *num = f->get_internal_name();
71 if (num != 0 && (n = strtol(num, 0, 0)) != 0)
72 f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE));
74 f->mode &= ~UNDERLINE_MODE;
76 f->mode &= ~BOLD_MODE;
77 if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
78 f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode;
82 tty_font::tty_font(const char *nm)
92 void tty_font::handle_x_command(int argc, const char **argv)
94 if (argc >= 1 && strcmp(argv[0], "bold") == 0)
96 else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
97 mode |= UNDERLINE_MODE;
102 static glyph *free_list;
108 void *operator new(size_t);
109 void operator delete(void *);
110 inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
113 glyph *glyph::free_list = 0;
115 void *glyph::operator new(size_t)
118 const int BLOCK = 1024;
119 free_list = (glyph *)new char[sizeof(glyph)*BLOCK];
120 for (int i = 0; i < BLOCK - 1; i++)
121 free_list[i].next = free_list + i + 1;
122 free_list[BLOCK - 1].next = 0;
124 glyph *p = free_list;
125 free_list = free_list->next;
130 void glyph::operator delete(void *p)
133 ((glyph *)p)->next = free_list;
134 free_list = (glyph *)p;
138 class tty_printer : public printer {
143 void add_char(unsigned char, int, int, unsigned char);
147 void set_char(int, font *, const environment *, int);
148 void draw(int code, int *p, int np, const environment *env);
149 void begin_page(int) { }
150 void end_page(int page_length);
151 font *make_font(const char *);
154 tty_printer::tty_printer() : cached_v(0)
157 lines = new glyph *[nlines];
158 for (int i = 0; i < nlines; i++)
162 tty_printer::~tty_printer()
167 void tty_printer::set_char(int i, font *f, const environment *env, int w)
170 fatal("width of character not equal to horizontal resolution");
171 add_char(f->get_code(i), env->hpos, env->vpos, ((tty_font *)f)->get_mode());
174 void tty_printer::add_char(unsigned char c, int h, int v, unsigned char mode)
177 // This is too expensive.
178 if (h % font::hor != 0)
179 fatal("horizontal position not a multiple of horizontal resolution");
181 int hpos = h / font::hor;
182 if (hpos < SHRT_MIN || hpos > SHRT_MAX) {
183 error("character with ridiculous horizontal position discarded");
187 if (v == cached_v && cached_v != 0)
190 if (v % font::vert != 0)
191 fatal("vertical position not a multiple of vertical resolution");
192 vpos = v / font::vert;
194 glyph **old_lines = lines;
195 lines = new glyph *[vpos + 1];
196 memcpy(lines, old_lines, nlines*sizeof(glyph *));
197 for (int i = nlines; i <= vpos; i++)
202 // Note that the first output line corresponds to groff
203 // position font::vert.
205 error("character above first line discarded");
211 glyph *g = new glyph;
216 // The list will be reversed later. After reversal, it must be in
217 // increasing order of hpos, with HDRAW characters before VDRAW
218 // characters before normal characters at each hpos, and otherwise
219 // in order of occurrence.
222 for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
223 if ((*pp)->hpos < hpos
224 || ((*pp)->hpos == hpos && (*pp)->draw_mode() >= g->draw_mode()))
231 void tty_printer::draw(int code, int *p, int np, const environment *env)
233 if (code != 'l' || !draw_flag)
236 error("2 arguments required for line");
248 add_char('|', env->hpos, v, VDRAW_MODE);
262 add_char('-', h, env->vpos, HDRAW_MODE);
269 void tty_printer::end_page(int page_length)
271 if (page_length % font::vert != 0)
272 error("vertical position at end of page not multiple of vertical resolution");
273 int lines_per_page = page_length / font::vert;
275 for (last_line = nlines; last_line > 0; last_line--)
276 if (lines[last_line - 1])
279 if (last_line > lines_per_page) {
280 error("characters past last line discarded");
283 while (lines[last_line]) {
284 glyph *tem = lines[last_line];
285 lines[last_line] = tem->next;
288 } while (last_line > lines_per_page);
291 for (int i = 0; i < last_line; i++) {
296 glyph *tem = p->next;
304 for (p = g; p; delete p, p = nextp) {
306 if (nextp && p->hpos == nextp->hpos) {
307 if (p->draw_mode() == HDRAW_MODE && nextp->draw_mode() == VDRAW_MODE) {
311 if (p->draw_mode() != 0 && p->draw_mode() == nextp->draw_mode()) {
312 nextp->code = p->code;
315 if (!overstrike_flag)
318 if (hpos > p->hpos) {
322 } while (hpos > p->hpos);
325 if (horizontal_tab_flag) {
327 int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
328 if (next_tab_pos > p->hpos)
334 for (; hpos < p->hpos; hpos++)
337 assert(hpos == p->hpos);
338 if (p->mode & UNDERLINE_MODE) {
342 if (p->mode & BOLD_MODE) {
351 if (form_feed_flag) {
352 if (last_line < lines_per_page)
356 for (; last_line < lines_per_page; last_line++)
361 font *tty_printer::make_font(const char *nm)
363 return tty_font::load_tty_font(nm);
366 printer *make_printer()
368 return new tty_printer;
373 int main(int argc, char **argv)
375 program_name = argv[0];
376 static char stderr_buf[BUFSIZ];
377 setbuf(stderr, stderr_buf);
379 while ((c = getopt(argc, argv, "F:vhfbuoBUd")) != EOF)
383 extern const char *version_string;
384 fprintf(stderr, "grotty version %s\n", version_string);
389 // Do not embolden by overstriking.
397 // Do not overstrike (other than emboldening and underlining).
401 // Do bold-underlining as bold.
402 bold_underline_mode = BOLD_MODE;
405 // Do bold-underlining as underlining.
406 bold_underline_mode = UNDERLINE_MODE;
409 // Use horizontal tabs.
410 horizontal_tab_flag = 1;
416 font::command_line_font_dir(optarg);
419 // Ignore \D commands.
431 for (int i = optind; i < argc; i++)
440 fprintf(stderr, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n",