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