xref: /original-bsd/old/roff/common_source/n3.c (revision fb9118b1)
1 #ifndef lint
2 static char sccsid[] = "@(#)n3.c	4.3 04/30/87";
3 #endif lint
4 
5 #include "tdef.h"
6 extern
7 #include "d.h"
8 extern
9 #include "v.h"
10 #ifdef NROFF
11 extern
12 #include "tw.h"
13 #endif
14 #include "sdef.h"
15 
16 /*
17 troff3.c
18 
19 macro and string routines, storage allocation
20 */
21 
22 unsigned blist[NBLIST];
23 extern struct s *frame, *stk, *nxf;
24 extern filep ip;
25 extern filep offset;
26 extern filep nextb;
27 extern char *enda;
28 
29 extern int ch;
30 extern int ibf;
31 extern int lgf;
32 extern int copyf;
33 extern int ch0;
34 extern int app;
35 extern int ds;
36 extern int nlflg;
37 extern int *argtop;
38 extern int *ap;
39 extern int nchar;
40 extern int pendt;
41 extern int rchar;
42 extern int dilev;
43 extern int nonumb;
44 extern int lt;
45 extern int nrbits;
46 extern int nform;
47 extern int fmt[];
48 extern int oldmn;
49 extern int newmn;
50 extern int macerr;
51 extern filep apptr;
52 extern int diflg;
53 extern filep woff;
54 extern filep roff;
55 extern int wbfi;
56 extern int po;
57 extern int *cp;
58 extern int xxx;
59 int pagech = '%';
60 int strflg;
61 extern struct contab {
62 	int rq;
63 	union {
64 		int (*f)();
65 		unsigned mx;
66 	}x;
67 }contab[NM];
68 #ifndef VMUNIX
69 int wbuf[BLK];
70 int rbuf[BLK];
71 #else
72 int *wbuf;
73 int *rbuf;
74 int Buf[NBLIST*BLK + NEV*EVS];
75 #endif
76 
77 caseig(){
78 	register i;
79 
80 	offset = 0;
81 	if((i = copyb()) != '.')control(i,1);
82 }
83 casern(){
84 	register i,j;
85 
86 	lgf++;
87 	skip();
88 	if(((i=getrq())==0) || ((oldmn=findmn(i)) < 0))return;
89 	skip();
90 	clrmn(findmn(j=getrq()));
91 	if(j)contab[oldmn].rq = (contab[oldmn].rq & MMASK) | j;
92 }
93 caserm(){
94 	lgf++;
95 	while(!skip()){
96 		clrmn(findmn(getrq()));
97 	}
98 }
99 caseas(){
100 	app++;
101 	caseds();
102 }
103 caseds(){
104 	ds++;
105 	casede();
106 }
107 caseam(){
108 	app++;
109 	casede();
110 }
111 casede(){
112 	register i, req;
113 	register filep savoff;
114 	extern filep finds();
115 
116 	if(dip != d)wbfl();
117 	req = '.';
118 	lgf++;
119 	skip();
120 	if((i=getrq())==0)goto de1;
121 	if((offset=finds(i)) == 0)goto de1;
122 	if(ds)copys();
123 		else req = copyb();
124 	wbfl();
125 	clrmn(oldmn);
126 	if(newmn)contab[newmn].rq = i | MMASK;
127 	if(apptr){
128 		savoff = offset;
129 		offset = apptr;
130 		wbt(IMP);
131 		offset = savoff;
132 	}
133 	offset = dip->op;
134 	if(req != '.')control(req,1);
135 de1:
136 	ds = app = 0;
137 	return;
138 }
139 findmn(i)
140 int i;
141 {
142 	register j;
143 
144 	for(j=0;j<NM;j++){
145 		if(i == (contab[j].rq & ~MMASK))break;
146 	}
147 	if(j==NM)j = -1;
148 	return(j);
149 }
150 clrmn(i)
151 int i;
152 {
153 	extern filep boff();
154 	if(i >= 0){
155 		if(contab[i].rq & MMASK)ffree(((filep)contab[i].x.mx)<<BLKBITS);
156 		contab[i].rq = 0;
157 		contab[i].x.mx = 0;
158 	}
159 }
160 filep finds(mn)
161 int mn;
162 {
163 	register i;
164 	extern filep boff();
165 	register filep savip;
166 	extern filep alloc();
167 	extern filep incoff();
168 
169 	oldmn = findmn(mn);
170 	newmn = 0;
171 	apptr = (filep)0;
172 	if(app && (oldmn >= 0) && (contab[oldmn].rq & MMASK)){
173 			savip = ip;
174 			ip = (((filep)contab[oldmn].x.mx)<<BLKBITS);
175 			oldmn = -1;
176 			while((i=rbf()) != 0);
177 			apptr = ip;
178 			if(!diflg)ip = incoff(ip);
179 			nextb = ip;
180 			ip = savip;
181 	}else{
182 		for(i=0;i<NM;i++){
183 			if(contab[i].rq == 0)break;
184 		}
185 		if((i==NM) ||
186 		   (nextb = alloc()) == 0){
187 			app = 0;
188 			if(macerr++ > 1)done2(02);
189 			prstr("Too many string/macro names.\n");
190 			edone(04);
191 			return(offset = 0);
192 		}
193 			contab[i].x.mx = (unsigned)(nextb>>BLKBITS);
194 		if(!diflg){
195 			newmn = i;
196 			if(oldmn == -1)contab[i].rq = -1;
197 		}else{
198 			contab[i].rq = mn | MMASK;
199 		}
200 	}
201 
202 	app = 0;
203 	return(offset = nextb);
204 }
205 skip(){
206 	register i;
207 
208 	while(((i=getch()) & CMASK) == ' ');
209 	ch=i;
210 	return(nlflg);
211 }
212 copyb()
213 {
214 	register i, j, k;
215 	int ii, req, state;
216 	filep savoff;
217 
218 	if(skip() || !(j=getrq()))j = '.';
219 	req = j;
220 	k = j>>BYTE;
221 	j &= BMASK;
222 	copyf++;
223 	flushi();
224 	nlflg = 0;
225 	state = 1;
226 	while(1){
227 		i = (ii = getch()) & CMASK;
228 		if(state == 3){
229 			if(i == k)break;
230 			if(!k){
231 				ch = ii;
232 				i = getach();
233 				ch = ii;
234 				if(!i)break;
235 			}
236 			state = 0;
237 			goto c0;
238 		}
239 		if(i == '\n'){
240 			state = 1;
241 			nlflg = 0;
242 			goto c0;
243 		}
244 		if((state == 1) && (i == '.')){
245 			state++;
246 			savoff = offset;
247 			goto c0;
248 		}
249 		if((state == 2) && (i == j)){
250 			state++;
251 			goto c0;
252 		}
253 		state = 0;
254 c0:
255 		if(offset)wbf(ii);
256 	}
257 	if(offset){
258 		wbfl();
259 		offset = savoff;
260 		wbt(0);
261 	}
262 	copyf--;
263 	return(req);
264 }
265 copys()
266 {
267 	register i;
268 
269 	copyf++;
270 	if(skip())goto c0;
271 	if(((i=getch()) & CMASK) != '"')wbf(i);
272 	while(((i=getch()) & CMASK) != '\n')wbf(i);
273 c0:
274 	wbt(0);
275 	copyf--;
276 }
277 filep alloc()
278 {
279 	register i;
280 	extern filep boff();
281 	filep j;
282 
283 	for(i=0;i<NBLIST;i++){
284 		if(blist[i] == 0)break;
285 	}
286 	if(i==NBLIST){
287 		j = 0;
288 	}else{
289 		blist[i] = -1;
290 		if((j = boff(i)) < NEV*EVS)j = 0;
291 	}
292 	return(nextb = j);
293 }
294 ffree(i)
295 filep i;
296 {
297 	register j;
298 
299 	while((blist[j = blisti(i)]) != -1){
300 		i = ((filep)blist[j])<<BLKBITS;
301 		blist[j] = 0;
302 	}
303 	blist[j] = 0;
304 }
305 filep boff(i)
306 int i;
307 {
308 	return(((filep)i)*BLK + NEV*EVS);
309 }
310 wbt(i)
311 int i;
312 {
313 	wbf(i);
314 	wbfl();
315 }
316 wbf(i)
317 int i;
318 {
319 	register j;
320 
321 	if(!offset)return;
322 	if(!woff){
323 		woff = offset;
324 #ifdef VMUNIX
325 		wbuf = &Buf[woff];
326 #endif
327 		wbfi = 0;
328 	}
329 	wbuf[wbfi++] = i;
330 	if(!((++offset) & (BLK-1))){
331 		wbfl();
332 		if(blist[j = blisti(--offset)] == -1){
333 			if(alloc() == 0){
334 				prstr("Out of temp file space.\n");
335 				done2(01);
336 			}
337 			blist[j] = (unsigned)(nextb>>BLKBITS);
338 		}
339 		offset = ((filep)blist[j])<<BLKBITS;
340 	}
341 	if(wbfi >= BLK)wbfl();
342 }
343 wbfl(){
344 	if(woff == 0)return;
345 #ifndef VMUNIX
346 	lseek(ibf, ((long)woff) * sizeof(int), 0);
347 	write(ibf, (char *)wbuf, wbfi * sizeof(int));
348 #endif
349 	if((woff & (~(BLK-1))) == (roff & (~(BLK-1))))roff = -1;
350 	woff = 0;
351 }
352 blisti(i)
353 filep i;
354 {
355 	return((i-NEV*EVS)/(BLK));
356 }
357 rbf(){
358 	register i;
359 	extern filep incoff();
360 
361 	if((i=rbf0(ip)) == 0){
362 		if(!app)i = popi();
363 	}else{
364 		ip = incoff(ip);
365 	}
366 	return(i);
367 }
368 rbf0(p)
369 filep p;
370 {
371 	register filep i;
372 
373 	if((i = (p & (~(BLK-1)))) != roff){
374 		roff = i;
375 #ifndef VMUNIX
376 		lseek(ibf, ((long)roff) * sizeof(int), 0);
377 		if(read(ibf, (char *)rbuf, BLK * sizeof(int)) == 0)return(0);
378 #else
379 		rbuf = &Buf[roff];
380 #endif
381 	}
382 	return(rbuf[p & (BLK-1)]);
383 }
384 filep incoff(p)
385 filep p;
386 {
387 	register i;
388 	register filep j;
389 	if(!((j = (++p)) & (BLK-1))){
390 		if((i = blist[blisti(--p)]) == -1){
391 			prstr("Bad storage allocation.\n");
392 			done2(-5);
393 		}
394 		j = ((filep)i)<<BLKBITS;
395 	}
396 	return(j);
397 }
398 popi(){
399 	register struct s *p;
400 
401 	if(frame == stk)return(0);
402 	if(strflg)strflg--;
403 	p = nxf = frame;
404 	p->nargs = 0;
405 	frame = p->pframe;
406 	ip = p->pip;
407 	nchar = p->pnchar;
408 	rchar = p->prchar;
409 	pendt = p->ppendt;
410 	ap = p->pap;
411 	cp = p->pcp;
412 	ch0 = p->pch0;
413 	return(p->pch);
414 }
415 
416 /*
417  *	test that the end of the allocation is above a certain location
418  *	in memory
419  */
420 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);}
421 
422 pushi(newip)
423 filep newip;
424 {
425 	register struct s *p;
426 	extern char	*setbrk();
427 
428 	SPACETEST(nxf, sizeof(struct s));
429 	p = nxf;
430 	p->pframe = frame;
431 	p->pip = ip;
432 	p->pnchar = nchar;
433 	p->prchar = rchar;
434 	p->ppendt = pendt;
435 	p->pap = ap;
436 	p->pcp = cp;
437 	p->pch0 = ch0;
438 	p->pch = ch;
439 	cp = ap = 0;
440 	nchar = rchar = pendt = ch0 = ch = 0;
441 	frame = nxf;
442 	if (nxf->nargs == 0)
443 		nxf += 1;
444 	else
445 		nxf = (struct s *)argtop;
446 	return(ip = newip);
447 }
448 
449 
450 char	*setbrk(x)
451 int	x;
452 {
453 	register char	*i;
454 	char	*sbrk();
455 
456 /* ought to be rounded up by sizeof(int) */
457 	if (x % 2 == 1)
458 		x++;
459 	if ( (i = sbrk(x)) >= (char *)-1) {
460 		prstrfl("Core limit reached.\n");
461 		edone(0100);
462 	} else {
463 		enda = i + x;
464 	}
465 	return(i);
466 }
467 
468 
469 getsn()
470 {
471 	register i;
472 
473 	if ((i = getach()) == 0)
474 		return(0);
475 	if (i == '(')
476 		return(getrq());
477 	else
478 		return(i);
479 }
480 
481 
482 setstr()
483 {
484 	register i;
485 
486 	lgf++;
487 	if (    ((i = getsn()) == 0)
488 	     || ((i = findmn(i)) == -1)
489 	     ||  !(contab[i].rq & MMASK)) {
490 		lgf--;
491 		return(0);
492 	} else {
493 		SPACETEST(nxf, sizeof(struct s));
494 		nxf->nargs = 0;
495 		strflg++;
496 		lgf--;
497 		return(pushi(((filep)contab[i].x.mx)<<BLKBITS));
498 	}
499 }
500 
501 typedef	int	tchar;
502 #define	cbits(x)	((x) & CMASK)
503 
504 collect()
505 {
506 	register j;
507 	tchar i;
508 	register tchar *strp;
509 	tchar * lim;
510 	tchar * *argpp, **argppend;
511 	int	quote;
512 	struct s *savnxf;
513 
514 	copyf++;
515 	nxf->nargs = 0;
516 	savnxf = nxf;
517 	if (skip())
518 		goto rtn;
519 
520 	{
521 		char *memp;
522 		memp = (char *)savnxf;
523 		/*
524 		 *	1 s structure for the macro descriptor
525 		 *	APERMAC tchar *'s for pointers into the strings
526 		 *	space for the tchar's themselves
527 		 */
528 		memp += sizeof(struct s);
529 		/*
530 		 *	CPERMAC (the total # of characters for ALL arguments)
531 		 *	to a macros, has been carefully chosen
532 		 *	so that the distance between stack frames is < DELTA
533 		 */
534 #define	CPERMAC	200
535 #define	APERMAC	9
536 		memp += APERMAC * sizeof(tchar *);
537 		memp += CPERMAC * sizeof(tchar);
538 		nxf = (struct s*)memp;
539 	}
540 	lim = (tchar *)nxf;
541 	argpp = (tchar **)(savnxf + 1);
542 	argppend = &argpp[APERMAC];
543 	SPACETEST(argppend, sizeof(tchar *));
544 	strp = (tchar *)argppend;
545 	/*
546 	 *	Zero out all the string pointers before filling them in.
547 	 */
548 	for (j = 0; j < APERMAC; j++){
549 		argpp[j] = (tchar *)0;
550 	}
551 #if 0
552 	fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n",
553 		savnxf, nxf, argpp, strp, lim, enda);
554 #endif 0
555 	strflg = 0;
556 	while ((argpp != argppend) && (!skip())) {
557 		*argpp++ = strp;
558 		quote = 0;
559 		if (cbits(i = getch()) == '"')
560 			quote++;
561 		else
562 			ch = i;
563 		while (1) {
564 			i = getch();
565 			if ( nlflg ||  (!quote && cbits(i) == ' '))
566 				break;
567 			if (   quote
568 			    && (cbits(i) == '"')
569 			    && (cbits(i = getch()) != '"')) {
570 				ch = i;
571 				break;
572 			}
573 			*strp++ = i;
574 			if (strflg && (strp >= lim)) {
575 #if 0
576 				fprintf(stderr, "strp=0x%x, lim = 0x%x\n",
577 					strp, lim);
578 #endif 0
579 				prstrfl("Macro argument too long.\n");
580 				copyf--;
581 				edone(004);
582 			}
583 			SPACETEST(strp, 3 * sizeof(tchar));
584 		}
585 		*strp++ = 0;
586 	}
587 	nxf = savnxf;
588 	nxf->nargs = argpp - (tchar **)(savnxf + 1);
589 	argtop = strp;
590 rtn:
591 	copyf--;
592 }
593 
594 
595 seta()
596 {
597 	register i;
598 
599 	if(((i = (getch() & CMASK) - '0') > 0) &&
600 		(i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **)));
601 }
602 caseda(){
603 	app++;
604 	casedi();
605 }
606 casedi(){
607 	register i, j;
608 	register *k;
609 
610 	lgf++;
611 	if(skip() || ((i=getrq()) == 0)){
612 		if(dip != d)wbt(0);
613 		if(dilev > 0){
614 			v.dn = dip->dnl;
615 			v.dl = dip->maxl;
616 			dip = &d[--dilev];
617 			offset = dip->op;
618 		}
619 		goto rtn;
620 	}
621 	if(++dilev == NDI){
622 		--dilev;
623 		prstr("Cannot divert.\n");
624 		edone(02);
625 	}
626 	if(dip != d)wbt(0);
627 	diflg++;
628 	dip = &d[dilev];
629 	dip->op = finds(i);
630 	dip->curd = i;
631 	clrmn(oldmn);
632 	k = (int *)&dip->dnl;
633 	for(j=0; j<10; j++)k[j] = 0;	/*not op and curd*/
634 rtn:
635 	app = 0;
636 	diflg = 0;
637 }
638 casedt(){
639 	lgf++;
640 	dip->dimac = dip->ditrap = dip->ditf = 0;
641 	skip();
642 	dip->ditrap = vnumb((int *)0);
643 	if(nonumb)return;
644 	skip();
645 	dip->dimac = getrq();
646 }
647 casetl(){
648 	register i, j;
649 	int w1, w2, w3, delim;
650 	filep begin;
651 	extern width(), pchar();
652 
653 	dip->nls = 0;
654 	skip();
655 	if(dip != d)wbfl();
656 	if((offset = begin = alloc()) == 0)return;
657 	if((delim = getch()) & MOT){
658 		ch = delim;
659 		delim = '\'';
660 	}else delim &= CMASK;
661 	if(!nlflg)
662 		while(((i = getch()) & CMASK) != '\n'){
663 			if((i & CMASK) == delim)i = IMP;
664 			wbf(i);
665 		}
666 	wbf(IMP);wbf(IMP);wbt(0);
667 
668 	w1 = hseg(width,begin);
669 	w2 = hseg(width,(filep)0);
670 	w3 = hseg(width,(filep)0);
671 	offset = dip->op;
672 #ifdef NROFF
673 	if(!offset)horiz(po);
674 #endif
675 	hseg(pchar,begin);
676 	if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR));
677 	hseg(pchar,(filep)0);
678 	if(w3){
679 		horiz(lt-w1-w2-w3-j);
680 		hseg(pchar,(filep)0);
681 	}
682 	newline(0);
683 	if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;}
684 	else{if(v.nl > dip->hnl)dip->hnl = v.nl;}
685 	ffree(begin);
686 }
687 casepc(){
688 	pagech = chget(IMP);
689 }
690 hseg(f,p)
691 int (*f)();
692 filep p;
693 {
694 	register acc, i;
695 	static filep q;
696 
697 	acc = 0;
698 	if(p)q = p;
699 	while(1){
700 		i = rbf0(q);
701 		q = incoff(q);
702 		if(!i || (i == IMP))return(acc);
703 		if((i & CMASK) == pagech){
704 			nrbits = i & ~CMASK;
705 			nform = fmt[findr('%')];
706 			acc += fnumb(v.pn,f);
707 		}else acc += (*f)(i);
708 	}
709 }
710 casepm(){
711 	register i, k;
712 	register char *p;
713 	int xx, cnt, kk, tot;
714 	filep j;
715 	char *kvt();
716 	char pmline[10];
717 
718 	kk = cnt = 0;
719 	tot = !skip();
720 	for(i = 0; i<NM; i++){
721 		if(!((xx = contab[i].rq) & MMASK))continue;
722 		p = pmline;
723 		j = (((filep)contab[i].x.mx)<<BLKBITS);
724 		k = 1;
725 		while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;}
726 		cnt++;
727 		kk += k;
728 		if(!tot){
729 			*p++ = xx & 0177;
730 			if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' ';
731 			*p++ = ' ';
732 			kvt(k,p);
733 			prstr(pmline);
734 		}
735 	}
736 	if(tot || (cnt > 1)){
737 		kvt(kk,pmline);
738 		prstr(pmline);
739 	}
740 }
741 char *kvt(k,p)
742 int k;
743 char *p;
744 {
745 	if(k>=100)*p++ = k/100 + '0';
746 	if(k>=10)*p++ = (k%100)/10 + '0';
747 	*p++ = k%10 + '0';
748 	*p++ = '\n';
749 	*p = 0;
750 	return(p);
751 }
752 dummy(){}
753