155845Sbostic /*- 255845Sbostic * Copyright (c) 1992 Henry Spencer. 361162Sbostic * Copyright (c) 1992, 1993 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*65332Sbostic * @(#)engine.c 8.2 (Berkeley) 01/02/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 6160201Sbostic static int matcher(/*register struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags*/); 6260201Sbostic static char *dissect(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/); 6360201Sbostic static char *backref(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev*/); 6460201Sbostic static char *fast(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/); 6560201Sbostic static char *slow(/*register struct match *m, char *start, char *stop, sopno startst, sopno stopst*/); 6660201Sbostic static states step(/*register struct re_guts *g, int start, int stop, register states bef, int ch, register states aft*/); 6760201Sbostic #define BOL (OUT+1) 6860201Sbostic #define EOL (BOL+1) 6960201Sbostic #define BOLEOL (BOL+2) 7060201Sbostic #define NOTHING (BOL+3) 7160201Sbostic #define BOW (BOL+4) 7260201Sbostic #define EOW (BOL+5) 7360201Sbostic #define CODEMAX (BOL+5) /* highest code used */ 7460201Sbostic #define NONCHAR(c) ((c) > CHAR_MAX) 7560201Sbostic #define NNONCHAR (CODEMAX-CHAR_MAX) 7656355Sbostic #ifdef REDEBUG 7760201Sbostic static void print(/*struct match *m, char *caption, states st, int ch, FILE *d*/); 7860201Sbostic #endif 7960201Sbostic #ifdef REDEBUG 8060201Sbostic static void at(/*struct match *m, char *title, char *start, char *stop, sopno startst, stopno stopst*/); 8160201Sbostic #endif 8260201Sbostic #ifdef REDEBUG 8360201Sbostic static char *pchar(/*int ch*/); 8460201Sbostic #endif 8560201Sbostic 8660201Sbostic #ifdef REDEBUG 8756355Sbostic #define SP(t, s, c) print(m, t, s, c, stdout) 8856355Sbostic #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) 8956355Sbostic #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } 9055845Sbostic #else 9155845Sbostic #define SP(t, s, c) /* nothing */ 9256355Sbostic #define AT(t, p1, p2, s1, s2) /* nothing */ 9356355Sbostic #define NOTE(s) /* nothing */ 9455845Sbostic #endif 9555845Sbostic 9655845Sbostic /* 9755845Sbostic - matcher - the actual matching engine 9860201Sbostic == static int matcher(register struct re_guts *g, char *string, \ 9960201Sbostic == size_t nmatch, regmatch_t pmatch[], int eflags); 10055845Sbostic */ 10155845Sbostic static int /* 0 success, REG_NOMATCH failure */ 10255845Sbostic matcher(g, string, nmatch, pmatch, eflags) 10355845Sbostic register struct re_guts *g; 10460201Sbostic char *string; 10555845Sbostic size_t nmatch; 10655845Sbostic regmatch_t pmatch[]; 10755845Sbostic int eflags; 10855845Sbostic { 10960201Sbostic register char *endp; 11055845Sbostic register int i; 11155845Sbostic struct match mv; 11255845Sbostic register struct match *m = &mv; 11360201Sbostic register char *dp; 11455845Sbostic const register sopno gf = g->firststate+1; /* +1 for OEND */ 11555845Sbostic const register sopno gl = g->laststate; 11660201Sbostic char *start; 11760201Sbostic char *stop; 11855845Sbostic 11956355Sbostic /* simplify the situation where possible */ 12055845Sbostic if (g->cflags®_NOSUB) 12156355Sbostic nmatch = 0; 12255845Sbostic if (eflags®_STARTEND) { 12355845Sbostic start = string + pmatch[0].rm_so; 12455845Sbostic stop = string + pmatch[0].rm_eo; 12555845Sbostic } else { 12655845Sbostic start = string; 12760201Sbostic stop = start + strlen(start); 12855845Sbostic } 12960201Sbostic if (stop < start) 13060201Sbostic return(REG_INVARG); 13155845Sbostic 13255882Sbostic /* prescreening; this does wonders for this rather slow code */ 13355882Sbostic if (g->must != NULL) { 13455882Sbostic for (dp = start; dp < stop; dp++) 13560201Sbostic if (*dp == g->must[0] && stop - dp >= g->mlen && 13660201Sbostic memcmp(dp, g->must, (size_t)g->mlen) == 0) 13755882Sbostic break; 13855882Sbostic if (dp == stop) /* we didn't find g->must */ 13955882Sbostic return(REG_NOMATCH); 14055882Sbostic } 14155882Sbostic 14255845Sbostic /* match struct setup */ 14355845Sbostic m->g = g; 14455845Sbostic m->eflags = eflags; 14555845Sbostic m->pmatch = NULL; 14655845Sbostic m->lastpos = NULL; 14755845Sbostic m->offp = string; 14855845Sbostic m->beginp = start; 14955845Sbostic m->endp = stop; 15055845Sbostic STATESETUP(m, 4); 15155845Sbostic SETUP(m->st); 15255845Sbostic SETUP(m->fresh); 15355845Sbostic SETUP(m->tmp); 15455845Sbostic SETUP(m->empty); 15555845Sbostic CLEAR(m->empty); 15655845Sbostic 15755845Sbostic /* this loop does only one repetition except for backrefs */ 15855845Sbostic for (;;) { 15955845Sbostic endp = fast(m, start, stop, gf, gl); 16055845Sbostic if (endp == NULL) { /* a miss */ 16155845Sbostic STATETEARDOWN(m); 16255845Sbostic return(REG_NOMATCH); 16355845Sbostic } 16455845Sbostic if (nmatch == 0 && !g->backrefs) 16555845Sbostic break; /* no further info needed */ 16655845Sbostic 16755845Sbostic /* where? */ 16855845Sbostic assert(m->coldp != NULL); 16955845Sbostic for (;;) { 17056355Sbostic NOTE("finding start"); 17155845Sbostic endp = slow(m, m->coldp, stop, gf, gl); 17255845Sbostic if (endp != NULL) 17355845Sbostic break; 17456355Sbostic assert(m->coldp < m->endp); 17555845Sbostic m->coldp++; 17655845Sbostic } 17755845Sbostic if (nmatch == 1 && !g->backrefs) 17855845Sbostic break; /* no further info needed */ 17955845Sbostic 18055845Sbostic /* oh my, he wants the subexpressions... */ 18155845Sbostic if (m->pmatch == NULL) 18255845Sbostic m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * 18355845Sbostic sizeof(regmatch_t)); 18455845Sbostic if (m->pmatch == NULL) { 18555845Sbostic STATETEARDOWN(m); 18655845Sbostic return(REG_ESPACE); 18755845Sbostic } 18856355Sbostic for (i = 1; i <= m->g->nsub; i++) 18956355Sbostic m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; 19056355Sbostic if (!g->backrefs && !(m->eflags®_BACKR)) { 19156355Sbostic NOTE("dissecting"); 19255845Sbostic dp = dissect(m, m->coldp, endp, gf, gl); 19356355Sbostic } else { 19455845Sbostic if (g->nplus > 0 && m->lastpos == NULL) 19560201Sbostic m->lastpos = (char **)malloc((g->nplus+1) * 19660201Sbostic sizeof(char *)); 19755845Sbostic if (g->nplus > 0 && m->lastpos == NULL) { 19855845Sbostic free(m->pmatch); 19955845Sbostic STATETEARDOWN(m); 20055845Sbostic return(REG_ESPACE); 20155845Sbostic } 20256355Sbostic NOTE("backref dissect"); 20355845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 20455845Sbostic } 20555845Sbostic if (dp != NULL) 20655845Sbostic break; 20755845Sbostic 20855845Sbostic /* uh-oh... we couldn't find a subexpression-level match */ 20955845Sbostic assert(g->backrefs); /* must be back references doing it */ 21055845Sbostic assert(g->nplus == 0 || m->lastpos != NULL); 21156355Sbostic for (;;) { 21256355Sbostic if (dp != NULL || endp <= m->coldp) 21356355Sbostic break; /* defeat */ 21456355Sbostic NOTE("backoff"); 21556355Sbostic endp = slow(m, m->coldp, endp-1, gf, gl); 21656355Sbostic if (endp == NULL) 21756355Sbostic break; /* defeat */ 21855845Sbostic /* try it on a shorter possibility */ 21956355Sbostic #ifndef NDEBUG 22055845Sbostic for (i = 1; i <= m->g->nsub; i++) { 22156355Sbostic assert(m->pmatch[i].rm_so == -1); 22256355Sbostic assert(m->pmatch[i].rm_eo == -1); 22355845Sbostic } 22456355Sbostic #endif 22556355Sbostic NOTE("backoff dissect"); 22655845Sbostic dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); 22755845Sbostic } 22855845Sbostic assert(dp == NULL || dp == endp); 22955845Sbostic if (dp != NULL) /* found a shorter one */ 23055845Sbostic break; 23155845Sbostic 23255845Sbostic /* despite initial appearances, there is no match here */ 23356355Sbostic NOTE("false alarm"); 23455845Sbostic start = m->coldp + 1; /* recycle starting later */ 23555845Sbostic assert(start <= stop); 23655845Sbostic } 23755845Sbostic 23855845Sbostic /* fill in the details if requested */ 23955845Sbostic if (nmatch > 0) { 24055845Sbostic pmatch[0].rm_so = m->coldp - m->offp; 24155845Sbostic pmatch[0].rm_eo = endp - m->offp; 24255845Sbostic } 24355845Sbostic if (nmatch > 1) { 24455845Sbostic assert(m->pmatch != NULL); 24555845Sbostic for (i = 1; i < nmatch; i++) 24655845Sbostic if (i <= m->g->nsub) 24755845Sbostic pmatch[i] = m->pmatch[i]; 24855845Sbostic else { 24955845Sbostic pmatch[i].rm_so = -1; 25055845Sbostic pmatch[i].rm_eo = -1; 25155845Sbostic } 25255845Sbostic } 25355845Sbostic 25455845Sbostic if (m->pmatch != NULL) 25555845Sbostic free((char *)m->pmatch); 25655845Sbostic if (m->lastpos != NULL) 25755845Sbostic free((char *)m->lastpos); 25855845Sbostic STATETEARDOWN(m); 25955845Sbostic return(0); 26055845Sbostic } 26155845Sbostic 26255845Sbostic /* 26355845Sbostic - dissect - figure out what matched what, no back references 26460201Sbostic == static char *dissect(register struct match *m, char *start, \ 26560201Sbostic == char *stop, sopno startst, sopno stopst); 26655845Sbostic */ 26760201Sbostic static char * /* == stop (success) always */ 26855845Sbostic dissect(m, start, stop, startst, stopst) 26955845Sbostic register struct match *m; 27060201Sbostic char *start; 27160201Sbostic char *stop; 27255845Sbostic sopno startst; 27355845Sbostic sopno stopst; 27455845Sbostic { 27555845Sbostic register int i; 27655845Sbostic register sopno ss; /* start sop of current subRE */ 27755845Sbostic register sopno es; /* end sop of current subRE */ 27860201Sbostic register char *sp; /* start of string matched by it */ 27960201Sbostic register char *stp; /* string matched by it cannot pass here */ 28060201Sbostic register char *rest; /* start of rest of string */ 28160201Sbostic register char *tail; /* string unmatched by rest of RE */ 28255845Sbostic register sopno ssub; /* start sop of subsubRE */ 28355845Sbostic register sopno esub; /* end sop of subsubRE */ 28460201Sbostic register char *ssp; /* start of string matched by subsubRE */ 28560201Sbostic register char *sep; /* end of string matched by subsubRE */ 28660201Sbostic register char *oldssp; /* previous ssp */ 28760201Sbostic register char *dp; 28855845Sbostic 28956355Sbostic AT("diss", start, stop, startst, stopst); 29055845Sbostic sp = start; 29155845Sbostic for (ss = startst; ss < stopst; ss = es) { 29255845Sbostic /* identify end of subRE */ 29355845Sbostic es = ss; 29455845Sbostic switch (OP(m->g->strip[es])) { 29555845Sbostic case OPLUS_: 29655845Sbostic case OQUEST_: 29755845Sbostic es += OPND(m->g->strip[es]); 29855845Sbostic break; 29955845Sbostic case OCH_: 30055845Sbostic while (OP(m->g->strip[es]) != O_CH) 30155845Sbostic es += OPND(m->g->strip[es]); 30255845Sbostic break; 30355845Sbostic } 30455845Sbostic es++; 30555845Sbostic 30655845Sbostic /* figure out what it matched */ 30755845Sbostic switch (OP(m->g->strip[ss])) { 30855845Sbostic case OEND: 30960201Sbostic assert(nope); 31055845Sbostic break; 31155845Sbostic case OCHAR: 31255845Sbostic sp++; 31355845Sbostic break; 31455845Sbostic case OBOL: 31555845Sbostic case OEOL: 31660201Sbostic case OBOW: 31760201Sbostic case OEOW: 31855845Sbostic break; 31955845Sbostic case OANY: 32055845Sbostic case OANYOF: 32155845Sbostic sp++; 32255845Sbostic break; 32355845Sbostic case OBACK_: 32455845Sbostic case O_BACK: 32560201Sbostic assert(nope); 32655845Sbostic break; 32755845Sbostic /* cases where length of match is hard to find */ 32855845Sbostic case OQUEST_: 32955845Sbostic stp = stop; 33055845Sbostic for (;;) { 33155845Sbostic /* how long could this one be? */ 33255845Sbostic rest = slow(m, sp, stp, ss, es); 33355845Sbostic assert(rest != NULL); /* it did match */ 33455845Sbostic /* could the rest match the rest? */ 33555845Sbostic tail = slow(m, rest, stop, es, stopst); 33655845Sbostic if (tail == stop) 33755845Sbostic break; /* yes! */ 33855845Sbostic /* no -- try a shorter match for this one */ 33955845Sbostic stp = rest - 1; 34055845Sbostic assert(stp >= sp); /* it did work */ 34155845Sbostic } 34255845Sbostic ssub = ss + 1; 34355845Sbostic esub = es - 1; 34455845Sbostic /* did innards match? */ 34555845Sbostic if (slow(m, sp, rest, ssub, esub) != NULL) { 34655845Sbostic dp = dissect(m, sp, rest, ssub, esub); 34755845Sbostic assert(dp == rest); 34855845Sbostic } else /* no */ 34955845Sbostic assert(sp == rest); 35055845Sbostic sp = rest; 35155845Sbostic break; 35255845Sbostic case OPLUS_: 35355845Sbostic stp = stop; 35455845Sbostic for (;;) { 35555845Sbostic /* how long could this one be? */ 35655845Sbostic rest = slow(m, sp, stp, ss, es); 35755845Sbostic assert(rest != NULL); /* it did match */ 35855845Sbostic /* could the rest match the rest? */ 35955845Sbostic tail = slow(m, rest, stop, es, stopst); 36055845Sbostic if (tail == stop) 36155845Sbostic break; /* yes! */ 36255845Sbostic /* no -- try a shorter match for this one */ 36355845Sbostic stp = rest - 1; 36455845Sbostic assert(stp >= sp); /* it did work */ 36555845Sbostic } 36655845Sbostic ssub = ss + 1; 36755845Sbostic esub = es - 1; 36855845Sbostic ssp = sp; 36955845Sbostic oldssp = ssp; 37055845Sbostic for (;;) { /* find last match of innards */ 37155845Sbostic sep = slow(m, ssp, rest, ssub, esub); 37255845Sbostic if (sep == NULL || sep == ssp) 37355845Sbostic break; /* failed or matched null */ 37455845Sbostic oldssp = ssp; /* on to next try */ 37555845Sbostic ssp = sep; 37655845Sbostic } 37755845Sbostic if (sep == NULL) { 37855845Sbostic /* last successful match */ 37955845Sbostic sep = ssp; 38055845Sbostic ssp = oldssp; 38155845Sbostic } 38255845Sbostic assert(sep == rest); /* must exhaust substring */ 38355845Sbostic assert(slow(m, ssp, sep, ssub, esub) == rest); 38455845Sbostic dp = dissect(m, ssp, sep, ssub, esub); 38555845Sbostic assert(dp == sep); 38655845Sbostic sp = rest; 38755845Sbostic break; 38855845Sbostic case OCH_: 38955845Sbostic stp = stop; 39055845Sbostic for (;;) { 39155845Sbostic /* how long could this one be? */ 39255845Sbostic rest = slow(m, sp, stp, ss, es); 39355845Sbostic assert(rest != NULL); /* it did match */ 39455845Sbostic /* could the rest match the rest? */ 39555845Sbostic tail = slow(m, rest, stop, es, stopst); 39655845Sbostic if (tail == stop) 39755845Sbostic break; /* yes! */ 39855845Sbostic /* no -- try a shorter match for this one */ 39955845Sbostic stp = rest - 1; 40055845Sbostic assert(stp >= sp); /* it did work */ 40155845Sbostic } 40255845Sbostic ssub = ss + 1; 40355845Sbostic esub = ss + OPND(m->g->strip[ss]) - 1; 40455845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 40555845Sbostic for (;;) { /* find first matching branch */ 40655845Sbostic if (slow(m, sp, rest, ssub, esub) == rest) 40755845Sbostic break; /* it matched all of it */ 40855845Sbostic /* that one missed, try next one */ 40955845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 41055845Sbostic esub++; 41155845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 41255845Sbostic ssub = esub + 1; 41355845Sbostic esub += OPND(m->g->strip[esub]); 41455845Sbostic if (OP(m->g->strip[esub]) == OOR2) 41555845Sbostic esub--; 41655845Sbostic else 41755845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 41855845Sbostic } 41955845Sbostic dp = dissect(m, sp, rest, ssub, esub); 42055845Sbostic assert(dp == rest); 42155845Sbostic sp = rest; 42255845Sbostic break; 42355845Sbostic case O_PLUS: 42455845Sbostic case O_QUEST: 42555845Sbostic case OOR1: 42655845Sbostic case OOR2: 42755845Sbostic case O_CH: 42860201Sbostic assert(nope); 42955845Sbostic break; 43055845Sbostic case OLPAREN: 43155845Sbostic i = OPND(m->g->strip[ss]); 43255845Sbostic m->pmatch[i].rm_so = sp - m->offp; 43355845Sbostic break; 43455845Sbostic case ORPAREN: 43555845Sbostic i = OPND(m->g->strip[ss]); 43655845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 43755845Sbostic break; 43855845Sbostic default: /* uh oh */ 43960201Sbostic assert(nope); 44055845Sbostic break; 44155845Sbostic } 44255845Sbostic } 44355845Sbostic 44455845Sbostic assert(sp == stop); 44555845Sbostic return(sp); 44655845Sbostic } 44755845Sbostic 44855845Sbostic /* 44955845Sbostic - backref - figure out what matched what, figuring in back references 45060201Sbostic == static char *backref(register struct match *m, char *start, \ 45160201Sbostic == char *stop, sopno startst, sopno stopst, sopno lev); 45255845Sbostic */ 45360201Sbostic static char * /* == stop (success) or NULL (failure) */ 45455845Sbostic backref(m, start, stop, startst, stopst, lev) 45555845Sbostic register struct match *m; 45660201Sbostic char *start; 45760201Sbostic char *stop; 45855845Sbostic sopno startst; 45955845Sbostic sopno stopst; 46055845Sbostic sopno lev; /* PLUS nesting level */ 46155845Sbostic { 46255845Sbostic register int i; 46355845Sbostic register sopno ss; /* start sop of current subRE */ 46460201Sbostic register char *sp; /* start of string matched by it */ 46555845Sbostic register sopno ssub; /* start sop of subsubRE */ 46655845Sbostic register sopno esub; /* end sop of subsubRE */ 46760201Sbostic register char *ssp; /* start of string matched by subsubRE */ 46860201Sbostic register char *dp; 46955845Sbostic register size_t len; 47055845Sbostic register int hard; 47155845Sbostic register sop s; 47255845Sbostic register regoff_t offsave; 47355845Sbostic register cset *cs; 47455845Sbostic 47556355Sbostic AT("back", start, stop, startst, stopst); 47655845Sbostic sp = start; 47755845Sbostic 47855845Sbostic /* get as far as we can with easy stuff */ 47955845Sbostic hard = 0; 48055845Sbostic for (ss = startst; !hard && ss < stopst; ss++) 48155845Sbostic switch (OP(s = m->g->strip[ss])) { 48255845Sbostic case OCHAR: 48360201Sbostic if (sp == stop || *sp++ != (char)OPND(s)) 48455845Sbostic return(NULL); 48555845Sbostic break; 48655845Sbostic case OANY: 48755845Sbostic if (sp == stop) 48855845Sbostic return(NULL); 48955845Sbostic sp++; 49055845Sbostic break; 49155845Sbostic case OANYOF: 49255845Sbostic cs = &m->g->sets[OPND(s)]; 49355845Sbostic if (sp == stop || !CHIN(cs, *sp++)) 49455845Sbostic return(NULL); 49555845Sbostic break; 49655845Sbostic case OBOL: 49755845Sbostic if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 49855845Sbostic (sp < m->endp && *(sp-1) == '\n' && 49955845Sbostic (m->g->cflags®_NEWLINE)) ) 50055845Sbostic { /* yes */ } 50155845Sbostic else 50255845Sbostic return(NULL); 50355845Sbostic break; 50455845Sbostic case OEOL: 50555845Sbostic if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || 50655845Sbostic (sp < m->endp && *sp == '\n' && 50755845Sbostic (m->g->cflags®_NEWLINE)) ) 50855845Sbostic { /* yes */ } 50955845Sbostic else 51055845Sbostic return(NULL); 51155845Sbostic break; 51260201Sbostic case OBOW: 51360201Sbostic if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || 51460201Sbostic (sp < m->endp && *(sp-1) == '\n' && 51560201Sbostic (m->g->cflags®_NEWLINE)) || 51660201Sbostic (sp > m->beginp && 517*65332Sbostic !ISWORD(*(sp-1))) ) && 518*65332Sbostic (sp < m->endp && ISWORD(*sp)) ) 51960201Sbostic { /* yes */ } 52060201Sbostic else 52160201Sbostic return(NULL); 52260201Sbostic break; 52360201Sbostic case OEOW: 52460201Sbostic if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || 52560201Sbostic (sp < m->endp && *sp == '\n' && 52660201Sbostic (m->g->cflags®_NEWLINE)) || 527*65332Sbostic (sp < m->endp && !ISWORD(*sp)) ) && 528*65332Sbostic (sp > m->beginp && ISWORD(*(sp-1))) ) 52960201Sbostic { /* yes */ } 53060201Sbostic else 53160201Sbostic return(NULL); 53260201Sbostic break; 53355845Sbostic case O_QUEST: 53455845Sbostic break; 53555845Sbostic case OOR1: /* matches null but needs to skip */ 53655845Sbostic ss++; 53755845Sbostic s = m->g->strip[ss]; 53855845Sbostic do { 53955845Sbostic assert(OP(s) == OOR2); 54055845Sbostic ss += OPND(s); 54155845Sbostic } while (OP(s = m->g->strip[ss]) != O_CH); 54255845Sbostic /* note that the ss++ gets us past the O_CH */ 54355845Sbostic break; 54455845Sbostic default: /* have to make a choice */ 54555845Sbostic hard = 1; 54655845Sbostic break; 54755845Sbostic } 54855845Sbostic if (!hard) { /* that was it! */ 54955845Sbostic if (sp != stop) 55055845Sbostic return(NULL); 55155845Sbostic return(sp); 55255845Sbostic } 55355845Sbostic ss--; /* adjust for the for's final increment */ 55455845Sbostic 55555845Sbostic /* the hard stuff */ 55656355Sbostic AT("hard", sp, stop, ss, stopst); 55755845Sbostic s = m->g->strip[ss]; 55855845Sbostic switch (OP(s)) { 55955845Sbostic case OBACK_: /* the vilest depths */ 56055845Sbostic i = OPND(s); 56155845Sbostic if (m->pmatch[i].rm_eo == -1) 56255845Sbostic return(NULL); 56355845Sbostic assert(m->pmatch[i].rm_so != -1); 56455845Sbostic len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; 56555845Sbostic assert(stop - m->beginp >= len); 56655845Sbostic if (sp > stop - len) 56755845Sbostic return(NULL); /* not enough left to match */ 56855845Sbostic ssp = m->offp + m->pmatch[i].rm_so; 56960201Sbostic if (memcmp(sp, ssp, len) != 0) 57055845Sbostic return(NULL); 57155845Sbostic while (m->g->strip[ss] != SOP(O_BACK, i)) 57255845Sbostic ss++; 57355845Sbostic return(backref(m, sp+len, stop, ss+1, stopst, lev)); 57455845Sbostic break; 57555845Sbostic case OQUEST_: /* to null or not */ 57655845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 57755845Sbostic if (dp != NULL) 57855845Sbostic return(dp); /* not */ 57955845Sbostic return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); 58055845Sbostic break; 58155845Sbostic case OPLUS_: 58255845Sbostic assert(m->lastpos != NULL); 58355845Sbostic assert(lev+1 <= m->g->nplus); 58455845Sbostic m->lastpos[lev+1] = sp; 58555845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev+1)); 58655845Sbostic break; 58755845Sbostic case O_PLUS: 58855845Sbostic if (sp == m->lastpos[lev]) /* last pass matched null */ 58955845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 59055845Sbostic /* try another pass */ 59155845Sbostic m->lastpos[lev] = sp; 59255845Sbostic dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); 59355845Sbostic if (dp == NULL) 59455845Sbostic return(backref(m, sp, stop, ss+1, stopst, lev-1)); 59555845Sbostic else 59655845Sbostic return(dp); 59755845Sbostic break; 59855845Sbostic case OCH_: /* find the right one, if any */ 59955845Sbostic ssub = ss + 1; 60055845Sbostic esub = ss + OPND(s) - 1; 60155845Sbostic assert(OP(m->g->strip[esub]) == OOR1); 60255845Sbostic for (;;) { /* find first matching branch */ 60355845Sbostic dp = backref(m, sp, stop, ssub, esub, lev); 60455845Sbostic if (dp != NULL) 60555845Sbostic return(dp); 60655845Sbostic /* that one missed, try next one */ 60755845Sbostic if (OP(m->g->strip[esub]) == O_CH) 60855845Sbostic return(NULL); /* there is none */ 60955845Sbostic esub++; 61055845Sbostic assert(OP(m->g->strip[esub]) == OOR2); 61155845Sbostic ssub = esub + 1; 61255845Sbostic esub += OPND(m->g->strip[esub]); 61355845Sbostic if (OP(m->g->strip[esub]) == OOR2) 61455845Sbostic esub--; 61555845Sbostic else 61655845Sbostic assert(OP(m->g->strip[esub]) == O_CH); 61755845Sbostic } 61855845Sbostic break; 61955845Sbostic case OLPAREN: /* must undo assignment if rest fails */ 62055845Sbostic i = OPND(s); 62155845Sbostic offsave = m->pmatch[i].rm_so; 62255845Sbostic m->pmatch[i].rm_so = sp - m->offp; 62355845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 62455845Sbostic if (dp != NULL) 62555845Sbostic return(dp); 62655845Sbostic m->pmatch[i].rm_so = offsave; 62755845Sbostic return(NULL); 62855845Sbostic break; 62955845Sbostic case ORPAREN: /* must undo assignment if rest fails */ 63055845Sbostic i = OPND(s); 63155845Sbostic offsave = m->pmatch[i].rm_eo; 63255845Sbostic m->pmatch[i].rm_eo = sp - m->offp; 63355845Sbostic dp = backref(m, sp, stop, ss+1, stopst, lev); 63455845Sbostic if (dp != NULL) 63555845Sbostic return(dp); 63655845Sbostic m->pmatch[i].rm_eo = offsave; 63755845Sbostic return(NULL); 63855845Sbostic break; 63955845Sbostic default: /* uh oh */ 64060201Sbostic assert(nope); 64155845Sbostic break; 64255845Sbostic } 64355845Sbostic 64455845Sbostic /* "can't happen" */ 64560201Sbostic assert(nope); 64655845Sbostic /* NOTREACHED */ 64755845Sbostic } 64855845Sbostic 64955845Sbostic /* 65055845Sbostic - fast - step through the string at top speed 65160201Sbostic == static char *fast(register struct match *m, char *start, \ 65260201Sbostic == char *stop, sopno startst, sopno stopst); 65355845Sbostic */ 65460201Sbostic static char * /* where tentative match ended, or NULL */ 65555845Sbostic fast(m, start, stop, startst, stopst) 65655845Sbostic register struct match *m; 65760201Sbostic char *start; 65860201Sbostic char *stop; 65955845Sbostic sopno startst; 66055845Sbostic sopno stopst; 66155845Sbostic { 66255845Sbostic register states st = m->st; 66355845Sbostic register states fresh = m->fresh; 66455845Sbostic register states tmp = m->tmp; 66560201Sbostic register char *p = start; 66660201Sbostic register int c = (start == m->beginp) ? OUT : *(start-1); 66760201Sbostic register int lastc; /* previous c */ 66860201Sbostic register int flagch; 66960201Sbostic register int i; 67060201Sbostic register char *coldp; /* last p after which no match was underway */ 67155845Sbostic 67255845Sbostic CLEAR(st); 67355845Sbostic SET1(st, startst); 67460201Sbostic st = step(m->g, startst, stopst, st, NOTHING, st); 67555845Sbostic ASSIGN(fresh, st); 67655845Sbostic SP("start", st, *p); 67755845Sbostic coldp = NULL; 67855845Sbostic for (;;) { 67955845Sbostic /* next character */ 68055845Sbostic lastc = c; 68160201Sbostic c = (p == m->endp) ? OUT : *p; 68255845Sbostic if (EQ(st, fresh)) 68355845Sbostic coldp = p; 68455845Sbostic 68555845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 68660201Sbostic flagch = '\0'; 68760201Sbostic i = 0; 68860201Sbostic if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 68960201Sbostic (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 69060201Sbostic flagch = BOL; 69160201Sbostic i = m->g->nbol; 69255845Sbostic } 69360201Sbostic if ( (c == '\n' && m->g->cflags®_NEWLINE) || 69460201Sbostic (c == OUT && !(m->eflags®_NOTEOL)) ) { 69560201Sbostic flagch = (flagch == BOL) ? BOLEOL : EOL; 69660201Sbostic i += m->g->neol; 69760201Sbostic } 69860201Sbostic if (i != 0) { 69960201Sbostic for (; i > 0; i--) 70060201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 70160201Sbostic SP("boleol", st, c); 70260201Sbostic } 70355845Sbostic 70460201Sbostic /* how about a word boundary? */ 705*65332Sbostic if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && 706*65332Sbostic (c != OUT && ISWORD(c)) ) { 70760201Sbostic flagch = BOW; 70860201Sbostic } 709*65332Sbostic if ( (lastc != OUT && ISWORD(lastc)) && 710*65332Sbostic (flagch == EOL || (c != OUT && !ISWORD(c))) ) { 71160201Sbostic flagch = EOW; 71260201Sbostic } 71360201Sbostic if (flagch == BOW || flagch == EOW) { 71460201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 71560201Sbostic SP("boweow", st, c); 71660201Sbostic } 71760201Sbostic 71855845Sbostic /* are we done? */ 71955845Sbostic if (ISSET(st, stopst) || p == stop) 72055845Sbostic break; /* NOTE BREAK OUT */ 72155845Sbostic 72255845Sbostic /* no, we must deal with this character */ 72355845Sbostic ASSIGN(tmp, st); 72455845Sbostic ASSIGN(st, fresh); 72560201Sbostic assert(c != OUT); 72655845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 72755845Sbostic SP("aft", st, c); 72860201Sbostic assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); 72955845Sbostic p++; 73055845Sbostic } 73155845Sbostic 73255845Sbostic assert(coldp != NULL); 73355845Sbostic m->coldp = coldp; 73455845Sbostic if (ISSET(st, stopst)) 73555845Sbostic return(p+1); 73655845Sbostic else 73755845Sbostic return(NULL); 73855845Sbostic } 73955845Sbostic 74055845Sbostic /* 74155845Sbostic - slow - step through the string more deliberately 74260201Sbostic == static char *slow(register struct match *m, char *start, \ 74360201Sbostic == char *stop, sopno startst, sopno stopst); 74455845Sbostic */ 74560201Sbostic static char * /* where it ended */ 74655845Sbostic slow(m, start, stop, startst, stopst) 74755845Sbostic register struct match *m; 74860201Sbostic char *start; 74960201Sbostic char *stop; 75055845Sbostic sopno startst; 75155845Sbostic sopno stopst; 75255845Sbostic { 75355845Sbostic register states st = m->st; 75455845Sbostic register states empty = m->empty; 75555845Sbostic register states tmp = m->tmp; 75660201Sbostic register char *p = start; 75760201Sbostic register int c = (start == m->beginp) ? OUT : *(start-1); 75860201Sbostic register int lastc; /* previous c */ 75960201Sbostic register int flagch; 76060201Sbostic register int i; 76160201Sbostic register char *matchp; /* last p at which a match ended */ 76255845Sbostic 76356355Sbostic AT("slow", start, stop, startst, stopst); 76455845Sbostic CLEAR(st); 76555845Sbostic SET1(st, startst); 76655845Sbostic SP("sstart", st, *p); 76760201Sbostic st = step(m->g, startst, stopst, st, NOTHING, st); 76855845Sbostic matchp = NULL; 76955845Sbostic for (;;) { 77055845Sbostic /* next character */ 77155845Sbostic lastc = c; 77260201Sbostic c = (p == m->endp) ? OUT : *p; 77355845Sbostic 77455845Sbostic /* is there an EOL and/or BOL between lastc and c? */ 77560201Sbostic flagch = '\0'; 77660201Sbostic i = 0; 77760201Sbostic if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || 77860201Sbostic (lastc == OUT && !(m->eflags®_NOTBOL)) ) { 77960201Sbostic flagch = BOL; 78060201Sbostic i = m->g->nbol; 78160201Sbostic } 78260201Sbostic if ( (c == '\n' && m->g->cflags®_NEWLINE) || 78360201Sbostic (c == OUT && !(m->eflags®_NOTEOL)) ) { 78460201Sbostic flagch = (flagch == BOL) ? BOLEOL : EOL; 78560201Sbostic i += m->g->neol; 78660201Sbostic } 78760201Sbostic if (i != 0) { 78860201Sbostic for (; i > 0; i--) 78960201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 79060201Sbostic SP("sboleol", st, c); 79160201Sbostic } 79255845Sbostic 79360201Sbostic /* how about a word boundary? */ 794*65332Sbostic if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && 795*65332Sbostic (c != OUT && ISWORD(c)) ) { 79660201Sbostic flagch = BOW; 79755845Sbostic } 798*65332Sbostic if ( (lastc != OUT && ISWORD(lastc)) && 799*65332Sbostic (flagch == EOL || (c != OUT && !ISWORD(c))) ) { 80060201Sbostic flagch = EOW; 80160201Sbostic } 80260201Sbostic if (flagch == BOW || flagch == EOW) { 80360201Sbostic st = step(m->g, startst, stopst, st, flagch, st); 80460201Sbostic SP("sboweow", st, c); 80560201Sbostic } 80655845Sbostic 80755845Sbostic /* are we done? */ 80855845Sbostic if (ISSET(st, stopst)) 80955845Sbostic matchp = p; 81055845Sbostic if (EQ(st, empty) || p == stop) 81155845Sbostic break; /* NOTE BREAK OUT */ 81255845Sbostic 81355845Sbostic /* no, we must deal with this character */ 81455845Sbostic ASSIGN(tmp, st); 81555845Sbostic ASSIGN(st, empty); 81660201Sbostic assert(c != OUT); 81755845Sbostic st = step(m->g, startst, stopst, tmp, c, st); 81855845Sbostic SP("saft", st, c); 81960201Sbostic assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); 82055845Sbostic p++; 82155845Sbostic } 82255845Sbostic 82355845Sbostic return(matchp); 82455845Sbostic } 82555845Sbostic 82655845Sbostic 82755845Sbostic /* 82855845Sbostic - step - map set of states reachable before char to set reachable after 82960201Sbostic == static states step(register struct re_guts *g, int start, int stop, \ 83060201Sbostic == register states bef, int ch, register states aft); 83160201Sbostic == #define BOL (OUT+1) 83260201Sbostic == #define EOL (BOL+1) 83360201Sbostic == #define BOLEOL (BOL+2) 83460201Sbostic == #define NOTHING (BOL+3) 83560201Sbostic == #define BOW (BOL+4) 83660201Sbostic == #define EOW (BOL+5) 83760201Sbostic == #define CODEMAX (BOL+5) // highest code used 83860201Sbostic == #define NONCHAR(c) ((c) > CHAR_MAX) 83960201Sbostic == #define NNONCHAR (CODEMAX-CHAR_MAX) 84055845Sbostic */ 84155845Sbostic static states 84255845Sbostic step(g, start, stop, bef, ch, aft) 84355845Sbostic register struct re_guts *g; 84455845Sbostic int start; /* start state within strip */ 84555845Sbostic int stop; /* state after stop state within strip */ 84655845Sbostic register states bef; /* states reachable before */ 84760201Sbostic int ch; /* character or NONCHAR code */ 84855845Sbostic register states aft; /* states already known reachable after */ 84955845Sbostic { 85055845Sbostic register cset *cs; 85155845Sbostic register sop s; 85255845Sbostic register sopno pc; 85355845Sbostic register onestate here; /* note, macros know this name */ 85455845Sbostic register sopno look; 85555845Sbostic register int i; 85655845Sbostic 85755845Sbostic for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { 85855845Sbostic s = g->strip[pc]; 85955845Sbostic switch (OP(s)) { 86055845Sbostic case OEND: 86155845Sbostic assert(pc == stop-1); 86255845Sbostic break; 86355845Sbostic case OCHAR: 86460201Sbostic /* only characters can match */ 86560201Sbostic assert(!NONCHAR(ch) || ch != (char)OPND(s)); 86660201Sbostic if (ch == (char)OPND(s)) 86755845Sbostic FWD(aft, bef, 1); 86855845Sbostic break; 86960201Sbostic case OBOL: 87060201Sbostic if (ch == BOL || ch == BOLEOL) 87160201Sbostic FWD(aft, bef, 1); 87260201Sbostic break; 87355845Sbostic case OEOL: 87460201Sbostic if (ch == EOL || ch == BOLEOL) 87560201Sbostic FWD(aft, bef, 1); 87655845Sbostic break; 87760201Sbostic case OBOW: 87860201Sbostic if (ch == BOW) 87960201Sbostic FWD(aft, bef, 1); 88060201Sbostic break; 88160201Sbostic case OEOW: 88260201Sbostic if (ch == EOW) 88360201Sbostic FWD(aft, bef, 1); 88460201Sbostic break; 88555845Sbostic case OANY: 88660201Sbostic if (!NONCHAR(ch)) 88760201Sbostic FWD(aft, bef, 1); 88855845Sbostic break; 88955845Sbostic case OANYOF: 89055845Sbostic cs = &g->sets[OPND(s)]; 89160201Sbostic if (!NONCHAR(ch) && CHIN(cs, ch)) 89255845Sbostic FWD(aft, bef, 1); 89355845Sbostic break; 89455845Sbostic case OBACK_: /* ignored here */ 89555845Sbostic case O_BACK: 89655845Sbostic FWD(aft, aft, 1); 89755845Sbostic break; 89855845Sbostic case OPLUS_: /* forward, this is just an empty */ 89955845Sbostic FWD(aft, aft, 1); 90055845Sbostic break; 90155845Sbostic case O_PLUS: /* both forward and back */ 90255845Sbostic FWD(aft, aft, 1); 90355845Sbostic i = ISSETBACK(aft, OPND(s)); 90455845Sbostic BACK(aft, aft, OPND(s)); 90555845Sbostic if (!i && ISSETBACK(aft, OPND(s))) { 90655845Sbostic /* oho, must reconsider loop body */ 90755845Sbostic pc -= OPND(s) + 1; 90855845Sbostic INIT(here, pc); 90955845Sbostic } 91055845Sbostic break; 91155845Sbostic case OQUEST_: /* two branches, both forward */ 91255845Sbostic FWD(aft, aft, 1); 91355845Sbostic FWD(aft, aft, OPND(s)); 91455845Sbostic break; 91555845Sbostic case O_QUEST: /* just an empty */ 91655845Sbostic FWD(aft, aft, 1); 91755845Sbostic break; 91855845Sbostic case OLPAREN: /* not significant here */ 91955845Sbostic case ORPAREN: 92055845Sbostic FWD(aft, aft, 1); 92155845Sbostic break; 92255845Sbostic case OCH_: /* mark the first two branches */ 92355845Sbostic FWD(aft, aft, 1); 92455845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 92555845Sbostic FWD(aft, aft, OPND(s)); 92655845Sbostic break; 92755845Sbostic case OOR1: /* done a branch, find the O_CH */ 92855845Sbostic if (ISSTATEIN(aft, here)) { 92955845Sbostic for (look = 1; 93055845Sbostic OP(s = g->strip[pc+look]) != O_CH; 93155845Sbostic look += OPND(s)) 93255845Sbostic assert(OP(s) == OOR2); 93355845Sbostic FWD(aft, aft, look); 93455845Sbostic } 93555845Sbostic break; 93655845Sbostic case OOR2: /* propagate OCH_'s marking */ 93755845Sbostic FWD(aft, aft, 1); 93855845Sbostic if (OP(g->strip[pc+OPND(s)]) != O_CH) { 93955845Sbostic assert(OP(g->strip[pc+OPND(s)]) == OOR2); 94055845Sbostic FWD(aft, aft, OPND(s)); 94155845Sbostic } 94255845Sbostic break; 94355845Sbostic case O_CH: /* just empty */ 94455845Sbostic FWD(aft, aft, 1); 94555845Sbostic break; 94655845Sbostic default: /* ooooops... */ 94760201Sbostic assert(nope); 94855845Sbostic break; 94955845Sbostic } 95055845Sbostic } 95155845Sbostic 95255845Sbostic return(aft); 95355845Sbostic } 95455845Sbostic 95556355Sbostic #ifdef REDEBUG 95655845Sbostic /* 95755845Sbostic - print - print a set of states 95860201Sbostic == #ifdef REDEBUG 95960201Sbostic == static void print(struct match *m, char *caption, states st, \ 96060201Sbostic == int ch, FILE *d); 96160201Sbostic == #endif 96255845Sbostic */ 96355845Sbostic static void 96456355Sbostic print(m, caption, st, ch, d) 96556355Sbostic struct match *m; 96655845Sbostic char *caption; 96755845Sbostic states st; 96860201Sbostic int ch; 96955845Sbostic FILE *d; 97055845Sbostic { 97156355Sbostic register struct re_guts *g = m->g; 97255845Sbostic register int i; 97355845Sbostic register int first = 1; 97455845Sbostic 97556355Sbostic if (!(m->eflags®_TRACE)) 97656355Sbostic return; 97756355Sbostic 97855845Sbostic fprintf(d, "%s", caption); 97955845Sbostic if (ch != '\0') 98056355Sbostic fprintf(d, " %s", pchar(ch)); 98155845Sbostic for (i = 0; i < g->nstates; i++) 98255845Sbostic if (ISSET(st, i)) { 98355845Sbostic fprintf(d, "%s%d", (first) ? "\t" : ", ", i); 98455845Sbostic first = 0; 98555845Sbostic } 98655845Sbostic fprintf(d, "\n"); 98755845Sbostic } 98856355Sbostic 98956355Sbostic /* 99056355Sbostic - at - print current situation 99160201Sbostic == #ifdef REDEBUG 99260201Sbostic == static void at(struct match *m, char *title, char *start, char *stop, \ 99360201Sbostic == sopno startst, stopno stopst); 99460201Sbostic == #endif 99556355Sbostic */ 99656355Sbostic static void 99756355Sbostic at(m, title, start, stop, startst, stopst) 99856355Sbostic struct match *m; 99956355Sbostic char *title; 100060201Sbostic char *start; 100160201Sbostic char *stop; 100256355Sbostic sopno startst; 100356355Sbostic sopno stopst; 100456355Sbostic { 100556355Sbostic if (!(m->eflags®_TRACE)) 100656355Sbostic return; 100756355Sbostic 100856355Sbostic printf("%s %s-", title, pchar(*start)); 100956355Sbostic printf("%s ", pchar(*stop)); 101056355Sbostic printf("%ld-%ld\n", (long)startst, (long)stopst); 101156355Sbostic } 101256355Sbostic 101356355Sbostic #ifndef PCHARDONE 101456355Sbostic #define PCHARDONE /* never again */ 101556355Sbostic /* 101656355Sbostic - pchar - make a character printable 101760201Sbostic == #ifdef REDEBUG 101860201Sbostic == static char *pchar(int ch); 101960201Sbostic == #endif 102056355Sbostic * 102156355Sbostic * Is this identical to regchar() over in debug.c? Well, yes. But a 102256355Sbostic * duplicate here avoids having a debugging-capable regexec.o tied to 102356355Sbostic * a matching debug.o, and this is convenient. It all disappears in 102456355Sbostic * the non-debug compilation anyway, so it doesn't matter much. 102556355Sbostic */ 102656355Sbostic static char * /* -> representation */ 102756355Sbostic pchar(ch) 102856355Sbostic int ch; 102956355Sbostic { 103056355Sbostic static char pbuf[10]; 103156355Sbostic 103256355Sbostic if (isprint(ch) || ch == ' ') 103356355Sbostic sprintf(pbuf, "%c", ch); 103456355Sbostic else 103556355Sbostic sprintf(pbuf, "\\%o", ch); 103656355Sbostic return(pbuf); 103756355Sbostic } 103855845Sbostic #endif 103956355Sbostic #endif 104055845Sbostic 104155845Sbostic #undef matcher 104255845Sbostic #undef fast 104355845Sbostic #undef slow 104455845Sbostic #undef dissect 104555845Sbostic #undef backref 104655845Sbostic #undef step 104755845Sbostic #undef print 104856355Sbostic #undef at 104955845Sbostic #undef match 1050