Annotation of 42BSD/ingres/source/monitor/mac.c, revision 1.1

1.1     ! root        1: # include      <useful.h>
        !             2: # include      <sccs.h>
        !             3: 
        !             4: SCCSID(@(#)mac.c       7.1     2/5/81)
        !             5: 
        !             6: 
        !             7: # define TRACE if (FALSE) printf
        !             8: 
        !             9: /*
        !            10: **  MACRO PROCESSOR
        !            11: */
        !            12: 
        !            13: 
        !            14: # define       ANYDELIM        '\020'          /* \| -- zero or more delims */
        !            15: # define       ONEDELIM        '\021'          /* \^ -- exactly one delim */
        !            16: # define       CHANGE          '\022'          /* \& -- token change */
        !            17: 
        !            18: # define       PARAMN          '\023'          /* $ -- non-preprocessed param */
        !            19: # define       PARAMP          '\024'          /* $$ -- preprocessed param */
        !            20: 
        !            21: # define       PRESCANENABLE   '@'             /* character to enable prescan */
        !            22: # define       LBRACE          '{'             /* left brace */
        !            23: # define       RBRACE          '}'             /* right brace */
        !            24: # define       BACKSLASH       '\\'            /* backslash */
        !            25: # define       LQUOTE          '`'             /* left quote */
        !            26: # define       RQUOTE          '\''            /* right quote */
        !            27: # define       SPACE           ' '
        !            28: # define       TAB             '\t'
        !            29: # define       NEWLINE         '\n'
        !            30: 
        !            31: # define       QUOTED          0200            /* pass right through bit */
        !            32: # define       CHARMASK        0177            /* character part */
        !            33: # define       BYTEMASK        0377            /* one byte */
        !            34: 
        !            35: # define       ITERTHRESH      100             /* iteration limit */
        !            36: # define       NPRIMS          (sizeof Macprims / sizeof Macprims[0])
        !            37: 
        !            38: /* token modes, used to compute token changes */
        !            39: # define       NONE            0               /* guarantees a token change */
        !            40: # define       ID              1               /* identifier */
        !            41: # define       NUMBER          2               /* number (int or float) */
        !            42: # define       DELIM           3               /* delimiter, guarantees a token change */
        !            43: # define       QUOTEMODE       4               /* quoted construct */
        !            44: # define       OP              5               /* operator */
        !            45: # define       NOCHANGE        6               /* guarantees no token change */
        !            46: 
        !            47: 
        !            48: 
        !            49: # include      "buf.h"                 /* headers for buffer manip */
        !            50: 
        !            51: 
        !            52: /* macro definitions */
        !            53: struct macro
        !            54: {
        !            55:        struct macro    *nextm;         /* pointer to next macro header */
        !            56:        char            *template;      /* pointer to macro template */
        !            57:        char            *substitute;    /* pointer to substitution text */
        !            58: };
        !            59: 
        !            60: /* primitive declarations */
        !            61: struct macro   Macprims[] =
        !            62: {
        !            63:        &Macprims[1],   "{define;\020\024t;\020\024s}",                         (char *) 1,
        !            64:        &Macprims[2],   "{rawdefine;\020\024t;\020\024s}",                      (char *) 2,
        !            65:        &Macprims[3],   "{remove;\020\024t}",                                   (char *) 3,
        !            66:        &Macprims[4],   "{dump}",                                               (char *) 4,
        !            67:        &Macprims[5],   "{type\020\024m}",                                      (char *) 5,
        !            68:        &Macprims[6],   "{read\020\024m}",                                      (char *) 6,
        !            69:        &Macprims[7],   "{readdefine;\020\024n;\020\024m}",                     (char *) 7,
        !            70:        &Macprims[8],   "{ifsame;\020\024a;\020\024b;\020\023t;\020\023f}",     (char *) 8,
        !            71:        &Macprims[9],   "{ifeq;\020\024a;\020\024b;\020\023t;\020\023f}",       (char *) 9,
        !            72:        &Macprims[10],  "{ifgt;\020\024a;\020\024b;\020\023t;\020\023f}",       (char *) 10,
        !            73:        &Macprims[11],  "{eval\020\024e}",                                      (char *) 11,
        !            74:        &Macprims[12],  "{substr;\020\024f;\020\024t;\024s}",                   (char *) 12,
        !            75:        &Macprims[13],  "{dnl}",                                                (char *) 13,
        !            76:        &Macprims[14],  "{remove}",                                             (char *) 3,
        !            77:        0,              "{dump;\020\024n}",                                     (char *) 4,
        !            78: };
        !            79: 
        !            80: struct macro   *Machead        = &Macprims[0]; /* head of macro list */
        !            81: 
        !            82: 
        !            83: /* parameters */
        !            84: struct param
        !            85: {
        !            86:        struct param    *nextp;
        !            87:        char            mode;
        !            88:        char            name;
        !            89:        char            *paramt;
        !            90: };
        !            91: 
        !            92: 
        !            93: 
        !            94: /* the environment */
        !            95: struct env
        !            96: {
        !            97:        struct env      *nexte;         /* next environment */
        !            98:        int             (*rawget)();    /* raw character get routine */
        !            99:        char            **rawpar;       /* a parameter to that routine */
        !           100:        char            prevchar;       /* previous character read */
        !           101:        char            tokenmode;      /* current token mode */
        !           102:        char            change;         /* token change flag */
        !           103:        char            eof;            /* eof flag */
        !           104:        char            newline;        /* set if bol */
        !           105:        char            rawnewline;     /* same for raw input */
        !           106:        struct buf      *pbuf;          /* peek buffer */
        !           107:        struct buf      *mbuf;          /* macro buffer */
        !           108:        char            endtrap;        /* endtrap flag */
        !           109:        char            pass;           /* pass flag */
        !           110:        char            pdelim;         /* current parameter delimiter */
        !           111:        struct param    *params;        /* parameter list */
        !           112:        int             itercount;      /* iteration count */
        !           113:        int             quotelevel;     /* quote nesting level */
        !           114: };
        !           115: 
        !           116: /* current environment pointer */
        !           117: struct env     *Macenv;
        !           118: /*
        !           119: **  MACINIT -- initialize for macro processing
        !           120: **
        !           121: **     *** EXTERNAL INTERFACE ***
        !           122: **
        !           123: **     The macro processor is initialized.  Any crap left over from
        !           124: **     previous processing (which will never occur normally, but may
        !           125: **     happen on an interrupt, for instance) will be cleaned up.  The
        !           126: **     raw input is defined, and the 'endtrap' parameter tells whether
        !           127: **     this is "primary" processing or not; in other words, it tells
        !           128: **     whether to spring {begintrap} and {endtrap}.
        !           129: **
        !           130: **     This routine must always be called prior to any processing.
        !           131: */
        !           132: 
        !           133: macinit(rawget, rawpar, endtrap)
        !           134: int    (*rawget)();
        !           135: char   **rawpar;
        !           136: int    endtrap;
        !           137: {
        !           138:        static struct env       env;
        !           139:        register struct env     *e;
        !           140:        register struct env     *f;
        !           141: 
        !           142:        /* clear out old crap */
        !           143:        for (e = Macenv; e != 0; e = f)
        !           144:        {
        !           145:                bufpurge(&e->mbuf);
        !           146:                bufpurge(&e->pbuf);
        !           147:                macpflush(e);
        !           148:                f = e->nexte;
        !           149:                if (f != 0)
        !           150:                        buffree(e);
        !           151:        }
        !           152: 
        !           153:        /* set up the primary environment */
        !           154:        Macenv = e = &env;
        !           155:        clrmem(e, sizeof *e);
        !           156: 
        !           157:        e->rawget = rawget;
        !           158:        e->rawpar = rawpar;
        !           159:        e->endtrap = endtrap;
        !           160:        e->newline = 1;
        !           161: 
        !           162:        if (endtrap)
        !           163:                macspring("{begintrap}");
        !           164: }
        !           165: /*
        !           166: **  MACGETCH -- get character after macro processing
        !           167: **
        !           168: **     *** EXTERNAL INTERFACE ROUTINE ***
        !           169: **
        !           170: **     The macro processor must have been previously initialized by a
        !           171: **     call to macinit().
        !           172: */
        !           173: 
        !           174: macgetch()
        !           175: {
        !           176:        register struct env     *e;
        !           177:        register int            c;
        !           178: 
        !           179:        e = Macenv;
        !           180:        for (;;)
        !           181:        {
        !           182:                /* get an input character */
        !           183:                c = macgch();
        !           184: 
        !           185:                /* check for end-of-file processing */
        !           186:                if (c == 0)
        !           187:                {
        !           188:                        /* check to see if we should spring {endtrap} */
        !           189:                        if (e->endtrap)
        !           190:                        {
        !           191:                                e->endtrap = 0;
        !           192:                                macspring("{endtrap}");
        !           193:                                continue;
        !           194:                        }
        !           195: 
        !           196:                        /* don't spring endtrap -- real end of file */
        !           197:                        return (0);
        !           198:                }
        !           199: 
        !           200:                /* not an end of file -- check for pass character through */
        !           201:                if (e->pass)
        !           202:                {
        !           203:                        e->pass = 0;
        !           204:                        e->change = 0;
        !           205:                }
        !           206:                if ((c & QUOTED) != 0 || !e->change || e->tokenmode == DELIM)
        !           207:                {
        !           208:                        /* the character is to be passed through */
        !           209:                        /* reset iteration count and purge macro buffer */
        !           210:                        e->itercount = 0;
        !           211:                        bufflush(&e->mbuf);
        !           212:                        e->newline = (c == NEWLINE);
        !           213:                        return (c & CHARMASK);
        !           214:                }
        !           215: 
        !           216:                /* this character is a candidate for macro processing */
        !           217:                macunget(0);
        !           218:                bufflush(&e->mbuf);
        !           219: 
        !           220:                /* check for infinite loop */
        !           221:                if (e->itercount > ITERTHRESH)
        !           222:                {
        !           223:                        printf("Infinite loop in macro\n");
        !           224:                        e->pass++;
        !           225:                        continue;
        !           226:                }
        !           227: 
        !           228:                /* see if we have a macro match */
        !           229:                if (macallscan())
        !           230:                {
        !           231:                        /* yep -- count iterations and rescan it */
        !           232:                        e->itercount++;
        !           233:                }
        !           234:                else
        !           235:                {
        !           236:                        /* nope -- pass the next token through raw */
        !           237:                        e->pass++;
        !           238:                }
        !           239:        }
        !           240: }
        !           241: /*
        !           242: **  MACGCH -- get input character, knowing about tokens
        !           243: **
        !           244: **     The next input character is returned.  In addition, the quote
        !           245: **     level info is maintained and the QUOTED bit is set if the
        !           246: **     returned character is (a) quoted or (b) backslash escaped.
        !           247: **     As a side effect the change flag is maintained.  Also, the
        !           248: **     character is saved in mbuf.
        !           249: */
        !           250: 
        !           251: macgch()
        !           252: {
        !           253:        register int            c;
        !           254:        register struct env     *e;
        !           255:        register int            i;
        !           256: 
        !           257:        e = Macenv;
        !           258: 
        !           259:        for (;;)
        !           260:        {
        !           261:                /* get virtual raw character, save in mbuf, and set change */
        !           262:                c = macfetch(e->quotelevel > 0);
        !           263: 
        !           264:                /* test for magic frotz */
        !           265:                switch (c)
        !           266:                {
        !           267:                  case 0:       /* end of file */
        !           268:                        return (0);
        !           269: 
        !           270:                  case LQUOTE:
        !           271:                        if (e->quotelevel++ == 0)
        !           272:                                continue;
        !           273:                        break;
        !           274: 
        !           275:                  case RQUOTE:
        !           276:                        if (e->quotelevel == 0)
        !           277:                                return (c);
        !           278:                        if (--e->quotelevel == 0)
        !           279:                        {
        !           280:                                continue;
        !           281:                        }
        !           282:                        break;
        !           283: 
        !           284:                  case BACKSLASH:
        !           285:                        if (e->quotelevel > 0)
        !           286:                                break;
        !           287:                        c = macfetch(1);
        !           288: 
        !           289:                        /* handle special cases */
        !           290:                        if (c == e->pdelim)
        !           291:                                break;
        !           292: 
        !           293:                        /* do translations */
        !           294:                        switch (c)
        !           295:                        {
        !           296:                          case SPACE:   /* space */
        !           297:                          case TAB:     /* tab */
        !           298:                          case NEWLINE: /* newline */
        !           299:                          case RQUOTE:
        !           300:                          case LQUOTE:
        !           301:                          case '$':
        !           302:                          case LBRACE:
        !           303:                          case RBRACE:
        !           304:                          case BACKSLASH:
        !           305:                                break;
        !           306: 
        !           307:                          default:
        !           308:                                /* take character as is (unquoted) */
        !           309:                                c = 0;
        !           310:                                break;
        !           311:                        }
        !           312: 
        !           313:                        if (c != 0)
        !           314:                                break;
        !           315: 
        !           316:                        /* not an escapable character -- treat it normally */
        !           317:                        macunget(1);
        !           318:                        c = BACKSLASH;
        !           319:                        /* do default character processing on backslash */
        !           320: 
        !           321:                  default:
        !           322:                        if (e->quotelevel > 0)
        !           323:                                break;
        !           324:                        return (c);
        !           325:                }
        !           326: 
        !           327:                /* the character is quoted */
        !           328:                return (c | QUOTED);
        !           329:        }
        !           330: }
        !           331: /*
        !           332: **  MACFETCH -- fetch virtual raw character
        !           333: **
        !           334: **     A character is fetched from the peek buffer.  If that buffer is
        !           335: **     empty, it is fetched from the raw input.  The character is then
        !           336: **     saved away, and the change flag is set accordingly.
        !           337: **     The QUOTED bit on the character is set if the 'quote' flag
        !           338: **     parameter is set; used for backslash escapes.
        !           339: **     Note that the QUOTED bit appears only on the character which
        !           340: **     goes into the macro buffer; the character returned is normal.
        !           341: */
        !           342: 
        !           343: macfetch(quote)
        !           344: int    quote;
        !           345: {
        !           346:        register struct env     *e;
        !           347:        register int            c;
        !           348:        register int            escapech;
        !           349: 
        !           350:        e = Macenv;
        !           351:        escapech = 0;
        !           352: 
        !           353:        for (;;)
        !           354:        {
        !           355:                /* get character from peek buffer */
        !           356:                c = bufget(&e->pbuf);
        !           357: 
        !           358:                if (c == 0)
        !           359:                {
        !           360:                        /* peek buffer is empty */
        !           361:                        /* check for already raw eof */
        !           362:                        if (!e->eof)
        !           363:                        {
        !           364:                                /* note that c must be int so that the QUOTED bit is not negative */
        !           365:                                c = (*e->rawget)(e->rawpar);
        !           366:                                if (c <= 0)
        !           367:                                {
        !           368:                                        c = 0;
        !           369:                                        e->eof++;
        !           370:                                }
        !           371:                                else
        !           372:                                {
        !           373:                                        if (e->rawnewline)
        !           374:                                                e->prevchar = NEWLINE;
        !           375:                                        e->rawnewline = (c == NEWLINE);
        !           376:                                }
        !           377:                        }
        !           378:                }
        !           379: 
        !           380:                /* test for escapable character */
        !           381:                if (escapech)
        !           382:                {
        !           383:                        switch (c)
        !           384:                        {
        !           385:                          case 't':     /* become quoted tab */
        !           386:                                c = TAB | QUOTED;
        !           387:                                break;
        !           388: 
        !           389:                          case 'n':     /* become quoted newline */
        !           390:                                c = NEWLINE | QUOTED;
        !           391:                                break;
        !           392: 
        !           393:                          default:
        !           394:                                bufput(c, &e->pbuf);
        !           395:                                c = BACKSLASH;
        !           396:                        }
        !           397:                        escapech = 0;
        !           398:                }
        !           399:                else
        !           400:                {
        !           401:                        if (c == BACKSLASH)
        !           402:                        {
        !           403:                                escapech++;
        !           404:                                continue;
        !           405:                        }
        !           406:                }
        !           407:                break;
        !           408:        }
        !           409: 
        !           410:        /* quote the character if appropriate to mask change flag */
        !           411:        /* ('escapech' now becomes the maybe quoted character) */
        !           412:        escapech = c;
        !           413:        if (quote && c != 0)
        !           414:                escapech |= QUOTED;
        !           415: 
        !           416:        /* set change flag */
        !           417:        macschng(escapech);
        !           418: 
        !           419:        if (c != 0)
        !           420:        {
        !           421:                /* save the character in the macro buffer */
        !           422:                bufput(escapech, &e->mbuf);
        !           423:        }
        !           424: 
        !           425:        return (c);
        !           426: }
        !           427: /*
        !           428: **  MACSCHNG -- set change flag and compute token type
        !           429: **
        !           430: **     The change flag and token type is set.  This does some tricky
        !           431: **     stuff to determine just when a new token begins.  Most notably,
        !           432: **     notice that quoted stuff IS scanned, but the change flag is
        !           433: **     reset in a higher level routine so that quoted stuff looks
        !           434: **     like a single token, but any begin/end quote causes a token
        !           435: **     change.
        !           436: */
        !           437: 
        !           438: macschng(ch)
        !           439: char   ch;
        !           440: {
        !           441:        register struct env     *e;
        !           442:        register char           c;
        !           443:        register int            thismode;
        !           444:        int                     changeflag;
        !           445: 
        !           446:        e = Macenv;
        !           447:        c = ch;
        !           448:        changeflag = 0;
        !           449:        thismode = macmode(c);
        !           450: 
        !           451:        switch (e->tokenmode)
        !           452:        {
        !           453:          case NONE:
        !           454:                /* always cause token change */
        !           455:                break;
        !           456: 
        !           457:          case QUOTEMODE:
        !           458:                /* change only on initial entry to quotes */
        !           459:                break;
        !           460: 
        !           461:          case DELIM:
        !           462:                changeflag++;
        !           463:                break;
        !           464: 
        !           465:          case ID:
        !           466:                /* take any sequence of letters and numerals */
        !           467:                if (thismode == NUMBER)
        !           468:                        thismode = ID;
        !           469:                break;
        !           470: 
        !           471:          case NUMBER:
        !           472:                /* take string of digits and decimal points */
        !           473:                if (c == '.')
        !           474:                        thismode = NUMBER;
        !           475:                break;
        !           476: 
        !           477:          case OP:
        !           478:                switch (e->prevchar)
        !           479:                {
        !           480:                  case '<':
        !           481:                  case '>':
        !           482:                  case '!':
        !           483:                        if (c != '=')
        !           484:                                changeflag++;
        !           485:                        break;
        !           486: 
        !           487:                  case '*':
        !           488:                        if (c != '*' && c != '/')
        !           489:                                changeflag++;
        !           490:                        break;
        !           491: 
        !           492:                  case '/':
        !           493:                        if (c != '*')
        !           494:                                changeflag++;
        !           495:                        break;
        !           496: 
        !           497:                  case '.':
        !           498:                        if (thismode == NUMBER)
        !           499:                                e->tokenmode = thismode;
        !           500:                        break;
        !           501: 
        !           502:                  default:
        !           503:                        changeflag++;
        !           504:                        break;
        !           505:                }
        !           506:                break;
        !           507: 
        !           508:          case NOCHANGE:        /* never cause token change */
        !           509:                e->tokenmode = thismode;
        !           510:                break;
        !           511:        }
        !           512: 
        !           513:        e->prevchar = c;
        !           514:        if (thismode != e->tokenmode)
        !           515:                changeflag++;
        !           516:        e->tokenmode = thismode;
        !           517:        e->change = changeflag;
        !           518: }
        !           519: /*
        !           520: **  MACMODE -- return mode of a character
        !           521: */
        !           522: 
        !           523: macmode(ch)
        !           524: char   ch;
        !           525: {
        !           526:        register char   c;
        !           527: 
        !           528:        c = ch;
        !           529: 
        !           530:        if ((c & QUOTED) != 0)
        !           531:                return (QUOTEMODE);
        !           532:        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_'))
        !           533:                return (ID);
        !           534:        if (c >= '0' && c <= '9')
        !           535:                return (NUMBER);
        !           536:        if (c == SPACE || c == TAB || c == NEWLINE)
        !           537:                return (DELIM);
        !           538:        return (OP);
        !           539: }
        !           540: /*
        !           541: **  MACALLSCAN -- scan to see if input matches a macro
        !           542: **
        !           543: **     Returns true if there was a match, false if not.  In any case,
        !           544: **     the virtual raw input (i.e., the peek buffer) will contain
        !           545: **     either the old raw input, or the substituted macro.
        !           546: */
        !           547: 
        !           548: macallscan()
        !           549: {
        !           550:        register struct macro   *m;
        !           551: 
        !           552:        for (m = Machead; m != 0; m = m->nextm)
        !           553:        {
        !           554:                /* check to see if it matches this macro */
        !           555:                if (macscan(m))
        !           556:                {
        !           557:                        /* it does -- substituted value is in mbuf */
        !           558:                        macrescan();
        !           559:                        return (1);
        !           560:                }
        !           561: 
        !           562:                /* it doesn't match this macro -- try the next one */
        !           563:                macrescan();
        !           564:        }
        !           565: 
        !           566:        /* it doesn't match any of them -- tough luck */
        !           567:        return (0);
        !           568: }
        !           569: /*
        !           570: **  MACSCAN -- scan a single macro for a match
        !           571: **
        !           572: **     As is scans it also collects parameters for possible future
        !           573: **     substitution.  If it finds a match, it takes responsibility
        !           574: **     for doing the substitution.
        !           575: */
        !           576: 
        !           577: macscan(mac)
        !           578: struct macro   *mac;
        !           579: {
        !           580:        register struct macro   *m;
        !           581:        register char           c;
        !           582:        register char           *temp;
        !           583:        char                    pname, pdelim;
        !           584: 
        !           585:        m = mac;
        !           586: 
        !           587:        /* check for anchored mode */
        !           588:        temp = m->template;
        !           589:        if (*temp == ONEDELIM)
        !           590:        {
        !           591:                if (!Macenv->newline)
        !           592:                        return (0);
        !           593:                temp++;
        !           594:        }
        !           595: 
        !           596:        /* scan the template */
        !           597:        for ( ; c = *temp; temp++)
        !           598:        {
        !           599:                if (c == PARAMN || c == PARAMP)
        !           600:                {
        !           601:                        /* we have a parameter */
        !           602:                        pname = *++temp;
        !           603:                        pdelim = *++temp;
        !           604:                        if (macparam(c, pname, pdelim))
        !           605:                        {
        !           606:                                /* parameter ok */
        !           607:                                continue;
        !           608:                        }
        !           609: 
        !           610:                        /* failure on parameter scan */
        !           611:                        return (0);
        !           612:                }
        !           613: 
        !           614:                if (!macmatch(c))
        !           615:                {
        !           616:                        /* failure on literal match */
        !           617:                        return (0);
        !           618:                }
        !           619:        }
        !           620: 
        !           621:        /* it matches!!  substitute the macro */
        !           622:        macsubs(m);
        !           623:        return (1);
        !           624: }
        !           625: /*
        !           626: **  MACPARAM -- collect a parameter
        !           627: **
        !           628: **     The parameter is collected and stored away "somewhere" with
        !           629: **     name 'name'.  The delimiter is taken to be 'delim'.  'Mode'
        !           630: **     tells whether to prescan the parameter (done immediately before
        !           631: **     substitute time to avoid side effects if the macro actually
        !           632: **     turns out to not match).
        !           633: */
        !           634: 
        !           635: macparam(mode, name, delim)
        !           636: char   mode;
        !           637: char   name;
        !           638: char   delim;
        !           639: {
        !           640:        register char           c;
        !           641:        register struct env     *e;
        !           642:        struct buf              *b;
        !           643:        register struct param   *p;
        !           644:        int                     bracecount;
        !           645:        extern char             *bufalloc(),*bufcrunch();
        !           646:        e = Macenv;
        !           647:        b = 0;
        !           648: 
        !           649:        e->pdelim = delim;
        !           650:        TRACE("\nmacparam(%d, %c, %c):\n", mode, name, delim);
        !           651:        if (mode == PARAMP)
        !           652:        {
        !           653:                /* check for REALLY prescan */
        !           654:                c = macgch();
        !           655:                if (c != PRESCANENABLE)
        !           656:                {
        !           657:                        mode = PARAMN;
        !           658:                        macunget(0);
        !           659:                }
        !           660:        }
        !           661: 
        !           662:        bracecount = 0;
        !           663:        e->tokenmode = NOCHANGE;
        !           664:        while (!macmatch(delim))
        !           665:        {
        !           666:                do
        !           667:                {
        !           668:                        c = macgch();
        !           669:                        if (c == 0 || c == NEWLINE)
        !           670:                        {
        !           671:                                e->pdelim = 0;
        !           672:                                bufpurge(&b);
        !           673:                                TRACE("macparam fails\n");
        !           674:                                return (0);
        !           675:                        }
        !           676:                        bufput(c, &b);
        !           677:                        if (c == LBRACE)
        !           678:                                bracecount++;
        !           679:                        else if (c == RBRACE && bracecount > 0)
        !           680:                                bracecount--;
        !           681:                } while (bracecount > 0);
        !           682:        }
        !           683: 
        !           684:        e->pdelim = 0;
        !           685: 
        !           686:        /* allocate and store the parameter */
        !           687:        p = (struct param *) bufalloc(sizeof *p);
        !           688:        p->mode = mode;
        !           689:        p->name = name;
        !           690:        p->nextp = e->params;
        !           691:        e->params = p;
        !           692:        p->paramt = bufcrunch(&b);
        !           693:        bufpurge(&b);
        !           694:        TRACE("macparam: |%s|\n", p->paramt);
        !           695: 
        !           696:        return (1);
        !           697: }
        !           698: /*
        !           699: **  MACMATCH -- test for a match between template character and input.
        !           700: **
        !           701: **     The parameter is the character from the template to match on.
        !           702: **     The input is read.  The template character may be a meta-
        !           703: **     character.  In all cases if the match occurs the input is
        !           704: **     thrown away; if no match occurs the input is left unchanged.
        !           705: **
        !           706: **     Return value is true for a match, false for no match.
        !           707: */
        !           708: 
        !           709: macmatch(template)
        !           710: char   template;
        !           711: {
        !           712:        register char   t;
        !           713:        register char   c;
        !           714:        register int    res;
        !           715: 
        !           716:        t = template;
        !           717:        TRACE("\tmacmatch(%c)", t);
        !           718: 
        !           719:        switch (t)
        !           720:        {
        !           721:          case ANYDELIM:        /* match zero or more delimiters */
        !           722:                /* chew and chuck delimiters */
        !           723:                while (macdelim())
        !           724:                        ;
        !           725: 
        !           726:                /* as a side effect, must match a token change */
        !           727:                if (!macckch())
        !           728:                {
        !           729:                        TRACE(" fail\n");
        !           730:                        return (0);
        !           731:                }
        !           732:                TRACE(" succeed\n");
        !           733:                return (1);
        !           734: 
        !           735:          case ONEDELIM:        /* match exactly one delimiter */
        !           736:                TRACE(":\n");
        !           737:                res = macdelim();
        !           738:                return (res);
        !           739: 
        !           740:          case CHANGE:          /* match a token change */
        !           741:          case 0:               /* end of template */
        !           742:                TRACE(":\n");
        !           743:                res = macckch();
        !           744:                return (res);
        !           745: 
        !           746:          default:              /* must have exact character match */
        !           747:                c = macgch();
        !           748:                TRACE(" against %c ", c);
        !           749:                if (c == t)
        !           750:                {
        !           751:                        TRACE("succeed\n");
        !           752:                        return (1);
        !           753:                }
        !           754: 
        !           755:                /* failure */
        !           756:                macunget(0);
        !           757:                TRACE("fail\n");
        !           758:                return (0);
        !           759:        }
        !           760: }
        !           761: /*
        !           762: **  MACDELIM -- test for next input character a delimiter
        !           763: **
        !           764: **     Returns true if the next input character is a delimiter, false
        !           765: **     otherwise.  Delimiters are chewed.
        !           766: */
        !           767: 
        !           768: macdelim()
        !           769: {
        !           770:        register char   c;
        !           771: 
        !           772:        c = macgch();
        !           773:        TRACE("\t\tmacdelim against %c: ", c);
        !           774:        if (macmode(c) == DELIM)
        !           775:        {
        !           776:                TRACE("succeed\n");
        !           777:                return (1);
        !           778:        }
        !           779:        macunget(0);
        !           780:        TRACE("fail\n");
        !           781:        return (0);
        !           782: }
        !           783: /*
        !           784: **  MACCKCH -- check for token change
        !           785: **
        !           786: **     Returns true if a token change occurs between this and the next
        !           787: **     character.  No characters are ever chewed, however, the token
        !           788: **     change (if it exists) is always chewed.
        !           789: */
        !           790: 
        !           791: macckch()
        !           792: {
        !           793:        register int            change;
        !           794:        register char           c;
        !           795:        register struct env     *e;
        !           796: 
        !           797:        e = Macenv;
        !           798: 
        !           799:        if (e->tokenmode == NONE)
        !           800:        {
        !           801:                /* then last character has been ungotten: take old change */
        !           802:                change = e->change;
        !           803:        }
        !           804:        else
        !           805:        {
        !           806:                c = macgch();
        !           807:                change = Macenv->change;
        !           808:                macunget(0);
        !           809:        }
        !           810:        TRACE("macckch got %c ret %d\n", c, change);
        !           811: 
        !           812:        /* chew the change and return */
        !           813:        e->tokenmode = NOCHANGE;
        !           814:        return (change);
        !           815: }
        !           816: /*
        !           817: **  MACSUBS -- substitute in macro substitution
        !           818: **
        !           819: **     This routine prescans appropriate parameters and then either
        !           820: **     loads the substitution into the macro buffer or calls the
        !           821: **     correct primitive routine.
        !           822: */
        !           823: 
        !           824: macsubs(mac)
        !           825: struct macro   *mac;
        !           826: {
        !           827:        register struct param   *p;
        !           828:        register struct env     *e;
        !           829:        register char           *s;
        !           830:        char                    *macprim();
        !           831: 
        !           832:        e = Macenv;
        !           833: 
        !           834:        for (p = e->params; p != 0; p = p->nextp)
        !           835:        {
        !           836:                /* check to see if we should prescan */
        !           837:                if (p->mode != PARAMP)
        !           838:                {
        !           839:                        continue;
        !           840:                }
        !           841: 
        !           842:                /* prescan parameter */
        !           843:                macprescan(&p->paramt);
        !           844:                p->mode = PARAMN;
        !           845:        }
        !           846: 
        !           847:        s = mac->substitute;
        !           848: 
        !           849:        /* clear out the macro call */
        !           850:        bufflush(&e->mbuf);
        !           851: 
        !           852:        if (s <= (char *) NPRIMS)
        !           853:        {
        !           854:                /* it is a primitive */
        !           855:                macload(macprim(s), 0);
        !           856:        }
        !           857:        else
        !           858:        {
        !           859:                /* it is a user-defined macro */
        !           860:                macload(s, 1);
        !           861:        }
        !           862: }
        !           863: /*
        !           864: **  MACPRESCAN -- prescan a parameter
        !           865: **
        !           866: **     The parameter pointed to by 'pp' is fed once through the macro
        !           867: **     processor and replaced with the new version.
        !           868: */
        !           869: 
        !           870: macprescan(pp)
        !           871: char   **pp;
        !           872: {
        !           873:        struct buf              *b;
        !           874:        char                    *p;
        !           875:        register struct env     *e;
        !           876:        register char           c;
        !           877:        extern int              macsget();
        !           878: 
        !           879:        b = 0;
        !           880:        p = *pp;
        !           881: 
        !           882:        /* set up a new environment */
        !           883:        macnewev(macsget, &p);
        !           884:        e = Macenv;
        !           885: 
        !           886:        /* scan the parameter */
        !           887:        while ((c = macgetch()) != 0)
        !           888:                bufput(c, &b);
        !           889: 
        !           890:        /* free the old parameter */
        !           891:        buffree(*pp);
        !           892: 
        !           893:        /* move in the new one */
        !           894:        *pp = bufcrunch(&b);
        !           895:        bufpurge(&b);
        !           896: 
        !           897:        /* restore the old environment */
        !           898:        macpopev();
        !           899: }
        !           900: /*
        !           901: **  MACNEWEV -- set up new environment
        !           902: **
        !           903: **     Parameters are raw get routine and parameter
        !           904: */
        !           905: 
        !           906: macnewev(rawget, rawpar)
        !           907: int    (*rawget)();
        !           908: char   **rawpar;
        !           909: {
        !           910:        register struct env     *e;
        !           911:        extern char             *bufalloc();
        !           912: 
        !           913:        e = (struct env *) bufalloc(sizeof *e);
        !           914:        e->rawget = rawget;
        !           915:        e->rawpar = rawpar;
        !           916:        e->nexte = Macenv;
        !           917:        e->newline = 1;
        !           918:        Macenv = e;
        !           919: }
        !           920: /*
        !           921: **  MACPOPEV -- pop an environment
        !           922: **
        !           923: **     Makes sure all buffers and stuff are purged
        !           924: */
        !           925: 
        !           926: macpopev()
        !           927: {
        !           928:        register struct env     *e;
        !           929: 
        !           930:        e = Macenv;
        !           931:        bufpurge(&e->mbuf);
        !           932:        bufpurge(&e->pbuf);
        !           933:        macpflush(e);
        !           934:        Macenv = e->nexte;
        !           935:        buffree(e);
        !           936: }
        !           937: /*
        !           938: **  MACPFLUSH -- flush all parameters
        !           939: **
        !           940: **     Used to deallocate all parameters in a given environment.
        !           941: */
        !           942: 
        !           943: macpflush(env)
        !           944: struct env     *env;
        !           945: {
        !           946:        register struct env     *e;
        !           947:        register struct param   *p;
        !           948:        register struct param   *q;
        !           949: 
        !           950:        e = env;
        !           951: 
        !           952:        for (p = e->params; p != 0; p = q)
        !           953:        {
        !           954:                buffree(p->paramt);
        !           955:                q = p->nextp;
        !           956:                buffree(p);
        !           957:        }
        !           958: 
        !           959:        e->params = 0;
        !           960: }
        !           961: /*
        !           962: **  MACSGET -- get from string
        !           963: **
        !           964: **     Works like a getchar from a string.  Used by macprescan().
        !           965: **     The parameter is a pointer to the string.
        !           966: */
        !           967: 
        !           968: macsget(pp)
        !           969: char   **pp;
        !           970: {
        !           971:        register char   **p;
        !           972:        register int    c;
        !           973: 
        !           974:        p = pp;
        !           975: 
        !           976:        c = **p & BYTEMASK;
        !           977:        if (c != 0)
        !           978:                (*p)++;
        !           979:        return (c);
        !           980: }
        !           981: /*
        !           982: **  MACLOAD -- load a string into the macro buffer
        !           983: **
        !           984: **     The parameters are a pointer to a string to be appended to
        !           985: **     the macro buffer and a flag telling whether parameter substi-
        !           986: **     tution can occur.
        !           987: */
        !           988: 
        !           989: macload(str, flag)
        !           990: char   *str;
        !           991: int    flag;
        !           992: {
        !           993:        register struct env     *e;
        !           994:        register char           *s;
        !           995:        register char           c;
        !           996:        extern char             *macplkup();
        !           997: 
        !           998:        e = Macenv;
        !           999:        s = str;
        !          1000: 
        !          1001:        if (s == 0)
        !          1002:                return;
        !          1003: 
        !          1004:        while ((c = *s++) != 0)
        !          1005:        {
        !          1006:                if (c == PARAMN)
        !          1007:                        macload(macplkup(*s++), 0);
        !          1008:                else
        !          1009:                        bufput(c & CHARMASK, &e->mbuf);
        !          1010:        }
        !          1011: }
        !          1012: /*
        !          1013: **  MACRESCAN -- rescan the macro buffer
        !          1014: **
        !          1015: **     Copies the macro buffer into the peek buffer so that it will be
        !          1016: **     reread.  Also deallocates any parameters which may happen to be
        !          1017: **     stored away.
        !          1018: */
        !          1019: 
        !          1020: macrescan()
        !          1021: {
        !          1022:        register struct env     *e;
        !          1023:        register char           c;
        !          1024: 
        !          1025:        e = Macenv;
        !          1026: 
        !          1027:        while ((c = bufget(&e->mbuf) & CHARMASK) != 0)
        !          1028:                bufput(c, &e->pbuf);
        !          1029: 
        !          1030:        e->quotelevel = 0;
        !          1031:        e->tokenmode = NONE;
        !          1032:        macpflush(e);
        !          1033: }
        !          1034: /*
        !          1035: **  MACUNGET -- unget a character
        !          1036: **
        !          1037: **     Moves one character from the macro buffer to the peek buffer.
        !          1038: **     If 'mask' is set, the character has the quote bit stripped off.
        !          1039: */
        !          1040: 
        !          1041: macunget(mask)
        !          1042: int    mask;
        !          1043: {
        !          1044:        register struct env     *e;
        !          1045:        register char           c;
        !          1046: 
        !          1047:        e = Macenv;
        !          1048: 
        !          1049:        if (e->prevchar != 0)
        !          1050:        {
        !          1051:                c = bufget(&e->mbuf);
        !          1052:                if (mask)
        !          1053:                         c &= CHARMASK;
        !          1054:                bufput(c, &e->pbuf);
        !          1055:                e->tokenmode = NONE;
        !          1056:        }
        !          1057: }
        !          1058: /*
        !          1059: **  MACPLKUP -- look up parameter
        !          1060: **
        !          1061: **     Returns a pointer to the named parameter.  Returns null
        !          1062: **     if the parameter is not found ("cannot happen").
        !          1063: */
        !          1064: 
        !          1065: char *
        !          1066: macplkup(name)
        !          1067: char   name;
        !          1068: {
        !          1069:        register struct param   *p;
        !          1070: 
        !          1071:        for (p = Macenv->params; p != 0; p = p->nextp)
        !          1072:        {
        !          1073:                if (p->name == name)
        !          1074:                        return (p->paramt);
        !          1075:        }
        !          1076: 
        !          1077:        return (0);
        !          1078: }
        !          1079: /*
        !          1080: **  MACSPRING -- spring a trap
        !          1081: **
        !          1082: **     The named trap is sprung, in other words, if the named macro is
        !          1083: **     defined it is called, otherwise there is no replacement text.
        !          1084: */
        !          1085: 
        !          1086: macspring(trap)
        !          1087: char   *trap;
        !          1088: {
        !          1089:        register struct env     *e;
        !          1090:        register char           *p;
        !          1091:        char                    *macro();
        !          1092: 
        !          1093:        e = Macenv;
        !          1094: 
        !          1095:        bufflush(&e->mbuf);
        !          1096: 
        !          1097:        /* fetch the macro */
        !          1098:        p = macro(trap);
        !          1099: 
        !          1100:        /* if not defined, don't bother */
        !          1101:        if (p == 0)
        !          1102:                return;
        !          1103: 
        !          1104:        /* load the trap */
        !          1105:        macload(p);
        !          1106: 
        !          1107:        /* insert a newline after the trap */
        !          1108:        bufput('\n', &e->mbuf);
        !          1109: 
        !          1110:        macrescan();
        !          1111: }
        !          1112: /*
        !          1113: **  MACPRIM -- do primitives
        !          1114: **
        !          1115: **     The parameter is the primitive to execute.
        !          1116: */
        !          1117: 
        !          1118: char *
        !          1119: macprim(n)
        !          1120: int    n;
        !          1121: {
        !          1122:        register struct env     *e;
        !          1123:        extern char             *macplkup();
        !          1124:        extern char             *macsstr();
        !          1125: 
        !          1126:        e = Macenv;
        !          1127: 
        !          1128:        switch (n)
        !          1129:        {
        !          1130:          case 1:       /* {define; $t; $s} */
        !          1131:                macdnl();
        !          1132:                macdefine(macplkup('t'), macplkup('s'), 0);
        !          1133:                break;
        !          1134: 
        !          1135:          case 2:       /* {rawdefine; $t; $s} */
        !          1136:                macdnl();
        !          1137:                macdefine(macplkup('t'), macplkup('s'), 1);
        !          1138:                break;
        !          1139: 
        !          1140:          case 3:       /* {remove $t} */
        !          1141:                macdnl();
        !          1142:                macremove(macplkup('t'));
        !          1143:                break;
        !          1144: 
        !          1145:          case 4:       /* {dump} */
        !          1146:                        /* {dump; $n} */
        !          1147:                macdnl();
        !          1148:                macdump(macplkup('n'));
        !          1149:                break;
        !          1150: 
        !          1151:          case 5:       /* {type $m} */
        !          1152:                macdnl();
        !          1153:                printf("%s\n", macplkup('m'));
        !          1154:                break;
        !          1155: 
        !          1156:          case 6:       /* {read $m} */
        !          1157:                printf("%s ", macplkup('m'));
        !          1158:                macread();
        !          1159:                break;
        !          1160:          
        !          1161:          case 7:       /* {read; $n; $m} */
        !          1162:                printf("%s ", macplkup('m'));
        !          1163:                macread();
        !          1164:                macdefine(macplkup('n'), bufcrunch(&e->mbuf), 1);
        !          1165:                return("{readcount}");
        !          1166: 
        !          1167:          case 8:       /* {ifsame; $a; $b; $t; $f} */
        !          1168:                if (sequal(macplkup('a'), macplkup('b')))
        !          1169:                        return (macplkup('t'));
        !          1170:                else
        !          1171:                        return (macplkup('f'));
        !          1172: 
        !          1173:          case 9:       /* {ifeq; $a; $b; $t; $f} */
        !          1174:                if (macnumber(macplkup('a')) == macnumber(macplkup('b')))
        !          1175:                        return (macplkup('t'));
        !          1176:                else
        !          1177:                        return (macplkup('f'));
        !          1178: 
        !          1179:          case 10:      /* {ifgt; $a; $b; $t; $f} */
        !          1180:                if (macnumber(macplkup('a')) > macnumber(macplkup('b')))
        !          1181:                        return (macplkup('t'));
        !          1182:                else
        !          1183:                        return (macplkup('f'));
        !          1184:          
        !          1185:          case 12:      /* {substr; $f; $t; $s} */
        !          1186:                return (macsstr(macnumber(macplkup('f')), macnumber(macplkup('t')), macplkup('s')));
        !          1187: 
        !          1188:          case 13:      /* {dnl} */
        !          1189:                macdnl();
        !          1190:                break;
        !          1191: 
        !          1192:          default:
        !          1193:                syserr("macro: bad primitive %d", n);
        !          1194:        }
        !          1195: 
        !          1196:        return ("");
        !          1197: }
        !          1198: /*
        !          1199: **  MACDNL -- delete to newline
        !          1200: **
        !          1201: **     Used in general after macro definitions to avoid embarrassing
        !          1202: **     newlines.  Just reads input until a newline character, and
        !          1203: **     then throws it away.
        !          1204: */
        !          1205: 
        !          1206: macdnl()
        !          1207: {
        !          1208:        register char           c;
        !          1209:        register struct env     *e;
        !          1210: 
        !          1211:        e = Macenv;
        !          1212: 
        !          1213:        while ((c = macgch()) != 0 && c != NEWLINE)
        !          1214:                ;
        !          1215: 
        !          1216:        bufflush(&e->mbuf);
        !          1217: }
        !          1218: /*
        !          1219: **  MACDEFINE -- define primitive
        !          1220: **
        !          1221: **     This function defines a macro.  The parameters are the
        !          1222: **     template, the substitution string, and a flag telling whether
        !          1223: **     this is a raw define or not.  Syntax checking is done.
        !          1224: */
        !          1225: 
        !          1226: macdefine(template, subs, raw)
        !          1227: char   *template;
        !          1228: char   *subs;
        !          1229: int    raw;
        !          1230: {
        !          1231:        register struct env     *e;
        !          1232:        char                    paramdefined[128];
        !          1233:        char                    *p;
        !          1234:        register char           c;
        !          1235:        char                    d;
        !          1236:        struct buf              *b;
        !          1237:        register struct macro   *m;
        !          1238:        extern int              macsget();
        !          1239:        extern char             *bufalloc(),*bufcrunch();
        !          1240:        char                    *mactcvt();
        !          1241:        int                     escapech;
        !          1242: 
        !          1243:        /* remove any old macro definition */
        !          1244:        macremove(template);
        !          1245: 
        !          1246:        /* get a new environment */
        !          1247:        macnewev(macsget, &p);
        !          1248:        b = 0;
        !          1249:        e = Macenv;
        !          1250: 
        !          1251:        /* undefine all parameters */
        !          1252:        clrmem(paramdefined, 128);
        !          1253: 
        !          1254:        /* avoid an initial token change */
        !          1255:        e->tokenmode = NOCHANGE;
        !          1256:        escapech = 1;
        !          1257: 
        !          1258:        /* allocate macro header and template */
        !          1259:        m = (struct macro *) bufalloc(sizeof *m);
        !          1260: 
        !          1261:        /* scan and convert template, collect available parameters */
        !          1262:        p = template;
        !          1263:        m->template = mactcvt(raw, paramdefined);
        !          1264:        if (m->template == 0)
        !          1265:        {
        !          1266:                /* some sort of syntax error */
        !          1267:                buffree(m);
        !          1268:                macpopev();
        !          1269:                return;
        !          1270:        }
        !          1271: 
        !          1272:        bufflush(&e->mbuf);
        !          1273:        bufflush(&e->pbuf);
        !          1274:        e->eof = 0;
        !          1275: 
        !          1276:        /* scan substitute string */
        !          1277:        for (p = subs; c = macfetch(0); )
        !          1278:        {
        !          1279:                if (c != '$')
        !          1280:                {
        !          1281:                        /* substitute non-parameters literally */
        !          1282:                        bufput(c & CHARMASK, &b);
        !          1283:                        continue;
        !          1284:                }
        !          1285: 
        !          1286:                /* it's a parameter */
        !          1287:                bufput(PARAMN, &b);
        !          1288:                c = macfetch(0);
        !          1289: 
        !          1290:                /* check to see if name is supplied */
        !          1291:                if (paramdefined[c] == 0)
        !          1292:                {
        !          1293:                        /* nope, it's not */
        !          1294:                        printf("define: parameter %c referenced but not defined\n", c);
        !          1295:                        buffree(m->template);
        !          1296:                        buffree(m);
        !          1297:                        macpopev();
        !          1298:                        bufpurge(&b);
        !          1299:                        return;
        !          1300:                }
        !          1301:                bufput(c & CHARMASK, &b);
        !          1302:        }
        !          1303: 
        !          1304:        /* allocate substitution string */
        !          1305:        m->substitute = bufcrunch(&b);
        !          1306: 
        !          1307:        /* allocate it as a macro */
        !          1308:        m->nextm = Machead;
        !          1309:        Machead = m;
        !          1310: 
        !          1311:        /* finished... */
        !          1312:        macpopev();
        !          1313:        bufpurge(&b);
        !          1314: }
        !          1315: /*
        !          1316: **  MACTCVT -- convert template to internal form
        !          1317: **
        !          1318: **     Converts the template from external form to internal form.
        !          1319: **
        !          1320: **     Parameters:
        !          1321: **     raw -- set if only raw type conversion should take place.
        !          1322: **     paramdefined -- a map of flags to determine declaration of
        !          1323: **             parameters, etc.  If zero, no parameters are allowed.
        !          1324: **
        !          1325: **     Return value:
        !          1326: **     A character pointer off into mystic space.
        !          1327: **
        !          1328: **     The characters of the template are read using macfetch, so
        !          1329: **     a new environment should be created which will arrange to
        !          1330: **     get this.
        !          1331: */
        !          1332: 
        !          1333: char *
        !          1334: mactcvt(raw, paramdefined)
        !          1335: int    raw;
        !          1336: char   paramdefined[128];
        !          1337: {
        !          1338:        register int            c;
        !          1339:        struct buf              *b;
        !          1340:        register char           d;
        !          1341:        register int            escapech;
        !          1342:        char                    *p;
        !          1343: 
        !          1344:        b = 0;
        !          1345:        escapech = 1;
        !          1346: 
        !          1347:        while (c = macfetch(0))
        !          1348:        {
        !          1349:                switch (c)
        !          1350:                {
        !          1351:                  case '$':             /* parameter */
        !          1352:                        if (escapech < 0)
        !          1353:                        {
        !          1354:                                printf("define: every parameter needs a delimiter\n");
        !          1355:                                bufpurge(&b);
        !          1356:                                return (0);
        !          1357:                        }
        !          1358: 
        !          1359:                        /* skip delimiters before parameter in non-raw */
        !          1360:                        if (Macenv->change && !escapech && !raw)
        !          1361:                                bufput(ANYDELIM, &b);
        !          1362: 
        !          1363:                        escapech = 0;
        !          1364:                        c = macfetch(0);
        !          1365:                        d = PARAMN;
        !          1366:                        if (c == '$')
        !          1367:                        {
        !          1368:                                /* prescanned parameter */
        !          1369:                                d = PARAMP;
        !          1370:                                c = macfetch(0);
        !          1371:                        }
        !          1372: 
        !          1373:                        /* process parameter name */
        !          1374:                        if (c == 0)
        !          1375:                        {
        !          1376:                                /* no parameter name */
        !          1377:                                printf("define: null parameter name\n");
        !          1378:                                bufpurge(&b);
        !          1379:                                return (0);
        !          1380:                        }
        !          1381: 
        !          1382:                        bufput(d, &b);
        !          1383:                        escapech = -1;
        !          1384: 
        !          1385:                        /* check for legal parameter */
        !          1386:                        if (paramdefined == 0)
        !          1387:                                break;
        !          1388: 
        !          1389:                        if (paramdefined[c])
        !          1390:                        {
        !          1391:                                printf("define: parameter %c redeclared\n", c);
        !          1392:                                bufpurge(&b);
        !          1393:                                return (0);
        !          1394:                        }
        !          1395:                        paramdefined[c]++;
        !          1396: 
        !          1397:                        /* get parameter delimiter */
        !          1398:                        break;
        !          1399: 
        !          1400:                  case BACKSLASH:               /* a backslash escape */
        !          1401:                        escapech = 1;
        !          1402:                        c = macfetch(0);
        !          1403:                        switch (c)
        !          1404:                        {
        !          1405:                          case '|':
        !          1406:                                c = ANYDELIM;
        !          1407:                                break;
        !          1408: 
        !          1409:                          case '^':
        !          1410:                                c = ONEDELIM;
        !          1411:                                break;
        !          1412: 
        !          1413:                          case '&':
        !          1414:                                c = CHANGE;
        !          1415:                                break;
        !          1416: 
        !          1417:                          default:
        !          1418:                                escapech = 0;
        !          1419:                                c = BACKSLASH;
        !          1420:                                macunget(0);
        !          1421:                                break;
        !          1422:                        }
        !          1423:                        break;
        !          1424: 
        !          1425:                  case NEWLINE | QUOTED:
        !          1426:                  case TAB | QUOTED:
        !          1427:                  case SPACE | QUOTED:
        !          1428:                        if (escapech < 0)
        !          1429:                                c &= CHARMASK;
        !          1430:                        escapech = 1;
        !          1431:                        break;
        !          1432: 
        !          1433:                  default:
        !          1434:                        /* change delimiters to ANYDELIM */
        !          1435:                        if (macmode(c) == DELIM && !raw)
        !          1436:                        {
        !          1437:                                while (macmode(c = macfetch(0)) == DELIM)
        !          1438:                                        ;
        !          1439:                                macunget(0);
        !          1440:                                if (c == 0)
        !          1441:                                        c = ONEDELIM;
        !          1442:                                else
        !          1443:                                        c = ANYDELIM;
        !          1444:                                escapech = 1;
        !          1445:                        }
        !          1446:                        else
        !          1447:                        {
        !          1448:                                if (Macenv->change && !escapech)
        !          1449:                                {
        !          1450:                                        bufput(ANYDELIM, &b);
        !          1451:                                }
        !          1452: 
        !          1453:                                if (escapech < 0)
        !          1454:                                {
        !          1455:                                        /* parameter: don't allow quoted delimiters */
        !          1456:                                        c &= CHARMASK;
        !          1457:                                }
        !          1458:                                escapech = 0;
        !          1459:                        }
        !          1460:                        break;
        !          1461:                }
        !          1462:                bufput(c, &b);
        !          1463:        }
        !          1464:        if (escapech <= 0)
        !          1465:                bufput(CHANGE, &b);
        !          1466: 
        !          1467:        p = bufcrunch(&b);
        !          1468:        bufpurge(&b);
        !          1469:        TRACE("mactcvt: '%s'\n", p);
        !          1470:        return (p);
        !          1471: }
        !          1472: /*
        !          1473: **  MACREMOVE -- remove macro
        !          1474: **
        !          1475: **     The named macro is looked up.  If it is found it is removed
        !          1476: **     from the macro list.
        !          1477: */
        !          1478: 
        !          1479: macremove(name)
        !          1480: char   *name;
        !          1481: {
        !          1482:        register struct macro   *m;
        !          1483:        register struct macro   **mp;
        !          1484:        extern int              macsget();
        !          1485:        char                    *p;
        !          1486:        register char           *cname;
        !          1487:        struct macro            *macmlkup();
        !          1488: 
        !          1489:        if (name != 0)
        !          1490:        {
        !          1491:                /* convert name to internal format */
        !          1492:                macnewev(macsget, &p);
        !          1493:                p = name;
        !          1494:                cname = mactcvt(0, 0);
        !          1495:                macpopev();
        !          1496:                if (cname == 0)
        !          1497:                {
        !          1498:                        /* some sort of syntax error */
        !          1499:                        return;
        !          1500:                }
        !          1501:        }
        !          1502: 
        !          1503:        /* find macro */
        !          1504:        while (name == 0 ? ((m = Machead)->substitute > (char *) NPRIMS) : ((m = macmlkup(cname)) != 0))
        !          1505:        {
        !          1506:                /* remove macro from list */
        !          1507:                mp = &Machead;
        !          1508: 
        !          1509:                /* find it's parent */
        !          1510:                while (*mp != m)
        !          1511:                        mp = &(*mp)->nextm;
        !          1512: 
        !          1513:                /* remove macro from list */
        !          1514:                *mp = m->nextm;
        !          1515:                buffree(m->template);
        !          1516:                buffree(m->substitute);
        !          1517:                buffree(m);
        !          1518:        }
        !          1519:        buffree(cname);
        !          1520: }
        !          1521: /*
        !          1522: **  MACMLKUP -- look up macro
        !          1523: **
        !          1524: **     The named macro is looked up and a pointer to the macro header
        !          1525: **     is returned.  Zero is returned if the macro is not found.
        !          1526: **     The name must be in internal form.
        !          1527: */
        !          1528: 
        !          1529: struct macro *
        !          1530: macmlkup(name)
        !          1531: char   *name;
        !          1532: {
        !          1533:        register struct macro   *m;
        !          1534:        register char           *n;
        !          1535: 
        !          1536:        n = name;
        !          1537: 
        !          1538:        /* scan the macro list for it */
        !          1539:        for (m = Machead; m != 0; m = m->nextm)
        !          1540:        {
        !          1541:                if (macmmatch(n, m->template, 0))
        !          1542:                        return (m);
        !          1543:        }
        !          1544:        return (0);
        !          1545: }
        !          1546: /*
        !          1547: **  MACMMATCH -- check for macro name match
        !          1548: **
        !          1549: **     The given 'name' and 'temp' are compared for equality.  If they
        !          1550: **     match true is returned, else false.
        !          1551: **     Both must be converted to internal format before the call is
        !          1552: **     given.
        !          1553: **
        !          1554: **     "Match" is defined as two macros which might scan as equal.
        !          1555: **
        !          1556: **     'Flag' is set to indicate that the macros must match exactly,
        !          1557: **     that is, neither may have any parameters and must end with both
        !          1558: **     at end-of-template.  This mode is used for getting traps and
        !          1559: **     such.
        !          1560: */
        !          1561: 
        !          1562: macmmatch(name, temp, flag)
        !          1563: char   *name;
        !          1564: char   *temp;
        !          1565: int    flag;
        !          1566: {
        !          1567:        register char   ac;
        !          1568:        register char   bc;
        !          1569:        char            *ap, *bp;
        !          1570: 
        !          1571:        ap = name;
        !          1572:        bp = temp;
        !          1573: 
        !          1574:        /* scan character by character */
        !          1575:        for (;; ap++, bp++)
        !          1576:        {
        !          1577:                ac = *ap;
        !          1578:                bc = *bp;
        !          1579:                TRACE("macmmatch: ac=%c/%u, bc=%c/%u\n", ac, ap, bc, bp);
        !          1580: 
        !          1581:                if (bc == ANYDELIM)
        !          1582:                {
        !          1583:                        if (macmmchew(&ap))
        !          1584:                                continue;
        !          1585:                }
        !          1586:                else
        !          1587:                {
        !          1588:                        switch (ac)
        !          1589:                        {
        !          1590:                          case SPACE:
        !          1591:                          case NEWLINE:
        !          1592:                          case TAB:
        !          1593:                                if (ac == bc || bc == ONEDELIM)
        !          1594:                                        continue;
        !          1595:                                break;
        !          1596: 
        !          1597:                          case ONEDELIM:
        !          1598:                                if (ac == bc || macmode(bc) == DELIM)
        !          1599:                                        continue;
        !          1600:                                break;
        !          1601: 
        !          1602:                          case ANYDELIM:
        !          1603:                                if (macmmchew(&bp))
        !          1604:                                        continue;
        !          1605:                                break;
        !          1606: 
        !          1607:                          case PARAMP:
        !          1608:                          case PARAMN:
        !          1609:                          case 0:
        !          1610:                                if (bc == PARAMN || bc == PARAMP || bc == 0 ||
        !          1611:                                    bc == ANYDELIM || bc == ONEDELIM ||
        !          1612:                                    bc == CHANGE || macmode(bc) == DELIM)
        !          1613:                                {
        !          1614:                                        /* success */
        !          1615:                                        if (!flag)
        !          1616:                                                return (1);
        !          1617:                                        if (ac == 0 && bc == 0)
        !          1618:                                                return (1);
        !          1619:                                }
        !          1620:                                break;
        !          1621: 
        !          1622:                          default:
        !          1623:                                if (ac == bc)
        !          1624:                                        continue;
        !          1625:                                break;
        !          1626:                        }
        !          1627:                }
        !          1628: 
        !          1629:                /* failure */
        !          1630:                return (0);
        !          1631:        }
        !          1632: }
        !          1633: /*
        !          1634: **  MACMMCHEW -- chew nonspecific match characters
        !          1635: **
        !          1636: **     The pointer passed as parameter is scanned so as to skip over
        !          1637: **     delimiters and pseudocharacters.
        !          1638: **     At least one character must match.
        !          1639: */
        !          1640: 
        !          1641: macmmchew(pp)
        !          1642: char   **pp;
        !          1643: {
        !          1644:        register char   *p;
        !          1645:        register char   c;
        !          1646:        register int    matchflag;
        !          1647: 
        !          1648:        p = *pp;
        !          1649: 
        !          1650:        for (matchflag = 0; ; matchflag++)
        !          1651:        {
        !          1652:                c = *p;
        !          1653:                if (c != ANYDELIM && c != ONEDELIM && c != CHANGE &&
        !          1654:                    macmode(c) != DELIM)
        !          1655:                        break;
        !          1656:                p++;
        !          1657:        }
        !          1658: 
        !          1659:        p--;
        !          1660:        if (matchflag == 0)
        !          1661:                return (0);
        !          1662:        *pp = p;
        !          1663:        return (1);
        !          1664: }
        !          1665: /*
        !          1666: **  MACREAD -- read a terminal input line
        !          1667: **
        !          1668: **     Reads one line from the user.  Returns the line into mbuf,
        !          1669: **     and a count of the number of characters read into the macro
        !          1670: **     "{readcount}" (-1 for end of file).
        !          1671: */
        !          1672: 
        !          1673: macread()
        !          1674: {
        !          1675:        register struct env     *e;
        !          1676:        register int            count;
        !          1677:        register char           c;
        !          1678: 
        !          1679:        e = Macenv;
        !          1680:        count = -1;
        !          1681: 
        !          1682:        while ((c = getchar()) > 0)
        !          1683:        {
        !          1684:                count++;
        !          1685:                if (c == NEWLINE)
        !          1686:                        break;
        !          1687:                bufput(c, &e->mbuf);
        !          1688:        }
        !          1689: 
        !          1690:        macdefine("{readcount}", iocv(count), 1);
        !          1691: }
        !          1692: /*
        !          1693: **  MACNUMBER -- return converted number
        !          1694: **
        !          1695: **     This procedure is essentially identical to the system atoi
        !          1696: **     routine, in that it does no syntax checking whatsoever.
        !          1697: */
        !          1698: 
        !          1699: macnumber(s)
        !          1700: char   *s;
        !          1701: {
        !          1702:        register char           *p;
        !          1703:        register char           c;
        !          1704:        register int            result;
        !          1705:        int                     minus;
        !          1706: 
        !          1707:        result = 0;
        !          1708:        p = s;
        !          1709:        minus = 0;
        !          1710: 
        !          1711:        while ((c = *p++) == SPACE)
        !          1712:                ;
        !          1713: 
        !          1714:        if (c == '-')
        !          1715:        {
        !          1716:                minus++;
        !          1717:                while ((c = *p++) == SPACE)
        !          1718:                        ;
        !          1719:        }
        !          1720: 
        !          1721:        while (c >= '0' && c <= '9')
        !          1722:        {
        !          1723:                result = result * 10 + (c - '0');
        !          1724:                c = *p++;
        !          1725:        }
        !          1726: 
        !          1727:        if (minus)
        !          1728:                result = -result;
        !          1729: 
        !          1730:        return (result);
        !          1731: }
        !          1732: /*
        !          1733: **  MACSUBSTR -- substring primitive
        !          1734: **
        !          1735: **     The substring of 'string' from 'from' to 'to' is extracted.
        !          1736: **     A pointer to the result is returned.  Note that macsstr
        !          1737: **     in the general case modifies 'string' in place.
        !          1738: */
        !          1739: 
        !          1740: char *
        !          1741: macsstr(from, to, string)
        !          1742: int    from;
        !          1743: int    to;
        !          1744: char   *string;
        !          1745: {
        !          1746:        register int    f;
        !          1747:        int             l;
        !          1748:        register char   *s;
        !          1749:        register int    t;
        !          1750: 
        !          1751:        s = string;
        !          1752:        t = to;
        !          1753:        f = from;
        !          1754: 
        !          1755:        if (f < 1)
        !          1756:                f = 1;
        !          1757: 
        !          1758:        if (f >= t)
        !          1759:                return ("");
        !          1760:        l = length(s);
        !          1761:        if (t < l)
        !          1762:                s[t] = 0;
        !          1763:        return (&s[f - 1]);
        !          1764: }
        !          1765: /*
        !          1766: **  MACDUMP -- dump a macro definition to the terminal
        !          1767: **
        !          1768: **     All macros matching 'name' are output to the buffer.  If
        !          1769: **     'name' is the null pointer, all macros are printed.
        !          1770: */
        !          1771: 
        !          1772: macdump(name)
        !          1773: char   *name;
        !          1774: {
        !          1775:        register struct macro   *m;
        !          1776:        register char           *p;
        !          1777:        register char           *n;
        !          1778:        extern int              macsget();
        !          1779:        extern char             *macmocv();
        !          1780:        char                    *ptr;
        !          1781: 
        !          1782:        n = name;
        !          1783:        if (n != 0)
        !          1784:        {
        !          1785:                macnewev(macsget, &ptr);
        !          1786:                ptr = n;
        !          1787:                n = mactcvt(0, 0);
        !          1788:                macpopev();
        !          1789:                if (n == 0)
        !          1790:                        return;
        !          1791:        }
        !          1792: 
        !          1793:        for (m = Machead; m != 0; m = m->nextm)
        !          1794:        {
        !          1795:                if (n == 0 || macmmatch(n, m->template, 0))
        !          1796:                {
        !          1797:                        if (m->substitute <= (char *) NPRIMS)
        !          1798:                                continue;
        !          1799:                        p = macmocv(m->template);
        !          1800:                        macload("`{rawdefine; ", 0);
        !          1801:                        macload(p, 0);
        !          1802:                        macload("; ", 0);
        !          1803:                        p = macmocv(m->substitute);
        !          1804:                        macload(p, 0);
        !          1805:                        macload("}'\n", 0);
        !          1806:                }
        !          1807:        }
        !          1808:        if (n != 0)
        !          1809:                buffree(n);
        !          1810: }
        !          1811: /*
        !          1812: **  MACMOCV -- macro output conversion
        !          1813: **
        !          1814: **     This routine converts the internal format of the named macro
        !          1815: **     to an unambigous external representation.
        !          1816: **
        !          1817: **     Note that much work can be done to this routine to make it
        !          1818: **     produce cleaner output, for example, translate "\|" to " "
        !          1819: **     in most cases.
        !          1820: */
        !          1821: 
        !          1822: char *
        !          1823: macmocv(m)
        !          1824: char   *m;
        !          1825: {
        !          1826:        register char   *p;
        !          1827:        struct buf      *b;
        !          1828:        register int    c;
        !          1829:        register int    pc;
        !          1830:        static char     *lastbuf;
        !          1831:        extern char     *bufcrunch();
        !          1832: 
        !          1833:        p = m;
        !          1834: 
        !          1835:        /* release last used buffer (as appropriate) */
        !          1836:        if (lastbuf != 0)
        !          1837:        {
        !          1838:                buffree(lastbuf);
        !          1839:                lastbuf = 0;
        !          1840:        }
        !          1841: 
        !          1842:        if (p <= (char *) NPRIMS)
        !          1843:        {
        !          1844:                /* we have a primitive */
        !          1845:                p = "Primitive xxx";
        !          1846:                itoa(m, &p[10]);
        !          1847:                return (p);
        !          1848:        }
        !          1849: 
        !          1850:        b = 0;
        !          1851: 
        !          1852:        for (; (c = *p++) != 0; pc = c)
        !          1853:        {
        !          1854:                switch (c)
        !          1855:                {
        !          1856:                  case BACKSLASH:
        !          1857:                  case '|':
        !          1858:                  case '&':
        !          1859:                  case '^':
        !          1860:                        break;
        !          1861: 
        !          1862:                  case ANYDELIM:
        !          1863:                        c = '\\|';
        !          1864:                        break;
        !          1865: 
        !          1866:                  case ONEDELIM:
        !          1867:                        c = '\\^';
        !          1868:                        break;
        !          1869: 
        !          1870:                  case CHANGE:
        !          1871:                        c = '\\&';
        !          1872:                        break;
        !          1873: 
        !          1874:                  case PARAMN:
        !          1875:                        c = '$';
        !          1876:                        break;
        !          1877: 
        !          1878:                  case PARAMP:
        !          1879:                        c = '$$';
        !          1880:                        break;
        !          1881: 
        !          1882:                  case '$':
        !          1883:                        c = '\\$';
        !          1884:                        break;
        !          1885: 
        !          1886:                  case NEWLINE:
        !          1887:                        c = ('\\' | QUOTED) | ('\n' << 8);
        !          1888:                        break;
        !          1889: 
        !          1890:                  default:
        !          1891:                        bufput(c, &b);
        !          1892:                        continue;
        !          1893:                }
        !          1894: 
        !          1895:                if (pc == BACKSLASH)
        !          1896:                        bufput(pc, &b);
        !          1897:                pc = c & CHARMASK;
        !          1898:                bufput(pc, &b);
        !          1899:                pc = (c >> 8) & CHARMASK;
        !          1900:                if (pc != 0)
        !          1901:                {
        !          1902:                        c = pc;
        !          1903:                        bufput(c, &b);
        !          1904:                }
        !          1905:        }
        !          1906: 
        !          1907:        p = bufcrunch(&b);
        !          1908:        bufpurge(&b);
        !          1909:        lastbuf = p;
        !          1910:        return (p);
        !          1911: }
        !          1912: /*
        !          1913: **  MACRO -- get macro substitution value
        !          1914: **
        !          1915: **     ***  EXTERNAL INTERFACE  ***
        !          1916: **
        !          1917: **     This routine handles the rather specialized case of looking
        !          1918: **     up a macro and returning the substitution value.  The name
        !          1919: **     must match EXACTLY, character for character.
        !          1920: **
        !          1921: **     The null pointer is returned if the macro is not defined.
        !          1922: */
        !          1923: 
        !          1924: char *
        !          1925: macro(name)
        !          1926: char   *name;
        !          1927: {
        !          1928:        register struct macro   *m;
        !          1929:        register char           *n;
        !          1930:        extern int              macsget();
        !          1931:        char                    *p;
        !          1932: 
        !          1933:        /* convert macro name to internal format */
        !          1934:        macnewev(macsget, &p);
        !          1935:        p = name;
        !          1936:        n = mactcvt(0, 0);
        !          1937:        macpopev();
        !          1938:        if (n == 0)
        !          1939:        {
        !          1940:                /* some sort of syntax error */
        !          1941:                return (0);
        !          1942:        }
        !          1943: 
        !          1944:        for (m = Machead; m != 0; m = m->nextm)
        !          1945:        {
        !          1946:                if (macmmatch(n, m->template, 1))
        !          1947:                {
        !          1948:                        buffree(n);
        !          1949:                        return (m->substitute);
        !          1950:                }
        !          1951:        }
        !          1952: 
        !          1953:        buffree(n);
        !          1954:        return (0);
        !          1955: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.