[comp.sources.amiga] v89i020: nro - nroff-like text formatter, Part02/02

page@swan.ulowell.edu (Bob Page) (02/03/89)

Submitted-by: U211344@HNYKUN11.BITNET (Olaf 'Rhialto' Seibert)
Posting-number: Volume 89, Issue 20
Archive-name: applications/nro.2

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	.edrc
#	Notice
#	an
#	dump.c
#	makefile
#	makefile.unix
#	mkr
#	nro.c
#	nro.h
#	nro.n
#	nroxtrn.h
#	prnro.c
#	prnro.n
#	skeleton.n
#	table.c
# This archive created: Mon Jan 30 20:01:10 1989
cat << \SHAR_EOF > .edrc
savetabs off
SHAR_EOF
cat << \SHAR_EOF > Notice

This software is (C) Copyright 1988 by Olaf Seibert. All Rights Reserved.

This software is NOT in the public domain. It may not be sold or used for
profit without prior written consent from the author, Olaf Seibert.

Conditions for redistribution are:

- This notice must remain included at all times. It may not be modified in
  any way.

- No charge may be made for distribution above media and transportation
  costs.

- The source and documentation of the program must always be distributed
  with the binary, unless the distributor of said binary agrees to supply
  the source and documentation on request, with no expiration date on
  availability of said source and documentation.

- If any part of this program (source or binary) or its documentation is
  included in any other software package, either integrated or separately,
  these redistribution conditions automatically apply to the entire
  package, unless prior written permission is obtained from the author.

- No claim is made regarding the quality of this software or its
  documentation. It is supplied purely as-is. The author cannot be held
  responsible for any damages occurring directly or indirectly from using
  or not using this program.

The author can be reached at:

  Olaf Seibert
  p/a Beek 5
  5815 CS  Merselo
  The Netherlands
SHAR_EOF
cat << \SHAR_EOF > an
.*
.*	Macro package for NRO in KosmoSoft version
.*
.nr h 5 	 @" header indent
.nr i 10	 @" normal text indent
.nr s @ni-@nh	 @" section heading indent (to the LEFT)
.*
.de TH
.in @nh;.rm 80-@nh;.he |$0($1)|$2|$0($1)|
.fo |$3|-#-|$4|
.in @ni;.rm 80-@ni
.ta +0 +5
.en
.*  Paragraph
.de PP
.sp 1;.ne 2;.ti +5
.en
.*  Bulleted Paragraph. Needs .RE after last para.
.*  Must be last on line. Relies on first tab stop.
.de BP
.br;.in @ni+5;.ti -3;o@t@@
.en
.*  Section Heading
.de SH
.sp 1;.ne 3;.ti -@@ns;.bo "$0 $1 $2 $3 $4 $6 $6 $7 $8 $9
.br
.en
.*  SubSection
.de SS
.br;.ne 2;.ti -@@ns+1/2;$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
.br
.en
.*  Relative indent Start
.de RS
.in +0$0
.en
.*  Relative indent End
.de RE
.in @ni
.en
.*  Italics
.de I
.it 1
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
.en
.*  Bold
.de B
.bo 1
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
.en
.*  Underline
.de U
.ul 1
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
.en
.*  UC
.de UC
.*  Empty
.en
.*  Italics and Roman
.de IR
.if !''$0' .it "$0
.if !''$1' $1
.if !''$2' .it "$2
.if !''$3' $3
.if !''$4' .it "$4
.if !''$5' $5
.if !''$6' .it "$6
.if !''$7' $7
.if !''$8' .it "$8
.if !''$9' $9
.en
.*  Roman and Italic
.de RI
.if !''$0' $0
.if !''$1' .it "$1
.if !''$2' $2
.if !''$3' .it "$3
.if !''$4' $4
.if !''$5' .it "$5
.if !''$6' $6
.if !''$7' .it "$7
.if !''$8' $8
.if !''$9' .it "$9
.en
.*  Bold and Roman
.de BR
.if !''$0' .bo "$0
.if !''$1' $1
.if !''$2' .bo "$2
.if !''$3' $3
.if !''$4' .bo "$4
.if !''$5' $5
.if !''$6' .bo "$6
.if !''$7' $7
.if !''$8' .bo "$8
.if !''$9' $9
.en
.*  Bold and Italic
.de BI
.if !''$0' .bo "$0
.if !''$1' .it "$1
.if !''$2' .bo "$2
.if !''$3' .it "$3
.if !''$4' .bo "$4
.if !''$5' .it "$5
.if !''$6' .bo "$6
.if !''$7' .it "$7
.if !''$8' .bo "$8
.if !''$9' .it "$9
.en
.*  Italic and Bold
.de IB
.if !''$0' .it "$0
.if !''$1' .bo "$1
.if !''$2' .it "$2
.if !''$3' .bo "$3
.if !''$4' .it "$4
.if !''$5' .bo "$5
.if !''$6' .it "$6
.if !''$7' .bo "$7
.if !''$8' .it "$8
.if !''$9' .bo "$9
.en
.*  Italic and Roman
.de IR
.if !''$0' .it "$0
.if !''$1' $1
.if !''$2' .it "$2
.if !''$3' $3
.if !''$4' .it "$4
.if !''$5' $5
.if !''$6' .it "$6
.if !''$7' $7
.if !''$8' .it "$8
.if !''$9' $9
.en
.*  SMall, do nothing
.de SM
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9
.en
SHAR_EOF
cat << \SHAR_EOF > dump.c
/*	This file includes all files needed by nro. */

#include <stdio.h>
#include "nro.h"
#include "nroxtrn.h"
SHAR_EOF
cat << \SHAR_EOF > makefile
#
#		Makefile for NRO - text formatter
#

COPTS=	+L
CFLAGS= $(COPTS) +Idmp
OBJ=	nro.o nrocmd.o nrotxt.o table.o
HFILES= nro.h nroxtrn.h
CC=	cc

.PRECIOUS:	df1:n/man df1:n/nro.n man nro.n df1:n/nro.c df1:nrotxt.c \
		df1:n/nrocmd.c df1:nro.h df1:nroxtrn.h

nro:	dmp $(OBJ) $(HFILES)
		ln -O nro $(LFLAGS) $(OBJ) -LVD0:c32

prnro:	prnro.o
		ln -O prnro $(LFLAGS) prnro.o -LVD0:c32

table.o: table.c $(HFILES)
		cc $(COPTS) -o table.o table.c

nro.o:		$(HFILES)
nrotxt.o:	$(HFILES)
nrocmd.o:	$(HFILES)

dmp:	dump.c $(HFILES)
		cc $(COPTS) -A +Hdmp dump.c
		delete dump.asm

man:	nro.n nro an
		nro -man nro.n >man
		t man

#nro.n:  df1:n/nro.n
#		 copy df1:n/nro.n nro.n

an:		df1:n/an
		copy df1:n/an an

save:	df1:n/nro.c df1:n/nrocmd.c df1:n/nrotxt.c df1:n/prnro.c \
	df1:n/nro.n df1:n/nroxtrn.h

df1\:n/nro.h:	nro.h
		copy nro.h df1:n

df1\:n/nroxtrn.h:   nroxtrn.h
		copy nroxtrn.h df1:n

df1\:n/nro.c:	nro.c
		copy nro.c df1:n
		copy nro.o df1:n

df1\:n/nrotxt.c:   nrotxt.c
		copy nrotxt.c df1:n
		copy nrotxt.o df1:n

df1\:n/nrocmd.c:   nrocmd.c
		copy nrocmd.c df1:n
		copy nrocmd.o df1:n

df1\:n/prnro.c: prnro.c
		copy prnro.c df1:n
		copy prnro.o df1:n

df1\:n/nro.n:	nro.n
		copy nro.n df1:n
		copy man df1:n
SHAR_EOF
cat << \SHAR_EOF > makefile.unix
#
#	Makefile for NRO - text formatter
#

OBJ=	nro.o nrocmd.o nrotxt.o table.o
HFILES=	nro.h nroxtrn.h

nro:	$(OBJ)
	cc -o nro $(LFLAGS) $(OBJ)

$(OBJ): $(HFILES)

prnro:	prnro.c
	cc -o prnro prnro.c
