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