mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
955 lines
16 KiB
C
955 lines
16 KiB
C
|
/*
|
||
|
* troff3.c
|
||
|
*
|
||
|
* macro and string routines, storage allocation
|
||
|
*/
|
||
|
|
||
|
#include "tdef.h"
|
||
|
#include "fns.h"
|
||
|
#include "ext.h"
|
||
|
|
||
|
Tchar *argtop;
|
||
|
int pagech = '%';
|
||
|
int strflg;
|
||
|
|
||
|
#define MHASHSIZE 128 /* must be 2**n */
|
||
|
#define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1)
|
||
|
Contab *mhash[MHASHSIZE];
|
||
|
|
||
|
|
||
|
Blockp *blist; /* allocated blocks for macros and strings */
|
||
|
int nblist; /* how many there are */
|
||
|
int bfree = -1; /* first (possible) free block in the list */
|
||
|
|
||
|
Contab *contabp = NULL;
|
||
|
#define MDELTA 500
|
||
|
int nm = 0;
|
||
|
|
||
|
int savname; /* name of macro/string being defined */
|
||
|
int savslot; /* place in Contab of savname */
|
||
|
int freeslot = -1; /* first (possible) free slot in contab */
|
||
|
|
||
|
void prcontab(Contab *p)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < nm; i++)
|
||
|
if (p)
|
||
|
if (p[i].rq != 0)
|
||
|
fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
|
||
|
else
|
||
|
fprintf(stderr, "slot %d empty\n", i);
|
||
|
else
|
||
|
fprintf(stderr, "slot %d empty\n", i);
|
||
|
}
|
||
|
|
||
|
|
||
|
void blockinit(void)
|
||
|
{
|
||
|
blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
|
||
|
if (blist == NULL) {
|
||
|
ERROR "not enough room for %d blocks", NBLIST WARN;
|
||
|
done2(1);
|
||
|
}
|
||
|
nblist = NBLIST;
|
||
|
blist[0].nextoff = blist[1].nextoff = -1;
|
||
|
blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
|
||
|
blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
|
||
|
/* -1 prevents blist[0] from being used; temporary fix */
|
||
|
/* for a design botch: offset==0 is overloaded. */
|
||
|
/* blist[1] reserved for .rd indicator -- also unused. */
|
||
|
/* but someone unwittingly looks at these, so allocate something */
|
||
|
bfree = 2;
|
||
|
}
|
||
|
|
||
|
|
||
|
char *grow(char *ptr, int num, int size) /* make array bigger */
|
||
|
{
|
||
|
char *p, new;
|
||
|
|
||
|
if (ptr == NULL)
|
||
|
p = (char *) calloc(num, size);
|
||
|
else
|
||
|
p = (char *) realloc(ptr, num * size);
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void mnspace(void)
|
||
|
{
|
||
|
nm = sizeof(contab)/sizeof(Contab) + MDELTA;
|
||
|
freeslot = sizeof(contab)/sizeof(Contab) + 1;
|
||
|
contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
|
||
|
if (contabp == NULL) {
|
||
|
ERROR "not enough memory for namespace of %d marcos", nm WARN;
|
||
|
exit(1);
|
||
|
}
|
||
|
contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
|
||
|
sizeof(contab));
|
||
|
if (contabp == NULL) {
|
||
|
ERROR "Cannot reinitialize macro/request name list" WARN;
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void caseig(void)
|
||
|
{
|
||
|
int i;
|
||
|
Offset oldoff = offset;
|
||
|
|
||
|
offset = 0;
|
||
|
i = copyb();
|
||
|
offset = oldoff;
|
||
|
if (i != '.')
|
||
|
control(i, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void casern(void)
|
||
|
{
|
||
|
int i, j, k;
|
||
|
|
||
|
lgf++;
|
||
|
skip();
|
||
|
if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
|
||
|
return;
|
||
|
skip();
|
||
|
clrmn(findmn(j = getrq()));
|
||
|
if (j) {
|
||
|
munhash(&contabp[oldmn]);
|
||
|
contabp[oldmn].rq = j;
|
||
|
maddhash(&contabp[oldmn]);
|
||
|
if (dip != d )
|
||
|
for (k = dilev; k; k--)
|
||
|
if (d[k].curd == i)
|
||
|
d[k].curd = j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void maddhash(Contab *rp)
|
||
|
{
|
||
|
Contab **hp;
|
||
|
|
||
|
if (rp->rq == 0)
|
||
|
return;
|
||
|
hp = &mhash[MHASH(rp->rq)];
|
||
|
rp->link = *hp;
|
||
|
*hp = rp;
|
||
|
}
|
||
|
|
||
|
void munhash(Contab *mp)
|
||
|
{
|
||
|
Contab *p;
|
||
|
Contab **lp;
|
||
|
|
||
|
if (mp->rq == 0)
|
||
|
return;
|
||
|
lp = &mhash[MHASH(mp->rq)];
|
||
|
p = *lp;
|
||
|
while (p) {
|
||
|
if (p == mp) {
|
||
|
*lp = p->link;
|
||
|
p->link = 0;
|
||
|
return;
|
||
|
}
|
||
|
lp = &p->link;
|
||
|
p = p->link;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mrehash(void)
|
||
|
{
|
||
|
Contab *p;
|
||
|
int i;
|
||
|
|
||
|
for (i=0; i < MHASHSIZE; i++)
|
||
|
mhash[i] = 0;
|
||
|
for (p=contabp; p < &contabp[nm]; p++)
|
||
|
p->link = 0;
|
||
|
for (p=contabp; p < &contabp[nm]; p++) {
|
||
|
if (p->rq == 0)
|
||
|
continue;
|
||
|
i = MHASH(p->rq);
|
||
|
p->link = mhash[i];
|
||
|
mhash[i] = p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void caserm(void)
|
||
|
{
|
||
|
int j;
|
||
|
int k = 0;
|
||
|
|
||
|
lgf++;
|
||
|
g0:
|
||
|
while (!skip() && (j = getrq()) != 0) {
|
||
|
if (dip != d)
|
||
|
for (k = dilev; k; k--)
|
||
|
if (d[k].curd == j) {
|
||
|
ERROR "cannot remove diversion %s during definition",
|
||
|
unpair(j) WARN;
|
||
|
goto g0;
|
||
|
}
|
||
|
clrmn(findmn(j));
|
||
|
}
|
||
|
lgf--;
|
||
|
}
|
||
|
|
||
|
|
||
|
void caseas(void)
|
||
|
{
|
||
|
app++;
|
||
|
caseds();
|
||
|
}
|
||
|
|
||
|
|
||
|
void caseds(void)
|
||
|
{
|
||
|
ds++;
|
||
|
casede();
|
||
|
}
|
||
|
|
||
|
|
||
|
void caseam(void)
|
||
|
{
|
||
|
app++;
|
||
|
casede();
|
||
|
}
|
||
|
|
||
|
|
||
|
void casede(void)
|
||
|
{
|
||
|
int i, req;
|
||
|
Offset savoff;
|
||
|
|
||
|
req = '.';
|
||
|
lgf++;
|
||
|
skip();
|
||
|
if ((i = getrq()) == 0)
|
||
|
goto de1;
|
||
|
if ((offset = finds(i)) == 0)
|
||
|
goto de1;
|
||
|
if (newmn)
|
||
|
savslot = newmn;
|
||
|
else
|
||
|
savslot = findmn(i);
|
||
|
savname = i;
|
||
|
if (ds)
|
||
|
copys();
|
||
|
else
|
||
|
req = copyb();
|
||
|
clrmn(oldmn);
|
||
|
if (newmn) {
|
||
|
if (contabp[newmn].rq)
|
||
|
munhash(&contabp[newmn]);
|
||
|
contabp[newmn].rq = i;
|
||
|
maddhash(&contabp[newmn]);
|
||
|
|
||
|
}
|
||
|
if (apptr) {
|
||
|
savoff = offset;
|
||
|
offset = apptr;
|
||
|
wbf((Tchar) IMP);
|
||
|
offset = savoff;
|
||
|
}
|
||
|
offset = dip->op;
|
||
|
if (req != '.')
|
||
|
control(req, 1);
|
||
|
de1:
|
||
|
ds = app = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int findmn(int i)
|
||
|
{
|
||
|
Contab *p;
|
||
|
|
||
|
for (p = mhash[MHASH(i)]; p; p = p->link)
|
||
|
if (i == p->rq)
|
||
|
return(p - contabp);
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void clrmn(int i)
|
||
|
{
|
||
|
if (i >= 0) {
|
||
|
if (contabp[i].mx)
|
||
|
ffree(contabp[i].mx);
|
||
|
munhash(&contabp[i]);
|
||
|
contabp[i].rq = 0;
|
||
|
contabp[i].mx = 0;
|
||
|
contabp[i].emx = 0;
|
||
|
contabp[i].f = 0;
|
||
|
if (contabp[i].divsiz != NULL) {
|
||
|
free(contabp[i].divsiz);
|
||
|
contabp[i].divsiz = NULL;
|
||
|
}
|
||
|
if (freeslot > i)
|
||
|
freeslot = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void growcontab(void)
|
||
|
{
|
||
|
nm += MDELTA;
|
||
|
contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
|
||
|
if (contabp == NULL) {
|
||
|
ERROR "Too many (%d) string/macro names", nm WARN;
|
||
|
done2(02);
|
||
|
} else {
|
||
|
memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
|
||
|
0, MDELTA * sizeof(Contab));
|
||
|
mrehash();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Offset finds(int mn)
|
||
|
{
|
||
|
int i;
|
||
|
Tchar j = IMP;
|
||
|
Offset savip;
|
||
|
|
||
|
oldmn = findmn(mn);
|
||
|
newmn = 0;
|
||
|
apptr = 0;
|
||
|
if (app && oldmn >= 0 && contabp[oldmn].mx) {
|
||
|
savip = ip;
|
||
|
ip = contabp[oldmn].emx;
|
||
|
oldmn = -1;
|
||
|
apptr = ip;
|
||
|
if (!diflg)
|
||
|
ip = incoff(ip);
|
||
|
nextb = ip;
|
||
|
ip = savip;
|
||
|
} else {
|
||
|
for (i = freeslot; i < nm; i++) {
|
||
|
if (contabp[i].rq == 0)
|
||
|
break;
|
||
|
}
|
||
|
if (i == nm)
|
||
|
growcontab();
|
||
|
freeslot = i + 1;
|
||
|
if ((nextb = alloc()) == -1) {
|
||
|
app = 0;
|
||
|
if (macerr++ > 1)
|
||
|
done2(02);
|
||
|
if (nextb == 0)
|
||
|
ERROR "Not enough space for string/macro names" WARN;
|
||
|
edone(04);
|
||
|
return(offset = 0);
|
||
|
}
|
||
|
contabp[i].mx = nextb;
|
||
|
if (!diflg) {
|
||
|
newmn = i;
|
||
|
if (oldmn == -1)
|
||
|
contabp[i].rq = -1;
|
||
|
} else {
|
||
|
contabp[i].rq = mn;
|
||
|
maddhash(&contabp[i]);
|
||
|
}
|
||
|
}
|
||
|
app = 0;
|
||
|
return(offset = nextb);
|
||
|
}
|
||
|
|
||
|
int skip(void)
|
||
|
{
|
||
|
Tchar i;
|
||
|
|
||
|
while (cbits(i = getch()) == ' ' || ismot(i))
|
||
|
;
|
||
|
ch = i;
|
||
|
return(nlflg);
|
||
|
}
|
||
|
|
||
|
|
||
|
int copyb(void)
|
||
|
{
|
||
|
int i, j, state;
|
||
|
Tchar ii;
|
||
|
int req, k;
|
||
|
Offset savoff;
|
||
|
Uchar *p;
|
||
|
|
||
|
if (skip() || !(j = getrq()))
|
||
|
j = '.';
|
||
|
req = j;
|
||
|
p = unpair(j);
|
||
|
/* was: k = j >> BYTE; j &= BYTEMASK; */
|
||
|
j = p[0];
|
||
|
k = p[1];
|
||
|
copyf++;
|
||
|
flushi();
|
||
|
nlflg = 0;
|
||
|
state = 1;
|
||
|
|
||
|
/* state 0 eat up
|
||
|
* state 1 look for .
|
||
|
* state 2 look for first char of end macro
|
||
|
* state 3 look for second char of end macro
|
||
|
*/
|
||
|
|
||
|
while (1) {
|
||
|
i = cbits(ii = getch());
|
||
|
if (state == 3) {
|
||
|
if (i == k)
|
||
|
break;
|
||
|
if (!k) {
|
||
|
ch = ii;
|
||
|
i = getach();
|
||
|
ch = ii;
|
||
|
if (!i)
|
||
|
break;
|
||
|
}
|
||
|
state = 0;
|
||
|
goto c0;
|
||
|
}
|
||
|
if (i == '\n') {
|
||
|
state = 1;
|
||
|
nlflg = 0;
|
||
|
goto c0;
|
||
|
}
|
||
|
if (state == 1 && i == '.') {
|
||
|
state++;
|
||
|
savoff = offset;
|
||
|
goto c0;
|
||
|
}
|
||
|
if (state == 2 && i == j) {
|
||
|
state++;
|
||
|
goto c0;
|
||
|
}
|
||
|
state = 0;
|
||
|
c0:
|
||
|
if (offset)
|
||
|
wbf(ii);
|
||
|
}
|
||
|
if (offset) {
|
||
|
offset = savoff;
|
||
|
wbf((Tchar)0);
|
||
|
}
|
||
|
copyf--;
|
||
|
return(req);
|
||
|
}
|
||
|
|
||
|
|
||
|
void copys(void)
|
||
|
{
|
||
|
Tchar i;
|
||
|
|
||
|
copyf++;
|
||
|
if (skip())
|
||
|
goto c0;
|
||
|
if (cbits(i = getch()) != '"')
|
||
|
wbf(i);
|
||
|
while (cbits(i = getch()) != '\n')
|
||
|
wbf(i);
|
||
|
c0:
|
||
|
wbf((Tchar)0);
|
||
|
copyf--;
|
||
|
}
|
||
|
|
||
|
|
||
|
Offset alloc(void) /* return free Offset in nextb */
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
for (i = bfree; i < nblist; i++)
|
||
|
if (blist[i].nextoff == 0)
|
||
|
break;
|
||
|
if (i == nblist) {
|
||
|
blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
|
||
|
if (blist == NULL) {
|
||
|
ERROR "can't grow blist for string/macro defns" WARN;
|
||
|
done2(2);
|
||
|
}
|
||
|
nblist *= 2;
|
||
|
for (j = i; j < nblist; j++) {
|
||
|
blist[j].nextoff = 0;
|
||
|
blist[j].bp = 0;
|
||
|
}
|
||
|
}
|
||
|
blist[i].nextoff = -1; /* this block is the end */
|
||
|
bfree = i + 1;
|
||
|
if (blist[i].bp == 0)
|
||
|
blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
|
||
|
if (blist[i].bp == NULL) {
|
||
|
ERROR "can't allocate memory for string/macro definitions" WARN;
|
||
|
done2(2);
|
||
|
}
|
||
|
nextb = (Offset) i * BLK;
|
||
|
return nextb;
|
||
|
}
|
||
|
|
||
|
|
||
|
void ffree(Offset i) /* free list of blocks starting at blist(o) */
|
||
|
{ /* (doesn't actually free the blocks, just the pointers) */
|
||
|
int j;
|
||
|
|
||
|
for ( ; blist[j = bindex(i)].nextoff != -1; ) {
|
||
|
if (bfree > j)
|
||
|
bfree = j;
|
||
|
i = blist[j].nextoff;
|
||
|
blist[j].nextoff = 0;
|
||
|
}
|
||
|
blist[j].nextoff = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void wbf(Tchar i) /* store i into offset, get ready for next one */
|
||
|
{
|
||
|
int j, off;
|
||
|
|
||
|
if (!offset)
|
||
|
return;
|
||
|
j = bindex(offset);
|
||
|
if (i == 0)
|
||
|
contabp[savslot].emx = offset;
|
||
|
off = boffset(offset);
|
||
|
blist[j].bp[off++] = i;
|
||
|
offset++;
|
||
|
if (pastend(offset)) { /* off the end of this block */
|
||
|
if (blist[j].nextoff == -1) {
|
||
|
if ((nextb = alloc()) == -1) {
|
||
|
ERROR "Out of temp file space" WARN;
|
||
|
done2(01);
|
||
|
}
|
||
|
blist[j].nextoff = nextb;
|
||
|
}
|
||
|
offset = blist[j].nextoff;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Tchar rbf(void) /* return next char from blist[] block */
|
||
|
{
|
||
|
Tchar i, j;
|
||
|
|
||
|
if (ip == RD_OFFSET) { /* for rdtty */
|
||
|
if (j = rdtty())
|
||
|
return(j);
|
||
|
else
|
||
|
return(popi());
|
||
|
}
|
||
|
|
||
|
i = rbf0(ip);
|
||
|
if (i == 0) {
|
||
|
if (!app)
|
||
|
i = popi();
|
||
|
return(i);
|
||
|
}
|
||
|
ip = incoff(ip);
|
||
|
return(i);
|
||
|
}
|
||
|
|
||
|
|
||
|
Offset xxxincoff(Offset p) /* get next blist[] block */
|
||
|
{
|
||
|
p++;
|
||
|
if (pastend(p)) { /* off the end of this block */
|
||
|
if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and nothing was allocated after it */
|
||
|
ERROR "Bad storage allocation" WARN;
|
||
|
done2(-5);
|
||
|
}
|
||
|
}
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
Tchar popi(void)
|
||
|
{
|
||
|
Stack *p;
|
||
|
|
||
|
if (frame == stk)
|
||
|
return(0);
|
||
|
if (strflg)
|
||
|
strflg--;
|
||
|
p = nxf = frame;
|
||
|
p->nargs = 0;
|
||
|
frame = p->pframe;
|
||
|
ip = p->pip;
|
||
|
pendt = p->ppendt;
|
||
|
lastpbp = p->lastpbp;
|
||
|
return(p->pch);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* test that the end of the allocation is above a certain location
|
||
|
* in memory
|
||
|
*/
|
||
|
#define SPACETEST(base, size) \
|
||
|
if ((char*)base + size >= (char*)stk+STACKSIZE) \
|
||
|
ERROR "Stacksize overflow in n3" WARN
|
||
|
|
||
|
Offset pushi(Offset newip, int mname)
|
||
|
{
|
||
|
Stack *p;
|
||
|
|
||
|
SPACETEST(nxf, sizeof(Stack));
|
||
|
p = nxf;
|
||
|
p->pframe = frame;
|
||
|
p->pip = ip;
|
||
|
p->ppendt = pendt;
|
||
|
p->pch = ch;
|
||
|
p->lastpbp = lastpbp;
|
||
|
p->mname = mname;
|
||
|
lastpbp = pbp;
|
||
|
pendt = ch = 0;
|
||
|
frame = nxf;
|
||
|
if (nxf->nargs == 0)
|
||
|
nxf += 1;
|
||
|
else
|
||
|
nxf = (Stack *)argtop;
|
||
|
return(ip = newip);
|
||
|
}
|
||
|
|
||
|
|
||
|
void *setbrk(int x)
|
||
|
{
|
||
|
char *i;
|
||
|
|
||
|
if ((i = (char *) calloc(x, 1)) == 0) {
|
||
|
ERROR "Core limit reached" WARN;
|
||
|
edone(0100);
|
||
|
}
|
||
|
return(i);
|
||
|
}
|
||
|
|
||
|
|
||
|
int getsn(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if ((i = getach()) == 0)
|
||
|
return(0);
|
||
|
if (i == '(')
|
||
|
return(getrq());
|
||
|
else
|
||
|
return(i);
|
||
|
}
|
||
|
|
||
|
|
||
|
Offset setstr(void)
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
lgf++;
|
||
|
if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
|
||
|
lgf--;
|
||
|
return(0);
|
||
|
} else {
|
||
|
SPACETEST(nxf, sizeof(Stack));
|
||
|
nxf->nargs = 0;
|
||
|
strflg++;
|
||
|
lgf--;
|
||
|
return pushi(contabp[j].mx, i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void collect(void)
|
||
|
{
|
||
|
int j;
|
||
|
Tchar i, *strp, *lim, **argpp, **argppend;
|
||
|
int quote;
|
||
|
Stack *savnxf;
|
||
|
|
||
|
copyf++;
|
||
|
nxf->nargs = 0;
|
||
|
savnxf = nxf;
|
||
|
if (skip())
|
||
|
goto rtn;
|
||
|
|
||
|
{
|
||
|
char *memp;
|
||
|
memp = (char *)savnxf;
|
||
|
/*
|
||
|
* 1 s structure for the macro descriptor
|
||
|
* APERMAC Tchar *'s for pointers into the strings
|
||
|
* space for the Tchar's themselves
|
||
|
*/
|
||
|
memp += sizeof(Stack);
|
||
|
/*
|
||
|
* CPERMAC = the total # of characters for ALL arguments
|
||
|
*/
|
||
|
#define CPERMAC 200
|
||
|
#define APERMAC 9
|
||
|
memp += APERMAC * sizeof(Tchar *);
|
||
|
memp += CPERMAC * sizeof(Tchar);
|
||
|
nxf = (Stack *)memp;
|
||
|
}
|
||
|
lim = (Tchar *)nxf;
|
||
|
argpp = (Tchar **)(savnxf + 1);
|
||
|
argppend = &argpp[APERMAC];
|
||
|
SPACETEST(argppend, sizeof(Tchar *));
|
||
|
strp = (Tchar *)argppend;
|
||
|
/*
|
||
|
* Zero out all the string pointers before filling them in.
|
||
|
*/
|
||
|
for (j = 0; j < APERMAC; j++)
|
||
|
argpp[j] = 0;
|
||
|
/* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
|
||
|
* savnxf, nxf, argpp, strp, lim WARN;
|
||
|
*/
|
||
|
strflg = 0;
|
||
|
while (argpp != argppend && !skip()) {
|
||
|
*argpp++ = strp;
|
||
|
quote = 0;
|
||
|
if (cbits(i = getch()) == '"')
|
||
|
quote++;
|
||
|
else
|
||
|
ch = i;
|
||
|
while (1) {
|
||
|
i = getch();
|
||
|
/* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
|
||
|
if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
|
||
|
break; /* collects rest into $9 */
|
||
|
if ( quote
|
||
|
&& cbits(i) == '"'
|
||
|
&& cbits(i = getch()) != '"') {
|
||
|
ch = i;
|
||
|
break;
|
||
|
}
|
||
|
*strp++ = i;
|
||
|
if (strflg && strp >= lim) {
|
||
|
/* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
|
||
|
ERROR "Macro argument too long" WARN;
|
||
|
copyf--;
|
||
|
edone(004);
|
||
|
}
|
||
|
SPACETEST(strp, 3 * sizeof(Tchar));
|
||
|
}
|
||
|
*strp++ = 0;
|
||
|
}
|
||
|
nxf = savnxf;
|
||
|
nxf->nargs = argpp - (Tchar **)(savnxf + 1);
|
||
|
argtop = strp;
|
||
|
rtn:
|
||
|
copyf--;
|
||
|
}
|
||
|
|
||
|
|
||
|
void seta(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
i = cbits(getch()) - '0';
|
||
|
if (i > 0 && i <= APERMAC && i <= frame->nargs)
|
||
|
pushback(*(((Tchar **)(frame + 1)) + i - 1));
|
||
|
}
|
||
|
|
||
|
|
||
|
void caseda(void)
|
||
|
{
|
||
|
app++;
|
||
|
casedi();
|
||
|
}
|
||
|
|
||
|
void casegd(void)
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
skip();
|
||
|
if ((i = getrq()) == 0)
|
||
|
return;
|
||
|
if ((j = findmn(i)) >= 0) {
|
||
|
if (contabp[j].divsiz != NULL) {
|
||
|
numtabp[DN].val = contabp[j].divsiz->dix;
|
||
|
numtabp[DL].val = contabp[j].divsiz->diy;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \
|
||
|
ERROR "lost diversion %s", unpair(dip->curd) WARN
|
||
|
|
||
|
void casedi(void)
|
||
|
{
|
||
|
int i, j, *k;
|
||
|
|
||
|
lgf++;
|
||
|
if (skip() || (i = getrq()) == 0) {
|
||
|
if (dip != d) {
|
||
|
FINDDIV(savslot);
|
||
|
wbf((Tchar)0);
|
||
|
}
|
||
|
if (dilev > 0) {
|
||
|
numtabp[DN].val = dip->dnl;
|
||
|
numtabp[DL].val = dip->maxl;
|
||
|
FINDDIV(j);
|
||
|
if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
|
||
|
ERROR "Cannot alloc diversion size" WARN;
|
||
|
done2(1);
|
||
|
} else {
|
||
|
contabp[j].divsiz->dix = numtabp[DN].val;
|
||
|
contabp[j].divsiz->diy = numtabp[DL].val;
|
||
|
}
|
||
|
dip = &d[--dilev];
|
||
|
offset = dip->op;
|
||
|
}
|
||
|
goto rtn;
|
||
|
}
|
||
|
if (++dilev == NDI) {
|
||
|
--dilev;
|
||
|
ERROR "Diversions nested too deep" WARN;
|
||
|
edone(02);
|
||
|
}
|
||
|
if (dip != d) {
|
||
|
FINDDIV(j);
|
||
|
savslot = j;
|
||
|
wbf((Tchar)0);
|
||
|
}
|
||
|
diflg++;
|
||
|
dip = &d[dilev];
|
||
|
dip->op = finds(i);
|
||
|
dip->curd = i;
|
||
|
clrmn(oldmn);
|
||
|
k = (int *) & dip->dnl;
|
||
|
for (j = 0; j < 10; j++)
|
||
|
k[j] = 0; /*not op and curd*/
|
||
|
rtn:
|
||
|
app = 0;
|
||
|
diflg = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void casedt(void)
|
||
|
{
|
||
|
lgf++;
|
||
|
dip->dimac = dip->ditrap = dip->ditf = 0;
|
||
|
skip();
|
||
|
dip->ditrap = vnumb((int *)0);
|
||
|
if (nonumb)
|
||
|
return;
|
||
|
skip();
|
||
|
dip->dimac = getrq();
|
||
|
}
|
||
|
|
||
|
#define LNSIZE 4000
|
||
|
void casetl(void)
|
||
|
{
|
||
|
int j;
|
||
|
int w[3];
|
||
|
Tchar buf[LNSIZE];
|
||
|
Tchar *tp;
|
||
|
Tchar i, delim;
|
||
|
|
||
|
/*
|
||
|
* bug fix
|
||
|
*
|
||
|
* if .tl is the first thing in the file, the p1
|
||
|
* doesn't come out, also the pagenumber will be 0
|
||
|
*
|
||
|
* tends too confuse the device filter (and the user as well)
|
||
|
*/
|
||
|
if (dip == d && numtabp[NL].val == -1)
|
||
|
newline(1);
|
||
|
dip->nls = 0;
|
||
|
skip();
|
||
|
if (ismot(delim = getch())) {
|
||
|
ch = delim;
|
||
|
delim = '\'';
|
||
|
} else
|
||
|
delim = cbits(delim);
|
||
|
tp = buf;
|
||
|
numtabp[HP].val = 0;
|
||
|
w[0] = w[1] = w[2] = 0;
|
||
|
j = 0;
|
||
|
while (cbits(i = getch()) != '\n') {
|
||
|
if (cbits(i) == cbits(delim)) {
|
||
|
if (j < 3)
|
||
|
w[j] = numtabp[HP].val;
|
||
|
numtabp[HP].val = 0;
|
||
|
if (w[j] != 0)
|
||
|
*tp++ = WORDSP;
|
||
|
j++;
|
||
|
*tp++ = 0;
|
||
|
} else {
|
||
|
if (cbits(i) == pagech) {
|
||
|
setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
|
||
|
i&SFMASK);
|
||
|
continue;
|
||
|
}
|
||
|
numtabp[HP].val += width(i);
|
||
|
if (tp < &buf[LNSIZE-10]) {
|
||
|
if (cbits(i) == ' ' && *tp != WORDSP)
|
||
|
*tp++ = WORDSP;
|
||
|
*tp++ = i;
|
||
|
} else {
|
||
|
ERROR "Overflow in casetl" WARN;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (j<3)
|
||
|
w[j] = numtabp[HP].val;
|
||
|
*tp++ = 0;
|
||
|
*tp++ = 0;
|
||
|
*tp = 0;
|
||
|
tp = buf;
|
||
|
if (NROFF)
|
||
|
horiz(po);
|
||
|
while (i = *tp++)
|
||
|
pchar(i);
|
||
|
if (w[1] || w[2])
|
||
|
horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
|
||
|
while (i = *tp++)
|
||
|
pchar(i);
|
||
|
if (w[2]) {
|
||
|
horiz(lt - w[0] - w[1] - w[2] - j);
|
||
|
while (i = *tp++)
|
||
|
pchar(i);
|
||
|
}
|
||
|
newline(0);
|
||
|
if (dip != d) {
|
||
|
if (dip->dnl > dip->hnl)
|
||
|
dip->hnl = dip->dnl;
|
||
|
} else {
|
||
|
if (numtabp[NL].val > dip->hnl)
|
||
|
dip->hnl = numtabp[NL].val;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void casepc(void)
|
||
|
{
|
||
|
pagech = chget(IMP);
|
||
|
}
|
||
|
|
||
|
|
||
|
void casepm(void)
|
||
|
{
|
||
|
int i, k;
|
||
|
int xx, cnt, tcnt, kk, tot;
|
||
|
Offset j;
|
||
|
|
||
|
kk = cnt = tcnt = 0;
|
||
|
tot = !skip();
|
||
|
stackdump();
|
||
|
for (i = 0; i < nm; i++) {
|
||
|
if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
|
||
|
continue;
|
||
|
tcnt++;
|
||
|
j = contabp[i].mx;
|
||
|
for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
|
||
|
k++;
|
||
|
cnt++;
|
||
|
kk += k;
|
||
|
if (!tot)
|
||
|
fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
|
||
|
}
|
||
|
fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
|
||
|
}
|
||
|
|
||
|
void stackdump(void) /* dumps stack of macros in process */
|
||
|
{
|
||
|
Stack *p;
|
||
|
|
||
|
if (frame != stk) {
|
||
|
fprintf(stderr, "stack: ");
|
||
|
for (p = frame; p != stk; p = p->pframe)
|
||
|
fprintf(stderr, "%s ", unpair(p->mname));
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
}
|