koreth@panarthea.ebay.sun.com (Steven Grimm) (11/15/89)
Submitted-by: rosenkra@hall.cray.com (Bill Rosenkranz)
Posting-number: Volume 3, Issue 10
Archive-name: nroff/part03
part03/03
-bill
rosenkra@hall.cray.com
rosenkra@boston.cray.com
-------------cut here 0---------------------cut here-----------------------
#!/bin/sh
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by hall!rosenkra on Sun Nov 12 16:35:37 CST 1989
# Contents: escape.c low.c macros.c strings.c
echo x - escape.c
sed 's/^@//' > "escape.c" <<'@//E*O*F escape.c//'
/*
* escape.c - Escape and special character input processing portion of
* nroff word processor
*
* adapted for atariST/TOS by Bill Rosenkranz 11/89
* net: rosenkra@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* original author:
*
* Stephen L. Browning
* 5723 North Parker Avenue
* Indianapolis, Indiana 46220
*
* history:
*
* - Originally written in BDS C;
* - Adapted for standard C by W. N. Paul
* - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
*/
#undef NRO_MAIN /* extern globals */
#include <stdio.h>
#include "nroff.h"
/*------------------------------*/
/* expesc */
/*------------------------------*/
expesc (p, q)
char *p;
char *q;
{
/*
* Expand escape sequences
*/
register char *s;
register char *t;
register char *pstr;
register int i;
register int val;
register int autoinc;
char c;
char fs[5]; /* for font change */
char nrstr[20];
char fmt[20];
char name[10];
int nreg;
char *pfs;
int inc;
int tmp;
char delim;
s = p;
t = q;
/*
* if escape parsing is not on, just copy string
*/
if (dc.escon == NO)
{
while (*s != EOS)
{
*t++ = *s++;
}
*t = EOS;
strcpy (p, q);
return;
}
/*
* do it...
*/
while (*s != EOS)
{
if (*s != dc.escchr)
{
/*
* not esc, continue...
*/
*t++ = *s++;
}
else if (*(s + 1) == dc.escchr)
{
/*
* \\ escape escape
*/
*t++ = *s++;
++s;
}
else if (*(s + 1) == 'n')
{
/*
* \nx, \n(xx register
*
* first check for \n+... or \n-... (either form)
*/
s += 2;
autoinc = 0;
if (*s == '+')
{
autoinc = 1;
s += 1;
}
if (*s == '-')
{
autoinc = -1;
s += 1;
}
/*
* was this \nx or \n(xx form?
*/
if (isalpha (*s))
{
/*
* \nx form. find reg (a-z)
*/
nreg = tolower (*s) - 'a';
/*
* was this \n+x or \n-x? if so, do the
* auto incr
*/
if (autoinc > 0)
dc.nr[nreg] += dc.nrauto[nreg];
else if (autoinc < 0)
dc.nr[nreg] -= dc.nrauto[nreg];
/*
* display format
*/
if (dc.nrfmt[nreg] == '1')
{
/*
* normal decimal digits
*/
t += itoda (dc.nr[nreg], t, 6) - 1;
}
else if (dc.nrfmt[nreg] == 'i')
{
/*
* lower roman
*/
t += itoroman (dc.nr[nreg], t, 24) - 1;
}
else if (dc.nrfmt[nreg] == 'I')
{
/*
* upper roman
*/
t += itoROMAN (dc.nr[nreg], t, 24) - 1;
}
else if (dc.nrfmt[nreg] == 'a')
{
/*
* lower letters
*/
t += itoletter (dc.nr[nreg], t, 12) - 1;
}
else if (dc.nrfmt[nreg] == 'A')
{
/*
* upper letters
*/
t += itoLETTER (dc.nr[nreg], t, 12) - 1;
}
else if (dc.nrfmt[nreg] & 0x80)
{
/*
* zero-filled decimal
*/
sprintf (fmt, "%%0%dld",
(int)(dc.nrfmt[nreg] & 0x7F));
fmt[5] = '\0';
sprintf (nrstr, fmt, (long) dc.nr[nreg]);
tmp = dc.nrfmt[nreg] & 0x7F;
nrstr[tmp] = '\0';
strcpy (t, nrstr);
t += strlen (nrstr);
}
else
{
/*
* normal (default)
*/
t += itoda (dc.nr[nreg], t, 6) - 1;
}
++s;
}
else if (*s == '%')
{
/*
* \n% form. find index into reg struct
*/
nreg = findreg ("%");
if (nreg < 0)
{
fprintf (err_stream,
"***%s: no register match\n",
myname);
err_exit (-1);
}
/*
* was this \n+% or \n-%? if so, do the
* auto incr
*/
if (autoinc > 0)
rg[nreg].rval += rg[nreg].rauto;
else if (autoinc < 0)
rg[nreg].rval -= rg[nreg].rauto;
/*
* display format
*/
if (rg[nreg].rfmt == '1')
{
/*
* normal decimal digits
*/
t += itoda (rg[nreg].rval, t, 6) - 1;
}
else if (rg[nreg].rfmt == 'i')
{
/*
* lower roman
*/
t += itoroman (rg[nreg].rval, t, 24) - 1;
}
else if (rg[nreg].rfmt == 'I')
{
/*
* upper roman
*/
t += itoROMAN (rg[nreg].rval, t, 24) - 1;
}
else if (rg[nreg].rfmt == 'a')
{
/*
* lower letters
*/
t += itoletter (rg[nreg].rval, t, 12) - 1;
}
else if (rg[nreg].rfmt == 'A')
{
/*
* upper letters
*/
t += itoLETTER (rg[nreg].rval, t, 12) - 1;
}
else if (rg[nreg].rfmt & 0x80)
{
/*
* zero-filled decimal
*/
sprintf (fmt, "%%0%dld",
(int)(rg[nreg].rfmt & 0x7F));
fmt[5] = '\0';
sprintf (nrstr, fmt, (long) rg[nreg].rval);
tmp = rg[nreg].rfmt & 0x7F;
nrstr[tmp] = '\0';
strcpy (t, nrstr);
t += strlen (nrstr);
}
else
{
/*
* normal (default)
*/
t += itoda (rg[nreg].rval, t, 6) - 1;
}
s += 1;
}
else if (*s == '(')
{
/*
* \n(xx form. find index into reg struct
*/
s += 1;
name[0] = *s;
name[1] = *(s + 1);
if (name[1] == ' ' || name[1] == '\t'
|| name[1] == '\n' || name[1] == '\r')
name[1] = '\0';
name[2] = '\0';
nreg = findreg (name);
if (nreg < 0)
{
fprintf (err_stream,
"***%s: no register match\n",
myname);
err_exit (-1);
}
/*
* was this \n+(xx or \n-(xx? if so, do the
* auto incr
*/
if (rg[nreg].rflag & RF_WRITE)
{
if (autoinc > 0)
rg[nreg].rval += rg[nreg].rauto;
else if (autoinc < 0)
rg[nreg].rval -= rg[nreg].rauto;
}
/*
* display format
*/
if (rg[nreg].rfmt == '1')
{
/*
* normal decimal digits
*/
t += itoda (rg[nreg].rval, t, 6) - 1;
}
else if (rg[nreg].rfmt == 'i')
{
/*
* lower roman
*/
t += itoroman (rg[nreg].rval, t, 24) - 1;
}
else if (rg[nreg].rfmt == 'I')
{
/*
* upper roman
*/
t += itoROMAN (rg[nreg].rval, t, 24) - 1;
}
else if (rg[nreg].rfmt == 'a')
{
/*
* lower letters
*/
t += itoletter (rg[nreg].rval, t, 12) - 1;
}
else if (rg[nreg].rfmt == 'A')
{
/*
* upper letters
*/
t += itoLETTER (rg[nreg].rval, t, 12) - 1;
}
else if (rg[nreg].rfmt & 0x80)
{
/*
* zero-filled decimal
*/
sprintf (fmt, "%%0%dld",
(int)(rg[nreg].rfmt & 0x7F));
fmt[5] = '\0';
sprintf (nrstr, fmt, (long) rg[nreg].rval);
tmp = rg[nreg].rfmt & 0x7F;
nrstr[tmp] = '\0';
strcpy (t, nrstr);
t += strlen (nrstr);
}
else
{
/*
* normal (default)
*/
t += itoda (rg[nreg].rval, t, 6) - 1;
}
s += 2;
}
}
else if (*(s + 1) == '\"')
{
/*
* \" comment
*/
*s = EOS;
*t = *s;
return;
}
else if (*(s + 1) == '*')
{
/*
* \*x, \*(xx string
*/
s += 2;
if (*s == '(')
{
/*
* \*(xx form
*/
s += 1;
name[0] = *s;
name[1] = *(s + 1);
name[2] = '\0';
pstr = getstr (name);
if (!pstr)
{
fprintf (err_stream,
"***%s: string not found\n",
myname);
err_exit (-1);
}
while (*pstr)
*t++ = *pstr++;
s += 2;
}
else
{
/*
* \*x form
*/
name[0] = *s;
name[1] = '\0';
pstr = getstr (name);
if (!pstr)
{
fprintf (err_stream,
"***%s: string not found\n",
myname);
err_exit (-1);
}
while (*pstr)
*t++ = *pstr++;
s += 1;
}
}
else if (*(s + 1) == 'f')
{
/*
* \fx font
*/
s += 2;
pfs = fs; /* set up ret string */
fs[0] = '\0';
/*
* it parses 1-2 char of s and returns esc seq for
* \fB and \fR (\fI is same as \fB)
*/
fontchange (*s, pfs);
/*
* imbed the atari (vt52) escape seq
*/
while (*pfs)
*t++ = *pfs++;
++s; /* skip B,I,R,S,P */
}
else if (*(s + 1) == '(')
{
/*
* \(xx special char
*/
s += 2;
/*
* it returns num char to skip and sets c to
* the ascii value of the char
*/
inc = specialchar (s, &c);
/*
* skip proper num char in s and add c to target
*/
if (inc)
{
s += inc;
*t++ = c;
}
}
else if (*(s + 1) == 'e')
{
/*
* \e printable version of escape
*/
*t++ = dc.escchr;
s += 2;
}
else if (*(s + 1) == '`')
{
/*
* \` grave, like \(ga
*/
*t++ = 0x60;
s += 2;
}
else if (*(s + 1) == '\'')
{
/*
* \' accute, like \(aa
*/
s += 2;
*t++ = 0xBA;
}
else if (*(s + 1) == '-')
{
/*
* \- minus
*/
s += 2;
*t++ = 0x2D;
}
else if (*(s + 1) == '.')
{
/*
* \. period
*/
s += 2;
*t++ = 0x2E;
}
else if (*(s + 1) == ' ')
{
/*
* \(space) space
*/
s += 2;
*t++ = 0x20;
}
else if (*(s + 1) == '0')
{
/*
* \0 digital width space
*/
s += 2;
*t++ = 0x20;
}
else if (*(s + 1) == '|')
{
/*
* \| narrow width char (0 in nroff)
*/
s += 2;
}
else if (*(s + 1) == '^')
{
/*
* \^ narrow width char (0 in nroff)
*/
s += 2;
}
else if (*(s + 1) == '&')
{
/*
* \& non-printing zero width
*/
s += 2;
}
else if (*(s + 1) == '!')
{
/*
* \! transparent copy line
*/
s += 2;
}
else if (*(s + 1) == '$')
{
/*
* \$N interpolate arg 1<=N<=9
*/
s += 2;
}
else if (*(s + 1) == '%')
{
/*
* \% hyphen
*/
s += 2;
*t++ = 0x2D;
*t++ = 0x2D;
}
else if (*(s + 1) == 'a')
{
/*
* \a
*/
s += 2;
}
else if (*(s + 1) == 'b')
{
/*
* \b'abc...'
*/
s += 2;
}
else if (*(s + 1) == 'c')
{
/*
* \c
*/
s += 2;
}
else if (*(s + 1) == 'd')
{
/*
* \d
*/
s += 2;
}
else if (*(s + 1) == 'h')
{
/*
* \h'N' horiz motion
*/
s += 2;
delim = *s++;
val = atoi (s);
for (i = 0; i < val; i++)
*t++ = ' ';
while (*s != delim)
{
if (*s == 0)
break;
s++;
}
if (*s)
s++;
}
else if (*(s + 1) == 'k')
{
/*
* \kx
*/
s += 2;
}
else if (*(s + 1) == 'l')
{
/*
* \l'Nc'
*/
s += 2;
}
else if (*(s + 1) == 'L')
{
/*
* \L'Nc'
*/
s += 2;
}
else if (*(s + 1) == 'o')
{
/*
* \o'abc...' overstrike
*/
s += 2;
delim = *s++;
while (*s != EOS && *s != delim)
{
*t++ = *s++;
*t++ = 0x08;
}
s++;
}
else if (*(s + 1) == 'p')
{
/*
* \p
*/
s += 2;
}
else if (*(s + 1) == 'r')
{
/*
* \r
*/
s += 2;
}
else if (*(s + 1) == 's')
{
/*
* \sN,\s+-N
*/
s += 2;
}
else if (*(s + 1) == 't')
{
/*
* \t horizontal tab
*/
s += 2;
*t++ = 0x09;
}
else if (*(s + 1) == 'u')
{
/*
* \u
*/
s += 2;
}
else if (*(s + 1) == 'v')
{
/*
* \v'N' vert tab
*/
s += 2;
delim = *s++;
val = atoi (s);
for (i = 0; i < val; i++)
*t++ = 0x0A;
while (*s != delim)
{
if (*s == 0)
break;
s++;
}
if (*s)
s++;
}
else if (*(s + 1) == 'w')
{
/*
* \w'str'
*/
s += 2;
}
else if (*(s + 1) == 'x')
{
/*
* \x'N'
*/
s += 2;
}
else if (*(s + 1) == 'z')
{
/*
* \zc print c w/o spacing
*/
s += 2;
*t++ = *s++;
*t++ = 0x08;
}
else if (*(s + 1) == '{')
{
/*
* \{
*/
s += 2;
}
else if (*(s + 1) == '}')
{
/*
* \}
*/
s += 2;
}
else if (*(s + 1) == '\n' || *(s + 1) == '\r')
{
/*
* \(newline) ignore newline
*/
s += 2;
}
else
{
/*
* \X any other character not above
*/
s += 1;
*t++ = *s++;
}
}
/*
* end the string and return it in original buf
*/
*t = EOS;
strcpy (p, q);
}
/*------------------------------*/
/* specialchar */
/*------------------------------*/
specialchar (s, c)
register char *s;
register char *c;
{
/*
* handles \(xx escape sequences for special characters (atari-specific)
*/
register char c1;
register char c2;
c1 = *s;
c2 = *(s+1);
/*
* symbols
*/
if (c1 == 'c' && c2 == 'o') {*c = 0xBD; return (2);} /* copyrite */
if (c1 == 'r' && c2 == 'g') {*c = 0xBE; return (2);} /* registered */
if (c1 == 't' && c2 == 'm') {*c = 0xBF; return (2);} /* trademark */
if (c1 == '1' && c2 == '2') {*c = 0xAB; return (2);} /* 1/2 */
if (c1 == '1' && c2 == '4') {*c = 0xAC; return (2);} /* 1/4 */
if (c1 == 'p' && c2 == '2') {*c = 0xFD; return (2);} /* ^2 */
if (c1 == 'p' && c2 == '3') {*c = 0xFE; return (2);} /* ^3 */
if (c1 == 'p' && c2 == 'n') {*c = 0xFC; return (2);} /* ^n */
if (c1 == 'a' && c2 == 'a') {*c = 0xBA; return (2);} /* acute */
if (c1 == 'g' && c2 == 'a') {*c = 0x60; return (2);} /* grave */
if (c1 == 'd' && c2 == 'e') {*c = 0xF8; return (2);} /* degree */
if (c1 == 'd' && c2 == 'g') {*c = 0xBB; return (2);} /* dagger */
if (c1 == 'c' && c2 == 't') {*c = 0x9B; return (2);} /* cent */
if (c1 == 'b' && c2 == 'u') {*c = 0xF9; return (2);} /* bullet */
if (c1 == 'd' && c2 == 't') {*c = 0xFA; return (2);} /* dot */
if (c1 == 'p' && c2 == 'p') {*c = 0xBC; return (2);} /* paragraph */
if (c1 == '^' && c2 == 'g') {*c = 0x07; return (2);} /* ring bell */
if (c1 == 'u' && c2 == 'a') {*c = 0x01; return (2);} /* up arrow */
if (c1 == 'd' && c2 == 'a') {*c = 0x02; return (2);} /* dn arrow */
if (c1 == '-' && c2 == '>') {*c = 0x03; return (2);} /* rt arrow */
if (c1 == '<' && c2 == '-') {*c = 0x04; return (2);} /* lf arrow */
if (c1 == 'd' && c2 == 'i') {*c = 0xF6; return (2);} /* divide */
if (c1 == 's' && c2 == 'r') {*c = 0xFB; return (2);} /* sq root */
if (c1 == '=' && c2 == '=') {*c = 0xF0; return (2);} /* == */
if (c1 == '>' && c2 == '=') {*c = 0xF2; return (2);} /* >= */
if (c1 == '<' && c2 == '=') {*c = 0xF3; return (2);} /* <= */
if (c1 == '+' && c2 == '-') {*c = 0xF1; return (2);} /* +- */
if (c1 == '~' && c2 == '=') {*c = 0xF7; return (2);} /* ~= */
if (c1 == 'a' && c2 == 'p') {*c = 0x7E; return (2);} /* approx */
if (c1 == 'n' && c2 == 'o') {*c = 0xAA; return (2);} /* not */
if (c1 == 'm' && c2 == 'o') {*c = 0xEE; return (2);} /* member */
if (c1 == 'c' && c2 == 'a') {*c = 0xEF; return (2);} /* intersect */
if (c1 == 'c' && c2 == 'u') {*c = 0x55; return (2);} /* union */
if (c1 == 'i' && c2 == '1') {*c = 0xF4; return (2);} /* integral1 */
if (c1 == 'i' && c2 == '2') {*c = 0xF5; return (2);} /* integral2 */
/*
* greek
*/
if (c1 == '*' && c2 == 'a') {*c = 0xE0; return (2);} /* alpha */
if (c1 == '*' && c2 == 'b') {*c = 0xE1; return (2);} /* beta */
if (c1 == '*' && c2 == 'g') {*c = 0xE2; return (2);} /* gamma */
if (c1 == '*' && c2 == 'd') {*c = 0x7F; return (2);} /* delta */
if (c1 == '*' && c2 == 's') {*c = 0xE4; return (2);} /* sigma */
if (c1 == '*' && c2 == 'p') {*c = 0xE3; return (2);} /* pi */
if (c1 == '*' && c2 == 'm') {*c = 0xE6; return (2);} /* mu */
*c = ' ';
return (0);
}
/*------------------------------*/
/* fontchange */
/*------------------------------*/
fontchange (fnt, s)
char fnt;
char *s;
{
/*
* handles \fx font change escapes for R,B,I,S,P (atari-specific)
* resets current and last font in dc struct (last used for .ft
* with no args)
*/
int tmp;
*s = '\0';
switch (fnt)
{
case 'R': /* Times Roman */
if (dc.dofnt == YES)
strcpy (s, "\33q");
dc.lastfnt = dc.thisfnt;
dc.thisfnt = 1;
break;
case 'I': /* Times italic */
if (dc.dofnt == YES)
strcpy (s, "\33p");
dc.lastfnt = dc.thisfnt;
dc.thisfnt = 2;
break;
case 'B': /* Times bold */
if (dc.dofnt == YES)
strcpy (s, "\33p");
dc.lastfnt = dc.thisfnt;
dc.thisfnt = 3;
break;
case 'S': /* math/special */
*s = '\0';
dc.lastfnt = dc.thisfnt;
dc.thisfnt = 4;
break;
case 'P': /* previous (exchange) */
if (dc.dofnt == YES)
{
if (dc.lastfnt == 1)
strcpy (s, "\33q"); /* to R */
else if (dc.lastfnt == 2)
strcpy (s, "\33p"); /* to I */
else if (dc.lastfnt == 3)
strcpy (s, "\33p"); /* to B */
else
*s = '\0'; /* nothing */
}
tmp = dc.thisfnt; /* swap this/last */
dc.thisfnt = dc.lastfnt;
dc.lastfnt = tmp;
break;
default:
*s = '\0';
break;
}
set_ireg (".f", dc.thisfnt, 0);
}
/*------------------------------*/
/* findreg */
/*------------------------------*/
findreg (name)
register char *name;
{
/*
* find register named 'name' in pool. return index into array or -1
* if not found.
*/
register int i;
register char *prname;
for (i = 0; i < MAXREGS; i++)
{
prname = rg[i].rname;
if (*prname == *name && *(prname + 1) == *(name + 1))
break;
}
return ((i < MAXREGS) ? i : -1);
}
@//E*O*F escape.c//
chmod u=rw,g=r,o=r escape.c
echo x - low.c
sed 's/^@//' > "low.c" <<'@//E*O*F low.c//'
/*
* low.c - misc low-level functions for nroff word processor
*
* adapted for atariST/TOS by Bill Rosenkranz 11/89
* net: rosenkra@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* original author:
*
* Stephen L. Browning
* 5723 North Parker Avenue
* Indianapolis, Indiana 46220
*
* history:
*
* - Originally written in BDS C;
* - Adapted for standard C by W. N. Paul
* - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
*/
#undef NRO_MAIN /* extern globals */
#include <stdio.h>
#include "nroff.h"
/*------------------------------*/
/* atod */
/*------------------------------*/
atod (c)
char c;
{
/*
* convert ascii character to decimal.
*/
return (((c < '0') || (c > '9')) ? -1 : c - '0');
}
/*------------------------------*/
/* robrk */
/*------------------------------*/
robrk ()
{
/*
* end current filled line
*/
if (co.outp > 0)
{
co.outbuf[co.outp] = '\r';
co.outbuf[co.outp+1] = '\n';
co.outbuf[co.outp+2] = EOS;
put (co.outbuf);
}
co.outp = 0;
co.outw = 0;
co.outwds = 0;
co.outesc = 0;
}
/*------------------------------*/
/* ctod */
/*------------------------------*/
ctod (p)
register char *p;
{
/*
* convert string to decimal.
* processes only positive values.
*/
register int val;
register int d;
val = 0;
while (*p != EOS)
{
d = atod (*p++);
if (d == -1)
return (val);
val = 10 * val + d;
}
return (val);
}
/*------------------------------*/
/* skipbl */
/*------------------------------*/
char *skipbl (p)
register char *p;
{
/*
* skip blanks and tabs in character buffer. return ptr to first
* non-space or non-tab char. this could mean EOS or \r or \n.
* also increments the arg ptr (side effect).
*/
while (*p == ' ' || *p == '\t')
++p;
return (p);
}
/*------------------------------*/
/* skipwd */
/*------------------------------*/
char *skipwd (p)
register char *p;
{
/*
* skip over word and punctuation. anything but space,\t,\r,\n, and EOS
* is skipped. return ptr to the first of these found. also increments
* the arg ptr (side effect).
*/
while (*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != EOS)
++p;
return (p);
}
/*------------------------------*/
/* space */
/*------------------------------*/
space (n)
int n;
{
/*
* space vertically n lines. this does header and footer also.
*/
robrk ();
if (pg.lineno > pg.bottom)
return;
if (pg.lineno == 0)
phead ();
skip (min (n, pg.bottom + 1 - pg.lineno));
pg.lineno += n;
set_ireg ("ln", pg.lineno, 0);
if (pg.lineno > pg.bottom)
pfoot ();
}
/*------------------------------*/
/* getfield */
/*------------------------------*/
char *getfield (p, q, delim)
register char *p;
register char *q;
char delim;
{
/*
* get field from title
*/
while (*p != delim && *p != '\r' && *p != '\n' && *p != EOS)
{
*q++ = *p++;
}
*q = EOS;
if (*p == delim)
++p;
return (p);
}
/*------------------------------*/
/* getwrd */
/*------------------------------*/
getwrd (p0, p1)
register char *p0;
register char *p1;
{
/*
* get non-blank word from p0 into p1.
* return number of characters processed.
*/
register int i;
register char *p;
char c;
/*
* init counter...
*/
i = 0;
/*
* skip leading whitespace
*/
while (*p0 && (*p0 == ' ' || *p0 == '\t'))
{
++i;
++p0;
}
/*
* set ptr and start to look for end of word
*/
p = p0;
while (*p0 != ' ' && *p0 != EOS && *p0 != '\t')
{
if (*p0 == '\n' || *p0 == '\r')
break;
*p1 = *p0++;
++p1;
++i;
}
c = *(p1 - 1);
if (c == '"')
c = *(p1 - 2);
if (c == '?' || c == '!')
{
*p1++ = ' ';
++i;
}
if (c == '.' && (*p0 == '\n' || *p0 == '\r' || islower (*p)))
{
*p1++ = ' ';
++i;
}
*p1 = EOS;
return (i);
}
/*------------------------------*/
/* countesc */
/*------------------------------*/
#define ESC 27
countesc (p)
register char *p;
{
/*
* count atari escape sequence characters in given null-terminated
* string
*/
register char *pp;
register int num;
pp = p;
num = 0;
while (*pp != EOS)
{
if (*pp == ESC)
{
/*
* count escape char (atari-specific, vt52)
* generally only p,q,b,and c will show up...
*/
switch (*(pp+1))
{
case 'A': /* ESC-a */
case 'B':
case 'C':
case 'D':
case 'E':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'd':
case 'e':
case 'f':
case 'j':
case 'k':
case 'l':
case 'o':
case 'p':
case 'q':
case 'v':
case 'w':
num += 2;
break;
case 'b': /* ESC-a-b */
case 'c':
num += 3;
break;
case 'Y': /* ESC-a-b-c */
num += 4;
break;
default:
num += 1;
break;
}
}
pp++;
}
return (num);
}
/*------------------------------*/
/* itoda */
/*------------------------------*/
itoda (value, p, size)
int value;
register char *p;
register int size;
{
/*
* convert integer to decimal ascii string
*/
register int i;
register int j;
register int k;
register int aval;
char c[20];
aval = abs (value);
c[0] = EOS;
i = 1;
do
{
c[i++] = (aval % 10) + '0';
aval /= 10;
} while (aval > 0 && i <= size);
if (value < 0 && i <= size)
c[i++] = '-';
for (j = 0; j < i; ++j)
*p++ = c[i - j - 1];
return (i);
}
/*------------------------------*/
/* itoROMAN */
/*------------------------------*/
itoROMAN (value, p, size)
int value;
register char *p;
register int size;
{
/*
* convert integer to upper roman. must be positive
*/
register int i;
register int j;
register int k;
register int aval;
char c[100];
int rem;
aval = abs (value);
c[0] = EOS;
i = 1;
/*
* trivial case:
*/
if (aval == 0)
{
c[i++] = '0';
goto done_100;
}
/*
* temporarily mod 100...
*/
aval = aval % 100;
if (aval > 0)
{
/*
* build backward
*
* | I| 1
* | II| 2
* | III| 3
* | VI| 4
* | V| 5
* | IV| 6
* | IIV| 7
* | IIIV| 8
* | XI| 9
* | X| 0
* | IX| 11
* | IIX| 12
*/
if ((aval % 5 == 0) && (aval % 10 != 0))/* 5 */
c[i++] = 'V';
else
{
rem = aval % 10;
if (rem == 9) /* 9 */
{
c[i++] = 'X';
c[i++] = 'I';
}
else if (rem == 8) /* 8 */
{
c[i++] = 'I';
c[i++] = 'I';
c[i++] = 'I';
c[i++] = 'V';
}
else if (rem == 7) /* 7 */
{
c[i++] = 'I';
c[i++] = 'I';
c[i++] = 'V';
}
else if (rem == 6) /* 6 */
{
c[i++] = 'I';
c[i++] = 'V';
}
else if (rem == 4) /* 4 */
{
c[i++] = 'V';
c[i++] = 'I';
}
else /* 3,2,1 */
{
for (j = 0; j < rem; j++)
c[i++] = 'I';
}
}
aval /= 10;
if (aval == 0)
goto done_100;
rem = aval % 10;
if (rem == 4)
{
c[i++] = 'L';
c[i++] = 'X';
}
else if (rem == 5)
{
c[i++] = 'L';
}
else if (rem < 4)
{
for (j = 0; j < rem; j++)
c[i++] = 'X';
}
else
{
for (j = 0; j < rem - 5; j++)
c[i++] = 'X';
c[i++] = 'L';
}
}
done_100:
/*
* divide by 100 (they are done) and temp mod by another 10
*/
aval = abs (value);
aval /= 100;
if (aval > 0)
{
rem = aval % 10;
if (rem == 4)
{
c[i++] = 'D';
c[i++] = 'C';
}
if (rem == 5)
{
c[i++] = 'D';
}
else if (rem < 4)
{
for (j = 0; j < rem; j++)
c[i++] = 'C';
}
else if (rem == 9)
{
c[i++] = 'M';
c[i++] = 'C';
}
else if (rem < 9)
{
for (j = 0; j < rem - 5; j++)
c[i++] = 'C';
c[i++] = 'D';
}
}
aval /= 10;
if (aval > 0)
{
rem = aval % 10;
if (rem < 4)
{
for (j = 0; j < rem; j++)
c[i++] = 'M';
}
}
if (value < 0)
c[i++] = '-';
for (j = 0; j < i; ++j)
*p++ = c[i - j - 1];
return (i);
}
/*------------------------------*/
/* itoroman */
/*------------------------------*/
itoroman (value, p, size)
int value;
char *p;
int size;
{
/*
* convert integer to lower roman
*/
register int i;
register int len;
register int aval;
char c[100];
c[0] = EOS;
len = itoROMAN (value, c, size);
for (i = 0; i < len; i++)
{
p[i] = c[i];
if (isalpha (p[i]))
p[i] = tolower (c[i]);
}
return (len);
}
/*------------------------------*/
/* itoLETTER */
/*------------------------------*/
itoLETTER (value, p, size)
int value;
register char *p;
register int size;
{
/*
* convert integer to upper letter value: 0,A,B,C,...,AA,AB,AC,...
*/
register int i;
register int j;
register int k;
register int aval;
int rem;
char c[20];
aval = abs (value);
c[0] = EOS;
i = 1;
/*
* 1 based:
*
* 0 0
* 1 A
* 25 Z
* 26 AA
* 51 AZ
* 52 AAA
* ...
*/
if (aval == 0)
c[i++] = '0';
else if (aval < 27)
{
c[i++] = aval - 1 + 'A';
}
else
{
do
{
c[i++] = ((aval - 1) % 26) + 'A';
aval = (aval - 1) / 26;
} while (aval > 0 && i <= size);
}
if (value < 0 && i <= size)
c[i++] = '-';
for (j = 0; j < i; ++j)
*p++ = c[i - j - 1];
return (i);
}
/*------------------------------*/
/* itoletter */
/*------------------------------*/
itoletter (value, p, size)
int value;
register char *p;
register int size;
{
/*
* convert integer to upper letter value: 0,a,b,c,...,aa,ab,ac,...
*/
register int i;
register int j;
register int k;
register int aval;
char c[20];
int rem;
aval = abs (value);
c[0] = EOS;
i = 1;
/*
* 1 based:
*
* 0 0
* 1 A
* 25 Z
* 26 AA
* 51 AZ
* 52 AAA
* ...
*/
if (aval == 0)
c[i++] = '0';
else if (aval < 27)
{
c[i++] = aval - 1 + 'a';
}
else
{
do
{
c[i++] = ((aval - 1) % 26) + 'a';
aval = (aval - 1) / 26;
} while (aval > 0 && i <= size);
}
if (value < 0 && i <= size)
c[i++] = '-';
for (j = 0; j < i; ++j)
*p++ = c[i - j - 1];
return (i);
}
/*------------------------------*/
/* min */
/*------------------------------*/
#ifdef min
#undef min
#endif
min (v1, v2)
register int v1;
register int v2;
{
/*
* find minimum of two integer ONLY
*/
return ((v1 < v2) ? v1 : v2);
}
/*------------------------------*/
/* max */
/*------------------------------*/
#ifdef max
#undef max
#endif
max (v1, v2)
register int v1;
register int v2;
{
/*
* find maximum of two integers ONLY
*/
return ((v1 > v2) ? v1 : v2);
}
/*------------------------------*/
/* err_exit */
/*------------------------------*/
#ifdef ALCYON
#include <osbind.h>
#endif
err_exit (code)
{
/*
* exit cleanly on fatal error (close files, etc). also handles normal
* exit.
*/
if (err_stream != stderr && err_stream != (FILE *) 0)
fclose (err_stream);
if (dbg_stream != stderr && dbg_stream != (FILE *) 0)
fclose (dbg_stream);
#ifdef ALCYON
if (hold_screen)
{
printf ("enter any key...");
Cconin ();
}
#endif
exit (code);
}
@//E*O*F low.c//
chmod u=rw,g=r,o=r low.c
echo x - macros.c
sed 's/^@//' > "macros.c" <<'@//E*O*F macros.c//'
/*
* macros.c - macro input/output processing for nroff word processor
*
* adapted for atariST/TOS by Bill Rosenkranz 11/89
* net: rosenkra@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* original author:
*
* Stephen L. Browning
* 5723 North Parker Avenue
* Indianapolis, Indiana 46220
*
* history:
*
* - Originally written in BDS C;
* - Adapted for standard C by W. N. Paul
* - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
*/
#undef NRO_MAIN /* extern globals */
#include <stdio.h>
#include "nroff.h"
/*------------------------------*/
/* defmac */
/*------------------------------*/
defmac (p, infp)
register char *p;
FILE *infp;
{
/*
* Define a macro. top level, read from stream.
*
* we should read macro without interpretation EXCEPT:
*
* 1) number registers are interpolated
* 2) strings indicated by \* are interpolated
* 3) arguments indicated by \$ are interpolated
* 4) concealed newlines indicated by \(newline) are eliminated
* 5) comments indicated by \" are eliminated
* 6) \t and \a are interpreted as ASCII h tab and SOH.
* 7) \\ is interpreted as backslash and \. is interpreted as a period.
*
* currently, we do only 3. a good place to do it would be here before
* putmac, after colmac...
*/
register char *q;
register int i;
char name[MNLEN];
char defn[MXMLEN];
char newend[10];
/*
* skip the .de and get to the name...
*/
q = skipwd (p);
q = skipbl (q);
/*
* ok, name now holds the name. make sure it is valid (i.e. first
* char is alpha...). getwrd returns the length of the word.
*/
i = getwrd (q, name);
if (!isalpha (*name))
{
fprintf (err_stream,
"***%s: missing or illegal macro definition name\n",
myname);
err_exit (-1);
}
/*
* truncate to 2 char max name.
*/
if (i > 2)
name[2] = EOS;
/*
* skip the name and see if we have a new end defined...
*/
q = skipwd (p);
q = skipbl (q);
for (i = 0; i < 10; i++)
newend[i] = EOS;
for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++)
{
newend[i] = q[i];
}
/*
* read a line from input stream until we get the end of macro
* command (.en or ..). actually. we should have read the next
* field just above here to get the .de NA . or .de NA en string
* to be new end of macro.
*/
i = 0;
while (getlin (p, infp) != EOF)
{
if (p[0] == dc.cmdchr && newend[0] != EOS
&& p[1] == newend[0] && p[2] == newend[1])
{
/*
* replacement end found
*/
break;
}
if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n')
{
/*
* .en found
*/
break;
}
if (p[0] == dc.cmdchr && p[1] == dc.cmdchr)
{
/*
* .. found
*/
break;
}
/*
* collect macro from the line we just read. all this does
* is put it in the string defn.
*/
if ((i = colmac (p, defn, i)) == ERR)
{
fprintf (err_stream,
"***%s: macro definition too long\n", myname);
err_exit (-1);
}
}
/*
* store the macro
*/
if (putmac (name, defn) == ERR)
{
fprintf (err_stream,
"***%s: macro definition table full\n", myname);
err_exit (-1);
}
}
/*------------------------------*/
/* colmac */
/*------------------------------*/
colmac (p, d, i)
register char *p;
char d[];
register int i;
{
/*
* Collect macro definition from input stream
*/
while (*p != EOS)
{
if (i >= MXMLEN - 1)
{
d[i - 1] = EOS;
return (ERR);
}
d[i++] = *p++;
}
d[i] = EOS;
return (i);
}
/*------------------------------*/
/* putmac */
/*------------------------------*/
putmac (name, p)
char *name;
char *p;
{
/*
* Put macro definition into table
*
* NOTE: any expansions of things like number registers SHOULD
* have been done already.
*/
/*
* any room left? (did we exceed max number of possible macros)
*/
if (mac.lastp >= MXMDEF)
return (ERR);
/*
* will new one fit in big buffer?
*/
if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
{
return (ERR);
}
/*
* add it...
*
* bump counter, set ptr to name, copy name, copy def.
* finally increment end of macro buffer ptr (emb).
*
* macro looks like this in mb:
*
* mac.mb[MACBUF] size of total buf
* lastp < MXMDEF number of macros possible
* *mnames[MXMDEF] -> names, each max length
* ..._____________________________...____________________...
* / / /|X|X|0|macro definition |0| / / / / / / /
* .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_...
* ^
* |
* \----- mac.mnames[mac.lastp] points here
*
* both the 2 char name (XX) and the descripton are null term and
* follow one after the other.
*/
++mac.lastp;
mac.mnames[mac.lastp] = mac.emb;
strcpy (mac.emb, name);
strcpy (mac.emb + strlen (name) + 1, p);
mac.emb += strlen (name) + strlen (p) + 2;
return (OK);
}
/*------------------------------*/
/* getmac */
/*------------------------------*/
char *getmac (name)
register char *name;
{
/*
* Get (lookup) macro definition from namespace
*/
register int i;
/*
* loop for all macros, starting with last one
*/
for (i = mac.lastp; i >= 0; --i)
{
/*
* is this REALLY a macro?
*/
if (mac.mnames[i])
{
/*
* if it compares, return a ptr to it
*/
if (!strcmp (name, mac.mnames[i]))
{
/*!!!debug puts (mac.mnames[i]);*/
if (mac.mnames[i][1] == EOS)
return (mac.mnames[i] + 2);
else
return (mac.mnames[i] + 3);
}
}
}
/*
* none found, return null
*/
return (NULL);
}
/*------------------------------*/
/* maceval */
/*------------------------------*/
maceval (p, m)
register char *p;
char m[];
{
/*
* Evaluate macro expansion
*/
register int i;
register int j;
char *argp[10];
char c;
/*
* replace command char with EOS
*/
*p++ = EOS;
/*
* initialize argp array to substitute command
* string for any undefined argument
*
* NO!!! this is fixed...
*/
for (i = 0; i < 10; ++i)
argp[i] = p;
/*
* skip the command name
*/
p = skipwd (p);
*p++ = EOS;
/*
* loop for all $n variables...
*/
for (i = 0; i < 10; ++i)
{
/*
* get to substituted param and if no more, reset remaining
* args to NULL and stop...
*/
p = skipbl (p);
if (*p == '\r' || *p == '\n' || *p == EOS)
{
for ( ; i < 10; i++)
*argp[i] = '\0';
break;
}
/*
* ...otherwise, see if this param is quoted. if it is,
* it is all one parameter, even with blanks (but not
* newlines...). look for another "c" (which is the quote).
*
* if no quote, just read the arg as a single word and null
* terminate it.
*/
if (*p == '\'' || *p == '"')
{
c = *p++;
argp[i] = p;
while (*p != c && *p != '\r' && *p != '\n' && *p != EOS)
++p;
*p++ = EOS;
}
else
{
argp[i] = p;
p = skipwd (p);
*p++ = EOS;
}
}
/*
* m contains text of the macro. p contained the input line.
* here we start at the end of the macro def and see if there
* are any $n thingies. go backwards.
*/
for (i = strlen (m) - 1; i >= 0; --i)
{
/*
* found a $.
*/
if (i > 0 && m[i - 1] == '$')
{
if (!isdigit (m[i]))
{
/*
* it wasn't a numeric replacement arg so
* push this char back onto input stream
*/
putbak (m[i]);
}
else
{
/*
* it WAS a numeric replacement arg. so we
* want to push back the appropriate macro
* invocation arg. m[i]-'0' is the numerical
* value of the $0 thru $9. if the arg is
* not there, argp[n] will be (char *) 0
* and pbstr will do nothing.
*/
pbstr (argp[m[i] - '0']);
--i;
}
}
else
{
/*
* no $ so push back the char...
*/
putbak (m[i]);
}
}
/*
* at this point, the iobuf will hold the new macro command, full
* expanded for $n things. the return gets us right back to the
* main loop in main() and we parse the (new) command just as if
* it were read from a file.
*/
}
/*------------------------------*/
/* printmac */
/*------------------------------*/
printmac (opt)
int opt; /* 0=name&size,1=total size,2=full */
{
/*
* print all macros and strings and tabulate sizes
*/
register long i;
register long space;
register long totalspace;
register char *pname;
register char *pdef;
space = 0L;
totalspace = 0L;
fflush (pout);
fflush (err_stream);
for (i = (long) mac.lastp; i >= 0; --i)
{
/*
* is this REALLY a macro?
*/
if (mac.mnames[i])
{
pname = (char *) (mac.mnames[i]);
pdef = pname + 3;
if (*(pname + 1) == '\0')
pdef = pname + 2;
space = (long) strlen (pdef);
totalspace += space;
switch (opt)
{
case 0:
fprintf (err_stream, "%s %ld\n", pname, space);
break;
case 2:
fprintf (err_stream, "%s %ld\n", pname, space);
fprintf (err_stream, "%s\n", pdef);
break;
case 1:
default:
break;
}
}
}
fprintf (err_stream, "Total space: %ld\n", totalspace);
}
@//E*O*F macros.c//
chmod u=rw,g=r,o=r macros.c
echo x - strings.c
sed 's/^@//' > "strings.c" <<'@//E*O*F strings.c//'
/*
* strings.c - String input/output processing for nroff word processor
*
* adapted for atariST/TOS by Bill Rosenkranz 11/89
* net: rosenkra@hall.cray.com
* CIS: 71460,17
* GENIE: W.ROSENKRANZ
*
* original author:
*
* Stephen L. Browning
* 5723 North Parker Avenue
* Indianapolis, Indiana 46220
*
* history:
*
* - Originally written in BDS C;
* - Adapted for standard C by W. N. Paul
* - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
*/
#undef NRO_MAIN /* extern globals */
#include <stdio.h>
#include "nroff.h"
/*------------------------------*/
/* defstr */
/*------------------------------*/
defstr (p)
register char *p;
{
/*
* Define a string. top level, read from command line.
*
* we should read string without interpretation EXCEPT:
*
* 1) number registers are interpolated
* 2) strings indicated by \* are interpolated
* 3) arguments indicated by \$ are interpolated
* 4) concealed newlines indicated by \(newline) are eliminated
* 5) comments indicated by \" are eliminated
* 6) \t and \a are interpreted as ASCII h tab and SOH.
* 7) \\ is interpreted as backslash and \. is interpreted as a period.
*
* currently, we do only 3. a good place to do it would be here before
* putstr, after colstr...
*/
register char *q;
register int i;
char name[MNLEN];
char defn[MXMLEN];
name[0] = '\0';
defn[0] = '\0';
/*
* skip the .ds and get to the name...
*/
q = skipwd (p);
q = skipbl (q);
/*
* ok, name now holds the name. make sure it is valid (i.e. first
* char is alpha...). getwrd returns the length of the word.
*/
i = getwrd (q, name);
if (!name[0])
{
fprintf (err_stream,
"***%s: missing or illegal string definition name\n",
myname);
err_exit (-1);
}
/*
* truncate to 2 char max name.
*/
if (i > 2)
name[2] = EOS;
/*
* skip the name to get to the string. it CAN start with a " to
* have leading blanks...
*/
q = skipwd (q);
q = skipbl (q);
/*
* read rest of line from input stream and collect string into
* temp buffer defn
*/
if ((i = colstr (q, defn)) == ERR)
{
fprintf (err_stream,
"***%s: string definition too long\n", myname);
err_exit (-1);
}
/*
* store the string
*/
if (putstr (name, defn) == ERR)
{
fprintf (err_stream,
"***%s: string definition table full\n", myname);
err_exit (-1);
}
}
/*------------------------------*/
/* colstr */
/*------------------------------*/
colstr (p, d)
register char *p;
char d[];
{
/*
* Collect string definition from input stream
*/
register int i = 0;
if (*p == '\"')
p++;
while (*p != EOS)
{
if (i >= MXMLEN - 1)
{
d[i - 1] = EOS;
return (ERR);
}
d[i++] = *p++;
}
d[i] = EOS;
return (i);
}
/*------------------------------*/
/* putstr */
/*------------------------------*/
putstr (name, p)
register char *name;
register char *p;
{
/*
* Put string definition into (macro) table
*
* NOTE: any expansions of things like number registers SHOULD
* have been done already. strings and macros share mb buffer
*/
/*
* any room left? (did we exceed max number of possible macros)
*/
if (mac.lastp >= MXMDEF)
return (ERR);
/*
* will new one fit in big buffer?
*/
if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
{
return (ERR);
}
/*
* add it...
*
* bump counter, set ptr to name, copy name, copy def.
* finally increment end of macro buffer ptr (emb).
*
* string looks like this in mb:
*
* mac.mb[MACBUF] size of total buf
* lastp < MXMDEF number of macros/strings possible
* *mnames[MXMDEF] -> names, each max length
* ...______________________________...____________________...
* / / /|X|X|0|string definition |0| / / / / / / /
* .../_/_/_|_|_|_|_________________...___|_|/_/_/_/_/_/_/_...
* ^
* |
* \----- mac.mnames[mac.lastp] points here
*
* both the 2 char name (XX) and the descripton are null term and
* follow one after the other.
*/
++mac.lastp;
mac.mnames[mac.lastp] = mac.emb;
strcpy (mac.emb, name);
strcpy (mac.emb + strlen (name) + 1, p);
mac.emb += strlen (name) + strlen (p) + 2;
return (OK);
}
/*------------------------------*/
/* getstr */
/*------------------------------*/
char *getstr (name)
register char *name;
{
/*
* Get (lookup) string definition from namespace
*/
register int i;
/*
* loop for all macros, starting with last one
*/
for (i = mac.lastp; i >= 0; --i)
{
/*
* is this REALLY a macro?
*/
if (mac.mnames[i])
{
/*
* if it compares, return a ptr to it
*/
if (!strcmp (name, mac.mnames[i]))
{
/*!!!debug puts (mac.mnames[i]);*/
if (mac.mnames[i][1] == EOS)
return (mac.mnames[i] + 2);
else
return (mac.mnames[i] + 3);
}
}
}
/*
* none found, return null
*/
return (NULL);
}
@//E*O*F strings.c//
chmod u=rw,g=r,o=r strings.c
exit 0