xref: /original-bsd/old/roff/common_source/n3.c (revision afe6d20d)
1 #ifndef lint
2 static char sccsid[] = "@(#)n3.c	4.4 06/25/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 	x += sizeof(int) - 1;
457 	x &= ~(sizeof(int) - 1);
458 	if ((u_int)(i = sbrk(x)) == -1) {
459 		prstrfl("Core limit reached.\n");
460 		edone(0100);
461 	} else {
462 		enda = i + x;
463 	}
464 	return(i);
465 }
466 
467 
468 getsn()
469 {
470 	register i;
471 
472 	if ((i = getach()) == 0)
473 		return(0);
474 	if (i == '(')
475 		return(getrq());
476 	else
477 		return(i);
478 }
479 
480 
481 setstr()
482 {
483 	register i;
484 
485 	lgf++;
486 	if (    ((i = getsn()) == 0)
487 	     || ((i = findmn(i)) == -1)
488 	     ||  !(contab[i].rq & MMASK)) {
489 		lgf--;
490 		return(0);
491 	} else {
492 		SPACETEST(nxf, sizeof(struct s));
493 		nxf->nargs = 0;
494 		strflg++;
495 		lgf--;
496 		return(pushi(((filep)contab[i].x.mx)<<BLKBITS));
497 	}
498 }
499 
500 typedef	int	tchar;
501 #define	cbits(x)	((x) & CMASK)
502 
503 collect()
504 {
505 	register j;
506 	tchar i;
507 	register tchar *strp;
508 	tchar * lim;
509 	tchar * *argpp, **argppend;
510 	int	quote;
511 	struct s *savnxf;
512 
513 	copyf++;
514 	nxf->nargs = 0;
515 	savnxf = nxf;
516 	if (skip())
517 		goto rtn;
518 
519 	{
520 		char *memp;
521 		memp = (char *)savnxf;
522 		/*
523 		 *	1 s structure for the macro descriptor
524 		 *	APERMAC tchar *'s for pointers into the strings
525 		 *	space for the tchar's themselves
526 		 */
527 		memp += sizeof(struct s);
528 		/*
529 		 *	CPERMAC (the total # of characters for ALL arguments)
530 		 *	to a macros, has been carefully chosen
531 		 *	so that the distance between stack frames is < DELTA
532 		 */
533 #define	CPERMAC	200
534 #define	APERMAC	9
535 		memp += APERMAC * sizeof(tchar *);
536 		memp += CPERMAC * sizeof(tchar);
537 		nxf = (struct s*)memp;
538 	}
539 	lim = (tchar *)nxf;
540 	argpp = (tchar **)(savnxf + 1);
541 	argppend = &argpp[APERMAC];
542 	SPACETEST(argppend, sizeof(tchar *));
543 	strp = (tchar *)argppend;
544 	/*
545 	 *	Zero out all the string pointers before filling them in.
546 	 */
547 	for (j = 0; j < APERMAC; j++){
548 		argpp[j] = (tchar *)0;
549 	}
550 #if 0
551 	fprintf(stderr, "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x\n",
552 		savnxf, nxf, argpp, strp, lim, enda);
553 #endif 0
554 	strflg = 0;
555 	while ((argpp != argppend) && (!skip())) {
556 		*argpp++ = strp;
557 		quote = 0;
558 		if (cbits(i = getch()) == '"')
559 			quote++;
560 		else
561 			ch = i;
562 		while (1) {
563 			i = getch();
564 			if ( nlflg ||  (!quote && cbits(i) == ' '))
565 				break;
566 			if (   quote
567 			    && (cbits(i) == '"')
568 			    && (cbits(i = getch()) != '"')) {
569 				ch = i;
570 				break;
571 			}
572 			*strp++ = i;
573 			if (strflg && (strp >= lim)) {
574 #if 0
575 				fprintf(stderr, "strp=0x%x, lim = 0x%x\n",
576 					strp, lim);
577 #endif 0
578 				prstrfl("Macro argument too long.\n");
579 				copyf--;
580 				edone(004);
581 			}
582 			SPACETEST(strp, 3 * sizeof(tchar));
583 		}
584 		*strp++ = 0;
585 	}
586 	nxf = savnxf;
587 	nxf->nargs = argpp - (tchar **)(savnxf + 1);
588 	argtop = strp;
589 rtn:
590 	copyf--;
591 }
592 
593 
594 seta()
595 {
596 	register i;
597 
598 	if(((i = (getch() & CMASK) - '0') > 0) &&
599 		(i <= APERMAC) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **)));
600 }
601 caseda(){
602 	app++;
603 	casedi();
604 }
605 casedi(){
606 	register i, j;
607 	register *k;
608 
609 	lgf++;
610 	if(skip() || ((i=getrq()) == 0)){
611 		if(dip != d)wbt(0);
612 		if(dilev > 0){
613 			v.dn = dip->dnl;
614 			v.dl = dip->maxl;
615 			dip = &d[--dilev];
616 			offset = dip->op;
617 		}
618 		goto rtn;
619 	}
620 	if(++dilev == NDI){
621 		--dilev;
622 		prstr("Cannot divert.\n");
623 		edone(02);
624 	}
625 	if(dip != d)wbt(0);
626 	diflg++;
627 	dip = &d[dilev];
628 	dip->op = finds(i);
629 	dip->curd = i;
630 	clrmn(oldmn);
631 	k = (int *)&dip->dnl;
632 	for(j=0; j<10; j++)k[j] = 0;	/*not op and curd*/
633 rtn:
634 	app = 0;
635 	diflg = 0;
636 }
637 casedt(){
638 	lgf++;
639 	dip->dimac = dip->ditrap = dip->ditf = 0;
640 	skip();
641 	dip->ditrap = vnumb((int *)0);
642 	if(nonumb)return;
643 	skip();
644 	dip->dimac = getrq();
645 }
646 casetl(){
647 	register i, j;
648 	int w1, w2, w3, delim;
649 	filep begin;
650 	extern width(), pchar();
651 
652 	dip->nls = 0;
653 	skip();
654 	if(dip != d)wbfl();
655 	if((offset = begin = alloc()) == 0)return;
656 	if((delim = getch()) & MOT){
657 		ch = delim;
658 		delim = '\'';
659 	}else delim &= CMASK;
660 	if(!nlflg)
661 		while(((i = getch()) & CMASK) != '\n'){
662 			if((i & CMASK) == delim)i = IMP;
663 			wbf(i);
664 		}
665 	wbf(IMP);wbf(IMP);wbt(0);
666 
667 	w1 = hseg(width,begin);
668 	w2 = hseg(width,(filep)0);
669 	w3 = hseg(width,(filep)0);
670 	offset = dip->op;
671 #ifdef NROFF
672 	if(!offset)horiz(po);
673 #endif
674 	hseg(pchar,begin);
675 	if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR));
676 	hseg(pchar,(filep)0);
677 	if(w3){
678 		horiz(lt-w1-w2-w3-j);
679 		hseg(pchar,(filep)0);
680 	}
681 	newline(0);
682 	if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;}
683 	else{if(v.nl > dip->hnl)dip->hnl = v.nl;}
684 	ffree(begin);
685 }
686 casepc(){
687 	pagech = chget(IMP);
688 }
689 hseg(f,p)
690 int (*f)();
691 filep p;
692 {
693 	register acc, i;
694 	static filep q;
695 
696 	acc = 0;
697 	if(p)q = p;
698 	while(1){
699 		i = rbf0(q);
700 		q = incoff(q);
701 		if(!i || (i == IMP))return(acc);
702 		if((i & CMASK) == pagech){
703 			nrbits = i & ~CMASK;
704 			nform = fmt[findr('%')];
705 			acc += fnumb(v.pn,f);
706 		}else acc += (*f)(i);
707 	}
708 }
709 casepm(){
710 	register i, k;
711 	register char *p;
712 	int xx, cnt, kk, tot;
713 	filep j;
714 	char *kvt();
715 	char pmline[10];
716 
717 	kk = cnt = 0;
718 	tot = !skip();
719 	for(i = 0; i<NM; i++){
720 		if(!((xx = contab[i].rq) & MMASK))continue;
721 		p = pmline;
722 		j = (((filep)contab[i].x.mx)<<BLKBITS);
723 		k = 1;
724 		while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;}
725 		cnt++;
726 		kk += k;
727 		if(!tot){
728 			*p++ = xx & 0177;
729 			if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' ';
730 			*p++ = ' ';
731 			kvt(k,p);
732 			prstr(pmline);
733 		}
734 	}
735 	if(tot || (cnt > 1)){
736 		kvt(kk,pmline);
737 		prstr(pmline);
738 	}
739 }
740 char *kvt(k,p)
741 int k;
742 char *p;
743 {
744 	if(k>=100)*p++ = k/100 + '0';
745 	if(k>=10)*p++ = (k%100)/10 + '0';
746 	*p++ = k%10 + '0';
747 	*p++ = '\n';
748 	*p = 0;
749 	return(p);
750 }
751 dummy(){}
752