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
7*66406Sbostic * Henry Spencer.
855845Sbostic *
955845Sbostic * %sccs.include.redist.c%
1055845Sbostic *
11*66406Sbostic * @(#)engine.c 8.5 (Berkeley) 03/20/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 === */
6766385Sbostic static int matcher __P((struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags));
6866385Sbostic static char *dissect __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
6966385Sbostic static char *backref __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev));
7066385Sbostic static char *fast __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
7166385Sbostic static char *slow __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst));
7266385Sbostic 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
8366385Sbostic static void print __P((struct match *m, char *caption, states st, int ch, FILE *d));
8460201Sbostic #endif
8560201Sbostic #ifdef REDEBUG
8666385Sbostic static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
8760201Sbostic #endif
8860201Sbostic #ifdef REDEBUG
8966385Sbostic 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 */
matcher(g,string,nmatch,pmatch,eflags)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 */
dissect(m,start,stop,startst,stopst)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) */
backref(m,start,stop,startst,stopst,lev)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 */
fast(m,start,stop,startst,stopst)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 */
slow(m,start,stop,startst,stopst)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
step(g,start,stop,bef,ch,aft)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
print(m,caption,st,ch,d)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
at(m,title,start,stop,startst,stopst)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 */
pchar(ch)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