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