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, 675 Mass Ave, Cambridge, MA 02139, USA. */
24 #define USHRT_MAX 65535
27 #define DEFAULT_LINES_PER_PAGE 66
31 static int horizontal_tab_flag
= 0;
32 static int form_feed_flag
= 0;
33 static int bold_flag
= 1;
34 static int underline_flag
= 1;
35 static int overstrike_flag
= 1;
36 static int draw_flag
= 1;
45 // Mode to use for bold-underlining.
46 static unsigned char bold_underline_mode
= BOLD_MODE
|UNDERLINE_MODE
;
48 class tty_font
: public font
{
49 tty_font(const char *);
53 unsigned char get_mode() { return mode
; }
55 void handle_x_command(int argc
, const char **argv
);
57 static tty_font
*load_tty_font(const char *);
60 tty_font
*tty_font::load_tty_font(const char *s
)
62 tty_font
*f
= new tty_font(s
);
67 const char *num
= f
->get_internal_name();
69 if (num
!= 0 && (n
= strtol(num
, 0, 0)) != 0)
70 f
->mode
= int(n
& (BOLD_MODE
|UNDERLINE_MODE
));
72 f
->mode
&= ~UNDERLINE_MODE
;
74 f
->mode
&= ~BOLD_MODE
;
75 if ((f
->mode
& (BOLD_MODE
|UNDERLINE_MODE
)) == (BOLD_MODE
|UNDERLINE_MODE
))
76 f
->mode
= (f
->mode
& ~(BOLD_MODE
|UNDERLINE_MODE
)) | bold_underline_mode
;
80 tty_font::tty_font(const char *nm
)
90 void tty_font::handle_x_command(int argc
, const char **argv
)
92 if (argc
>= 1 && strcmp(argv
[0], "bold") == 0)
94 else if (argc
>= 1 && strcmp(argv
[0], "underline") == 0)
95 mode
|= UNDERLINE_MODE
;
100 static glyph
*free_list
;
106 void *operator new(size_t);
107 void operator delete(void *);
108 inline int draw_mode() { return mode
& (VDRAW_MODE
|HDRAW_MODE
); }
111 glyph
*glyph::free_list
= 0;
113 void *glyph::operator new(size_t)
116 const int BLOCK
= 1024;
117 free_list
= (glyph
*)new char[sizeof(glyph
)*BLOCK
];
118 for (int i
= 0; i
< BLOCK
- 1; i
++)
119 free_list
[i
].next
= free_list
+ i
+ 1;
120 free_list
[BLOCK
- 1].next
= 0;
122 glyph
*p
= free_list
;
123 free_list
= free_list
->next
;
128 void glyph::operator delete(void *p
)
131 ((glyph
*)p
)->next
= free_list
;
132 free_list
= (glyph
*)p
;
136 class tty_printer
: public printer
{
139 int columns_per_page
;
142 void add_char(unsigned char, int, int, unsigned char);
146 void set_char(int, font
*, const environment
*, int);
147 void draw(int code
, int *p
, int np
, const environment
*env
);
148 void begin_page(int) { }
150 font
*make_font(const char *);
153 tty_printer::tty_printer() : cached_v(0)
155 if (font::paperlength
== 0)
156 lines_per_page
= DEFAULT_LINES_PER_PAGE
;
157 else if (font::paperlength
% font::vert
!= 0)
158 fatal("paperlength not a multiple of vertical resolution");
160 lines_per_page
= font::paperlength
/font::vert
;
161 if (lines_per_page
<= 0)
162 fatal("paperlength too small");
163 lines
= new glyph
*[lines_per_page
];
164 for (int i
= 0; i
< lines_per_page
; i
++)
166 columns_per_page
= font::paperwidth
/font::hor
;
167 // If columns_per_page is zero, we won't truncate.
168 if (columns_per_page
< 0)
169 columns_per_page
= 0;
172 tty_printer::~tty_printer()
177 void tty_printer::set_char(int i
, font
*f
, const environment
*env
, int w
)
180 fatal("width of character not equal to horizontal resolution");
181 add_char(f
->get_code(i
), env
->hpos
, env
->vpos
, ((tty_font
*)f
)->get_mode());
184 void tty_printer::add_char(unsigned char c
, int h
, int v
, unsigned char mode
)
187 // This is too expensive.
188 if (h
% font::hor
!= 0)
189 fatal("horizontal position not a multiple of horizontal resolution");
191 int hpos
= h
/ font::hor
;
193 error("character to the left of first column discarded");
196 if (columns_per_page
!= 0 && hpos
>= columns_per_page
) {
197 error("character to the right of last column discarded");
200 if (hpos
> USHRT_MAX
) {
201 error("character with ridiculously large horizontal position discarded");
205 if (v
== cached_v
&& cached_v
!= 0)
208 if (v
% font::vert
!= 0)
209 fatal("vertical position not a multiple of vertical resolution");
210 vpos
= v
/ font::vert
;
211 if (vpos
> lines_per_page
) {
212 error("character below last line discarded");
215 // Note that the first output line corresponds to groff
216 // position font::vert.
218 error("character above first line discarded");
224 glyph
*g
= new glyph
;
229 // The list will be reversed later. After reversal, it must be in
230 // increasing order of hpos, with HDRAW characters before VDRAW
231 // characters before normal characters at each hpos, and otherwise
232 // in order of occurrence.
234 for (glyph
**pp
= lines
+ (vpos
- 1); *pp
; pp
= &(*pp
)->next
)
235 if ((*pp
)->hpos
< hpos
236 || ((*pp
)->hpos
== hpos
&& (*pp
)->draw_mode() >= g
->draw_mode()))
243 void tty_printer::draw(int code
, int *p
, int np
, const environment
*env
)
245 if (code
!= 'l' || !draw_flag
)
248 error("2 arguments required for line");
260 add_char('|', env
->hpos
, v
, VDRAW_MODE
);
274 add_char('-', h
, env
->vpos
, HDRAW_MODE
);
281 void tty_printer::end_page()
283 for (int last_line
= lines_per_page
; last_line
> 0; last_line
--)
284 if (lines
[last_line
- 1])
287 for (int i
= 0; i
< last_line
; i
++) {
292 glyph
*tem
= p
->next
;
300 for (p
= g
; p
; delete p
, p
= nextp
) {
302 if (nextp
&& p
->hpos
== nextp
->hpos
) {
303 if (p
->draw_mode() == HDRAW_MODE
&& nextp
->draw_mode() == VDRAW_MODE
) {
307 if (p
->draw_mode() != 0 && p
->draw_mode() == nextp
->draw_mode()) {
308 nextp
->code
= p
->code
;
311 if (!overstrike_flag
)
314 if (hpos
> p
->hpos
) {
319 if (horizontal_tab_flag
) {
321 int next_tab_pos
= ((hpos
+ TAB_WIDTH
) / TAB_WIDTH
) * TAB_WIDTH
;
322 if (next_tab_pos
> p
->hpos
)
328 for (; hpos
< p
->hpos
; hpos
++)
331 assert(hpos
== p
->hpos
);
332 if (p
->mode
& UNDERLINE_MODE
) {
336 if (p
->mode
& BOLD_MODE
) {
345 if (form_feed_flag
) {
346 if (last_line
< lines_per_page
)
350 for (; last_line
< lines_per_page
; last_line
++)
355 font
*tty_printer::make_font(const char *nm
)
357 return tty_font::load_tty_font(nm
);
360 printer
*make_printer()
362 return new tty_printer
;
367 int main(int argc
, char **argv
)
369 program_name
= argv
[0];
370 static char stderr_buf
[BUFSIZ
];
371 setbuf(stderr
, stderr_buf
);
373 while ((c
= getopt(argc
, argv
, "F:vhfbuoBUd")) != EOF
)
377 extern const char *version_string
;
378 fprintf(stderr
, "grotty version %s\n", version_string
);
383 // Do not embolden by overstriking.
391 // Do not overstrike (other than emboldening and underlining).
395 // Do bold-underlining as bold.
396 bold_underline_mode
= BOLD_MODE
;
399 // Do bold-underlining as underlining.
400 bold_underline_mode
= UNDERLINE_MODE
;
403 // Use horizontal tabs.
404 horizontal_tab_flag
= 1;
410 font::command_line_font_dir(optarg
);
413 // Ignore \D commands.
425 for (int i
= optind
; i
< argc
; i
++)
434 fprintf(stderr
, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n",