lint:
	lint nro.c nrocmd.c nrotxt.c table.c

man:	nro.n nro an
	nro -b1 -v3 nro.n >man
	more man
SHAR_EOF
cat << \SHAR_EOF > mkr
failat 25
makedir ram:n
;copy SYS1:bin/cc ram:c
;copy SYS1:bin/as ram:c
;copy SYS1:bin/ln ram:c
copy :c32.lib ram:
;copy :make ram:c
copy #?.(c|o|h) ram:n
copy makefile ram:n
copy dmp ram:n
set CLIB=VD0: INCLUDE=SYS1:include CCTEMP=VD0:
cd ram:n
SHAR_EOF
cat << \SHAR_EOF > nro.c
/*
 *	NRO Text Formatter -
 *	similar to Unix NROFF or RSX-11M RNO -
 *	adaptation of text processor given in
 *	"Software Tools", Kernighan and Plauger.
 *
 *	Originally by Stephen L. Browning, 5723 North Parker Avenue
 *	Indianapolis, Indiana 46220
 *
 *	Transformed beyond immediate recognition, and
 *	adapted for Amiga by Olaf Seibert, KosmoSoft
 *
 *	Vossendijk 149-1 (study)   Beek 5 (home)
 *	5634 TN  Nijmegen	   5815 CS  Merselo
 *	The Netherlands 	   The Netherlands
 *	Phone:
 *	       (...-31)80561045     (...-31)4786205
 *	    or 080-561045	    04786-205
 *
 *	This program is NOT in the public domain. It may, however
 *	be distributed only at no charge, and this notice must be
 *	included unaltered.
 */

#include <stdio.h>
#include "nro.h"
#include "nroxtrn.h"


main(argc, argv)
int argc;
uchar *argv[];
{
	int i;
	int ofp;

	pout = stdout;
	ofp = 0;
	init();
	for (i=1; i<argc; i++) {
		if (*argv[i] == '-' || *argv[i] == '+') {
			pswitch(argv[i]);
		} else if (*argv[i] == '>') {
			if (ofp == 0) {
#ifdef CPM
				if (!strcmp(argv[i]+1, "$P")) {
					ofp = 1;
					co.lpr = TRUE;
				} else
#endif
				if ((pout = fopen(argv[i]+1, "w")) == NULL) {
					error("*** nro: cannot create %s\n", argv[i]+1);
				} else {
					ofp = 1;
				}
			} else {
				error("*** nro: too many output files\n");
			}
		}
	}

	for (i=1; i<argc; i++) {
		if (*argv[i] != '-' && *argv[i] != '+' && *argv[i] != '>') {
			if ((sofile[0] = fopen(argv[i], "r")) == NULL) {
				error("nro: unable to open file %s\n", argv[i]);
				continue;
			} else {
				if (verbose > 2)
					error("nro: processing file '%s'\n", argv[i]);
				profile();
				fclose(sofile[0]);
			}
		}
	}

	if (argc == 1) {
		error("Usage: nro [-#] [+#] [-p#] [-v] [-b#] [-rn#] [-rd#] [-rp#]\n"
		      "           [-mmacfile] infile(s) ... [>outfile]\n");
		fatal();
	} else {
		endfiles();
	}

#ifdef CMPEOF
	putc(CPMEOF, pout);
#endif CMPEOF
	fflush(pout);
	if (pout != stdout) {
		fclose(pout);
	}
}



/*
 *	Retrieve one line of input text
 */

getlin(p, infile)
uchar *p;
FILE *infile;
{
	int i;
	int c;
	uchar *q;

	q = p;
	for (i=0; i<MAXLINE-1; i++) {
		c = ngetc(infile);
#ifdef CPMEOF
		if (c == CPMEOF || c == EOF) {
#if 0
}	/* To keep ctags, cb and such happy */
#endif
#else
		if (c == EOF) {
#endif CPMEOF
			*q = EOS;
			return i == 0 ? EOF : 0;
		}
		*q++ = c;
		if (iseol(c)) break;
	}
	*q = EOS;
	return q - p;	/* strlen(p) */
}



/*
 *	Initialize parameters for nro word processor
 */

init()
{
	int i;
	static char nl[] = "\n";

	dc.bsflg   = FALSE;
	dc.curmode = FXPLAIN;
	dc.envsp   = 0;
	dc.envstack[0] = 0;
	for (i=0; i<26; i++) dc.nr[i] = 0;
#ifdef CPM
	dc.lpr	   = FALSE;
#endif

	for (i=0; i<NUMENV; i++) environ[i] = NULL;

	initenv();

	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   = 32767;
	pg.prflg   = TRUE;

	strncpy(pg.ehead, nl, MAXLINE);
	strncpy(pg.ohead, nl, MAXLINE);
	strncpy(pg.efoot, nl, MAXLINE);
	strncpy(pg.ofoot, nl, MAXLINE);

	pg.ehlim[LEFT] = pg.ohlim[LEFT] = env.inval;
	pg.eflim[LEFT] = pg.oflim[LEFT] = env.inval;
	pg.ehlim[RIGHT] = pg.ohlim[RIGHT] = env.rmval;
	pg.eflim[RIGHT] = pg.oflim[RIGHT] = env.rmval;

	mac.mxmdef = MXMDEF;
	mac.macbuf = MACBUF;
	mac.mxmlen = MXMLEN;
	mac.mnames = NULL;
	mac.mb	   = NULL;
	mac.pbb    = NULL;
	mac.lastp  = 0;
	mac.ppb    = NULL;
}


/*
 *	Initenv - initialise the environment to default
 */

initenv()
{
	int i;

	env.fill    = YES;
	env.lsval   = 1;
	env.inval   = 0;
	env.tival   = 0;
	env.rmval   = PAGEWIDTH - 1;
	env.tmval   = PAGEWIDTH - 1;
	env.ceval   = 0;
	env.ulval   = 0;
	env.cuval   = 0;
	env.boval   = 0;
	env.itval   = 0;
	env.juval   = YES;
	env.pgchr   = PGCHAR;
	env.cmdchr  = CMDCHAR;
	env.c2chr   = C2CHAR;
	env.sprdir  = 0;
	env.dontbrk = FALSE;
	env.reqmode = FXPLAIN;
	env.expmode = FXPLAIN;
	env.curmode = FXPLAIN;
	env.outp    = 0;
	env.outw    = 0;
	env.outwds  = 0;

	strncpy(env.outbuf, "", MAXLINE);

	for (i=0; i<MAXTAB; i++) env.tabstop[i] = NOTAB;
}


/*
 *	Initialize buffers for macros
 */

initbuffers()
{
	static short inited = FALSE;

	int i;

	if (inited)
		return;

	if ((mac.mnames=(uchar **)malloc(sizeof(*mac.mnames)*mac.mxmdef)) &&
	    (mac.mb    =(uchar *)malloc(sizeof(*mac.mb)    *mac.macbuf)) &&
	    (mac.pbb   =(uchar *)malloc(sizeof(*mac.pbb)   *mac.mxmlen)) ) {

		for (i=0; i<mac.mxmdef; i++) mac.mnames[i] = NULL;
		mac.emb = mac.mb;
		mac.ppb = mac.pbb - 1;
		mac.pbbend = mac.pbb + mac.mxmlen;

		if (verbose > 1) {
			error("nro: max number of macros: %d\n", mac.mxmdef);
			error("     max total length of macro definitions: %d\n",
					mac.macbuf);
			error("     max pushback characters: %d\n", mac.mxmlen);
		}
		inited = TRUE;
	} else {
		error("*** nro: cannot allocate memory for macro buffers\n");
	}
}

#define rawgetc(infp)\
	((mac.ppb >= mac.pbb) ? pbbgetc() : getc(infp))

#define pbbgetc()       (*mac.ppb--)

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

