155845Sbostic /*- 266362Sbostic * Copyright (c) 1992, 1993, 1994 Henry Spencer. 366362Sbostic * Copyright (c) 1992, 1993, 1994 461162Sbostic * The Regents of the University of California. 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*66385Sbostic * @(#)engine.c 8.4 (Berkeley) 03/19/94 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 step sstep 2855845Sbostic #define print sprint 2956355Sbostic #define at sat 3055845Sbostic #define match smat 3155845Sbostic #endif 3255845Sbostic #ifdef LNAMES 3355845Sbostic #define matcher lmatcher 3455845Sbostic #define fast lfast 3555845Sbostic #define slow lslow 3655845Sbostic #define dissect ldissect 3755845Sbostic #define backref lbackref 3855845Sbostic #define step lstep 3955845Sbostic #define print lprint 4056355Sbostic #define at lat 4155845Sbostic #define match lmat 4255845Sbostic #endif 4355845Sbostic 4455845Sbostic /* another structure passed up and down to avoid zillions of parameters */ 4555845Sbostic struct match { 4655845Sbostic struct re_guts *g; 4755845Sbostic int eflags; 4855845Sbostic regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ 4960201Sbostic char *offp; /* offsets work from here */ 5060201Sbostic char *beginp; /* start of string -- virtual NUL precedes */ 5160201Sbostic char *endp; /* end of string -- virtual NUL here */ 5260201Sbostic char *coldp; /* can be no match starting before here */ 5360201Sbostic char **lastpos; /* [nplus+1] */ 5455845Sbostic STATEVARS; 5555845Sbostic states st; /* current states */ 5655845Sbostic states fresh; /* states for a fresh start */ 5755845Sbostic states tmp; /* temporary */ 5855845Sbostic states empty; /* empty set of states */ 5955845Sbostic }; 6055845Sbostic 6166362Sbostic /* ========= begin header generated by ./mkh ========= */ 6266362Sbostic #ifdef __cplusplus 6366362Sbostic extern "C" { 6466362Sbostic #endif 6566362Sbostic 6666362Sbostic /* === engine.c === */ 67*66385Sbostic static int matcher __P((struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags)); 68*66385Sbostic static char *dissect __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); 69*66385Sbostic static char *backref __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev)); 70*66385Sbostic static char *fast __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); 71*66385Sbostic static char *slow __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); 72*66385Sbostic static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft)); 7360201Sbostic #define BOL (OUT+1) 7460201Sbostic #define EOL (BOL+1) 7560201Sbostic #define BOLEOL (BOL+2) 7660201Sbostic #define NOTHING (BOL+3) 7760201Sbostic #define BOW (BOL+4) 7860201Sbostic #define EOW (BOL+5) 7960201Sbostic #define CODEMAX (BOL+5) /* highest code used */ 8060201Sbostic #define NONCHAR(c) ((c) > CHAR_MAX) 8160201Sbostic #define NNONCHAR (CODEMAX-CHAR_MAX) 8256355Sbostic #ifdef REDEBUG 83*66385Sbostic static void print __P((struct match *m, char *caption, states st, int ch, FILE *d)); 8460201Sbostic #endif 8560201Sbostic #ifdef REDEBUG 86*66385Sbostic static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst)); 8760201Sbostic #endif 8860201Sbostic #ifdef REDEBUG 89*66385Sbostic static char *pchar __P((int ch)); 9060201Sbostic #endif 9160201Sbostic 9266362Sbostic #ifdef __cplusplus 9366362Sbostic } 9466362Sbostic #endif 9566362Sbostic /* ========= end header generated by ./mkh ========= */ 9666362Sbostic 9760201Sbostic #ifdef REDEBUG 9856355Sbostic #define SP(t, s, c) print(m, t, s, c, stdout) 9956355Sbostic #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) 10056355Sbostic #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } 10155845Sbostic #else 10255845Sbostic #define SP(t, s, c) /* nothing */ 10356355Sbostic #define AT(t, p1, p2, s1, s2) /* nothing */ 10456355Sbostic #define NOTE(s) /* nothing */ 10555845Sbostic #endif 10655845Sbostic 10755845Sbostic /* 10855845Sbostic - matcher - the actual matching engine 10960201Sbostic == static int matcher(register struct re_guts *g, char *string, \ 11060201Sbostic == size_t nmatch, regmatch_t pmatch[], int eflags); 11155845Sbostic */ 11255845Sbostic static int /* 0 success, REG_NOMATCH failure */ 11355845Sbostic matcher(g, string, nmatch, pmatch, eflags) 11455845Sbostic register struct re_guts *g; 11560201Sbostic char *string; 11655845Sbostic size_t nmatch; 11755845Sbostic regmatch_t pmatch[]; 11855845Sbostic int eflags; 11955845Sbostic { 12060201Sbostic register char *endp; 12155845Sbostic register int i; 12255845Sbostic struct match mv; 12355845Sbostic register struct match *m = &mv; 12460201Sbostic register char *dp; 12555845Sbostic const register sopno gf = g->firststate+1; /* +1 for OEND */ 12655845Sbostic const register sopno gl = g->laststate; 12760201Sbostic char *start; 12860201Sbostic char *stop; 12955845Sbostic 13056355Sbostic /* simplify the situation where possible */ 13155845Sbostic if (g->cflags®_NOSUB) 13256355Sbostic nmatch = 0; 13355845Sbostic if (eflags®_STARTEND) { 13455845Sbostic start = string + pmatch[0].rm_so; 13555845Sbostic stop = string + pmatch[0].rm_eo; 13655845Sbostic } else { 13755845Sbostic start = string; 13860201Sbostic stop = start + strlen(start); 13955845Sbostic } 14060201Sbostic if (stop < start) 14160201Sbostic return(REG_INVARG); 14255845Sbostic 14355882Sbostic /* prescreening; this does wonders for this rather slow code */ 14455882Sbostic if (g->must != NULL) { 14555882Sbostic for (dp = start; dp < stop; dp++) 14660201Sbostic if (*dp == g->must[0] && stop - dp >= g->mlen && 14760201Sbostic memcmp(dp, g->must, (size_t)g->mlen) == 0) 14855882Sbostic break; 14955882Sbostic if (dp == stop) /* we didn't find g->must */ 15055882Sbostic return(REG_NOMATCH); 15155882Sbostic } 15255882Sbostic 15355845Sbostic /* match struct setup */ 15455845Sbostic m->g = g; 15555845Sbostic m->eflags = eflags; 15655845Sbostic m->pmatch = NULL; 15755845Sbostic m->lastpos = NULL; 15855845Sbostic m->offp = string; 15955845Sbostic m->beginp = start; 16055845Sbostic m->endp = stop; 16155845Sbostic STATESETUP(m, 4); 16255845Sbostic SETUP(m->st); 16355845Sbostic SETUP(m->fresh); 16455845Sbostic SETUP(m->tmp); 16555845Sbostic SETUP(m->empty); 16655845Sbostic CLEAR(m->empty); 16755845Sbostic 16855845Sbostic /* this loop does only one repetition except for backrefs */ 16955845Sbostic for (;;) { 17055845Sbostic endp = fast(m, start, stop, gf, gl); 17155845Sbostic if (endp == NULL) { /* a miss */ 17255845Sbostic STATETEARDOWN(m); 17355845Sbostic return(REG_NOMATCH); 17455845Sbostic } 17555845Sbostic if (nmatch == 0 && !g->backrefs) 17655845Sbostic break; /* no further info needed */ 17755845Sbostic 17855845Sbostic /* where? */ 17955845Sbostic assert(m->coldp != NULL); 18055845Sbostic for (;;) { 18156355Sbostic NOTE("finding start"); 18255845Sbostic endp = slow(m, m->coldp, stop, gf, gl); 18355845Sbostic if (endp != NULL) 18455845Sbostic break; 18556355Sbostic assert(m->coldp < m->endp); 18655845Sbostic m->coldp++; 18755845Sbostic } 18855845Sbostic if (nmatch == 1 && !g->backrefs) 18955845Sbostic break; /* no further info needed */ 19055845Sbostic 19155845Sbostic /* oh my, he wants the subexpressions... */ 19255845Sbostic if (m->pmatch == NULL) 19355845Sbostic m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * 19455845Sbostic sizeof(regmatch_t)); 19555845Sbostic if (m->pmatch == NULL) { 19655845Sbostic STATETEARDOWN(m); 19755845Sbostic return(REG_ESPACE); 19855845Sbostic } 19956355Sbostic for (i = 1; i <= m->g->nsub; i++) 20056355Sbostic m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; 20156355Sbostic if (!g->backrefs && !(m->eflags®_BACKR)) { 20256355Sbostic NOTE("dissecting"); 20355845Sbostic dp = dissect(m, m->coldp, endp, gf, gl); 20456355Sbostic } else { 20555845Sbostic if (g->nplus > 0 && m->lastpos == NULL) 20660201Sbostic m->lastpos = (char **)malloc((g->nplus+1) * 20760201Sbostic sizeof(char *)); 20855845Sbostic if (g->nplus > 0 && m->lastpos == NULL) { 20955845Sbostic free(m->pmatch); 21055845Sbostic STATETEARDOWN(m); 21155845Sbostic return(REG_ESPACE); 21255845Sbostic } 21356355Sbostic NOTE("backref dissect"); 21455845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 21555845Sbostic } 21655845Sbostic if (dp != NULL) 21755845Sbostic break; 21855845Sbostic 21955845Sbostic /* uh-oh... we couldn't find a subexpression-level match */ 22055845Sbostic assert(g->backrefs); /* must be back references doing it */ 22155845Sbostic assert(g->nplus == 0 || m->lastpos != NULL); 22256355Sbostic for (;;) { 22356355Sbostic if (dp != NULL || endp <= m->coldp) 22456355Sbostic break; /* defeat */ 22556355Sbostic NOTE("backoff"); 22656355Sbostic endp = slow(m, m->coldp, endp-1, gf, gl); 22756355Sbostic if (endp == NULL) 22856355Sbostic break; /* defeat */ 22955845Sbostic /* try it on a shorter possibility */ 23056355Sbostic #ifndef NDEBUG 23155845Sbostic for (i = 1; i <= m->g->nsub; i++) { 23256355Sbostic assert(m->pmatch[i].rm_so == -1); 23356355Sbostic assert(m->pmatch[i].rm_eo == -1); 23455845Sbostic } 23556355Sbostic #endif 23656355Sbostic NOTE("backoff dissect"); 23755845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 23855845Sbostic } 23955845Sbostic assert(dp == NULL || dp == endp); 24055845Sbostic if (dp != NULL) /* found a shorter one */ 24155845Sbostic break; 24255845Sbostic 24355845Sbostic /* despite initial appearances, there is no match here */ 24456355Sbostic NOTE("false alarm"); 24555845Sbostic start = m->coldp + 1; /* recycle starting later */ 24655845Sbostic assert(start <= stop); 24755845Sbostic } 24855845Sbostic 24955845Sbostic /* fill in the details if requested */ 25055845Sbostic if (nmatch > 0) { 25155845Sbostic pmatch[0].rm_so = m->coldp - m->offp; 25255845Sbostic pmatch[0].rm_eo = endp - m->offp; 25355845Sbostic } 25455845Sbostic if (nmatch > 1) { 25555845Sbostic assert(m->pmatch != NULL); 25655845Sbostic for (i = 1; i < nmatch; i++) 25755845Sbostic if (i <= m->g->nsub) 25855845Sbostic pmatch[i] = m->pmatch[i]; 25955845Sbostic else { 26055845Sbostic pmatch[i].rm_so = -1; 26155845Sbostic pmatch[i].rm_eo = -1; 26255845Sbostic } 26355845Sbostic } 26455845Sbostic 26555845Sbostic if (m->pmatch != NULL) 26655845Sbostic free((char *)m->pmatch); 26755845Sbostic if (m->lastpos != NULL) 26855845Sbostic free((char *)m->lastpos); 26955845Sbostic STATETEARDOWN(m); 27055845Sbostic return(0); 27155845Sbostic } 27255845Sbostic 27355845Sbostic /* 27455845Sbostic - dissect - figure out what matched what, no back references 27560201Sbostic == static char *dissect(register struct match *m, char *start, \ 27660201Sbostic == char *stop, sopno startst, sopno stopst); 27755845Sbostic */ 27860201Sbostic static char * /* == stop (success) always */ 27955845Sbostic dissect(m, start, stop, startst, stopst) 28055845Sbostic register struct match *m; 28160201Sbostic char *start; 28260201Sbostic char *stop; 28355845Sbostic sopno startst; 28455845Sbostic sopno stopst; 28555845Sbostic { 28655845Sbostic register int i; 28755845Sbostic register sopno ss; /* start sop of current subRE */ 28855845Sbostic register sopno es; /* end sop of current subRE */ 28960201Sbostic register char *sp; /* start of string matched by it */ 29060201Sbostic register char *stp; /* string matched by it cannot pass here */ 29160201Sbostic register char *rest; /* start of rest of string */ 29260201Sbostic register char *tail; /* string unmatched by rest of RE */ 29355845Sbostic register sopno ssub; /* start sop of subsubRE */ 29455845Sbostic register sopno esub; /* end sop of subsubRE */ 29560201Sbostic register char *ssp; /* start of string matched by subsubRE */ 29660201Sbostic register char *sep; /* end of string matched by subsubRE */ 29760201Sbostic register char *oldssp; /* previous ssp */ 29860201Sbostic register char *dp; 29955845Sbostic 30056355Sbostic AT("diss", start, stop, startst, stopst); 30155845Sbostic sp = start; 30255845Sbostic for (ss = startst; ss < stopst; ss = es) { 30355845Sbostic /* identify end of subRE */ 30455845Sbostic es = ss; 30555845Sbostic switch (OP(m->g->strip[es])) { 30655845Sbostic case OPLUS_: 30755845Sbostic case OQUEST_: 30855845Sbostic es += OPND(m->g->strip[es]); 30955845Sbostic break; 31055845Sbostic case OCH_: 31155845Sbostic while (OP(m->g->strip[es]) != O_CH) 31255845Sbostic es += OPND(m->g->strip[es]); 31355845Sbostic break; 31455845Sbostic } 31555845Sbostic es++; 31655845Sbostic 31755845Sbostic /* figure out what it matched */ 31855845Sbostic switch (OP(m->g->strip[ss])) { 31955845Sbostic case OEND: 32060201Sbostic assert(nope); 32155845Sbostic break; 32255845Sbostic case OCHAR: 32355845Sbostic sp++; 32455845Sbostic break; 32555845Sbostic case OBOL: 32655845Sbostic case OEOL: 32760201Sbostic case OBOW: 32860201Sbostic case OEOW: 32955845Sbostic break; 33055845Sbostic case OANY: 33155845Sbostic case OANYOF: 33255845Sbostic sp++; 33355845Sbostic break; 33455845Sbostic case OBACK_: 33555845Sbostic case O_BACK: 33660201Sbostic assert(nope); 33755845Sbostic break; 33855845Sbostic /* cases where length of match is hard to find */ 33955845Sbostic case OQUEST_: 34055845Sbostic stp = stop; 34155845Sbostic for (;;) { 34255845Sbostic /* how long could this one be? */ 34355845Sbostic rest = slow(m, sp, stp, ss, es); 34455845Sbostic assert(rest != NULL); /* it did match */ 34555845Sbostic /* could the rest match the rest? */ 34655845Sbostic tail = slow(m, rest, stop, es, stopst); 34755845Sbostic if (tail == stop) 34855845Sbostic break; /* yes! */ 34955845Sbostic /* no -- try a shorter match for this one */ 35055845Sbostic stp = rest - 1; 35155845Sbostic assert(stp >= sp); /* it did work */ 35255845Sbostic } 35355845Sbostic ssub = ss + 1; 35455845Sbostic esub = es - 1; 35555845Sbostic /* did innards match? */ 35655845Sbostic if (slow(m, sp, rest, ssub, esub) != NULL) { 35755845Sbostic dp = dissect(m, sp, rest, ssub, esub); 35855845Sbostic assert(dp == rest); 35955845Sbostic } else /* no */ 36055845Sbostic assert(sp == rest); 36155845Sbostic sp = rest; 36255845Sbostic break; 36355845Sbostic case OPLUS_: 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 = es - 1; 37955845Sbostic ssp = sp; 38055845Sbostic oldssp = ssp; 38155845Sbostic for (;;) { /* find last match of innards */ 38255845Sbostic sep = slow(m, ssp, rest, ssub, esub); 38355845Sbostic if (sep == NULL || sep == ssp) 38455845Sbostic break; /* failed or matched null */ 38555845Sbostic oldssp = ssp; /* on to next try */ 38655845Sbostic ssp = sep; 38755845Sbostic } 38855845Sbostic if (sep == NULL) { 38955845Sbostic /* last successful match */ 39055845Sbostic sep = ssp; 39155845Sbostic ssp = oldssp; 39255845Sbostic } 39355845Sbostic assert(sep == rest); /* must exhaust substring */ 39455845Sbostic assert(slow(m, ssp, sep, ssub, esub) == rest); 39555845Sbostic dp = dissect(m, ssp, sep, ssub, esub); 39655845Sbostic assert(dp == sep); 39755845Sbostic sp = rest; 39855845Sbostic break; 39955845Sbostic case OCH_: 40055845Sbostic stp = stop; 40155845Sbostic for (;;) { 40255845Sbostic /* how long could this one be? */ 40355845Sbostic rest = slow(m, sp, stp, ss, es); 40455845Sbostic assert(rest != NULL); /* it did match */ 40555845Sbostic /* could the rest match the rest? */ 40655845Sbostic tail = slow(m, rest, stop, es, stopst); 40755845Sbostic if (tail == stop) 40855845Sbostic break; /* yes! */ 40955845Sbostic /* no -- try a shorter match for this one */ 41055845Sbostic stp = rest - 1; 41155845Sbostic assert(stp >= sp); /* it did work */ 41255845Sbostic } 41355845Sbostic ssub = ss + 1; 41455845Sbostic esub = ss + OPND(m->g->strip[ss]) - 1; 41555845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 41655845Sbostic for (;;) { /* find first matching branch */ 41755845Sbostic if (slow(m, sp, rest, ssub, esub) == rest) 41855845Sbostic break; /* it matched all of it */ 41955845Sbostic /* that one missed, try next one */ 42055845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 42155845Sbostic esub++; 42255845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 42355845Sbostic ssub = esub + 1; 42455845Sbostic esub += OPND(m->g->strip[esub]); 42555845Sbostic if (OP(m->g->strip[esub]) == OOR2) 42655845Sbostic esub--; 42755845Sbostic else 42855845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 42955845Sbostic } 43055845Sbostic dp = dissect(m, sp, rest, ssub, esub); 43155845Sbostic assert(dp == rest); 43255845Sbostic sp = rest; 43355845Sbostic break; 43455845Sbostic case O_PLUS: 43555845Sbostic case O_QUEST: 43655845Sbostic case OOR1: 43755845Sbostic case OOR2: 43855845Sbostic case O_CH: 43960201Sbostic assert(nope); 44055845Sbostic break; 44155845Sbostic case OLPAREN: 44255845Sbostic i = OPND(m->g->strip[ss]); 44366362Sbostic assert(0 < i && i <= m->g->nsub); 44455845Sbostic m->pmatch[i].rm_so = sp - m->offp; 44555845Sbostic break; 44655845Sbostic case ORPAREN: 44755845Sbostic i = OPND(m->g->strip[ss]); 44866362Sbostic assert(0 < i && i <= m->g->nsub); 44955845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 45055845Sbostic break; 45155845Sbostic default: /* uh oh */ 45260201Sbostic assert(nope); 45355845Sbostic break; 45455845Sbostic } 45555845Sbostic } 45655845Sbostic 45755845Sbostic assert(sp == stop); 45855845Sbostic return(sp); 45955845Sbostic } 46055845Sbostic 46155845Sbostic /* 46255845Sbostic - backref - figure out what matched what, figuring in back references 46360201Sbostic == static char *backref(register struct match *m, char *start, \ 46460201Sbostic == char *stop, sopno startst, sopno stopst, sopno lev); 46555845Sbostic */ 46660201Sbostic static char * /* == stop (success) or NULL (failure) */ 46755845Sbostic backref(m, start, stop, startst, stopst, lev) 46855845Sbostic register struct match *m; 46960201Sbostic char *start; 47060201Sbostic char *stop; 47155845Sbostic sopno startst; 47255845Sbostic sopno stopst; 47355845Sbostic sopno lev; /* PLUS nesting level */ 47455845Sbostic { 47555845Sbostic register int i; 47655845Sbostic register sopno ss; /* start sop of current subRE */ 47760201Sbostic register char *sp; /* start of string matched by it */ 47855845Sbostic register sopno ssub; /* start sop of subsubRE */ 47955845Sbostic register sopno esub; /* end sop of subsubRE */ 48060201Sbostic register char *ssp; /* start of string matched by subsubRE */ 48160201Sbostic register char *dp; 48255845Sbostic register size_t len; 48355845Sbostic register int hard; 48455845Sbostic register sop s; 48555845Sbostic register regoff_t offsave; 48655845Sbostic register cset *cs; 48755845Sbostic 48856355Sbostic AT("back", start, stop, startst, stopst); 48955845Sbostic sp = start; 49055845Sbostic 49155845Sbostic /* get as far as we can with easy stuff */ 49255845Sbostic hard = 0; 49355845Sbostic for (ss = startst; !hard && ss < stopst; ss++) 49455845Sbostic switch (OP(s = m->g->strip[ss])) { 49555845Sbostic case OCHAR: 49660201Sbostic if (sp == stop || *sp++ != (char)OPND(s)) 49755845Sbostic return(NULL); 49855845Sbostic break; 49955845Sbostic case OANY: 50055845Sbostic if (sp == stop) 50155845Sbostic return(NULL); 50255845Sbostic sp++; 50355845Sbostic break; 50455845Sbostic case OANYOF: 50555845Sbostic cs = &m->g->sets[OPND(s)]; 50655845Sbostic if (sp == stop || !CHIN(cs, *sp++)) 50755845Sbostic return(NULL); 50855845Sbostic break; 50955845Sbostic case OBOL: 51055845Sbostic if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 51155845Sbostic (sp < m->endp && *(sp-1) == '\n' && 51255845Sbostic (m->g->cflags®_NEWLINE)) ) 51355845Sbostic { /* yes */ } 51455845Sbostic else 51555845Sbostic return(NULL); 51655845Sbostic break; 51755845Sbostic case OEOL: 51855845Sbostic if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || 51955845Sbostic (sp < m->endp && *sp == '\n' && 52055845Sbostic (m->g->cflags®_NEWLINE)) ) 52155845Sbostic { /* yes */ } 52255845Sbostic else 52355845Sbostic return(NULL); 52455845Sbostic break; 52560201Sbostic case OBOW: 52660201Sbostic if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 52760201Sbostic (sp < m->endp && *(sp-1) == '\n' && 52860201Sbostic (m->g->cflags®_NEWLINE)) || 52960201Sbostic (sp > m->beginp && 53065332Sbostic !ISWORD(*(sp-1))) ) && 53165332Sbostic (sp < m->endp && ISWORD(*sp)) ) 53260201Sbostic { /* yes */ } 53360201Sbostic else 53460201Sbostic return(NULL); 53560201Sbostic break; 53660201Sbostic case OEOW: 53760201Sbostic if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || 53860201Sbostic (sp < m->endp && *sp == '\n' && 53960201Sbostic (m->g->cflags®_NEWLINE)) || 54065332Sbostic (sp < m->endp && !ISWORD(*sp)) ) && 54165332Sbostic (sp > m->beginp && ISWORD(*(sp-1))) ) 54260201Sbostic { /* yes */ } 54360201Sbostic else 54460201Sbostic return(NULL); 54560201Sbostic break; 54655845Sbostic case O_QUEST: 54755845Sbostic break; 54855845Sbostic case OOR1: /* matches null but needs to skip */ 54955845Sbostic ss++; 55055845Sbostic s = m->g->strip[ss]; 55155845Sbostic do { 55255845Sbostic assert(OP(s) == OOR2); 55355845Sbostic ss += OPND(s); 55455845Sbostic } while (OP(s = m->g->strip[ss]) != O_CH); 55555845Sbostic /* note that the ss++ gets us past the O_CH */ 55655845Sbostic break; 55755845Sbostic default: /* have to make a choice */ 55855845Sbostic hard = 1; 55955845Sbostic break; 56055845Sbostic } 56155845Sbostic if (!hard) { /* that was it! */ 56255845Sbostic if (sp != stop) 56355845Sbostic return(NULL); 56455845Sbostic return(sp); 56555845Sbostic } 56655845Sbostic ss--; /* adjust for the for's final increment */ 56755845Sbostic 56855845Sbostic /* the hard stuff */ 56956355Sbostic AT("hard", sp, stop, ss, stopst); 57055845Sbostic s = m->g->strip[ss]; 57155845Sbostic switch (OP(s)) { 57255845Sbostic case OBACK_: /* the vilest depths */ 57355845Sbostic i = OPND(s); 57466362Sbostic assert(0 < i && i <= m->g->nsub); 57555845Sbostic if (m->pmatch[i].rm_eo == -1) 57655845Sbostic return(NULL); 57755845Sbostic assert(m->pmatch[i].rm_so != -1); 57855845Sbostic len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; 57955845Sbostic assert(stop - m->beginp >= len); 58055845Sbostic if (sp > stop - len) 58155845Sbostic return(NULL); /* not enough left to match */ 58255845Sbostic ssp = m->offp + m->pmatch[i].rm_so; 58360201Sbostic if (memcmp(sp, ssp, len) != 0) 58455845Sbostic return(NULL); 58555845Sbostic while (m->g->strip[ss] != SOP(O_BACK, i)) 58655845Sbostic ss++; 58755845Sbostic return(backref(m, sp+len, stop, ss+1, stopst, lev)); 58855845Sbostic break; 58955845Sbostic case OQUEST_: /* to null or not */ 59055845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 59155845Sbostic if (dp != NULL) 59255845Sbostic return(dp); /* not */ 59355845Sbostic return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); 59455845Sbostic break; 59555845Sbostic case OPLUS_: 59655845Sbostic assert(m->lastpos != NULL); 59755845Sbostic assert(lev+1 <= m->g->nplus); 59855845Sbostic m->lastpos[lev+1] = sp; 59955845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev+1)); 60055845Sbostic break; 60155845Sbostic case O_PLUS: 60255845Sbostic if (sp == m->lastpos[lev]) /* last pass matched null */ 60355845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 60455845Sbostic /* try another pass */ 60555845Sbostic m->lastpos[lev] = sp; 60655845Sbostic dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); 60755845Sbostic if (dp == NULL) 60855845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 60955845Sbostic else 61055845Sbostic return(dp); 61155845Sbostic break; 61255845Sbostic case OCH_: /* find the right one, if any */ 61355845Sbostic ssub = ss + 1; 61455845Sbostic esub = ss + OPND(s) - 1; 61555845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 61655845Sbostic for (;;) { /* find first matching branch */ 61755845Sbostic dp = backref(m, sp, stop, ssub, esub, lev); 61855845Sbostic if (dp != NULL) 61955845Sbostic return(dp); 62055845Sbostic /* that one missed, try next one */ 62155845Sbostic if (OP(m->g->strip[esub]) == O_CH) 62255845Sbostic return(NULL); /* there is none */ 62355845Sbostic esub++; 62455845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 62555845Sbostic ssub = esub + 1; 62655845Sbostic esub += OPND(m->g->strip[esub]); 62755845Sbostic if (OP(m->g->strip[esub]) == OOR2) 62855845Sbostic esub--; 62955845Sbostic else 63055845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 63155845Sbostic } 63255845Sbostic break; 63355845Sbostic case OLPAREN: /* must undo assignment if rest fails */ 63455845Sbostic i = OPND(s); 63566362Sbostic assert(0 < i && i <= m->g->nsub); 63655845Sbostic offsave = m->pmatch[i].rm_so; 63755845Sbostic m->pmatch[i].rm_so = sp - m->offp; 63855845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 63955845Sbostic if (dp != NULL) 64055845Sbostic return(dp); 64155845Sbostic m->pmatch[i].rm_so = offsave; 64255845Sbostic return(NULL); 64355845Sbostic break; 64455845Sbostic case ORPAREN: /* must undo assignment if rest fails */ 64555845Sbostic i = OPND(s); 64666362Sbostic assert(0 < i && i <= m->g->nsub); 64755845Sbostic offsave = m->pmatch[i].rm_eo; 64855845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 64955845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 65055845Sbostic if (dp != NULL) 65155845Sbostic return(dp); 65255845Sbostic m->pmatch[i].rm_eo = offsave; 65355845Sbostic return(NULL); 65455845Sbostic break; 65555845Sbostic default: /* uh oh */ 65660201Sbostic assert(nope); 65755845Sbostic break; 65855845Sbostic } 65955845Sbostic 66055845Sbostic /* "can't happen" */ 66160201Sbostic assert(nope); 66255845Sbostic /* NOTREACHED */ 66355845Sbostic } 66455845Sbostic 66555845Sbostic /* 66655845Sbostic - fast - step through the string at top speed 66760201Sbostic == static char *fast(register struct match *m, char *start, \ 66860201Sbostic == char *stop, sopno startst, sopno stopst); 66955845Sbostic */ 67060201Sbostic static char * /* where tentative match ended, or NULL */ 67155845Sbostic fast(m, start, stop, startst, stopst) 67255845Sbostic register struct match *m; 67360201Sbostic char *start; 67460201Sbostic char *stop; 67555845Sbostic sopno startst; 67655845Sbostic sopno stopst; 67755845Sbostic { 67855845Sbostic register states st = m->st; 67955845Sbostic register states fresh = m->fresh; 68055845Sbostic register states tmp = m->tmp; 68160201Sbostic register char *p = start; 68260201Sbostic register int c = (start == m->beginp) ? OUT : *(start-1); 68360201Sbostic register int lastc; /* previous c */ 68460201Sbostic register int flagch; 68560201Sbostic register int i; 68660201Sbostic register char *coldp; /* last p after which no match was underway */ 68755845Sbostic 68855845Sbostic CLEAR(st); 68955845Sbostic SET1(st, startst); 69060201Sbostic st = step(m->g, startst, stopst, st, NOTHING, st); 69155845Sbostic ASSIGN(fresh, st); 69255845Sbostic SP("start", st, *p); 69355845Sbostic coldp = NULL; 69455845Sbostic for (;;) { 69555845Sbostic /* next character */ 69655845Sbostic lastc = c; 69760201Sbostic c = (p == m->endp) ? OUT : *p; 69855845Sbostic if (EQ(st, fresh)) 69955845Sbostic coldp = p; 70055845Sbostic 70155845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 70260201Sbostic flagch = '\0'; 70360201Sbostic i = 0; 70460201Sbostic if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 70560201Sbostic (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 70660201Sbostic flagch = BOL; 70760201Sbostic i = m->g->nbol; 70855845Sbostic } 70960201Sbostic if ( (c == '\n' && m->g->cflags®_NEWLINE) || 71060201Sbostic (c == OUT && !(m->eflags®_NOTEOL)) ) { 71160201Sbostic flagch = (flagch == BOL) ? BOLEOL : EOL; 71260201Sbostic i += m->g->neol; 71360201Sbostic } 71460201Sbostic if (i != 0) { 71560201Sbostic for (; i > 0; i--) 71660201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 71760201Sbostic SP("boleol", st, c); 71860201Sbostic } 71955845Sbostic 72060201Sbostic /* how about a word boundary? */ 72165332Sbostic if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && 72265332Sbostic (c != OUT && ISWORD(c)) ) { 72360201Sbostic flagch = BOW; 72460201Sbostic } 72565332Sbostic if ( (lastc != OUT && ISWORD(lastc)) && 72665332Sbostic (flagch == EOL || (c != OUT && !ISWORD(c))) ) { 72760201Sbostic flagch = EOW; 72860201Sbostic } 72960201Sbostic if (flagch == BOW || flagch == EOW) { 73060201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 73160201Sbostic SP("boweow", st, c); 73260201Sbostic } 73360201Sbostic 73455845Sbostic /* are we done? */ 73555845Sbostic if (ISSET(st, stopst) || p == stop) 73655845Sbostic break; /* NOTE BREAK OUT */ 73755845Sbostic 73855845Sbostic /* no, we must deal with this character */ 73955845Sbostic ASSIGN(tmp, st); 74055845Sbostic ASSIGN(st, fresh); 74160201Sbostic assert(c != OUT); 74255845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 74355845Sbostic SP("aft", st, c); 74460201Sbostic assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); 74555845Sbostic p++; 74655845Sbostic } 74755845Sbostic 74855845Sbostic assert(coldp != NULL); 74955845Sbostic m->coldp = coldp; 75055845Sbostic if (ISSET(st, stopst)) 75155845Sbostic return(p+1); 75255845Sbostic else 75355845Sbostic return(NULL); 75455845Sbostic } 75555845Sbostic 75655845Sbostic /* 75755845Sbostic - slow - step through the string more deliberately 75860201Sbostic == static char *slow(register struct match *m, char *start, \ 75960201Sbostic == char *stop, sopno startst, sopno stopst); 76055845Sbostic */ 76160201Sbostic static char * /* where it ended */ 76255845Sbostic slow(m, start, stop, startst, stopst) 76355845Sbostic register struct match *m; 76460201Sbostic char *start; 76560201Sbostic char *stop; 76655845Sbostic sopno startst; 76755845Sbostic sopno stopst; 76855845Sbostic { 76955845Sbostic register states st = m->st; 77055845Sbostic register states empty = m->empty; 77155845Sbostic register states tmp = m->tmp; 77260201Sbostic register char *p = start; 77360201Sbostic register int c = (start == m->beginp) ? OUT : *(start-1); 77460201Sbostic register int lastc; /* previous c */ 77560201Sbostic register int flagch; 77660201Sbostic register int i; 77760201Sbostic register char *matchp; /* last p at which a match ended */ 77855845Sbostic 77956355Sbostic AT("slow", start, stop, startst, stopst); 78055845Sbostic CLEAR(st); 78155845Sbostic SET1(st, startst); 78255845Sbostic SP("sstart", st, *p); 78360201Sbostic st = step(m->g, startst, stopst, st, NOTHING, st); 78455845Sbostic matchp = NULL; 78555845Sbostic for (;;) { 78655845Sbostic /* next character */ 78755845Sbostic lastc = c; 78860201Sbostic c = (p == m->endp) ? OUT : *p; 78955845Sbostic 79055845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 79160201Sbostic flagch = '\0'; 79260201Sbostic i = 0; 79360201Sbostic if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 79460201Sbostic (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 79560201Sbostic flagch = BOL; 79660201Sbostic i = m->g->nbol; 79760201Sbostic } 79860201Sbostic if ( (c == '\n' && m->g->cflags®_NEWLINE) || 79960201Sbostic (c == OUT && !(m->eflags®_NOTEOL)) ) { 80060201Sbostic flagch = (flagch == BOL) ? BOLEOL : EOL; 80160201Sbostic i += m->g->neol; 80260201Sbostic } 80360201Sbostic if (i != 0) { 80460201Sbostic for (; i > 0; i--) 80560201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 80660201Sbostic SP("sboleol", st, c); 80760201Sbostic } 80855845Sbostic 80960201Sbostic /* how about a word boundary? */ 81065332Sbostic if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && 81165332Sbostic (c != OUT && ISWORD(c)) ) { 81260201Sbostic flagch = BOW; 81355845Sbostic } 81465332Sbostic if ( (lastc != OUT && ISWORD(lastc)) && 81565332Sbostic (flagch == EOL || (c != OUT && !ISWORD(c))) ) { 81660201Sbostic flagch = EOW; 81760201Sbostic } 81860201Sbostic if (flagch == BOW || flagch == EOW) { 81960201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 82060201Sbostic SP("sboweow", st, c); 82160201Sbostic } 82255845Sbostic 82355845Sbostic /* are we done? */ 82455845Sbostic if (ISSET(st, stopst)) 82555845Sbostic matchp = p; 82655845Sbostic if (EQ(st, empty) || p == stop) 82755845Sbostic break; /* NOTE BREAK OUT */ 82855845Sbostic 82955845Sbostic /* no, we must deal with this character */ 83055845Sbostic ASSIGN(tmp, st); 83155845Sbostic ASSIGN(st, empty); 83260201Sbostic assert(c != OUT); 83355845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 83455845Sbostic SP("saft", st, c); 83560201Sbostic assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); 83655845Sbostic p++; 83755845Sbostic } 83855845Sbostic 83955845Sbostic return(matchp); 84055845Sbostic } 84155845Sbostic 84255845Sbostic 84355845Sbostic /* 84455845Sbostic - step - map set of states reachable before char to set reachable after 84566362Sbostic == static states step(register struct re_guts *g, sopno start, sopno stop, \ 84660201Sbostic == register states bef, int ch, register states aft); 84760201Sbostic == #define BOL (OUT+1) 84860201Sbostic == #define EOL (BOL+1) 84960201Sbostic == #define BOLEOL (BOL+2) 85060201Sbostic == #define NOTHING (BOL+3) 85160201Sbostic == #define BOW (BOL+4) 85260201Sbostic == #define EOW (BOL+5) 85360201Sbostic == #define CODEMAX (BOL+5) // highest code used 85460201Sbostic == #define NONCHAR(c) ((c) > CHAR_MAX) 85560201Sbostic == #define NNONCHAR (CODEMAX-CHAR_MAX) 85655845Sbostic */ 85755845Sbostic static states 85855845Sbostic step(g, start, stop, bef, ch, aft) 85955845Sbostic register struct re_guts *g; 86066362Sbostic sopno start; /* start state within strip */ 86166362Sbostic sopno stop; /* state after stop state within strip */ 86255845Sbostic register states bef; /* states reachable before */ 86360201Sbostic int ch; /* character or NONCHAR code */ 86455845Sbostic register states aft; /* states already known reachable after */ 86555845Sbostic { 86655845Sbostic register cset *cs; 86755845Sbostic register sop s; 86855845Sbostic register sopno pc; 86955845Sbostic register onestate here; /* note, macros know this name */ 87055845Sbostic register sopno look; 87155845Sbostic register int i; 87255845Sbostic 87355845Sbostic for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { 87455845Sbostic s = g->strip[pc]; 87555845Sbostic switch (OP(s)) { 87655845Sbostic case OEND: 87755845Sbostic assert(pc == stop-1); 87855845Sbostic break; 87955845Sbostic case OCHAR: 88060201Sbostic /* only characters can match */ 88160201Sbostic assert(!NONCHAR(ch) || ch != (char)OPND(s)); 88260201Sbostic if (ch == (char)OPND(s)) 88355845Sbostic FWD(aft, bef, 1); 88455845Sbostic break; 88560201Sbostic case OBOL: 88660201Sbostic if (ch == BOL || ch == BOLEOL) 88760201Sbostic FWD(aft, bef, 1); 88860201Sbostic break; 88955845Sbostic case OEOL: 89060201Sbostic if (ch == EOL || ch == BOLEOL) 89160201Sbostic FWD(aft, bef, 1); 89255845Sbostic break; 89360201Sbostic case OBOW: 89460201Sbostic if (ch == BOW) 89560201Sbostic FWD(aft, bef, 1); 89660201Sbostic break; 89760201Sbostic case OEOW: 89860201Sbostic if (ch == EOW) 89960201Sbostic FWD(aft, bef, 1); 90060201Sbostic break; 90155845Sbostic case OANY: 90260201Sbostic if (!NONCHAR(ch)) 90360201Sbostic FWD(aft, bef, 1); 90455845Sbostic break; 90555845Sbostic case OANYOF: 90655845Sbostic cs = &g->sets[OPND(s)]; 90760201Sbostic if (!NONCHAR(ch) && CHIN(cs, ch)) 90855845Sbostic FWD(aft, bef, 1); 90955845Sbostic break; 91055845Sbostic case OBACK_: /* ignored here */ 91155845Sbostic case O_BACK: 91255845Sbostic FWD(aft, aft, 1); 91355845Sbostic break; 91455845Sbostic case OPLUS_: /* forward, this is just an empty */ 91555845Sbostic FWD(aft, aft, 1); 91655845Sbostic break; 91755845Sbostic case O_PLUS: /* both forward and back */ 91855845Sbostic FWD(aft, aft, 1); 91955845Sbostic i = ISSETBACK(aft, OPND(s)); 92055845Sbostic BACK(aft, aft, OPND(s)); 92155845Sbostic if (!i && ISSETBACK(aft, OPND(s))) { 92255845Sbostic /* oho, must reconsider loop body */ 92355845Sbostic pc -= OPND(s) + 1; 92455845Sbostic INIT(here, pc); 92555845Sbostic } 92655845Sbostic break; 92755845Sbostic case OQUEST_: /* two branches, both forward */ 92855845Sbostic FWD(aft, aft, 1); 92955845Sbostic FWD(aft, aft, OPND(s)); 93055845Sbostic break; 93155845Sbostic case O_QUEST: /* just an empty */ 93255845Sbostic FWD(aft, aft, 1); 93355845Sbostic break; 93455845Sbostic case OLPAREN: /* not significant here */ 93555845Sbostic case ORPAREN: 93655845Sbostic FWD(aft, aft, 1); 93755845Sbostic break; 93855845Sbostic case OCH_: /* mark the first two branches */ 93955845Sbostic FWD(aft, aft, 1); 94055845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 94155845Sbostic FWD(aft, aft, OPND(s)); 94255845Sbostic break; 94355845Sbostic case OOR1: /* done a branch, find the O_CH */ 94455845Sbostic if (ISSTATEIN(aft, here)) { 94555845Sbostic for (look = 1; 94655845Sbostic OP(s = g->strip[pc+look]) != O_CH; 94755845Sbostic look += OPND(s)) 94855845Sbostic assert(OP(s) == OOR2); 94955845Sbostic FWD(aft, aft, look); 95055845Sbostic } 95155845Sbostic break; 95255845Sbostic case OOR2: /* propagate OCH_'s marking */ 95355845Sbostic FWD(aft, aft, 1); 95455845Sbostic if (OP(g->strip[pc+OPND(s)]) != O_CH) { 95555845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 95655845Sbostic FWD(aft, aft, OPND(s)); 95755845Sbostic } 95855845Sbostic break; 95955845Sbostic case O_CH: /* just empty */ 96055845Sbostic FWD(aft, aft, 1); 96155845Sbostic break; 96255845Sbostic default: /* ooooops... */ 96360201Sbostic assert(nope); 96455845Sbostic break; 96555845Sbostic } 96655845Sbostic } 96755845Sbostic 96855845Sbostic return(aft); 96955845Sbostic } 97055845Sbostic 97156355Sbostic #ifdef REDEBUG 97255845Sbostic /* 97355845Sbostic - print - print a set of states 97460201Sbostic == #ifdef REDEBUG 97560201Sbostic == static void print(struct match *m, char *caption, states st, \ 97660201Sbostic == int ch, FILE *d); 97760201Sbostic == #endif 97855845Sbostic */ 97955845Sbostic static void 98056355Sbostic print(m, caption, st, ch, d) 98156355Sbostic struct match *m; 98255845Sbostic char *caption; 98355845Sbostic states st; 98460201Sbostic int ch; 98555845Sbostic FILE *d; 98655845Sbostic { 98756355Sbostic register struct re_guts *g = m->g; 98855845Sbostic register int i; 98955845Sbostic register int first = 1; 99055845Sbostic 99156355Sbostic if (!(m->eflags®_TRACE)) 99256355Sbostic return; 99356355Sbostic 99455845Sbostic fprintf(d, "%s", caption); 99555845Sbostic if (ch != '\0') 99656355Sbostic fprintf(d, " %s", pchar(ch)); 99755845Sbostic for (i = 0; i < g->nstates; i++) 99855845Sbostic if (ISSET(st, i)) { 99955845Sbostic fprintf(d, "%s%d", (first) ? "\t" : ", ", i); 100055845Sbostic first = 0; 100155845Sbostic } 100255845Sbostic fprintf(d, "\n"); 100355845Sbostic } 100456355Sbostic 100556355Sbostic /* 100656355Sbostic - at - print current situation 100760201Sbostic == #ifdef REDEBUG 100860201Sbostic == static void at(struct match *m, char *title, char *start, char *stop, \ 100966362Sbostic == sopno startst, sopno stopst); 101060201Sbostic == #endif 101156355Sbostic */ 101256355Sbostic static void 101356355Sbostic at(m, title, start, stop, startst, stopst) 101456355Sbostic struct match *m; 101556355Sbostic char *title; 101660201Sbostic char *start; 101760201Sbostic char *stop; 101856355Sbostic sopno startst; 101956355Sbostic sopno stopst; 102056355Sbostic { 102156355Sbostic if (!(m->eflags®_TRACE)) 102256355Sbostic return; 102356355Sbostic 102456355Sbostic printf("%s %s-", title, pchar(*start)); 102556355Sbostic printf("%s ", pchar(*stop)); 102656355Sbostic printf("%ld-%ld\n", (long)startst, (long)stopst); 102756355Sbostic } 102856355Sbostic 102956355Sbostic #ifndef PCHARDONE 103056355Sbostic #define PCHARDONE /* never again */ 103156355Sbostic /* 103256355Sbostic - pchar - make a character printable 103360201Sbostic == #ifdef REDEBUG 103460201Sbostic == static char *pchar(int ch); 103560201Sbostic == #endif 103656355Sbostic * 103756355Sbostic * Is this identical to regchar() over in debug.c? Well, yes. But a 103856355Sbostic * duplicate here avoids having a debugging-capable regexec.o tied to 103956355Sbostic * a matching debug.o, and this is convenient. It all disappears in 104056355Sbostic * the non-debug compilation anyway, so it doesn't matter much. 104156355Sbostic */ 104256355Sbostic static char * /* -> representation */ 104356355Sbostic pchar(ch) 104456355Sbostic int ch; 104556355Sbostic { 104656355Sbostic static char pbuf[10]; 104756355Sbostic 104856355Sbostic if (isprint(ch) || ch == ' ') 104956355Sbostic sprintf(pbuf, "%c", ch); 105056355Sbostic else 105156355Sbostic sprintf(pbuf, "\\%o", ch); 105256355Sbostic return(pbuf); 105356355Sbostic } 105455845Sbostic #endif 105556355Sbostic #endif 105655845Sbostic 105755845Sbostic #undef matcher 105855845Sbostic #undef fast 105955845Sbostic #undef slow 106055845Sbostic #undef dissect 106155845Sbostic #undef backref 106255845Sbostic #undef step 106355845Sbostic #undef print 106456355Sbostic #undef at 106555845Sbostic #undef match 1066