/*
 *	main.c - main for nroff word processor
 *
 *	similar to Unix(tm) nroff or RSX-11M RNO. adaptation of text processor
 *	given in "Software Tools", Kernighan and Plauger.
 *
 *	adapted for atariST/TOS by Bill Rosenkranz 11/89
 *	net:	rosenkra@hall.cray.com
 *	CIS:	71460,17
 *	GENIE:	W.ROSENKRANZ
 *
 *	original author:
 *
 *	Stephen L. Browning
 *	5723 North Parker Avenue
 *	Indianapolis, Indiana 46220
 *
 *	history:
 *
 *	- Originally written in BDS C;
 *	- Adapted for standard C by W. N. Paul
 *	- Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
 *      - Heavily modified by Devin Reade to avoid memory trashing bugs.
 *
 * $Id: nroff.c,v 1.2 1997/03/20 06:40:50 gdr Exp $
 */

#ifdef __ORCAC__
segment "main______";
#pragma stacksize 6144
#pragma optimize 79
#endif

#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#ifdef __GNO__
#include <err.h>
#include <termcap.h>
#include <gno/gno.h>
#else
#include "unix/err.h"
#include "unix/termcap.h"
#endif

#ifdef sparc
#include <memory.h>
#include "unix/sunos.h"
#endif

#include "nroff.h"
#include "macros.h"
#include "io.h"

static void	init (void);
static void	processFile (void);
static int	pswitch (char *p, int *q);
static void	usage (void);

/*************************************************************************
 *
 * Global variables block.  Keep them in main.c so that the IIgs'
 * debuggers can find them.
 */

struct docctl		dc;
struct page		pg;
struct macros_t		mac;
struct regs		rg[MAXREGS];
FILE		       *out_stream;
FILE		       *err_stream;
FILE		       *dbg_stream;
FILE		       *sofile[Nfiles+1];
int			ignoring;		/* .ig vs .de */
int			hold_screen;
int			debugging;
int			stepping;		/* paging */
int			mc_ing = 0;		/* turned off */
int			mc_space = 2;
char			mc_char = '|';
char			tmpdir[256];
char			s_standout[20];
char			e_standout[20];
char			s_bold[20];
char			e_bold[20];
char			s_italic[20];
char			e_italic[20];
char		       *dbgfile = "nroff.dbg";
#ifdef GEMDOS
char		       *printer = "prn:";	/* this WON'T work!!! */
#else
char		       *printer = ".ttyb";	/* this probably won't */
#endif

static char		termcap[1024];		/* _must_ be 1024 */
static char  *progname;
static char    *version = "(GNO) v1.2, 5 Mar 97 gdr";

/*
 * End of global variable definitions.
 *
 *************************************************************************/

#ifdef CHECK_STACK
static void
stackCleanup (void) {
    fprintf(stderr, "stack usage: %d bytes\n", _endStackCheck());
}
#endif

