Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / libs / libdriver / printer.cpp
blobfd77d6b59eb700e09192319e7262c6a3b9df3b51
1 // -*- C++ -*-
3 // <groff_src_dir>/src/libs/libdriver/printer.cpp
5 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003, 2004, 2005
6 Free Software Foundation, Inc.
7 Written by James Clark (jjc@jclark.com)
9 Last update: 02 Mar 2005
11 This file is part of groff.
13 groff is free software; you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2, or (at your option)
16 any later version.
18 groff is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with groff; see the file COPYING. If not, write to the Free
25 Software Foundation, 51 Franklin St - Fifth Floor, Boston, MA
26 02110-1301, USA.
29 #include "driver.h"
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.
35 We normally expect to catch this, and clean up the error context, when
36 the pager exits, because we should get, and handle, a SIGPIPE.
38 However ...
41 #if (defined(_MSC_VER) || defined(_WIN32)) \
42 && !defined(__CYGWIN__) && !defined(_UWIN)
44 /* Native MS-Windows doesn't know about SIGPIPE, so we cannot detect the
45 early exit from the pager, and therefore, cannot clean up the error
46 context; thus we use the following static function to identify this
47 particular error context, and so suppress unwanted diagnostics.
50 static int
51 check_for_output_error (FILE* stream)
53 /* First, clean up any prior error context on the output stream */
54 if (ferror (stream))
55 clearerr (stream);
56 /* Clear errno, in case clearerr() and fflush() don't */
57 errno = 0;
58 /* Flush the output stream, so we can capture any error context, other
59 than the specific case we wish to suppress.
61 Microsoft doesn't document it, but the error code for the specific
62 context we are trying to suppress seems to be EINVAL -- a strange
63 choice, since it is not normally associated with fflush(); of course,
64 it *should* be EPIPE, but this *definitely* is not used, and *is* so
65 documented.
67 return ((fflush(stream) < 0) && (errno != EINVAL));
70 #else
72 /* For other systems, we simply assume that *any* output error context
73 is to be reported.
75 # define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0
77 #endif
80 font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
81 : p(f), next(fp)
85 printer::printer()
86 : font_list(0), font_table(0), nfonts(0)
90 printer::~printer()
92 a_delete font_table;
93 while (font_list) {
94 font_pointer_list *tem = font_list;
95 font_list = font_list->next;
96 delete tem->p;
97 delete tem;
99 if (check_for_output_error(stdout))
100 fatal("output error");
103 void printer::load_font(int n, const char *nm)
105 assert(n >= 0);
106 if (n >= nfonts) {
107 if (nfonts == 0) {
108 nfonts = 10;
109 if (nfonts <= n)
110 nfonts = n + 1;
111 font_table = new font *[nfonts];
112 for (int i = 0; i < nfonts; i++)
113 font_table[i] = 0;
115 else {
116 font **old_font_table = font_table;
117 int old_nfonts = nfonts;
118 nfonts *= 2;
119 if (n >= nfonts)
120 nfonts = n + 1;
121 font_table = new font *[nfonts];
122 int i;
123 for (i = 0; i < old_nfonts; i++)
124 font_table[i] = old_font_table[i];
125 for (i = old_nfonts; i < nfonts; i++)
126 font_table[i] = 0;
127 a_delete old_font_table;
130 font *f = find_font(nm);
131 font_table[n] = f;
134 font *printer::find_font(const char *nm)
136 for (font_pointer_list *p = font_list; p; p = p->next)
137 if (strcmp(p->p->get_name(), nm) == 0)
138 return p->p;
139 font *f = make_font(nm);
140 if (!f)
141 fatal("sorry, I can't continue");
142 font_list = new font_pointer_list(f, font_list);
143 return f;
146 font *printer::make_font(const char *nm)
148 return font::load_font(nm);
151 void printer::end_of_line()
155 void printer::special(char *, const environment *, char)
159 void printer::devtag(char *, const environment *, char)
163 void printer::draw(int, int *, int, const environment *)
167 void printer::change_color(const environment * const)
171 void printer::change_fill_color(const environment * const)
175 void printer::set_ascii_char(unsigned char c, const environment *env,
176 int *widthp)
178 char buf[2];
179 int w;
180 font *f;
182 buf[0] = c;
183 buf[1] = '\0';
185 int i = set_char_and_width(buf, env, &w, &f);
186 set_char(i, f, env, w, 0);
187 if (widthp) {
188 *widthp = w;
192 void printer::set_special_char(const char *nm, const environment *env,
193 int *widthp)
195 font *f;
196 int w;
197 int i = set_char_and_width(nm, env, &w, &f);
198 if (i != -1) {
199 set_char(i, f, env, w, nm);
200 if (widthp)
201 *widthp = w;
205 int printer::set_char_and_width(const char *nm, const environment *env,
206 int *widthp, font **f)
208 int i = font::name_to_index(nm);
209 int fn = env->fontno;
210 if (fn < 0 || fn >= nfonts) {
211 error("bad font position `%1'", fn);
212 return(-1);
214 *f = font_table[fn];
215 if (*f == 0) {
216 error("no font mounted at `%1'", fn);
217 return(-1);
219 if (!(*f)->contains(i)) {
220 if (nm[0] != '\0' && nm[1] == '\0')
221 error("font `%1' does not contain ascii character `%2'",
222 (*f)->get_name(),
223 nm[0]);
224 else
225 error("font `%1' does not contain special character `%2'",
226 (*f)->get_name(),
227 nm);
228 return(-1);
230 int w = (*f)->get_width(i, env->size);
231 if (widthp)
232 *widthp = w;
233 return( i );
236 void printer::set_numbered_char(int num, const environment *env, int *widthp)
238 int i = font::number_to_index(num);
239 int fn = env->fontno;
240 if (fn < 0 || fn >= nfonts) {
241 error("bad font position `%1'", fn);
242 return;
244 font *f = font_table[fn];
245 if (f == 0) {
246 error("no font mounted at `%1'", fn);
247 return;
249 if (!f->contains(i)) {
250 error("font `%1' does not contain numbered character %2",
251 f->get_name(),
252 num);
253 return;
255 int w = f->get_width(i, env->size);
256 if (widthp)
257 *widthp = w;
258 set_char(i, f, env, w, 0);
261 font *printer::get_font_from_index(int fontno)
263 if ((fontno >= 0) && (fontno < nfonts))
264 return(font_table[fontno]);
265 else
266 return(0);