ngetc(infp)
FILE *infp;
{
	register int chr;
	int i, j;

again:
	chr = rawgetc(infp);

	if (chr != ESCCHAR) {
		if (dc.iflvl == 0) return chr;
		else goto again;
	}

	chr = rawgetc(infp);

	switch (chr) {
	case '\n':              /* Concealed newline */
		goto again;
	case ' ':               /* Non breakable space */
		chr =  NBSP;
		break;
	case '"':               /* A comment */
		while (isnteol(chr)) chr = rawgetc(infp);
		break;
	case ESCCHAR:		/* Escaped escape character */
	case 'e':               /* Current value of escape character */
		chr = ESCCHAR;
		break;
	case 'n':               /* Substitute numeric register */
		if (dc.iflvl) goto again;
		chr = rawgetc(infp);
		i = dc.nr[tolower(chr) - 'a'];
		j = abs(i);
		do {
			putbak('0' + j % 10);
			j /= 10;
		} while (j);
		if (i < 0)      chr = '-';
		else chr = pbbgetc();
		break;
	case 't':               /* Tab */
		chr = '\t';
		break;
	case 'X':               /* eXtended Character */
		chr = getval(&i, infp);
		break;
	case '{':               /* Begin of if block */
		if (dc.iflvl) dc.iflvl++;
		chr = BEGIF;
		break;
	case '}':               /* End of if block */
		if (dc.iflvl) dc.iflvl--;
		goto again;
			/* @. to conceal line beginning with command chr */
	default:	/* Dunno. Somebody is mistakin'. Maybe even EOF. */
		if (chr == env.cmdchr) chr |= 0x8000;
	}

	if (dc.iflvl) goto again;

	return chr;
}

/*
 *	Restore push back buffer after closing a file
 */

restorepbb()
{
	mac.ppb = mac.pbb - 1;	/* Should not even be necessary */
	mac.pbb = sopbb[dc.flevel - 1];
}


/*
 *	Process input files from command line
 */

profile()
{
	int chr;
	uchar ibuf[MAXWORD];

	initbuffers();

	for (dc.flevel=0; dc.flevel>=0; --dc.flevel) {
		infile = sofile[dc.flevel];
		while (ibuf[0] = chr = ngetc(infile), chr != EOF) {
			if (chr == env.cmdchr) {
				comand(ibuf);   /* Command line */
			} else
				text(ibuf, infile);             /* Text line */
		}
		if (dc.flevel > 0) {
			fclose(infile);
			restorepbb();
		}
	}
}


/*
 *	End processing of files: eject page if necessary.
 */

endfiles()
{
	if (pg.lineno > 0 || env.outp != 0)  space(pg.plval);
}


#define K *1024
#define M *1024 K

/*
 *	Process switch values from command line
 */

pswitch(p)
uchar *p;
{
	int swgood;

	swgood = TRUE;
	if (*p == '-') {
		switch (tolower(*++p)) {
		case 'b':
			set(&dc.bsflg, ctod(++p), '1', 1, 0, 2);
			break;
		case 'm':
			if ((sofile[0] = fopen(++p, "r")) == NULL) {
				error("*** nro: unable to open file %s\n", p);
			}
			if (verbose > 2)
				error("nro: processing file '%s'\n", p);
			profile();
			fclose(sofile[0]);
			break;
		case 'p':
			set(&pg.offset, ctod(++p), '1', 0, 0, HUGE);
			break;
		case 'r':       /* Reserve memory */
			switch(tolower(p[1])) {
			case 'd':       /* Total buffer for definitions */
				if (mac.mb == NULL)
					set(&mac.macbuf, ctod(&p[2]), '1', MACBUF, 0, 16 M);
				else swgood = FALSE;
				break;
			case 'n':       /* Number of definitions */
				if (mac.mnames == NULL)
					set(&mac.mxmdef, ctod(&p[2]), '1', MXMDEF, 0, 10 K);
				else swgood = FALSE;
				break;
			case 'p':       /* Pushback buffer */
				if (mac.pbb == NULL)
					set(&mac.mxmlen, ctod(&p[2]), '1', MXMLEN, 0, 100 K);
				else swgood = FALSE;
				break;
			default:
				swgood = FALSE;
			}
			break;
		case 'v':
			error("NRO - KosmoSoft version 1.5 - V25.06.88\n");
			verbose = max(1,ctod(++p));
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			pg.lastpg = ctod(p);
			break;
		default:
			swgood = FALSE;
			break;
		}
	} else if (*p == '+') {
		pg.frstpg = ctod(++p);
	} else {
		swgood = FALSE;
	}
	if (swgood == FALSE) {
		error("*** nro: illegal switch %s\n", p);
	}
	return;
}

#undef K
#undef M


/*
 *	Print a message at the standard error channel
 */

/*VARARGS1*/
error(format, arg1, arg2, arg3)
uchar *format;
long arg1, arg2, arg3;
{
	fflush(pout);
	fprintf(stderr, format, arg1, arg2, arg3);

	if (*format == '*')
		fatal();
}

/*
 *	fatal - cannot recover from a serious error
 */

fatal()
{
	exit(10);
}

int tolower(c)
register char c;
{
	if (c >= 'A' && c <= 'Z')
		return c - 'A' + 'a';
	return c;
}

int toupper(c)
register char c;
{
	if (c >= 'a' && c <= 'z')
		return c - 'a' + 'A';
	return c;
}
SHAR_EOF
cat << \SHAR_EOF > nro.h

/*
 *	Parameter file for NRO word processor
 *
 *	Originally by Stephen L. Browning, 5723 North Parker Avenue
 *	Indianapolis, Indiana 46220
 *
 *	Transformed beyond immediate recognition, and
 *	adapted for Amiga by Olaf Seibert, KosmoSoft
 *
 *	Vossendijk 149-1 (study)   Beek 5 (home)
 *	5634 TN  Nijmegen          5815 CS  Merselo
 *	The Netherlands            The Netherlands
 *	Phone:
 *	       (...-31)80561045     (...-31)4786205
 *	    or 080-561045           04786-205
 *
 *	This program is NOT in the public domain. It may, however
 *	be distributed only at no charge, and this notice must be
 *	included unaltered.
 */


#include <ctype.h>
#undef tolower
#undef toupper

typedef unsigned char uchar;
typedef unsigned short ushort;

#define EOS	(uchar) '\0'
#define ESC	(uchar) 0x1B
#undef  CPMEOF	(uchar) 0x1A
#define NBSP	(uchar) 0xA0

#define TRUE	1
#define FALSE	0
#define OK	0

#define NOARGS	0x8000

#define MACRO	 0      /* Macro definition */
#define BP	 1      /* Begin page   */
#define BR	 2      /* Break        */
#define CE	 3      /* Center       */
#define FI	 4      /* Fill         */
#define FO	 5      /* Footer       */
#define HE	 6      /* Header       */
#define IN	 7      /* Indent       */
#define LS	 8      /* Line spacing */
#define NF	 9      /* No fill      */
#define PL	10      /* Page lenght  */
#define RM	11      /* Right margin */
#define SP	12      /* Line space   */
#define TI	13      /* Temp indent  */
#define UL	14      /* Underline    */
#define JU	15      /* Justify      */
#define NJ	16      /* No justify   */
#define M1	17      /* Top margin   */
#define M2	18      /* Second top margin    */
#define M3	19      /* First bottom margin  */
#define M4	20      /* Bottom-most margin   */
#define BS	21      /* Allow/disallow '\b' in output */
#define NE	22      /* Need n lines */
#define PC	23      /* Page number character */
#define CC	24      /* Control character    */
#define PO	25      /* Page offset  */
#define BO	26      /* Bold face    */
#define EH	27      /* Header for even numbered pages       */
#define OH	28      /* Header for odd numbered pages        */
#define EF	29      /* Footer for even numbered pages       */
#define OF	30      /* Footer for odd numbered pages        */
#define SO	31      /* Source file  */
#define CU	32      /* Continuous underline */
#define DE	33      /* Define macro */
#define EN	34      /* End macro definition */
#define NR	35      /* Set number register  */
#define IT	36	/* italicize    */
#define UN	37	/* Undefine a macro and all later ones */
#define PN	38	/* Page numbering - roman or arabic */
#define C2	39	/* No-break second command character */
#define COMMENT	40	/* What the name says */
#define IF	41	/* Conditional without remembering */
#define IE	42	/* Conditional with remembering */
#define EL	43	/* Else part of last remembered conditional */
#define EV	44	/* Environment switch */
#define TA	45	/* Tab settings */
#define TM	46	/* Terminal Message */


