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.