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 
prcontab(Contab * p)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 
blockinit(void)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 
grow(char * ptr,int num,int size)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 
mnspace(void)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 
caseig(void)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 
casern(void)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 
maddhash(Contab * rp)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 
munhash(Contab * mp)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 
mrehash(void)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 
caserm(void)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 
caseas(void)198 void caseas(void)
199 {
200 	app++;
201 	caseds();
202 }
203 
204 
caseds(void)205 void caseds(void)
206 {
207 	ds++;
208 	casede();
209 }
210 
211 
caseam(void)212 void caseam(void)
213 {
214 	app++;
215 	casede();
216 }
217 
218 
casede(void)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 
findmn(int i)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 
clrmn(int i)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 
growcontab(void)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 
finds(int mn)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 
skip(void)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 
copyb(void)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 
copys(void)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 
alloc(void)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 
ffree(Offset i)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 
wbf(Tchar i)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 
rbf(void)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 
xxxincoff(Offset p)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 
popi(void)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 
pushi(Offset newip,int mname)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 
setbrk(int x)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 
getsn(void)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 
setstr(void)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 
collect(void)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 
seta(void)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 
caseda(void)743 void caseda(void)
744 {
745 	app++;
746 	casedi();
747 }
748 
casegd(void)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 
casedi(void)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 
casedt(void)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
casetl(void)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 
casepc(void)914 void casepc(void)
915 {
916 	pagech = chget(IMP);
917 }
918 
919 
casepm(void)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 
stackdump(void)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 }
955