int
main (int argc, char *argv[]) {
    register int	i;
    int		swflg;
    int		ifp = 0;
    char	       *ptmp;
    char	       *pterm;
    char		capability[100];
    char	       *pcap;
    char	       *ps;

#ifdef __GNO__
#ifdef CHECK_STACK
    _beginStackCheck();
    atexit(stackCleanup);
#endif
    if (argc > 0) {
	progname = __prognameGS();
    } else {
	exit(1);		/* not running from a shell? */
    }
#else
    if (argc > 0) {
	progname = basename(argv[0]);
    } else {
	progname = "nroff";
    }
#endif


    /*
     *   set up initial flags and file descriptors
     */
    swflg       = FALSE;
    ignoring    = FALSE;
    hold_screen = FALSE;
    debugging   = FALSE;
    stepping    = FALSE;
    mc_ing      = FALSE;
    out_stream  = stdout;
    err_stream  = stderr;
    dbg_stream  = stderr;
    
  
    /*
     *   this is for tmp files, if ever needed. it SHOULD start
     *   out without the trailing slash. if not in env, use default
     */
    if ((ptmp = getenv ("TMPDIR")) != NULL) {
	strcpy (tmpdir, ptmp);
    } else {
	strcpy (tmpdir, ".");
    }
  
    /*
     *   handle terminal for \fB, \fI
     */
    s_standout[0] = '\0';
    e_standout[0] = '\0';
    s_bold[0]     = '\0';
    e_bold[0]     = '\0';
    s_italic[0]   = '\0';
    e_italic[0]   = '\0';

    /*
     * get termcap information
     */
    if ((pterm = getenv("TERM")) == NULL) {
	errx(1, "TERM environment variable not set");
    }
    switch (tgetent(termcap, pterm)) {
    case -1:
	errx(1, "couldn't open termcap database");
	/*NOTREACHED*/
    case 0:
	errx(1, "terminal type %s not found in termcap database", pterm);
	/*NOTREACHED*/
    }
	
    /*
     *   we currently use standout mode for all weirdness
     *   like BOLD, italic, etc.
     */
    pcap = capability;
    if ((ps = tgetstr ("so", &pcap)) != NULL) {
	/*
	 *   sun has padding in here. this is NOT portable.
	 *   better to use tputs() to strip it...
	 */
	/*	while (*ps && *ps != 0x1b)	ps++;  */
	strcpy (s_standout, ps);
	strcpy (s_bold, ps);
	strcpy (s_italic, ps);
    } else { 
	err(1, "couldn't get standout mode");
	/*NOTREACHED*/
    }
    if ((ps = tgetstr ("se", &pcap)) != NULL) {
	/*	while (*ps && *ps != 0x1b)	ps++; */
	strcpy (e_standout, ps);
	strcpy (e_bold, ps);
	strcpy (e_italic, ps);
    }
    
    /*
     *   initialize structures (defaults)
     */
    init ();

    /*
     *   parse cmdline flags
     */
    for (i = 1; i < argc; ++i) {   
	if (*argv[i] == '-' || *argv[i] == '+') {
	    if (pswitch (argv[i], &swflg) == ERR) {
		err_exit (-1);
	    }
	}
    }

    /*
     *   loop on files
     */
    for (i = 1; i < argc; ++i) {
	if (*argv[i] != '-' && *argv[i] != '+') {
	    /*
	     *   open this file...
	     */
	    if ((sofile[0] = fopen (argv[i], "r")) == NULL_FPTR) {
		err(-1, "unable to open file %s", argv[i]);
	    } else {
		/*
		 *   do it for this file...
		 */
		ifp = 1;
		processFile ();
		fclose (sofile[0]);
	    }
	} else if (*argv[i] == '-' && *(argv[i]+1) == 0) {
	    /*
	     *   - means read stdin (anywhere in file list)
	     */
	    sofile[0] = stdin;
	    ifp = 1;
	    sleep(1);
	    processFile ();
	}
    }
    
    
    /*
     *   if no files, usage (should really use stdin...)
     */
    if ((ifp == 0 && swflg == FALSE) || argc <= 1) {
	usage ();
	err_exit (-1);
    }
    
    /*
     *   normal exit. this will fflush/fclose streams...
     */
    err_exit (0);
#if defined(__GNUC__) || defined(__INSIGHT__)
    return 0;
#endif
}


/*------------------------------*/
/*	usage			*/
/*------------------------------*/
static void
usage (void) {
    /*
     *   note: -l may not work correctly
     */
    
    fprintf(stderr, "Usage:   %s [options] file [...]\n", progname);
    fputs("\t-a\tno font changes\n", stderr);
    fputs("\t-b\t\tbackspace\n", stderr);
    fputs("\t-d\t\tdebug mode (file: nroff.dbg)\n", stderr);
#ifdef GEMDOS
    fputs("\t-h\t\thold screen before desktop\n", stderr);
#endif
#if 0
    fputs("\t-l\t\toutput to printer\n", stderr);
#endif
    fputs("\t-m<name>\tmacro file (e.g. -man)\n", stderr);
    fputs("\t-o<file>\terror log file (stderr is default)\n", stderr);
    fputs("\t-po<n>\t\tpage offset\n", stderr);
    fputs("\t-pn<n>\t\tinitial page number\n", stderr);
    fputs("\t-pl<n>\t\tpage length\n", stderr);
    fputs("\t-s\t\tstep through pages\n", stderr);
    fputs("\t-v\t\tprint version only\n", stderr);
    fputs("\t+<n>\t\tfirst page to do\n", stderr);
    fputs("\t-<n>\t\tlast page to do\n", stderr);
    fputs("\t-\t\tuse stdin (in file list)\n", stderr);
}


