/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* troff3.c
*
* macro and string routines, storage allocation
*/
#include "tdef.h"
#ifdef NROFF
#include "tw.h"
#endif
#include "ext.h"
#define MHASH(x) ((x>>6)^x)&0177
struct contab *mhash[128]; /* 128 == the 0177 on line above */
#define blisti(i) (((i)-ENV_BLK*BLK) / BLK)
filep blist[NBLIST];
tchar *argtop;
int pagech = '%';
int strflg;
#ifdef INCORE
tchar *wbuf;
tchar corebuf[(ENV_BLK + NBLIST + 1) * BLK];
#else
tchar wbuf[BLK];
tchar rbuf[BLK];
#endif
int
caseig()
{
int i;
filep oldoff;
oldoff = offset;
offset = 0;
i = copyb();
offset = oldoff;
if (i != '.')
control(i, 1);
return (0);
}
int
casern()
{
int i, j;
lgf++;
skip();
if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
return (0);
skip();
clrmn(findmn(j = getrq()));
if (j) {
munhash(&contab[oldmn]);
contab[oldmn].rq = j;
maddhash(&contab[oldmn]);
}
return (0);
}
int
maddhash(rp)
struct contab *rp;
{
struct contab **hp;
if (rp->rq == 0)
return (0);
hp = &mhash[MHASH(rp->rq)];
rp->link = *hp;
*hp = rp;
return (0);
}
int
munhash(mp)
struct contab *mp;
{
struct contab *p;
struct contab **lp;
if (mp->rq == 0)
return (0);
lp = &mhash[MHASH(mp->rq)];
p = *lp;
while (p) {
if (p == mp) {
*lp = p->link;
p->link = 0;
return (0);
}
lp = &p->link;
p = p->link;
}
return (0);
}
int
mrehash()
{
struct contab *p;
int i;
for (i=0; i<128; i++)
mhash[i] = 0;
for (p=contab; p < &contab[NM]; p++)
p->link = 0;
for (p=contab; p < &contab[NM]; p++) {
if (p->rq == 0)
continue;
i = MHASH(p->rq);
p->link = mhash[i];
mhash[i] = p;
}
return (0);
}
int
caserm()
{
int j;
lgf++;
while (!skip() && (j = getrq()) != 0)
clrmn(findmn(j));
lgf--;
return (0);
}
int
caseas()
{
app++;
caseds();
return (0);
}
int
caseds()
{
ds++;
casede();
return (0);
}
int
caseam()
{
app++;
casede();
return (0);
}
int
casede()
{
int i, req;
filep savoff;
extern filep finds();
if (dip != d)
wbfl();
req = '.';
lgf++;
skip();
if ((i = getrq()) == 0)
goto de1;
if ((offset = finds(i)) == 0)
goto de1;
if (ds)
copys();
else
req = copyb();
wbfl();
clrmn(oldmn);
if (newmn) {
if (contab[newmn].rq)
munhash(&contab[newmn]);
contab[newmn].rq = i;
maddhash(&contab[newmn]);
}
if (apptr) {
savoff = offset;
offset = apptr;
wbt((tchar) IMP);
offset = savoff;
}
offset = dip->op;
if (req != '.')
control(req, 1);
de1:
ds = app = 0;
return (0);
}
int
findmn(i)
int i;
{
struct contab *p;
for (p = mhash[MHASH(i)]; p; p = p->link)
if (i == p->rq)
return(p - contab);
return(-1);
}
int
clrmn(i)
int i;
{
if (i >= 0) {
if (contab[i].mx)
ffree((filep)contab[i].mx);
munhash(&contab[i]);
contab[i].rq = 0;
contab[i].mx = 0;
contab[i].f = 0;
}
return (0);
}
filep finds(mn)
int mn;
{
int i;
filep savip;
extern filep alloc();
extern filep incoff();
oldmn = findmn(mn);
newmn = 0;
apptr = (filep)0;
if (app && oldmn >= 0 && contab[oldmn].mx) {
savip = ip;
ip = (filep)contab[oldmn].mx;
oldmn = -1;
while ((i = rbf()) != 0)
;
apptr = ip;
if (!diflg)
ip = incoff(ip);
nextb = ip;
ip = savip;
} else {
for (i = 0; i < NM; i++) {
if (contab[i].rq == 0)
break;
}
if (i == NM || (nextb = alloc()) == 0) {
app = 0;
if (macerr++ > 1)
done2(02);
errprint(gettext("Too many (%d) string/macro names"),
NM);
edone(04);
return(offset = 0);
}
contab[i].mx = (unsigned) nextb;
if (!diflg) {
newmn = i;
if (oldmn == -1)
contab[i].rq = -1;
} else {
contab[i].rq = mn;
maddhash(&contab[i]);
}
}
app = 0;
return(offset = nextb);
}
int
skip() /*skip over blanks; return nlflg*/
{
tchar i;
while (cbits(i = getch()) == ' ')
;
ch = i;
return(nlflg);
}
int
copyb()
{
int i, j, state;
tchar ii;
int req, k;
filep savoff;
if (skip() || !(j = getrq()))
j = '.';
req = j;
k = j >> BYTE;
j &= BYTEMASK;
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) {
wbfl();
offset = savoff;
wbt((tchar)0);
}
copyf--;
return(req);
}
int
copys()
{
tchar i;
copyf++;
if (skip())
goto c0;
if (cbits(i = getch()) != '"')
wbf(i);
while (cbits(i = getch()) != '\n')
wbf(i);
c0:
wbt((tchar)0);
copyf--;
return (0);
}
filep alloc() /*return free blist[] block in nextb*/
{
int i;
filep j;
for (i = 0; i < NBLIST; i++) {
if (blist[i] == 0)
break;
}
if (i == NBLIST) {
j = 0;
} else {
blist[i] = -1;
j = (filep)i * BLK + ENV_BLK * BLK;
}
#ifdef DEBUG
if (debug & DB_ALLC) {
char cc1, cc2;
fdprintf(stderr, "alloc: ");
if (oldmn >= 0 && oldmn < NM) {
cc1 = contab[oldmn].rq & 0177;
if ((cc2 = (contab[oldmn].rq >> BYTE) & 0177) == 0)
cc2 = ' ';
fdprintf(stderr, "oldmn %d %c%c, ", oldmn, cc1, cc2);
}
fdprintf(stderr, "newmn %d; nextb was %x, will be %x\n",
newmn, nextb, j);
}
#endif /* DEBUG */
return(nextb = j);
}
int
ffree(i) /*free blist[i] and blocks pointed to*/
filep i;
{
int j;
while (blist[j = blisti(i)] != (unsigned) ~0) {
i = (filep) blist[j];
blist[j] = 0;
}
blist[j] = 0;
return (0);
}
int
wbt(i)
tchar i;
{
wbf(i);
wbfl();
return (0);
}
int
wbf(i) /*store i into blist[offset] (?) */
tchar i;
{
int j;
if (!offset)
return (0);
if (!woff) {
woff = offset;
#ifdef INCORE
wbuf = &corebuf[woff]; /* INCORE only */
#endif
wbfi = 0;
}
wbuf[wbfi++] = i;
if (!((++offset) & (BLK - 1))) {
wbfl();
j = blisti(--offset);
if (j < 0 || j >= NBLIST) {
errprint(gettext("Out of temp file space"));
done2(01);
}
if (blist[j] == (unsigned) ~0) {
if (alloc() == 0) {
errprint(gettext("Out of temp file space"));
done2(01);
}
blist[j] = (unsigned)(nextb);
}
offset = ((filep)blist[j]);
}
if (wbfi >= BLK)
wbfl();
return (0);
}
int
wbfl() /*flush current blist[] block*/
{
if (woff == 0)
return (0);
#ifndef INCORE
lseek(ibf, ((long)woff) * sizeof(tchar), 0);
write(ibf, (char *)wbuf, wbfi * sizeof(tchar));
#endif
if ((woff & (~(BLK - 1))) == (roff & (~(BLK - 1))))
roff = -1;
woff = 0;
return (0);
}
tchar rbf() /*return next char from blist[] block*/
{
tchar i;
filep j, p;
extern filep incoff();
if (ip == NBLIST*BLK) { /* for rdtty */
if (j = rdtty())
return(j);
else
return(popi());
}
/* this is an inline expansion of rbf0: dirty! */
#ifndef INCORE
j = ip & ~(BLK - 1);
if (j != roff) {
roff = j;
lseek(ibf, (long)j * sizeof(tchar), 0);
if (read(ibf, (char *)rbuf, BLK * sizeof(tchar)) <= 0)
i = 0;
else
i = rbuf[ip & (BLK-1)];
} else
i = rbuf[ip & (BLK-1)];
#else
i = corebuf[ip];
#endif
/* end of rbf0 */
if (i == 0) {
if (!app)
i = popi();
return(i);
}
/* this is an inline expansion of incoff: also dirty */
p = ++ip;
if ((p & (BLK - 1)) == 0) {
if ((ip = blist[blisti(p-1)]) == (unsigned) ~0) {
errprint(gettext("Bad storage allocation"));
ip = 0;
done2(-5);
}
/* this was meant to protect against people removing
* the macro they were standing on, but it's too
* sensitive to block boundaries.
* if (ip == 0) {
* errprint(gettext("Block removed while in use"));
* done2(-6);
* }
*/
}
return(i);
}
tchar rbf0(p)
filep p;
{
#ifndef INCORE
filep i;
if ((i = p & ~(BLK - 1)) != roff) {
roff = i;
lseek(ibf, (long)roff * sizeof(tchar), 0);
if (read(ibf, (char *)rbuf, BLK * sizeof(tchar)) == 0)
return(0);
}
return(rbuf[p & (BLK-1)]);
#else
return(corebuf[p]);
#endif
}
filep incoff(p) /*get next blist[] block*/
filep p;
{
p++;
if ((p & (BLK - 1)) == 0) {
if ((p = blist[blisti(p-1)]) == (unsigned) ~0) {
errprint(gettext("Bad storage allocation"));
done2(-5);
}
}
return(p);
}
tchar popi()
{
struct s *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) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);}
int
pushi(newip, mname)
filep newip;
int mname;
{
struct s *p;
extern char *setbrk();
SPACETEST(nxf, sizeof(struct s));
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 = (struct s *)argtop;
return(ip = newip);
}
char *setbrk(x)
int x;
{
char *i, *k;
int j;
char *sbrk();
if ((i = sbrk(x)) == (char *) -1) {
errprint(gettext("Core limit reached"));
edone(0100);
}
if (j = (unsigned)i % sizeof(int)) { /*check alignment for 3B*/
j = sizeof(int) - j; /*only init calls should need this*/
if ((k = sbrk(j)) == (char *) -1) {
errprint("Core limit reached");
edone(0100);
}
if (k != i + x) { /*there must have been an intervening sbrk*/
errprint ("internal error in setbrk: i=%x, j=%d, k=%x",
i, j, k);
edone(0100);
}
i += j;
}
enda = i + x;
return(i);
}
int
getsn()
{
int i;
if ((i = getach()) == 0)
return(0);
if (i == '(')
return(getrq());
else
return(i);
}
int
setstr()
{
int i, j;
lgf++;
if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contab[j].mx) {
lgf--;
return(0);
} else {
SPACETEST(nxf, sizeof(struct s));
nxf->nargs = 0;
strflg++;
lgf--;
return pushi((filep)contab[j].mx, i);
}
}
int
collect()
{
int j;
tchar i;
tchar *strp;
tchar * lim;
tchar * *argpp, **argppend;
int quote;
struct s *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(struct s);
/*
* CPERMAC (the total # of characters for ALL arguments)
* to a macros, has been carefully chosen
* so that the distance between stack frames is < DELTA
*/
#define CPERMAC 200
#define APERMAC 9
memp += APERMAC * sizeof(tchar *);
memp += CPERMAC * sizeof(tchar);
nxf = (struct s*)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] = (tchar *)0;
}
#if 0
errprint("savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x",
savnxf, nxf, argpp, strp, lim, enda);
#endif
strflg = 0;
while ((argpp != argppend) && (!skip())) {
*argpp++ = strp;
quote = 0;
if (cbits(i = getch()) == '"')
quote++;
else
ch = i;
while (1) {
i = getch();
if (nlflg || (!quote && cbits(i) == ' '))
break;
if ( quote
&& (cbits(i) == '"')
&& (cbits(i = getch()) != '"')) {
ch = i;
break;
}
*strp++ = i;
if (strflg && strp >= lim) {
#if 0
errprint("strp=0x%x, lim = 0x%x",
strp, lim);
#endif
errprint(gettext("Macro argument too long"));
copyf--;
edone(004);
}
SPACETEST(strp, 3 * sizeof(tchar));
}
*strp++ = 0;
}
nxf = savnxf;
nxf->nargs = argpp - (tchar **)(savnxf + 1);
argtop = strp;
rtn:
copyf--;
return (0);
}
int
seta()
{
int i;
i = cbits(getch()) - '0';
if (i > 0 && i <= APERMAC && i <= frame->nargs)
pushback(*(((tchar **)(frame + 1)) + i - 1));
return (0);
}
int
caseda()
{
app++;
casedi();
return (0);
}
int
casedi()
{
int i, j;
int *k;
lgf++;
if (skip() || (i = getrq()) == 0) {
if (dip != d)
wbt((tchar)0);
if (dilev > 0) {
numtab[DN].val = dip->dnl;
numtab[DL].val = dip->maxl;
dip = &d[--dilev];
offset = dip->op;
}
goto rtn;
}
if (++dilev == NDI) {
--dilev;
errprint(gettext("Diversions nested too deep"));
edone(02);
}
if (dip != d)
wbt((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;
return (0);
}
int
casedt()
{
lgf++;
dip->dimac = dip->ditrap = dip->ditf = 0;
skip();
dip->ditrap = vnumb((int *)0);
if (nonumb)
return (0);
skip();
dip->dimac = getrq();
return (0);
}
int
casetl()
{
int j;
int w[3];
tchar buf[LNSIZE];
tchar *tp;
tchar i, delim;
dip->nls = 0;
skip();
if (ismot(delim = getch())) {
ch = delim;
delim = '\'';
} else
delim = cbits(delim);
tp = buf;
numtab[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] = numtab[HP].val;
numtab[HP].val = 0;
j++;
*tp++ = 0;
} else {
if (cbits(i) == pagech) {
setn1(numtab[PN].val, numtab[findr('%')].fmt,
i&SFMASK);
continue;
}
numtab[HP].val += width(i);
if (tp < &buf[LNSIZE-10])
*tp++ = i;
}
}
if (j<3)
w[j] = numtab[HP].val;
*tp++ = 0;
*tp++ = 0;
*tp++ = 0;
tp = buf;
#ifdef NROFF
horiz(po);
#endif
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 (numtab[NL].val > dip->hnl)
dip->hnl = numtab[NL].val;
}
return (0);
}
int
casepc()
{
pagech = chget(IMP);
return (0);
}
int
casepm()
{
int i, k;
char *p;
int xx, cnt, tcnt, kk, tot;
filep j;
char pmline[10];
kk = cnt = tcnt = 0;
tot = !skip();
for (i = 0; i < NM; i++) {
if ((xx = contab[i].rq) == 0 || contab[i].mx == 0)
continue;
tcnt++;
p = pmline;
j = (filep) contab[i].mx;
k = 1;
while ((j = blist[blisti(j)]) != (unsigned) ~0) {
k++;
}
cnt++;
kk += k;
if (!tot) {
*p++ = xx & 0177;
if (!(*p++ = (xx >> BYTE) & 0177))
*(p - 1) = ' ';
*p++ = 0;
fdprintf(stderr, "%s %d\n", pmline, k);
}
}
fdprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
return (0);
}
int
stackdump() /* dumps stack of macros in process */
{
struct s *p;
if (frame != stk) {
for (p = frame; p != stk; p = p->pframe)
fdprintf(stderr, "%c%c ", p->mname&0177, (p->mname>>BYTE)&0177);
fdprintf(stderr, "\n");
}
return (0);
}