# 2.11BSD#431 - /usr/ingres/source/monitor/mac.c

##### Functions

    macallscan        X
    macckch           X
    macdefine         X
    macdelim          X
    macdnl            X
    macdump           X
    macfetch          X
    macgch            X
    macgetch          X
    macinit           X
    macload           X
    macmatch          X
    macmlkup          X
    macmmatch         X
    macmmchew         X
    macmocv           X
    macmode           X
    macnewev          X
    macnumber         X
    macparam          X
    macpflush         X
    macplkup          X
    macpopev          X
    macprescan        X
    macprim           X
    macread           X
    macremove         X
    macrescan         X
    macro             X
    macscan           X
    macschng          X
    macsget           X
    macspring         X
    macsstr           X
    macsubs           X
    mactcvt           X
    macunget          X

##### Variables

    Macenv            X
    Machead           X
    Macprims          X

##### Macros

    ANYDELIM          X
    BACKSLASH         X
    BYTEMASK          X
    CHANGE            X
    CHARMASK          X
    DELIM             X
    ID                X
    ITERTHRESH        X
    LBRACE            X
    LQUOTE            X
    NEWLINE           X
    NOCHANGE          X
    NONE              X
    NPRIMS            X
    NUMBER            X
    ONEDELIM          X
    OP                X
    PARAMN            X
    PARAMP            X
    PRESCANENABLE     X
    QUOTED            X
    QUOTEMODE         X
    RBRACE            X
    RQUOTE            X
    SPACE             X
    TAB               X
    TRACE             X

##### struct's

    env               X
    macro             X
    param             X

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

#### Defined functions

macallscan defined in line 567; used 1 times

- in line 232

macckch defined in line 824; used 2 times

- in line 755, 771

macdefine defined in line 1300; used 8 times

- in line 1200-1205(2), 1232, 1787
- in /usr/ingres/source/monitor/go.c line 66
- in /usr/ingres/source/monitor/main.c line 113-115(3)

macdelim defined in line 799; used 2 times

- in line 751, 765

macdnl defined in line 1277; used 6 times

- in line 1199-1209(3), 1215-1220(2), 1257

macdump defined in line 1878; used 1 times

- in line 1216

macfetch defined in line 352; used 9 times

- in line 267, 292, 1352, 1363, 1426, 1443, 1449, 1481, 1516

macgch defined in line 256; used 7 times

- in line 186, 680, 694, 775, 803, 839, 1284

macgetch defined in line 177; used 8 times

- in line 925
- in /usr/ingres/source/monitor/eval.c line 41
- in /usr/ingres/source/monitor/expr.c line 569
- in /usr/ingres/source/monitor/getfilename.c line 29, 37
- in /usr/ingres/source/monitor/go.c line 53
- in /usr/ingres/source/monitor/mcall.c line 59
- in /usr/ingres/source/monitor/trapquery.c line 86

macinit defined in line 132; used 7 times

- in /usr/ingres/source/monitor/branch.c line 38
- in /usr/ingres/source/monitor/eval.c line 40
- in /usr/ingres/source/monitor/getfilename.c line 26
- in /usr/ingres/source/monitor/go.c line 51
- in /usr/ingres/source/monitor/main.c line 112
- in /usr/ingres/source/monitor/mcall.c line 56
- in /usr/ingres/source/monitor/trapquery.c line 84

macload defined in line 1043; used 9 times

- in line 889-894(2), 1060, 1171, 1906-1911(5)

macmatch defined in line 737; used 2 times

- in line 635, 690

macmlkup defined in line 1615; used 2 times

- in line 1569, 1586

macmmatch defined in line 1651; used 3 times

- in line 1626, 1901, 2057

macmmchew defined in line 1734; used 2 times

- in line 1672, 1692

macmocv defined in line 1931; used 3 times

- in line 1886, 1905-1909(2)

macmode defined in line 539; used 7 times

- in line 461, 805, 1514-1516(2), 1687, 1701, 1747

macnewev defined in line 947; used 5 times

- in line 921, 1322, 1574, 1891, 2045

macnumber defined in line 1799; used 6 times

- in line 1242(2), 1248(2), 1254(2)

macparam defined in line 659; used 1 times

- in line 625

macpflush defined in line 990; used 3 times

- in line 146, 977, 1088

macplkup defined in line 1129; used 26 times

- in line 1060, 1200-1210(5), 1216-1254(20)

macpopev defined in line 970; used 7 times

- in line 936, 1343, 1372, 1387, 1577, 1894, 2048

macprescan defined in line 907; used 1 times

- in line 877

macprim defined in line 1187; used 1 times

- in line 889

macread defined in line 1770; used 2 times

- in line 1226-1231(2)

macremove defined in line 1561; used 2 times

- in line 1210, 1319

macrescan defined in line 1076; used 3 times

- in line 577-582(2), 1176