/*
 * init
 *	initialize parameters for nro word processor
 */
static void
init (void) {
    
    
#ifdef MINIX
    register int	i;
#else
    register long	i;
#endif
    time_t		tval;
    char	       *ctim;
    
    /*
     *   misc global flags, etc...
     */
    mc_space   = 2;
    mc_char    = '|';
    tval       = time (0L);
    ctim       = ctime (&tval);
    
    /*
     *   basic document controls...
     */
    dc.fill    = YES;
    dc.dofnt   = YES;
    dc.lsval   = 1;
    dc.inval   = 0;
    dc.rmval   = PAGEWIDTH - 1;
    dc.llval   = PAGEWIDTH - 1;
    dc.ltval   = PAGEWIDTH - 1;
    dc.tival   = 0;
    dc.ceval   = 0;
    dc.ulval   = 0;
    dc.cuval   = 0;
    dc.juval   = YES;
    dc.adjval  = ADJ_BOTH;
    dc.boval   = 0;
    dc.bsflg   = FALSE;
    dc.prflg   = TRUE;
    dc.sprdir  = 0;
    dc.flevel  = 0;
    dc.lastfnt = 1;
    dc.thisfnt = 1;
    dc.escon   = YES;
    dc.pgchr   = '%';
    dc.cmdchr  = '.';
    dc.escchr  = '\\';
    dc.nobrchr  = '\'';
    for (i = 0; i < 26; ++i) {
	dc.nr[i] = 0;
    }
    for (i = 0; i < 26; ++i) {
	dc.nrauto[i] = 1;
    }
    for (i = 0; i < 26; ++i) {
	dc.nrfmt[i] = '1';
    }
    
    /*
     *   initialize internal regs. first zero out...
     */
    for (i = 0; i < MAXREGS; i++) {
	rg[i].rname[0] = EOS;
	rg[i].rname[1] = EOS;
	rg[i].rname[2] = EOS;
	rg[i].rname[3] = EOS;
	rg[i].rauto = 1;
	rg[i].rval  = 0;
	rg[i].rflag = RF_READ;
	rg[i].rfmt  = '1';
    }
  
    /*
     *   predefined regs. these are read/write:
     */
    i = 0;
    
    strcpy (rg[i].rname, "%");		/* current page */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "ct");		/* character type */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "dl");		/* width of last complete di */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "dn");		/* height of last complete di */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, "dw");		/* day of week (1-7) */
    rg[i].rval  = 0;
    if      (!strncmp (&ctim[0], "Sun", 3))      rg[i].rval  = 1; 
    else if (!strncmp (&ctim[0], "Mon", 3))      rg[i].rval  = 2;
    else if (!strncmp (&ctim[0], "Tue", 3))      rg[i].rval  = 3;
    else if (!strncmp (&ctim[0], "Wed", 3))      rg[i].rval  = 4;
    else if (!strncmp (&ctim[0], "Thu", 3))      rg[i].rval  = 5;
    else if (!strncmp (&ctim[0], "Fri", 3))      rg[i].rval  = 6;
    else if (!strncmp (&ctim[0], "Sat", 3))      rg[i].rval  = 7;
    rg[i].rauto = 1;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "dy");		/* day of month (1-31) */
    rg[i].rauto = 1;
    rg[i].rval  = atoi (&ctim[8]);
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "hp");		/* current h pos on input */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, "ln");		/* output line num */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "mo");		/* current month (1-12) */
    rg[i].rval  = 0;
    if      (!strncmp (&ctim[4], "Jan", 3))      rg[i].rval  = 1;
    else if (!strncmp (&ctim[4], "Feb", 3))      rg[i].rval  = 2;
    else if (!strncmp (&ctim[4], "Mar", 3))      rg[i].rval  = 3;
    else if (!strncmp (&ctim[4], "Apr", 3))      rg[i].rval  = 4;
    else if (!strncmp (&ctim[4], "May", 3))      rg[i].rval  = 5;
    else if (!strncmp (&ctim[4], "Jun", 3))      rg[i].rval  = 6;
    else if (!strncmp (&ctim[4], "Jul", 3))      rg[i].rval  = 7;
    else if (!strncmp (&ctim[4], "Aug", 3))      rg[i].rval  = 8;
    else if (!strncmp (&ctim[4], "Sep", 3))      rg[i].rval  = 9;
    else if (!strncmp (&ctim[4], "Oct", 3))      rg[i].rval  = 10;
    else if (!strncmp (&ctim[4], "Nov", 3))      rg[i].rval  = 11;
    else if (!strncmp (&ctim[4], "Dec", 3))      rg[i].rval  = 12;
    rg[i].rauto = 1;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "nl");		/* v pos of last base-line */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "sb");		/* depth of str below base */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "st");		/* height of str above base */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, "yr");		/* last 2 dig of current year*/
    rg[i].rauto = 1;
    rg[i].rval  = atoi (&ctim[22]);
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, "hh");		/* current hour (0-23) */
    rg[i].rauto = 1;
    rg[i].rval  = atoi (&ctim[11]);
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = 2 | 0x80;
    i++;
    
    strcpy (rg[i].rname, "mm");		/* current minute (0-59) */
    rg[i].rauto = 1;
    rg[i].rval  = atoi (&ctim[14]);
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = 2 | 0x80;
    i++;
    
    strcpy (rg[i].rname, "ss");		/* current second (0-59) */
    rg[i].rauto = 1;
    rg[i].rval  = atoi (&ctim[17]);
    rg[i].rflag = RF_READ | RF_WRITE;
    rg[i].rfmt  = 2 | 0x80;
    i++;
    
  
    /*
     *   these are read only (by user):
     */
    strcpy (rg[i].rname, ".$");		/* num args at current macro*/
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".A");		/* 1 for nroff */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".H");		/* hor resolution */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".T");		/* 1 for troff */
    rg[i].rauto = 0;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".V");		/* vert resolution */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".a");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".c");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".d");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
	
    strcpy (rg[i].rname, ".f");		/* current font (1-4) */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".h");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".i");		/* current indent */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".l");		/* current line length */
    rg[i].rauto = 1;
    rg[i].rval  = PAGEWIDTH - 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".n");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".o");		/* current offset */
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".p");		/* current page len */
    rg[i].rauto = 1;
    rg[i].rval  = PAGELEN;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".s");		/* current point size */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".t");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".u");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
    
    strcpy (rg[i].rname, ".v");		/* current v line spacing */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".w");		/* width of prev char */
    rg[i].rauto = 1;
    rg[i].rval  = 1;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".x");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".y");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';
    i++;
  
    strcpy (rg[i].rname, ".z");
    rg[i].rauto = 1;
    rg[i].rval  = 0;
    rg[i].rflag = RF_READ;
    rg[i].rfmt  = '1';

    /*
     *   page controls...
     */
    pg.curpag   = 0;
    pg.newpag   = 1;
    pg.lineno   = 0;
    pg.plval    = PAGELEN;
    pg.m1val    = 2;
    pg.m2val    = 2;
    pg.m3val    = 2;
    pg.m4val    = 2;
    pg.bottom   = pg.plval - pg.m4val - pg.m3val;
    pg.offset   = 0;
    pg.frstpg   = 0;
    pg.lastpg   = 30000;
    pg.ehead[0] = pg.ohead[0] = '\n';
    pg.efoot[0] = pg.ofoot[0] = '\n';
    memset(pg.ehead + 1, EOS, MAXLINE -1);
    memset(pg.ohead + 1, EOS, MAXLINE -1);
    memset(pg.efoot + 1, EOS, MAXLINE -1);
    memset(pg.ofoot + 1, EOS, MAXLINE -1);

