1/* $NetBSD$ */ 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 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 82font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) 83: p(f), next(fp) 84{ 85} 86 87printer::printer() 88: font_list(0), font_table(0), nfonts(0) 89{ 90} 91 92printer::~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 105void 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 136font *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 148font *printer::make_font(const char *nm) 149{ 150 return font::load_font(nm); 151} 152 153void printer::end_of_line() 154{ 155} 156 157void printer::special(char *, const environment *, char) 158{ 159} 160 161void printer::devtag(char *, const environment *, char) 162{ 163} 164 165void printer::draw(int, int *, int, const environment *) 166{ 167} 168 169void printer::change_color(const environment * const) 170{ 171} 172 173void printer::change_fill_color(const environment * const) 174{ 175} 176 177void 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 194void 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 207int 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 238void 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 263font *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