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