Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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