1 /* $MirOS: src/usr.bin/oldroff/nroff/n3.c,v 1.6 2006/11/04 05:43:43 tg Exp $ */
2 
3 /*-
4  * Copyright (c) 1979, 1980, 1981, 1986, 1988, 1990, 1991, 1992
5  *     The Regents of the University of California.
6  * Copyright (C) Caldera International Inc.  2001-2002.
7  * Copyright (c) 2003, 2004, 2005, 2006
8  *	Thorsten "mirabilos" Glaser <tg@mirbsd.org>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms,
12  * with or without modification, are permitted provided
13  * that the following conditions are met:
14  *
15  * Redistributions of source code and documentation must retain
16  * the above copyright notice, this list of conditions and the
17  * following disclaimer.  Redistributions in binary form must
18  * reproduce the above copyright notice, this list of conditions
19  * and the following disclaimer in the documentation and/or other
20  * materials provided with the distribution.
21  *
22  * All advertising materials mentioning features or use of this
23  * software must display the following acknowledgement:
24  *   This product includes software developed or owned by
25  *   Caldera International, Inc.
26  *
27  * Advertising materials mentioning features or use of this work must
28  * display the following acknowledgement:
29  *	This product includes material provided by Thorsten Glaser.
30  *
31  * Neither the name of Caldera International, Inc. nor the names
32  * of other contributors may be used to endorse or promote products
33  * derived from this software without specific prior written permission.
34  *
35  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
36  * INTERNATIONAL, INC. AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
37  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39  * ARE DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
40  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
41  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  *
48  * Licensor offers the work "AS IS" and WITHOUT WARRANTY of any kind,
49  * express, or implied, to the maximum extent permitted by applicable
50  * law, without malicious intent or gross negligence; in no event may
51  * licensor, an author or contributor be held liable for any indirect
52  * or other damage, or direct damage except proven a consequence of a
53  * direct error of said person and intended use of this work, loss or
54  * other issues arising in any way out of its use, even if advised of
55  * the possibility of such damage or existence of a defect.
56  */
57 
58 #include <stdio.h>
59 #include "tdef.h"
60 extern
61 #include "d.h"
62 extern
63 #include "v.h"
64 #ifdef NROFF
65 extern
66 #include "tw.h"
67 #endif
68 #include "sdef.h"
69 
70 __SCCSID("@(#)n3.c	4.5 (Berkeley) 4/18/91");
71 __RCSID("$MirOS: src/usr.bin/oldroff/nroff/n3.c,v 1.6 2006/11/04 05:43:43 tg Exp $");
72 
73 /*
74 troff3.c
75 
76 macro and string routines, storage allocation
77 */
78 
79 unsigned blist[NBLIST];
80 int ecskip = 0;
81 extern struct s *frame, *stk, *nxf;
82 extern filep ip;
83 extern filep offset;
84 extern filep nextb;
85 extern char *enda;
86 
87 extern int ch;
88 extern int ibf;
89 extern int lgf;
90 extern int copyf;
91 extern int ch0;
92 extern int app;
93 extern int ds;
94 extern int nlflg;
95 extern int *argtop;
96 extern int *ap;
97 extern int nchar;
98 extern int pendt;
99 extern int rchar;
100 extern int dilev;
101 extern int nonumb;
102 extern int lt;
103 extern int nrbits;
104 extern int nform;
105 extern int fmt[];
106 extern int oldmn;
107 extern int newmn;
108 extern int macerr;
109 extern filep apptr;
110 extern int diflg;
111 extern filep woff;
112 extern filep roff;
113 extern int wbfi;
114 extern int po;
115 extern int *cp;
116 extern int xxx;
117 extern int groffmode;
118 int pagech = '%';
119 int strflg;
120 extern struct contab {
121 	int rq;
122 	union {
123 		int (*f)();
124 		unsigned mx;
125 	}x;
126 }contab[NM];
127 #ifndef VMUNIX
128 int wbuf[BLK];
129 int rbuf[BLK];
130 #else
131 int *wbuf;
132 int *rbuf;
133 int Buf[NBLIST*BLK + NEV*EVS];
134 #endif
135 
caseig()136 caseig(){
137 	register i;
138 
139 	offset = 0;
140 	if((i = copyb()) != '.')control(i,1);
141 }
casern()142 casern(){
143 	register i,j;
144 
145 	lgf++;
146 	skip();
147 	if(((i=getrq())==0) || ((oldmn=findmn(i)) < 0))return;
148 	skip();
149 	clrmn(findmn(j=getrq()));
150 	if(j)contab[oldmn].rq = (contab[oldmn].rq & MMASK) | j;
151 }
caserm()152 caserm(){
153 	lgf++;
154 	while(!skip()){
155 		clrmn(findmn(getrq()));
156 	}
157 }
caseas()158 caseas(){
159 	app++;
160 	caseds();
161 }
caseds()162 caseds(){
163 	ds++;
164 	casede();
165 }
caseam()166 caseam(){
167 	app++;
168 	casede();
169 }
getrq_fc(j)170 getrq_fc(j){
171 	if ( ((j>='a')&&(j<='z')) || ((j>='A')&&(j<='Z')) ||
172 	     ((j>='0')&&(j<='9')) )
173 		return (!0);
174 	return 0;
175 }
casede()176 casede(){
177 	register i, j, req;
178 	register filep savoff;
179 	extern filep finds();
180 
181 	if(dip != d)wbfl();
182 	req = '.';
183 	lgf++;
184 	skip();
185 	if((i=getrq())==0)goto de1;
186 
187 	if (ds == 0 && app == 0) {
188 		register jw = 0;
189 
190 		while (getrq_fc((j=getch()) & CMASK)) {
191 			if (jw++)
192 				fprintf(stderr,
193 				    "warning: additional junk found!\n");
194 			else	fprintf(stderr,
195 				    "warning: roff handles only two-character"
196 				    " macroes, third character\n\treturned is"
197 				    " 0x%02X, overridden. Fix source (line"
198 				    " %d)!\n", j, v.cd+1);
199 		}
200 		if (!ch) ch=j;
201 	}
202 
203 	if((offset=finds(i)) == 0)goto de1;
204 	if(ds)copys();
205 		else req = copyb();
206 	wbfl();
207 	clrmn(oldmn);
208 	if(newmn)contab[newmn].rq = i | MMASK;
209 	if(apptr){
210 		savoff = offset;
211 		offset = apptr;
212 		wbt(IMP);
213 		offset = savoff;
214 	}
215 	offset = dip->op;
216 	if(req != '.')control(req,1);
217 de1:
218 	ds = app = 0;
219 	return;
220 }
findmn(i)221 findmn(i)
222 int i;
223 {
224 	register j;
225 
226 	for(j=0;j<NM;j++){
227 		if(i == (contab[j].rq & ~MMASK))break;
228 	}
229 	if(j==NM)j = -1;
230 	return(j);
231 }
clrmn(i)232 clrmn(i)
233 int i;
234 {
235 	extern filep boff();
236 	if(i >= 0){
237 		if(contab[i].rq & MMASK)ffree(((filep)contab[i].x.mx)<<BLKBITS);
238 		contab[i].rq = 0;
239 		contab[i].x.mx = 0;
240 	}
241 }
finds(mn)242 filep finds(mn)
243 int mn;
244 {
245 	register i;
246 	extern filep boff();
247 	register filep savip;
248 	extern filep alloc();
249 	extern filep incoff();
250 
251 	oldmn = findmn(mn);
252 	newmn = 0;
253 	apptr = (filep)0;
254 	if(app && (oldmn >= 0) && (contab[oldmn].rq & MMASK)){
255 			savip = ip;
256 			ip = (((filep)contab[oldmn].x.mx)<<BLKBITS);
257 			oldmn = -1;
258 			while((i=rbf()) != 0);
259 			apptr = ip;
260 			if(!diflg)ip = incoff(ip);
261 			nextb = ip;
262 			ip = savip;
263 	}else{
264 		for(i=0;i<NM;i++){
265 			if(contab[i].rq == 0)break;
266 		}
267 		if((i==NM) ||
268 		   (nextb = alloc()) == 0){
269 			app = 0;
270 			if(macerr++ > 1)done2(02);
271 			prstr("Too many string/macro names.\n");
272 			edone(04);
273 			return(offset = 0);
274 		}
275 			contab[i].x.mx = (unsigned)(nextb>>BLKBITS);
276 		if(!diflg){
277 			newmn = i;
278 			if(oldmn == -1)contab[i].rq = -1;
279 		}else{
280 			contab[i].rq = mn | MMASK;
281 		}
282 	}
283 
284 	app = 0;
285 	return(offset = nextb);
286 }
skip()287 skip(){
288 	register i;
289 
290 	while(((i=getch()) & CMASK) == ' ');
291 	ch=i;
292 	return(nlflg);
293 }
copyb()294 copyb()
295 {
296 	register i, j, k;
297 	int ii, req, state;
298 	filep savoff;
299 
300 	if(skip() || !(j=getrq()))j = '.';
301 	req = j;
302 	k = j>>BYTE;
303 	j &= BMASK;
304 	copyf++;
305 	flushi();
306 	nlflg = 0;
307 	state = 1;
308 	while(1){
309 		i = (ii = getch()) & CMASK;
310 		if(state == 3){
311 			if(i == k)break;
312 			if(!k){
313 				ch = ii;
314 				i = getach();
315 				ch = ii;
316 				if(!i)break;
317 			}
318 			state = 0;
319 			goto c0;
320 		}
321 		if(i == '\n'){
322 			state = 1;
323 			nlflg = 0;
324 			goto c0;
325 		}
326 		if((state == 1) && (i == '.')){
327 			state++;
328 			savoff = offset;
329 			goto c0;
330 		}
331 		if((state == 2) && (i == j)){
332 			state++;
333 			goto c0;
334 		}
335 		state = 0;
336 c0:
337 		if(offset)wbf(ii);
338 	}
339 	if(offset){
340 		wbfl();
341 		offset = savoff;
342 		wbt(0);
343 	}
344 	copyf--;
345 	return(req);
346 }
copys()347 copys()
348 {
349 	register i;
350 
351 	copyf++;
352 	if(skip())goto c0;
353 	if(((i=getch()) & CMASK) != '"')wbf(i);
354 	while(((i=getch()) & CMASK) != '\n')wbf(i);
355 c0:
356 	wbt(0);
357 	copyf--;
358 }
alloc()359 filep alloc()
360 {
361 	register i;
362 	extern filep boff();
363 	filep j;
364 
365 	for(i=0;i<NBLIST;i++){
366 		if(blist[i] == 0)break;
367 	}
368 	if(i==NBLIST){
369 		j = 0;
370 	}else{
371 		blist[i] = -1;
372 		if((j = boff(i)) < NEV*EVS)j = 0;
373 	}
374 	return(nextb = j);
375 }
ffree(i)376 ffree(i)
377 filep i;
378 {
379 	register j;
380 
381 	while((blist[j = blisti(i)]) != -1){
382 		i = ((filep)blist[j])<<BLKBITS;
383 		blist[j] = 0;
384 	}
385 	blist[j] = 0;
386 }
boff(i)387 filep boff(i)
388 int i;
389 {
390 	return(((filep)i)*BLK + NEV*EVS);
391 }
wbt(i)392 wbt(i)
393 int i;
394 {
395 	wbf(i);
396 	wbfl();
397 }
wbf(i)398 wbf(i)
399 int i;
400 {
401 	register j;
402 
403 	if(!offset)return;
404 	if(!woff){
405 		woff = offset;
406 #ifdef VMUNIX
407 		wbuf = &Buf[woff];
408 #endif
409 		wbfi = 0;
410 	}
411 	wbuf[wbfi++] = i;
412 	if(!((++offset) & (BLK-1))){
413 		wbfl();
414 		if(blist[j = blisti(--offset)] == -1){
415 			if(alloc() == 0){
416 				prstr("Out of temp file space.\n");
417 				done2(01);
418 			}
419 			blist[j] = (unsigned)(nextb>>BLKBITS);
420 		}
421 		offset = ((filep)blist[j])<<BLKBITS;
422 	}
423 	if(wbfi >= BLK)wbfl();
424 }
wbfl()425 wbfl(){
426 	if(woff == 0)return;
427 #ifndef VMUNIX
428 	lseek(ibf, ((long)woff) * sizeof(int), 0);
429 	write(ibf, (char *)wbuf, wbfi * sizeof(int));
430 #endif
431 	if((woff & (~(BLK-1))) == (roff & (~(BLK-1))))roff = -1;
432 	woff = 0;
433 }
blisti(i)434 blisti(i)
435 filep i;
436 {
437 	return((i-NEV*EVS)/(BLK));
438 }
rbf()439 rbf(){
440 	register i;
441 	extern filep incoff();
442 
443 	if((i=rbf0(ip)) == 0){
444 		if(!app)i = popi();
445 	}else{
446 		ip = incoff(ip);
447 	}
448 	return(i);
449 }
rbf0(p)450 rbf0(p)
451 filep p;
452 {
453 	register filep i;
454 
455 	if((i = (p & (~(BLK-1)))) != roff){
456 		roff = i;
457 #ifndef VMUNIX
458 		lseek(ibf, ((long)roff) * sizeof(int), 0);
459 		if(read(ibf, (char *)rbuf, BLK * sizeof(int)) == 0)return(0);
460 #else
461 		rbuf = &Buf[roff];
462 #endif
463 	}
464 	return(rbuf[p & (BLK-1)]);
465 }
incoff(p)466 filep incoff(p)
467 filep p;
468 {
469 	register i;
470 	register filep j;
471 	if(!((j = (++p)) & (BLK-1))){
472 		if((i = blist[blisti(--p)]) == -1){
473 			prstr("Bad storage allocation.\n");
474 			done2(-5);
475 		}
476 		j = ((filep)i)<<BLKBITS;
477 	}
478 	return(j);
479 }
popi()480 popi(){
481 	register struct s *p;
482 
483 	if(frame == stk)return(0);
484 	if(strflg)strflg--;
485 	p = nxf = frame;
486 	p->nargs = 0;
487 	frame = p->pframe;
488 	ip = p->pip;
489 	nchar = p->pnchar;
490 	rchar = p->prchar;
491 	pendt = p->ppendt;
492 	ap = p->pap;
493 	cp = p->pcp;
494 	ch0 = p->pch0;
495 	return(p->pch);
496 }
497 
498 /*
499  *	test that the end of the allocation is above a certain location
500  *	in memory
501  */
502 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);}
503 
pushi(newip)504 pushi(newip)
505 filep newip;
506 {
507 	register struct s *p;
508 	extern char	*setbrk();
509 
510 	SPACETEST(nxf, sizeof(struct s));
511 	p = nxf;
512 	p->pframe = frame;
513 	p->pip = ip;
514 	p->pnchar = nchar;
515 	p->prchar = rchar;
516 	p->ppendt = pendt;
517 	p->pap = ap;
518 	p->pcp = cp;
519 	p->pch0 = ch0;
520 	p->pch = ch;
521 	cp = ap = 0;
522 	nchar = rchar = pendt = ch0 = ch = 0;
523 	frame = nxf;
524 	if (nxf->nargs == 0)
525 		nxf += 1;
526 	else
527 		nxf = (struct s *)argtop;
528 	return(ip = newip);
529 }
530 
531 
setbrk(x)532 char	*setbrk(x)
533 int	x;
534 {
535 	register char	*i;
536 	char	*sbrk();
537 
538 	x += sizeof(int) - 1;
539 	x &= ~(sizeof(int) - 1);
540 	if ((u_int)(i = sbrk(x)) == -1) {
541 		prstrfl("Core limit reached.\n");
542 		edone(0100);
543 	} else {
544 		enda = i + x;
545 	}
546 	return(i);
547 }
548 
549 
getsn()550 getsn()
551 {
552 	register i;
553 
554 	if ((i = getach()) == 0)
555 		return(0);
556 #ifdef backwards
557 	if (groffmode && !copyf && (i == '['))
558 		fprintf(stderr, "warning: request for long string"
559 		    " in line %d denied!\n", v.cd+1);
560 #else
561 	if (/* groffmode && !copyf && */ !ecskip && (i == '[')) {
562 		fputs("warning: request for long string [", stderr);
563 		while ((i = getach())) {
564 			putc(i, stderr);
565 			if (i == ']')
566 				break;
567 		}
568 		if (i != ']')
569 			fputs("<NUL>]", stderr);
570 		fprintf(stderr, " in line %d denied!\n", v.cd+1);
571 		return (0);
572 	}
573 #endif
574 	if (i == '(')
575 		return(getrq());
576 	else
577 		return(i);
578 }
579 
580 
setstr()581 setstr()
582 {
583 	register i;
584 
585 	lgf++;
586 	if (    ((i = getsn()) == 0)
587 	     || ((i = findmn(i)) == -1)
588 	     ||  !(contab[i].rq & MMASK)) {
589 		lgf--;
590 		return(0);
591 	} else {
592 		SPACETEST(nxf, sizeof(struct s));
593 		nxf->nargs = 0;
594 		strflg++;
595 		lgf--;
596 		return(pushi(((filep)contab[i].x.mx)<<BLKBITS));
597 	}
598 }
599 
600 typedef	int	tchar;
601 #define	cbits(x)	((x) & CMASK)
602 
collect()603 collect()
604 {
605 	register j;
606 	tchar i;
607 	register tchar *strp;
608 	tchar * lim;
609 	tchar * *argpp, **argppend;
610 	int	quote;
611 	struct s *savnxf;
612 
613 	copyf++;
614 	nxf->nargs = 0;
615 	savnxf = nxf;
616 	if (skip())
617 		goto rtn;
618 
619 	{
620 		char *memp;
621 		memp = (char *)savnxf;
622 		/*
623 		 *	1 s structure for the macro descriptor
624 		 *	APERMAC tchar *'s for pointers into the strings
625 		 *	space for the tchar's themselves
626 		 */
627 		memp += sizeof(struct s);
628 		/*
629 		 *	CPERMAC (the total # of characters for ALL arguments)
630 		 *	to a macros, has been carefully chosen
631 		 *	so that the distance between stack frames is < DELTA
632 		 */
633 #define	CPERMAC	500
634 #define	APERMAC	9
635 		memp += APERMAC * sizeof(tchar *);
636 		memp += CPERMAC * sizeof(tchar);
637 		nxf = (struct s*)memp;
638 	}
639 	lim = (tchar *)nxf;
640 	argpp = (tchar **)(savnxf + 1);
641 	argppend = &argpp[APERMAC];
642 	SPACETEST(argppend, sizeof(tchar *));
643 	strp = (tchar *)argppend;
644 	/*
645 	 *	Zero out all the string pointers before filling them in.
646 	 */
647 	for (j = 0; j < APERMAC; j++){
648 		argpp[j] = (tchar *)0;
649 	}
650 #if 0
651 	fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n",
652 		savnxf, nxf, argpp, strp, lim, enda);
653 #endif
654 	strflg = 0;
655 	while ((argpp != argppend) && (!skip())) {
656 		*argpp++ = strp;
657 		quote = 0;
658 		if (cbits(i = getch()) == '"')
659 			quote++;
660 		else
661 			ch = i;
662 		while (1) {
663 			i = getch();
664 			if ( nlflg ||  (!quote && cbits(i) == ' '))
665 				break;
666 			if (   quote
667 			    && (cbits(i) == '"')
668 			    && (cbits(i = getch()) != '"')) {
669 				ch = i;
670 				break;
671 			}
672 			*strp++ = i;
673 			if (strflg && (strp >= lim)) {
674 #if 0
675 				fprintf(stderr, "strp=0x%x, lim = 0x%x\n",
676 					strp, lim);
677 #endif
678 				prstrfl("Macro argument too long.\n");
679 				copyf--;
680 				edone(004);
681 			}
682 			SPACETEST(strp, 3 * sizeof(tchar));
683 		}
684 		*strp++ = 0;
685 	}
686 	nxf = savnxf;
687 	nxf->nargs = argpp - (tchar **)(savnxf + 1);
688 	argtop = strp;
689 rtn:
690 	copyf--;
691 }
692 
693 
seta()694 seta()
695 {
696 	register i;
697 
698 	if(((i = (getch() & CMASK) - '0') > 0) &&
699 		(i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **)));
700 }
caseda()701 caseda(){
702 	app++;
703 	casedi();
704 }
casedi()705 casedi(){
706 	register i, j;
707 	register *k;
708 
709 	lgf++;
710 	if(skip() || ((i=getrq()) == 0)){
711 		if(dip != d)wbt(0);
712 		if(dilev > 0){
713 			v.dn = dip->dnl;
714 			v.dl = dip->maxl;
715 			dip = &d[--dilev];
716 			offset = dip->op;
717 		}
718 		goto rtn;
719 	}
720 	if(++dilev == NDI){
721 		--dilev;
722 		prstr("Cannot divert.\n");
723 		edone(02);
724 	}
725 	if(dip != d)wbt(0);
726 	diflg++;
727 	dip = &d[dilev];
728 	dip->op = finds(i);
729 	dip->curd = i;
730 	clrmn(oldmn);
731 	k = (int *)&dip->dnl;
732 	for(j=0; j<10; j++)k[j] = 0;	/*not op and curd*/
733 rtn:
734 	app = 0;
735 	diflg = 0;
736 }
casedt()737 casedt(){
738 	lgf++;
739 	dip->dimac = dip->ditrap = dip->ditf = 0;
740 	skip();
741 	dip->ditrap = vnumb((int *)0);
742 	if(nonumb)return;
743 	skip();
744 	dip->dimac = getrq();
745 }
casetl()746 casetl(){
747 	register i, j;
748 	int w1, w2, w3, delim;
749 	filep begin;
750 	extern width(), pchar();
751 
752 	dip->nls = 0;
753 	skip();
754 	if(dip != d)wbfl();
755 	if((offset = begin = alloc()) == 0)return;
756 	if((delim = getch()) & MOT){
757 		ch = delim;
758 		delim = '\'';
759 	}else delim &= CMASK;
760 	if(!nlflg)
761 		while(((i = getch()) & CMASK) != '\n'){
762 			if((i & CMASK) == delim)i = IMP;
763 			wbf(i);
764 		}
765 	wbf(IMP);wbf(IMP);wbt(0);
766 
767 	w1 = hseg(width,begin);
768 	w2 = hseg(width,(filep)0);
769 	w3 = hseg(width,(filep)0);
770 	offset = dip->op;
771 #ifdef NROFF
772 	if(!offset)horiz(po);
773 #endif
774 	hseg(pchar,begin);
775 	if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR));
776 	hseg(pchar,(filep)0);
777 	if(w3){
778 		horiz(lt-w1-w2-w3-j);
779 		hseg(pchar,(filep)0);
780 	}
781 	newline(0);
782 	if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;}
783 	else{if(v.nl > dip->hnl)dip->hnl = v.nl;}
784 	ffree(begin);
785 }
casepc()786 casepc(){
787 	pagech = chget(IMP);
788 }
789 hseg(f,p)
790 int (*f)();
791 filep p;
792 {
793 	register acc, i;
794 	static filep q;
795 
796 	acc = 0;
797 	if(p)q = p;
798 	while(1){
799 		i = rbf0(q);
800 		q = incoff(q);
801 		if(!i || (i == IMP))return(acc);
802 		if((i & CMASK) == pagech){
803 			nrbits = i & ~CMASK;
804 			nform = fmt[findr('%')];
805 			acc += fnumb(v.pn,f);
806 		}else acc += (*f)(i);
807 	}
808 }
casepm()809 casepm(){
810 	register i, k;
811 	register char *p;
812 	int xx, cnt, kk, tot;
813 	filep j;
814 	char *kvt();
815 	char pmline[10];
816 
817 	kk = cnt = 0;
818 	tot = !skip();
819 	for(i = 0; i<NM; i++){
820 		if(!((xx = contab[i].rq) & MMASK))continue;
821 		p = pmline;
822 		j = (((filep)contab[i].x.mx)<<BLKBITS);
823 		k = 1;
824 		while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;}
825 		cnt++;
826 		kk += k;
827 		if(!tot){
828 			*p++ = xx & 0177;
829 			if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' ';
830 			*p++ = ' ';
831 			kvt(k,p);
832 			prstr(pmline);
833 		}
834 	}
835 	if(tot || (cnt > 1)){
836 		kvt(kk,pmline);
837 		prstr(pmline);
838 	}
839 }
kvt(k,p)840 char *kvt(k,p)
841 int k;
842 char *p;
843 {
844 	if(k>=100)*p++ = k/100 + '0';
845 	if(k>=10)*p++ = (k%100)/10 + '0';
846 	*p++ = k%10 + '0';
847 	*p++ = '\n';
848 	*p = 0;
849 	return(p);
850 }
dummy()851 dummy(){}
852