mkdev: remove devutf/C*
[troff.git] / troff / n3.c
blob20c556c4c87078b1e3d5f004adcecbb2ef3a35ec
1 /*
2 * troff3.c
3 *
4 * macro and string routines, storage allocation
5 */
7 #include "tdef.h"
8 #include "fns.h"
9 #include "ext.h"
11 Tchar *argtop;
12 int pagech = '%';
13 int strflg;
15 #define MHASHSIZE 128 /* must be 2**n */
16 #define MHASH(x) ((x>>6)^x) & (MHASHSIZE-1)
17 Contab *mhash[MHASHSIZE];
20 Blockp *blist; /* allocated blocks for macros and strings */
21 int nblist; /* how many there are */
22 int bfree = -1; /* first (possible) free block in the list */
24 Contab *contabp = NULL;
25 #define MDELTA 500
26 int nm = 0;
28 int savname; /* name of macro/string being defined */
29 int savslot; /* place in Contab of savname */
30 int freeslot = -1; /* first (possible) free slot in contab */
32 void prcontab(Contab *p)
34 int i;
35 for (i = 0; i < nm; i++)
36 if (p)
37 if (p[i].rq != 0)
38 fprintf(stderr, "slot %d, %-2.2s\n", i, unpair(p[i].rq));
39 else
40 fprintf(stderr, "slot %d empty\n", i);
41 else
42 fprintf(stderr, "slot %d empty\n", i);
46 void blockinit(void)
48 blist = (Blockp *) calloc(NBLIST, sizeof(Blockp));
49 if (blist == NULL) {
50 ERROR "not enough room for %d blocks", NBLIST WARN;
51 done2(1);
53 nblist = NBLIST;
54 blist[0].nextoff = blist[1].nextoff = -1;
55 blist[0].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
56 blist[1].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
57 /* -1 prevents blist[0] from being used; temporary fix */
58 /* for a design botch: offset==0 is overloaded. */
59 /* blist[1] reserved for .rd indicator -- also unused. */
60 /* but someone unwittingly looks at these, so allocate something */
61 bfree = 2;
65 char *grow(char *ptr, int num, int size) /* make array bigger */
67 if (ptr == NULL)
68 return calloc(num, size);
69 else
70 return realloc(ptr, num * size);
73 void mnspace(void)
75 nm = sizeof(contab)/sizeof(Contab) + MDELTA;
76 freeslot = sizeof(contab)/sizeof(Contab) + 1;
77 contabp = (Contab *) grow((char *) contabp, nm, sizeof(Contab));
78 if (contabp == NULL) {
79 ERROR "not enough memory for namespace of %d marcos", nm WARN;
80 exit(1);
82 contabp = (Contab *) memcpy((char *) contabp, (char *)contab,
83 sizeof(contab));
84 if (contabp == NULL) {
85 ERROR "Cannot reinitialize macro/request name list" WARN;
86 exit(1);
91 void caseig(void)
93 int i;
94 Offset oldoff = offset;
96 offset = 0;
97 i = copyb();
98 offset = oldoff;
99 if (i != '.')
100 control(i, 1);
104 void casern(void)
106 int i, j, k;
108 lgf++;
109 skip();
110 if ((i = getrq()) == 0 || (oldmn = findmn(i)) < 0)
111 return;
112 skip();
113 clrmn(findmn(j = getrq()));
114 if (j) {
115 munhash(&contabp[oldmn]);
116 contabp[oldmn].rq = j;
117 maddhash(&contabp[oldmn]);
118 if (dip != d )
119 for (k = dilev; k; k--)
120 if (d[k].curd == i)
121 d[k].curd = j;
125 void maddhash(Contab *rp)
127 Contab **hp;
129 if (rp->rq == 0)
130 return;
131 hp = &mhash[MHASH(rp->rq)];
132 rp->link = *hp;
133 *hp = rp;
136 void munhash(Contab *mp)
138 Contab *p;
139 Contab **lp;
141 if (mp->rq == 0)
142 return;
143 lp = &mhash[MHASH(mp->rq)];
144 p = *lp;
145 while (p) {
146 if (p == mp) {
147 *lp = p->link;
148 p->link = 0;
149 return;
151 lp = &p->link;
152 p = p->link;
156 void mrehash(void)
158 Contab *p;
159 int i;
161 for (i=0; i < MHASHSIZE; i++)
162 mhash[i] = 0;
163 for (p=contabp; p < &contabp[nm]; p++)
164 p->link = 0;
165 for (p=contabp; p < &contabp[nm]; p++) {
166 if (p->rq == 0)
167 continue;
168 i = MHASH(p->rq);
169 p->link = mhash[i];
170 mhash[i] = p;
174 void caserm(void)
176 int j;
177 int k = 0;
179 lgf++;
181 while (!skip() && (j = getrq()) != 0) {
182 if (dip != d)
183 for (k = dilev; k; k--)
184 if (d[k].curd == j) {
185 ERROR "cannot remove diversion %s during definition",
186 unpair(j) WARN;
187 goto g0;
189 clrmn(findmn(j));
191 lgf--;
195 void caseas(void)
197 app++;
198 caseds();
202 void caseds(void)
204 ds++;
205 casede();
209 void caseam(void)
211 app++;
212 casede();
216 void casede(void)
218 int i, req;
219 Offset savoff;
221 req = '.';
222 lgf++;
223 skip();
224 if ((i = getrq()) == 0)
225 goto de1;
226 if ((offset = finds(i)) == 0)
227 goto de1;
228 if (newmn)
229 savslot = newmn;
230 else
231 savslot = findmn(i);
232 savname = i;
233 if (ds)
234 copys();
235 else
236 req = copyb();
237 clrmn(oldmn);
238 if (newmn) {
239 if (contabp[newmn].rq)
240 munhash(&contabp[newmn]);
241 contabp[newmn].rq = i;
242 maddhash(&contabp[newmn]);
245 if (apptr) {
246 savoff = offset;
247 offset = apptr;
248 wbf((Tchar) IMP);
249 offset = savoff;
251 offset = dip->op;
252 if (req != '.')
253 control(req, 1);
254 de1:
255 ds = app = 0;
259 int findmn(int i)
261 Contab *p;
263 for (p = mhash[MHASH(i)]; p; p = p->link)
264 if (i == p->rq)
265 return(p - contabp);
266 return(-1);
270 void clrmn(int i)
272 if (i >= 0) {
273 if (contabp[i].mx)
274 ffree(contabp[i].mx);
275 munhash(&contabp[i]);
276 contabp[i].rq = 0;
277 contabp[i].mx = 0;
278 contabp[i].emx = 0;
279 contabp[i].f = 0;
280 if (contabp[i].divsiz != NULL) {
281 free(contabp[i].divsiz);
282 contabp[i].divsiz = NULL;
284 if (freeslot > i)
285 freeslot = i;
289 void growcontab(void)
291 nm += MDELTA;
292 contabp = (Contab *) grow((char *) contabp , nm, sizeof(Contab));
293 if (contabp == NULL) {
294 ERROR "Too many (%d) string/macro names", nm WARN;
295 done2(02);
296 } else {
297 memset((char *)(contabp) + (nm - MDELTA) * sizeof(Contab),
298 0, MDELTA * sizeof(Contab));
299 mrehash();
304 Offset finds(int mn)
306 int i;
307 Offset savip;
309 oldmn = findmn(mn);
310 newmn = 0;
311 apptr = 0;
312 if (app && oldmn >= 0 && contabp[oldmn].mx) {
313 savip = ip;
314 ip = contabp[oldmn].emx;
315 oldmn = -1;
316 apptr = ip;
317 if (!diflg)
318 ip = incoff(ip);
319 nextb = ip;
320 ip = savip;
321 } else {
322 for (i = freeslot; i < nm; i++) {
323 if (contabp[i].rq == 0)
324 break;
326 if (i == nm)
327 growcontab();
328 freeslot = i + 1;
329 if ((nextb = alloc()) == -1) {
330 app = 0;
331 if (macerr++ > 1)
332 done2(02);
333 if (nextb == 0)
334 ERROR "Not enough space for string/macro names" WARN;
335 edone(04);
336 return(offset = 0);
338 contabp[i].mx = nextb;
339 if (!diflg) {
340 newmn = i;
341 if (oldmn == -1)
342 contabp[i].rq = -1;
343 } else {
344 contabp[i].rq = mn;
345 maddhash(&contabp[i]);
348 app = 0;
349 return(offset = nextb);
352 int skip(void)
354 Tchar i;
356 while (cbits(i = getch()) == ' ' || ismot(i))
358 ch = i;
359 return nlflg;
363 int copyb(void)
365 int i, j, state;
366 Tchar ii;
367 int req, k;
368 Offset savoff;
369 Uchar *p;
371 if (skip() || !(j = getrq()))
372 j = '.';
373 req = j;
374 p = unpair(j);
375 /* was: k = j >> BYTE; j &= BYTEMASK; */
376 j = p[0];
377 k = p[1];
378 copyf++;
379 flushi();
380 nlflg = 0;
381 state = 1;
383 /* state 0 eat up
384 * state 1 look for .
385 * state 2 look for first char of end macro
386 * state 3 look for second char of end macro
389 while (1) {
390 i = cbits(ii = getch());
391 if (state == 3) {
392 if (i == k)
393 break;
394 if (!k) {
395 ch = ii;
396 i = getach();
397 ch = ii;
398 if (!i)
399 break;
401 state = 0;
402 goto c0;
404 if (i == '\n') {
405 state = 1;
406 nlflg = 0;
407 goto c0;
409 if (state == 1 && i == '.') {
410 state++;
411 savoff = offset;
412 goto c0;
414 if (state == 2 && i == j) {
415 state++;
416 goto c0;
418 state = 0;
420 if (offset)
421 wbf(ii);
423 if (offset) {
424 offset = savoff;
425 wbf((Tchar)0);
427 copyf--;
428 return(req);
432 void copys(void)
434 Tchar i;
436 copyf++;
437 if (skip())
438 goto c0;
439 if (cbits(i = getch()) != '"')
440 wbf(i);
441 while (cbits(i = getch()) != '\n')
442 wbf(i);
444 wbf((Tchar)0);
445 copyf--;
449 Offset alloc(void) /* return free Offset in nextb */
451 int i, j;
453 for (i = bfree; i < nblist; i++)
454 if (blist[i].nextoff == 0)
455 break;
456 if (i == nblist) {
457 blist = (Blockp *) realloc((char *) blist, 2 * nblist * sizeof(Blockp));
458 if (blist == NULL) {
459 ERROR "can't grow blist for string/macro defns" WARN;
460 done2(2);
462 nblist *= 2;
463 for (j = i; j < nblist; j++) {
464 blist[j].nextoff = 0;
465 blist[j].bp = 0;
468 blist[i].nextoff = -1; /* this block is the end */
469 bfree = i + 1;
470 if (blist[i].bp == 0)
471 blist[i].bp = (Tchar *) calloc(BLK, sizeof(Tchar));
472 if (blist[i].bp == NULL) {
473 ERROR "can't allocate memory for string/macro definitions" WARN;
474 done2(2);
476 nextb = (Offset) i * BLK;
477 return nextb;
481 void ffree(Offset i) /* free list of blocks starting at blist(o) */
482 { /* (doesn't actually free the blocks, just the pointers) */
483 int j;
485 for ( ; blist[j = bindex(i)].nextoff != -1; ) {
486 if (bfree > j)
487 bfree = j;
488 i = blist[j].nextoff;
489 blist[j].nextoff = 0;
491 blist[j].nextoff = 0;
495 void wbf(Tchar i) /* store i into offset, get ready for next one */
497 int j, off;
499 if (!offset)
500 return;
501 j = bindex(offset);
502 if (i == 0)
503 contabp[savslot].emx = offset;
504 off = boffset(offset);
505 blist[j].bp[off++] = i;
506 offset++;
507 if (pastend(offset)) { /* off the end of this block */
508 if (blist[j].nextoff == -1) {
509 if ((nextb = alloc()) == -1) {
510 ERROR "Out of temp file space" WARN;
511 done2(01);
513 blist[j].nextoff = nextb;
515 offset = blist[j].nextoff;
520 Tchar rbf(void) /* return next char from blist[] block */
522 Tchar i, j;
524 if (ip == RD_OFFSET) { /* for rdtty */
525 if (j = rdtty())
526 return(j);
527 else
528 return(popi());
531 i = rbf0(ip);
532 if (i == 0) {
533 if (!app)
534 i = popi();
535 return(i);
537 ip = incoff(ip);
538 return(i);
542 Offset xxxincoff(Offset p) /* get next blist[] block */
544 p++;
545 if (pastend(p)) { /* off the end of this block */
546 if ((p = blist[bindex(p-1)].nextoff) == -1) { /* and nothing was allocated after it */
547 ERROR "Bad storage allocation" WARN;
548 done2(-5);
551 return(p);
555 Tchar popi(void)
557 Stack *p;
559 if (frame == stk)
560 return(0);
561 if (strflg)
562 strflg--;
563 p = nxf = frame;
564 p->nargs = 0;
565 frame = p->pframe;
566 ip = p->pip;
567 pendt = p->ppendt;
568 lastpbp = p->lastpbp;
569 return(p->pch);
573 * test that the end of the allocation is above a certain location
574 * in memory
576 #define SPACETEST(base, size) \
577 if ((char*)base + size >= (char*)stk+STACKSIZE) \
578 ERROR "Stacksize overflow in n3" WARN
580 Offset pushi(Offset newip, int mname)
582 Stack *p;
584 SPACETEST(nxf, sizeof(Stack));
585 p = nxf;
586 p->pframe = frame;
587 p->pip = ip;
588 p->ppendt = pendt;
589 p->pch = ch;
590 p->lastpbp = lastpbp;
591 p->mname = mname;
592 lastpbp = pbp;
593 pendt = ch = 0;
594 frame = nxf;
595 if (nxf->nargs == 0)
596 nxf += 1;
597 else
598 nxf = (Stack *)argtop;
599 return(ip = newip);
603 void *setbrk(int x)
605 char *i;
607 if ((i = (char *) calloc(x, 1)) == 0) {
608 ERROR "Core limit reached" WARN;
609 edone(0100);
611 return(i);
615 int getsn(void)
617 int i;
619 if ((i = getach()) == 0)
620 return(0);
621 if (i == '(')
622 return(getrq());
623 else
624 return(i);
628 Offset setstr(void)
630 int i, j;
632 lgf++;
633 if ((i = getsn()) == 0 || (j = findmn(i)) == -1 || !contabp[j].mx) {
634 lgf--;
635 return(0);
636 } else {
637 SPACETEST(nxf, sizeof(Stack));
638 nxf->nargs = 0;
639 strflg++;
640 lgf--;
641 return pushi(contabp[j].mx, i);
647 void collect(void)
649 int j;
650 Tchar i, *strp, *lim, **argpp, **argppend;
651 int quote;
652 Stack *savnxf;
654 copyf++;
655 nxf->nargs = 0;
656 savnxf = nxf;
657 if (skip())
658 goto rtn;
661 char *memp;
662 memp = (char *)savnxf;
664 * 1 s structure for the macro descriptor
665 * APERMAC Tchar *'s for pointers into the strings
666 * space for the Tchar's themselves
668 memp += sizeof(Stack);
670 * CPERMAC = the total # of characters for ALL arguments
672 #define CPERMAC 200
673 #define APERMAC 9
674 memp += APERMAC * sizeof(Tchar *);
675 memp += CPERMAC * sizeof(Tchar);
676 nxf = (Stack *)memp;
678 lim = (Tchar *)nxf;
679 argpp = (Tchar **)(savnxf + 1);
680 argppend = &argpp[APERMAC];
681 SPACETEST(argppend, sizeof(Tchar *));
682 strp = (Tchar *)argppend;
684 * Zero out all the string pointers before filling them in.
686 for (j = 0; j < APERMAC; j++)
687 argpp[j] = 0;
688 /* ERROR "savnxf=0x%x,nxf=0x%x,argpp=0x%x,strp=argppend=0x%x, lim=0x%x",
689 * savnxf, nxf, argpp, strp, lim WARN;
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 /* fprintf(stderr, "collect %c %d\n", cbits(i), cbits(i)); */
702 if (nlflg || (!quote && argpp != argppend && cbits(i) == ' '))
703 break; /* collects rest into $9 */
704 if ( quote
705 && cbits(i) == '"'
706 && cbits(i = getch()) != '"') {
707 ch = i;
708 break;
710 *strp++ = i;
711 if (strflg && strp >= lim) {
712 /* ERROR "strp=0x%x, lim = 0x%x", strp, lim WARN; */
713 ERROR "Macro argument too long" WARN;
714 copyf--;
715 edone(004);
717 SPACETEST(strp, 3 * sizeof(Tchar));
719 *strp++ = 0;
721 nxf = savnxf;
722 nxf->nargs = argpp - (Tchar **)(savnxf + 1);
723 argtop = strp;
724 rtn:
725 copyf--;
729 void seta(void)
731 int i;
733 i = cbits(getch()) - '0';
734 if (i > 0 && i <= APERMAC && i <= frame->nargs)
735 pushback(*(((Tchar **)(frame + 1)) + i - 1));
739 void caseda(void)
741 app++;
742 casedi();
745 void casegd(void)
747 int i, j;
749 skip();
750 if ((i = getrq()) == 0)
751 return;
752 if ((j = findmn(i)) >= 0) {
753 if (contabp[j].divsiz != NULL) {
754 numtabp[DN].val = contabp[j].divsiz->dix;
755 numtabp[DL].val = contabp[j].divsiz->diy;
760 #define FINDDIV(o) if ((o = findmn(dip->curd)) < 0) \
761 ERROR "lost diversion %s", unpair(dip->curd) WARN
763 void casedi(void)
765 int i, j, *k;
767 lgf++;
768 if (skip() || (i = getrq()) == 0) {
769 if (dip != d) {
770 FINDDIV(savslot);
771 wbf((Tchar)0);
773 if (dilev > 0) {
774 numtabp[DN].val = dip->dnl;
775 numtabp[DL].val = dip->maxl;
776 FINDDIV(j);
777 if ((contabp[j].divsiz = (Divsiz *) malloc(sizeof(Divsiz))) == NULL) {
778 ERROR "Cannot alloc diversion size" WARN;
779 done2(1);
780 } else {
781 contabp[j].divsiz->dix = numtabp[DN].val;
782 contabp[j].divsiz->diy = numtabp[DL].val;
784 dip = &d[--dilev];
785 offset = dip->op;
787 goto rtn;
789 if (++dilev == NDI) {
790 --dilev;
791 ERROR "Diversions nested too deep" WARN;
792 edone(02);
794 if (dip != d) {
795 FINDDIV(j);
796 savslot = j;
797 wbf((Tchar)0);
799 diflg++;
800 dip = &d[dilev];
801 dip->op = finds(i);
802 dip->curd = i;
803 clrmn(oldmn);
804 k = (int *) & dip->dnl;
805 for (j = 0; j < 10; j++)
806 k[j] = 0; /*not op and curd*/
807 rtn:
808 app = 0;
809 diflg = 0;
813 void casedt(void)
815 lgf++;
816 dip->dimac = dip->ditrap = dip->ditf = 0;
817 skip();
818 dip->ditrap = vnumb((int *)0);
819 if (nonumb)
820 return;
821 skip();
822 dip->dimac = getrq();
825 #define LNSIZE 4000
826 void casetl(void)
828 int j;
829 int w[3];
830 Tchar buf[LNSIZE];
831 Tchar *tp;
832 Tchar i, delim;
835 * bug fix
837 * if .tl is the first thing in the file, the p1
838 * doesn't come out, also the pagenumber will be 0
840 * tends too confuse the device filter (and the user as well)
842 if (dip == d && numtabp[NL].val == -1)
843 newline(1);
844 dip->nls = 0;
845 skip();
846 if (ismot(delim = getch())) {
847 ch = delim;
848 delim = '\'';
849 } else
850 delim = cbits(delim);
851 tp = buf;
852 numtabp[HP].val = 0;
853 w[0] = w[1] = w[2] = 0;
854 j = 0;
855 while (cbits(i = getch()) != '\n') {
856 if (cbits(i) == cbits(delim)) {
857 if (j < 3)
858 w[j] = numtabp[HP].val;
859 numtabp[HP].val = 0;
860 if (w[j] != 0)
861 *tp++ = WORDSP;
862 j++;
863 *tp++ = 0;
864 } else {
865 if (cbits(i) == pagech) {
866 setn1(numtabp[PN].val, numtabp[findr('%')].fmt,
867 i&SFMASK);
868 continue;
870 numtabp[HP].val += width(i);
871 if (tp < &buf[LNSIZE-10]) {
872 if (cbits(i) == ' ' && *tp != WORDSP)
873 *tp++ = WORDSP;
874 *tp++ = i;
875 } else {
876 ERROR "Overflow in casetl" WARN;
880 if (j<3)
881 w[j] = numtabp[HP].val;
882 *tp++ = 0;
883 *tp++ = 0;
884 *tp = 0;
885 tp = buf;
886 if (NROFF)
887 horiz(po);
888 while (i = *tp++)
889 pchar(i);
890 if (w[1] || w[2])
891 horiz(j = quant((lt - w[1]) / 2 - w[0], HOR));
892 while (i = *tp++)
893 pchar(i);
894 if (w[2]) {
895 horiz(lt - w[0] - w[1] - w[2] - j);
896 while (i = *tp++)
897 pchar(i);
899 newline(0);
900 if (dip != d) {
901 if (dip->dnl > dip->hnl)
902 dip->hnl = dip->dnl;
903 } else {
904 if (numtabp[NL].val > dip->hnl)
905 dip->hnl = numtabp[NL].val;
910 void casepc(void)
912 pagech = chget(IMP);
916 void casepm(void)
918 int i, k;
919 int xx, cnt, tcnt, kk, tot;
920 Offset j;
922 kk = cnt = tcnt = 0;
923 tot = !skip();
924 stackdump();
925 for (i = 0; i < nm; i++) {
926 if ((xx = contabp[i].rq) == 0 || contabp[i].mx == 0)
927 continue;
928 tcnt++;
929 j = contabp[i].mx;
930 for (k = 1; (j = blist[bindex(j)].nextoff) != -1; )
931 k++;
932 cnt++;
933 kk += k;
934 if (!tot)
935 fprintf(stderr, "%-2.2s %d\n", unpair(xx), k);
937 fprintf(stderr, "pm: total %d, macros %d, space %d\n", tcnt, cnt, kk);
940 void stackdump(void) /* dumps stack of macros in process */
942 Stack *p;
944 if (frame != stk) {
945 fprintf(stderr, "stack: ");
946 for (p = frame; p != stk; p = p->pframe)
947 fprintf(stderr, "%s ", unpair(p->mname));
948 fprintf(stderr, "\n");