#if 0  
    for (i = 1; i < MAXLINE; ++i) {
	pg.ehead[i] = pg.ohead[i] = EOS;
	pg.efoot[i] = pg.ofoot[i] = EOS;
    }
#endif
    pg.ehlim[LEFT]  = pg.ohlim[LEFT]  = dc.inval;
    pg.eflim[LEFT]  = pg.oflim[LEFT]  = dc.inval;
    pg.ehlim[RIGHT] = pg.ohlim[RIGHT] = dc.rmval;
    pg.eflim[RIGHT] = pg.oflim[RIGHT] = dc.rmval;
    
    /*
     *   output buffer controls...
     */
    initOutbuf();
  
    /*
     *   macros...
     */
    initMacros();
  
    /*
     *   file descriptors (for sourced files)
     */
    for (i = 0; i < Nfiles+1; ++i) {
	sofile[i] = NULL_FPTR;
    }
}


/*
 * pswitch
 *
 *	process switch values from command line
 */
static int 
pswitch (char *p, int *q) {
    int     swgood;
    char    mfile[256];
    char   *ptmac;
    int	indx;
    int	val;
    
    swgood = TRUE;
    if (*p == '-') {
	/*
	 *   since is STILL use the goofy atari/dri xmain code, i
	 *   look for both upper and lower case. if you use dLibs
	 *   (and if its startup code does not ucase the cmd line),
	 *   you can probably look for just lower case. gulam and
	 *   other shells typically don't change case of cmd line.
	 */
	switch (*++p) {
	case 0:					/* stdin */
	    break;
	    
	case 'a': 				/* font changes */
	case 'A': 
	    dc.dofnt = NO;
	    break;
	    
	case 'b': 				/* backspace */
	case 'B': 
	    dc.bsflg = TRUE;
	    break;
	    
	case 'd': 				/* debug mode */
	case 'D': 
	    if ((dbg_stream = fopen (dbgfile, "w")) == NULL) {
		warn ("unable to open debug file %s, using stderr", dbgfile);
		dbg_stream  = stderr;
	    }
	    debugging  = TRUE;
	    break;
	    
	case 'h': 				/* hold screen */
	case 'H': 
	    hold_screen = TRUE;
	    break;
	    
	case 'l': 				/* to lpr (was P) */
	case 'L': 
#ifdef GEMDOS
	    out_stream = (FILE *) 0;
#else
	    out_stream = fopen (printer, "w");
#endif
	    setPrinting(TRUE);
	    break;
	    
	case 'm': 				/* macro file */
	case 'M': 
	    /*
	     *   build macro file name. start with lib
	     *
	     *   put c:\lib\tmac in environment so we can
	     *   read it here. else use default. if you want
	     *   file from cwd, "setenv TMACDIR ." from shell.
	     *
	     *   we want file names like "tmac.an" (for -man)
	     */
	    if ((ptmac = getenv ("TMACDIR")) != NULL) {
		/*
		 *   this is the lib path (e.g. "c:\lib\tmac")
		 */
		strcpy (mfile, ptmac);
		
		/*
		 *   this is the prefix (i.e. "\tmac.")
		 */
		strcat (mfile, TMACPRE);
	    } else {
		/*
		 *   use default lib/prefix (i.e.
		 *   "c:\lib\tmac\tmac.")
		 */
		strcpy (mfile, TMACFULL);
	    }

	    /*
	     *   finally, add extension (e.g. "an")
	     */
	    strcat (mfile, ++p);
	    
	    /*
	     *   open file and read it
	     */
	    if ((sofile[0] = fopen (mfile, "r")) == NULL_FPTR) {
		err(-1, "unable to open macro file %s", mfile);
		/*NOTREACHED*/
	    }
	    processFile ();
	    fclose (sofile[0]);
	    break;
	    
	case 'o': 				/* output error log */
	case 'O': 
	    if (!*(p+1)) {
		err(-1, "no error file specified");
		/*NOTREACHED*/
	    }
	    if ((err_stream = fopen (p+1, "w")) == NULL) {
		err(-1, "unable to open error file %s", p+1);
		/*NOTREACHED*/
	    }
	    err_set_file(err_stream);
	    break;
	    
	case 'p': 				/* .po, .pn */
	case 'P':
	    if (*(p+1) == 'o' || *(p+1) == 'O') {	/* -po___ */
		p += 2;
		set (&pg.offset, ctod (p), '1', 0, 0, HUGE);
		set_ireg (".o", pg.offset, 0);
	    } else if (*(p+1) == 'n' || *(p+1) == 'N') { /* -pn___ */
		p += 2;
		set (&pg.curpag, ctod (p) - 1, '1', 0, -HUGE, HUGE);
		pg.newpag = pg.curpag + 1;
		set_ireg ("%", pg.newpag, 0);
	    } else if (*(p+1) == 'l' || *(p+1) == 'L') { /* -pl___ */
		p += 2;
		set (&pg.plval, ctod (p) - 1, '1', 0,
		     pg.m1val + pg.m2val + pg.m3val + pg.m4val + 1,
		     HUGE);
		set_ireg (".p", pg.plval, 0);
		pg.bottom = pg.plval - pg.m3val - pg.m4val;
	    } else {					/* -p___ */
		p++;
		set (&pg.offset, ctod (p), '1', 0, 0, HUGE);
		set_ireg (".o", pg.offset, 0);
	    }
	    break;
	    
	case 'r':				/* set number reg */
	case 'R':
	    if (!isalpha (*(p+1))) {
		warnx("invalid number register name (%c)", *(p+1));
	    } else {
		/*
		 *   indx is the user num register and val
		 *   is the final value.
		 */
		indx = tolower (*(p+1)) - 'a';
		val  = atoi (p+2);
		set (&dc.nr[indx], val, '1', 0, -INFINITE, INFINITE);
	    }
	    break;
	    
	case 's': 				/* page step mode */
	case 'S': 
	    stepping = TRUE;
	    break;
	    
	case 'v': 				/* version */
	case 'V': 
	    printf ("%s %s\n", progname, version);
	    *q = TRUE;
	    break;
	    
	case '0': 				/* last page */
	case '1': 
	case '2': 
	case '3': 
	case '4': 
	case '5': 
	case '6': 
	case '7': 
	case '8': 
	case '9': 
	    pg.lastpg = ctod (p);
	    break;
	    
	default: 				/* illegal */
	    swgood = FALSE;
	    break;
	}
    } else if (*p == '+') {				/* first page */
	pg.frstpg = ctod (++p);
    } else {						/* illegal */
	swgood = FALSE;
    }
    
  
    if (swgood == FALSE) {
	warnx("illegal option: %s", p);
	return (ERR);
    }
    
    return (OK);
}


