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