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