/*
 * processFile
 *
 *	process input files from command line
 */
static void 
processFile (void) {
    
    static char ibuf[MAXLINE];
    int i;
    
    /*
     *   handle nesting of includes (.so). note that .so causes dc.flevel
     *   to be increased...
     */
    for (dc.flevel = 0; dc.flevel >= 0; dc.flevel -= 1) {
	while ((i = getlin (ibuf, sofile[dc.flevel])) != EOF) {
	    /*
	     *   if line is a command or text
	     */
	    if (ibuf[0] == dc.cmdchr) {
		comand (ibuf);
	    } else {
		/*
		 *   this is a text line. first see if
		 *   first char is space. if it is, break
		 *   line.
		 */
		if (ibuf[0] == ' ') {
		    robrk ();
		}
		text (ibuf);
	    }
	}
	
	/*
	 *   close included file
	 */
	if (dc.flevel > 0) {
	    fclose (sofile[dc.flevel]);
	}
    }
    if (pg.lineno > 0) {
	nroffSpace (HUGE);
    }
}

#pragma optimize 8
#pragma debug 0

void
debugMessage (const char *fmt, ...) {
    va_list ap;

    va_start(ap, fmt);
    fprintf(err_stream, "%s: ", progname);
    vfprintf(err_stream, fmt, ap);
    va_end(ap);
    return;
}
