962 lines · 16.3 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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 500int	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; 	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, k; 	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;	/* pointless */	}	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;	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;	savoff = 0; /* 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;

Lines 1–500 of 962.