1114402Sru// -*- C++ -*- 2114402Sru 3114402Sru// <groff_src_dir>/src/libs/libdriver/printer.cpp 4114402Sru 5151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2003, 2004, 2005 6114402Sru Free Software Foundation, Inc. 7114402Sru Written by James Clark (jjc@jclark.com) 8114402Sru 9151497Sru Last update: 02 Mar 2005 10114402Sru 11114402Sru This file is part of groff. 12114402Sru 13114402Sru groff is free software; you can redistribute it and/or modify it 14114402Sru under the terms of the GNU General Public License as published by 15114402Sru the Free Software Foundation; either version 2, or (at your option) 16114402Sru any later version. 17114402Sru 18114402Sru groff is distributed in the hope that it will be useful, but 19114402Sru WITHOUT ANY WARRANTY; without even the implied warranty of 20114402Sru MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21114402Sru General Public License for more details. 22114402Sru 23114402Sru You should have received a copy of the GNU General Public License 24114402Sru along with groff; see the file COPYING. If not, write to the Free 25151497Sru Software Foundation, 51 Franklin St - Fifth Floor, Boston, MA 26151497Sru 02110-1301, USA. 27114402Sru*/ 28114402Sru 29114402Sru#include "driver.h" 30114402Sru 31151497Sru/* If we are sending output to an onscreen pager (as is the normal case 32151497Sru when reading man pages), then we may get an error state on the output 33151497Sru stream, if the user does not read all the way to the end. 34151497Sru 35151497Sru We normally expect to catch this, and clean up the error context, when 36151497Sru the pager exits, because we should get, and handle, a SIGPIPE. 37151497Sru 38151497Sru However ... 39151497Sru*/ 40151497Sru 41151497Sru#if (defined(_MSC_VER) || defined(_WIN32)) \ 42151497Sru && !defined(__CYGWIN__) && !defined(_UWIN) 43151497Sru 44151497Sru /* Native MS-Windows doesn't know about SIGPIPE, so we cannot detect the 45151497Sru early exit from the pager, and therefore, cannot clean up the error 46151497Sru context; thus we use the following static function to identify this 47151497Sru particular error context, and so suppress unwanted diagnostics. 48151497Sru */ 49151497Sru 50151497Sru static int 51151497Sru check_for_output_error (FILE* stream) 52151497Sru { 53151497Sru /* First, clean up any prior error context on the output stream */ 54151497Sru if (ferror (stream)) 55151497Sru clearerr (stream); 56151497Sru /* Clear errno, in case clearerr() and fflush() don't */ 57151497Sru errno = 0; 58151497Sru /* Flush the output stream, so we can capture any error context, other 59151497Sru than the specific case we wish to suppress. 60151497Sru 61151497Sru Microsoft doesn't document it, but the error code for the specific 62151497Sru context we are trying to suppress seems to be EINVAL -- a strange 63151497Sru choice, since it is not normally associated with fflush(); of course, 64151497Sru it *should* be EPIPE, but this *definitely* is not used, and *is* so 65151497Sru documented. 66151497Sru */ 67151497Sru return ((fflush(stream) < 0) && (errno != EINVAL)); 68151497Sru } 69151497Sru 70151497Sru#else 71151497Sru 72151497Sru /* For other systems, we simply assume that *any* output error context 73151497Sru is to be reported. 74151497Sru */ 75151497Sru# define check_for_output_error(stream) ferror(stream) || fflush(stream) < 0 76151497Sru 77151497Sru#endif 78151497Sru 79151497Sru 80114402Srufont_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) 81114402Sru: p(f), next(fp) 82114402Sru{ 83114402Sru} 84114402Sru 85114402Sruprinter::printer() 86114402Sru: font_list(0), font_table(0), nfonts(0) 87114402Sru{ 88114402Sru} 89114402Sru 90114402Sruprinter::~printer() 91114402Sru{ 92114402Sru a_delete font_table; 93114402Sru while (font_list) { 94114402Sru font_pointer_list *tem = font_list; 95114402Sru font_list = font_list->next; 96114402Sru delete tem->p; 97114402Sru delete tem; 98114402Sru } 99151497Sru if (check_for_output_error(stdout)) 100114402Sru fatal("output error"); 101114402Sru} 102114402Sru 103114402Sruvoid printer::load_font(int n, const char *nm) 104114402Sru{ 105114402Sru assert(n >= 0); 106114402Sru if (n >= nfonts) { 107114402Sru if (nfonts == 0) { 108114402Sru nfonts = 10; 109114402Sru if (nfonts <= n) 110114402Sru nfonts = n + 1; 111114402Sru font_table = new font *[nfonts]; 112114402Sru for (int i = 0; i < nfonts; i++) 113114402Sru font_table[i] = 0; 114114402Sru } 115114402Sru else { 116114402Sru font **old_font_table = font_table; 117114402Sru int old_nfonts = nfonts; 118114402Sru nfonts *= 2; 119114402Sru if (n >= nfonts) 120114402Sru nfonts = n + 1; 121114402Sru font_table = new font *[nfonts]; 122114402Sru int i; 123114402Sru for (i = 0; i < old_nfonts; i++) 124114402Sru font_table[i] = old_font_table[i]; 125114402Sru for (i = old_nfonts; i < nfonts; i++) 126114402Sru font_table[i] = 0; 127114402Sru a_delete old_font_table; 128114402Sru } 129114402Sru } 130114402Sru font *f = find_font(nm); 131114402Sru font_table[n] = f; 132114402Sru} 133114402Sru 134114402Srufont *printer::find_font(const char *nm) 135114402Sru{ 136114402Sru for (font_pointer_list *p = font_list; p; p = p->next) 137114402Sru if (strcmp(p->p->get_name(), nm) == 0) 138114402Sru return p->p; 139114402Sru font *f = make_font(nm); 140114402Sru if (!f) 141114402Sru fatal("sorry, I can't continue"); 142114402Sru font_list = new font_pointer_list(f, font_list); 143114402Sru return f; 144114402Sru} 145114402Sru 146114402Srufont *printer::make_font(const char *nm) 147114402Sru{ 148114402Sru return font::load_font(nm); 149114402Sru} 150114402Sru 151114402Sruvoid printer::end_of_line() 152114402Sru{ 153114402Sru} 154114402Sru 155114402Sruvoid printer::special(char *, const environment *, char) 156114402Sru{ 157114402Sru} 158114402Sru 159151497Sruvoid printer::devtag(char *, const environment *, char) 160151497Sru{ 161151497Sru} 162151497Sru 163114402Sruvoid printer::draw(int, int *, int, const environment *) 164114402Sru{ 165114402Sru} 166114402Sru 167114402Sruvoid printer::change_color(const environment * const) 168114402Sru{ 169114402Sru} 170114402Sru 171114402Sruvoid printer::change_fill_color(const environment * const) 172114402Sru{ 173114402Sru} 174114402Sru 175114402Sruvoid printer::set_ascii_char(unsigned char c, const environment *env, 176114402Sru int *widthp) 177114402Sru{ 178114402Sru char buf[2]; 179114402Sru int w; 180114402Sru font *f; 181114402Sru 182114402Sru buf[0] = c; 183114402Sru buf[1] = '\0'; 184114402Sru 185114402Sru int i = set_char_and_width(buf, env, &w, &f); 186114402Sru set_char(i, f, env, w, 0); 187114402Sru if (widthp) { 188114402Sru *widthp = w; 189114402Sru } 190114402Sru} 191114402Sru 192114402Sruvoid printer::set_special_char(const char *nm, const environment *env, 193114402Sru int *widthp) 194114402Sru{ 195114402Sru font *f; 196114402Sru int w; 197114402Sru int i = set_char_and_width(nm, env, &w, &f); 198114402Sru if (i != -1) { 199114402Sru set_char(i, f, env, w, nm); 200114402Sru if (widthp) 201114402Sru *widthp = w; 202114402Sru } 203114402Sru} 204114402Sru 205114402Sruint printer::set_char_and_width(const char *nm, const environment *env, 206114402Sru int *widthp, font **f) 207114402Sru{ 208114402Sru int i = font::name_to_index(nm); 209114402Sru int fn = env->fontno; 210114402Sru if (fn < 0 || fn >= nfonts) { 211114402Sru error("bad font position `%1'", fn); 212114402Sru return(-1); 213114402Sru } 214114402Sru *f = font_table[fn]; 215114402Sru if (*f == 0) { 216114402Sru error("no font mounted at `%1'", fn); 217114402Sru return(-1); 218114402Sru } 219114402Sru if (!(*f)->contains(i)) { 220114402Sru if (nm[0] != '\0' && nm[1] == '\0') 221114402Sru error("font `%1' does not contain ascii character `%2'", 222114402Sru (*f)->get_name(), 223114402Sru nm[0]); 224114402Sru else 225114402Sru error("font `%1' does not contain special character `%2'", 226114402Sru (*f)->get_name(), 227114402Sru nm); 228114402Sru return(-1); 229114402Sru } 230114402Sru int w = (*f)->get_width(i, env->size); 231114402Sru if (widthp) 232114402Sru *widthp = w; 233114402Sru return( i ); 234114402Sru} 235114402Sru 236114402Sruvoid printer::set_numbered_char(int num, const environment *env, int *widthp) 237114402Sru{ 238114402Sru int i = font::number_to_index(num); 239114402Sru int fn = env->fontno; 240114402Sru if (fn < 0 || fn >= nfonts) { 241114402Sru error("bad font position `%1'", fn); 242114402Sru return; 243114402Sru } 244114402Sru font *f = font_table[fn]; 245114402Sru if (f == 0) { 246114402Sru error("no font mounted at `%1'", fn); 247114402Sru return; 248114402Sru } 249114402Sru if (!f->contains(i)) { 250114402Sru error("font `%1' does not contain numbered character %2", 251114402Sru f->get_name(), 252114402Sru num); 253114402Sru return; 254114402Sru } 255114402Sru int w = f->get_width(i, env->size); 256114402Sru if (widthp) 257114402Sru *widthp = w; 258114402Sru set_char(i, f, env, w, 0); 259114402Sru} 260114402Sru 261114402Srufont *printer::get_font_from_index(int fontno) 262114402Sru{ 263114402Sru if ((fontno >= 0) && (fontno < nfonts)) 264114402Sru return(font_table[fontno]); 265114402Sru else 266114402Sru return(0); 267114402Sru} 268