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
caseig()84 caseig(){
85 register i;
86
87 offset = 0;
88 if((i = copyb()) != '.')control(i,1);
89 }
casern()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 }
caserm()100 caserm(){
101 lgf++;
102 while(!skip()){
103 clrmn(findmn(getrq()));
104 }
105 }
caseas()106 caseas(){
107 app++;
108 caseds();
109 }
caseds()110 caseds(){
111 ds++;
112 casede();
113 }
caseam()114 caseam(){
115 app++;
116 casede();
117 }
casede()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 }
findmn(i)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 }
clrmn(i)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 }
finds(mn)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 }
skip()212 skip(){
213 register i;
214
215 while(((i=getch()) & CMASK) == ' ');
216 ch=i;
217 return(nlflg);
218 }
copyb()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 }
copys()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 }
alloc()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 }
ffree(i)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 }
boff(i)312 filep boff(i)
313 int i;
314 {
315 return(((filep)i)*BLK + NEV*EVS);
316 }
wbt(i)317 wbt(i)
318 int i;
319 {
320 wbf(i);
321 wbfl();
322 }
wbf(i)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 }
wbfl()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 }
blisti(i)359 blisti(i)
360 filep i;
361 {
362 return((i-NEV*EVS)/(BLK));
363 }
rbf()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 }
rbf0(p)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 }
incoff(p)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 }
popi()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
pushi(newip)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
setbrk(x)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
getsn()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
setstr()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
collect()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
seta()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 }
caseda()608 caseda(){
609 app++;
610 casedi();
611 }
casedi()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 }
casedt()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 }
casetl()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 }
casepc()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 }
casepm()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 }
kvt(k,p)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 }
dummy()758 dummy(){}
759