#define UNKNOWN -1

/*
 *      MAXLINE is set to a value slightly larger
 *      than twice the longest expected input line.
 *      Because of the way underlining is handled, the
 *      input line which is to be underlined, can almost
 *      triple in length.  Unlike normal underlining and
 *      boldfacing, continuous underlining affects all
 *      characters in the buffer, and represents the
 *      worst case condition.  If the distance between
 *      the left margin and the right margin is greater
 *      than about 65 characters, and continuous underlining
 *      is in effect, there is a high probability of buffer
 *      overflow.
 *	On the Amiga, we can use the standard codes for 
 *	bold, underline, and even italics, and let the
 *	printer driver worry about it.
 */

#define MAXLINE		300	/* Was 200 */
#define MAXWORD		50
#define MAXTAB		10
#define NOTAB		((ushort) -1)
#define PAGELEN		66
#define PAGEWIDTH	80
#define HUGE		0x7FFFffff
#define LEFT		0	/* Indecies into header margin limit arrays */
#define RIGHT		1
#define NFILES		4	/* Nesting depth for input files */

/*
 *      The following parameters may be defined in bdscio.h
 */

#define YES     1
#define NO      0
#define ERR     -1

/*
 *      The parameter values selected for macro definitions
 *      are somewhat arbitrary.  MACBUF is the storage area
 *      for both macro names and definitions.  Since macro
 *      processing is handled by pushing back the expansion
 *      into the pushback buffer, the longest possible expansion
 *      would be MXMLEN characters.
 *      It is assumed that most macro definitions will not
 *      exceed 20 characters, hence MXMDEF of 100.
 */

#define MXMDEF  512             /* Maximum no. of macro definitions */
#define MACBUF  20480           /* Macro definition buffer */
#define MXMLEN  1024            /* Maximum length of each macro pushback */
#define MNLEN   10              /* Maximum length of macro name */

struct macros {
	int   mxmdef;		/* See MXMDEF */
	int   macbuf;
	int   mxmlen;
        uchar **mnames;		/* Table of pointers to macro names */
        int   lastp;		/* Index to last mname  */
        uchar *emb;		/* Next char avail in macro defn buffer */
        uchar *mb;		/* Table of macro definitions */
        uchar *ppb;		/* Pointer into push back buffer */
        uchar *pbb;		/* Push back buffer */
		uchar *pbbend;	/* End of push back buffer */
};


/* Control parameters for nro */

#define NUMENV		10
#define ENVSTACK	20

struct environ {
        int   lsval;	/* Current line spacing, init = 1       */
        int   tival;	/* Current temp indent, init = 0        */
        int   inval;	/* Current indent, >= 0, init = 0       */
        int   tmval;	/* Current temp right margin, init = 60 */
        int   rmval;	/* Current right margin, init = 60      */
        int   ceval;	/* Number of lines to center, init = 0  */
        int   ulval;	/* Number of lines to underline, init = 0 */
        int   cuval;	/* No. lines to continuously underline, init = 0 */
	int   itval;	/* Number of lines to italicize, init = 0 */
        int   juval;	/* Justify if YES, init = YES           */
        int   boval;	/* Number of lines to bold face, init = 0 */

        int   fill;	/* Fill if YES, init = YES              */
	int   pnflg;	/* Value for page numbering, init = 0   */
	short dontbrk;	/* Disables line breaking, init = FALSE */

        int   pgchr;	/* Page number character, init = '#'    */
        int   cmdchr;	/* Command character, init = '.'        */
        int   c2chr;	/* No-break cmd character, init = '\''  */
        int   sprdir;	/* Direction for spread(), init = 0     */

	short reqmode;	/* Requested mode for bold underline &c */
	short expmode;	/* Expected mode at begin of output buffer */
	short curmode;	/* Current mode in output buffer        */

	short lastie;	/* Remembered conditional               */

        short outp;	/* Next avail char position in outbuf, init = 0 */
        short outw;	/* Width of text currently in buffer    */
        short outwds;	/* Number of words in buffer, init = 0  */
        uchar outbuf[MAXLINE];	/* Output of filled text        */
	ushort tabstop[MAXTAB]; /* Tab settings                 */
};

/* Global variables: */

struct docctl {		/* -- These should not be pushable: --  */
        int   bsflg;	/* Can output contain '\b', init = FALSE */
	short iflvl;	/* Number of @} 's to be skipped        */
        short flevel;	/* Nesting depth for source cmd, init = 0 */
        int   nr[26];	/* Number registers                     */
	short curmode;	/* Current mode at end of printer       */
	uchar envstack[ENVSTACK];
	uchar envsp;	/* Current environment stack depth      */
#ifdef CPM
        short lpr;	/* Output to printer, init = FALSE      */
#endif
};


/* Page control parameters for nro */

struct page {
        int   curpag;	/* Current output page number, init =0  */
        int   newpag;	/* Next output page number, init = 1    */
        int   lineno;	/* Next line to be printed, init = 0    */
        int   plval;	/* Page length in lines, init = 66      */
        int   m1val;	/* Margin before and including header   */
        int   m2val;	/* Margin after header                  */
        int   m3val;	/* Margin after last text line          */
        int   m4val;	/* Bottom margin, including footer      */
        int   bottom;	/* Last live line on page               */
			/*   = plval - m3val - m4val            */
        int   offset;	/* Page offset from left, init = 0      */
        int   frstpg;	/* First page to print, init = 0        */
        int   lastpg;	/* Last page to print, init = 30000     */
        int   prflg;	/* Print on or off, init = TRUE         */
        int   ehlim[2];	/* Left/right margins for headers/footers     */
        int   ohlim[2];	/* Init = 0 and PAGEWIDTH                     */
        int   eflim[2];
        int   oflim[2];
        uchar ehead[MAXLINE];	/* Top of page title, init = '\n'     */
        uchar ohead[MAXLINE];
        uchar efoot[MAXLINE];	/* Bottom of page title, init = '\n'  */
        uchar ofoot[MAXLINE];
};

#define BSAMIGA   0  /* Use Amiga command sequences for bold & underline */
#define BSYES     1  /* Use backspaces for bold & underline         */
#define BSNO      2  /* Use carriage returns for bold & underline   */

#define PNARABIC  0  /* Use Arabic way of page numbering            */
#define PNLROMAN  1  /* Use lowercase Roman way of page numbering   */
#define PNUROMAN  2  /* Use upperercase Roman way of page numbering */

void *malloc();
uchar *getmac(), *tabexp();
short processfx();

#ifndef CPM
# define prchar(c, fp)	putc(c, fp)
#endif

#define STRINGTYP	'"'	/* Command has string argument          */
#define MORETXT		';'	/* Command seperator                    */
#define ESCCHAR		'@'	/* The substitution escape char         */
#define CMDCHAR		'.'	/* The default command character        */
#define C2CHAR		'\''	/* The default no-break cmd character   */
#define PGCHAR		'#'	/* The default page number character    */

#define BEGIF		('{'|0x8000)
#define ENDIF		('}'|0x8000)

#define FXPLAIN		0	/* Printer command sequences */
#define FXBO		1
#define FXIT		2
#define FXUL		4

#define NOGUARD		0x8000

/* #define putlin(string, stream)	fwrite(string, strlen(string), 1, stream) fputs(string, stream); */
#ifndef CPM
#  define iseol(c)	(c) == '\n'
#  define isnteol(c)	(c) != '\n'
#else
#  define iseol(c)	(c) == '\n' || (c) == '\r'
#  define isnteol(c)	(c) != '\n' && (c) != '\r'
#endif
#undef isspace
#define isspace(c)	(c) == ' ' || (c) == '\t'
#define isntspace(c)	(c) != ' ' && (c) != '\t'
SHAR_EOF
cat << \SHAR_EOF > nro.n
.tm Entering macro file
.so an
.tm Entering main file
.TH NRO 1 "AM*GA Programmer's Manual" "KosmoSoft" "Version 1.5"
.de cmd
!sp $1;!ne 2;!ti -5;!bo "$0
.en
.de fun
.sp $1;.ne 2;.ti -5;.bo "$0
.en
.SH NAME
nro - text formatter
.SH SYNOPSIS
.in +5;.ta +0;.ti -5
.bo "nro@t[-n] [+n] [-pxx] [-v] [-bx] [-rnx] [-rdx] [-rpx]
.bo "[-mmfile] ifile ... [>ofile]
.in -5;.ta
.SH DESCRIPTION
.ul "NRO
is a text processor and formatter based on the design
provided in
.bo ""Software Tools"
by Kernighan and Plauger. The text and commands found in the
.cu "ifile(s)
are processed to generate formatted text. The output may be directed into a
file or to the printer, otherwise, the output will appear at the user
console.

