[comp.sources.atari.st] v03i009: nroff -- Partial clone of UNIX "nroff" formatter part02/03

koreth@panarthea.ebay.sun.com (Steven Grimm) (11/15/89)

Submitted-by: rosenkra@hall.cray.com (Bill Rosenkranz)
Posting-number: Volume 3, Issue 9
Archive-name: nroff/part02


part02/03

-bill
rosenkra@hall.cray.com

------------cut here----------------cut here---------------------------------
#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by hall!rosenkra on Sun Nov 12 16:35:33 CST 1989
# Contents:  main.c command.c text.c io.c
 
echo x - main.c
sed 's/^@//' > "main.c" <<'@//E*O*F main.c//'
/*
 *	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
 */

#define NRO_MAIN			/* to define globals in nro.h */

#include <stdio.h>
#ifdef ATARIST
#include <sys\types.h>
#include <sys\time.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include "nroff.h"


main (argc, argv)
int     argc;
char   *argv[];
{
	register int	i;
	int		swflg;
	int		ifp = 0;


	swflg       = FALSE;
	hold_screen = FALSE;
	debugging   = FALSE;
	pout        = stdout;
	err_stream  = stderr;
	dbg_stream  = stderr;


	/*
	 *   initialize structures (defaults)
	 */
	init ();


	/*
	 *   parse cmdline flags
	 */
	for (i = 1; i < argc; ++i)
	{
		if (*argv[i] == '-' || *argv[i] == '+')
		{
			if (pswitch (argv[i], argv[i+1], &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)
			{
				fprintf (err_stream,
					"***%s: unable to open file %s\n",
					myname, argv[i]);
				err_exit (-1);
			}
			else
			{
				/*
				 *   do it for this file...
				 */
				ifp = 1;
				profile ();
				fclose (sofile[0]);
			}
		}
		else if (*argv[i] == '-' && *(argv[i]+1) == 0)
		{
			/*
			 *   - means read stdin
			 */
			sofile[0] = stdin;
			ifp = 1;
			profile ();
		}

	}


	/*
	 *   if no files, usage
	 */
	if ((ifp == 0 && swflg == FALSE) || argc <= 1)
	{
		usage ();

		err_exit (-1);
	}

	/*
	 *   if not going to stdout (-l)
	 */
	if (pout != stdout)
	{
		fflush (pout);
		fclose (pout);
	}

	err_exit (0);
}




/*------------------------------*/
/*	usage			*/
/*------------------------------*/
usage ()
{
	/*
	 *   note: -l not documented
	 */
	fprintf (stderr, "Usage: %s [options] file [...]\n", myname);
	fprintf (stderr, "Options:\n");
	fprintf (stderr, "-a              font changes\n");
	fprintf (stderr, "-b              backspace\n");
	fprintf (stderr, "-h              hold screen\n");
/*	fprintf (stderr, "-l              output to printer\n");*/
	fprintf (stderr, "-m<name>        macro file (e.g. -man)\n");
	fprintf (stderr, "-o file         error log file\n");
	fprintf (stderr, "-po<n>          page offset\n");
	fprintf (stderr, "-pn<n>          initial page number\n");
	fprintf (stderr, "-v              version\n");
	fprintf (stderr, "+<n>            first page to do\n");
	fprintf (stderr, "-<n>            last page to do\n");
	fprintf (stderr, "-               use stdin\n");
}




/*------------------------------*/
/*	init			*/
/*------------------------------*/
init ()
{

/*
 *	initialize parameters for nro word processor
 */

	register long	i;
#ifdef ALCYON
	time_t		dum = 0;
#else
	extern long	time ();
	time_t		dum = time (0);
#endif
	char	       *ctim;

	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] = rg[i].rname[1] = rg[i].rname[2] = rg[i].rname[3] = '\0';
		rg[i].rauto = 1;
		rg[i].rval  = 0;
		rg[i].rflag = RF_READ;
		rg[i].rfmt  = '1';
	}



	/*
	 *   this should be checked...
	 */
	ctim = ctime (&dum);


	/*
	 *   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++;
	

	/*
	 *   these are read only:
	 */
	strcpy (rg[i].rname, ".$");		/* num of 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';

	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';
	for (i = 1; i < MAXLINE; ++i)
	{
		pg.ehead[i] = pg.ohead[i] = EOS;
		pg.efoot[i] = pg.ofoot[i] = EOS;
	}
	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;

	co.outp   = 0;
	co.outw   = 0;
	co.outwds = 0;
	co.lpr    = FALSE;
	for (i = 0; i < MAXLINE; ++i)
		co.outbuf[i] = EOS;

	for (i = 0; i < MXMDEF; ++i)
		mac.mnames[i] = NULL;
	for (i = 0; i < MACBUF; ++i)
		mac.mb[i] = '\0';
	for (i = 0; i < MAXLINE; ++i)
		mac.pbb[i] = '\0';
	mac.lastp = 0;
	mac.emb   = &mac.mb[0];
	mac.ppb   = NULL;
}




/*------------------------------*/
/*	pswitch			*/
/*------------------------------*/
pswitch (p, p2, q)
register char  *p;
register char  *p2;
register int   *q;
{

/*
 *	process switch values from command line
 */

	int     swgood;
	char    mfile[128];
	char   *ptmac;

	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': 
			dbg_stream = fopen (dbgfile, "w");
			debugging = TRUE;
			break;

		case 'h': 				/* hold screen */
		case 'H': 
			hold_screen = TRUE;
			break;

		case 'l': 				/* to lpr (was P) */
		case 'L': 
			pout = fopen (printer, "w");
			co.lpr = 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"))
			{
				/*
				 *   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)
			{
				fprintf (stderr,
					"***%s: unable to open macro file %s\n",
					myname, mfile);
				err_exit (-1);
			}
			profile ();
			fclose (sofile[0]);
			break;

		case 'o': 				/* output error log */
		case 'O': 
			if (!p2)
			{
				fprintf (stderr,
					"***%s: no error file specified\n",
					myname);
				err_exit (-1);
			}
			if ((err_stream = fopen (p2, "w")) == NULL)
			{
				fprintf (stderr,
					"***%s: unable to open error file %s\n",
					myname, p2);
				err_exit (-1);
			}
			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					/* -p___ */
			{
				set (&pg.offset, ctod (++p), '1', 0, 0, HUGE);
				set_ireg (".o", pg.offset, 0);
			}
			break;

		case 'v': 				/* version */
		case 'V': 
			printf ("%s\n", 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)
	{
		fprintf (stderr, "***%s: illegal switch %s\n", myname, p);
		return (ERR);
	}

	return (OK);
}




/*------------------------------*/
/*	profile			*/
/*------------------------------*/
profile ()
{

/*
 *	process input files from command line
 */

	char    ibuf[MAXLINE];

	/*
	 *   handle nesting of includes (.so)
	 */
	for (dc.flevel = 0; dc.flevel >= 0; dc.flevel -= 1)
	{
		while (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)
		space (HUGE);
}





@//E*O*F main.c//
chmod u=rw,g=r,o=r main.c
 
echo x - command.c
sed 's/^@//' > "command.c" <<'@//E*O*F command.c//'
/*
 *	command.c - command input parser/processor for nroff text processor
 *
 *	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
 */

#undef NRO_MAIN					/* extern globals */

#include <stdio.h>
#include "nroff.h"



/*------------------------------*/       
/*	comand			*/
/*------------------------------*/       
comand (p)
register char  *p;
{

/*
 *	main command processor
 */

	register int	i;
	register int	ct;
	register int	val;
	register int   	indx;
	int		newval;
	int     	spval;
	char    	argtyp;
	char    	name[MAXLINE];
	char    	macexp[MXMLEN];
	int		tmp;
	char	       *pfs;
	char		fs[20];


	/*
	 *   get command code
	 */
	ct = comtyp (p, macexp);

	/*
	 *   error?
	 */
	if (ct == UNKNOWN)
	{
		fprintf (err_stream,
			"***%s: unrecognized command %s\n", myname, p);
		return;
	}

	/*
	 *   ignore comments
	 */
	if (ct == COMMENT)
		return;


	/*
	 *   do escape expansion on command line args
	 */
	expesc (p, name);


	/*
	 *   get value of command
	 */
	val = getval (p, &argtyp);


	/*
	 *   do the command
	 */
	switch (ct)
	{
	/* set (&param, val, type, defval, minval, maxval) */
	case FC:
		/*
		 *   field delim/pad chars
		 *
		 *   .fc [delim] [pad]
		 */
		fprintf (err_stream, "***%s: .fc not available\n", myname);
		break;
	case TR:
		/*
		 *   translate
		 *
		 *   .tr ab...
		 */
		fprintf (err_stream, "***%s: .tr not available\n", myname);
		break;




	case AD:
		/*
		 *   adjust
		 *
		 *   .ad [mode]
		 */
		p = skipwd (p);
		p = skipbl (p);

		switch (*p)
		{
		case 'l':
			dc.adjval = ADJ_LEFT;
			dc.juval  = YES;
			break;
		case 'r':
			dc.adjval = ADJ_RIGHT;
			dc.juval  = YES;
			break;
		case 'c':
			dc.adjval = ADJ_CENTER;
			dc.juval  = YES;
			break;
		case 'b':
		case 'n':
			dc.adjval = ADJ_BOTH;
			dc.juval  = YES;
			break;
		default:
			break;
		}
		break;
	case AF:
		/*
		 *   assign format to number reg
		 *
		 *   .af R {1,a,A,i,I,0...1}
		 */
		p = skipwd (p);
		p = skipbl (p);
		if (!isalpha (*p))
		{
			fprintf (err_stream,
				"***%s: invalid or missing number register name\n",
				myname);
		}
		else
		{
			/*
			 *   number register format is 1,a,A,i,I,0...1
			 *   default is 1. for 0001 format, store num dig
			 *   or'ed with 0x80, up to 8 digits.
			 */
			indx = tolower (*p) - 'a';
			p = skipwd (p);
			p = skipbl (p);
			if (*p == '1')
				dc.nrfmt[indx] = '1';
			else if (*p == 'a')
				dc.nrfmt[indx] = 'a';
			else if (*p == 'A')
				dc.nrfmt[indx] = 'A';
			else if (*p == 'i')
				dc.nrfmt[indx] = 'i';
			else if (*p == 'I')
				dc.nrfmt[indx] = 'I';
			else if (*p == '0')
			{
				for (i = 0; isdigit (p[i]); i++)
					;
				dc.nrfmt[indx] = (char) (i);
				if (dc.nrfmt[indx] <= 0)
					dc.nrfmt[indx] = '1';
				else if (dc.nrfmt[indx] > 8)
				{
					dc.nrfmt[indx]  = 8;
					dc.nrfmt[indx] |= 0x80;
				}
				else
					dc.nrfmt[indx] |= 0x80;

			}
			else
				dc.nrfmt[indx] = '1';
		}
		break;
	case BO:
		/*
		 *   bold face
		 *
		 *   .bo [N]
		 */
		set (&dc.boval, val, argtyp, 1, 0, HUGE);
		dc.cuval = dc.ulval = 0;
		break;
	case BP:
		/*
		 *   begin page
		 *
		 *   .bp [+/-N]
		 */
		if (pg.lineno > 0)
			space (HUGE);
		set (&pg.curpag, val, argtyp, pg.curpag + 1, -HUGE, HUGE);
		pg.newpag = pg.curpag;
		set_ireg ("%", pg.newpag, 0);
		break;
	case BR:
		/*
		 *   break (page)
		 *
		 *   .br
		 */
		robrk ();
		break;
	case BS:
		/*
		 *   backspc in output
		 *
		 *   .bs [N]
		 */
		set (&dc.bsflg, val, argtyp, 1, 0, 1);
		break;
	case C2:
		/*
		 *   nobreak char
		 *
		 *   .c2 [c=']
		 */
		if (argtyp == '\r' || argtyp == '\n')
			dc.nobrchr = '\'';
		else
			dc.nobrchr = argtyp;
		break;
	case CC:
		/*
		 *   command character
		 *
		 *   .cc [c=.]
		 */
		if (argtyp == '\r' || argtyp == '\n')
			dc.cmdchr = '.';
		else
			dc.cmdchr = argtyp;
		break;
	case CE:
		/*
		 *   center
		 *
		 *   .ce [N]
		 */
		robrk ();
		set (&dc.ceval, val, argtyp, 1, 0, HUGE);
		break;
	case CU:
		/*
		 *   continuous underline
		 *
		 *   .cu [N]
		 */
		set (&dc.cuval, val, argtyp, 1, 0, HUGE);
		dc.ulval = dc.boval = 0;
		break;
	case DE:
		/*
		 *   define macro
		 *
		 *   .de name [end]
		 */
		defmac (p, sofile[dc.flevel]);
		break;
	case DS:
		/*
		 *   define string
		 *
		 *   .ds name string
		 */
		defstr (p);
		break;
	case EC:
		/*
		 *   escape char
		 *
		 *   .ec [c=\]
		 */
		if (argtyp == '\r' || argtyp == '\n')
			dc.escchr = '\\';
		else
			dc.escchr = argtyp;
		dc.escon = YES;
		break;
	case EF:
		/*
		 *   even footer
		 *
		 *   .ef "a" "b" "c"
		 */
		gettl (p, pg.efoot, &pg.eflim[0]);
		break;
	case EH:
		/*
		 *   even header
		 *
		 *   .eh "a" "b" "c"
		 */
		gettl (p, pg.ehead, &pg.ehlim[0]);
		break;
	case EN:
		/*
		 *   end macro def (should not get one here...)
		 *
		 *   .en or ..
		 */
		fprintf (err_stream, "***%s: missing .de command\n", myname);
		break;
	case EO:
		/*
		 *   escape off
		 *
		 *   .eo
		 */
		dc.escon = NO;
		break;
	case FI:
		/*
		 *   fill
		 *
		 *   .fi
		 */
		robrk ();
		dc.fill = YES;
		break;
	case FL:
		/*
		 *   flush NOW
		 *
		 *   .fl
		 */
		fflush (pout);
		break;
	case FO:
		/*
		 *   footer
		 *
		 *   .fo "a" "b" "c"
		 */
		gettl (p, pg.efoot, &pg.eflim[0]);
		gettl (p, pg.ofoot, &pg.oflim[0]);
		break;
	case FT:
		/*
		 *   font change
		 *
		 *   .ft {R,I,B,S,P}
		 *
		 *   the way it's implemented here, it causes a break
		 *   rather than be environmental...
		 */
		p = skipwd (p);
		p = skipbl (p);
		if (!isalpha (*p))
		{
			fprintf (err_stream,
				"***%s: invalid or missing font name\n",
				myname);
		}
		else
		{
			pfs = &fs[0];

			fontchange (*p, pfs);

			robrk ();
			fflush (pout);
			fprintf (pout, "%s", pfs);
			fflush (pout);
		}
		break;
	case TL:
	case HE:
		/*
		 *   header (both are currently identical. .he is -me)
		 *
		 *   .tl "a" "b" "c"
		 *   .he "a" "b" "c"
		 */
		gettl (p, pg.ehead, &pg.ehlim[0]);
		gettl (p, pg.ohead, &pg.ohlim[0]);
		break;
	case IN:
		/*
		 *   indenting
		 *
		 *   .in [+/-N]
		 */
		set (&dc.inval, val, argtyp, 0, 0, dc.rmval - 1);
		set_ireg (".i", dc.inval, 0);
		dc.tival = dc.inval;
		break;
	case JU:
		/*
		 *   justify
		 *
		 *   .ju
		 */
		dc.juval = YES;
		break;
	case LL:
		/*
		 *   line length
		 *
		 *   .ll [+/-N]
		 *   .rm [+/-N]
		 */
		set (&dc.rmval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE);
		set (&dc.llval, val, argtyp, PAGEWIDTH, dc.tival + 1, HUGE);
		set_ireg (".l", dc.llval, 0);
		break;
	case LS:
		/*
		 *   line spacing
		 *
		 *   .ls [+/-N=+1]
		 */
		set (&dc.lsval, val, argtyp, 1, 1, HUGE);
		set_ireg (".v", dc.lsval, 0);
		break;
	case LT:
		/*
		 *   title length
		 *
		 *   .lt N
		 */
		set (&dc.ltval, val, argtyp, PAGEWIDTH, 0, HUGE);
		pg.ehlim[RIGHT] = dc.ltval;
		pg.ohlim[RIGHT] = dc.ltval;
		break;
	case M1:
		/*
		 *   topmost margin
		 *
		 *   .m1 N
		 */
		set (&pg.m1val, val, argtyp, 2, 0, HUGE);
		break;
	case M2:
		/*
		 *   second top margin
		 *
		 *   .m2 N
		 */
		set (&pg.m2val, val, argtyp, 2, 0, HUGE);
		break;
	case M3:
		/*
		 *   1st bottom margin
		 *
		 *   .m3 N
		 */
		set (&pg.m3val, val, argtyp, 2, 0, HUGE);
		pg.bottom = pg.plval - pg.m4val - pg.m3val;
		break;
	case M4:
		/*
		 *   bottom-most marg
		 *
		 *   .m4 N
		 */
		set (&pg.m4val, val, argtyp, 2, 0, HUGE);
		pg.bottom = pg.plval - pg.m4val - pg.m3val;
		break;
	case MACRO:
		/*
		 *   macro expansion
		 *
		 *   (internal)
		 */
		maceval (p, macexp);
		break;
	case NA:
		/*
		 *   no adjust
		 *
		 *   .na
		 */
		dc.adjval = ADJ_OFF;
		dc.juval  = NO;
		break;
	case NE:
		/*
		 *   need n lines
		 *
		 *   .ne N
		 */
		robrk ();
		if ((pg.bottom - pg.lineno + 1) < (val * dc.lsval))
		{
			space (HUGE);
		}
		break;
	case NF:
		/*
		 *   no fill
		 *
		 *   .nf
		 */
		robrk ();
		dc.fill = NO;
		break;
	case NJ:
		/*
		 *   no justify
		 *
		 *   .nj
		 */
		dc.juval = NO;
		break;
	case NR:
		/*
		 *   set number reg
		 *
		 *   .nr R +/-N M
		 */
		p = skipwd (p);
		p = skipbl (p);
		if (!isalpha (*p))
		{
			fprintf (err_stream,
				"***%s: invalid or missing number register name\n",
				myname);
		}
		else
		{
			/*
			 *   indx is the register, R, and val is the final
			 *   value (default = 0). getval does skipwd,skipbl
			 */
			indx = tolower (*p) - 'a';
			val = getval (p, &argtyp);
			set (&dc.nr[indx], val, argtyp, 0, -INFINITE, INFINITE);

			/*
			 *   now get autoincrement M, if any (default = 1).
			 *   getval does skipwd,skipbl
			 */
			p = skipwd (p);
			p = skipbl (p);
			val = getval (p, &argtyp);
			set (&dc.nrauto[indx], val, '1', 1, -INFINITE, INFINITE);
		}
		break;
	case OF:
		/*
		 *   odd footer
		 *
		 *   .of "a" "b" "c"
		 */
		gettl (p, pg.ofoot, &pg.oflim[0]);
		break;
	case OH:
		/*
		 *   odd header
		 *
		 *   .oh "a" "b" "c"
		 */
		gettl (p, pg.ohead, &pg.ohlim[0]);
		break;
	case PC:
		/*
		 *   page number char
		 *
		 *   .pc [c=NULL]
		 */
		if (argtyp == '\r' || argtyp == '\n')
			dc.pgchr = EOS;
		else
			dc.pgchr = argtyp;
		break;
	case PL:
		/*
		 *   page length
		 *
		 *   .pl N
		 */
		set (&pg.plval,
		     val,
		     argtyp,
		     PAGELEN,
		     pg.m1val + pg.m2val + pg.m3val + pg.m4val + 1,
		     HUGE);
		set_ireg (".p", pg.plval, 0);
		pg.bottom = pg.plval - pg.m3val - pg.m4val;
		break;
	case PM:
		/*
		 *   print macro names and sizes
		 *
		 *   .pm [t]
		 */
		if (argtyp == '\r' || argtyp == '\n')
			printmac (0);
		else if (argtyp == 't')
			printmac (1);
		else if (argtyp == 'T')
			printmac (2);
		else
			printmac (0);
		break;
	case PN:
		/*
		 *   page number
		 *
		 *   .pn N
		 */
		tmp = pg.curpag;
		set (&pg.curpag, val - 1, argtyp, tmp, -HUGE, HUGE);
		pg.newpag = pg.curpag + 1;
		set_ireg ("%", pg.newpag, 0);
		break;
	case PO:
		/*
		 *   page offset
		 *
		 *   .po N
		 */
		set (&pg.offset, val, argtyp, 0, 0, HUGE);
		set_ireg (".o", pg.offset, 0);
		break;
	case RR:
		/*
		 *   unset number reg
		 *
		 *   .rr R
		 */
		p = skipwd (p);
		p = skipbl (p);
		if (!isalpha (*p))
		{
			fprintf (err_stream,
				"***%s: invalid or missing number register name\n",
				myname);
		}
		else
		{
			indx = tolower (*p) - 'a';
			val = 0;
			set (&dc.nr[indx], val, argtyp, 0, -HUGE, HUGE);
		}
		break;
	case SO:
		/*
		 *   source file
		 *
		 *   .so name
		 */
		p = skipwd (p);
		p = skipbl (p);
		if (getwrd (p, name) == 0)
			break;
		if (dc.flevel + 1 >= Nfiles)
		{
			fprintf (err_stream,
				"***%s: .so commands nested too deeply\n",
				myname);
			err_exit (-1);
		}
		if ((sofile[dc.flevel + 1] = fopen (name, "r")) == NULL)
		{
			fprintf (err_stream,
				"***%s: unable to open %s\n", myname, name);
			err_exit (-1);
		}
		dc.flevel += 1;
		break;
	case SP:
		/*
		 *   space
		 *
		 *   .sp [N=1]
		 */
		set (&spval, val, argtyp, 1, 0, HUGE);
		space (spval);
		break;
	case TI:
		/*
		 *   temporary indent
		 *
		 *   .ti [+/-N]
		 */
		robrk ();
		set (&dc.tival, val, argtyp, 0, 0, dc.rmval);
		break;
	case UL:
		/*
		 *   underline
		 *
		 *   .ul [N]
		 */
		set (&dc.ulval, val, argtyp, 0, 1, HUGE);
		dc.cuval = dc.boval = 0;
		break;
	}
}





/*------------------------------*/
/*	comtyp			*/
/*------------------------------*/
comtyp (p, m)
register char  *p;
char	       *m;
{

/*
 *	decodes nro command and returns its associated
 *	value.
 */

	register char	c1;
	register char	c2;
	char	       *s;
	char    	macnam[MNLEN];

	/*
	 *   skip past dot and any whitespace
	 */
	p++;
	while (*p && (*p == ' ' || *p == '\t'))
		p++;
	if (*p == '\0')
		return (COMMENT);

	/* 
	 *	First check to see if the command is a macro.
	 *	If it is, truncate to two characters and return
	 *	expansion in m.  Note that upper and lower case
	 *	characters are handled differently.
	 */
	getwrd (p, macnam);
	macnam[2] = EOS;
	if ((s = getmac (macnam)) != NULL)
	{
		strcpy (m, s);
		return (MACRO);
	}
	c1 = *p++;
	c2 = *p;
	if (c1 == '\\' && c2 == '\"')		return (COMMENT);
	if (c1 == 'a' && c2 == 'f')		return (AF);
	if (c1 == 'a' && c2 == 'd')		return (AD);
	if (c1 == 'b' && c2 == 'o')		return (BO);
	if (c1 == 'b' && c2 == 'p')		return (BP);
	if (c1 == 'b' && c2 == 'r')		return (BR);
	if (c1 == 'b' && c2 == 's')		return (BS);
	if (c1 == 'c' && c2 == 'c')		return (CC);
	if (c1 == 'c' && c2 == 'e')		return (CE);
	if (c1 == 'c' && c2 == 'u')		return (CU);
	if (c1 == 'd' && c2 == 'e')		return (DE);
	if (c1 == 'd' && c2 == 's')		return (DS);
	if (c1 == 'e' && c2 == 'f')		return (EF);
	if (c1 == 'e' && c2 == 'c')		return (EC);
	if (c1 == 'e' && c2 == 'h')		return (EH);
	if (c1 == 'e' && c2 == 'n')		return (EN);
	if (c1 == '.')				return (EN);
	if (c1 == 'e' && c2 == 'o')		return (EO);
	if (c1 == 'f' && c2 == 'i')		return (FI);
	if (c1 == 'f' && c2 == 'l')		return (FL);
	if (c1 == 'f' && c2 == 'o')		return (FO);
	if (c1 == 'f' && c2 == 't')		return (FT);
	if (c1 == 'h' && c2 == 'e')		return (HE);
	if (c1 == 'i' && c2 == 'n')		return (IN);
	if (c1 == 'j' && c2 == 'u')		return (JU);
	if (c1 == 'l' && c2 == 'l')		return (LL);
	if (c1 == 'l' && c2 == 's')		return (LS);
	if (c1 == 'm' && c2 == '1')		return (M1);
	if (c1 == 'm' && c2 == '2')		return (M2);
	if (c1 == 'm' && c2 == '3')		return (M3);
	if (c1 == 'm' && c2 == '4')		return (M4);
	if (c1 == 'n' && c2 == 'a')		return (NA);
	if (c1 == 'n' && c2 == 'e')		return (NE);
	if (c1 == 'n' && c2 == 'f')		return (NF);
	if (c1 == 'n' && c2 == 'j')		return (NJ);
	if (c1 == 'n' && c2 == 'r')		return (NR);
	if (c1 == 'o' && c2 == 'f')		return (OF);
	if (c1 == 'o' && c2 == 'h')		return (OH);
	if (c1 == 'p' && c2 == 'c')		return (PC);
	if (c1 == 'p' && c2 == 'l')		return (PL);
	if (c1 == 'p' && c2 == 'm')		return (PM);
	if (c1 == 'p' && c2 == 'o')		return (PO);
	if (c1 == 'r' && c2 == 'm')		return (RM);
	if (c1 == 'r' && c2 == 'r')		return (RR);
	if (c1 == 's' && c2 == 'o')		return (SO);
	if (c1 == 's' && c2 == 'p')		return (SP);
	if (c1 == 't' && c2 == 'i')		return (TI);
	if (c1 == 't' && c2 == 'l')		return (TL);
	if (c1 == 'u' && c2 == 'l')		return (UL);

	if (c1 == 'p' && c2 == 'n')		return (PN);
	if (c1 == 'r' && c2 == 'r')		return (RR);
	if (c1 == 'c' && c2 == '2')		return (C2);
	if (c1 == 't' && c2 == 'r')		return (TR);
	if (c1 == 'l' && c2 == 't')		return (LT);
	if (c1 == 'f' && c2 == 'c')		return (FC);

	return (UNKNOWN);
}





/*------------------------------*/
/*	gettl			*/
/*------------------------------*/
gettl (p, q, limit)
register char  *p;
register char  *q;
int		limit[];
{

/*
 *	get header or footer title
 */

	/*
	 *   skip forward a word...
	 */
	p = skipwd (p);
	p = skipbl (p);

	/*
	 *   copy and set limits
	 */
	strcpy (q, p);
	limit[LEFT]  = dc.inval;
	limit[RIGHT] = dc.rmval;
}





/*------------------------------*/
/*	getval			*/
/*------------------------------*/
getval (p, p_argt)
register char  *p;
register char  *p_argt;
{

/*
 *	retrieves optional argument following nro command.
 *	returns positive integer value with sign (if any)
 *	saved in character addressed by p_argt.
 */

	p = skipwd (p);
	p = skipbl (p);
	*p_argt = *p;
	if ((*p == '+') || (*p == '-'))
		++p;
	return (ctod (p));
}




/*------------------------------*/
/*	set			*/
/*------------------------------*/
set (param, val, type, defval, minval, maxval)
register int   *param;
register int	val;
register char	type;
register int	defval;
register int	minval;
register int	maxval;
{

/*
 *	set parameter and check range. this is for basically all commands
 *	which take interger args
 *
 *	no param (i.e. \r or \n) means reset default
 *	+ means param += val (increment)
 *	- means param -= val (decrement)
 *	anything else makes an assignment within the defined numerical limits
 *
 *	examples:
 *
 *	.nr a 14	set register 'a' to 14
 *	.nr a +1	increment register 'a' by 1
 *	.nr a		reset register 'a' to default value (0)
 */

	switch (type)
	{
	case '\r': 
	case '\n': 
		*param = defval;
		break;
	case '+': 
		*param += val;
		break;
	case '-': 
		*param -= val;
		break;
	default: 
		*param = val;
		break;
	}
	*param = min (*param, maxval);
	*param = max (*param, minval);
}





/*------------------------------*/
/*	set_ireg		*/
/*------------------------------*/
set_ireg (name, val, opt)
register char  *name;
register int	val;
register int	opt;				/* 0=internal, 1=user set */
{

/*
 *	set internal register "name" to val. ret 0 if ok, else -1 if reg not
 *	found or 1 if read only
 */

	register int	nreg;

	nreg = findreg (name);
	if (nreg < 0)
		return (-1);

	if ((rg[nreg].rflag & RF_WRITE) || (opt == 0))
	{
		rg[nreg].rval = val;

		return (0);
	}

	return (1);
}

@//E*O*F command.c//
chmod u=rw,g=r,o=r command.c
 
echo x - text.c
sed 's/^@//' > "text.c" <<'@//E*O*F text.c//'
/*
 *	text.c - text output processing portion of nroff word processor
 *
 *	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
 */

#undef NRO_MAIN					/* extern globals */

#include <stdio.h>
#include "nroff.h"


/*------------------------------*/
/*	text			*/
/*------------------------------*/
text (p)
register char  *p;
{

/*
 *	main text processing
 */

	register int	i;
	char		wrdbuf[MAXLINE];


	/*
	 *   skip over leading blanks if in fill mode. we indent later.
	 *   since leadbl does a robrk, do it if in .nf mode
	 */
	if (dc.fill == YES)
	{
		if (*p == ' ' || *p == '\n' || *p == '\r')
			leadbl (p);
	}
	else
		robrk ();


	/*
	 *   expand escape sequences
	 */
	expesc (p, wrdbuf);


	/*
	 *   test for how to output
	 */
	if (dc.ulval > 0)
	{
		/*
		 *   underline (.ul)
		 *
		 *   Because of the way underlining is handled,
		 *   MAXLINE should be declared to be three times
		 *   larger than the longest expected input line
		 *   for underlining.  Since many of the character
		 *   buffers use this parameter, a lot of memory
		 *   can be allocated when it may not really be
		 *   needed.  A MAXLINE of 180 would allow about
		 *   60 characters in the output line to be
		 *   underlined (remember that only alphanumerics
		 *   get underlined - no spaces or punctuation).
		 */
		underl (p, wrdbuf, MAXLINE);
		--dc.ulval;
	}
	if (dc.cuval > 0)
	{
		/*
		 *   continuous underline (.cu)
		 */
		underl (p, wrdbuf, MAXLINE);
		--dc.cuval;
	}
	if (dc.boval > 0)
	{
		/*
		 *   bold (.bo)
		 */
		bold (p, wrdbuf, MAXLINE);
		--dc.boval;
	}
	if (dc.ceval > 0)
	{
		/*
		 *   centered (.ce)
		 */
		center (p);
		put (p);
		--dc.ceval;
	}
	else if ((*p == '\r' || *p == '\n') && dc.fill == NO)
	{
		/*
		 *   all blank line
		 */
		put (p);
	}
	else if (dc.fill == NO)
	{
		/*
		 *   unfilled (.nf)
		 */
		put (p);
	}
	else
	{
		/*
		 *   anything else...
		 *
		 *   init escape char counter for this line...
		 */
		co.outesc = 0;


		/*
		 *   get a word and put it out. increment ptr to the next
		 *   word.
		 */
		while ((i = getwrd (p, wrdbuf)) > 0)
		{
			co.outesc += countesc (wrdbuf);

			putwrd (wrdbuf);
			p += i;
		}
	}
}




/*------------------------------*/
/*	bold			*/
/*------------------------------*/
bold (p0, p1, size)
register char  *p0;
register char  *p1;
int		size;
{

/*
 *	insert bold face text (by overstriking)
 */

	register int	i;
	register int	j;

	j = 0;
	for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i)
	{
		if (isalpha (p0[i]) || isdigit (p0[i]))
		{
			p1[j++] = p0[i];
			p1[j++] = '\b';
		}
		p1[j++] = p0[i];
	}
	p1[j++] = '\n';
	p1[j] = EOS;
	while (*p1 != EOS)
		*p0++ = *p1++;
	*p0 = EOS;
}






/*------------------------------*/
/*	center			*/
/*------------------------------*/
center (p)
register char  *p;
{

/*
 *	center a line by setting tival
 */

	dc.tival = max ((dc.rmval + dc.tival - width (p)) >> 1, 0);
}




/*------------------------------*/
/*	expand			*/
/*------------------------------*/
expand (p0, c, s)
register char  *p0;
char		c;
register char  *s;
{

/*
 *	expand title buffer to include character string
 */

	register char  *p;
	register char  *q;
	register char  *r;
	char    	tmp[MAXLINE];

	p = p0;
	q = tmp;
	while (*p != EOS)
	{
		if (*p == c)
		{
			r = s;
			while (*r != EOS)
				*q++ = *r++;
		}
		else
			*q++ = *p;
		++p;
	}
	*q = EOS;
	strcpy (p0, tmp);		/* copy it back */
}




/*------------------------------*/
/*	justcntr		*/
/*------------------------------*/
justcntr (p, q, limit)
register char  *p;
char	       *q;
int		limit[];
{

/*
 *	center title text into print buffer
 */

	register int	len;

	len = width (p);
	q   = &q[(limit[RIGHT] + limit[LEFT] - len) >> 1];
	while (*p != EOS)
		*q++ = *p++;
}





/*------------------------------*/
/*	justleft		*/
/*------------------------------*/
justleft (p, q, limit)
register char  *p;
char	       *q;
int		limit;
{

/*
 *	left justify title text into print buffer
 */

	q = &q[limit];
	while (*p != EOS)
		*q++ = *p++;
}




/*------------------------------*/
/*	justrite		*/
/*------------------------------*/
justrite (p, q, limit)
register char  *p;
char	       *q;
int     	limit;
{

/*
 *	right justify title text into print buffer
 */

	register int	len;

	len = width (p);
	q = &q[limit - len];
	while (*p != EOS)
		*q++ = *p++;
}






/*------------------------------*/
/*	leadbl			*/
/*------------------------------*/
leadbl (p)
register char  *p;
{

/*
 *	delete leading blanks, set tival
 */

	register int	i;
	register int	j;

	/*
	 *   end current line and reset co struct
	 */
	robrk ();

	/*
	 *   skip spaces
	 */
	for (i = 0; p[i] == ' ' || p[i] == '\t'; ++i)
		;

	/*
	 *   if not end of line, reset current temp indent
	 */
	if (p[i] != '\n' && p[i] != '\r')
		dc.tival = i;

	/*
	 *   shift string
	 */
	for (j = 0; p[i] != EOS; ++j)
		p[j] = p[i++];
	p[j] = EOS;
}





/*------------------------------*/
/*	pfoot			*/
/*------------------------------*/
pfoot ()
{

/*
 *	put out page footer
 */

	if (dc.prflg == TRUE)
	{
		skip (pg.m3val);
		if (pg.m4val > 0)
		{
			if ((pg.curpag % 2) == 0)
			{
				puttl (pg.efoot, pg.eflim, pg.curpag);
			}
			else
			{
				puttl (pg.ofoot, pg.oflim, pg.curpag);
			}
			skip (pg.m4val - 1);
		}
	}
}





/*------------------------------*/
/*	phead			*/
/*------------------------------*/
phead ()
{

/*
 *	put out page header
 */

	pg.curpag = pg.newpag;
	if (pg.curpag >= pg.frstpg && pg.curpag <= pg.lastpg)
	{
		dc.prflg = TRUE;
	}
	else
	{
		dc.prflg = FALSE;
	}
	++pg.newpag;
	set_ireg ("%", pg.newpag, 0);
	if (dc.prflg == TRUE)
	{
		if (pg.m1val > 0)
		{
			skip (pg.m1val - 1);
			if ((pg.curpag % 2) == 0)
			{
				puttl (pg.ehead, pg.ehlim, pg.curpag);
			}
			else
			{
				puttl (pg.ohead, pg.ohlim, pg.curpag);
			}
		}
		skip (pg.m2val);
	}
	/* 
	 *	initialize lineno for the next page
	 */
	pg.lineno = pg.m1val + pg.m2val + 1;
	set_ireg ("ln", pg.lineno, 0);
}




/*------------------------------*/
/*	puttl			*/
/*------------------------------*/
puttl (p, lim, pgno)
register char  *p;
int		lim[];
int		pgno;
{

/*
 *	put out title or footer
 */

	register int	i;
	char		pn[8];
	char		t[MAXLINE];
	char		h[MAXLINE];
	char		delim;

	itoda (pgno, pn, 6);
	for (i = 0; i < MAXLINE; ++i)
		h[i] = ' ';
	delim = *p++;
	p = getfield (p, t, delim);
	expand (t, dc.pgchr, pn);
	justleft (t, h, lim[LEFT]);
	p = getfield (p, t, delim);
	expand (t, dc.pgchr, pn);
	justcntr (t, h, lim);
	p = getfield (p, t, delim);
	expand (t, dc.pgchr, pn);
	justrite (t, h, lim[RIGHT]);
	for (i = MAXLINE - 4; h[i] == ' '; --i)
		h[i] = EOS;
	h[++i] = '\n';
	h[++i] = '\r';
	h[++i] = EOS;
	if (strlen (h) > 2)
	{
		for (i = 0; i < pg.offset; ++i)
			prchar (' ', pout);
	}
	putlin (h, pout);
}





/*------------------------------*/
/*	putwrd			*/
/*------------------------------*/
putwrd (wrdbuf)
register char  *wrdbuf;
{

/*
 *	put word in output buffer
 */

	register char  *p0;
	register char  *p1;
	int     	w;
	int     	last;
	int     	llval;
	int     	nextra;



	/*
	 *   check if this word puts us over the limit
	 */
	w     = width (wrdbuf);
	last  = strlen (wrdbuf) + co.outp;
	llval = dc.rmval - dc.tival;
	if (((co.outp > 0) && ((co.outw + w) > llval))
	||   (last > MAXLINE))
	{
		/*
		 *   last word exceeds limit so prepare to break line, print
		 *   it, and reset outbuf.
		 */
		last -= co.outp;
		if (dc.juval == YES)
		{
			nextra = llval - co.outw + 1;

			/* 
			 *	Check whether last word was end of
			 *	sentence and modify counts so that
			 *	it is right justified.
			 */
			if (co.outbuf[co.outp - 2] == ' ')
			{
				--co.outp;
				++nextra;
			}
			spread (co.outbuf, co.outp - 1, nextra, co.outwds, co.outesc);
			if ((nextra > 0) && (co.outwds > 1))
			{
				co.outp += (nextra - 1);
			}
/*			if (co.outesc > 0)
			{
				co.outp += co.outesc;
			}
*/
		}

		/*
		 *   break line, output it, and reset all co members. reset
		 *   esc count.
		 */
		robrk ();

		co.outesc = countesc (wrdbuf);
	}


	/*
	 *   copy the current word to the out buffer which may have been
	 *   reset
	 */
	p0 = wrdbuf;
	p1 = co.outbuf + co.outp;
	while (*p0 != EOS)
		*p1++ = *p0++;

	co.outp              = last;
	co.outbuf[co.outp++] = ' ';
	co.outw             += w + 1;
	co.outwds           += 1;
}




/*------------------------------*/
/*	skip			*/
/*------------------------------*/
skip (n)
register int	n;
{

/*
 *	skips the number of lines specified by n.
 */

	register int	i;

	if (dc.prflg == TRUE && n > 0)
	{
		for (i = 0; i < n; ++i)
		{
			prchar ('\n', pout);
		}
		prchar ('\r', pout);
	}
}





/*------------------------------*/
/*	spread			*/
/*------------------------------*/
spread (p, outp, nextra, outwds, escapes)
register char  *p;
int     	outp;
int		nextra;
int		outwds;
int		escapes;
{

/*
 *	spread words to justify right margin
 */

	register int	i;
	register int	j;
	register int	nb;
	register int	ne;
	register int	nholes;
	int		jmin;


	/*
	 *   quick sanity check...
	 */
	if ((nextra <= 0) || (outwds <= 1))
		return;


/*fflush (pout); fprintf (err_stream, "in spread: escapes = %d\n", escapes); fflush (err_stream);*/


	/*
	 *   set up for the spread and do it...
	 */
	dc.sprdir = ~dc.sprdir;
	ne        = nextra;
	nholes    = outwds - 1;			/* holes between words */
	i         = outp - 1;			/* last non-blank character */
	j         = min (MAXLINE - 3, i + ne);	/* leave room for CR,LF,EOS */
/*
	j        += escapes;
	if (p[i-1] == 27)
		j += 2;
	j = min (j, MAXLINE - 3);
*/
	while (i < j)
	{
		p[j] = p[i];
		if (p[i] == ' ')
		{
			if (dc.sprdir == 0)
				nb = (ne - 1) / nholes + 1;
			else
				nb = ne / nholes;
			ne -= nb;
			--nholes;
			for (; nb > 0; --nb)
			{
				--j;
				p[j] = ' ';
			}
		}
		--i;
		--j;
	}
}





/*------------------------------*/
/*	strkovr			*/
/*------------------------------*/
strkovr (p, q)
register char  *p;
register char  *q;
{

/*
 *	split overstrikes (backspaces) into seperate buffer
 */

	register char  *pp;
	int		bsflg;

	bsflg = FALSE;
	pp = p;
	while (*p != EOS)
	{
		*q = ' ';
		*pp = *p;
		++p;
		if (*p == '\b')
		{
			if (*pp >= ' ' && *pp <= '~')
			{
				bsflg = TRUE;
				*q = *pp;
				++p;
				*pp = *p;
				++p;
			}
		}
		++q;
		++pp;
	}
	*q++ = '\r';
	*q = *pp = EOS;

	return (bsflg);
}





/*------------------------------*/
/*	underl			*/
/*------------------------------*/
underl (p0, p1, size)
register char  *p0;
register char  *p1;
int		size;
{

/*
 *	underline a line
 */

	register int	i;
	register int	j;

	j = 0;
	for (i = 0; (p0[i] != '\n') && (j < size - 1); ++i)
	{
		if (p0[i] >= ' ' && p0[i] <= '~')
		{
			if (isalpha (p0[i]) || isdigit (p0[i]) || dc.cuval > 0)
			{
				p1[j++] = '_';
				p1[j++] = '\b';
			}
		}
		p1[j++] = p0[i];
	}
	p1[j++] = '\n';
	p1[j] = EOS;
	while (*p1 != EOS)
		*p0++ = *p1++;
	*p0 = EOS;
}




/*------------------------------*/
/*	width			*/
/*------------------------------*/
width (s)
register char  *s;
{

/*
 *	compute width of character string
 */

	register int	w;

	w = 0;
	while (*s != EOS)
	{
		if (*s == '\b')
			--w;
		else if (*s != '\n' && *s != '\r')
			++w;
		++s;
	}

	return (w);
}
@//E*O*F text.c//
chmod u=rw,g=r,o=r text.c
 
echo x - io.c
sed 's/^@//' > "io.c" <<'@//E*O*F io.c//'
/*
 *	io.c - low level I/O processing portion of nroff word processor
 *
 *	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
 */

#undef NRO_MAIN					/* extern globals */

#include <stdio.h>
#include "nroff.h"

/*------------------------------*/
/*	getlin			*/
/*------------------------------*/
getlin (p, in_buf)
char   *p;
FILE   *in_buf;
{

/*
 *	retrieve one line of input text
 */

	register char  *q;
	register int	i;
	int		c;
	int		nreg;

	q = p;
	for (i = 0; i < MAXLINE - 1; ++i)
	{
		c = ngetc (in_buf);
		if (c == EOF)
		{
			*q = EOS;
			c  = strlen (p);
			return (c == 0 ? EOF : c);
		}
		*q++ = c;
		if (c == '\n')
			break;
	}
	*q = EOS;

	nreg = findreg (".c");
	if (nreg > 0)
		set_ireg (".c", rg[nreg].rval + 1, 0);

	return (strlen (p));
}






/*------------------------------*/
/*	ngetc			*/
/*------------------------------*/
ngetc (infp)
FILE   *infp;
{

/*
 *	get character from input file or push back buffer
 */

	register int	c;

	if (mac.ppb >= &mac.pbb[0])
		c = *mac.ppb--;
	else
		c = getc (infp);

	return (c);
}



/*------------------------------*/
/*	pbstr			*/
/*------------------------------*/
pbstr (p)
char    p[];
{

/*
 *	Push back string into input stream
 */

	register int	i;

	/*
	 *   if string is null, we do nothing
	 */
	for (i = strlen (p) - 1; i >= 0; --i)
	{
		putbak (p[i]);
	}
}





/*------------------------------*/
/*	putbak			*/
/*------------------------------*/
putbak (c)
char    c;
{

/*
 *	Push character back into input stream. we use the push-back buffer
 *	stored with macros.
 */

	if (mac.ppb < &(mac.pbb[0]))
	{
		mac.ppb = &(mac.pbb[0]);
		*mac.ppb = c;
	}
	else
	{
		if (mac.ppb >= &mac.pbb[MAXLINE - 1])
		{
			fprintf (err_stream,
				"***%s: push back buffer overflow\n", myname);
			err_exit (-1);
		}
		*++(mac.ppb) = c;
	}
}



/*------------------------------*/
/*	prchar			*/
/*------------------------------*/
prchar (c, fp)
char    c;
FILE   *fp;
{

/*
 *	print character with test for printer
 */

	putc (c, fp);
}






/*------------------------------*/
/*	put			*/
/*------------------------------*/
put (p)
char   *p;
{

/*
 *	put out line with proper spacing and indenting
 */

	register int	j;
	char		os[MAXLINE];

	if (pg.lineno == 0 || pg.lineno > pg.bottom)
	{
		phead ();
	}
	if (dc.prflg == TRUE)
	{
		if (!dc.bsflg)
		{
			if (strkovr (p, os) == TRUE)
			{
				for (j = 0; j < pg.offset; ++j)
					prchar (' ', pout);
				for (j = 0; j < dc.tival; ++j)
					prchar (' ', pout);
				putlin (os, pout);
			}
		}
		for (j = 0; j < pg.offset; ++j)
			prchar (' ', pout);
		for (j = 0; j < dc.tival; ++j)
			prchar (' ', pout);
		putlin (p, pout);
	}
	dc.tival = dc.inval;
	skip (min (dc.lsval - 1, pg.bottom - pg.lineno));
	pg.lineno = pg.lineno + dc.lsval;
	set_ireg ("ln", pg.lineno, 0);
	if (pg.lineno > pg.bottom)
		pfoot ();
}




/*------------------------------*/
/*	putlin			*/
/*------------------------------*/
putlin (p, pbuf)
register char  *p;
FILE	       *pbuf;
{

/*
 *	output a null terminated string to the file
 *	specified by pbuf.
 */

	while (*p != EOS)
		prchar (*p++, pbuf);
}







@//E*O*F io.c//
chmod u=rw,g=r,o=r io.c
 
exit 0