macro defined in line 2036; used 9 times

- in line 1157, 1164
- in /usr/ingres/source/monitor/branch.c line 59
- in /usr/ingres/source/monitor/edit.c line 24, 44
- in /usr/ingres/source/monitor/go.c line 33, 71
- in /usr/ingres/source/monitor/shell.c line 27, 44

macscan defined in line 598; used 1 times

- in line 574

macschng defined in line 450; used 1 times

- in line 426

macsget defined in line 1018; used 12 times

- in line 914, 921, 1312, 1322, 1566, 1574, 1884, 1891, 2041-2045(2)
- in /usr/ingres/source/monitor/mcall.c line 47, 56

macspring defined in line 1152; used 2 times

- in line 162, 195

macsstr defined in line 1844; used 2 times

- in line 1192, 1254

macsubs defined in line 859; used 1 times

- in line 643

mactcvt defined in line 1412; used 5 times

- in line 1316, 1338, 1576, 1893, 2047

macunget defined in line 1101; used 8 times

- in line 220, 322, 684, 784, 810, 841, 1499, 1518

#### Defined variables

Macenv defined in line 112; used 27 times

- in line 142, 153, 182, 262, 359, 458, 612, 672, 830, 840, 866, 922, 957-959(2), 974-978(2), 1051, 1081, 1107, 1134, 1159, 1194, 1282, 1324, 1439, 1527, 1776

Machead defined in line 75; used 8 times

- in line 571, 1383-1384(2), 1586-1589(2), 1624, 1899, 2055

Macprims defined in line 56; used 17 times

- in line 31(2), 58-75(15)

#### Defined struct's

env defined in line 90; used 52 times

- in line 92(2), 112(2), 137-139(6), 179(2), 259(2), 355(2), 453(2), 665(2), 828(2), 863(2), 912(2), 951-954(4), 972(2), 991-993(4), 1047(2), 1078(2), 1104(2), 1155(2), 1190(2), 1280(2), 1305(2), 1772(2)

macro defined in line 48; used 34 times

- in line 50(2), 56(2), 75(2), 569(2), 599-601(4), 860(2), 1311(2), 1334(2), 1564-1569(6), 1615-1618(4), 1629(2), 1881(2), 2039(2)

param defined in line 79; used 16 times

- in line 81(2), 106(2), 667(2), 713(2), 862(2), 994-995(4), 1132(2)

#### Defined macros

ANYDELIM defined in line 9; used 7 times

- in line 1440, 1485, 1522, 1529, 1670, 1700, 1746

BACKSLASH defined in line 19; used 5 times

- in line 323, 404, 410, 1498, 2003

BYTEMASK defined in line 28; used 1 times

- in line 1026

CHANGE defined in line 11; used 4 times

- in line 1493, 1544, 1701, 1746

CHARMASK defined in line 27; used 10 times

- in line 216, 1062, 1083, 1113, 1357, 1376, 1508, 1535, 2005-2007(2)

DELIM defined in line 37; used 8 times

- in line 209, 553, 805, 1514-1516(2), 1687, 1701, 1747

ID defined in line 35; used 2 times

- in line 480, 549

ITERTHRESH defined in line 30; used 1 times

- in line 224

LBRACE defined in line 17; used 1 times

- in line 703

LQUOTE defined in line 20; never used
NEWLINE defined in line 24; used 9 times

- in line 215, 383-384(2), 399, 552, 695, 1284, 1504, 1782

NOCHANGE defined in line 40; used 3 times

- in line 689, 846, 1330

NONE defined in line 34; used 3 times

- in line 832, 1087, 1115

NPRIMS defined in line 31; used 4 times

- in line 886, 1586, 1903, 1950

NUMBER defined in line 36; used 4 times

- in line 479, 486, 510, 551

ONEDELIM defined in line 10; used 6 times

- in line 610, 1489, 1520, 1682, 1700, 1746

OP defined in line 39; used 1 times

- in line 554

PARAMN defined in line 13; used 7 times

- in line 620, 683, 878, 1059, 1362, 1444, 1699

PARAMP defined in line 14; used 5 times

- in line 620, 677, 871, 1448, 1699

PRESCANENABLE defined in line 16; used 1 times

- in line 681

QUOTED defined in line 26; used 7 times

- in line 209, 333, 395-399(2), 423, 546, 1995

QUOTEMODE defined in line 38; used 1 times

- in line 547

RBRACE defined in line 18; used 1 times

- in line 705

RQUOTE defined in line 21; never used
SPACE defined in line 22; used 4 times

- in line 552, 1506, 1811, 1817

TAB defined in line 23; used 3 times

- in line 395, 552, 1505

TRACE defined in line 2; used 17 times

- in line 676, 699, 720, 745, 757-764(3), 770, 776-779(2), 785, 804-811(3), 843, 1548, 1668

Last modified: 1995-02-18 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 3463 |