155845Sbostic /*- 255845Sbostic * Copyright (c) 1992 Henry Spencer. 355845Sbostic * Copyright (c) 1992 The Regents of the University of California. 455845Sbostic * All rights reserved. 555845Sbostic * 655845Sbostic * This code is derived from software contributed to Berkeley by 755845Sbostic * Henry Spencer of the University of Toronto. 855845Sbostic * 955845Sbostic * %sccs.include.redist.c% 1055845Sbostic * 11*56355Sbostic * @(#)engine.c 5.3 (Berkeley) 09/30/92 1255845Sbostic */ 1355845Sbostic 1455845Sbostic /* 1555845Sbostic * The matching engine and friends. This file is #included by regexec.c 1655845Sbostic * after suitable #defines of a variety of macros used herein, so that 1755845Sbostic * different state representations can be used without duplicating masses 1855845Sbostic * of code. 1955845Sbostic */ 2055845Sbostic 2155845Sbostic #ifdef SNAMES 2255845Sbostic #define matcher smatcher 2355845Sbostic #define fast sfast 2455845Sbostic #define slow sslow 2555845Sbostic #define dissect sdissect 2655845Sbostic #define backref sbackref 2755845Sbostic #define expand sexpand 2855845Sbostic #define step sstep 2955845Sbostic #define print sprint 30*56355Sbostic #define at sat 3155845Sbostic #define match smat 3255845Sbostic #endif 3355845Sbostic #ifdef LNAMES 3455845Sbostic #define matcher lmatcher 3555845Sbostic #define fast lfast 3655845Sbostic #define slow lslow 3755845Sbostic #define dissect ldissect 3855845Sbostic #define backref lbackref 3955845Sbostic #define expand lexpand 4055845Sbostic #define step lstep 4155845Sbostic #define print lprint 42*56355Sbostic #define at lat 4355845Sbostic #define match lmat 4455845Sbostic #endif 4555845Sbostic 4655845Sbostic /* another structure passed up and down to avoid zillions of parameters */ 4755845Sbostic struct match { 4855845Sbostic struct re_guts *g; 4955845Sbostic int eflags; 5055845Sbostic regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ 5155845Sbostic uchar *offp; /* offsets work from here */ 5255845Sbostic uchar *beginp; /* start of string -- virtual NUL precedes */ 5355845Sbostic uchar *endp; /* end of string -- virtual NUL here */ 5455845Sbostic uchar *coldp; /* can be no match starting before here */ 5555845Sbostic uchar **lastpos; /* [nplus+1] */ 5655845Sbostic STATEVARS; 5755845Sbostic states st; /* current states */ 5855845Sbostic states fresh; /* states for a fresh start */ 5955845Sbostic states tmp; /* temporary */ 6055845Sbostic states empty; /* empty set of states */ 6155845Sbostic }; 6255845Sbostic 63*56355Sbostic #include "engine.ih" 64*56355Sbostic 65*56355Sbostic #ifdef REDEBUG 66*56355Sbostic #define SP(t, s, c) print(m, t, s, c, stdout) 67*56355Sbostic #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) 68*56355Sbostic #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } 6955845Sbostic #else 7055845Sbostic #define SP(t, s, c) /* nothing */ 71*56355Sbostic #define AT(t, p1, p2, s1, s2) /* nothing */ 72*56355Sbostic #define NOTE(s) /* nothing */ 7355845Sbostic #endif 7455845Sbostic 7555845Sbostic /* 7655845Sbostic - matcher - the actual matching engine 77*56355Sbostic == static int matcher(register struct re_guts *g, uchar *string, \ 78*56355Sbostic == size_t nmatch, regmatch_t pmatch[], int eflags); 7955845Sbostic */ 8055845Sbostic static int /* 0 success, REG_NOMATCH failure */ 8155845Sbostic matcher(g, string, nmatch, pmatch, eflags) 8255845Sbostic register struct re_guts *g; 8355845Sbostic uchar *string; 8455845Sbostic size_t nmatch; 8555845Sbostic regmatch_t pmatch[]; 8655845Sbostic int eflags; 8755845Sbostic { 8855845Sbostic register uchar *endp; 8955845Sbostic register int i; 9055845Sbostic struct match mv; 9155845Sbostic register struct match *m = &mv; 9255845Sbostic register uchar *dp; 9355845Sbostic const register sopno gf = g->firststate+1; /* +1 for OEND */ 9455845Sbostic const register sopno gl = g->laststate; 9555845Sbostic uchar *start; 9655845Sbostic uchar *stop; 9755845Sbostic 98*56355Sbostic /* simplify the situation where possible */ 9955845Sbostic if (g->cflags®_NOSUB) 100*56355Sbostic nmatch = 0; 10155845Sbostic if (eflags®_STARTEND) { 10255845Sbostic start = string + pmatch[0].rm_so; 10355845Sbostic stop = string + pmatch[0].rm_eo; 10455845Sbostic } else { 10555845Sbostic start = string; 10655845Sbostic stop = start + strlen((char *)start); 10755845Sbostic } 10855845Sbostic 10955882Sbostic /* prescreening; this does wonders for this rather slow code */ 11055882Sbostic if (g->must != NULL) { 11155882Sbostic for (dp = start; dp < stop; dp++) 11255882Sbostic if (*dp == (uchar)g->must[0] && stop - dp >= g->mlen && 11355882Sbostic strncmp((char *)dp, g->must, (size_t)g->mlen) == 0) 11455882Sbostic break; 11555882Sbostic if (dp == stop) /* we didn't find g->must */ 11655882Sbostic return(REG_NOMATCH); 11755882Sbostic } 11855882Sbostic 11955845Sbostic /* match struct setup */ 12055845Sbostic m->g = g; 12155845Sbostic m->eflags = eflags; 12255845Sbostic m->pmatch = NULL; 12355845Sbostic m->lastpos = NULL; 12455845Sbostic m->offp = string; 12555845Sbostic m->beginp = start; 12655845Sbostic m->endp = stop; 12755845Sbostic STATESETUP(m, 4); 12855845Sbostic SETUP(m->st); 12955845Sbostic SETUP(m->fresh); 13055845Sbostic SETUP(m->tmp); 13155845Sbostic SETUP(m->empty); 13255845Sbostic CLEAR(m->empty); 13355845Sbostic 13455845Sbostic /* this loop does only one repetition except for backrefs */ 13555845Sbostic for (;;) { 13655845Sbostic endp = fast(m, start, stop, gf, gl); 13755845Sbostic if (endp == NULL) { /* a miss */ 13855845Sbostic STATETEARDOWN(m); 13955845Sbostic return(REG_NOMATCH); 14055845Sbostic } 14155845Sbostic if (nmatch == 0 && !g->backrefs) 14255845Sbostic break; /* no further info needed */ 14355845Sbostic 14455845Sbostic /* where? */ 14555845Sbostic assert(m->coldp != NULL); 14655845Sbostic for (;;) { 147*56355Sbostic NOTE("finding start"); 14855845Sbostic endp = slow(m, m->coldp, stop, gf, gl); 14955845Sbostic if (endp != NULL) 15055845Sbostic break; 151*56355Sbostic assert(m->coldp < m->endp); 15255845Sbostic m->coldp++; 15355845Sbostic } 15455845Sbostic if (nmatch == 1 && !g->backrefs) 15555845Sbostic break; /* no further info needed */ 15655845Sbostic 15755845Sbostic /* oh my, he wants the subexpressions... */ 15855845Sbostic if (m->pmatch == NULL) 15955845Sbostic m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * 16055845Sbostic sizeof(regmatch_t)); 16155845Sbostic if (m->pmatch == NULL) { 16255845Sbostic STATETEARDOWN(m); 16355845Sbostic return(REG_ESPACE); 16455845Sbostic } 165*56355Sbostic for (i = 1; i <= m->g->nsub; i++) 166*56355Sbostic m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; 167*56355Sbostic if (!g->backrefs && !(m->eflags®_BACKR)) { 168*56355Sbostic NOTE("dissecting"); 16955845Sbostic dp = dissect(m, m->coldp, endp, gf, gl); 170*56355Sbostic } else { 17155845Sbostic if (g->nplus > 0 && m->lastpos == NULL) 17255845Sbostic m->lastpos = (uchar **)malloc((g->nplus+1) * 17355845Sbostic sizeof(uchar *)); 17455845Sbostic if (g->nplus > 0 && m->lastpos == NULL) { 17555845Sbostic free(m->pmatch); 17655845Sbostic STATETEARDOWN(m); 17755845Sbostic return(REG_ESPACE); 17855845Sbostic } 179*56355Sbostic NOTE("backref dissect"); 18055845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 18155845Sbostic } 18255845Sbostic if (dp != NULL) 18355845Sbostic break; 18455845Sbostic 18555845Sbostic /* uh-oh... we couldn't find a subexpression-level match */ 18655845Sbostic assert(g->backrefs); /* must be back references doing it */ 18755845Sbostic assert(g->nplus == 0 || m->lastpos != NULL); 188*56355Sbostic for (;;) { 189*56355Sbostic if (dp != NULL || endp <= m->coldp) 190*56355Sbostic break; /* defeat */ 191*56355Sbostic NOTE("backoff"); 192*56355Sbostic endp = slow(m, m->coldp, endp-1, gf, gl); 193*56355Sbostic if (endp == NULL) 194*56355Sbostic break; /* defeat */ 19555845Sbostic /* try it on a shorter possibility */ 196*56355Sbostic #ifndef NDEBUG 19755845Sbostic for (i = 1; i <= m->g->nsub; i++) { 198*56355Sbostic assert(m->pmatch[i].rm_so == -1); 199*56355Sbostic assert(m->pmatch[i].rm_eo == -1); 20055845Sbostic } 201*56355Sbostic #endif 202*56355Sbostic NOTE("backoff dissect"); 20355845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 20455845Sbostic } 20555845Sbostic assert(dp == NULL || dp == endp); 20655845Sbostic if (dp != NULL) /* found a shorter one */ 20755845Sbostic break; 20855845Sbostic 20955845Sbostic /* despite initial appearances, there is no match here */ 210*56355Sbostic NOTE("false alarm"); 21155845Sbostic start = m->coldp + 1; /* recycle starting later */ 21255845Sbostic assert(start <= stop); 21355845Sbostic } 21455845Sbostic 21555845Sbostic /* fill in the details if requested */ 21655845Sbostic if (nmatch > 0) { 21755845Sbostic pmatch[0].rm_so = m->coldp - m->offp; 21855845Sbostic pmatch[0].rm_eo = endp - m->offp; 21955845Sbostic } 22055845Sbostic if (nmatch > 1) { 22155845Sbostic assert(m->pmatch != NULL); 22255845Sbostic for (i = 1; i < nmatch; i++) 22355845Sbostic if (i <= m->g->nsub) 22455845Sbostic pmatch[i] = m->pmatch[i]; 22555845Sbostic else { 22655845Sbostic pmatch[i].rm_so = -1; 22755845Sbostic pmatch[i].rm_eo = -1; 22855845Sbostic } 22955845Sbostic } 23055845Sbostic 23155845Sbostic if (m->pmatch != NULL) 23255845Sbostic free((char *)m->pmatch); 23355845Sbostic if (m->lastpos != NULL) 23455845Sbostic free((char *)m->lastpos); 23555845Sbostic STATETEARDOWN(m); 23655845Sbostic return(0); 23755845Sbostic } 23855845Sbostic 23955845Sbostic /* 24055845Sbostic - dissect - figure out what matched what, no back references 241*56355Sbostic == static uchar *dissect(register struct match *m, uchar *start, \ 242*56355Sbostic == uchar *stop, sopno startst, sopno stopst); 24355845Sbostic */ 24455845Sbostic static uchar * /* == stop (success) always */ 24555845Sbostic dissect(m, start, stop, startst, stopst) 24655845Sbostic register struct match *m; 24755845Sbostic uchar *start; 24855845Sbostic uchar *stop; 24955845Sbostic sopno startst; 25055845Sbostic sopno stopst; 25155845Sbostic { 25255845Sbostic register int i; 25355845Sbostic register sopno ss; /* start sop of current subRE */ 25455845Sbostic register sopno es; /* end sop of current subRE */ 25555845Sbostic register uchar *sp; /* start of string matched by it */ 25655845Sbostic register uchar *stp; /* string matched by it cannot pass here */ 25755845Sbostic register uchar *rest; /* start of rest of string */ 25855845Sbostic register uchar *tail; /* string unmatched by rest of RE */ 25955845Sbostic register sopno ssub; /* start sop of subsubRE */ 26055845Sbostic register sopno esub; /* end sop of subsubRE */ 26155845Sbostic register uchar *ssp; /* start of string matched by subsubRE */ 26255845Sbostic register uchar *sep; /* end of string matched by subsubRE */ 26355845Sbostic register uchar *oldssp; /* previous ssp */ 26455845Sbostic register uchar *dp; 26555845Sbostic 266*56355Sbostic AT("diss", start, stop, startst, stopst); 26755845Sbostic sp = start; 26855845Sbostic for (ss = startst; ss < stopst; ss = es) { 26955845Sbostic /* identify end of subRE */ 27055845Sbostic es = ss; 27155845Sbostic switch (OP(m->g->strip[es])) { 27255845Sbostic case OPLUS_: 27355845Sbostic case OQUEST_: 27455845Sbostic es += OPND(m->g->strip[es]); 27555845Sbostic break; 27655845Sbostic case OCH_: 27755845Sbostic while (OP(m->g->strip[es]) != O_CH) 27855845Sbostic es += OPND(m->g->strip[es]); 27955845Sbostic break; 28055845Sbostic } 28155845Sbostic es++; 28255845Sbostic 28355845Sbostic /* figure out what it matched */ 28455845Sbostic switch (OP(m->g->strip[ss])) { 28555845Sbostic case OEND: 28655845Sbostic assert(0); 28755845Sbostic break; 28855845Sbostic case OCHAR: 28955845Sbostic sp++; 29055845Sbostic break; 29155845Sbostic case OBOL: 29255845Sbostic case OEOL: 29355845Sbostic break; 29455845Sbostic case OANY: 29555845Sbostic case OANYOF: 29655845Sbostic sp++; 29755845Sbostic break; 29855845Sbostic case OBACK_: 29955845Sbostic case O_BACK: 30055845Sbostic assert(0); 30155845Sbostic break; 30255845Sbostic /* cases where length of match is hard to find */ 30355845Sbostic case OQUEST_: 30455845Sbostic stp = stop; 30555845Sbostic for (;;) { 30655845Sbostic /* how long could this one be? */ 30755845Sbostic rest = slow(m, sp, stp, ss, es); 30855845Sbostic assert(rest != NULL); /* it did match */ 30955845Sbostic /* could the rest match the rest? */ 31055845Sbostic tail = slow(m, rest, stop, es, stopst); 31155845Sbostic if (tail == stop) 31255845Sbostic break; /* yes! */ 31355845Sbostic /* no -- try a shorter match for this one */ 31455845Sbostic stp = rest - 1; 31555845Sbostic assert(stp >= sp); /* it did work */ 31655845Sbostic } 31755845Sbostic ssub = ss + 1; 31855845Sbostic esub = es - 1; 31955845Sbostic /* did innards match? */ 32055845Sbostic if (slow(m, sp, rest, ssub, esub) != NULL) { 32155845Sbostic dp = dissect(m, sp, rest, ssub, esub); 32255845Sbostic assert(dp == rest); 32355845Sbostic } else /* no */ 32455845Sbostic assert(sp == rest); 32555845Sbostic sp = rest; 32655845Sbostic break; 32755845Sbostic case OPLUS_: 32855845Sbostic stp = stop; 32955845Sbostic for (;;) { 33055845Sbostic /* how long could this one be? */ 33155845Sbostic rest = slow(m, sp, stp, ss, es); 33255845Sbostic assert(rest != NULL); /* it did match */ 33355845Sbostic /* could the rest match the rest? */ 33455845Sbostic tail = slow(m, rest, stop, es, stopst); 33555845Sbostic if (tail == stop) 33655845Sbostic break; /* yes! */ 33755845Sbostic /* no -- try a shorter match for this one */ 33855845Sbostic stp = rest - 1; 33955845Sbostic assert(stp >= sp); /* it did work */ 34055845Sbostic } 34155845Sbostic ssub = ss + 1; 34255845Sbostic esub = es - 1; 34355845Sbostic ssp = sp; 34455845Sbostic oldssp = ssp; 34555845Sbostic for (;;) { /* find last match of innards */ 34655845Sbostic sep = slow(m, ssp, rest, ssub, esub); 34755845Sbostic if (sep == NULL || sep == ssp) 34855845Sbostic break; /* failed or matched null */ 34955845Sbostic oldssp = ssp; /* on to next try */ 35055845Sbostic ssp = sep; 35155845Sbostic } 35255845Sbostic if (sep == NULL) { 35355845Sbostic /* last successful match */ 35455845Sbostic sep = ssp; 35555845Sbostic ssp = oldssp; 35655845Sbostic } 35755845Sbostic assert(sep == rest); /* must exhaust substring */ 35855845Sbostic assert(slow(m, ssp, sep, ssub, esub) == rest); 35955845Sbostic dp = dissect(m, ssp, sep, ssub, esub); 36055845Sbostic assert(dp == sep); 36155845Sbostic sp = rest; 36255845Sbostic break; 36355845Sbostic case OCH_: 36455845Sbostic stp = stop; 36555845Sbostic for (;;) { 36655845Sbostic /* how long could this one be? */ 36755845Sbostic rest = slow(m, sp, stp, ss, es); 36855845Sbostic assert(rest != NULL); /* it did match */ 36955845Sbostic /* could the rest match the rest? */ 37055845Sbostic tail = slow(m, rest, stop, es, stopst); 37155845Sbostic if (tail == stop) 37255845Sbostic break; /* yes! */ 37355845Sbostic /* no -- try a shorter match for this one */ 37455845Sbostic stp = rest - 1; 37555845Sbostic assert(stp >= sp); /* it did work */ 37655845Sbostic } 37755845Sbostic ssub = ss + 1; 37855845Sbostic esub = ss + OPND(m->g->strip[ss]) - 1; 37955845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 38055845Sbostic for (;;) { /* find first matching branch */ 38155845Sbostic if (slow(m, sp, rest, ssub, esub) == rest) 38255845Sbostic break; /* it matched all of it */ 38355845Sbostic /* that one missed, try next one */ 38455845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 38555845Sbostic esub++; 38655845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 38755845Sbostic ssub = esub + 1; 38855845Sbostic esub += OPND(m->g->strip[esub]); 38955845Sbostic if (OP(m->g->strip[esub]) == OOR2) 39055845Sbostic esub--; 39155845Sbostic else 39255845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 39355845Sbostic } 39455845Sbostic dp = dissect(m, sp, rest, ssub, esub); 39555845Sbostic assert(dp == rest); 39655845Sbostic sp = rest; 39755845Sbostic break; 39855845Sbostic case O_PLUS: 39955845Sbostic case O_QUEST: 40055845Sbostic case OOR1: 40155845Sbostic case OOR2: 40255845Sbostic case O_CH: 40355845Sbostic assert(0); 40455845Sbostic break; 40555845Sbostic case OLPAREN: 40655845Sbostic i = OPND(m->g->strip[ss]); 40755845Sbostic m->pmatch[i].rm_so = sp - m->offp; 40855845Sbostic break; 40955845Sbostic case ORPAREN: 41055845Sbostic i = OPND(m->g->strip[ss]); 41155845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 41255845Sbostic break; 41355845Sbostic default: /* uh oh */ 41455845Sbostic assert(0); 41555845Sbostic break; 41655845Sbostic } 41755845Sbostic } 41855845Sbostic 41955845Sbostic assert(sp == stop); 42055845Sbostic return(sp); 42155845Sbostic } 42255845Sbostic 42355845Sbostic /* 42455845Sbostic - backref - figure out what matched what, figuring in back references 425*56355Sbostic == static uchar *backref(register struct match *m, uchar *start, \ 426*56355Sbostic == uchar *stop, sopno startst, sopno stopst, sopno lev); 42755845Sbostic */ 42855845Sbostic static uchar * /* == stop (success) or NULL (failure) */ 42955845Sbostic backref(m, start, stop, startst, stopst, lev) 43055845Sbostic register struct match *m; 43155845Sbostic uchar *start; 43255845Sbostic uchar *stop; 43355845Sbostic sopno startst; 43455845Sbostic sopno stopst; 43555845Sbostic sopno lev; /* PLUS nesting level */ 43655845Sbostic { 43755845Sbostic register int i; 43855845Sbostic register sopno ss; /* start sop of current subRE */ 43955845Sbostic register uchar *sp; /* start of string matched by it */ 44055845Sbostic register sopno ssub; /* start sop of subsubRE */ 44155845Sbostic register sopno esub; /* end sop of subsubRE */ 44255845Sbostic register uchar *ssp; /* start of string matched by subsubRE */ 44355845Sbostic register uchar *dp; 44455845Sbostic register size_t len; 44555845Sbostic register int hard; 44655845Sbostic register sop s; 44755845Sbostic register regoff_t offsave; 44855845Sbostic register cset *cs; 44955845Sbostic 450*56355Sbostic AT("back", start, stop, startst, stopst); 45155845Sbostic sp = start; 45255845Sbostic 45355845Sbostic /* get as far as we can with easy stuff */ 45455845Sbostic hard = 0; 45555845Sbostic for (ss = startst; !hard && ss < stopst; ss++) 45655845Sbostic switch (OP(s = m->g->strip[ss])) { 45755845Sbostic case OCHAR: 45855845Sbostic if (sp == stop || *sp++ != OPND(s)) 45955845Sbostic return(NULL); 46055845Sbostic break; 46155845Sbostic case OANY: 46255845Sbostic if (sp == stop) 46355845Sbostic return(NULL); 46455845Sbostic sp++; 46555845Sbostic break; 46655845Sbostic case OANYOF: 46755845Sbostic cs = &m->g->sets[OPND(s)]; 46855845Sbostic if (sp == stop || !CHIN(cs, *sp++)) 46955845Sbostic return(NULL); 47055845Sbostic break; 47155845Sbostic case OBOL: 47255845Sbostic if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 47355845Sbostic (sp < m->endp && *(sp-1) == '\n' && 47455845Sbostic (m->g->cflags®_NEWLINE)) ) 47555845Sbostic { /* yes */ } 47655845Sbostic else 47755845Sbostic return(NULL); 47855845Sbostic break; 47955845Sbostic case OEOL: 48055845Sbostic if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || 48155845Sbostic (sp < m->endp && *sp == '\n' && 48255845Sbostic (m->g->cflags®_NEWLINE)) ) 48355845Sbostic { /* yes */ } 48455845Sbostic else 48555845Sbostic return(NULL); 48655845Sbostic break; 48755845Sbostic case O_QUEST: 48855845Sbostic break; 48955845Sbostic case OOR1: /* matches null but needs to skip */ 49055845Sbostic ss++; 49155845Sbostic s = m->g->strip[ss]; 49255845Sbostic do { 49355845Sbostic assert(OP(s) == OOR2); 49455845Sbostic ss += OPND(s); 49555845Sbostic } while (OP(s = m->g->strip[ss]) != O_CH); 49655845Sbostic /* note that the ss++ gets us past the O_CH */ 49755845Sbostic break; 49855845Sbostic default: /* have to make a choice */ 49955845Sbostic hard = 1; 50055845Sbostic break; 50155845Sbostic } 50255845Sbostic if (!hard) { /* that was it! */ 50355845Sbostic if (sp != stop) 50455845Sbostic return(NULL); 50555845Sbostic return(sp); 50655845Sbostic } 50755845Sbostic ss--; /* adjust for the for's final increment */ 50855845Sbostic 50955845Sbostic /* the hard stuff */ 510*56355Sbostic AT("hard", sp, stop, ss, stopst); 51155845Sbostic s = m->g->strip[ss]; 51255845Sbostic switch (OP(s)) { 51355845Sbostic case OBACK_: /* the vilest depths */ 51455845Sbostic i = OPND(s); 51555845Sbostic if (m->pmatch[i].rm_eo == -1) 51655845Sbostic return(NULL); 51755845Sbostic assert(m->pmatch[i].rm_so != -1); 51855845Sbostic len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; 51955845Sbostic assert(stop - m->beginp >= len); 52055845Sbostic if (sp > stop - len) 52155845Sbostic return(NULL); /* not enough left to match */ 52255845Sbostic ssp = m->offp + m->pmatch[i].rm_so; 52355845Sbostic if (strncmp((char *)sp, (char *)ssp, len) != 0) 52455845Sbostic return(NULL); 52555845Sbostic while (m->g->strip[ss] != SOP(O_BACK, i)) 52655845Sbostic ss++; 52755845Sbostic return(backref(m, sp+len, stop, ss+1, stopst, lev)); 52855845Sbostic break; 52955845Sbostic case OQUEST_: /* to null or not */ 53055845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 53155845Sbostic if (dp != NULL) 53255845Sbostic return(dp); /* not */ 53355845Sbostic return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); 53455845Sbostic break; 53555845Sbostic case OPLUS_: 53655845Sbostic assert(m->lastpos != NULL); 53755845Sbostic assert(lev+1 <= m->g->nplus); 53855845Sbostic m->lastpos[lev+1] = sp; 53955845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev+1)); 54055845Sbostic break; 54155845Sbostic case O_PLUS: 54255845Sbostic if (sp == m->lastpos[lev]) /* last pass matched null */ 54355845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 54455845Sbostic /* try another pass */ 54555845Sbostic m->lastpos[lev] = sp; 54655845Sbostic dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); 54755845Sbostic if (dp == NULL) 54855845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 54955845Sbostic else 55055845Sbostic return(dp); 55155845Sbostic break; 55255845Sbostic case OCH_: /* find the right one, if any */ 55355845Sbostic ssub = ss + 1; 55455845Sbostic esub = ss + OPND(s) - 1; 55555845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 55655845Sbostic for (;;) { /* find first matching branch */ 55755845Sbostic dp = backref(m, sp, stop, ssub, esub, lev); 55855845Sbostic if (dp != NULL) 55955845Sbostic return(dp); 56055845Sbostic /* that one missed, try next one */ 56155845Sbostic if (OP(m->g->strip[esub]) == O_CH) 56255845Sbostic return(NULL); /* there is none */ 56355845Sbostic esub++; 56455845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 56555845Sbostic ssub = esub + 1; 56655845Sbostic esub += OPND(m->g->strip[esub]); 56755845Sbostic if (OP(m->g->strip[esub]) == OOR2) 56855845Sbostic esub--; 56955845Sbostic else 57055845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 57155845Sbostic } 57255845Sbostic break; 57355845Sbostic case OLPAREN: /* must undo assignment if rest fails */ 57455845Sbostic i = OPND(s); 57555845Sbostic offsave = m->pmatch[i].rm_so; 57655845Sbostic m->pmatch[i].rm_so = sp - m->offp; 57755845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 57855845Sbostic if (dp != NULL) 57955845Sbostic return(dp); 58055845Sbostic m->pmatch[i].rm_so = offsave; 58155845Sbostic return(NULL); 58255845Sbostic break; 58355845Sbostic case ORPAREN: /* must undo assignment if rest fails */ 58455845Sbostic i = OPND(s); 58555845Sbostic offsave = m->pmatch[i].rm_eo; 58655845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 58755845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 58855845Sbostic if (dp != NULL) 58955845Sbostic return(dp); 59055845Sbostic m->pmatch[i].rm_eo = offsave; 59155845Sbostic return(NULL); 59255845Sbostic break; 59355845Sbostic default: /* uh oh */ 59455845Sbostic assert(0); 59555845Sbostic break; 59655845Sbostic } 59755845Sbostic 59855845Sbostic /* "can't happen" */ 59955845Sbostic assert(0); 60055845Sbostic /* NOTREACHED */ 60155845Sbostic } 60255845Sbostic 60355845Sbostic /* 60455845Sbostic - fast - step through the string at top speed 605*56355Sbostic == static uchar *fast(register struct match *m, uchar *start, \ 606*56355Sbostic == uchar *stop, sopno startst, sopno stopst); 60755845Sbostic */ 60855845Sbostic static uchar * /* where tentative match ended, or NULL */ 60955845Sbostic fast(m, start, stop, startst, stopst) 61055845Sbostic register struct match *m; 61155845Sbostic uchar *start; 61255845Sbostic uchar *stop; 61355845Sbostic sopno startst; 61455845Sbostic sopno stopst; 61555845Sbostic { 61655845Sbostic register states st = m->st; 61755845Sbostic register states fresh = m->fresh; 61855845Sbostic register states tmp = m->tmp; 61955845Sbostic register uchar *p = start; 620*56355Sbostic register uchar c = (start == m->beginp) ? '\0' : *(start-1); 62155845Sbostic register uchar lastc; /* previous c */ 62255845Sbostic register int atbol; 62355845Sbostic register int ateol; 62455845Sbostic register uchar *coldp; /* last p after which no match was underway */ 62555845Sbostic 62655845Sbostic CLEAR(st); 62755845Sbostic SET1(st, startst); 62855845Sbostic st = expand(m->g, startst, stopst, st, 0, 0); 62955845Sbostic ASSIGN(fresh, st); 63055845Sbostic SP("start", st, *p); 63155845Sbostic coldp = NULL; 63255845Sbostic for (;;) { 63355845Sbostic /* next character */ 63455845Sbostic lastc = c; 63555845Sbostic c = (p == m->endp) ? '\0' : *p; 63655845Sbostic if (EQ(st, fresh)) 63755845Sbostic coldp = p; 63855845Sbostic 63955845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 64055845Sbostic atbol = ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 64155845Sbostic (lastc == '\0' && !(m->eflags®_NOTBOL)) ); 64255845Sbostic ateol = ( (c == '\n' && m->g->cflags®_NEWLINE) || 64355845Sbostic (c == '\0' && !(m->eflags®_NOTEOL)) ); 64455845Sbostic if (atbol || ateol) { 64555845Sbostic st = expand(m->g, startst, stopst, st, atbol, ateol); 64655845Sbostic SP("bef", st, c); 64755845Sbostic } 64855845Sbostic 64955845Sbostic /* are we done? */ 65055845Sbostic if (ISSET(st, stopst) || p == stop) 65155845Sbostic break; /* NOTE BREAK OUT */ 65255845Sbostic 65355845Sbostic /* no, we must deal with this character */ 65455845Sbostic ASSIGN(tmp, st); 65555845Sbostic ASSIGN(st, fresh); 65655845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 65755845Sbostic SP("aft", st, c); 65855845Sbostic assert(EQ(expand(m->g, startst, stopst, st, 0, 0), st)); 65955845Sbostic p++; 66055845Sbostic } 66155845Sbostic 66255845Sbostic assert(coldp != NULL); 66355845Sbostic m->coldp = coldp; 66455845Sbostic if (ISSET(st, stopst)) 66555845Sbostic return(p+1); 66655845Sbostic else 66755845Sbostic return(NULL); 66855845Sbostic } 66955845Sbostic 67055845Sbostic /* 67155845Sbostic - slow - step through the string more deliberately 672*56355Sbostic == static uchar *slow(register struct match *m, uchar *start, \ 673*56355Sbostic == uchar *stop, sopno startst, sopno stopst); 67455845Sbostic */ 67555845Sbostic static uchar * /* where it ended */ 67655845Sbostic slow(m, start, stop, startst, stopst) 67755845Sbostic register struct match *m; 67855845Sbostic uchar *start; 67955845Sbostic uchar *stop; 68055845Sbostic sopno startst; 68155845Sbostic sopno stopst; 68255845Sbostic { 68355845Sbostic register states st = m->st; 68455845Sbostic register states empty = m->empty; 68555845Sbostic register states tmp = m->tmp; 68655845Sbostic register uchar *p = start; 68755845Sbostic register uchar c = (start == m->beginp) ? '\0' : *(start-1); 68855845Sbostic register uchar lastc; /* previous c */ 68955845Sbostic register int atbol; 69055845Sbostic register int ateol; 69155845Sbostic register uchar *matchp; /* last p at which a match ended */ 69255845Sbostic 693*56355Sbostic AT("slow", start, stop, startst, stopst); 69455845Sbostic CLEAR(st); 69555845Sbostic SET1(st, startst); 69655845Sbostic SP("sstart", st, *p); 69755845Sbostic matchp = NULL; 69855845Sbostic for (;;) { 69955845Sbostic /* next character */ 70055845Sbostic lastc = c; 70155845Sbostic c = (p == m->endp) ? '\0' : *p; 70255845Sbostic 70355845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 70455845Sbostic atbol = ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 70555845Sbostic (lastc == '\0' && !(m->eflags®_NOTBOL)) ); 70655845Sbostic ateol = ( (c == '\n' && m->g->cflags®_NEWLINE) || 70755845Sbostic (c == '\0' && !(m->eflags®_NOTEOL)) ); 70855845Sbostic 70955845Sbostic /* do we need an expansion before looking at the char? */ 71055845Sbostic if (p == start || atbol || ateol) { 71155845Sbostic st = expand(m->g, startst, stopst, st, atbol, ateol); 71255845Sbostic SP("sbef", st, c); 71355845Sbostic } 71455845Sbostic 71555845Sbostic /* are we done? */ 71655845Sbostic if (ISSET(st, stopst)) 71755845Sbostic matchp = p; 71855845Sbostic if (EQ(st, empty) || p == stop) 71955845Sbostic break; /* NOTE BREAK OUT */ 72055845Sbostic 72155845Sbostic /* no, we must deal with this character */ 72255845Sbostic ASSIGN(tmp, st); 72355845Sbostic ASSIGN(st, empty); 72455845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 72555845Sbostic SP("saft", st, c); 72655845Sbostic assert(EQ(expand(m->g, startst, stopst, st, 0, 0), st)); 72755845Sbostic p++; 72855845Sbostic } 72955845Sbostic 73055845Sbostic return(matchp); 73155845Sbostic } 73255845Sbostic 73355845Sbostic 73455845Sbostic /* 73555845Sbostic - expand - return set of states reachable from an initial set 736*56355Sbostic == static states expand(register struct re_guts *g, int start, \ 737*56355Sbostic == int stop, register states st, int atbol, int ateol); 73855845Sbostic */ 73955845Sbostic static states 74055845Sbostic expand(g, start, stop, st, atbol, ateol) 74155845Sbostic register struct re_guts *g; 74255845Sbostic int start; /* start state within strip */ 74355845Sbostic int stop; /* state after stop state within strip */ 74455845Sbostic register states st; 74555845Sbostic int atbol; /* at start or just after \n? (for BOL) */ 74655845Sbostic int ateol; /* just before \n or \0? (for EOL) */ 74755845Sbostic { 74855845Sbostic register sop s; 74955845Sbostic register sopno pc; 75055845Sbostic register onestate here; /* note, macros know this name */ 75155845Sbostic register sopno look; 75255845Sbostic register int i; 75355845Sbostic 75455845Sbostic for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { 75555845Sbostic s = g->strip[pc]; 75655845Sbostic switch (OP(s)) { 75755845Sbostic case OEND: 75855845Sbostic assert(pc == stop-1); 75955845Sbostic break; 76055845Sbostic case OCHAR: /* can't get past this */ 76155845Sbostic break; 76255845Sbostic case OBOL: 76355845Sbostic if (atbol) 76455845Sbostic FWD(st, st, 1); 76555845Sbostic break; 76655845Sbostic case OEOL: 76755845Sbostic if (ateol) 76855845Sbostic FWD(st, st, 1); 76955845Sbostic break; 77055845Sbostic case OANY: /* can't get past this either */ 77155845Sbostic break; 77255845Sbostic case OANYOF: /* or this */ 77355845Sbostic break; 77455845Sbostic case OBACK_: /* not significant here */ 77555845Sbostic case O_BACK: 77655845Sbostic FWD(st, st, 1); 77755845Sbostic break; 77855845Sbostic case OPLUS_: /* forward, this is just an empty */ 77955845Sbostic FWD(st, st, 1); 78055845Sbostic break; 78155845Sbostic case O_PLUS: /* both forward and back */ 78255845Sbostic FWD(st, st, 1); 78355845Sbostic i = ISSETBACK(st, OPND(s)); 78455845Sbostic BACK(st, st, OPND(s)); 78555845Sbostic if (!i && ISSETBACK(st, OPND(s))) { 78655845Sbostic /* oho, must reconsider loop body */ 78755845Sbostic pc -= OPND(s) + 1; 78855845Sbostic INIT(here, pc); 78955845Sbostic } 79055845Sbostic break; 79155845Sbostic case OQUEST_: /* two branches, both forward */ 79255845Sbostic FWD(st, st, 1); 79355845Sbostic FWD(st, st, OPND(s)); 79455845Sbostic break; 79555845Sbostic case O_QUEST: /* just an empty */ 79655845Sbostic FWD(st, st, 1); 79755845Sbostic break; 79855845Sbostic case OLPAREN: /* not significant here */ 79955845Sbostic case ORPAREN: 80055845Sbostic FWD(st, st, 1); 80155845Sbostic break; 80255845Sbostic case OCH_: /* mark the first two branches */ 80355845Sbostic FWD(st, st, 1); 80455845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 80555845Sbostic FWD(st, st, OPND(s)); 80655845Sbostic break; 80755845Sbostic case OOR1: /* done a branch, find the O_CH */ 80855845Sbostic if (ISSTATEIN(st, here)) { 80955845Sbostic for (look = 1; 81055845Sbostic OP(s = g->strip[pc+look]) != O_CH; 81155845Sbostic look += OPND(s)) 81255845Sbostic assert(OP(s) == OOR2); 81355845Sbostic FWD(st, st, look); 81455845Sbostic } 81555845Sbostic break; 81655845Sbostic case OOR2: /* propagate OCH_'s marking onward */ 81755845Sbostic FWD(st, st, 1); 81855845Sbostic if (OP(g->strip[pc+OPND(s)]) != O_CH) { 81955845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 82055845Sbostic FWD(st, st, OPND(s)); 82155845Sbostic } 82255845Sbostic break; 82355845Sbostic case O_CH: /* just an empty */ 82455845Sbostic FWD(st, st, 1); 82555845Sbostic break; 82655845Sbostic default: /* ooooops... */ 82755845Sbostic assert(0); 82855845Sbostic break; 82955845Sbostic } 83055845Sbostic } 83155845Sbostic 83255845Sbostic return(st); 83355845Sbostic } 83455845Sbostic 83555845Sbostic /* 83655845Sbostic - step - map set of states reachable before char to set reachable after 837*56355Sbostic == static states step(register struct re_guts *g, int start, int stop, \ 838*56355Sbostic == register states bef, uchar ch, register states aft); 83955845Sbostic */ 84055845Sbostic static states 84155845Sbostic step(g, start, stop, bef, ch, aft) 84255845Sbostic register struct re_guts *g; 84355845Sbostic int start; /* start state within strip */ 84455845Sbostic int stop; /* state after stop state within strip */ 84555845Sbostic register states bef; /* states reachable before */ 84655845Sbostic uchar ch; 84755845Sbostic register states aft; /* states already known reachable after */ 84855845Sbostic { 84955845Sbostic register cset *cs; 85055845Sbostic register sop s; 85155845Sbostic register sopno pc; 85255845Sbostic register onestate here; /* note, macros know this name */ 85355845Sbostic register sopno look; 85455845Sbostic register int i; 85555845Sbostic 85655845Sbostic for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { 85755845Sbostic s = g->strip[pc]; 85855845Sbostic switch (OP(s)) { 85955845Sbostic case OEND: 86055845Sbostic assert(pc == stop-1); 86155845Sbostic break; 86255845Sbostic case OCHAR: 86355845Sbostic if (ch == OPND(s)) 86455845Sbostic FWD(aft, bef, 1); 86555845Sbostic break; 86655845Sbostic case OBOL: /* these are looked after by expand() */ 86755845Sbostic case OEOL: 86855845Sbostic break; 86955845Sbostic case OANY: 87055845Sbostic FWD(aft, bef, 1); 87155845Sbostic break; 87255845Sbostic case OANYOF: 87355845Sbostic cs = &g->sets[OPND(s)]; 87455845Sbostic if (CHIN(cs, ch)) 87555845Sbostic FWD(aft, bef, 1); 87655845Sbostic break; 87755845Sbostic case OBACK_: /* ignored here */ 87855845Sbostic case O_BACK: 87955845Sbostic FWD(aft, aft, 1); 88055845Sbostic break; 88155845Sbostic case OPLUS_: /* forward, this is just an empty */ 88255845Sbostic FWD(aft, aft, 1); 88355845Sbostic break; 88455845Sbostic case O_PLUS: /* both forward and back */ 88555845Sbostic FWD(aft, aft, 1); 88655845Sbostic i = ISSETBACK(aft, OPND(s)); 88755845Sbostic BACK(aft, aft, OPND(s)); 88855845Sbostic if (!i && ISSETBACK(aft, OPND(s))) { 88955845Sbostic /* oho, must reconsider loop body */ 89055845Sbostic pc -= OPND(s) + 1; 89155845Sbostic INIT(here, pc); 89255845Sbostic } 89355845Sbostic break; 89455845Sbostic case OQUEST_: /* two branches, both forward */ 89555845Sbostic FWD(aft, aft, 1); 89655845Sbostic FWD(aft, aft, OPND(s)); 89755845Sbostic break; 89855845Sbostic case O_QUEST: /* just an empty */ 89955845Sbostic FWD(aft, aft, 1); 90055845Sbostic break; 90155845Sbostic case OLPAREN: /* not significant here */ 90255845Sbostic case ORPAREN: 90355845Sbostic FWD(aft, aft, 1); 90455845Sbostic break; 90555845Sbostic case OCH_: /* mark the first two branches */ 90655845Sbostic FWD(aft, aft, 1); 90755845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 90855845Sbostic FWD(aft, aft, OPND(s)); 90955845Sbostic break; 91055845Sbostic case OOR1: /* done a branch, find the O_CH */ 91155845Sbostic if (ISSTATEIN(aft, here)) { 91255845Sbostic for (look = 1; 91355845Sbostic OP(s = g->strip[pc+look]) != O_CH; 91455845Sbostic look += OPND(s)) 91555845Sbostic assert(OP(s) == OOR2); 91655845Sbostic FWD(aft, aft, look); 91755845Sbostic } 91855845Sbostic break; 91955845Sbostic case OOR2: /* propagate OCH_'s marking */ 92055845Sbostic FWD(aft, aft, 1); 92155845Sbostic if (OP(g->strip[pc+OPND(s)]) != O_CH) { 92255845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 92355845Sbostic FWD(aft, aft, OPND(s)); 92455845Sbostic } 92555845Sbostic break; 92655845Sbostic case O_CH: /* just empty */ 92755845Sbostic FWD(aft, aft, 1); 92855845Sbostic break; 92955845Sbostic default: /* ooooops... */ 93055845Sbostic assert(0); 93155845Sbostic break; 93255845Sbostic } 93355845Sbostic } 93455845Sbostic 93555845Sbostic return(aft); 93655845Sbostic } 93755845Sbostic 938*56355Sbostic #ifdef REDEBUG 93955845Sbostic /* 94055845Sbostic - print - print a set of states 941*56355Sbostic == #ifdef REDEBUG 942*56355Sbostic == static void print(struct match *m, char *caption, states st, \ 943*56355Sbostic == uchar ch, FILE *d); 944*56355Sbostic == #endif 94555845Sbostic */ 94655845Sbostic static void 947*56355Sbostic print(m, caption, st, ch, d) 948*56355Sbostic struct match *m; 94955845Sbostic char *caption; 95055845Sbostic states st; 95155845Sbostic uchar ch; 95255845Sbostic FILE *d; 95355845Sbostic { 954*56355Sbostic register struct re_guts *g = m->g; 95555845Sbostic register int i; 95655845Sbostic register int first = 1; 95755845Sbostic 958*56355Sbostic if (!(m->eflags®_TRACE)) 959*56355Sbostic return; 960*56355Sbostic 96155845Sbostic fprintf(d, "%s", caption); 96255845Sbostic if (ch != '\0') 963*56355Sbostic fprintf(d, " %s", pchar(ch)); 96455845Sbostic for (i = 0; i < g->nstates; i++) 96555845Sbostic if (ISSET(st, i)) { 96655845Sbostic fprintf(d, "%s%d", (first) ? "\t" : ", ", i); 96755845Sbostic first = 0; 96855845Sbostic } 96955845Sbostic fprintf(d, "\n"); 97055845Sbostic } 971*56355Sbostic 972*56355Sbostic /* 973*56355Sbostic - at - print current situation 974*56355Sbostic == #ifdef REDEBUG 975*56355Sbostic == static void at(struct match *m, char *title, uchar *start, uchar *stop, \ 976*56355Sbostic == sopno startst, stopno stopst); 977*56355Sbostic == #endif 978*56355Sbostic */ 979*56355Sbostic static void 980*56355Sbostic at(m, title, start, stop, startst, stopst) 981*56355Sbostic struct match *m; 982*56355Sbostic char *title; 983*56355Sbostic uchar *start; 984*56355Sbostic uchar *stop; 985*56355Sbostic sopno startst; 986*56355Sbostic sopno stopst; 987*56355Sbostic { 988*56355Sbostic if (!(m->eflags®_TRACE)) 989*56355Sbostic return; 990*56355Sbostic 991*56355Sbostic printf("%s %s-", title, pchar(*start)); 992*56355Sbostic printf("%s ", pchar(*stop)); 993*56355Sbostic printf("%ld-%ld\n", (long)startst, (long)stopst); 994*56355Sbostic } 995*56355Sbostic 996*56355Sbostic #ifndef PCHARDONE 997*56355Sbostic #define PCHARDONE /* never again */ 998*56355Sbostic /* 999*56355Sbostic - pchar - make a character printable 1000*56355Sbostic == #ifdef REDEBUG 1001*56355Sbostic == static char *pchar(int ch); 1002*56355Sbostic == #endif 1003*56355Sbostic * 1004*56355Sbostic * Is this identical to regchar() over in debug.c? Well, yes. But a 1005*56355Sbostic * duplicate here avoids having a debugging-capable regexec.o tied to 1006*56355Sbostic * a matching debug.o, and this is convenient. It all disappears in 1007*56355Sbostic * the non-debug compilation anyway, so it doesn't matter much. 1008*56355Sbostic */ 1009*56355Sbostic static char * /* -> representation */ 1010*56355Sbostic pchar(ch) 1011*56355Sbostic int ch; 1012*56355Sbostic { 1013*56355Sbostic static char pbuf[10]; 1014*56355Sbostic 1015*56355Sbostic if (isprint(ch) || ch == ' ') 1016*56355Sbostic sprintf(pbuf, "%c", ch); 1017*56355Sbostic else 1018*56355Sbostic sprintf(pbuf, "\\%o", ch); 1019*56355Sbostic return(pbuf); 1020*56355Sbostic } 102155845Sbostic #endif 1022*56355Sbostic #endif 102355845Sbostic 102455845Sbostic #undef matcher 102555845Sbostic #undef fast 102655845Sbostic #undef slow 102755845Sbostic #undef dissect 102855845Sbostic #undef backref 102955845Sbostic #undef expand 103055845Sbostic #undef step 103155845Sbostic #undef print 1032*56355Sbostic #undef at 103355845Sbostic #undef match 1034