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 Free Software Foundation, Inc. 7 Written by James Clark (jjc@jclark.com) 8 9 Last update: 02 Mar 2005 10 11 This file is part of groff. 12 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. 17 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. 22 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. 27*/ 28 29#include "driver.h" 30 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. 34 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. 37 38 However ... 39*/ 40 41#if (defined(_MSC_VER) || defined(_WIN32)) \ 42 && !defined(__CYGWIN__) && !defined(_UWIN) 43 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. 48 */ 49 50 static int 51 check_for_output_error (FILE* stream) 52 { 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. 60 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. 66 */ 67 return ((fflush(stream) < 0) && (errno != EINVAL)); 68 } 69 70#else 71 72 /* For other systems, we simply assume that *any* output error context 73 is to be reported. 74 */ 75# define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0 76 77#endif 78 79 80font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) 81: p(f), next(fp) 82{ 83} 84 85printer::printer() 86: font_list(0), font_table(0), nfonts(0) 87{ 88} 89 90printer::~printer() 91{ 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; 98 } 99 if (check_for_output_error(stdout)) 100 fatal("output error"); 101} 102 103void printer::load_font(int n, const char *nm) 104{ 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; 114 } 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; 128 } 129 } 130 font *f = find_font(nm); 131 font_table[n] = f; 132} 133 134font *printer::find_font(const char *nm) 135{ 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; 144} 145 146font *printer::make_font(const char *nm) 147{ 148 return font::load_font(nm); 149} 150 151void printer::end_of_line() 152{ 153} 154 155void printer::special(char *, const environment *, char) 156{ 157} 158 159void printer::devtag(char *, const environment *, char) 160{ 161} 162 163void printer::draw(int, int *, int, const environment *) 164{ 165} 166 167void printer::change_color(const environment * const) 168{ 169} 170 171void printer::change_fill_color(const environment * const) 172{ 173} 174 175void printer::set_ascii_char(unsigned char c, const environment *env, 176 int *widthp) 177{ 178 char buf[2]; 179 int w; 180 font *f; 181 182 buf[0] = c; 183 buf[1] = '\0'; 184 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; 189 } 190} 191 192void printer::set_special_char(const char *nm, const environment *env, 193 int *widthp) 194{ 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; 202 } 203} 204 205int printer::set_char_and_width(const char *nm, const environment *env, 206 int *widthp, font **f) 207{ 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); 213 } 214 *f = font_table[fn]; 215 if (*f == 0) { 216 error("no font mounted at `%1'", fn); 217 return(-1); 218 } 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); 229 } 230 int w = (*f)->get_width(i, env->size); 231 if (widthp) 232 *widthp = w; 233 return( i ); 234} 235 236void printer::set_numbered_char(int num, const environment *env, int *widthp) 237{ 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; 243 } 244 font *f = font_table[fn]; 245 if (f == 0) { 246 error("no font mounted at `%1'", fn); 247 return; 248 } 249 if (!f->contains(i)) { 250 error("font `%1' does not contain numbered character %2", 251 f->get_name(), 252 num); 253 return; 254 } 255 int w = f->get_width(i, env->size); 256 if (widthp) 257 *widthp = w; 258 set_char(i, f, env, w, 0); 259} 260 261font *printer::get_font_from_index(int fontno) 262{ 263 if ((fontno >= 0) && (fontno < nfonts)) 264 return(font_table[fontno]); 265 else 266 return(0); 267} 268