xref: /csrg-svn/old/roff/common_source/n3.c (revision 7067)
1 #ifndef lint
2 static char sccsid[] = "@(#)n3.c	4.1 06/07/82";
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 pushi(newip)
416 filep newip;
417 {
418 	register struct s *p;
419 	extern char *setbrk();
420 
421 	if((enda - sizeof(struct s)) < (char *)nxf)setbrk(DELTA);
422 	p = nxf;
423 	p->pframe = frame;
424 	p->pip = ip;
425 	p->pnchar = nchar;
426 	p->prchar = rchar;
427 	p->ppendt = pendt;
428 	p->pap = ap;
429 	p->pcp = cp;
430 	p->pch0 = ch0;
431 	p->pch = ch;
432 	cp = ap = 0;
433 	nchar = rchar = pendt = ch0 = ch = 0;
434 	frame = nxf;
435 	if(nxf->nargs == 0) nxf += 1;
436 		else nxf = (struct s *)argtop;
437 	return(ip = newip);
438 }
439 char *setbrk(x)
440 int x;
441 {
442 	register char *i;
443 	char *sbrk();
444 
445 	if((i = sbrk(x)) == MAXPTR){
446 		prstrfl("Core limit reached.\n");
447 		edone(0100);
448 	}else{
449 		enda = i + x;
450 	}
451 	return(i);
452 }
453 getsn(){
454 	register i;
455 
456 	if((i=getach()) == 0)return(0);
457 	if(i == '(')return(getrq());
458 		else return(i);
459 }
460 setstr(){
461 	register i;
462 
463 	lgf++;
464 	if(((i=getsn()) == 0) ||
465 	   ((i=findmn(i)) == -1) ||
466 	   !(contab[i].rq & MMASK)){
467 		lgf--;
468 		return(0);
469 	}else{
470 		if((enda-2) < (char *)nxf)setbrk(DELTA);
471 		nxf->nargs = 0;
472 		strflg++;
473 		lgf--;
474 		return(pushi(((filep)contab[i].x.mx)<<BLKBITS));
475 	}
476 }
477 collect()
478 {
479 	register i;
480 	register int *strp;
481 	int *lim;
482 	int **argpp, **argppend;
483 	int quote;
484 	struct s *savnxf;
485 
486 	copyf++;
487 	nxf->nargs = 0;
488 	savnxf = nxf;
489 	if(skip())goto rtn;
490 	lim = (int *)(nxf = savnxf + sizeof(struct s)/sizeof(savnxf));
491 	strflg = 0;
492 	if((argppend =
493 		(argpp = (int **)savnxf+(sizeof(struct s)/sizeof(int **))) + 9)
494 		> (int **)enda)setbrk(DELTA);
495 	strp = (int *)argppend;
496 	for(i=8; i>=0; i--)argpp[i] = 0;
497 	while((argpp != argppend) && (!skip())){
498 		*argpp++ = strp;
499 		quote = 0;
500 		if(((i = getch()) & CMASK) == '"')quote++;
501 			else ch = i;
502 		while(1){
503 			i = getch();
504 			if( nlflg ||
505 			  ((!quote) && ((i & CMASK) == ' ')))break;
506 			if(quote && ((i & CMASK) == '"') &&
507 			  (((i=getch()) & CMASK) != '"')){
508 				ch = i;
509 				break;
510 			}
511 			*strp++ = i;
512 			if(strflg && (strp >= lim)){
513 				prstrfl("Macro argument too long.\n");
514 				copyf--;
515 				edone(004);
516 			}
517 			if((enda-4) <= (char *)strp)setbrk(DELTA);
518 		}
519 		*strp++ = 0;
520 	}
521 	nxf = savnxf;
522 	nxf->nargs = argpp -(int **)(nxf + 1);
523 	argtop = strp;
524 rtn:
525 	copyf--;
526 }
527 seta()
528 {
529 	register i;
530 
531 	if(((i = (getch() & CMASK) - '0') > 0) &&
532 		(i <= 9) && (i <= frame->nargs))ap = *((int **)frame + i-1 + (sizeof(struct s)/sizeof(int **)));
533 }
534 caseda(){
535 	app++;
536 	casedi();
537 }
538 casedi(){
539 	register i, j;
540 	register *k;
541 
542 	lgf++;
543 	if(skip() || ((i=getrq()) == 0)){
544 		if(dip != d)wbt(0);
545 		if(dilev > 0){
546 			v.dn = dip->dnl;
547 			v.dl = dip->maxl;
548 			dip = &d[--dilev];
549 			offset = dip->op;
550 		}
551 		goto rtn;
552 	}
553 	if(++dilev == NDI){
554 		--dilev;
555 		prstr("Cannot divert.\n");
556 		edone(02);
557 	}
558 	if(dip != d)wbt(0);
559 	diflg++;
560 	dip = &d[dilev];
561 	dip->op = finds(i);
562 	dip->curd = i;
563 	clrmn(oldmn);
564 	k = (int *)&dip->dnl;
565 	for(j=0; j<10; j++)k[j] = 0;	/*not op and curd*/
566 rtn:
567 	app = 0;
568 	diflg = 0;
569 }
570 casedt(){
571 	lgf++;
572 	dip->dimac = dip->ditrap = dip->ditf = 0;
573 	skip();
574 	dip->ditrap = vnumb((int *)0);
575 	if(nonumb)return;
576 	skip();
577 	dip->dimac = getrq();
578 }
579 casetl(){
580 	register i, j;
581 	int w1, w2, w3, delim;
582 	filep begin;
583 	extern width(), pchar();
584 
585 	dip->nls = 0;
586 	skip();
587 	if(dip != d)wbfl();
588 	if((offset = begin = alloc()) == 0)return;
589 	if((delim = getch()) & MOT){
590 		ch = delim;
591 		delim = '\'';
592 	}else delim &= CMASK;
593 	if(!nlflg)
594 		while(((i = getch()) & CMASK) != '\n'){
595 			if((i & CMASK) == delim)i = IMP;
596 			wbf(i);
597 		}
598 	wbf(IMP);wbf(IMP);wbt(0);
599 
600 	w1 = hseg(width,begin);
601 	w2 = hseg(width,(filep)0);
602 	w3 = hseg(width,(filep)0);
603 	offset = dip->op;
604 #ifdef NROFF
605 	if(!offset)horiz(po);
606 #endif
607 	hseg(pchar,begin);
608 	if(w2 || w3)horiz(j=quant((lt - w2)/2-w1,HOR));
609 	hseg(pchar,(filep)0);
610 	if(w3){
611 		horiz(lt-w1-w2-w3-j);
612 		hseg(pchar,(filep)0);
613 	}
614 	newline(0);
615 	if(dip != d){if(dip->dnl > dip->hnl)dip->hnl = dip->dnl;}
616 	else{if(v.nl > dip->hnl)dip->hnl = v.nl;}
617 	ffree(begin);
618 }
619 casepc(){
620 	pagech = chget(IMP);
621 }
622 hseg(f,p)
623 int (*f)();
624 filep p;
625 {
626 	register acc, i;
627 	static filep q;
628 
629 	acc = 0;
630 	if(p)q = p;
631 	while(1){
632 		i = rbf0(q);
633 		q = incoff(q);
634 		if(!i || (i == IMP))return(acc);
635 		if((i & CMASK) == pagech){
636 			nrbits = i & ~CMASK;
637 			nform = fmt[findr('%')];
638 			acc += fnumb(v.pn,f);
639 		}else acc += (*f)(i);
640 	}
641 }
642 casepm(){
643 	register i, k;
644 	register char *p;
645 	int xx, cnt, kk, tot;
646 	filep j;
647 	char *kvt();
648 	char pmline[10];
649 
650 	kk = cnt = 0;
651 	tot = !skip();
652 	for(i = 0; i<NM; i++){
653 		if(!((xx = contab[i].rq) & MMASK))continue;
654 		p = pmline;
655 		j = (((filep)contab[i].x.mx)<<BLKBITS);
656 		k = 1;
657 		while((j = blist[blisti(j)]) != -1){k++; j <<= BLKBITS;}
658 		cnt++;
659 		kk += k;
660 		if(!tot){
661 			*p++ = xx & 0177;
662 			if(!(*p++ = (xx >> BYTE) & 0177))*(p-1) = ' ';
663 			*p++ = ' ';
664 			kvt(k,p);
665 			prstr(pmline);
666 		}
667 	}
668 	if(tot || (cnt > 1)){
669 		kvt(kk,pmline);
670 		prstr(pmline);
671 	}
672 }
673 char *kvt(k,p)
674 int k;
675 char *p;
676 {
677 	if(k>=100)*p++ = k/100 + '0';
678 	if(k>=10)*p++ = (k%100)/10 + '0';
679 	*p++ = k%10 + '0';
680 	*p++ = '\n';
681 	*p = 0;
682 	return(p);
683 }
684 dummy(){}
685