GROFF COMPILATION FIX
[unix-history] / usr / src / usr.bin / groff / grotty / grotty.cc
CommitLineData
b0f007a2
NH
1// -*- C++ -*-
2/* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.uucp)
4
5This file is part of groff.
6
7groff is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 1, or (at your option) any later
10version.
11
12groff is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License along
18with groff; see the file LICENSE. If not, write to the Free Software
19Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21#include "driver.h"
22
23#ifndef USHRT_MAX
24#define USHRT_MAX 65535
25#endif
26
27#define DEFAULT_LINES_PER_PAGE 66
28
29#define TAB_WIDTH 8
30
31static int horizontal_tab_flag = 0;
32static int form_feed_flag = 0;
33static int bold_flag = 1;
34static int underline_flag = 1;
35static int overstrike_flag = 1;
36
37enum { UNDERLINE_MODE = 01, BOLD_MODE = 02 };
38
39// Mode to use for bold-underlining.
40static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
41
42class tty_font : public font {
43 tty_font(const char *);
44 unsigned char mode;
45public:
46 ~tty_font();
47 unsigned char get_mode() { return mode; }
48#if 0
49 void handle_x_command(int argc, const char **argv);
50#endif
51 static tty_font *load_tty_font(const char *);
52};
53
54tty_font *tty_font::load_tty_font(const char *s)
55{
56 tty_font *f = new tty_font(s);
57 if (!f->load()) {
58 delete f;
59 return 0;
60 }
61 const char *s = f->get_internal_name();
62 long n;
63 if (s != 0 && (n = strtol(s, 0, 0)) != 0)
64 f->mode = int(n & (BOLD_MODE|UNDERLINE_MODE));
65 if (!underline_flag)
66 f->mode &= ~UNDERLINE_MODE;
67 if (!bold_flag)
68 f->mode &= ~BOLD_MODE;
69 if ((f->mode & (BOLD_MODE|UNDERLINE_MODE)) == (BOLD_MODE|UNDERLINE_MODE))
70 f->mode = (f->mode & ~(BOLD_MODE|UNDERLINE_MODE)) | bold_underline_mode;
71 return f;
72}
73
74tty_font::tty_font(const char *nm)
75: font(nm), mode(0)
76{
77}
78
79tty_font::~tty_font()
80{
81}
82
83#if 0
84void tty_font::handle_x_command(int argc, const char **argv)
85{
86 if (argc >= 1 && strcmp(argv[0], "bold") == 0)
87 mode |= BOLD_MODE;
88 else if (argc >= 1 && strcmp(argv[0], "underline") == 0)
89 mode |= UNDERLINE_MODE;
90}
91#endif
92
93// hpos and vpos must be non-adjacent, to work round a bug in g++ 1.37.1
94
95struct glyph {
96 unsigned short hpos;
97 unsigned short serial;
98 unsigned short vpos;
99 unsigned char code;
100 unsigned char mode;
101};
102
103class tty_printer : public printer {
104 enum { INITIAL_VEC_SIZE = 32 };
105 glyph *vec;
106 int vec_used;
107 int vec_size;
108 int lines_per_page;
109 int columns_per_page;
110public:
111 tty_printer();
112 ~tty_printer();
113 void set_char(int, font *, const environment *, int);
114 void begin_page(int) { }
115 void end_page();
116 font *make_font(const char *);
117};
118
119tty_printer::tty_printer()
120: vec_used(0), vec_size(0), vec(0)
121{
122 if (font::paperlength == 0)
123 lines_per_page = DEFAULT_LINES_PER_PAGE;
124 else if (font::paperlength % font::vert != 0)
125 fatal("paperlength not a multiple of vertical resolution");
126 else
127 lines_per_page = font::paperlength/font::vert;
128 if (lines_per_page > USHRT_MAX || lines_per_page <= 0)
129 fatal("ridiculous paperlength");
130 columns_per_page = font::paperwidth/font::hor;
131 // If columns_per_page is zero, we won't truncate.
132 if (columns_per_page < 0)
133 columns_per_page = 0;
134}
135
136tty_printer::~tty_printer()
137{
138 delete vec;
139}
140
141void tty_printer::set_char(int i, font *f, const environment *env, int w)
142{
143 int h = env->hpos;
144 if (h % font::hor != 0)
145 fatal("horizontal position not a multiple of horizontal resolution");
146 h /= font::hor;
147 if (h < 0) {
148 error("character to the left of first column discarded");
149 return;
150 }
151 if (columns_per_page != 0 && h >= columns_per_page) {
152 error("character to the right of last column discarded");
153 return;
154 }
155 if (h > USHRT_MAX) {
156 error("character with ridiculously large horizontal position discarded");
157 return;
158 }
159 int v = env->vpos;
160 if (v % font::vert != 0)
161 fatal("vertical position not a multiple of vertical resolution");
162 v /= font::vert;
163 // Note that the first output line corresponds to groff position font::vert.
164 if (v <= 0) {
165 error("character above first line discarded");
166 return;
167 }
168 if (v > lines_per_page) {
169 error("character below last line discarded");
170 return;
171 }
172 if (w != font::hor)
173 fatal("width of character not equal to horizontal resolution");
174 if (vec_used >= vec_size) {
175 if (vec_size == 0)
176 vec_size = INITIAL_VEC_SIZE;
177 else {
178 if (vec_size > USHRT_MAX/2) {
179 if (vec_size >= USHRT_MAX)
180 fatal("too many characters on the page");
181 vec_size = USHRT_MAX;
182 }
183 else
184 vec_size *= 2;
185 }
186 glyph *old_vec = vec;
187 vec = new glyph [vec_size];
188 if (vec_used)
189 memcpy(vec, old_vec, vec_used*sizeof(glyph));
190 delete old_vec;
191 }
192 // We need a stable sort, but qsort is not stable, so we fake it.
193 vec[vec_used].serial = vec_used;
194 vec[vec_used].hpos = h;
195 vec[vec_used].vpos = v;
196 vec[vec_used].code = f->get_code(i);
197 vec[vec_used].mode = ((tty_font *)f)->get_mode();
198 vec_used++;
199}
200
201extern "C" {
202static int compare_glyph(void *p1, void *p2)
203{
204 int v1 = ((glyph *)p1)->vpos;
205 int v2 = ((glyph *)p2)->vpos;
206 if (v1 < v2)
207 return -1;
208 if (v1 > v2)
209 return 1;
210 int h1 = ((glyph *)p1)->hpos;
211 int h2 = ((glyph *)p2)->hpos;
212 if (h1 < h2)
213 return -1;
214 if (h1 > h2)
215 return 1;
216 if (((glyph *)p1)->serial < ((glyph *)p2)->serial)
217 return -1;
218 return 1;
219}
220}
221
222void tty_printer::end_page()
223{
224 qsort(vec, vec_used, sizeof(glyph), compare_glyph);
225 int hpos = 0;
226 int vpos = 1;
227 // We have already discarded characters with vpos < 1 or > lines_per_page.
228 for (int i = 0; i < vec_used; i++) {
229 assert(vpos <= vec[i].vpos);
230 if (!overstrike_flag
231 && i + 1 < vec_used
232 && vec[i].hpos == vec[i + 1].hpos
233 && vec[i].vpos == vec[i + 1].vpos)
234 continue;
235 for (; vpos < vec[i].vpos; vpos++) {
236 putchar('\n');
237 hpos = 0;
238 }
239 if (hpos > vec[i].hpos) {
240 putchar('\b');
241 hpos--;
242 }
243 else {
244 if (horizontal_tab_flag) {
245 for (;;) {
246 int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
247 if (next_tab_pos > vec[i].hpos)
248 break;
249 putchar('\t');
250 hpos = next_tab_pos;
251 }
252 }
253 for (; hpos < vec[i].hpos; hpos++)
254 putchar(' ');
255 }
256 assert(hpos == vec[i].hpos && vpos == vec[i].vpos);
257 if (isalnum(vec[i].code) && vec[i].mode & UNDERLINE_MODE) {
258 putchar('_');
259 putchar('\b');
260 }
261 if (vec[i].mode & BOLD_MODE) {
262 putchar(vec[i].code);
263 putchar('\b');
264 }
265 putchar(vec[i].code);
266 hpos++;
267 }
268 if (form_feed_flag) {
269 if (hpos != 0) {
270 putchar('\n');
271 vpos++;
272 }
273 if (vpos <= lines_per_page)
274 putchar('\f');
275 }
276 else {
277 for (; vpos <= lines_per_page; vpos++)
278 putchar('\n');
279 }
280 vec_used = 0;
281}
282
283font *tty_printer::make_font(const char *nm)
284{
285 return tty_font::load_tty_font(nm);
286}
287
288printer *make_printer()
289{
290 return new tty_printer;
291}
292
293static void usage();
294
295int main(int argc, char **argv)
296{
297 program_name = argv[0];
298 static char stderr_buf[BUFSIZ];
299 setbuf(stderr, stderr_buf);
300 int c;
301 while ((c = getopt(argc, argv, "F:vhfbuoBU")) != EOF)
302 switch(c) {
303 case 'v':
304 {
305 extern const char *version_string;
306 fprintf(stderr, "grotty version %s\n", version_string);
307 fflush(stderr);
308 break;
309 }
310 case 'b':
311 // Do not embolden by overstriking.
312 bold_flag = 0;
313 break;
314 case 'u':
315 // Do not underline.
316 underline_flag = 0;
317 break;
318 case 'o':
319 // Do not overstrike (other than emboldening and underlining).
320 overstrike_flag = 0;
321 break;
322 case 'B':
323 // Do bold-underlining as bold.
324 bold_underline_mode = BOLD_MODE;
325 break;
326 case 'U':
327 // Do bold-underlining as underlining.
328 bold_underline_mode = UNDERLINE_MODE;
329 break;
330 case 'h':
331 // Use horizontal tabs.
332 horizontal_tab_flag = 1;
333 break;
334 case 'f':
335 form_feed_flag = 1;
336 break;
337 case 'F':
338 font::command_line_font_dir(optarg);
339 break;
340 case '?':
341 usage();
342 break;
343 default:
344 assert(0);
345 }
346 if (optind >= argc)
347 do_file("-");
348 else {
349 for (int i = optind; i < argc; i++)
350 do_file(argv[i]);
351 }
352 delete pr;
353 exit(0);
354}
355
356static void usage()
357{
358 fprintf(stderr, "usage: %s [-hfvbuoBU] [-F dir] [files ...]\n",
359 program_name);
360 exit(1);
361}