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