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