Annotation of 43BSD/ingres/source/monitor/mac.c, revision 1.1.1.1

1.1       root        1: # include      <useful.h>
                      2: # include      <sccs.h>
                      3: 
                      4: SCCSID(@(#)mac.c       8.1     12/31/84)
                      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.