The
.ul "+n
option causes the output to start with page
.ul "n.
The
.ul "-n
option causes the output to stop after page
.ul "n.

The
.ul "-v
option prints the version number to the console. Specifying a higher
numerical argument makes
.bo "NRO
more and more verbose.

The
.ul "-p
option causes the output to be shifted to the right by
.ul "xx
spaces. This has the same effect as the
.bo "@.po
command.

The
.ul "-b
option with argument
.ul "x
controls if backspaces appear in the output text when underlining or
overstriking. This has the same effect as the
.bo "@.bs
command with the same argument.

The
.ul "-r
options allow you to specify how much memory is allocated for macro
definitions and related things. The
.ul "-rn
option lets you specify how many macros you may define while your text is
being formatted. Default is 512. The
.ul "-rd
option lets you specify how much memory is reserved for keeping the
contents of your macro definitions. Default is 20480 characters. The
.ul "-rp
option lets you specify how much characters may be pushed back into the
input, when processing a macro evaluation. Default is 1024 characters.
.br
If any of these options is present they must be located before the first
file to be processed to have any effect.

The
.ul "-m
option processes the file
.ul "mfile
for macro definitions. Note that files processed in this way should contain
only macro definitions, no immediate output should be generated from this
file.
.PP
Commands typically are distinguished by a period in column one of the input
followed by a two character abbreviation for the command funtion. The
abbreviation may then be followed by an optional numeric or character
argument.
.br
The numeric argument may be an absolute value such as setting the right
margin to a particular column, or the argument may be preceded by an
operator to indicate that the parameter should be modified relative to a
previous setting. You may use the operators +, -, /, *, % (mod), | (bitwise
or), & (bitwise and), = (equal), < (less than) and > (greater than) to
calculate values.
.ul "No
normal operator precedence is taken into account; the expression is
evaluated strictly from left to right. You may use parentheses to group
sub-expressions together. Note that all operators are dyadic, even the -.
To generate a negative value, use a form like 0-5. A leading operator in an
expression is not used in the evaluation. Instead, it has the effect of
altering a previously set value. The + operator increases the set value
with the given value, the - operator decreases the set value with the given
value, the * operator multiplies the set value with the given value, and
the / operator divides the set value by the given value. A leading operator
within parentheses is ignored.
.PP
Commands that have effect on a given number of input lines, can also take a
text argument, if it is preceded by a double quote character `"'. This
behaves exactly as if you gave the number 1, and followed the command with
the given text argument.
.br
More text or commands may follow a command if they are seperated by a
semicolon `;', unless the first command must be the last one on an input
line.

