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
caseig()43 caseig()
44 {
45 register i;
46
47 offset = 0;
48 if ((i = copyb()) != '.')
49 control(i, 1);
50 }
51
52
casern()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
caserm()68 caserm()
69 {
70 lgf++;
71 while (!skip()) {
72 clrmn(findmn(getrq()));
73 }
74 }
75
76
caseas()77 caseas()
78 {
79 app++;
80 caseds();
81 }
82
83
caseds()84 caseds()
85 {
86 ds++;
87 casede();
88 }
89
90
caseam()91 caseam()
92 {
93 app++;
94 casede();
95 }
96
97
casede()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
findmn(i)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
clrmn(i)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
finds(mn)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
skip()214 skip()
215 {
216 tchar i;
217
218 while (cbits(i = getch()) == ' ')
219 ;
220 ch = i;
221 return(nlflg);
222 }
223
224
copyb()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
copys()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
alloc()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
ffree(i)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
wbt(i)335 wbt(i)
336 tchar i;
337 {
338 wbf(i);
339 wbfl();
340 }
341
342
wbf(i)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
wbfl()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
rbf()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
rbf0(p)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
incoff(p)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
popi()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
pushi(newip)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
setbrk(x)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
getsn()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
setstr()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
collect()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
seta()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
caseda()676 caseda()
677 {
678 app++;
679 casedi();
680 }
681
682
casedi()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
casedt()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
casetl()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
casepc()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
casepm()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
dummy()858 dummy()
859 {
860 }
861