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(®ionFileName, 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