3 // <groff_src_dir>/src/libs/libdriver/printer.cpp
5 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003, 2004, 2005,
7 Free Software Foundation, Inc.
8 Written by James Clark (jjc@jclark.com)
10 Last update: 5 Jan 2009
12 This file is part of groff.
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
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
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.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
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.
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.
40 #if (defined(_MSC_VER) || defined(_WIN32)) \
41 && !defined(__CYGWIN__) && !defined(_UWIN)
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.
50 check_for_output_error (FILE* stream)
52 /* First, clean up any prior error context on the output stream */
55 /* Clear errno, in case clearerr() and fflush() don't */
57 /* Flush the output stream, so we can capture any error context, other
58 than the specific case we wish to suppress.
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
66 return ((fflush(stream) < 0) && (errno != EINVAL));
71 /* For other systems, we simply assume that *any* output error context
74 # define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0
79 font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
85 : font_list(0), font_table(0), nfonts(0)
93 font_pointer_list *tem = font_list;
94 font_list = font_list->next;
98 if (check_for_output_error(stdout))
99 fatal("output error");
102 void printer::load_font(int n, const char *nm)
110 font_table = new font *[nfonts];
111 for (int i = 0; i < nfonts; i++)
115 font **old_font_table = font_table;
116 int old_nfonts = nfonts;
120 font_table = new font *[nfonts];
122 for (i = 0; i < old_nfonts; i++)
123 font_table[i] = old_font_table[i];
124 for (i = old_nfonts; i < nfonts; i++)
126 a_delete old_font_table;
129 font *f = find_font(nm);
133 font *printer::find_font(const char *nm)
135 for (font_pointer_list *p = font_list; p; p = p->next)
136 if (strcmp(p->p->get_name(), nm) == 0)
138 font *f = make_font(nm);
140 fatal("sorry, I can't continue");
141 font_list = new font_pointer_list(f, font_list);
145 font *printer::make_font(const char *nm)
147 return font::load_font(nm);
150 void printer::end_of_line()
154 void printer::special(char *, const environment *, char)
158 void printer::devtag(char *, const environment *, char)
162 void printer::draw(int, int *, int, const environment *)
166 void printer::change_color(const environment * const)
170 void printer::change_fill_color(const environment * const)
174 void printer::set_ascii_char(unsigned char c, const environment *env,
184 glyph *g = set_char_and_width(buf, env, &w, &f);
185 set_char(g, f, env, w, 0);
191 void printer::set_special_char(const char *nm, const environment *env,
196 glyph *g = set_char_and_width(nm, env, &w, &f);
197 if (g != UNDEFINED_GLYPH) {
198 set_char(g, f, env, w, nm);
204 glyph *printer::set_char_and_width(const char *nm, const environment *env,
205 int *widthp, font **f)
207 glyph *g = name_to_glyph(nm);
208 int fn = env->fontno;
209 if (fn < 0 || fn >= nfonts) {
210 error("bad font position `%1'", fn);
211 return UNDEFINED_GLYPH;
215 error("no font mounted at `%1'", fn);
216 return UNDEFINED_GLYPH;
218 if (!(*f)->contains(g)) {
219 if (nm[0] != '\0' && nm[1] == '\0')
220 error("font `%1' does not contain ascii character `%2'",
224 error("font `%1' does not contain special character `%2'",
227 return UNDEFINED_GLYPH;
229 int w = (*f)->get_width(g, env->size);
235 void printer::set_numbered_char(int num, const environment *env, int *widthp)
237 glyph *g = number_to_glyph(num);
238 int fn = env->fontno;
239 if (fn < 0 || fn >= nfonts) {
240 error("bad font position `%1'", fn);
243 font *f = font_table[fn];
245 error("no font mounted at `%1'", fn);
248 if (!f->contains(g)) {
249 error("font `%1' does not contain numbered character %2",
254 int w = f->get_width(g, env->size);
257 set_char(g, f, env, w, 0);
260 font *printer::get_font_from_index(int fontno)
262 if ((fontno >= 0) && (fontno < nfonts))
263 return(font_table[fontno]);