9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

n3.c (16259B)


      1 /*
      2  * troff3.c
      3  * 
      4  * macro and string routines, storage allocation
      5  */
      6 
      7 #include "tdef.h"
      8 #include "fns.h"
      9 #include "ext.h"
     10 
     11 Tchar	*argtop;
     12 int	pagech = '%';
     13 int	strflg;
     14 
     15 #define	MHASHSIZE	128	/* must be 2**n */
     16 #define	MHASH(x)	((x>>6)^x) & (MHASHSIZE-1)
     17 Contab	*mhash[MHASHSIZE];
     18 
     19 
     20 Blockp	*blist;		/* allocated blocks for macros and strings */
     21 int	nblist;		/* how many there are */
     22 int	bfree = -1;	/* first (possible) free block in the list */
     23 
     24 Contab *contabp = NULL;
     25 #define MDELTA 500
     26 int	nm = 0;
     27 
     28 int savname;		/* name of macro/string being defined */
     29 int savslot;		/* place in Contab of savname */
     30 int freeslot = -1;	/* first (possible) free slot in contab */
     31 
     32 void prcontab(Contab *p)
     33 {
     34 	int i;
     35 	for (i = 0; i < nm; i++)
     36 		if (p)
     37 			if (p[i].rq != 0)
     38 				fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
     39 			else
     40 				fprintf(stderr, "slot %d empty\n", i);
     41 		else
     42 			fprintf(stderr, "slot %d empty\n", i);
     43 }
     44 
     45 
     46 void blockinit(void)
     47 {
     48 	blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
     49 	if (blist == NULL) {
     50 		ERROR "not enough room for %d blocks", NBLIST WARN;
     51 		done2(1);
     52 	}
     53 	nblist = NBLIST;
     54 	blist[0].nextoff = blist[1].nextoff = -1;
     55 	blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
     56 	blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
     57 		/* -1 prevents blist[0] from being used; temporary fix */
     58 		/* for a design botch: offset==0 is overloaded. */
     59 		/* blist[1] reserved for .rd indicator -- also unused. */
     60 		/* but someone unwittingly looks at these, so allocate something */
     61 	bfree = 2;
     62 }
     63 
     64 
     65 char *grow(char *ptr, int num, int size)	/* make array bigger */
     66 {
     67 	char *p;
     68 
     69 	if (ptr == NULL)
     70 		p = (char *) calloc(num, size);
     71 	else
     72 		p = (char *) realloc(ptr, num * size);
     73 	return p;
     74 }
     75 
     76 void mnspace(void)
     77 {
     78 	nm = sizeof(contab)/sizeof(Contab) + MDELTA;
     79 	freeslot = sizeof(contab)/sizeof(Contab) + 1;
     80 	contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
     81 	if (contabp == NULL) {
     82 		ERROR "not enough memory for namespace of %d marcos", nm WARN;
     83 		exit(1);
     84 	}
     85 	contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
     86 							sizeof(contab));
     87 	if (contabp == NULL) {
     88 		ERROR "Cannot reinitialize macro/request name list" WARN;
     89 		exit(1);
     90 	}
     91 
     92 }
     93 
     94 void caseig(void)
     95 {
     96 	int i;
     97 	Offset oldoff = offset;
     98 
     99 	offset = 0;
    100 	i = copyb();
    101 	offset = oldoff;
    102 	if (i != '.')
    103 		control(i, 1);
    104 }
    105 
    106 
    107 void casern(void)
    108 {
    109 	int i, j, k;
    110 
    111 	lgf++;
    112 	skip();
    113 	if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
    114 		return;
    115 	skip();
    116 	clrmn(findmn(j = getrq()));
    117 	if (j) {
    118 		munhash(&contabp[oldmn]);
    119 		contabp[oldmn].rq = j;
    120 		maddhash(&contabp[oldmn]);
    121 		if (dip != d )
    122 			for (k = dilev; k; k--)
    123 				if (d[k].curd == i)
    124 					d[k].curd = j;
    125 	}
    126 }
    127 
    128 void maddhash(Contab *rp)
    129 {
    130 	Contab **hp;
    131 
    132 	if (rp->rq == 0)
    133 		return;
    134 	hp = &mhash[MHASH(rp->rq)];
    135 	rp->link = *hp;
    136 	*hp = rp;
    137 }
    138 
    139 void munhash(Contab *mp)
    140 {	
    141 	Contab *p;
    142 	Contab **lp;
    143 
    144 	if (mp->rq == 0)
    145 		return;
    146 	lp = &mhash[MHASH(mp->rq)];
    147 	p = *lp;
    148 	while (p) {
    149 		if (p == mp) {
    150 			*lp = p->link;
    151 			p->link = 0;
    152 			return;
    153 		}
    154 		lp = &p->link;
    155 		p = p->link;
    156 	}
    157 }
    158 
    159 void mrehash(void)
    160 {
    161 	Contab *p;
    162 	int i;
    163 
    164 	for (i=0; i < MHASHSIZE; i++)
    165 		mhash[i] = 0;
    166 	for (p=contabp; p < &contabp[nm]; p++)
    167 		p->link = 0;
    168 	for (p=contabp; p < &contabp[nm]; p++) {
    169 		if (p->rq == 0)
    170 			continue;
    171 		i = MHASH(p->rq);
    172 		p->link = mhash[i];
    173 		mhash[i] = p;
    174 	}
    175 }
    176 
    177 void caserm(void)
    178 {
    179 	int j;
    180 	int k = 0;
    181 
    182 	lgf++;
    183 g0:
    184 	while (!skip() && (j = getrq()) != 0) {
    185 		if (dip != d)
    186 			for (k = dilev; k; k--)
    187 				if (d[k].curd == j) {
    188 					ERROR "cannot remove diversion %s during definition",
    189 								unpair(j) WARN;
    190 					goto g0;
    191 				}
    192 		clrmn(findmn(j));
    193 	}
    194 	lgf--;
    195 }
    196 
    197 
    198 void caseas(void)
    199 {
    200 	app++;
    201 	caseds();
    202 }
    203 
    204 
    205 void caseds(void)
    206 {
    207 	ds++;
    208 	casede();
    209 }
    210 
    211 
    212 void caseam(void)
    213 {
    214 	app++;
    215 	casede();
    216 }
    217 
    218 
    219 void casede(void)
    220 {
    221 	int i, req;
    222 	Offset savoff;
    223 
    224 	req = '.';
    225 	lgf++;
    226 	skip();
    227 	if ((i = getrq()) == 0)
    228 		goto de1;
    229 	if ((offset = finds(i)) == 0)
    230 		goto de1;
    231 	if (newmn)
    232 		savslot = newmn;
    233 	else
    234 		savslot = findmn(i);
    235 	savname = i;
    236 	if (ds)
    237 		copys();
    238 	else
    239 		req = copyb();
    240 	clrmn(oldmn);
    241 	if (newmn) {
    242 		if (contabp[newmn].rq)
    243 			munhash(&contabp[newmn]);
    244 		contabp[newmn].rq = i;
    245 		maddhash(&contabp[newmn]);
    246 
    247 	}
    248 	if (apptr) {
    249 		savoff = offset;
    250 		offset = apptr;
    251 		wbf((Tchar) IMP);
    252 		offset = savoff;
    253 	}
    254 	offset = dip->op;
    255 	if (req != '.')
    256 		control(req, 1);
    257 de1:
    258 	ds = app = 0;
    259 }
    260 
    261 
    262 int findmn(int i)
    263 {
    264 	Contab *p;
    265 
    266 	for (p = mhash[MHASH(i)]; p; p = p->link)
    267 		if (i == p->rq)
    268 			return(p - contabp);
    269 	return(-1);
    270 }
    271 
    272 
    273 void clrmn(int i)
    274 {
    275 	if (i >= 0) {
    276 		if (contabp[i].mx)
    277 			ffree(contabp[i].mx);
    278 		munhash(&contabp[i]);
    279 		contabp[i].rq = 0;
    280 		contabp[i].mx = 0;
    281 		contabp[i].emx = 0;
    282 		contabp[i].f = 0;
    283 		if (contabp[i].divsiz != NULL) {
    284 			free(contabp[i].divsiz);
    285 			contabp[i].divsiz = NULL;
    286 		}
    287 		if (freeslot > i)
    288 			freeslot = i;
    289 	}
    290 }
    291 
    292 void growcontab(void)
    293 {
    294 	nm += MDELTA;
    295 	contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
    296 	if (contabp == NULL) {
    297 		ERROR "Too many (%d) string/macro names", nm WARN;
    298 		done2(02);
    299 	} else {
    300 		memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
    301 						0, MDELTA * sizeof(Contab));
    302 		mrehash();
    303 	}
    304 }
    305 
    306 
    307 Offset finds(int mn)
    308 {
    309 	int i;
    310 	Offset savip;
    311 
    312 	oldmn = findmn(mn);
    313 	newmn = 0;
    314 	apptr = 0;
    315 	if (app && oldmn >= 0 && contabp[oldmn].mx) {
    316 		savip = ip;
    317 		ip = contabp[oldmn].emx;
    318 		oldmn = -1;
    319 		apptr = ip;
    320 		if (!diflg)
    321 			ip = incoff(ip);
    322 		nextb = ip;
    323 		ip = savip;
    324 	} else {
    325 		for (i = freeslot; i < nm; i++) {
    326 			if (contabp[i].rq == 0)
    327 				break;
    328 		}
    329 		if (i == nm) 
    330 			growcontab();
    331 		freeslot = i + 1;
    332 		if ((nextb = alloc()) == -1) {
    333 			app = 0;
    334 			if (macerr++ > 1)
    335 				done2(02);
    336 			if (nextb == 0)
    337 				ERROR "Not enough space for string/macro names" WARN;
    338 			edone(04);
    339 			return(offset = 0);
    340 		}
    341 		contabp[i].mx = nextb;
    342 		if (!diflg) {
    343 			newmn = i;
    344 			if (oldmn == -1)
    345 				contabp[i].rq = -1;
    346 		} else {
    347 			contabp[i].rq = mn;
    348 			maddhash(&contabp[i]);
    349 		}
    350 	}
    351 	app = 0;
    352 	return(offset = nextb);
    353 }
    354 
    355 int skip(void)
    356 {
    357 	Tchar i;
    358 
    359 	while (cbits(i = getch()) == ' ' || ismot(i))
    360 		;
    361 	ch = i;
    362 	return(nlflg);
    363 }
    364 
    365 
    366 int copyb(void)
    367 {
    368 	int i, j, state;
    369 	Tchar ii;
    370 	int req, k;
    371 	Offset savoff;
    372 	Uchar *p;
    373 
    374 	savoff = 0;
    375 	if (skip() || !(j = getrq()))
    376 		j = '.';
    377 	req = j;
    378 	p = unpair(j);
    379 	/* was: k = j >> BYTE; j &= BYTEMASK; */
    380 	j = p[0];
    381 	k = p[1];
    382 	copyf++;
    383 	flushi();
    384 	nlflg = 0;
    385 	state = 1;
    386 
    387 /* state 0	eat up
    388  * state 1	look for .
    389  * state 2	look for first char of end macro
    390  * state 3	look for second char of end macro
    391  */
    392 
    393 	while (1) {
    394 		i = cbits(ii = getch());
    395 		if (state == 3) {
    396 			if (i == k)
    397 				break;
    398 			if (!k) {
    399 				ch = ii;
    400 				i = getach();
    401 				ch = ii;
    402 				if (!i)
    403 					break;
    404 			}
    405 			state = 0;
    406 			goto c0;
    407 		}
    408 		if (i == '\n') {
    409 			state = 1;
    410 			nlflg = 0;
    411 			goto c0;
    412 		}
    413 		if (state == 1 && i == '.') {
    414 			state++;
    415 			savoff = offset;
    416 			goto c0;
    417 		}
    418 		if (state == 2 && i == j) {
    419 			state++;
    420 			goto c0;
    421 		}
    422 		state = 0;
    423 c0:
    424 		if (offset)
    425 			wbf(ii);
    426 	}
    427 	if (offset) {
    428 		offset = savoff;
    429 		wbf((Tchar)0);
    430 	}
    431 	copyf--;
    432 	return(req);
    433 }
    434 
    435 
    436 void copys(void)
    437 {
    438 	Tchar i;
    439 
    440 	copyf++;
    441 	if (skip())
    442 		goto c0;
    443 	if (cbits(i = getch()) != '"')
    444 		wbf(i);
    445 	while (cbits(i = getch()) != '\n')
    446 		wbf(i);
    447 c0:
    448 	wbf((Tchar)0);
    449 	copyf--;
    450 }
    451 
    452 
    453 Offset alloc(void)	/* return free Offset in nextb */
    454 {
    455 	int i, j;
    456 
    457 	for (i = bfree; i < nblist; i++)
    458 		if (blist[i].nextoff == 0)
    459 			break;
    460 	if (i == nblist) {
    461 		blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
    462 		if (blist == NULL) {
    463 			ERROR "can't grow blist for string/macro defns" WARN;
    464 			done2(2);
    465 		}
    466 		nblist *= 2;
    467 		for (j = i; j < nblist; j++) {
    468 			blist[j].nextoff = 0;
    469 			blist[j].bp = 0;
    470 		}
    471 	}
    472 	blist[i].nextoff = -1;	/* this block is the end */
    473 	bfree = i + 1;
    474 	if (blist[i].bp == 0)
    475 		blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
    476 	if (blist[i].bp == NULL) {
    477 		ERROR "can't allocate memory for string/macro definitions" WARN;
    478 		done2(2);
    479 	}
    480 	nextb = (Offset) i * BLK;
    481 	return nextb;
    482 }
    483 
    484 
    485 void ffree(Offset i)	/* free list of blocks starting at blist(o) */
    486 {			/* (doesn't actually free the blocks, just the pointers) */
    487 	int j;
    488 
    489 	for ( ; blist[j = bindex(i)].nextoff != -1; ) {
    490 		if (bfree > j)
    491 			bfree = j;
    492 		i = blist[j].nextoff;
    493 		blist[j].nextoff = 0;
    494 	}
    495 	blist[j].nextoff = 0;
    496 }
    497 
    498 
    499 void wbf(Tchar i)	/* store i into offset, get ready for next one */
    500 {
    501 	int j, off;
    502 
    503 	if (!offset)
    504 		return;
    505 	j = bindex(offset);
    506 	if (i == 0)
    507 		contabp[savslot].emx = offset;
    508 	off = boffset(offset);
    509 	blist[j].bp[off++] = i;
    510 	offset++;
    511 	if (pastend(offset)) {	/* off the end of this block */
    512 		if (blist[j].nextoff == -1) {
    513 			if ((nextb = alloc()) == -1) {
    514 				ERROR "Out of temp file space" WARN;
    515 				done2(01);
    516 			}
    517 			blist[j].nextoff = nextb;
    518 		}
    519 		offset = blist[j].nextoff;
    520 	}
    521 }
    522 
    523 
    524 Tchar rbf(void)	/* return next char from blist[] block */
    525 {
    526 	Tchar i, j;
    527 
    528 	if (ip == RD_OFFSET) {		/* for rdtty */
    529 		if (j = rdtty())
    530 			return(j);
    531 		else
    532 			return(popi());
    533 	}
    534 	
    535 	i = rbf0(ip);
    536 	if (i == 0) {
    537 		if (!app)
    538 			i = popi();
    539 		return(i);
    540 	}
    541 	ip = incoff(ip);
    542 	return(i);
    543 }
    544 
    545 
    546 Offset xxxincoff(Offset p)		/* get next blist[] block */
    547 {
    548 	p++;
    549 	if (pastend(p)) {		/* off the end of this block */
    550 		if ((p = blist[bindex(p-1)].nextoff) == -1) {	/* and nothing was allocated after it */
    551 			ERROR "Bad storage allocation" WARN;
    552 			done2(-5);
    553 		}
    554 	}
    555 	return(p);
    556 }
    557 
    558 
    559 Tchar popi(void)
    560 {
    561 	Stack *p;
    562 
    563 	if (frame == stk)
    564 		return(0);
    565 	if (strflg)
    566 		strflg--;
    567 	p = nxf = frame;
    568 	p->nargs = 0;
    569 	frame = p->pframe;
    570 	ip = p->pip;
    571 	pendt = p->ppendt;
    572 	lastpbp = p->lastpbp;
    573 	return(p->pch);
    574 }
    575 
    576 /*
    577  *	test that the end of the allocation is above a certain location
    578  *	in memory
    579  */
    580 #define SPACETEST(base, size) \
    581 	if ((char*)base + size >= (char*)stk+STACKSIZE) \
    582 		ERROR "Stacksize overflow in n3" WARN
    583 
    584 Offset pushi(Offset newip, int  mname)
    585 {
    586 	Stack *p;
    587 
    588 	SPACETEST(nxf, sizeof(Stack));
    589 	p = nxf;
    590 	p->pframe = frame;
    591 	p->pip = ip;
    592 	p->ppendt = pendt;
    593 	p->pch = ch;
    594 	p->lastpbp = lastpbp;
    595 	p->mname = mname;
    596 	lastpbp = pbp;
    597 	pendt = ch = 0;
    598 	frame = nxf;
    599 	if (nxf->nargs == 0) 
    600 		nxf += 1;
    601 	else 
    602 		nxf = (Stack *)argtop;
    603 	return(ip = newip);
    604 }
    605 
    606 
    607 void *setbrk(int x)
    608 {
    609 	char *i;
    610 
    611 	if ((i = (char *) calloc(x, 1)) == 0) {
    612 		ERROR "Core limit reached" WARN;
    613 		edone(0100);
    614 	}
    615 	return(i);
    616 }
    617 
    618 
    619 int getsn(void)
    620 {
    621 	int i;
    622 
    623 	if ((i = getach()) == 0)
    624 		return(0);
    625 	if (i == '(')
    626 		return(getrq());
    627 	else 
    628 		return(i);
    629 }
    630 
    631 
    632 Offset setstr(void)
    633 {
    634 	int i, j;
    635 
    636 	lgf++;
    637 	if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
    638 		lgf--;
    639 		return(0);
    640 	} else {
    641 		SPACETEST(nxf, sizeof(Stack));
    642 		nxf->nargs = 0;
    643 		strflg++;
    644 		lgf--;
    645 		return pushi(contabp[j].mx, i);
    646 	}
    647 }
    648 
    649 
    650 
    651 void collect(void)
    652 {
    653 	int j;
    654 	Tchar i, *strp, *lim, **argpp, **argppend;
    655 	int quote;
    656 	Stack *savnxf;
    657 
    658 	copyf++;
    659 	nxf->nargs = 0;
    660 	savnxf = nxf;
    661 	if (skip())
    662 		goto rtn;
    663 
    664 	{
    665 		char *memp;
    666 		memp = (char *)savnxf;
    667 		/*
    668 		 *	1 s structure for the macro descriptor
    669 		 *	APERMAC Tchar *'s for pointers into the strings
    670 		 *	space for the Tchar's themselves
    671 		 */
    672 		memp += sizeof(Stack);
    673 		/*
    674 		 *	CPERMAC = the total # of characters for ALL arguments
    675 		 */
    676 #define	CPERMAC	200
    677 #define	APERMAC	9
    678 		memp += APERMAC * sizeof(Tchar *);
    679 		memp += CPERMAC * sizeof(Tchar);
    680 		nxf = (Stack *)memp;
    681 	}
    682 	lim = (Tchar *)nxf;
    683 	argpp = (Tchar **)(savnxf + 1);
    684 	argppend = &argpp[APERMAC];
    685 	SPACETEST(argppend, sizeof(Tchar *));
    686 	strp = (Tchar *)argppend;
    687 	/*
    688 	 *	Zero out all the string pointers before filling them in.
    689 	 */
    690 	for (j = 0; j < APERMAC; j++)
    691 		argpp[j] = 0;
    692 	/* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
    693 	 * 	savnxf, nxf, argpp, strp, lim WARN;
    694 	 */
    695 	strflg = 0;
    696 	while (argpp != argppend && !skip()) {
    697 		*argpp++ = strp;
    698 		quote = 0;
    699 		if (cbits(i = getch()) == '"')
    700 			quote++;
    701 		else 
    702 			ch = i;
    703 		while (1) {
    704 			i = getch();
    705 /* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
    706 			if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
    707 				break;	/* collects rest into $9 */
    708 			if (   quote
    709 			    && cbits(i) == '"'
    710 			    && cbits(i = getch()) != '"') {
    711 				ch = i;
    712 				break;
    713 			}
    714 			*strp++ = i;
    715 			if (strflg && strp >= lim) {
    716 				/* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
    717 				ERROR "Macro argument too long" WARN;
    718 				copyf--;
    719 				edone(004);
    720 			}
    721 			SPACETEST(strp, 3 * sizeof(Tchar));
    722 		}
    723 		*strp++ = 0;
    724 	}
    725 	nxf = savnxf;
    726 	nxf->nargs = argpp - (Tchar **)(savnxf + 1);
    727 	argtop = strp;
    728 rtn:
    729 	copyf--;
    730 }
    731 
    732 
    733 void seta(void)
    734 {
    735 	int i;
    736 
    737 	i = cbits(getch()) - '0';
    738 	if (i > 0 && i <= APERMAC && i <= frame->nargs)
    739 		pushback(*(((Tchar **)(frame + 1)) + i - 1));
    740 }
    741 
    742 
    743 void caseda(void)
    744 {
    745 	app++;
    746 	casedi();
    747 }
    748 
    749 void casegd(void)
    750 {
    751 	int i, j;
    752 
    753 	skip();
    754 	if ((i = getrq()) == 0)
    755 		return;
    756 	if ((j = findmn(i)) >= 0) {
    757 		if (contabp[j].divsiz != NULL) {
    758 			numtabp[DN].val = contabp[j].divsiz->dix;
    759 			numtabp[DL].val = contabp[j].divsiz->diy;
    760 		}
    761 	}
    762 }
    763 
    764 #define FINDDIV(o) if ((o =  findmn(dip->curd)) < 0) \
    765 			ERROR "lost diversion %s", unpair(dip->curd) WARN
    766 
    767 void casedi(void)
    768 {
    769 	int i, j, *k;
    770 
    771 	lgf++;
    772 	if (skip() || (i = getrq()) == 0) {
    773 		if (dip != d) {
    774 			FINDDIV(savslot);
    775 			wbf((Tchar)0);
    776 		}
    777 		if (dilev > 0) {
    778 			numtabp[DN].val = dip->dnl;
    779 			numtabp[DL].val = dip->maxl;
    780 			FINDDIV(j);
    781 			if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
    782 				ERROR "Cannot alloc diversion size" WARN;
    783 				done2(1);
    784 			} else {
    785 				contabp[j].divsiz->dix = numtabp[DN].val;
    786 				contabp[j].divsiz->diy = numtabp[DL].val;
    787 			}
    788 			dip = &d[--dilev];
    789 			offset = dip->op;
    790 		}
    791 		goto rtn;
    792 	}
    793 	if (++dilev == NDI) {
    794 		--dilev;
    795 		ERROR "Diversions nested too deep" WARN;
    796 		edone(02);
    797 	}
    798 	if (dip != d) {
    799 		FINDDIV(j);
    800 		savslot = j;
    801 		wbf((Tchar)0);
    802 	}
    803 	diflg++;
    804 	dip = &d[dilev];
    805 	dip->op = finds(i);
    806 	dip->curd = i;
    807 	clrmn(oldmn);
    808 	k = (int *) & dip->dnl;
    809 	for (j = 0; j < 10; j++)
    810 		k[j] = 0;	/*not op and curd*/
    811 rtn:
    812 	app = 0;
    813 	diflg = 0;
    814 }
    815 
    816 
    817 void casedt(void)
    818 {
    819 	lgf++;
    820 	dip->dimac = dip->ditrap = dip->ditf = 0;
    821 	skip();
    822 	dip->ditrap = vnumb((int *)0);
    823 	if (nonumb)
    824 		return;
    825 	skip();
    826 	dip->dimac = getrq();
    827 }
    828 
    829 #define LNSIZE 4000
    830 void casetl(void)
    831 {
    832 	int j;
    833 	int w[3];
    834 	Tchar buf[LNSIZE];
    835 	Tchar *tp;
    836 	Tchar i, delim;
    837 
    838  	/*
    839  	 * bug fix
    840  	 *
    841  	 * if .tl is the first thing in the file, the p1
    842  	 * doesn't come out, also the pagenumber will be 0
    843  	 *
    844  	 * tends too confuse the device filter (and the user as well)
    845  	 */
    846  	if (dip == d && numtabp[NL].val == -1)
    847  		newline(1);
    848 	dip->nls = 0;
    849 	skip();
    850 	if (ismot(delim = getch())) {
    851 		ch = delim;
    852 		delim = '\'';
    853 	} else 
    854 		delim = cbits(delim);
    855 	tp = buf;
    856 	numtabp[HP].val = 0;
    857 	w[0] = w[1] = w[2] = 0;
    858 	j = 0;
    859 	while (cbits(i = getch()) != '\n') {
    860 		if (cbits(i) == cbits(delim)) {
    861 			if (j < 3)
    862 				w[j] = numtabp[HP].val;
    863 			numtabp[HP].val = 0;
    864 			if (w[j] != 0)
    865 				*tp++ = WORDSP;
    866 			j++;
    867 			*tp++ = 0;
    868 		} else {
    869 			if (cbits(i) == pagech) {
    870 				setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
    871 				      i&SFMASK);
    872 				continue;
    873 			}
    874 			numtabp[HP].val += width(i);
    875 			if (tp < &buf[LNSIZE-10]) {
    876 				if (cbits(i) == ' ' && *tp != WORDSP)
    877 					*tp++ = WORDSP;
    878 				*tp++ = i;
    879 			} else {
    880 				ERROR "Overflow in casetl" WARN;
    881 			}
    882 		}
    883 	}
    884 	if (j<3)
    885 		w[j] = numtabp[HP].val;
    886 	*tp++ = 0;
    887 	*tp++ = 0;
    888 	*tp = 0;
    889 	tp = buf;
    890 	if (NROFF)
    891 		horiz(po);
    892 	while (i = *tp++)
    893 		pchar(i);
    894 	if (w[1] || w[2])
    895 		horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
    896 	while (i = *tp++)
    897 		pchar(i);
    898 	if (w[2]) {
    899 		horiz(lt - w[0] - w[1] - w[2] - j);
    900 		while (i = *tp++)
    901 			pchar(i);
    902 	}
    903 	newline(0);
    904 	if (dip != d) {
    905 		if (dip->dnl > dip->hnl)
    906 			dip->hnl = dip->dnl;
    907 	} else {
    908 		if (numtabp[NL].val > dip->hnl)
    909 			dip->hnl = numtabp[NL].val;
    910 	}
    911 }
    912 
    913 
    914 void casepc(void)
    915 {
    916 	pagech = chget(IMP);
    917 }
    918 
    919 
    920 void casepm(void)
    921 {
    922 	int i, k;
    923 	int xx, cnt, tcnt, kk, tot;
    924 	Offset j;
    925 
    926 	kk = cnt = tcnt = 0;
    927 	tot = !skip();
    928 	stackdump();
    929 	for (i = 0; i < nm; i++) {
    930 		if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
    931 			continue;
    932 		tcnt++;
    933 		j = contabp[i].mx;
    934 		for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
    935 			k++; 
    936 		cnt++;
    937 		kk += k;
    938 		if (!tot)
    939 			fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
    940 	}
    941 	fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
    942 }
    943 
    944 void stackdump(void)	/* dumps stack of macros in process */
    945 {
    946 	Stack *p;
    947 
    948 	if (frame != stk) {
    949 		fprintf(stderr, "stack: ");
    950 		for (p = frame; p != stk; p = p->pframe)
    951 			fprintf(stderr, "%s ", unpair(p->mname));
    952 		fprintf(stderr, "\n");
    953 	}
    954 }