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