1294113Sbapt// -*- C++ -*-
2241675Suqs/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3294113Sbapt     Written by Gaius Mulley (gaius@glam.ac.uk).
4279527Sbapt
5241675SuqsThis file is part of groff.
6241675Suqs
7241675Suqsgroff is free software; you can redistribute it and/or modify it under
8241675Suqsthe terms of the GNU General Public License as published by the Free
9241675SuqsSoftware Foundation; either version 2, or (at your option) any later
10241675Suqsversion.
11241675Suqs
12241675Suqsgroff is distributed in the hope that it will be useful, but WITHOUT ANY
13241675SuqsWARRANTY; without even the implied warranty of MERCHANTABILITY or
14241675SuqsFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15241675Suqsfor more details.
16241675Suqs
17241675SuqsYou should have received a copy of the GNU General Public License along
18241675Suqswith groff; see the file COPYING.  If not, write to the Free Software
19241675SuqsFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20275432Sbapt
21275432Sbapt#define PREHTMLC
22241675Suqs
23241675Suqs#include "lib.h"
24279527Sbapt
25261344Suqs#include <signal.h>
26241675Suqs#include <ctype.h>
27241675Suqs#include <assert.h>
28241675Suqs#include <stdlib.h>
29241675Suqs#include <errno.h>
30274880Sbapt#include "errarg.h"
31294113Sbapt#include "error.h"
32275432Sbapt#include "stringclass.h"
33294113Sbapt#include "posix.h"
34241675Suqs#include "defs.h"
35241675Suqs#include "searchpath.h"
36241675Suqs#include "paper.h"
37241675Suqs#include "device.h"
38241675Suqs#include "font.h"
39294113Sbapt
40294113Sbapt#include <errno.h>
41241675Suqs#include <sys/types.h>
42279527Sbapt#ifdef HAVE_UNISTD_H
43241675Suqs# include <unistd.h>
44279527Sbapt#endif
45279527Sbapt
46279527Sbapt#ifdef _POSIX_VERSION
47241675Suqs# include <sys/wait.h>
48279527Sbapt# define PID_T pid_t
49241675Suqs#else /* not _POSIX_VERSION */
50279527Sbapt# define PID_T int
51274880Sbapt#endif /* not _POSIX_VERSION */
52279527Sbapt
53279527Sbapt#include <stdarg.h>
54279527Sbapt
55279527Sbapt#include "nonposix.h"
56279527Sbapt
57279527Sbapt/* Establish some definitions to facilitate discrimination between
58279527Sbapt   differing runtime environments. */
59279527Sbapt
60279527Sbapt#undef MAY_FORK_CHILD_PROCESS
61279527Sbapt#undef MAY_SPAWN_ASYNCHRONOUS_CHILD
62279527Sbapt
63279527Sbapt#if defined(__MSDOS__) || defined(_WIN32)
64279527Sbapt
65279527Sbapt// Most MS-DOS and Win32 environments will be missing the `fork' capability
66279527Sbapt// (some like Cygwin have it, but it is best avoided).
67279527Sbapt
68279527Sbapt# define MAY_FORK_CHILD_PROCESS 0
69261344Suqs
70274880Sbapt// On these systems, we use `spawn...', instead of `fork' ... `exec...'.
71279527Sbapt# include <process.h>	// for `spawn...'
72279527Sbapt# include <fcntl.h>	// for attributes of pipes
73279527Sbapt
74279527Sbapt# if defined(__CYGWIN__) || defined(_UWIN) || defined(_WIN32)
75279527Sbapt
76279527Sbapt// These Win32 implementations allow parent and `spawn...'ed child to
77279527Sbapt// multitask asynchronously.
78279527Sbapt
79279527Sbapt#  define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
80279527Sbapt
81279527Sbapt# else
82279527Sbapt
83279527Sbapt// Others may adopt MS-DOS behaviour where parent must sleep,
84279527Sbapt// from `spawn...' until child terminates.
85279527Sbapt
86279527Sbapt#  define MAY_SPAWN_ASYNCHRONOUS_CHILD 0
87279527Sbapt
88279527Sbapt# endif /* not defined __CYGWIN__, _UWIN, or _WIN32 */
89241675Suqs
90279527Sbapt# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
91279527Sbapt/* When we are building a DEBUGGING version we need to tell pre-grohtml
92241675Suqs   where to put intermediate files (the DEBUGGING version will preserve
93279527Sbapt   these on exit).
94279527Sbapt
95279527Sbapt   On a UNIX host, we might simply use `/tmp', but MS-DOS and Win32 will
96279527Sbapt   probably not have this on all disk drives, so default to using
97279527Sbapt   `c:/temp' instead.  (Note that user may choose to override this by
98241675Suqs   supplying a definition such as
99279527Sbapt
100279527Sbapt     -DDEBUG_FILE_DIR=d:/path/to/debug/files
101279527Sbapt
102279527Sbapt   in the CPPFLAGS to `make'.) */
103279527Sbapt
104279527Sbapt#  define DEBUG_FILE_DIR c:/temp
105241675Suqs# endif
106279527Sbapt
107279527Sbapt#else /* not __MSDOS__ or _WIN32 */
108279527Sbapt
109279527Sbapt// For non-Microsoft environments assume UNIX conventions,
110279527Sbapt// so `fork' is required and child processes are asynchronous.
111279527Sbapt# define MAY_FORK_CHILD_PROCESS 1
112279527Sbapt# define MAY_SPAWN_ASYNCHRONOUS_CHILD 1
113279527Sbapt
114279527Sbapt# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR)
115279527Sbapt/* For a DEBUGGING version, on the UNIX host, we can also usually rely
116261344Suqs   on being able to use `/tmp' for temporary file storage.  (Note that,
117279527Sbapt   as in the __MSDOS__ or _WIN32 case above, the user may override this
118279527Sbapt   by defining
119279527Sbapt
120279527Sbapt     -DDEBUG_FILE_DIR=/path/to/debug/files
121279527Sbapt
122279527Sbapt   in the CPPFLAGS.) */
123279527Sbapt
124279527Sbapt#  define DEBUG_FILE_DIR /tmp
125279527Sbapt# endif
126279527Sbapt
127279527Sbapt#endif /* not __MSDOS__ or _WIN32 */
128279527Sbapt
129279527Sbapt#ifdef DEBUGGING
130279527Sbapt// For a DEBUGGING version, we need some additional macros,
131279527Sbapt// to direct the captured debug mode output to appropriately named files
132279527Sbapt// in the specified DEBUG_FILE_DIR.
133279527Sbapt
134279527Sbapt# define DEBUG_TEXT(text) #text
135279527Sbapt# define DEBUG_NAME(text) DEBUG_TEXT(text)
136279527Sbapt# define DEBUG_FILE(name) DEBUG_NAME(DEBUG_FILE_DIR) "/" name
137279527Sbapt#endif
138279527Sbapt
139279527Sbaptextern "C" const char *Version_string;
140279527Sbapt
141279527Sbapt#include "pre-html.h"
142279527Sbapt#include "pushback.h"
143261344Suqs#include "html-strings.h"
144241675Suqs
145279527Sbapt#define DEFAULT_LINE_LENGTH 7	// inches wide
146279527Sbapt#define DEFAULT_IMAGE_RES 100	// number of pixels per inch resolution
147279527Sbapt#define IMAGE_BOARDER_PIXELS 0
148279527Sbapt#define INLINE_LEADER_CHAR '\\'
149279527Sbapt
150241675Suqs// Don't use colour names here!  Otherwise there is a dependency on
151241675Suqs// a file called `rgb.txt' which maps names to colours.
152241675Suqs#define TRANSPARENT "-background rgb:f/f/f -transparent rgb:f/f/f"
153279527Sbapt#define MIN_ALPHA_BITS 0
154279527Sbapt#define MAX_ALPHA_BITS 4
155241675Suqs
156279527Sbapt#define PAGE_TEMPLATE_SHORT "pg"
157279527Sbapt#define PAGE_TEMPLATE_LONG "-page-"
158279527Sbapt#define PS_TEMPLATE_SHORT "ps"
159279527Sbapt#define PS_TEMPLATE_LONG "-ps-"
160279527Sbapt#define REGION_TEMPLATE_SHORT "rg"
161279527Sbapt#define REGION_TEMPLATE_LONG "-regions-"
162279527Sbapt
163279527Sbapt#if 0
164279527Sbapt# define DEBUGGING
165279527Sbapt#endif
166279527Sbapt
167279527Sbapt#if !defined(TRUE)
168279527Sbapt# define TRUE (1==1)
169279527Sbapt#endif
170279527Sbapt#if !defined(FALSE)
171279527Sbapt# define FALSE (1==0)
172279527Sbapt#endif
173279527Sbapt
174279527Sbapttypedef enum {
175279527Sbapt  CENTERED, LEFT, RIGHT, INLINE
176279527Sbapt} IMAGE_ALIGNMENT;
177279527Sbapt
178279527Sbaptstatic int postscriptRes = -1;		// postscript resolution,
179279527Sbapt					// dots per inch
180279527Sbaptstatic int stdoutfd = 1;		// output file descriptor -
181279527Sbapt					// normally 1 but might move
182279527Sbapt					// -1 means closed
183279527Sbaptstatic char *psFileName = NULL;		// name of postscript file
184241675Suqsstatic char *psPageName = NULL;		// name of file containing
185279527Sbapt					// postscript current page
186241675Suqsstatic char *regionFileName = NULL;	// name of file containing all
187279527Sbapt					// image regions
188279527Sbaptstatic char *imagePageName = NULL;	// name of bitmap image containing
189279527Sbapt					// current page
190279527Sbaptstatic const char *image_device = "pnmraw";
191241675Suqsstatic int image_res = DEFAULT_IMAGE_RES;
192279527Sbaptstatic int vertical_offset = 0;
193279527Sbaptstatic char *image_template = NULL;	// image template filename
194241675Suqsstatic char *macroset_template= NULL;	// image template passed to troff
195279527Sbapt					// by -D
196279527Sbaptstatic int troff_arg = 0;		// troff arg index
197279527Sbaptstatic char *image_dir = NULL;		// user specified image directory
198279527Sbaptstatic int textAlphaBits = MAX_ALPHA_BITS;
199279527Sbaptstatic int graphicAlphaBits = MAX_ALPHA_BITS;
200279527Sbaptstatic char *antiAlias = NULL;		// antialias arguments we pass to gs
201279527Sbaptstatic int show_progress = FALSE;	// should we display page numbers as
202279527Sbapt					// they are processed?
203279527Sbaptstatic int currentPageNo = -1;		// current image page number
204279527Sbapt#if defined(DEBUGGING)
205279527Sbaptstatic int debug = FALSE;
206275432Sbaptstatic char *troffFileName = NULL;	// output of pre-html output which
207279527Sbapt					// is sent to troff -Tps
208279527Sbaptstatic char *htmlFileName = NULL;	// output of pre-html output which
209279527Sbapt					// is sent to troff -Thtml
210279527Sbapt#endif
211241675Suqs
212279527Sbaptstatic char *linebuf = NULL;		// for scanning devps/DESC
213279527Sbaptstatic int linebufsize = 0;
214279527Sbaptstatic const char *image_gen = NULL;    // the `gs' program
215279527Sbapt
216279527Sbaptconst char *const FONT_ENV_VAR = "GROFF_FONT_PATH";
217279527Sbaptstatic search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0);
218279527Sbapt
219279527Sbapt
220279527Sbapt/*
221279527Sbapt *  Images are generated via postscript, gs, and the pnm utilities.
222279527Sbapt */
223279527Sbapt#define IMAGE_DEVICE "-Tps"
224241675Suqs
225279527Sbapt
226279527Sbaptstatic int do_file(const char *filename);
227274880Sbapt
228279527Sbapt
229279527Sbapt/*
230279527Sbapt *  sys_fatal - Write a fatal error message.
231279527Sbapt *              Taken from src/roff/groff/pipeline.c.
232279527Sbapt */
233279527Sbapt
234279527Sbaptvoid sys_fatal(const char *s)
235241675Suqs{
236279527Sbapt  fatal("%1: %2", s, strerror(errno));
237279527Sbapt}
238279527Sbapt
239279527Sbapt/*
240279527Sbapt *  get_line - Copy a line (w/o newline) from a file to the
241279527Sbapt *             global line buffer.
242279527Sbapt */
243279527Sbapt
244279527Sbaptint get_line(FILE *f)
245279527Sbapt{
246241675Suqs  if (f == 0)
247279527Sbapt    return 0;
248279527Sbapt  if (linebuf == 0) {
249279527Sbapt    linebuf = new char[128];
250279527Sbapt    linebufsize = 128;
251279527Sbapt  }
252279527Sbapt  int i = 0;
253279527Sbapt  // skip leading whitespace
254279527Sbapt  for (;;) {
255279527Sbapt    int c = getc(f);
256241675Suqs    if (c == EOF)
257279527Sbapt      return 0;
258279527Sbapt    if (c != ' ' && c != '\t') {
259279527Sbapt      ungetc(c, f);
260279527Sbapt      break;
261279527Sbapt    }
262279527Sbapt  }
263279527Sbapt  for (;;) {
264241675Suqs    int c = getc(f);
265279527Sbapt    if (c == EOF)
266279527Sbapt      break;
267279527Sbapt    if (i + 1 >= linebufsize) {
268279527Sbapt      char *old_linebuf = linebuf;
269279527Sbapt      linebuf = new char[linebufsize * 2];
270279527Sbapt      memcpy(linebuf, old_linebuf, linebufsize);
271279527Sbapt      a_delete old_linebuf;
272279527Sbapt      linebufsize *= 2;
273279527Sbapt    }
274279527Sbapt    linebuf[i++] = c;
275279527Sbapt    if (c == '\n') {
276279527Sbapt      i--;
277279527Sbapt      break;
278279527Sbapt    }
279279527Sbapt  }
280279527Sbapt  linebuf[i] = '\0';
281279527Sbapt  return 1;
282279527Sbapt}
283241675Suqs
284241675Suqs/*
285241675Suqs *  get_resolution - Return the postscript resolution from devps/DESC.
286241675Suqs */
287241675Suqs
288241675Suqsstatic unsigned int get_resolution(void)
289241675Suqs{
290241675Suqs  char *pathp;
291241675Suqs  FILE *f;
292241675Suqs  unsigned int res;
293241675Suqs  f = font_path.open_file("devps/DESC", &pathp);
294241675Suqs  a_delete pathp;
295241675Suqs  if (f == 0)
296241675Suqs    fatal("can't open devps/DESC");
297241675Suqs  while (get_line(f)) {
298241675Suqs    int n = sscanf(linebuf, "res %u", &res);
299241675Suqs    if (n >= 1) {
300241675Suqs      fclose(f);
301241675Suqs      return res;
302241675Suqs    }
303241675Suqs  }
304241675Suqs  fatal("can't find `res' keyword in devps/DESC");
305261344Suqs  return 0;
306261344Suqs}
307261344Suqs
308261344Suqs/*
309261344Suqs *  html_system - A wrapper for system().
310261344Suqs */
311261344Suqs
312261344Suqsvoid html_system(const char *s, int redirect_stdout)
313261344Suqs{
314241675Suqs  // Redirect standard error to the null device.  This is more
315241675Suqs  // portable than using "2> /dev/null", since it doesn't require a
316241675Suqs  // Unixy shell.
317274880Sbapt  int save_stderr = dup(2);
318261344Suqs  int save_stdout = dup(1);
319241675Suqs  int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666);
320241675Suqs  if (save_stderr > 2 && fdnull > 2)
321241675Suqs    dup2(fdnull, 2);
322241675Suqs  if (redirect_stdout && save_stdout > 1 && fdnull > 1)
323241675Suqs    dup2(fdnull, 1);
324241675Suqs  if (fdnull >= 0)
325241675Suqs    close(fdnull);
326241675Suqs  int status = system(s);
327241675Suqs  dup2(save_stderr, 2);
328241675Suqs  if (redirect_stdout)
329275432Sbapt    dup2(save_stdout, 1);
330274880Sbapt  if (status == -1)
331274880Sbapt    fprintf(stderr, "Calling `%s' failed\n", s);
332274880Sbapt  else if (status)
333275432Sbapt    fprintf(stderr, "Calling `%s' returned status %d\n", s, status);
334294113Sbapt  close(save_stderr);
335274880Sbapt  close(save_stdout);
336241675Suqs}
337241675Suqs
338241675Suqs/*
339241675Suqs *  make_message - Create a string via malloc and place the result of the
340241675Suqs *                 va args into string.  Finally the new string is returned.
341241675Suqs *                 Taken from man page of printf(3).
342241675Suqs */
343241675Suqs
344241675Suqschar *make_message(const char *fmt, ...)
345241675Suqs{
346274880Sbapt  /* Guess we need no more than 100 bytes. */
347241675Suqs  int n, size = 100;
348241675Suqs  char *p;
349241675Suqs  char *np;
350241675Suqs  va_list ap;
351275432Sbapt  if ((p = (char *)malloc(size)) == NULL)
352241675Suqs    return NULL;
353241675Suqs  while (1) {
354241675Suqs    /* Try to print in the allocated space. */
355241675Suqs    va_start(ap, fmt);
356241675Suqs    n = vsnprintf(p, size, fmt, ap);
357241675Suqs    va_end(ap);
358241675Suqs    /* If that worked, return the string. */
359241675Suqs    if (n > -1 && n < size - 1) { /* glibc 2.1 and pre-ANSI C 99 */
360241675Suqs      if (size > n + 1) {
361241675Suqs	np = strsave(p);
362241675Suqs	free(p);
363241675Suqs	return np;
364241675Suqs      }
365241675Suqs      return p;
366241675Suqs    }
367241675Suqs    /* Else try again with more space. */
368241675Suqs    else		/* glibc 2.0 */
369241675Suqs      size *= 2;	/* twice the old size */
370241675Suqs    if ((np = (char *)realloc(p, size)) == NULL) {
371241675Suqs      free(p);		/* realloc failed, free old, p. */
372241675Suqs      return NULL;
373241675Suqs    }
374241675Suqs    p = np;		/* use realloc'ed, p */
375241675Suqs  }
376241675Suqs}
377294113Sbapt
378294113Sbapt/*
379241675Suqs *  the class and methods for retaining ascii text
380241675Suqs */
381241675Suqs
382241675Suqsstruct char_block {
383241675Suqs  enum { SIZE = 256 };
384241675Suqs  char buffer[SIZE];
385241675Suqs  int used;
386241675Suqs  char_block *next;
387241675Suqs
388279527Sbapt  char_block();
389241675Suqs};
390261344Suqs
391274880Sbapt/*
392241675Suqs *  char_block - Constructor.  Set the, used, and, next, fields to zero.
393241675Suqs */
394241675Suqs
395241675Suqschar_block::char_block()
396275432Sbapt: used(0), next(0)
397294113Sbapt{
398275432Sbapt  for (int i = 0; i < SIZE; i++)
399275432Sbapt    buffer[i] = 0;
400275432Sbapt}
401279527Sbapt
402274880Sbaptclass char_buffer {
403241675Suqspublic:
404261344Suqs  char_buffer();
405241675Suqs  ~char_buffer();
406274880Sbapt  int read_file(FILE *fp);
407279527Sbapt  int do_html(int argc, char *argv[]);
408261344Suqs  int do_image(int argc, char *argv[]);
409261344Suqs  void emit_troff_output(int device_format_selector);
410261344Suqs  void write_upto_newline(char_block **t, int *i, int is_html);
411294113Sbapt  int can_see(char_block **t, int *i, const char *string);
412294113Sbapt  int skip_spaces(char_block **t, int *i);
413274880Sbapt  void skip_until_newline(char_block **t, int *i);
414241675Suqsprivate:
415294113Sbapt  char_block *head;
416294113Sbapt  char_block *tail;
417279527Sbapt  int run_output_filter(int device_format_selector, int argc, char *argv[]);
418261344Suqs};
419241675Suqs
420294113Sbapt/*
421294113Sbapt *  char_buffer - Constructor.
422241675Suqs */
423274880Sbapt
424274880Sbaptchar_buffer::char_buffer()
425275432Sbapt: head(0), tail(0)
426275432Sbapt{
427241675Suqs}
428274880Sbapt
429241675Suqs/*
430241675Suqs *  char_buffer - Destructor.  Throw away the whole buffer list.
431274880Sbapt */
432241675Suqs
433241675Suqschar_buffer::~char_buffer()
434241675Suqs{
435261344Suqs  while (head != NULL) {
436261344Suqs    char_block *temp = head;
437241675Suqs    head = head->next;
438241675Suqs    delete temp;
439241675Suqs  }
440241675Suqs}
441241675Suqs
442279527Sbapt/*
443241675Suqs *  read_file - Read in a complete file, fp, placing the contents inside
444241675Suqs *              char_blocks.
445294113Sbapt */
446294113Sbapt
447241675Suqsint char_buffer::read_file(FILE *fp)
448241675Suqs{
449241675Suqs  int n;
450241675Suqs  while (!feof(fp)) {
451241675Suqs    if (tail == NULL) {
452241675Suqs      tail = new char_block;
453279527Sbapt      head = tail;
454279527Sbapt    }
455279527Sbapt    else {
456241675Suqs      if (tail->used == char_block::SIZE) {
457241675Suqs	tail->next = new char_block;
458241675Suqs	tail = tail->next;
459279527Sbapt      }
460241675Suqs    }
461279527Sbapt    // at this point we have a tail which is ready for the next SIZE
462279527Sbapt    // bytes of the file
463279527Sbapt    n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp);
464241675Suqs    if (n <= 0)
465279527Sbapt      // error
466241675Suqs      return 0;
467279527Sbapt    else
468274880Sbapt      tail->used += n * sizeof(char);
469279527Sbapt  }
470279527Sbapt  return 1;
471279527Sbapt}
472279527Sbapt
473279527Sbapt/*
474279527Sbapt *  writeNbytes - Write n bytes to stdout.
475279527Sbapt */
476279527Sbapt
477279527Sbaptstatic void writeNbytes(const char *s, int l)
478279527Sbapt{
479279527Sbapt  int n = 0;
480279527Sbapt  int r;
481279527Sbapt
482279527Sbapt  while (n < l) {
483279527Sbapt    r = write(stdoutfd, s, l - n);
484279527Sbapt    if (r < 0)
485261344Suqs      sys_fatal("write");
486274880Sbapt    n += r;
487279527Sbapt    s += r;
488279527Sbapt  }
489279527Sbapt}
490279527Sbapt
491279527Sbapt/*
492279527Sbapt *  writeString - Write a string to stdout.
493279527Sbapt */
494279527Sbapt
495279527Sbaptstatic void writeString(const char *s)
496279527Sbapt{
497279527Sbapt  writeNbytes(s, strlen(s));
498279527Sbapt}
499279527Sbapt
500279527Sbapt/*
501279527Sbapt *  makeFileName - Create the image filename template
502279527Sbapt *                 and the macroset image template.
503279527Sbapt */
504279527Sbapt
505241675Suqsstatic void makeFileName(void)
506279527Sbapt{
507279527Sbapt  if ((image_dir != NULL) && (strchr(image_dir, '%') != NULL)) {
508241675Suqs    error("cannot use a `%%' within the image directory name");
509279527Sbapt    exit(1);
510279527Sbapt  }
511279527Sbapt
512279527Sbapt  if ((image_template != NULL) && (strchr(image_template, '%') != NULL)) {
513279527Sbapt    error("cannot use a `%%' within the image template");
514241675Suqs    exit(1);
515279527Sbapt  }
516279527Sbapt
517279527Sbapt  if (image_dir == NULL)
518279527Sbapt    image_dir = (char *)"";
519279527Sbapt  else if (strlen(image_dir) > 0
520279527Sbapt	   && image_dir[strlen(image_dir) - 1] != '/') {
521241675Suqs    image_dir = make_message("%s/", image_dir);
522279527Sbapt    if (image_dir == NULL)
523279527Sbapt      sys_fatal("make_message");
524279527Sbapt  }
525279527Sbapt
526279527Sbapt  if (image_template == NULL)
527279527Sbapt    macroset_template = make_message("%sgrohtml-%d", image_dir,
528279527Sbapt				     (int)getpid());
529279527Sbapt  else
530279527Sbapt    macroset_template = make_message("%s%s", image_dir, image_template);
531279527Sbapt
532261344Suqs  if (macroset_template == NULL)
533279527Sbapt    sys_fatal("make_message");
534279527Sbapt
535279527Sbapt  image_template =
536279527Sbapt    (char *)malloc(strlen("-%d") + strlen(macroset_template) + 1);
537279527Sbapt  if (image_template == NULL)
538279527Sbapt    sys_fatal("malloc");
539279527Sbapt  strcpy(image_template, macroset_template);
540279527Sbapt  strcat(image_template, "-%d");
541279527Sbapt}
542279527Sbapt
543279527Sbapt/*
544279527Sbapt *  setupAntiAlias - Set up the antialias string, used when we call gs.
545279527Sbapt */
546279527Sbapt
547279527Sbaptstatic void setupAntiAlias(void)
548279527Sbapt{
549279527Sbapt  if (textAlphaBits == 0 && graphicAlphaBits == 0)
550279527Sbapt    antiAlias = make_message(" ");
551279527Sbapt  else if (textAlphaBits == 0)
552279527Sbapt    antiAlias = make_message("-dGraphicsAlphaBits=%d ", graphicAlphaBits);
553279527Sbapt  else if (graphicAlphaBits == 0)
554279527Sbapt    antiAlias = make_message("-dTextAlphaBits=%d ", textAlphaBits);
555279527Sbapt  else
556279527Sbapt    antiAlias = make_message("-dTextAlphaBits=%d -dGraphicsAlphaBits=%d ",
557261344Suqs			     textAlphaBits, graphicAlphaBits);
558241675Suqs}
559279527Sbapt
560279527Sbapt/*
561279527Sbapt *  checkImageDir - Check whether the image directory is available.
562279527Sbapt */
563279527Sbapt
564241675Suqsstatic void checkImageDir(void)
565241675Suqs{
566241675Suqs  if (image_dir != NULL && strcmp(image_dir, "") != 0)
567279527Sbapt    if (!(mkdir(image_dir, 0777) == 0 || errno == EEXIST)) {
568261344Suqs      error("cannot create directory `%1'", image_dir);
569279527Sbapt      exit(1);
570279527Sbapt    }
571279527Sbapt}
572279527Sbapt
573279527Sbapt/*
574279527Sbapt *  write_end_image - End the image.  Write out the image extents if we
575279527Sbapt *                    are using -Tps.
576279527Sbapt */
577279527Sbapt
578279527Sbaptstatic void write_end_image(int is_html)
579279527Sbapt{
580279527Sbapt  /*
581279527Sbapt   *  if we are producing html then these
582279527Sbapt   *    emit image name and enable output
583279527Sbapt   *  else
584279527Sbapt   *    we are producing images
585279527Sbapt   *    in which case these generate image
586279527Sbapt   *    boundaries
587279527Sbapt   */
588279527Sbapt  writeString("\\O[4]\\O[2]");
589279527Sbapt  if (is_html)
590279527Sbapt    writeString("\\O[1]");
591279527Sbapt  else
592279527Sbapt    writeString("\\O[0]");
593279527Sbapt}
594279527Sbapt
595279527Sbapt/*
596241675Suqs *  write_start_image - Write troff code which will:
597241675Suqs *
598279527Sbapt *                      (i)  disable html output for the following image
599279527Sbapt *                      (ii) reset the max/min x/y registers during postscript
600279527Sbapt *                           rendering.
601279527Sbapt */
602241675Suqs
603279527Sbaptstatic void write_start_image(IMAGE_ALIGNMENT pos, int is_html)
604279527Sbapt{
605241675Suqs  writeString("\\O[5");
606279527Sbapt  switch (pos) {
607279527Sbapt  case INLINE:
608279527Sbapt    writeString("i");
609279527Sbapt    break;
610279527Sbapt  case LEFT:
611279527Sbapt    writeString("l");
612279527Sbapt    break;
613279527Sbapt  case RIGHT:
614279527Sbapt    writeString("r");
615279527Sbapt    break;
616279527Sbapt  case CENTERED:
617275432Sbapt  default:
618279527Sbapt    writeString("c");
619279527Sbapt    break;
620279527Sbapt  }
621279527Sbapt  writeString(image_template);
622241675Suqs  writeString(".png]");
623279527Sbapt  if (is_html)
624279527Sbapt    writeString("\\O[0]\\O[3]");
625279527Sbapt  else
626279527Sbapt    // reset min/max registers
627279527Sbapt    writeString("\\O[1]\\O[3]");
628279527Sbapt}
629279527Sbapt
630279527Sbapt/*
631279527Sbapt *  write_upto_newline - Write the contents of the buffer until a newline
632279527Sbapt *                       is seen.  Check for HTML_IMAGE_INLINE_BEGIN and
633279527Sbapt *                       HTML_IMAGE_INLINE_END; process them if they are
634279527Sbapt *                       present.
635241675Suqs */
636279527Sbapt
637279527Sbaptvoid char_buffer::write_upto_newline(char_block **t, int *i, int is_html)
638274880Sbapt{
639279527Sbapt  int j = *i;
640279527Sbapt
641279527Sbapt  if (*t) {
642279527Sbapt    while (j < (*t)->used
643279527Sbapt	   && (*t)->buffer[j] != '\n'
644279527Sbapt	   && (*t)->buffer[j] != INLINE_LEADER_CHAR)
645279527Sbapt      j++;
646241675Suqs    if (j < (*t)->used
647279527Sbapt	&& (*t)->buffer[j] == '\n')
648279527Sbapt      j++;
649279527Sbapt    writeNbytes((*t)->buffer + (*i), j - (*i));
650279527Sbapt    if ((*t)->buffer[j] == INLINE_LEADER_CHAR) {
651279527Sbapt      if (can_see(t, &j, HTML_IMAGE_INLINE_BEGIN))
652279527Sbapt	write_start_image(INLINE, is_html);
653279527Sbapt      else if (can_see(t, &j, HTML_IMAGE_INLINE_END))
654279527Sbapt	write_end_image(is_html);
655279527Sbapt      else {
656279527Sbapt	if (j < (*t)->used) {
657279527Sbapt	  *i = j;
658279527Sbapt	  j++;
659279527Sbapt	  writeNbytes((*t)->buffer + (*i), j - (*i));
660279527Sbapt	}
661279527Sbapt      }
662279527Sbapt    }
663279527Sbapt    if (j == (*t)->used) {
664279527Sbapt      *i = 0;
665279527Sbapt      *t = (*t)->next;
666241675Suqs      if (*t && (*t)->buffer[j - 1] != '\n')
667279527Sbapt	write_upto_newline(t, i, is_html);
668279527Sbapt    }
669279527Sbapt    else
670279527Sbapt      // newline was seen
671279527Sbapt      *i = j;
672279527Sbapt  }
673279527Sbapt}
674241675Suqs
675279527Sbapt/*
676279527Sbapt *  can_see - Return TRUE if we can see string in t->buffer[i] onwards.
677279527Sbapt */
678279527Sbapt
679279527Sbaptint char_buffer::can_see(char_block **t, int *i, const char *str)
680279527Sbapt{
681279527Sbapt  int j = 0;
682279527Sbapt  int l = strlen(str);
683279527Sbapt  int k = *i;
684279527Sbapt  char_block *s = *t;
685279527Sbapt
686279527Sbapt  while (s) {
687279527Sbapt    while (k < s->used && j < l && s->buffer[k] == str[j]) {
688279527Sbapt      j++;
689279527Sbapt      k++;
690279527Sbapt    }
691279527Sbapt    if (j == l) {
692279527Sbapt      *i = k;
693241675Suqs      *t = s;
694241675Suqs      return TRUE;
695241675Suqs    }
696241675Suqs    else if (k < s->used && s->buffer[k] != str[j])
697274880Sbapt      return( FALSE );
698261344Suqs    s = s->next;
699261344Suqs    k = 0;
700261344Suqs  }
701261344Suqs  return FALSE;
702261344Suqs}
703274880Sbapt
704274880Sbapt/*
705274880Sbapt *  skip_spaces - Return TRUE if we have not run out of data.
706261344Suqs *                Consume spaces also.
707274880Sbapt */
708274880Sbapt
709261344Suqsint char_buffer::skip_spaces(char_block **t, int *i)
710274880Sbapt{
711274880Sbapt  char_block *s = *t;
712274880Sbapt  int k = *i;
713261344Suqs
714261344Suqs  while (s) {
715274880Sbapt    while (k < s->used && isspace(s->buffer[k]))
716261344Suqs      k++;
717261344Suqs    if (k == s->used) {
718261344Suqs      k = 0;
719261344Suqs      s = s->next;
720274880Sbapt    }
721261344Suqs    else {
722274880Sbapt      *i = k;
723274880Sbapt      return TRUE;
724274880Sbapt    }
725274880Sbapt  }
726274880Sbapt  return FALSE;
727261344Suqs}
728261344Suqs
729261344Suqs/*
730241675Suqs *  skip_until_newline - Skip all characters until a newline is seen.
731241675Suqs *                       The newline is not consumed.
732241675Suqs */
733241675Suqs
734241675Suqsvoid char_buffer::skip_until_newline(char_block **t, int *i)
735241675Suqs{
736241675Suqs  int j = *i;
737241675Suqs
738241675Suqs  if (*t) {
739261344Suqs    while (j < (*t)->used && (*t)->buffer[j] != '\n')
740261344Suqs      j++;
741261344Suqs    if (j == (*t)->used) {
742274880Sbapt      *i = 0;
743294113Sbapt      *t = (*t)->next;
744294113Sbapt      skip_until_newline(t, i);
745241675Suqs    }
746241675Suqs    else
747241675Suqs      // newline was seen
748241675Suqs      *i = j;
749241675Suqs  }
750241675Suqs}
751241675Suqs
752241675Suqs#define DEVICE_FORMAT(filter) (filter == HTML_OUTPUT_FILTER)
753241675Suqs#define HTML_OUTPUT_FILTER     0
754241675Suqs#define IMAGE_OUTPUT_FILTER    1
755241675Suqs#define OUTPUT_STREAM(name)   creat((name), S_IWUSR | S_IRUSR)
756241675Suqs#define PS_OUTPUT_STREAM      OUTPUT_STREAM(psFileName)
757241675Suqs#define REGION_OUTPUT_STREAM  OUTPUT_STREAM(regionFileName)
758241675Suqs
759241675Suqs/*
760241675Suqs *  emit_troff_output - Write formatted buffer content to the troff
761241675Suqs *                      post-processor data pipeline.
762241675Suqs */
763241675Suqs
764241675Suqsvoid char_buffer::emit_troff_output(int device_format_selector)
765241675Suqs{
766241675Suqs  // Handle output for BOTH html and image device formats
767241675Suqs  // if `device_format_selector' is passed as
768241675Suqs  //
769241675Suqs  //   HTML_FORMAT(HTML_OUTPUT_FILTER)
770241675Suqs  //     Buffer data is written to the output stream
771241675Suqs  //     with template image names translated to actual image names.
772241675Suqs  //
773241675Suqs  //   HTML_FORMAT(IMAGE_OUTPUT_FILTER)
774241675Suqs  //     Buffer data is written to the output stream
775241675Suqs  //     with no translation, for image file creation in the post-processor.
776241675Suqs
777241675Suqs  int idx = 0;
778241675Suqs  char_block *element = head;
779241675Suqs
780241675Suqs  while (element != NULL)
781241675Suqs    write_upto_newline(&element, &idx, device_format_selector);
782241675Suqs
783241675Suqs#if 0
784294113Sbapt  if (close(stdoutfd) < 0)
785241675Suqs    sys_fatal ("close");
786241675Suqs
787241675Suqs  // now we grab fd=1 so that the next pipe cannot use fd=1
788241675Suqs  if (stdoutfd == 1) {
789294113Sbapt    if (dup(2) != stdoutfd)
790241675Suqs      sys_fatal ("dup failed to use fd=1");
791241675Suqs  }
792294113Sbapt#endif /* 0 */
793241675Suqs}
794294113Sbapt
795241675Suqs/*
796241675Suqs *  The image class remembers the position of all images in the
797294113Sbapt *  postscript file and assigns names for each image.
798294113Sbapt */
799241675Suqs
800241675Suqsstruct imageItem {
801241675Suqs  imageItem *next;
802241675Suqs  int X1;
803241675Suqs  int Y1;
804241675Suqs  int X2;
805241675Suqs  int Y2;
806241675Suqs  char *imageName;
807241675Suqs  int resolution;
808241675Suqs  int maxx;
809274880Sbapt  int pageNo;
810241675Suqs
811241675Suqs  imageItem(int x1, int y1, int x2, int y2,
812241675Suqs	    int page, int res, int max_width, char *name);
813241675Suqs  ~imageItem();
814241675Suqs};
815241675Suqs
816241675Suqs/*
817241675Suqs *  imageItem - Constructor.
818241675Suqs */
819241675Suqs
820241675SuqsimageItem::imageItem(int x1, int y1, int x2, int y2,
821241675Suqs		     int page, int res, int max_width, char *name)
822241675Suqs{
823241675Suqs  X1 = x1;
824241675Suqs  Y1 = y1;
825241675Suqs  X2 = x2;
826241675Suqs  Y2 = y2;
827241675Suqs  pageNo = page;
828241675Suqs  resolution = res;
829241675Suqs  maxx = max_width;
830241675Suqs  imageName = name;
831241675Suqs  next = NULL;
832241675Suqs}
833241675Suqs
834274880Sbapt/*
835241675Suqs *  imageItem - Destructor.
836241675Suqs */
837241675Suqs
838241675SuqsimageItem::~imageItem()
839294113Sbapt{
840294113Sbapt  if (imageName)
841241675Suqs    free(imageName);
842241675Suqs}
843241675Suqs
844261344Suqs/*
845241675Suqs *  imageList - A class containing a list of imageItems.
846241675Suqs */
847241675Suqs
848261344Suqsclass imageList {
849261344Suqsprivate:
850261344Suqs  imageItem *head;
851241675Suqs  imageItem *tail;
852241675Suqs  int count;
853241675Suqspublic:
854241675Suqs  imageList();
855241675Suqs  ~imageList();
856241675Suqs  void add(int x1, int y1, int x2, int y2,
857241675Suqs	   int page, int res, int maxx, char *name);
858241675Suqs  void createImages(void);
859241675Suqs  int createPage(int pageno);
860241675Suqs  void createImage(imageItem *i);
861241675Suqs  int getMaxX(int pageno);
862241675Suqs};
863274880Sbapt
864274880Sbapt/*
865274880Sbapt *  imageList - Constructor.
866274880Sbapt */
867274880Sbapt
868274880SbaptimageList::imageList()
869274880Sbapt: head(0), tail(0), count(0)
870274880Sbapt{
871241675Suqs}
872241675Suqs
873241675Suqs/*
874241675Suqs *  imageList - Destructor.
875241675Suqs */
876241675Suqs
877241675SuqsimageList::~imageList()
878241675Suqs{
879241675Suqs  while (head != NULL) {
880241675Suqs    imageItem *i = head;
881241675Suqs    head = head->next;
882241675Suqs    delete i;
883241675Suqs  }
884241675Suqs}
885241675Suqs
886241675Suqs/*
887275432Sbapt *  createPage - Create one image of, page pageno, from the postscript file.
888261344Suqs */
889241675Suqs
890241675Suqsint imageList::createPage(int pageno)
891241675Suqs{
892241675Suqs  char *s;
893241675Suqs
894241675Suqs  if (currentPageNo == pageno)
895241675Suqs    return 0;
896241675Suqs
897241675Suqs  if (currentPageNo >= 1) {
898241675Suqs    /*
899241675Suqs     *  We need to unlink the files which change each time a new page is
900294113Sbapt     *  processed.  The final unlink is done by xtmpfile when pre-grohtml
901241675Suqs     *  exits.
902241675Suqs     */
903241675Suqs    unlink(imagePageName);
904241675Suqs    unlink(psPageName);
905241675Suqs  }
906274880Sbapt
907275432Sbapt  if (show_progress) {
908241675Suqs    fprintf(stderr, "[%d] ", pageno);
909274880Sbapt    fflush(stderr);
910241675Suqs  }
911241675Suqs
912294113Sbapt#if defined(DEBUGGING)
913241675Suqs  if (debug)
914241675Suqs    fprintf(stderr, "creating page %d\n", pageno);
915294113Sbapt#endif
916294113Sbapt
917294113Sbapt  s = make_message("psselect -q -p%d %s %s\n",
918294113Sbapt		   pageno, psFileName, psPageName);
919294113Sbapt
920294113Sbapt  if (s == NULL)
921294113Sbapt    sys_fatal("make_message");
922294113Sbapt#if defined(DEBUGGING)
923294113Sbapt  if (debug) {
924294113Sbapt    fwrite(s, sizeof(char), strlen(s), stderr);
925294113Sbapt    fflush(stderr);
926294113Sbapt  }
927294113Sbapt#endif
928294113Sbapt  html_system(s, 1);
929294113Sbapt
930294113Sbapt  s = make_message("echo showpage | "
931294113Sbapt		   "%s%s -q -dBATCH -dSAFER "
932294113Sbapt		   "-dDEVICEHEIGHTPOINTS=792 "
933294113Sbapt		   "-dDEVICEWIDTHPOINTS=%d -dFIXEDMEDIA=true "
934294113Sbapt		   "-sDEVICE=%s -r%d %s "
935294113Sbapt		   "-sOutputFile=%s %s -\n",
936294113Sbapt		   image_gen,
937294113Sbapt		   EXE_EXT,
938294113Sbapt		   (getMaxX(pageno) * image_res) / postscriptRes,
939294113Sbapt		   image_device,
940294113Sbapt		   image_res,
941294113Sbapt		   antiAlias,
942294113Sbapt		   imagePageName,
943294113Sbapt		   psPageName);
944294113Sbapt  if (s == NULL)
945294113Sbapt    sys_fatal("make_message");
946294113Sbapt#if defined(DEBUGGING)
947294113Sbapt  if (debug) {
948294113Sbapt    fwrite(s, sizeof(char), strlen(s), stderr);
949294113Sbapt    fflush(stderr);
950294113Sbapt  }
951294113Sbapt#endif
952294113Sbapt  html_system(s, 1);
953294113Sbapt  free(s);
954294113Sbapt  currentPageNo = pageno;
955294113Sbapt  return 0;
956294113Sbapt}
957294113Sbapt
958294113Sbapt/*
959294113Sbapt *  min - Return the minimum of two numbers.
960294113Sbapt */
961294113Sbapt
962294113Sbaptint min(int x, int y)
963294113Sbapt{
964294113Sbapt  if (x < y)
965294113Sbapt    return x;
966294113Sbapt  else
967294113Sbapt    return y;
968294113Sbapt}
969294113Sbapt
970294113Sbapt/*
971294113Sbapt *  max - Return the maximum of two numbers.
972294113Sbapt */
973294113Sbapt
974294113Sbaptint max(int x, int y)
975294113Sbapt{
976294113Sbapt  if (x > y)
977294113Sbapt    return x;
978294113Sbapt  else
979294113Sbapt    return y;
980294113Sbapt}
981294113Sbapt
982294113Sbapt/*
983294113Sbapt *  getMaxX - Return the largest right-hand position for any image
984294113Sbapt *            on, pageno.
985294113Sbapt */
986294113Sbapt
987294113Sbaptint imageList::getMaxX(int pageno)
988294113Sbapt{
989294113Sbapt  imageItem *h = head;
990294113Sbapt  int x = postscriptRes * DEFAULT_LINE_LENGTH;
991294113Sbapt
992294113Sbapt  while (h != NULL) {
993294113Sbapt    if (h->pageNo == pageno)
994294113Sbapt      x = max(h->X2, x);
995294113Sbapt    h = h->next;
996294113Sbapt  }
997294113Sbapt  return x;
998294113Sbapt}
999294113Sbapt
1000294113Sbapt/*
1001294113Sbapt *  createImage - Generate a minimal png file from the set of page images.
1002294113Sbapt */
1003294113Sbapt
1004294113Sbaptvoid imageList::createImage(imageItem *i)
1005294113Sbapt{
1006294113Sbapt  if (i->X1 != -1) {
1007294113Sbapt    char *s;
1008294113Sbapt    int x1 = max(min(i->X1, i->X2) * image_res / postscriptRes
1009294113Sbapt		   - IMAGE_BOARDER_PIXELS,
1010294113Sbapt		 0);
1011294113Sbapt    int y1 = max(image_res * vertical_offset / 72
1012294113Sbapt		   + min(i->Y1, i->Y2) * image_res / postscriptRes
1013294113Sbapt		   - IMAGE_BOARDER_PIXELS,
1014294113Sbapt		 0);
1015294113Sbapt    int x2 = max(i->X1, i->X2) * image_res / postscriptRes
1016294113Sbapt	     + IMAGE_BOARDER_PIXELS;
1017294113Sbapt    int y2 = image_res * vertical_offset / 72
1018294113Sbapt	     + max(i->Y1, i->Y2) * image_res / postscriptRes
1019294113Sbapt	     + 1 + IMAGE_BOARDER_PIXELS;
1020294113Sbapt    if (createPage(i->pageNo) == 0) {
1021294113Sbapt      s = make_message("pnmcut%s %d %d %d %d < %s "
1022294113Sbapt		       "| pnmcrop -quiet | pnmtopng%s %s > %s\n",
1023294113Sbapt		       EXE_EXT,
1024294113Sbapt		       x1, y1, x2 - x1 + 1, y2 - y1 + 1,
1025294113Sbapt		       imagePageName,
1026294113Sbapt		       EXE_EXT,
1027294113Sbapt		       TRANSPARENT,
1028294113Sbapt		       i->imageName);
1029294113Sbapt      if (s == NULL)
1030294113Sbapt	sys_fatal("make_message");
1031294113Sbapt
1032294113Sbapt#if defined(DEBUGGING)
1033294113Sbapt      if (debug) {
1034294113Sbapt	fprintf(stderr, s);
1035294113Sbapt	fflush(stderr);
1036294113Sbapt      }
1037294113Sbapt#endif
1038294113Sbapt      html_system(s, 0);
1039294113Sbapt      free(s);
1040294113Sbapt    }
1041294113Sbapt    else {
1042294113Sbapt      fprintf(stderr, "failed to generate image of page %d\n", i->pageNo);
1043294113Sbapt      fflush(stderr);
1044294113Sbapt    }
1045294113Sbapt#if defined(DEBUGGING)
1046294113Sbapt  }
1047294113Sbapt  else {
1048294113Sbapt    if (debug) {
1049294113Sbapt      fprintf(stderr, "ignoring image as x1 coord is -1\n");
1050294113Sbapt      fflush(stderr);
1051294113Sbapt    }
1052294113Sbapt#endif
1053294113Sbapt  }
1054294113Sbapt}
1055294113Sbapt
1056294113Sbapt/*
1057294113Sbapt *  add - Add an image description to the imageList.
1058294113Sbapt */
1059294113Sbapt
1060294113Sbaptvoid imageList::add(int x1, int y1, int x2, int y2,
1061294113Sbapt		    int page, int res, int maxx, char *name)
1062294113Sbapt{
1063294113Sbapt  imageItem *i = new imageItem(x1, y1, x2, y2, page, res, maxx, name);
1064294113Sbapt
1065294113Sbapt  if (head == NULL) {
1066294113Sbapt    head = i;
1067294113Sbapt    tail = i;
1068294113Sbapt  }
1069294113Sbapt  else {
1070294113Sbapt    tail->next = i;
1071294113Sbapt    tail = i;
1072294113Sbapt  }
1073294113Sbapt}
1074294113Sbapt
1075294113Sbapt/*
1076294113Sbapt *  createImages - For each image descriptor on the imageList,
1077294113Sbapt *                 create the actual image.
1078294113Sbapt */
1079294113Sbapt
1080294113Sbaptvoid imageList::createImages(void)
1081294113Sbapt{
1082294113Sbapt  imageItem *h = head;
1083294113Sbapt
1084294113Sbapt  while (h != NULL) {
1085294113Sbapt    createImage(h);
1086294113Sbapt    h = h->next;
1087294113Sbapt  }
1088294113Sbapt}
1089294113Sbapt
1090294113Sbaptstatic imageList listOfImages;	// List of images defined by the region file.
1091294113Sbapt
1092294113Sbapt/*
1093294113Sbapt *  generateImages - Parse the region file and generate images
1094294113Sbapt *                   from the postscript file.  The region file
1095294113Sbapt *                   contains the x1,y1--x2,y2 extents of each
1096294113Sbapt *                   image.
1097294113Sbapt */
1098294113Sbapt
1099294113Sbaptstatic void generateImages(char *region_file_name)
1100294113Sbapt{
1101294113Sbapt  pushBackBuffer *f=new pushBackBuffer(region_file_name);
1102294113Sbapt
1103294113Sbapt  while (f->putPB(f->getPB()) != eof) {
1104294113Sbapt    if (f->isString("grohtml-info:page")) {
1105294113Sbapt      int page = f->readInt();
1106294113Sbapt      int x1 = f->readInt();
1107294113Sbapt      int y1 = f->readInt();
1108294113Sbapt      int x2 = f->readInt();
1109294113Sbapt      int y2 = f->readInt();
1110294113Sbapt      int maxx = f->readInt();
1111294113Sbapt      char *name = f->readString();
1112294113Sbapt      int res = postscriptRes;
1113294113Sbapt      listOfImages.add(x1, y1, x2, y2, page, res, maxx, name);
1114294113Sbapt      while (f->putPB(f->getPB()) != '\n'
1115294113Sbapt	     && f->putPB(f->getPB()) != eof)
1116294113Sbapt	(void)f->getPB();
1117294113Sbapt      if (f->putPB(f->getPB()) == '\n')
1118294113Sbapt	(void)f->getPB();
1119294113Sbapt    }
1120294113Sbapt    else {
1121294113Sbapt      /* Write any error messages out to the user. */
1122294113Sbapt      fputc(f->getPB(), stderr);
1123294113Sbapt    }
1124294113Sbapt  }
1125294113Sbapt
1126294113Sbapt  listOfImages.createImages();
1127294113Sbapt  if (show_progress) {
1128294113Sbapt    fprintf(stderr, "done\n");
1129294113Sbapt    fflush(stderr);
1130294113Sbapt  }
1131294113Sbapt  delete f;
1132294113Sbapt}
1133294113Sbapt
1134294113Sbapt/*
1135294113Sbapt *  set_redirection - Set up I/O Redirection for handle, was, to refer to
1136294113Sbapt *                    stream on handle, willbe.
1137294113Sbapt */
1138294113Sbapt
1139294113Sbaptstatic void set_redirection(int was, int willbe)
1140294113Sbapt{
1141294113Sbapt  // Nothing to do if `was' and `willbe' already have same handle.
1142294113Sbapt  if (was != willbe) {
1143294113Sbapt    // Otherwise attempt the specified redirection.
1144294113Sbapt    if (dup2 (willbe, was) < 0) {
1145294113Sbapt      // Redirection failed, so issue diagnostic and bail out.
1146294113Sbapt      fprintf(stderr, "failed to replace fd=%d with %d\n", was, willbe);
1147294113Sbapt      if (willbe == STDOUT_FILENO)
1148294113Sbapt	fprintf(stderr,
1149294113Sbapt		"likely that stdout should be opened before %d\n", was);
1150294113Sbapt      sys_fatal("dup2");
1151294113Sbapt    }
1152294113Sbapt
1153294113Sbapt    // When redirection has been successfully completed assume redundant
1154294113Sbapt    // handle `willbe' is no longer required, so close it.
1155294113Sbapt    if (close(willbe) < 0)
1156294113Sbapt      // Issue diagnostic if `close' fails.
1157294113Sbapt      sys_fatal("close");
1158294113Sbapt  }
1159294113Sbapt}
1160294113Sbapt
1161294113Sbapt/*
1162294113Sbapt *  save_and_redirect - Get duplicate handle for stream, was, then
1163294113Sbapt *                      redirect, was, to refer to, willbe.
1164294113Sbapt */
1165294113Sbapt
1166294113Sbaptstatic int save_and_redirect(int was, int willbe)
1167294113Sbapt{
1168294113Sbapt  if (was == willbe)
1169294113Sbapt    // No redirection specified so don't do anything but silently bailing out.
1170294113Sbapt    return (was);
1171294113Sbapt
1172294113Sbapt  // Proceeding with redirection so first save and verify our duplicate
1173294113Sbapt  // handle for `was'.
1174294113Sbapt  int saved = dup(was);
1175294113Sbapt  if (saved < 0) {
1176294113Sbapt    fprintf(stderr, "unable to get duplicate handle for %d\n", was);
1177294113Sbapt    sys_fatal("dup");
1178294113Sbapt  }
1179294113Sbapt
1180294113Sbapt  // Duplicate handle safely established so complete redirection.
1181294113Sbapt  set_redirection(was, willbe);
1182294113Sbapt
1183294113Sbapt  // Finally return the saved duplicate descriptor for the
1184294113Sbapt  // original `was' stream.
1185294113Sbapt  return saved;
1186294113Sbapt}
1187294113Sbapt
1188294113Sbapt/*
1189294113Sbapt *  alterDeviceTo - If, toImage, is set
1190294113Sbapt *                     the argument list is altered to include
1191294113Sbapt *                     IMAGE_DEVICE and we invoke groff rather than troff.
1192294113Sbapt *                  Else
1193294113Sbapt *                     set -Thtml and groff.
1194294113Sbapt */
1195294113Sbapt
1196294113Sbaptstatic void alterDeviceTo(int argc, char *argv[], int toImage)
1197294113Sbapt{
1198294113Sbapt  int i = 0;
1199294113Sbapt
1200294113Sbapt  if (toImage) {
1201294113Sbapt    while (i < argc) {
1202294113Sbapt      if (strcmp(argv[i], "-Thtml") == 0)
1203294113Sbapt	argv[i] = (char *)IMAGE_DEVICE;
1204294113Sbapt      i++;
1205294113Sbapt    }
1206294113Sbapt    argv[troff_arg] = (char *)"groff";	/* rather than troff */
1207294113Sbapt  }
1208294113Sbapt  else {
1209294113Sbapt    while (i < argc) {
1210294113Sbapt      if (strcmp(argv[i], IMAGE_DEVICE) == 0)
1211294113Sbapt	argv[i] = (char *)"-Thtml";
1212294113Sbapt      i++;
1213294113Sbapt    }
1214294113Sbapt    argv[troff_arg] = (char *)"groff";	/* use groff -Z */
1215294113Sbapt  }
1216294113Sbapt}
1217294113Sbapt
1218294113Sbapt/*
1219294113Sbapt *  addZ - Append -Z onto the command list for groff.
1220294113Sbapt */
1221294113Sbapt
1222294113Sbaptchar **addZ(int argc, char *argv[])
1223294113Sbapt{
1224294113Sbapt  char **new_argv = (char **)malloc((argc + 2) * sizeof(char *));
1225294113Sbapt  int i = 0;
1226294113Sbapt
1227294113Sbapt  if (new_argv == NULL)
1228294113Sbapt    sys_fatal("malloc");
1229294113Sbapt
1230294113Sbapt  if (argc > 0) {
1231294113Sbapt    new_argv[i] = argv[i];
1232294113Sbapt    i++;
1233294113Sbapt  }
1234294113Sbapt  new_argv[i] = (char *)"-Z";
1235294113Sbapt  while (i < argc) {
1236294113Sbapt    new_argv[i + 1] = argv[i];
1237294113Sbapt    i++;
1238294113Sbapt  }
1239294113Sbapt  argc++;
1240294113Sbapt  new_argv[argc] = NULL;
1241294113Sbapt  return new_argv;
1242294113Sbapt}
1243294113Sbapt
1244294113Sbapt/*
1245294113Sbapt *  addRegDef - Append a defined register or string onto the command
1246294113Sbapt *              list for troff.
1247294113Sbapt */
1248294113Sbapt
1249294113Sbaptchar **addRegDef(int argc, char *argv[], const char *numReg)
1250294113Sbapt{
1251294113Sbapt  char **new_argv = (char **)malloc((argc + 2) * sizeof(char *));
1252294113Sbapt  int i = 0;
1253294113Sbapt
1254294113Sbapt  if (new_argv == NULL)
1255294113Sbapt    sys_fatal("malloc");
1256294113Sbapt
1257294113Sbapt  while (i < argc) {
1258294113Sbapt    new_argv[i] = argv[i];
1259294113Sbapt    i++;
1260294113Sbapt  }
1261294113Sbapt  new_argv[argc] = strsave(numReg);
1262294113Sbapt  argc++;
1263294113Sbapt  new_argv[argc] = NULL;
1264241675Suqs  return new_argv;
1265274880Sbapt}
1266274880Sbapt
1267274880Sbapt/*
1268241675Suqs *  dump_args - Display the argument list.
1269241675Suqs */
1270275432Sbapt
1271241675Suqsvoid dump_args(int argc, char *argv[])
1272274880Sbapt{
1273274880Sbapt  fprintf(stderr, "  %d arguments:", argc);
1274274880Sbapt  for (int i = 0; i < argc; i++)
1275241675Suqs    fprintf(stderr, " %s", argv[i]);
1276241675Suqs  fprintf(stderr, "\n");
1277241675Suqs}
1278275432Sbapt
1279261344Suqsint char_buffer::run_output_filter(int filter, int /* argc */, char **argv)
1280261344Suqs{
1281275432Sbapt  int pipedes[2];
1282275432Sbapt  PID_T child_pid;
1283261344Suqs  int status;
1284274880Sbapt
1285274880Sbapt  if (pipe(pipedes) < 0)
1286274880Sbapt    sys_fatal("pipe");
1287241675Suqs
1288241675Suqs#if MAY_FORK_CHILD_PROCESS
1289275432Sbapt  // This is the UNIX process model.  To invoke our post-processor,
1290274880Sbapt  // we must `fork' the current process.
1291274880Sbapt
1292241675Suqs  if ((child_pid = fork()) < 0)
1293274880Sbapt    sys_fatal("fork");
1294241675Suqs
1295275432Sbapt  else if (child_pid == 0) {
1296274880Sbapt    // This is the child process fork.  We redirect its `stdin' stream
1297241675Suqs    // to read data emerging from our pipe.  There is no point in saving,
1298274880Sbapt    // since we won't be able to restore later!
1299241675Suqs
1300274880Sbapt    set_redirection(STDIN_FILENO, pipedes[0]);
1301275432Sbapt
1302274880Sbapt    // The parent process will be writing this data, so we should release
1303274880Sbapt    // the child's writeable handle on the pipe, since we have no use for it.
1304275432Sbapt
1305274880Sbapt    if (close(pipedes[1]) < 0)
1306274880Sbapt      sys_fatal("close");
1307274880Sbapt
1308274880Sbapt    // The IMAGE_OUTPUT_FILTER needs special output redirection...
1309274880Sbapt
1310274880Sbapt    if (filter == IMAGE_OUTPUT_FILTER) {
1311274880Sbapt      // with BOTH `stdout' AND `stderr' diverted to files.
1312274880Sbapt
1313261344Suqs      set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
1314274880Sbapt      set_redirection(STDERR_FILENO, REGION_OUTPUT_STREAM);
1315261344Suqs    }
1316261344Suqs
1317274880Sbapt    // Now we are ready to launch the output filter.
1318274880Sbapt
1319274880Sbapt    execvp(argv[0], argv);
1320274880Sbapt
1321274880Sbapt    // If we get to here then the `exec...' request for the output filter
1322261344Suqs    // failed.  Diagnose it and bail out.
1323261344Suqs
1324261344Suqs    error("couldn't exec %1: %2", argv[0], strerror(errno), ((char *)0));
1325275432Sbapt    fflush(stderr);	// just in case error() didn't
1326275432Sbapt    exit(1);
1327275432Sbapt  }
1328294113Sbapt
1329274880Sbapt  else {
1330275432Sbapt    // This is the parent process fork.  We will be writing data to the
1331274880Sbapt    // filter pipeline, and the child will be reading it.  We have no further
1332274880Sbapt    // use for our read handle on the pipe, and should close it.
1333241675Suqs
1334241675Suqs    if (close(pipedes[0]) < 0)
1335274880Sbapt      sys_fatal("close");
1336274880Sbapt
1337275432Sbapt    // Now we redirect the `stdout' stream to the inlet end of the pipe,
1338294113Sbapt    // and push out the appropiately formatted data to the filter.
1339274880Sbapt
1340241675Suqs    pipedes[1] = save_and_redirect(STDOUT_FILENO, pipedes[1]);
1341241675Suqs    emit_troff_output(DEVICE_FORMAT(filter));
1342241675Suqs
1343261344Suqs    // After emitting all the data we close our connection to the inlet
1344241675Suqs    // end of the pipe so the child process will detect end of data.
1345241675Suqs
1346241675Suqs    set_redirection(STDOUT_FILENO, pipedes[1]);
1347275432Sbapt
1348274880Sbapt    // Finally, we must wait for the child process to complete.
1349274880Sbapt
1350274880Sbapt    if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
1351274880Sbapt      sys_fatal("wait");
1352274880Sbapt  }
1353274880Sbapt
1354274880Sbapt#elif MAY_SPAWN_ASYNCHRONOUS_CHILD
1355274880Sbapt
1356274880Sbapt  // We do not have `fork', (or we prefer not to use it),
1357274880Sbapt  // but asynchronous processes are allowed, passing data through pipes.
1358274880Sbapt  // This should be ok for most Win32 systems and is preferred to `fork'
1359274880Sbapt  // for starting child processes under Cygwin.
1360274880Sbapt
1361274880Sbapt  // Before we start the post-processor we bind its inherited `stdin'
1362274880Sbapt  // stream to the readable end of our pipe, saving our own `stdin' stream
1363274880Sbapt  // in `pipedes[0]'.
1364274880Sbapt
1365274880Sbapt  pipedes[0] = save_and_redirect(STDIN_FILENO, pipedes[0]);
1366274880Sbapt
1367241675Suqs  // for the Win32 model,
1368241675Suqs  // we need special provision for saving BOTH `stdout' and `stderr'.
1369241675Suqs
1370241675Suqs  int saved_stdout = dup(STDOUT_FILENO);
1371241675Suqs  int saved_stderr = STDERR_FILENO;
1372241675Suqs
1373279527Sbapt  // The IMAGE_OUTPUT_FILTER needs special output redirection...
1374274880Sbapt
1375279527Sbapt  if (filter == IMAGE_OUTPUT_FILTER) {
1376275432Sbapt    // with BOTH `stdout' AND `stderr' diverted to files while saving a
1377274880Sbapt    // duplicate handle for `stderr'.
1378275432Sbapt
1379274880Sbapt    set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM);
1380274880Sbapt    saved_stderr = save_and_redirect(STDERR_FILENO, REGION_OUTPUT_STREAM);
1381241675Suqs  }
1382275432Sbapt
1383274880Sbapt  // We then use an asynchronous spawn request to start the post-processor.
1384241675Suqs
1385274880Sbapt  if ((child_pid = spawnvp(_P_NOWAIT, argv[0], argv)) < 0) {
1386279527Sbapt    // Should the spawn request fail we issue a diagnostic and bail out.
1387279527Sbapt
1388279527Sbapt    error("cannot spawn %1: %2", argv[0], strerror(errno), ((char *)0));
1389279527Sbapt    exit(1);
1390279527Sbapt  }
1391279527Sbapt
1392279527Sbapt  // Once the post-processor has been started we revert our `stdin'
1393279527Sbapt  // to its original saved source, which also closes the readable handle
1394279527Sbapt  // for the pipe.
1395279527Sbapt
1396279527Sbapt  set_redirection(STDIN_FILENO, pipedes[0]);
1397279527Sbapt
1398279527Sbapt  // if we redirected `stderr', for use by the image post-processor,
1399279527Sbapt  // then we also need to reinstate its original assignment.
1400241675Suqs
1401241675Suqs  if (filter == IMAGE_OUTPUT_FILTER)
1402241675Suqs    set_redirection(STDERR_FILENO, saved_stderr);
1403241675Suqs
1404241675Suqs  // Now we redirect the `stdout' stream to the inlet end of the pipe,
1405241675Suqs  // and push out the appropiately formatted data to the filter.
1406241675Suqs
1407274880Sbapt  set_redirection(STDOUT_FILENO, pipedes[1]);
1408274880Sbapt  emit_troff_output(DEVICE_FORMAT(filter));
1409274880Sbapt
1410274880Sbapt  // After emitting all the data we close our connection to the inlet
1411274880Sbapt  // end of the pipe so the child process will detect end of data.
1412274880Sbapt
1413274880Sbapt  set_redirection(STDOUT_FILENO, saved_stdout);
1414274880Sbapt
1415279527Sbapt  // And finally, we must wait for the child process to complete.
1416279527Sbapt
1417274880Sbapt  if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid)
1418274880Sbapt    sys_fatal("wait");
1419274880Sbapt
1420274880Sbapt#else /* can't do asynchronous pipes! */
1421274880Sbapt
1422274880Sbapt  // TODO: code to support an MS-DOS style process model
1423274880Sbapt  //        should go here
1424274880Sbapt
1425274880Sbapt#endif /* MAY_FORK_CHILD_PROCESS or MAY_SPAWN_ASYNCHRONOUS_CHILD */
1426274880Sbapt
1427274880Sbapt  return 0;
1428274880Sbapt}
1429274880Sbapt
1430274880Sbapt/*
1431274880Sbapt *  do_html - Set the troff number htmlflip and
1432274880Sbapt *            write out the buffer to troff -Thtml.
1433241675Suqs */
1434275432Sbapt
1435274880Sbaptint char_buffer::do_html(int argc, char *argv[])
1436275432Sbapt{
1437274880Sbapt  string s;
1438241675Suqs
1439279527Sbapt  alterDeviceTo(argc, argv, 0);
1440279527Sbapt  argv += troff_arg;		// skip all arguments up to groff
1441279527Sbapt  argc -= troff_arg;
1442294113Sbapt  argv = addZ(argc, argv);
1443241675Suqs  argc++;
1444241675Suqs
1445241675Suqs  s = "-dwww-image-template=";
1446241675Suqs  s += macroset_template;	// do not combine these statements,
1447274880Sbapt				// otherwise they will not work
1448275432Sbapt  s += '\0';                	// the trailing `\0' is ignored
1449275432Sbapt  argv = addRegDef(argc, argv, s.contents());
1450241675Suqs  argc++;
1451274880Sbapt
1452241675Suqs#if defined(DEBUGGING)
1453274880Sbapt# define HTML_DEBUG_STREAM  OUTPUT_STREAM(htmlFileName)
1454275432Sbapt  // slight security risk so only enabled if compiled with defined(DEBUGGING)
1455275432Sbapt  if (debug) {
1456275432Sbapt    int saved_stdout = save_and_redirect(STDOUT_FILENO, HTML_DEBUG_STREAM);
1457241675Suqs    emit_troff_output(DEVICE_FORMAT(HTML_OUTPUT_FILTER));
1458294113Sbapt    set_redirection(STDOUT_FILENO, saved_stdout);
1459241675Suqs  }
1460241675Suqs#endif
1461241675Suqs
1462294113Sbapt  return run_output_filter(HTML_OUTPUT_FILTER, argc, argv);
1463241675Suqs}
1464241675Suqs
1465275432Sbapt/*
1466241675Suqs *  do_image - Write out the buffer to troff -Tps.
1467241675Suqs */
1468241675Suqs
1469261344Suqsint char_buffer::do_image(int argc, char *argv[])
1470261344Suqs{
1471241675Suqs  string s;
1472241675Suqs
1473294113Sbapt  alterDeviceTo(argc, argv, 1);
1474294113Sbapt  argv += troff_arg;		// skip all arguments up to troff/groff
1475294113Sbapt  argc -= troff_arg;
1476294113Sbapt  argv = addRegDef(argc, argv, "-rps4html=1");
1477294113Sbapt  argc++;
1478294113Sbapt
1479294113Sbapt  s = "-dwww-image-template=";
1480294113Sbapt  s += macroset_template;
1481294113Sbapt  s += '\0';
1482294113Sbapt  argv = addRegDef(argc, argv, s.contents());
1483294113Sbapt  argc++;
1484294113Sbapt
1485294113Sbapt  // override local settings and produce a page size letter postscript file
1486294113Sbapt  argv = addRegDef(argc, argv, "-P-pletter");
1487294113Sbapt  argc++;
1488294113Sbapt
1489275432Sbapt#if defined(DEBUGGING)
1490241675Suqs# define IMAGE_DEBUG_STREAM  OUTPUT_STREAM(troffFileName)
1491275432Sbapt  // slight security risk so only enabled if compiled with defined(DEBUGGING)
1492241675Suqs  if (debug) {
1493241675Suqs    int saved_stdout = save_and_redirect(STDOUT_FILENO, IMAGE_DEBUG_STREAM);
1494241675Suqs    emit_troff_output(DEVICE_FORMAT(IMAGE_OUTPUT_FILTER));
1495275432Sbapt    set_redirection(STDOUT_FILENO, saved_stdout);
1496241675Suqs  }
1497241675Suqs#endif
1498275432Sbapt
1499241675Suqs  return run_output_filter(IMAGE_OUTPUT_FILTER, argc, argv);
1500241675Suqs}
1501261344Suqs
1502275432Sbaptstatic char_buffer inputFile;
1503241675Suqs
1504294113Sbapt/*
1505294113Sbapt *  usage - Emit usage arguments.
1506241675Suqs */
1507241675Suqs
1508241675Suqsstatic void usage(FILE *stream)
1509241675Suqs{
1510241675Suqs  fprintf(stream,
1511241675Suqs	  "usage: %s troffname [-Iimage_name] [-Dimage_directory]\n"
1512241675Suqs	  "       [-P-o vertical_image_offset] [-P-i image_resolution]\n"
1513241675Suqs	  "       [troff flags]\n",
1514241675Suqs	  program_name);
1515241675Suqs  fprintf(stream,
1516241675Suqs	  "    vertical_image_offset (default %d/72 of an inch)\n",
1517294113Sbapt	  vertical_offset);
1518241675Suqs  fprintf(stream,
1519241675Suqs	  "    image_resolution (default %d) pixels per inch\n",
1520241675Suqs	  image_res);
1521275432Sbapt  fprintf(stream,
1522241675Suqs	  "    image_name is the name of the stem for all images\n"
1523241675Suqs	  "    (default is grohtml-<pid>)\n");
1524241675Suqs  fprintf(stream,
1525275432Sbapt	  "    place all png files into image_directory\n");
1526279527Sbapt}
1527275432Sbapt
1528275432Sbapt/*
1529241675Suqs *  scanArguments - Scan for all arguments including -P-i, -P-o, -P-D,
1530275432Sbapt *                  and -P-I.  Return the argument index of the first
1531241675Suqs *                  non-option.
1532275432Sbapt */
1533275432Sbapt
1534275432Sbaptstatic int scanArguments(int argc, char **argv)
1535275432Sbapt{
1536275432Sbapt  const char *command_prefix = getenv("GROFF_COMMAND_PREFIX");
1537275432Sbapt  if (!command_prefix)
1538275432Sbapt    command_prefix = PROG_PREFIX;
1539294113Sbapt  char *troff_name = new char[strlen(command_prefix) + strlen("troff") + 1];
1540275432Sbapt  strcpy(troff_name, command_prefix);
1541275432Sbapt  strcat(troff_name, "troff");
1542275432Sbapt  int c, i;
1543275432Sbapt  static const struct option long_options[] = {
1544275432Sbapt    { "help", no_argument, 0, CHAR_MAX + 1 },
1545275432Sbapt    { "version", no_argument, 0, 'v' },
1546275432Sbapt    { NULL, 0, 0, 0 }
1547294113Sbapt  };
1548275432Sbapt  while ((c = getopt_long(argc, argv, "+a:bdD:F:g:hi:I:j:lno:prs:S:v",
1549241675Suqs			  long_options, NULL))
1550275432Sbapt	 != EOF)
1551241675Suqs    switch(c) {
1552241675Suqs    case 'a':
1553241675Suqs      textAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)),
1554279527Sbapt			  MAX_ALPHA_BITS);
1555279527Sbapt      if (textAlphaBits == 3) {
1556279527Sbapt	error("cannot use 3 bits of antialiasing information");
1557279527Sbapt	exit(1);
1558241675Suqs      }
1559241675Suqs      break;
1560279527Sbapt    case 'b':
1561241675Suqs      // handled by post-grohtml (set background color to white)
1562241675Suqs      break;
1563275432Sbapt    case 'd':
1564275432Sbapt#if defined(DEBUGGING)
1565275432Sbapt      debug = TRUE;
1566294113Sbapt#endif
1567261344Suqs      break;
1568279527Sbapt    case 'D':
1569294113Sbapt      image_dir = optarg;
1570279527Sbapt      break;
1571294113Sbapt    case 'F':
1572279527Sbapt      font_path.command_line_dir(optarg);
1573294113Sbapt      break;
1574241675Suqs    case 'g':
1575275432Sbapt      graphicAlphaBits = min(max(MIN_ALPHA_BITS, atoi(optarg)),
1576275432Sbapt			     MAX_ALPHA_BITS);
1577275432Sbapt      if (graphicAlphaBits == 3) {
1578275432Sbapt	error("cannot use 3 bits of antialiasing information");
1579275432Sbapt	exit(1);
1580294113Sbapt      }
1581275432Sbapt      break;
1582294113Sbapt    case 'h':
1583275432Sbapt      // handled by post-grohtml
1584241675Suqs      break;
1585241675Suqs    case 'i':
1586241675Suqs      image_res = atoi(optarg);
1587241675Suqs      break;
1588241675Suqs    case 'I':
1589241675Suqs      image_template = optarg;
1590241675Suqs      break;
1591241675Suqs    case 'j':
1592241675Suqs      // handled by post-grohtml (set job name for multiple file output)
1593294113Sbapt      break;
1594241675Suqs    case 'l':
1595241675Suqs      // handled by post-grohtml (no automatic section links)
1596279527Sbapt      break;
1597279527Sbapt    case 'n':
1598279527Sbapt      // handled by post-grohtml (generate simple heading anchors)
1599279527Sbapt      break;
1600279527Sbapt    case 'o':
1601279527Sbapt      vertical_offset = atoi(optarg);
1602279527Sbapt      break;
1603279527Sbapt    case 'p':
1604279527Sbapt      show_progress = TRUE;
1605279527Sbapt      break;
1606279527Sbapt    case 'r':
1607294113Sbapt      // handled by post-grohtml (no header and footer lines)
1608279527Sbapt      break;
1609279527Sbapt    case 's':
1610279527Sbapt      // handled by post-grohtml (use font size n as the html base font size)
1611279527Sbapt      break;
1612294113Sbapt    case 'S':
1613279527Sbapt      // handled by post-grohtml (set file split level)
1614279527Sbapt      break;
1615241675Suqs    case 'v':
1616279527Sbapt      printf("GNU pre-grohtml (groff) version %s\n", Version_string);
1617279527Sbapt      exit(0);
1618241675Suqs    case CHAR_MAX + 1: // --help
1619241675Suqs      usage(stdout);
1620279527Sbapt      exit(0);
1621294113Sbapt      break;
1622241675Suqs    case '?':
1623279527Sbapt      usage(stderr);
1624279527Sbapt      exit(1);
1625241675Suqs      break;
1626294113Sbapt    default:
1627241675Suqs      break;
1628241675Suqs    }
1629241675Suqs
1630241675Suqs  i = optind;
1631241675Suqs  while (i < argc) {
1632241675Suqs    if (strcmp(argv[i], troff_name) == 0)
1633241675Suqs      troff_arg = i;
1634274880Sbapt    else if (argv[i][0] != '-')
1635274880Sbapt      return i;
1636274880Sbapt    i++;
1637241675Suqs  }
1638241675Suqs  a_delete troff_name;
1639274880Sbapt
1640274880Sbapt  return argc;
1641241675Suqs}
1642241675Suqs
1643241675Suqs/*
1644241675Suqs *  makeTempFiles - Name the temporary files.
1645274880Sbapt */
1646274880Sbapt
1647241675Suqsstatic int makeTempFiles(void)
1648241675Suqs{
1649241675Suqs#if defined(DEBUGGING)
1650241675Suqs  psFileName = DEBUG_FILE("prehtml-ps");
1651241675Suqs  regionFileName = DEBUG_FILE("prehtml-region");
1652241675Suqs  imagePageName = DEBUG_FILE("prehtml-page");
1653241675Suqs  psPageName = DEBUG_FILE("prehtml-psn");
1654241675Suqs  troffFileName = DEBUG_FILE("prehtml-troff");
1655241675Suqs  htmlFileName = DEBUG_FILE("prehtml-html");
1656274880Sbapt#else /* not DEBUGGING */
1657241675Suqs  FILE *f;
1658274880Sbapt
1659241675Suqs  /* psPageName contains a single page of postscript */
1660241675Suqs  f = xtmpfile(&psPageName,
1661241675Suqs	       PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1662241675Suqs	       TRUE);
1663274880Sbapt  if (f == NULL) {
1664274880Sbapt    sys_fatal("xtmpfile");
1665274880Sbapt    return -1;
1666294113Sbapt  }
1667241675Suqs  fclose(f);
1668274880Sbapt
1669274880Sbapt  /* imagePageName contains a bitmap image of the single postscript page */
1670241675Suqs  f = xtmpfile(&imagePageName,
1671241675Suqs	       PAGE_TEMPLATE_LONG, PAGE_TEMPLATE_SHORT,
1672241675Suqs	       TRUE);
1673241675Suqs  if (f == NULL) {
1674274880Sbapt    sys_fatal("xtmpfile");
1675274880Sbapt    return -1;
1676241675Suqs  }
1677294113Sbapt  fclose(f);
1678241675Suqs
1679241675Suqs  /* psFileName contains a postscript file of the complete document */
1680294113Sbapt  f = xtmpfile(&psFileName,
1681294113Sbapt	       PS_TEMPLATE_LONG, PS_TEMPLATE_SHORT,
1682241675Suqs	       TRUE);
1683241675Suqs  if (f == NULL) {
1684241675Suqs    sys_fatal("xtmpfile");
1685241675Suqs    return -1;
1686241675Suqs  }
1687241675Suqs  fclose(f);
1688241675Suqs
1689241675Suqs  /* regionFileName contains a list of the images and their boxed coordinates */
1690241675Suqs  f = xtmpfile(&regionFileName,
1691275432Sbapt	       REGION_TEMPLATE_LONG, REGION_TEMPLATE_SHORT,
1692274880Sbapt	       TRUE);
1693274880Sbapt  if (f == NULL) {
1694294113Sbapt    sys_fatal("xtmpfile");
1695241675Suqs    return -1;
1696241675Suqs  }
1697241675Suqs  fclose(f);
1698274880Sbapt
1699274880Sbapt#endif /* not DEBUGGING */
1700274880Sbapt  return 0;
1701274880Sbapt}
1702241675Suqs
1703274880Sbaptint main(int argc, char **argv)
1704274880Sbapt{
1705241675Suqs  program_name = argv[0];
1706241675Suqs  int i;
1707274880Sbapt  int found = 0;
1708274880Sbapt  int ok = 1;
1709294113Sbapt
1710241675Suqs#ifdef CAPTURE_MODE
1711241675Suqs  FILE *dump;
1712275432Sbapt  fprintf(stderr, "%s: invoked with %d arguments ...\n", argv[0], argc);
1713274880Sbapt  for (i = 0; i < argc; i++)
1714275432Sbapt    fprintf(stderr, "%2d: %s\n", i, argv[i]);
1715241675Suqs  if ((dump = fopen(DEBUG_FILE("pre-html-data"), "wb")) != NULL) {
1716241675Suqs    while((i = fgetc(stdin)) >= 0)
1717241675Suqs      fputc(i, dump);
1718294113Sbapt    fclose(dump);
1719241675Suqs  }
1720241675Suqs  exit(1);
1721241675Suqs#endif /* CAPTURE_MODE */
1722241675Suqs  device = "html";
1723241675Suqs  if (!font::load_desc())
1724241675Suqs    fatal("cannot find devhtml/DESC exiting");
1725241675Suqs  image_gen = font::image_generator;
1726241675Suqs  if (image_gen == NULL || (strcmp(image_gen, "") == 0))
1727261344Suqs    fatal("devhtml/DESC must set the image_generator field, exiting");
1728241675Suqs  postscriptRes = get_resolution();
1729241675Suqs  i = scanArguments(argc, argv);
1730241675Suqs  setupAntiAlias();
1731241675Suqs  checkImageDir();
1732241675Suqs  makeFileName();
1733274880Sbapt  while (i < argc) {
1734274880Sbapt    if (argv[i][0] != '-') {
1735241675Suqs      /* found source file */
1736241675Suqs      ok = do_file(argv[i]);
1737241675Suqs      if (!ok)
1738274880Sbapt	return 0;
1739274880Sbapt      found = 1;
1740274880Sbapt    }
1741241675Suqs    i++;
1742241675Suqs  }
1743241675Suqs
1744274880Sbapt  if (!found)
1745274880Sbapt    do_file("-");
1746274880Sbapt  if (makeTempFiles())
1747241675Suqs    return 1;
1748241675Suqs  ok = inputFile.do_image(argc, argv);
1749274880Sbapt  if (ok == 0) {
1750274880Sbapt    generateImages(regionFileName);
1751274880Sbapt    ok = inputFile.do_html(argc, argv);
1752241675Suqs  }
1753241675Suqs  return ok;
1754241675Suqs}
1755274880Sbapt
1756274880Sbaptstatic int do_file(const char *filename)
1757274880Sbapt{
1758241675Suqs  FILE *fp;
1759241675Suqs
1760241675Suqs  current_filename = filename;
1761241675Suqs  if (strcmp(filename, "-") == 0)
1762274880Sbapt    fp = stdin;
1763241675Suqs  else {
1764241675Suqs    fp = fopen(filename, "r");
1765241675Suqs    if (fp == 0) {
1766241675Suqs      error("can't open `%1': %2", filename, strerror(errno));
1767241675Suqs      return 0;
1768274880Sbapt    }
1769274880Sbapt  }
1770274880Sbapt
1771241675Suqs  if (inputFile.read_file(fp)) {
1772274880Sbapt    // XXX
1773241675Suqs  }
1774275432Sbapt
1775274880Sbapt  if (fp != stdin)
1776279527Sbapt    fclose(fp);
1777279527Sbapt  current_filename = NULL;
1778275432Sbapt  return 1;
1779274880Sbapt}
1780279527Sbapt