Line data Source code
1 : /* Copyright (C) 1989-2025 Free Software Foundation, Inc.
2 : Written by James Clark (jjc@jclark.com)
3 :
4 : This file is part of groff, the GNU roff typesetting system.
5 :
6 : groff is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : groff is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : #include <config.h>
22 : #endif
23 :
24 : #include <assert.h>
25 : #include <errno.h> // EINVAL, errno
26 : #include <stdio.h> // clearerr(), ferror(), fflush(), stdout
27 : #include <string.h> // strcmp()
28 :
29 : #include "driver.h"
30 :
31 : /* If we are sending output to an onscreen pager (as is the normal case
32 : when reading man pages), then we may get an error state on the output
33 : stream, if the user does not read all the way to the end.
34 :
35 : We normally expect to catch this, and clean up the error context,
36 : when the pager exits, because we should get, and handle, a SIGPIPE.
37 :
38 : However ...
39 : */
40 :
41 : #if (defined(_MSC_VER) || defined(_WIN32)) \
42 : && !defined(__CYGWIN__) && !defined(_UWIN)
43 :
44 : /* Native MS-Windows doesn't know about SIGPIPE, so we cannot detect
45 : the early exit from the pager, and therefore, cannot clean up the
46 : error context; thus we use the following static function to
47 : identify this particular error context, and so suppress unwanted
48 : diagnostics.
49 : */
50 :
51 : static int
52 : check_for_output_error (FILE* stream)
53 : {
54 : /* First, clean up any prior error context on the output stream */
55 : if (ferror (stream))
56 : clearerr (stream);
57 : /* Clear errno, in case clearerr() and fflush() don't */
58 : errno = 0;
59 : /* Flush the output stream, so we can capture any error context,
60 : other than the specific case we wish to suppress.
61 :
62 : Microsoft doesn't document it, but the error code for the
63 : specific context we are trying to suppress seems to be EINVAL --
64 : a strange choice, since it is not normally associated with
65 : fflush(); of course, it *should* be EPIPE, but this *definitely*
66 : is not used, and *is* so documented.
67 : */
68 : return ((fflush(stream) < 0) && (errno != EINVAL));
69 : }
70 :
71 : #else
72 :
73 : /* For other systems, we simply assume that *any* output error context
74 : is to be reported.
75 : */
76 : # define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0
77 :
78 : #endif
79 :
80 :
81 1464 : font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
82 1464 : : p(f), next(fp)
83 : {
84 1464 : }
85 :
86 1004 : printer::printer()
87 1004 : : font_list(0 /* nullptr */), font_table(0 /* nullptr */), nfonts(0)
88 : {
89 1004 : }
90 :
91 2008 : printer::~printer()
92 : {
93 1004 : delete[] font_table;
94 2468 : while (font_list) {
95 1464 : font_pointer_list *tem = font_list;
96 1464 : font_list = font_list->next;
97 1464 : delete tem->p;
98 1464 : delete tem;
99 : }
100 1004 : if (check_for_output_error(stdout))
101 0 : fatal("output error");
102 1004 : }
103 :
104 2374 : void printer::load_font(int n, const char *nm)
105 : {
106 2374 : assert(n >= 0);
107 2374 : if (n >= nfonts) {
108 989 : if (0 == nfonts) {
109 975 : nfonts = 10;
110 975 : if (nfonts <= n)
111 15 : nfonts = n + 1;
112 975 : font_table = new font *[nfonts];
113 11117 : for (int i = 0; i < nfonts; i++)
114 10142 : font_table[i] = 0 /* nullptr */;
115 : }
116 : else {
117 14 : font **old_font_table = font_table;
118 14 : int old_nfonts = nfonts;
119 14 : nfonts *= 2;
120 14 : if (n >= nfonts)
121 3 : nfonts = n + 1;
122 14 : font_table = new font *[nfonts];
123 : int i;
124 437 : for (i = 0; i < old_nfonts; i++)
125 423 : font_table[i] = old_font_table[i];
126 480 : for (i = old_nfonts; i < nfonts; i++)
127 466 : font_table[i] = 0 /* nullptr */;
128 14 : delete[] old_font_table;
129 : }
130 : }
131 2374 : font *f = find_font(nm);
132 2374 : font_table[n] = f;
133 2374 : }
134 :
135 2374 : font *printer::find_font(const char *nm)
136 : {
137 9130 : for (font_pointer_list *p = font_list; p; p = p->next)
138 7666 : if (strcmp(p->p->get_filename(), nm) == 0)
139 910 : return p->p;
140 1464 : font *f = make_font(nm);
141 1464 : if (0 /* nullptr */ == f)
142 0 : fatal("cannot find font '%1'", nm);
143 1464 : font_list = new font_pointer_list(f, font_list);
144 1464 : return f;
145 : }
146 :
147 0 : font *printer::make_font(const char *nm)
148 : {
149 0 : return font::load_font(nm);
150 : }
151 :
152 29491 : void printer::end_of_line()
153 : {
154 29491 : }
155 :
156 0 : void printer::special(char *, const environment *, char)
157 : {
158 0 : }
159 :
160 5877 : void printer::devtag(char *, const environment *, char)
161 : {
162 5877 : }
163 :
164 : // TODO: 1st and 3rd args should be `const`.
165 0 : void printer::draw(int, int *, int, const environment *)
166 : {
167 0 : }
168 :
169 47439 : void printer::change_color(const environment * const)
170 : {
171 47439 : }
172 :
173 65278 : void printer::change_fill_color(const environment * const)
174 : {
175 65278 : }
176 :
177 1420823 : void printer::set_ascii_char(unsigned char c, const environment *env,
178 : int *widthp)
179 : {
180 : char buf[2];
181 : int w;
182 : font *f;
183 :
184 1420823 : buf[0] = c;
185 1420823 : buf[1] = '\0';
186 :
187 1420823 : glyph *g = set_char_and_width(buf, env, &w, &f);
188 :
189 1420823 : if (g != UNDEFINED_GLYPH) {
190 1420822 : set_char(g, f, env, w, 0 /* nullptr */);
191 1420822 : if (widthp != 0 /* nullptr */)
192 1420606 : *widthp = w;
193 : }
194 1420823 : }
195 :
196 16637 : void printer::set_special_char(const char *nm, const environment *env,
197 : int *widthp)
198 : {
199 : font *f;
200 : int w;
201 16637 : glyph *g = set_char_and_width(nm, env, &w, &f);
202 16637 : if (g != UNDEFINED_GLYPH) {
203 16637 : set_char(g, f, env, w, nm);
204 16637 : if (widthp != 0 /* nullptr */)
205 0 : *widthp = w;
206 : }
207 16637 : }
208 :
209 1437460 : glyph *printer::set_char_and_width(const char *nm,
210 : const environment *env, int *widthp,
211 : font **f)
212 : {
213 1437460 : glyph *g = name_to_glyph(nm);
214 1437460 : int fn = env->fontno;
215 1437460 : if ((fn < 0) || (fn >= nfonts)) {
216 1 : error("invalid font position '%1'", fn);
217 1 : return UNDEFINED_GLYPH;
218 : }
219 1437459 : *f = font_table[fn];
220 1437459 : if (0 /* nullptr */ == *f) {
221 0 : error("no font mounted at position %1", fn);
222 0 : return UNDEFINED_GLYPH;
223 : }
224 1437459 : if (!(*f)->contains(g)) {
225 0 : if ((nm[0] != '\0') && ('\0' == nm[1]))
226 0 : error("font description file '%1' lacks glyph for ordinary"
227 0 : " character '%2'", (*f)->get_filename(), nm[0]);
228 : else
229 0 : error("font description file '%1' lacks glyph for special"
230 0 : " character '%2'", (*f)->get_filename(), nm);
231 0 : return UNDEFINED_GLYPH;
232 : }
233 1437459 : int w = (*f)->get_width(g, env->size);
234 1437459 : if (widthp != 0 /* nullptr */)
235 1437459 : *widthp = w;
236 1437459 : return g;
237 : }
238 :
239 21138 : void printer::set_numbered_char(int num, const environment *env, int
240 : *widthp)
241 : {
242 21138 : glyph *g = number_to_glyph(num);
243 21138 : int fn = env->fontno;
244 21138 : if ((fn < 0) || (fn >= nfonts)) {
245 0 : error("invalid font position '%1'", fn);
246 0 : return;
247 : }
248 21138 : font *f = font_table[fn];
249 21138 : if (0 /* nullptr */ == f) {
250 0 : error("no font mounted at position %1", fn);
251 0 : return;
252 : }
253 21138 : if (!f->contains(g)) {
254 0 : error("font '%1' has no glyph at index %2", f->get_filename(), num);
255 0 : return;
256 : }
257 21138 : int w = f->get_width(g, env->size);
258 21138 : if (widthp != 0 /* nullptr */)
259 0 : *widthp = w;
260 21138 : set_char(g, f, env, w, 0 /* nullptr */);
261 : }
262 :
263 5210 : font *printer::get_font_from_index(int fontno)
264 : {
265 5210 : if ((fontno >= 0) && (fontno < nfonts))
266 5210 : return font_table[fontno];
267 : else
268 0 : return 0 /* nullptr */;
269 : }
270 :
271 : // Local Variables:
272 : // fill-column: 72
273 : // mode: C++
274 : // End:
275 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:
|