Sync-to-go: update copyright for 2015
[s-roff.git] / src / lib-driver / printer.cpp
blobfb047defdca0deb8da0b668a06b6e11192eef0c8
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2001 - 2006
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
13 * This is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with groff; see the file COPYING. If not, write to the Free
20 * Software Foundation, 51 Franklin St - Fifth Floor, Boston, MA
21 * 02110-1301, USA.
24 #include "config.h"
26 #include "driver.h"
28 /* If we are sending output to an onscreen pager (as is the normal case
29 when reading man pages), then we may get an error state on the output
30 stream, if the user does not read all the way to the end.
32 We normally expect to catch this, and clean up the error context, when
33 the pager exits, because we should get, and handle, a SIGPIPE.
35 However ...
38 #if (defined(_MSC_VER) || defined(_WIN32)) \
39 && !defined(__CYGWIN__) && !defined(_UWIN)
41 /* Native MS-Windows doesn't know about SIGPIPE, so we cannot detect the
42 early exit from the pager, and therefore, cannot clean up the error
43 context; thus we use the following static function to identify this
44 particular error context, and so suppress unwanted diagnostics.
47 static int
48 check_for_output_error (FILE* stream) /* FIXME in lib-roff, then?? */
50 /* First, clean up any prior error context on the output stream */
51 if (ferror (stream))
52 clearerr (stream);
53 /* Clear errno, in case clearerr() and fflush() don't */
54 errno = 0;
55 /* Flush the output stream, so we can capture any error context, other
56 than the specific case we wish to suppress.
58 Microsoft doesn't document it, but the error code for the specific
59 context we are trying to suppress seems to be EINVAL -- a strange
60 choice, since it is not normally associated with fflush(); of course,
61 it *should* be EPIPE, but this *definitely* is not used, and *is* so
62 documented.
64 return ((fflush(stream) < 0) && (errno != EINVAL));
67 #else
69 /* For other systems, we simply assume that *any* output error context
70 is to be reported.
72 # define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0
74 #endif
77 font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
78 : p(f), next(fp)
82 printer::printer()
83 : font_list(0), font_table(0), nfonts(0)
87 printer::~printer()
89 a_delete font_table;
90 while (font_list) {
91 font_pointer_list *tem = font_list;
92 font_list = font_list->next;
93 delete tem->p;
94 delete tem;
96 if (check_for_output_error(stdout))
97 fatal("output error");
100 void printer::load_font(int n, const char *nm)
102 assert(n >= 0);
103 if (n >= nfonts) {
104 if (nfonts == 0) {
105 nfonts = 10;
106 if (nfonts <= n)
107 nfonts = n + 1;
108 font_table = new font *[nfonts];
109 for (int i = 0; i < nfonts; i++)
110 font_table[i] = 0;
112 else {
113 font **old_font_table = font_table;
114 int old_nfonts = nfonts;
115 nfonts *= 2;
116 if (n >= nfonts)
117 nfonts = n + 1;
118 font_table = new font *[nfonts];
119 int i;
120 for (i = 0; i < old_nfonts; i++)
121 font_table[i] = old_font_table[i];
122 for (i = old_nfonts; i < nfonts; i++)
123 font_table[i] = 0;
124 a_delete old_font_table;
127 font *f = find_font(nm);
128 font_table[n] = f;
131 font *printer::find_font(const char *nm)
133 for (font_pointer_list *p = font_list; p; p = p->next)
134 if (strcmp(p->p->get_name(), nm) == 0)
135 return p->p;
136 font *f = make_font(nm);
137 if (!f)
138 fatal("sorry, I can't continue");
139 font_list = new font_pointer_list(f, font_list);
140 return f;
143 font *printer::make_font(const char *nm)
145 return font::load_font(nm);
148 void printer::end_of_line()
152 void printer::special(char *, const environment *, char)
156 void printer::devtag(char *, const environment *, char)
160 void printer::draw(int, int *, int, const environment *)
164 void printer::change_color(const environment * const)
168 void printer::change_fill_color(const environment * const)
172 void printer::set_ascii_char(unsigned char c, const environment *env,
173 int *widthp)
175 char buf[2];
176 int w;
177 font *f;
179 buf[0] = c;
180 buf[1] = '\0';
182 glyph *g = set_char_and_width(buf, env, &w, &f);
183 set_char(g, f, env, w, 0);
184 if (widthp) {
185 *widthp = w;
189 void printer::set_special_char(const char *nm, const environment *env,
190 int *widthp)
192 font *f;
193 int w;
194 glyph *g = set_char_and_width(nm, env, &w, &f);
195 if (g != UNDEFINED_GLYPH) {
196 set_char(g, f, env, w, nm);
197 if (widthp)
198 *widthp = w;
202 glyph *printer::set_char_and_width(const char *nm, const environment *env,
203 int *widthp, font **f)
205 glyph *g = name_to_glyph(nm);
206 int fn = env->fontno;
207 if (fn < 0 || fn >= nfonts) {
208 error("bad font position `%1'", fn);
209 return UNDEFINED_GLYPH;
211 *f = font_table[fn];
212 if (*f == 0) {
213 error("no font mounted at `%1'", fn);
214 return UNDEFINED_GLYPH;
216 if (!(*f)->contains(g)) {
217 if (nm[0] != '\0' && nm[1] == '\0')
218 error("font `%1' does not contain ascii character `%2'",
219 (*f)->get_name(),
220 nm[0]);
221 else
222 error("font `%1' does not contain special character `%2'",
223 (*f)->get_name(),
224 nm);
225 return UNDEFINED_GLYPH;
227 int w = (*f)->get_width(g, env->size);
228 if (widthp)
229 *widthp = w;
230 return g;
233 void printer::set_numbered_char(int num, const environment *env, int *widthp)
235 glyph *g = number_to_glyph(num);
236 int fn = env->fontno;
237 if (fn < 0 || fn >= nfonts) {
238 error("bad font position `%1'", fn);
239 return;
241 font *f = font_table[fn];
242 if (f == 0) {
243 error("no font mounted at `%1'", fn);
244 return;
246 if (!f->contains(g)) {
247 error("font `%1' does not contain numbered character %2",
248 f->get_name(),
249 num);
250 return;
252 int w = f->get_width(g, env->size);
253 if (widthp)
254 *widthp = w;
255 set_char(g, f, env, w, 0);
258 font *printer::get_font_from_index(int fontno)
260 if ((fontno >= 0) && (fontno < nfonts))
261 return(font_table[fontno]);
262 else
263 return(0);
266 // s-it2-mode