.tm ...commands
The following commands are recognized:
.in +5;.ta +0;.cc !
!*---------------------------*
!cmd .bo
@tcauses the following lines of text to appear in boldface. The optional
argument specifies the number of lines to be typed in boldface. An argument
of zero explicitly turns boldface off, while a negative argument turns it
on indefinitely. When overstrike is being used to produce the boldface,
boldface and underlining are mutually exclusive features, and the
appearance of a boldface command will cause any underlining to cease.
!*---------------------------*
!cmd .bp
@tcauses succeeding text to appear at the top of a new page. The optional
argument specifies the page number for the new page. The initial value is
one and the default value is one more than the previous page number.
!*---------------------------*
!cmd .br
@tcauses succeeding text to start on a new line at the current left margin.
There is no argument for this command.
!*---------------------------*
!cmd .bs
@tenables or disables the appearance of backspaces in the output text. A
value of
!cu "zero
doesn't use backspaces at all, but utilizes standard ISO printer codes.
The Commodore Amiga console and printer devices support these directly, but
on other systems you need a post-processor to convert these standard ISO
codes into, for example, Epson printer codes. If you don't want this,
underlining and boldface can be done by inserting character - backspace -
character combinations into the output. This is fine for devices which
properly recognize the backspace character. Many printers, however, do not
recognize backspaces, so the option is provided to overprint one line
buffer with another. The first line buffer is terminated with just a
carriage return rather than the carriage return - linefeed combination.
!br;An argument of
!cu "2
to the backspace command removes backspaces from the output. Even with
printers which do recognize backspaces, this usually is faster. An argument
of
!cu "1
puts them into the output. The default is to use Commodore Amiga (ISO)
control sequences.
!*---------------------------*
!cmd .cc
@tchanges the
!ul "NRO
command character to that specified by the character argument. If no
argument is provided, the default is a period.
!*---------------------------*
!cmd .ce
@tcauses the next line of text to appear centered on the output. This
automatically generates a break. The optional argument specifies if more
than one line is to be centered. An argument of zero explicitly turns
centering off, while a negative argument turns it on indefinitely.
!*---------------------------*
!cmd .cu
@tcauses the next line(s) of text to be continuously underlined. Unlike the
underline command (see
!bo ".ul)
which underlines only alphanumerics, continuous underlining underlines all
printable characters. The optional argument specifies the number of lines
of text to underlined. An argument of zero explicitly turns continuous
underline off, while a negative argument turns it on indefinitely. Any
normal underlining command currently in effect will be terminated.
!*---------------------------*
!cmd .de
@tcauses all text and commands following to be used to define a macro. The
definition is terminated by a line with
!bo ".en
as the first three characters. The rest of that line is ignored.
!br;The first argument following the
!bo ".de
command becomes the name of the new command.
!br;It should be noted that upper and lower case arguments are
considered different. Thus, the commands
!bo ".PP
and
!bo ".pp
could define two different macros. Care should be exercised since existing
commands and macros may be redefined. A macro may contain up to ten
arguments. In the macro definition, the placement of arguments is
designated by the two character sequences, $0, $1, ... $9.
!br
When the macro is invoked, each argument of the macro command line is
substituted for its corresponding designator in the expansion. The first
argument of the macro command is substituted for the $0 in the expansion,
the second argument for the $1, and so forth. Arguments are typically
strings which do not contain blanks or tabs. If an argument is to contain
blanks, then it should be surrounded by either single or double quotes.
!br
A macro name may be at most ten characters long. If more are supplied, the
results are unpredictable. To get things like $4 in the macro text, use a
double $$, i.e. $$4.
!*---------------------------*
!cmd .ef
@tspecifies the text for the footer on even numbered pages. The format is
the same as for the footer command (see
!bo ".fo).
!*---------------------------*
!cmd .eh
@tspecifies the text for the header on even numbered pages. The format is
the same as for the footer command (see
!bo ".fo).
!*---------------------------*
!cmd .el
@tSee
!bo ".if
and
!bo ".ie.
The
!bo ".el
command reverses the truth of the condition remembered by the last
!bo ".ie.
command, and if the result is true, it accepts the input on the remainder
of the line, just like the
!bo ".if
command. Multi-line else-parts are thus also possible. You may have
multiple
!bo ".el
request following a single
!bo ".ie
command. Since every
!bo ".el
reverses the remembered condition, you have if effect multiple 'then-' and
'else-parts', just divided into bits and pieces.
!*---------------------------*
!cmd .ev
@tenvironment switch. If a numerical argument is given, the number of the
current environment is pushed on a special environment number stack, and
the named environment is made current. If no argument is supplied, the
previous environment number that was in effect will be restored. As a
variation of this, the command
!bo ".ev -
will restore the previous environment and
!ul "discard
the current environment. This is useful if you don't need the particular
environment anymore. At a new invocation of this environment it will have
default values again.
!br
The environment is the set of values that determine the appearance of
formatted output. There are ten environments available, and up to nineteen
environment numbers can be pushed. Because a stack of previous environment
numbers is maintained, always return to a previous environment by a
!bo ".ev
command without numeric argument.
!br
The following commands affect values that are in the environment:
!bo 2
.ls .ti .in .rm .ce .ul .cu .it .ta .ju .nj .bo .fi .nf .pn .pc .cc and
!bo ".c2.
!br
Also in the environment are the last remembered conditional,
!bo ".ie,
and collected partial output lines.
!*---------------------------*
!cmd .en
@tdesignates the end of a macro definition.
!*---------------------------*
!cmd .fi
@tcauses the input text to be rearranged or filled to obtain the maximum
word count possible between the previously set left and right margins. No
argument is expected.
!*---------------------------*
!cmd .fo
@tspecifies text to be used for a footer. The footer text contains three
strings seperated by a delimiter character. The first non-blank character
following the command is designated as the delimiter. The first text string
is left justified to the current indentation value (specified by
!bo ".in).
The second string is centered between the current indentation value and the
current right margin value (specified by
!bo ".rm).
The third string is right justified to the current right margin value. The
absence of footer text will result in the footer being printed as one blank
line. The presence of the page number character (set by
!bo ".pc)
in the footer text results in the current page number being inserted at
that position. Multiple occurrances of the page number character are
allowed. This command must be the last command on an input line.
!*---------------------------*
!cmd .he
@tspecifies text to be used for a header. The for
mat is the same as for the
footer (see
!bo ".fo).
!*---------------------------*
!cmd .ie
@tSame as
!bo ".if,
but remembers the resulting condition, that can be used by subsequent
!bo ".el
requests. Only one level of conditions is remembered: they cannot be
nested. Every occurrence of a
!bo ".ie
request overrides the result as remembered by the previous one.
!*---------------------------*
!cmd .if
@tConditional acceptance of input. The request is followed by a
conditional, which may take several forms. Depending on the condition,
subsequent input may be accepted or ignored. The following forms of
condition are valid:
!in +9;!ti -4;!nj
!bo ".if [!]<letter>
anything
!ti -4;!bo ".if [!]<expression>
anything
!ti -4;!bo ".if [!]<delimiter> <string1> <delimiter> <string2> <delimiter>
anything
!in -9;!ju
The following <letter>s may be used:
!bo "o:
Current page number is odd;
!bo "e:
Current page number is even;
!bo "n:
Formatter is
!ul "NRO,
which is always true;
!bo "t:
Formatter is TRO(FF), which is always false.
!br
An <expression> is said to be true if it is > 0.
!br
The last form is a string comparison, which is true if <string1> and
<string2> are exactly equal. Any <delimiter> may be used as long as it
doesn't make the conditional look like one of the other forms.
!br
A not-symbol `!' may immediately precede the condition to reverse its
truth.
!br
Normally, the accepted or ignored input affected is only the rest of the
current input line. A multi-line `then-part' must begin with the opening
delimiter @@{ and the last line must end with the closing delimiter @@}. It
may also be useful to conceal the newline following the opening delimiter
if it is at the end of an input line. Because the delimiters are deleted
from the input, make sure that the line is not empty without them, because
this would cause a break. It is sufficient to place them on a line with a
comment command to avoid this.
!*---------------------------*
!cmd .in
@tindents the left margin to the column value specified by the argument.
The default left margin is set to zero. This command performs a break.
!*---------------------------*
!cmd .it
@tcauses the following lines of text to appear in italics. The optional
argument specifies the number of lines to be typed in italics. An argument
of zero explicitly turns italics off, while a negative argument turns it on
indefinitely. This command is
!bo "not
functional when the Commodore Amiga (ISO) command sequences are not being
used, since it can't be emulated by overstriking printlines.
!*---------------------------*
!cmd .ju
@tcauses blanks to be inserted between words in a line of output in order
to align or justify the right margin. The default is to justify. No
argument is expected.
!*---------------------------*
!cmd .ls
@tsets the line spacing to the value specified by the argument. The default
is for single spacing.
!*---------------------------*
!cmd .m1
@tspecifies the number of lines in the header margin. This is the space
from the physical top of page to and including the header text. A value of
zero causes the header to not be printed. A value of one causes the header
to appear at the physical top of page. Larger argument values cause the
appropriate number of blank lines to appear before the header is printed.
!*---------------------------*
!cmd .m2
@tspecifies the number of blank lines to be printed between the header line
and the first line of the processed text.
!*---------------------------*
!cmd .m3
@tspecifies the number of blank lines to be printed between the last line
of processed text and the footer line.
!*---------------------------*
!cmd .m4
@tspecifies the number of lines in the footer margin. This command affects
the footer the same way the
!bo ".m1
command affects the header.
!*---------------------------*
!cmd .ne
@tspecifies a number of lines which should not be broken across a page
boundary. If the number of lines remaining on a page is less than the value
needed, then a new output page is started.
!*---------------------------*
!cmd .nf
@tspecifies that succeeding text should be printed without rearrangement,
or with no fill. The default is to justify. No argument is expected.
!*---------------------------*
!cmd .nj
@tspecifies that no attempt should be made to align or justify the right
margin. No argument is expected.
!*---------------------------*
!cmd .nr
@tcauses the value of a number register to be set or modified. A total of
twenty-six number registers are available designated @@na through @@nz
(either upper or lower case is allowed). When the sequence @@nc is imbedded
in the text, the current value of number register c replaces the sequence,
thus, such things as paragraph numbering can be accomplished with relative
ease.
!*---------------------------*
!cmd .of
@tspecifies the text for the footer on odd numbered pages. The format is
the same as the footer command (see
!bo ".fo).
!*---------------------------*
!cmd .oh
@tspecifies the text for the header on odd numbered pages. The format is
the same as the footer command (see
!bo ".fo).
!*---------------------------*
!cmd .pc
@tspecifies the page number character to be used in headers and footers.
The occurrance of this character in the header or footer text results in
the current page number being printed. The default for this character is
the hash mark `#'.
!*---------------------------*
!cmd .pl
@tspecifies the page lenght or the number of lines per output page. The
default is 66.
!*---------------------------*
!cmd .pn
@tspecifies the way page numbering is done. You may specify the following
values: 0 uses normal arabic page numbers, 1 generates lowercase roman
numbers, and 2 specifies uppercase roman numbers. Default is arabic page
numbering.
!*---------------------------*
!cmd .po
@tspecifies a page offset value. This allows the formatted text to be
shifted to the right by the number of spaces specified. This feature may
also be invoked by a switch on the command line. All horizontal positions
(like tabstops, indentations) are adjusted accordingly.
!*---------------------------*
!cmd .rm
@tsets the column value for the right margin. The default is 80.
!*---------------------------*
!cmd .so
@tcauses input to be retrieved from the file specified by the command's
character string argument. The contents of the new file are inserted into
the output stream until an EOF is detected. Processing of the original file
is then resumed. File nesting is allowed up to a reasonable level (four).
!*---------------------------*
!cmd .sp
@tspecifies a number of blank lines to be output before printing the next
line of text. This automatically generates a break. You cannot move
upwards.
!*---------------------------*
!cmd .ta
@ttab settings. This command allows you to set tabstops. It may have
optional numeric arguments. When issued without arguments, all tabstops are
removed. When issued with one or more numeric arguments, tabstops are set
at the specified number of spaces from the left hand side of the paper. An
argument may optionally be preceded with a `+' to indicate that a distance
from the previously mentioned tab is meant instead of an absolute position.
A `+' sign before the first argument indicates a distance from the current
indent.
!*---------------------------*
!cmd .ti
@ttemporarily alters the indentation or left margin value for a single
succeeding line of output text. This command performs a break. If an input
line starts with spaces, this has the effect that a break is generated, and
a temporary indent for the number of spaces is set.
!*---------------------------*
!cmd .tm
@twrites a message to the standard error output, so you see it in your
console window. This command must be the last one on an input line. When
used with the no-break command character, this `no-break' gets another
meaning: don't break the formatted output if it also is printed on the
console. The command is ignored instead.
!*---------------------------*
!cmd .ul
@tunderlines the alphanumeric text in the following line(s). The optional
argument specifies the number of lines to be underlined. An argument of
zero explicitly turns underlining off, while a negative argument turns it
on indefinitely. When overstrike is being used to produce the underline,
underlining and boldface are mutually exclusive features, and the
appearance of an underline command cancels any existing boldface
operations.
!*---------------------------*
!cmd .un
@tundefines a previously defined macro, and all macros that were defined
later. If this macro was a redefinition of an older macro with the same
name, the old definition will be available again. Thus, macros are defined
in a stack-like fashion.
!cmd .*
!cmd ." 0
@tBoth of these serve as a way to insert comments in the input text. They
have absolutely no effect on the output.
!*---------------------------*

!cc
.in -5;.PP
.tm End of commands
Instead of having the command immediately at the beginning of a line, you
may also begin a line with a command character, then some blanks, and then
again a command character, this time followed immediately by the command.
There exists even a second command character, called the
.bo "no break command character,
`'', which suppresses the break normally generated by some commands. This
no break command character can only be used in this way. If the first
non-blank character is
.ul "not
a command character, it is considered to be text. An example illustrates
this.

.RS 5;.nf
@.    .sp   @@" This is a space command,
@.    this is some normal text,
@.    'sp 3 @@" and this spaces without a break.
.RE;.fi
.PP
When a line does not begin with the command character, its words are placed
one by one on an output line. As soon as a word doesn't fit, the collected
line is printed, possibly after justification. The word is then placed on
the next output line. If a line is about to be printed at the top of a
page, the page header, if any, is printed first. If a line is on the last
usable line of a page, the page footer, if any, is printed next, and the
page is ejected.
.br
If you want to begin an input text line with an instance of the command
character, you may precede it with the escape character.
.PP
A number of translations can be performed on the input, even before it is
interpreted as either text or commands. Such a translation takes place
where an escape character `@@' is seen in the input text. The single
charachter following the escape character determines the effect.

.tm ...functions
The following functions are currently implemented:
.in +5
.fun @@@@
@tis a single @@.
.*---------------------------*
.fun @@e
@tis replaced by the current value of the escape character. Currently,
there is no way to change it.
.*---------------------------*
.fun @@n
@tfollowed by a single letter, is replaced by the contents of the
designated number register.
.*---------------------------*
.fun @@t
@tis replaced with a tab character, to be used in conjunction with the
.bo "@.ta
command. You may also use a normal tab character if you wish. If a tab is
encountered, the necessary space is generated by non-breakable spaces. Any
spaces on the output line before the tab are also made non-breakable. This
is to avoid justification spoiling the tab.
.br
Tabs beyond the current right margin or beyond the last tab stop are
ignored, except that they separate words.
.*---------------------------*
.fun @@X(expression)
@tis replaced with the character with character code value `expression'.
.*---------------------------*
.fun @@(space)
@tis replaced by a non-breakable space. It behaves just like any printable
character, you just don't see it. This space won't be modified by
justification, and it will be underlined by continous underline.
.*---------------------------*
.fun @@(newline)
@tis deleted from the input. If a @@ is placed at the end of an input line,
it will appear as if the next input line actually is following the contents
of the current line. This is called `concealing the newline'.
.*---------------------------*
.fun @@.
@twhere . stands for the current command character, produces the command
character. It will, however, not be recognized as such. This provides a way
to start your input line with a command character that in fact is a text
line. This only works if the command character is different from any other
valid character following the escape character, and does not work for
.bo "@.en
commands that end a macro definition.
.*---------------------------*
.fun @@{
.fun @@} 0
@tThese two delimiters were already mentioned in the section about the
.bo "@.if
and
.bo "@.el
commands. They serve to delimit the lines you want to be affected by these
commands. Normally, when the condition is false, the
.bo "@.if
skips input until it finds the end of the current line. If it sees the @@{
following the condition, it sets a flag to indicate to the low-level file
reader, that it must count these delimiters. All input is then skipped
until the matching closing delimiter @@} is found. So, the
.bo "@.if
command never 'sees' anything of it. Also in this case, the
.bo "@.if
command skips the rest of the line remaining after the closing @@}.
.br
On the other hand, if the condition evaluates to be true, all and any
opening and closing delimiters are ignored completely. The command
following the condition is executed, and also of course any commands on
following lines. Since a command (or text) is expected on the same line as
the
.bo "@.if
command, omission of a command makes it look like there is an empty line,
and this generates an unexpected break. Therefore, you should conceal the
newline at the end of such a line. (See @@(newline).)
.*---------------------------*
.fun @@"
@tThis is yet another way to insert a comment. Note that text may precede
the comment function. All text from the comment function until the end of
the line will be ignored. Note that spaces between the last word on a line
and the comment are not deleted, and this may effect your layout in some
(as of yet unimplemented) cirumstances.

.in -5
Any unrecognized character that follows the @@ will be left in the input.
.PP
Macro expansion is accomplished in the following way. There exists an input
push-back buffer. If any input is needed, this push-back buffer is examined
first. If a character is present, the request is satisfied by taking the
last pushed back character. Only if the push back buffer is empty, a
character is read from the input file. At any time that
.ul "NRO
reads a character that is unexpected, it is pushed back, in the hope that
it can be used later.
.br
When a macro is to be expanded, its body is pushed back, while at the same
time subsituting the arguments. Normally when an instance of the escape
character is to be pushed back, it is `guarded' against re-substitution
when it is read back, by doubling it, so anything pushed back will be read
back exactly the same. This is not done
.ul "only
for macro bodies, to allow resubstitution to occur in them. This means that
the body of a macro is interpreted twice, once at definition time, and once
at application time. The macro arguments are interpreted only once, so that
a double escape character in an argument will show up in the resulting text
as a single escape character, instead of disappearing. This seems to be the
most intuitive approach. It will disallow some more complex applications
but avoids needing four @@'s in an argument if you want only one.
.tm ...examples
.SH EXAMPLES
.SS "Macros:
You may even define a macro that defines a macro, in the following way:
.br;.RS +5;.nf
@.de keep
@.de $0
$1 $2 $3 $4 $5 $6 $7 $8 $9
@@@@.en
@.en
.fi;.RE
This macro defines a macro with a name designated by the first argument,
and containing the text designated by the remaining arguments. Remember
that you can always enclose an argument with quotes.
.br
Note that you must use two escape characters to make the
.bo "@.en
part of the macro body. This is because macro definitions are handled
slightly different from normal input lines. In the definition of `keep'
there will be a line with
.bo "@@.en,
and at the time of definition of the inner macro the second escape
character will be stripped off, so that the end of the inner macro
definition is recognized.
.br
Another way to to it, is to change the command character temporarily while
defining the outer macro.

.SS "Conditionals:
Here are a few examples of correct use of the
.bo "@.if, .ie
and
.bo "@.el
commands:
.br;.RS +5;.nf

@.if @@na Register A is greater than zero!

@.if @@na @@{.firstcommand
@.	   .secondcommand
@.	   .lastcommand @@}

@.if @@na @@{@@
@.	   .firstcommand
@.	   .secondcommand
@.	   .lastcommand @@}

@.ie @@na @@{.firstcommand
@.	   .secondcommand
@.	   .lastcommand @@}
@.el Register A is NOT greater than zero!!
@.el Maybe a bit late, but register A IS greater than zero!!
.fi;.RE
.tm ...undocumented features
.SH "UNDOCUMENTED FEATURES"
.PP
<censored>
SHAR_EOF
cat << \SHAR_EOF > nroxtrn.h
/*
 *		External "common" for NRO word processor
 *
 *		Originally by Stephen L. Browning, 5723 North Parker Avenue
 *		Indianapolis, Indiana 46220
 *
 *		Transformed beyond immediate recognition, and
 *		adapted for Amiga by Olaf Seibert, KosmoSoft
 *
 *		Vossendijk 149-1 (study)   Beek 5 (home)
 *		5634 TN  Nijmegen          5815 CS  Merselo
 *		The Netherlands            The Netherlands
 *		Phone:
 *		       (...-31)80561045     (...-31)4786205
 *		    or 080-561045           04786-205
 *
 *		This program is NOT in the public domain. It may, however
 *		be distributed only at no charge, and this notice must be
 *		included unaltered.
 */

#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN struct environ *environ[NUMENV];

EXTERN struct environ env;
EXTERN struct docctl  dc;
EXTERN struct page    pg;
EXTERN struct macros  mac;

EXTERN FILE   *pout;
EXTERN FILE   *sofile[NFILES];  /* input files */
EXTERN FILE   *infile;			/* current input file */
EXTERN uchar  *sopbb[NFILES-1];	/* and push back buffer pointers */
EXTERN short  verbose;

extern uchar  *commseq[];
SHAR_EOF
cat << \SHAR_EOF > prnro.c
#include <stdio.h>
#include <ctype.h>

char KosmoSoftID[] = "(@)# prnro.c 1.0 V14.04.88 (C) KosmoSoft";

/*
 *	prnro.c
 *
 *	konverteer ANSI printerkodes naar epson-kode.
 *	Alleen geschikt voor gebruik met NRO, omdat alleen
 *	bold/italic/underline ondersteund worden.
 *	Voor de aardigheid heb ik er ook nog NLQ aan/uit bij
 *	gedaan.
 *
 *	Werkt van stdin naar stdout.
 *
 *	(C) Copyright KosmoSoft 1988
 *
 */

void AnsiToEpson(), DoEscape(), DoCSI(), CollectCommand();
void DoSGR(), DoDEN(), Initialize();
int CollectParameter();

FILE *in, *out;

int Parameter[8];
int NumPars;
int Command;

#define SGR	'm'
#define DEN	'"'

#define	NBSP	0xA0
#define ESC	0x1B
#define CSI	0x9B
#define CSI2	'['

main(argc, argv)
int argc;
char *argv[];
{
	in = stdin;
	out = stdout;
	AnsiToEpson();
}

void AnsiToEpson()
{
	int chr;

	Initialize();	/* Start in bekende toestand */

	while ((chr = getc(in)) != EOF) {
		switch (chr) {
		case NBSP:
			putc(' ', out);
			continue;
		case ESC:
			DoEscape();
			continue;
		case CSI:
			DoCSI();
			continue;
		default:
			putc(chr, out);
		}
	}
	
	Initialize();	/* en laat geen rommel achter */
}

void DoEscape()
{
	int chr;

	if ((chr = getc(in)) == CSI2) {
		DoCSI();
	} else if (chr != EOF) {
		putc(chr, out);
	}
}

void DoCSI()
{
	CollectCommand();

	switch (Command) {
	case SGR:
		DoSGR();
		break;
	case DEN:
		DoDEN();
		break;
	}
}

void CollectCommand()
{
	register int chr;

	NumPars = 0;

	while ( (chr = CollectParameter()) == ';')
		;
	
	Command = chr;
}

int CollectParameter()
{
	register int chr;
	register int par;

	par = 0;

	while (isdigit(chr = getc(in))) {
		par *= 10;
		par += chr - '0';
	}

	Parameter[NumPars++] = par;

	return chr;
}

char SGR0[] = "\0335\033-0\033F",	/* normal characters */
     SGR3[] = "\0334",			/* italics on */
     SGR23[]= "\0335",			/*         off */
     SGR4[] = "\033-1",			/* underline on */
     SGR24[]= "\033-0",			/*           off */
     SGR1[] = "\033E",			/* boldface on */
     SGR22[]= "\033F";			/*          off */

void DoSGR()
{
	register int i;
	register char *string = NULL;

	for (i = 0; i < NumPars; i++) {
		switch (Parameter[i]) {
		case 0:
			string = SGR0;
			break;
		case 3:
			string = SGR3;
			break;
		case 23:
			string = SGR23;
			break;
		case 4:
			string = SGR4;
			break;
		case 24:
			string = SGR24;
			break;
		case 1:
			string = SGR1;
			break;
		case 22:
			string = SGR22;
			break;
		}
		if (string)
			fputs(string, out);
	}
}

char DEN1[] = "\033x0",		/* NLQ off */
     DEN2[] = "\033x1",		/*     on */
     DEN3[] = "\033H",		/* double strike off */
     DEN4[] = "\033G";		/*               on */

char *DENs[] = {
	"", DEN1, DEN2, DEN3, DEN4 
};

void DoDEN()
{
	register int i;
	register int den;

	for (i = 0; i < NumPars; i++) {
		if ( (den = Parameter[i]) <= 4)
			fputs(DENs[den], out);
	}
}


char RIS[] = "\375\033@\375";

void Initialize()
{
	fputs(SGR0, out);
}
SHAR_EOF
cat << \SHAR_EOF > prnro.n
.so an
.TH PRNRO 1 "AM*GA Programmer's Manual" "KosmoSoft"
.SH NAME
prnro - make output of nro printable
.SH SYNOPSIS
.bo "prnro
.bo "[< inputfile]
.bo "[> outputfile]
.SH DESCRIPTION
.bo "Prnro
converts ANSI standard output of
.bo "nro
into Epson printer codes, so that it may be printed on
any Epson compatible printer, like the Mannesman Tally 86.
.br;.bo "Prnro
reads from the standard input, and produces the result
on the standard output.
.SH CAVEATS
Since
.bo "nro
only produces a very small subset of the ANSI standard,
.bo "(bold,
.it "italics,
and
.ul "underline),
.bo "prnro
is not a general-purpose ANSI to Epson converter.
.SH EXAMPLES
nro document.n >document.a
.br
prnro <document.a | lpr

nro anotherdocument.n | prnro | lpr
.SH "SEE ALSO"
nro(1),
lpr(1)
.SH WARNINGS
Don't look up!
.SH BUGS
Unimplemented ANSI standard command sequences are silently ignored
as soon as this fact can be determined.
.SH NOTES
This program is (C) Copyright 1988 by KosmoSoft.
.br
Versions of
.bo "prnro
for other types of printers can be prepared on request.
SHAR_EOF
cat << \SHAR_EOF > skeleton.n
.so an
.TH SKELETON 1 "AM*GA Programmer's Manual" "KosmoSoft"
.SH NAME
skeleton - sample manual page
.SH SYNOPSIS
.bo "skeleton
[options]
.SH DESCRIPTION
This section describes the program or file.
.SH CAVEATS
caveats
.SH EXAMPLES
skeleton
.SH DIAGNOSTICS
are not the same as paragnostics.
.SH "RETURN VALUE"
return value
.SH "SEE ALSO"
nro(1),
man(7)
.SH WARNINGS
Don't look up!
.SH BUGS
They are everywhere
.SH MISCELLANEOUS
Mos error - core dumped
.SH NOTES
This is only intended as a skeleton
SHAR_EOF
cat << \SHAR_EOF > table.c
/*
 *	Variable module for NRO
 *
 *      Originally by Stephen L. Browning, 5723 North Parker Avenue
 *      Indianapolis, Indiana 46220
 *
 *	Transformed beyond immediate recognition, and
 *	adapted for Amiga by Olaf Seibert, KosmoSoft
 *
 *	Vossendijk 149-1 (study)   Beek 5 (home)
 *	5634 TN  Nijmegen          5815 CS  Merselo
 *	The Netherlands            The Netherlands
 *	Phone:
 *	       (...-31)80561045     (...-31)4786205
 *	    or 080-561045           04786-205
 *
 *	This program is NOT in the public domain. It may, however
 *	be distributed only at no charge, and this notice must be
 *	included unaltered.
 */

#include <stdio.h>
#include "nro.h"
#define EXTERN
#include "nroxtrn.h"

#define CSI		0x9B

static uchar cancel[] = { CSI, '0', 'm', 0 };

static uchar bo[] = { CSI, '1', 'm', 0 };
static uchar it[] = { CSI, '3', 'm', 0 };
static uchar ul[] = { CSI, '4', 'm', 0 };

static uchar boit[] = { CSI, '1', ';', '3', 'm', 0 };
static uchar boul[] = { CSI, '1', ';', '4', 'm', 0 };
static uchar itul[] = { CSI, '4', ';', '3', 'm', 0 };

static uchar boitul[] = { CSI, '1', ';', '4', ';', '3', 'm', 0 };


uchar *commseq[] = {
	cancel, bo, it, boit,
	ul, boul, itul, boitul
};

static uchar KosmoSoftID[] =
"(@)# Copyright (C) 1988 by Olaf Seibert.\
 May be distributed for free only.\n";SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.