Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / groff / src / libs / libdriver / printer.cpp
1 // -*- C++ -*-
2
3 // <groff_src_dir>/src/libs/libdriver/printer.cpp
4
5 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003, 2004, 2005,
6                  2006, 2009
7    Free Software Foundation, Inc.
8    Written by James Clark (jjc@jclark.com)
9
10    Last update: 5 Jan 2009
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
16    the Free Software Foundation, either version 3 of the License, or
17    (at your option) any later version.
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
25    along with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #include "driver.h"
29
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
79 font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp)
80 : p(f), next(fp)
81 {
82 }
83
84 printer::printer()
85 : font_list(0), font_table(0), nfonts(0)
86 {
87 }
88
89 printer::~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   }
98   if (check_for_output_error(stdout))
99     fatal("output error");
100 }
101
102 void 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
133 font *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
145 font *printer::make_font(const char *nm)
146 {
147   return font::load_font(nm);
148 }
149
150 void printer::end_of_line()
151 {
152 }
153
154 void printer::special(char *, const environment *, char)
155 {
156 }
157
158 void printer::devtag(char *, const environment *, char)
159 {
160 }
161
162 void printer::draw(int, int *, int, const environment *)
163 {
164 }
165
166 void printer::change_color(const environment * const)
167 {
168 }
169
170 void printer::change_fill_color(const environment * const)
171 {
172 }
173
174 void 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
184   glyph *g = set_char_and_width(buf, env, &w, &f);
185   set_char(g, f, env, w, 0);
186   if (widthp) {
187     *widthp = w;
188   }
189 }
190
191 void printer::set_special_char(const char *nm, const environment *env,
192                                int *widthp)
193 {
194   font *f;
195   int w;
196   glyph *g = set_char_and_width(nm, env, &w, &f);
197   if (g != UNDEFINED_GLYPH) {
198     set_char(g, f, env, w, nm);
199     if (widthp)
200       *widthp = w;
201   }
202 }
203
204 glyph *printer::set_char_and_width(const char *nm, const environment *env,
205                                    int *widthp, font **f)
206 {
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;
212   }
213   *f = font_table[fn];
214   if (*f == 0) {
215     error("no font mounted at `%1'", fn);
216     return UNDEFINED_GLYPH;
217   }
218   if (!(*f)->contains(g)) {
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);
227     return UNDEFINED_GLYPH;
228   }
229   int w = (*f)->get_width(g, env->size);
230   if (widthp)
231     *widthp = w;
232   return g;
233 }
234
235 void printer::set_numbered_char(int num, const environment *env, int *widthp)
236 {
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);
241     return;
242   }
243   font *f = font_table[fn];
244   if (f == 0) {
245     error("no font mounted at `%1'", fn);
246     return;
247   }
248   if (!f->contains(g)) {
249     error("font `%1' does not contain numbered character %2",
250           f->get_name(),
251           num);
252     return;
253   }
254   int w = f->get_width(g, env->size);
255   if (widthp)
256     *widthp = w;
257   set_char(g, f, env, w, 0);
258 }
259
260 font *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 }