1 #ifndef lint
2 /*
3 static char sccsid[] = "@(#)n3.c	2.3 (CWI) 86/11/27";
4 */
5 static char sccsid[] = "@(#)n3.c	2.4 (Berkeley) 07/27/93";
6 #endif lint
7 /*      @(#)n3.c	1.1     */
8 /*
9  * troff3.c
10  *
11  * macro and string routines, storage allocation
12  */
13 
14 
15 #include "tdef.h"
16 #ifdef NROFF
17 #include "tw.h"
18 #endif
19 #include <sgtty.h>
20 #include "ext.h"
21 
22 #define	MHASH(x)	((x>>6)^x)&0177
23 struct	contab *mhash[128];	/* 128 == the 0177 on line above */
24 #define	blisti(i)	(((i)-NEV*(int)sizeof(env))/BLK)
25 filep	blist[NBLIST];
26 tchar	*argtop;
27 int	pagech = '%';
28 int	strflg;
29 
30 	tchar *wbuf;
31 	tchar corebuf[NEV*sizeof(env)/sizeof(tchar) + NBLIST*BLK+ 1];
32 
caseig()33 caseig()
34 {
35 	register i;
36 
37 	offset = 0;
38 	if ((i = copyb()) != '.')
39 		control(i, 1);
40 }
41 
42 
casern()43 casern()
44 {
45 	register i, j;
46 
47 	lgf++;
48 	skip();
49 	if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
50 		return;
51 	skip();
52 	clrmn(findmn(j = getrq()));
53 	if (j) {
54 		munhash(&contab[oldmn]);
55 		contab[oldmn].rq = j;
56 		maddhash(&contab[oldmn]);
57 	}
58 }
59 
maddhash(rp)60 maddhash(rp)
61 register struct contab *rp;
62 {
63 	register struct contab **hp;
64 
65 	if (rp->rq == 0)
66 		return;
67 	hp = &mhash[MHASH(rp->rq)];
68 	rp->link = *hp;
69 	*hp = rp;
70 }
71 
munhash(mp)72 munhash(mp)
73 register struct contab *mp;
74 {
75 	register struct contab *p;
76 	register struct contab **lp;
77 
78 	if (mp->rq == 0)
79 		return;
80 	lp = &mhash[MHASH(mp->rq)];
81 	p = *lp;
82 	while (p) {
83 		if (p == mp) {
84 			*lp = p->link;
85 			p->link = 0;
86 			return;
87 		}
88 		lp = &p->link;
89 		p = p->link;
90 	}
91 }
92 
mrehash()93 mrehash()
94 {
95 	register struct contab *p;
96 	register i;
97 
98 	for (i=0; i<128; i++)
99 		mhash[i] = 0;
100 	for (p=contab; p < &contab[NM]; p++)
101 		p->link = 0;
102 	for (p=contab; p < &contab[NM]; p++) {
103 		if (p->rq == 0)
104 			continue;
105 		i = MHASH(p->rq);
106 		p->link = mhash[i];
107 		mhash[i] = p;
108 	}
109 }
110 
caserm()111 caserm()
112 {
113 	int j;
114 
115 	lgf++;
116 	while (!skip() && (j = getrq()) != 0)
117 		clrmn(findmn(j));
118 	lgf--;
119 }
120 
121 
caseas()122 caseas()
123 {
124 	app++;
125 	caseds();
126 }
127 
128 
caseds()129 caseds()
130 {
131 	ds++;
132 	casede();
133 }
134 
135 
caseam()136 caseam()
137 {
138 	app++;
139 	casede();
140 }
141 
142 
casede()143 casede()
144 {
145 	register i, req;
146 	register filep savoff;
147 	extern filep finds();
148 
149 	if (dip != d)
150 		wbfl();
151 	req = '.';
152 	lgf++;
153 	skip();
154 	if ((i = getrq()) == 0)
155 		goto de1;
156 	if ((offset = finds(i)) == 0)
157 		goto de1;
158 	if (ds)
159 		copys();
160 	else
161 		req = copyb();
162 	wbfl();
163 	clrmn(oldmn);
164 	if (newmn) {
165 		if (contab[newmn].rq)
166 			munhash(&contab[newmn]);
167 		contab[newmn].rq = i;
168 		maddhash(&contab[newmn]);
169 	}
170 	if (apptr) {
171 		savoff = offset;
172 		offset = apptr;
173 		wbt((tchar) IMP);
174 		offset = savoff;
175 	}
176 	offset = dip->op;
177 	if (req != '.')
178 		control(req, 1);
179 de1:
180 	ds = app = 0;
181 	return;
182 }
183 
184 
findmn(i)185 findmn(i)
186 register int	i;
187 {
188 	register struct contab *p;
189 
190 	for (p = mhash[MHASH(i)]; p; p = p->link)
191 		if (i == p->rq)
192 			return(p - contab);
193 	return(-1);
194 }
195 
196 
clrmn(i)197 clrmn(i)
198 register int	i;
199 {
200 	if (i >= 0) {
201 		if (contab[i].mx)
202 			ffree((filep)contab[i].mx);
203 		munhash(&contab[i]);
204 		contab[i].rq = 0;
205 		contab[i].mx = 0;
206 		contab[i].f = 0;
207 	}
208 }
209 
210 
finds(mn)211 filep finds(mn)
212 register int	mn;
213 {
214 	register i;
215 	register filep savip;
216 	extern filep alloc();
217 	extern filep incoff();
218 
219 	oldmn = findmn(mn);
220 	newmn = 0;
221 	apptr = (filep)0;
222 	if (app && oldmn >= 0 && contab[oldmn].mx) {
223 		savip = ip;
224 		ip = (filep)contab[oldmn].mx;
225 		oldmn = -1;
226 		while ((i = rbf()) != 0)
227 			;
228 		apptr = ip;
229 		if (!diflg)
230 			ip = incoff(ip);
231 		nextb = ip;
232 		ip = savip;
233 	} else {
234 		for (i = 0; i < NM; i++) {
235 			if (contab[i].rq == 0)
236 				break;
237 		}
238 		if (i == NM || (nextb = alloc()) == 0) {
239 			app = 0;
240 			if (macerr++ > 1)
241 				done2(02);
242 			errprint("Too many (%d) string/macro names", NM);
243 			edone(04);
244 			return(offset = 0);
245 		}
246 		contab[i].mx = (unsigned) nextb;
247 		if (!diflg) {
248 			newmn = i;
249 			if (oldmn == -1)
250 				contab[i].rq = -1;
251 		} else {
252 			contab[i].rq = mn;
253 			maddhash(&contab[i]);
254 		}
255 	}
256 	app = 0;
257 	return(offset = nextb);
258 }
259 
260 
skip()261 skip()
262 {
263 	register tchar i;
264 
265 	while (cbits(i = getch()) == ' ')
266 		;
267 	ch = i;
268 	return(nlflg);
269 }
270 
271 
copyb()272 copyb()
273 {
274 	register i, j, state;
275 	register tchar ii;
276 	int	req, k;
277 	filep savoff;
278 
279 	if (skip() || !(j = getrq()))
280 		j = '.';
281 	req = j;
282 	k = j >> BYTE;
283 	j &= BYTEMASK;
284 	copyf++;
285 	flushi();
286 	nlflg = 0;
287 	state = 1;
288 	while (1) {
289 		i = cbits(ii = getch());
290 		if (state == 3) {
291 			if (i == k)
292 				break;
293 			if (!k) {
294 				ch = ii;
295 				i = getach();
296 				ch = ii;
297 				if (!i)
298 					break;
299 			}
300 			state = 0;
301 			goto c0;
302 		}
303 		if (i == '\n') {
304 			state = 1;
305 			nlflg = 0;
306 			goto c0;
307 		}
308 		if (state == 1 && i == '.') {
309 			state++;
310 			savoff = offset;
311 			goto c0;
312 		}
313 		if ((state == 2) && (i == j)) {
314 			state++;
315 			goto c0;
316 		}
317 		state = 0;
318 c0:
319 		if (offset)
320 			wbf(ii);
321 	}
322 	if (offset) {
323 		wbfl();
324 		offset = savoff;
325 		wbt((tchar)0);
326 	}
327 	copyf--;
328 	return(req);
329 }
330 
331 
copys()332 copys()
333 {
334 	register tchar i;
335 
336 	copyf++;
337 	if (skip())
338 		goto c0;
339 	if (cbits(i = getch()) != '"')
340 		wbf(i);
341 	while (cbits(i = getch()) != '\n')
342 		wbf(i);
343 c0:
344 	wbt((tchar)0);
345 	copyf--;
346 }
347 
348 
alloc()349 filep alloc()
350 {
351 	register i;
352 	register filep j;
353 
354 	for (i = 0; i < NBLIST; i++) {
355 		if (blist[i] == 0)
356 			break;
357 	}
358 	if (i == NBLIST) {
359 		j = 0;
360 	} else {
361 		blist[i] = -1;
362 		if ((j = ((filep)i * BLK + NEV*(int)sizeof(env))) < NEV*(int)sizeof(env))
363 			j = 0;
364 	}
365 	return(nextb = j);
366 }
367 
368 
ffree(i)369 ffree(i)
370 filep i;
371 {
372 	register j;
373 
374 	while (blist[j = blisti(i)] != (unsigned) ~0) {
375 		i = (filep) blist[j];
376 		blist[j] = 0;
377 	}
378 	blist[j] = 0;
379 }
380 
wbt(i)381 wbt(i)
382 tchar i;
383 {
384 	wbf(i);
385 	wbfl();
386 }
387 
388 
wbf(i)389 wbf(i)
390 register tchar i;
391 {
392 	register j;
393 
394 	if (!offset)
395 		return;
396 	if (!woff) {
397 		woff = offset;
398 		wbuf = &corebuf[woff];	/* INCORE only */
399 		wbfi = 0;
400 	}
401 	wbuf[wbfi++] = i;
402 	if (!((++offset) & (BLK - 1))) {
403 		wbfl();
404 		j = blisti(--offset);
405 		if (j < 0 || j >= NBLIST) {
406 			errprint("Out of temp file space");
407 			done2(01);
408 		}
409 		if (blist[j] == (unsigned) ~0) {
410 			if (alloc() == 0) {
411 				errprint("Out of temp file space");
412 				done2(01);
413 			}
414 			blist[j] = (unsigned)(nextb);
415 		}
416 		offset = ((filep)blist[j]);
417 	}
418 	if (wbfi >= BLK)
419 		wbfl();
420 }
421 
422 
wbfl()423 wbfl()
424 {
425 	if (woff == 0)
426 		return;
427 	if ((woff & (~(BLK - 1))) == (roff & (~(BLK - 1))))
428 		roff = -1;
429 	woff = 0;
430 }
431 
432 
rbf()433 tchar rbf()
434 {
435 	register tchar i;
436 	register filep j, p;
437 	extern filep incoff();
438 
439 	if (ip == NBLIST*BLK) {		/* for rdtty */
440 		if (j = rdtty())
441 			return(j);
442 		else
443 			return(popi());
444 	}
445 	/* this is an inline expansion of rbf0: dirty! */
446 	i = corebuf[ip];
447 	/* end of rbf0 */
448 	if (i == 0) {
449 		if (!app)
450 			i = popi();
451 		return(i);
452 	}
453 	/* this is an inline expansion of incoff: also dirty */
454 	p = ++ip;
455 	if ((p & (BLK - 1)) == 0) {
456 		if ((ip = blist[blisti(p-1)]) == (unsigned) ~0) {
457 			ip = 0;
458 			errprint("Bad storage allocation");
459 			done2(-5);
460 		}
461 		/* this was meant to protect against people removing
462 		/* the macro they were standing on, but it's too
463 		/* sensitive to block boundaries.
464 		/* if (ip == 0) {
465 		/*	errprint("Block removed while in use");
466 		/*	done2(-6);
467 		/* }
468 		*/
469 	}
470 	return(i);
471 }
472 
473 
rbf0(p)474 tchar rbf0(p)
475 register filep p;
476 {
477 	return(corebuf[p]);
478 }
479 
480 
incoff(p)481 filep incoff(p)
482 register filep p;
483 {
484 	p++;
485 	if ((p & (BLK - 1)) == 0) {
486 		if ((p = blist[blisti(p-1)]) == (unsigned) ~0) {
487 			errprint("Bad storage allocation");
488 			done2(-5);
489 		}
490 	}
491 	return(p);
492 }
493 
494 
popi()495 tchar popi()
496 {
497 	register struct s *p;
498 
499 	if (frame == stk)
500 		return(0);
501 	if (strflg)
502 		strflg--;
503 	p = nxf = frame;
504 	p->nargs = 0;
505 	frame = p->pframe;
506 	ip = p->pip;
507 	pendt = p->ppendt;
508 	lastpbp = p->lastpbp;
509 	return(p->pch);
510 }
511 
512 /*
513  *	test that the end of the allocation is above a certain location
514  *	in memory
515  */
516 #ifdef notdef
517 #define SPACETEST(base, size) while ((enda - (size)) <= (char *)(base)){setbrk(DELTA);}
518 #else
519 #define SPACETEST(base, size)
520 #endif
521 
pushi(newip,mname)522 pushi(newip, mname)
523 filep newip;
524 int mname;
525 {
526 	register struct s *p;
527 
528 	SPACETEST(nxf, sizeof(struct s));
529 	p = nxf;
530 	p->pframe = frame;
531 	p->pip = ip;
532 	p->ppendt = pendt;
533 	p->pch = ch;
534 	p->lastpbp = lastpbp;
535 	p->mname = mname;
536 	lastpbp = pbp;
537 	pendt = ch = 0;
538 	frame = nxf;
539 	if (nxf->nargs == 0)
540 		nxf += 1;
541 	else
542 		nxf = (struct s *)argtop;
543 	return(ip = newip);
544 }
545 
getsn()546 getsn()
547 {
548 	register i;
549 
550 	if ((i = getach()) == 0)
551 		return(0);
552 	if (i == '(')
553 		return(getrq());
554 	else
555 		return(i);
556 }
557 
558 
setstr()559 setstr()
560 {
561 	register i, j;
562 
563 	lgf++;
564 	if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contab[j].mx) {
565 		lgf--;
566 		return(0);
567 	} else {
568 		SPACETEST(nxf, sizeof(struct s));
569 		nxf->nargs = 0;
570 		strflg++;
571 		lgf--;
572 		return pushi((filep)contab[j].mx, i);
573 	}
574 }
575 
576 
577 
collect()578 collect()
579 {
580 	register j;
581 	register tchar i;
582 	register tchar *strp;
583 	tchar * lim;
584 	tchar * *argpp, **argppend;
585 	int	quote;
586 	struct s *savnxf;
587 
588 	copyf++;
589 	nxf->nargs = 0;
590 	savnxf = nxf;
591 	if (skip())
592 		goto rtn;
593 
594 	{
595 		char *memp;
596 		memp = (char *)savnxf;
597 		/*
598 		 *	1 s structure for the macro descriptor
599 		 *	APERMAC tchar *'s for pointers into the strings
600 		 *	space for the tchar's themselves
601 		 */
602 		memp += sizeof(struct s);
603 		/*
604 		 *	CPERMAC (the total # of characters for ALL arguments)
605 		 *	to a macros, has been carefully chosen
606 		 *	so that the distance between stack frames is < DELTA
607 		 */
608 #define	CPERMAC	200
609 #define	APERMAC	9
610 		memp += APERMAC * sizeof(tchar *);
611 		memp += CPERMAC * sizeof(tchar);
612 		nxf = (struct s*)memp;
613 	}
614 	lim = (tchar *)nxf;
615 	argpp = (tchar **)(savnxf + 1);
616 	argppend = &argpp[APERMAC];
617 	SPACETEST(argppend, sizeof(tchar *));
618 	strp = (tchar *)argppend;
619 	/*
620 	 *	Zero out all the string pointers before filling them in.
621 	 */
622 	for (j = 0; j < APERMAC; j++){
623 		argpp[j] = (tchar *)0;
624 	}
625 #if 0
626 	errprint("savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x,lim=0x%x,enda=0x%x",
627 		savnxf, nxf, argpp, strp, lim, enda);
628 #endif 0
629 	strflg = 0;
630 	while ((argpp != argppend) && (!skip())) {
631 		*argpp++ = strp;
632 		quote = 0;
633 		if (cbits(i = getch()) == '"')
634 			quote++;
635 		else
636 			ch = i;
637 		while (1) {
638 			i = getch();
639 			if (nlflg || (!quote && cbits(i) == ' '))
640 				break;
641 			if (   quote
642 			    && (cbits(i) == '"')
643 			    && (cbits(i = getch()) != '"')) {
644 				ch = i;
645 				break;
646 			}
647 			*strp++ = i;
648 			if (strflg && strp >= lim) {
649 				errprint("Macro argument too long");
650 				copyf--;
651 				edone(004);
652 			}
653 			SPACETEST(strp, 3 * sizeof(tchar));
654 		}
655 		*strp++ = 0;
656 	}
657 	nxf = savnxf;
658 	nxf->nargs = argpp - (tchar **)(savnxf + 1);
659 	argtop = strp;
660 rtn:
661 	copyf--;
662 }
663 
664 
seta()665 seta()
666 {
667 	register i;
668 
669 	i = cbits(getch()) - '0';
670 	if (i > 0 && i <= APERMAC && i <= frame->nargs)
671 		pushback(*(((tchar **)(frame + 1)) + i - 1));
672 }
673 
674 
caseda()675 caseda()
676 {
677 	app++;
678 	casedi();
679 }
680 
681 
casedi()682 casedi()
683 {
684 	register i, j;
685 	register *k;
686 
687 	lgf++;
688 	if (skip() || (i = getrq()) == 0) {
689 		if (dip != d)
690 			wbt((tchar)0);
691 		if (dilev > 0) {
692 			numtab[DN].val = dip->dnl;
693 			numtab[DL].val = dip->maxl;
694 			dip = &d[--dilev];
695 			offset = dip->op;
696 		}
697 		goto rtn;
698 	}
699 	if (++dilev == NDI) {
700 		--dilev;
701 		errprint("Diversions nested too deep");
702 		edone(02);
703 	}
704 	if (dip != d)
705 		wbt((tchar)0);
706 	diflg++;
707 	dip = &d[dilev];
708 	dip->op = finds(i);
709 	dip->curd = i;
710 	clrmn(oldmn);
711 	k = (int *) & dip->dnl;
712 	for (j = 0; j < 10; j++)
713 		k[j] = 0;	/*not op and curd*/
714 rtn:
715 	app = 0;
716 	diflg = 0;
717 }
718 
719 
casedt()720 casedt()
721 {
722 	lgf++;
723 	dip->dimac = dip->ditrap = dip->ditf = 0;
724 	skip();
725 	dip->ditrap = vnumb((int *)0);
726 	if (nonumb)
727 		return;
728 	skip();
729 	dip->dimac = getrq();
730 }
731 
732 
casetl()733 casetl()
734 {
735 	register j;
736 	int w[3];
737 	tchar buf[LNSIZE];
738 	register tchar *tp;
739 	tchar i, delim;
740 
741 	/*
742 	 * bug fix
743 	 *
744 	 * if .tl is the first thing in the file, the p1
745 	 * doesn't come out, also the pagenumber will be 0
746 	 *
747 	 * tends too confuse the device filter (and the user as well)
748 	 */
749 	if( dip == d && numtab[NL].val == -1)
750 		newline(1);
751 
752 	/* end fix */
753 	dip->nls = 0;
754 	skip();
755 	if (ismot(delim = getch())) {
756 		ch = delim;
757 		delim = '\'';
758 	} else
759 		delim = cbits(delim);
760 	tp = buf;
761 	numtab[HP].val = 0;
762 	w[0] = w[1] = w[2] = 0;
763 	j = 0;
764 	while (cbits(i = getch()) != '\n') {
765 		if (cbits(i) == cbits(delim)) {
766 			if (j < 3)
767 				w[j] = numtab[HP].val;
768 			numtab[HP].val = 0;
769 			j++;
770 			*tp++ = 0;
771 		} else {
772 			if (cbits(i) == pagech) {
773 				setn1(numtab[PN].val, numtab[findr('%')].fmt,
774 				      i&SFMASK);
775 				continue;
776 			}
777 			numtab[HP].val += width(i);
778 			if (tp < &buf[LNSIZE-10])
779 				*tp++ = i;
780 		}
781 	}
782 	if (j<3)
783 		w[j] = numtab[HP].val;
784 	*tp++ = 0;
785 	*tp++ = 0;
786 	*tp++ = 0;
787 	tp = buf;
788 #ifdef NROFF
789 	horiz(po);
790 #endif
791 	while (i = *tp++)
792 		pchar(i);
793 	if (w[1] || w[2])
794 		horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
795 	while (i = *tp++)
796 		pchar(i);
797 	if (w[2]) {
798 		horiz(lt - w[0] - w[1] - w[2] - j);
799 		while (i = *tp++)
800 			pchar(i);
801 	}
802 	newline(0);
803 	if (dip != d) {
804 		if (dip->dnl > dip->hnl)
805 			dip->hnl = dip->dnl;
806 	} else {
807 		if (numtab[NL].val > dip->hnl)
808 			dip->hnl = numtab[NL].val;
809 	}
810 }
811 
812 
casepc()813 casepc()
814 {
815 	pagech = chget(IMP);
816 }
817 
818 
casepm()819 casepm()
820 {
821 	register i, k;
822 	register char	*p;
823 	int	xx, cnt, tcnt, kk, tot;
824 	filep j;
825 	char	pmline[10];
826 
827 	kk = cnt = tcnt = 0;
828 	tot = !skip();
829 	for (i = 0; i < NM; i++) {
830 		if ((xx = contab[i].rq) == 0 || contab[i].mx == 0)
831 			continue;
832 		tcnt++;
833 		p = pmline;
834 		j = (filep) contab[i].mx;
835 		k = 1;
836 		while ((j = blist[blisti(j)]) != (unsigned) ~0) {
837 			k++;
838 		}
839 		cnt++;
840 		kk += k;
841 		if (!tot) {
842 			*p++ = xx & 0177;
843 			if (!(*p++ = (xx >> BYTE) & 0177))
844 				*(p - 1) = ' ';
845 			*p++ = 0;
846 			fdprintf(stderr, "%s %d\n", pmline, k);
847 		}
848 	}
849 	fdprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
850 }
851 
stackdump()852 stackdump()	/* dumps stack of macros in process */
853 {
854 	struct s *p;
855 
856 	if (p != stk) {
857 		for (p = frame; p != stk; p = p->pframe)
858 			fdprintf(stderr, "%c%c ", p->mname&0177, (p->mname>>BYTE)&0177);
859 		fdprintf(stderr, "\n");
860 	}
861 }
862