1 /* $NetBSD: engine.c,v 1.7 2011/11/19 17:45:11 tnozaki Exp $ */
4 * Copyright (c) 1992, 1993, 1994 Henry Spencer.
5 * Copyright (c) 1992, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Henry Spencer of the University of Toronto.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * @(#)engine.c 8.4 (Berkeley) 3/19/94
43 * The matching engine and friends. This file is #included by regexec.c
44 * after suitable #defines of a variety of macros used herein, so that
45 * different state representations can be used without duplicating masses
50 #define matcher smatcher
53 #define dissect sdissect
54 #define backref sbackref
61 #define matcher lmatcher
64 #define dissect ldissect
65 #define backref lbackref
72 /* another structure passed up and down to avoid zillions of parameters */
76 regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
77 const RCHAR_T *offp; /* offsets work from here */
78 const RCHAR_T *beginp; /* start of string -- virtual NUL precedes */
79 const RCHAR_T *endp; /* end of string -- virtual NUL here */
80 const RCHAR_T *coldp; /* can be no match starting before here */
81 const RCHAR_T **lastpos; /* [nplus+1] */
83 states st; /* current states */
84 states fresh; /* states for a fresh start */
85 states tmp; /* temporary */
86 states empty; /* empty set of states */
89 /* ========= begin header generated by ./mkh ========= */
94 /* === engine.c === */
95 static int matcher __P((struct re_guts *g, const RCHAR_T *string, size_t nmatch, regmatch_t pmatch[], int eflags));
96 static const RCHAR_T *dissect __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
97 static const RCHAR_T *backref __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev));
98 static const RCHAR_T *fast __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
99 static const RCHAR_T *slow __P((struct match *m, const RCHAR_T *start, const RCHAR_T *stop, sopno startst, sopno stopst));
100 static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int flag, RCHAR_T ch, states aft));
103 #define BOLEOL (BOL+2)
104 #define NOTHING (BOL+3)
108 static void print __P((struct match *m, char *caption, states st, int ch, FILE *d));
111 static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst));
114 static char *pchar __P((int ch));
120 /* ========= end header generated by ./mkh ========= */
123 #define SP(t, s, c) print(m, t, s, c, stdout)
124 #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
125 #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); }
127 #define SP(t, s, c) /* nothing */
128 #define AT(t, p1, p2, s1, s2) /* nothing */
129 #define NOTE(s) /* nothing */
133 - matcher - the actual matching engine
134 == static int matcher(register struct re_guts *g, const RCHAR_T *string, \
135 == size_t nmatch, regmatch_t pmatch[], int eflags);
137 static int /* 0 success, REG_NOMATCH failure */
138 matcher(g, string, nmatch, pmatch, eflags)
139 register struct re_guts *g;
140 const RCHAR_T *string;
145 register const RCHAR_T *endp;
148 register struct match *m = &mv;
149 register const RCHAR_T *dp;
150 register const sopno gf = g->firststate+1; /* +1 for OEND */
151 register const sopno gl = g->laststate;
152 const RCHAR_T *start;
155 /* simplify the situation where possible */
156 if (g->cflags®_NOSUB)
158 if (eflags®_STARTEND) {
159 start = string + pmatch[0].rm_so;
160 stop = string + pmatch[0].rm_eo;
163 stop = start + STRLEN(start);
168 /* prescreening; this does wonders for this rather slow code */
169 if (g->must != NULL) {
170 for (dp = start; dp < stop; dp++)
171 if (*dp == g->must[0] && (size_t)(stop - dp) >= g->mlen &&
172 MEMCMP(dp, g->must, g->mlen) == 0)
174 if (dp == stop) /* we didn't find g->must */
178 /* match struct setup */
193 /* this loop does only one repetition except for backrefs */
195 endp = fast(m, start, stop, gf, gl);
196 if (endp == NULL) { /* a miss */
200 if (nmatch == 0 && !g->backrefs)
201 break; /* no further info needed */
204 assert(m->coldp != NULL);
206 NOTE("finding start");
207 endp = slow(m, m->coldp, stop, gf, gl);
210 assert(m->coldp < m->endp);
213 if (nmatch == 1 && !g->backrefs)
214 break; /* no further info needed */
216 /* oh my, he wants the subexpressions... */
217 if (m->pmatch == NULL)
218 m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
220 if (m->pmatch == NULL) {
224 for (i = 1; i <= m->g->nsub; i++)
225 m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
226 if (!g->backrefs && !(m->eflags®_BACKR)) {
228 dp = dissect(m, m->coldp, endp, gf, gl);
230 if (g->nplus > 0 && m->lastpos == NULL)
231 m->lastpos = (const RCHAR_T **)malloc((g->nplus+1) *
232 sizeof(const RCHAR_T *));
233 if (g->nplus > 0 && m->lastpos == NULL) {
238 NOTE("backref dissect");
239 dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
244 /* uh-oh... we couldn't find a subexpression-level match */
245 assert(g->backrefs); /* must be back references doing it */
246 assert(g->nplus == 0 || m->lastpos != NULL);
248 if (dp != NULL || endp <= m->coldp)
251 endp = slow(m, m->coldp, endp-1, gf, gl);
254 /* try it on a shorter possibility */
256 for (i = 1; i <= m->g->nsub; i++) {
257 assert(m->pmatch[i].rm_so == -1);
258 assert(m->pmatch[i].rm_eo == -1);
261 NOTE("backoff dissect");
262 dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
264 assert(dp == NULL || dp == endp);
265 if (dp != NULL) /* found a shorter one */
268 /* despite initial appearances, there is no match here */
270 start = m->coldp + 1; /* recycle starting later */
271 assert(start <= stop);
274 /* fill in the details if requested */
276 pmatch[0].rm_so = m->coldp - m->offp;
277 pmatch[0].rm_eo = endp - m->offp;
280 assert(m->pmatch != NULL);
281 for (i = 1; i < nmatch; i++)
283 pmatch[i] = m->pmatch[i];
285 pmatch[i].rm_so = -1;
286 pmatch[i].rm_eo = -1;
290 if (m->pmatch != NULL)
291 free((char *)m->pmatch);
292 if (m->lastpos != NULL)
293 free((char *)m->lastpos);
299 - dissect - figure out what matched what, no back references
300 == static const RCHAR_T *dissect(register struct match *m, const RCHAR_T *start, \
301 == const RCHAR_T *stop, sopno startst, sopno stopst);
303 static const RCHAR_T * /* == stop (success) always */
304 dissect(m, start, stop, startst, stopst)
305 register struct match *m;
306 const RCHAR_T *start;
312 register sopno ss; /* start sop of current subRE */
313 register sopno es; /* end sop of current subRE */
314 register const RCHAR_T *sp; /* start of string matched by it */
315 register const RCHAR_T *stp; /* string matched by it cannot pass here */
316 register const RCHAR_T *rest; /* start of rest of string */
317 register const RCHAR_T *tail; /* string unmatched by rest of RE */
318 register sopno ssub; /* start sop of subsubRE */
319 register sopno esub; /* end sop of subsubRE */
320 register const RCHAR_T *ssp; /* start of string matched by subsubRE */
321 register const RCHAR_T *sep; /* end of string matched by subsubRE */
322 register const RCHAR_T *oldssp; /* previous ssp */
323 register const RCHAR_T *dp;
325 AT("diss", start, stop, startst, stopst);
327 for (ss = startst; ss < stopst; ss = es) {
328 /* identify end of subRE */
330 switch (m->g->strip[es]) {
333 es += m->g->stripdata[es];
336 while (m->g->strip[es] != O_CH)
337 es += m->g->stripdata[es];
342 /* figure out what it matched */
343 switch (m->g->strip[ss]) {
363 /* cases where length of match is hard to find */
367 /* how long could this one be? */
368 rest = slow(m, sp, stp, ss, es);
369 assert(rest != NULL); /* it did match */
370 /* could the rest match the rest? */
371 tail = slow(m, rest, stop, es, stopst);
374 /* no -- try a shorter match for this one */
376 assert(stp >= sp); /* it did work */
380 /* did innards match? */
381 if (slow(m, sp, rest, ssub, esub) != NULL) {
382 dp = dissect(m, sp, rest, ssub, esub);
391 /* how long could this one be? */
392 rest = slow(m, sp, stp, ss, es);
393 assert(rest != NULL); /* it did match */
394 /* could the rest match the rest? */
395 tail = slow(m, rest, stop, es, stopst);
398 /* no -- try a shorter match for this one */
400 assert(stp >= sp); /* it did work */
406 for (;;) { /* find last match of innards */
407 sep = slow(m, ssp, rest, ssub, esub);
408 if (sep == NULL || sep == ssp)
409 break; /* failed or matched null */
410 oldssp = ssp; /* on to next try */
414 /* last successful match */
418 assert(sep == rest); /* must exhaust substring */
419 assert(slow(m, ssp, sep, ssub, esub) == rest);
420 dp = dissect(m, ssp, sep, ssub, esub);
427 /* how long could this one be? */
428 rest = slow(m, sp, stp, ss, es);
429 assert(rest != NULL); /* it did match */
430 /* could the rest match the rest? */
431 tail = slow(m, rest, stop, es, stopst);
434 /* no -- try a shorter match for this one */
436 assert(stp >= sp); /* it did work */
439 esub = ss + m->g->stripdata[ss] - 1;
440 assert(m->g->strip[esub] == OOR1);
441 for (;;) { /* find first matching branch */
442 if (slow(m, sp, rest, ssub, esub) == rest)
443 break; /* it matched all of it */
444 /* that one missed, try next one */
445 assert(m->g->strip[esub] == OOR1);
447 assert(m->g->strip[esub] == OOR2);
449 esub += m->g->stripdata[esub];
450 if (m->g->strip[esub] == OOR2)
453 assert(m->g->strip[esub] == O_CH);
455 dp = dissect(m, sp, rest, ssub, esub);
467 i = m->g->stripdata[ss];
468 assert(0 < i && i <= m->g->nsub);
469 m->pmatch[i].rm_so = sp - m->offp;
472 i = m->g->stripdata[ss];
473 assert(0 < i && i <= m->g->nsub);
474 m->pmatch[i].rm_eo = sp - m->offp;
487 - backref - figure out what matched what, figuring in back references
488 == static const RCHAR_T *backref(register struct match *m, const RCHAR_T *start, \
489 == const RCHAR_T *stop, sopno startst, sopno stopst, sopno lev);
491 static const RCHAR_T * /* == stop (success) or NULL (failure) */
492 backref(m, start, stop, startst, stopst, lev)
493 register struct match *m;
494 const RCHAR_T *start;
498 sopno lev; /* PLUS nesting level */
501 register sopno ss; /* start sop of current subRE */
502 register const RCHAR_T *sp; /* start of string matched by it */
503 register sopno ssub; /* start sop of subsubRE */
504 register sopno esub; /* end sop of subsubRE */
505 register const RCHAR_T *ssp; /* start of string matched by subsubRE */
506 register const RCHAR_T *dp;
511 register regoff_t offsave;
514 AT("back", start, stop, startst, stopst);
517 /* get as far as we can with easy stuff */
519 for (ss = startst; !hard && ss < stopst; ss++) {
521 d = m->g->stripdata[ss];
524 if (sp == stop || *sp++ != d)
534 if (sp == stop || !CHIN(cs, *sp++))
538 if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) ||
539 (sp < m->endp && *(sp-1) == '\n' &&
540 (m->g->cflags®_NEWLINE)) )
546 if ( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
547 (sp < m->endp && *sp == '\n' &&
548 (m->g->cflags®_NEWLINE)) )
554 if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) ||
555 (sp < m->endp && *(sp-1) == '\n' &&
556 (m->g->cflags®_NEWLINE)) ||
558 !ISWORD(*(sp-1))) ) &&
559 (sp < m->endp && ISWORD(*sp)) )
565 if (( (sp == m->endp && !(m->eflags®_NOTEOL)) ||
566 (sp < m->endp && *sp == '\n' &&
567 (m->g->cflags®_NEWLINE)) ||
568 (sp < m->endp && !ISWORD(*sp)) ) &&
569 (sp > m->beginp && ISWORD(*(sp-1))) )
576 case OOR1: /* matches null but needs to skip */
579 d = m->g->stripdata[ss];
584 d = m->g->stripdata[ss];
586 /* note that the ss++ gets us past the O_CH */
588 default: /* have to make a choice */
593 if (!hard) { /* that was it! */
598 ss--; /* adjust for the for's final increment */
601 AT("hard", sp, stop, ss, stopst);
603 d = m->g->stripdata[ss];
605 case OBACK_: /* the vilest depths */
607 assert(0 < i && i <= m->g->nsub);
608 if (m->pmatch[i].rm_eo == -1)
610 assert(m->pmatch[i].rm_so != -1);
611 len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
612 assert(stop - m->beginp >= len);
614 return(NULL); /* not enough left to match */
615 ssp = m->offp + m->pmatch[i].rm_so;
616 if (memcmp(sp, ssp, len) != 0)
618 while (m->g->strip[ss] != O_BACK || m->g->stripdata[ss] != i)
620 return(backref(m, sp+len, stop, ss+1, stopst, lev));
622 case OQUEST_: /* to null or not */
623 dp = backref(m, sp, stop, ss+1, stopst, lev);
625 return(dp); /* not */
626 return(backref(m, sp, stop, ss+d+1, stopst, lev));
629 assert(m->lastpos != NULL);
630 assert(lev+1 <= m->g->nplus);
631 m->lastpos[lev+1] = sp;
632 return(backref(m, sp, stop, ss+1, stopst, lev+1));
635 if (sp == m->lastpos[lev]) /* last pass matched null */
636 return(backref(m, sp, stop, ss+1, stopst, lev-1));
637 /* try another pass */
638 m->lastpos[lev] = sp;
639 dp = backref(m, sp, stop, ss-d+1, stopst, lev);
641 return(backref(m, sp, stop, ss+1, stopst, lev-1));
645 case OCH_: /* find the right one, if any */
648 assert(m->g->strip[esub] == OOR1);
649 for (;;) { /* find first matching branch */
650 dp = backref(m, sp, stop, ssub, esub, lev);
653 /* that one missed, try next one */
654 if (m->g->strip[esub] == O_CH)
655 return(NULL); /* there is none */
657 assert(m->g->strip[esub] == OOR2);
659 esub += m->g->stripdata[esub];
660 if (m->g->strip[esub] == OOR2)
663 assert(m->g->strip[esub] == O_CH);
666 case OLPAREN: /* must undo assignment if rest fails */
668 assert(0 < i && i <= m->g->nsub);
669 offsave = m->pmatch[i].rm_so;
670 m->pmatch[i].rm_so = sp - m->offp;
671 dp = backref(m, sp, stop, ss+1, stopst, lev);
674 m->pmatch[i].rm_so = offsave;
677 case ORPAREN: /* must undo assignment if rest fails */
679 assert(0 < i && i <= m->g->nsub);
680 offsave = m->pmatch[i].rm_eo;
681 m->pmatch[i].rm_eo = sp - m->offp;
682 dp = backref(m, sp, stop, ss+1, stopst, lev);
685 m->pmatch[i].rm_eo = offsave;
700 - fast - step through the string at top speed
701 == static const RCHAR_T *fast(register struct match *m, const RCHAR_T *start, \
702 == const RCHAR_T *stop, sopno startst, sopno stopst);
704 static const RCHAR_T * /* where tentative match ended, or NULL */
705 fast(m, start, stop, startst, stopst)
706 register struct match *m;
707 const RCHAR_T *start;
712 register states st = m->st;
713 register states fresh = m->fresh;
714 register states tmp = m->tmp;
715 register const RCHAR_T *p = start;
716 register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
717 register RCHAR_T lastc; /* previous c */
720 register const RCHAR_T *coldp; /* last p after which no match was underway */
724 st = step(m->g, startst, stopst, st, NOTHING, OUT, st);
731 c = (p == m->endp) ? OUT : *p;
735 /* is there an EOL and/or BOL between lastc and c? */
738 if ( (lastc == '\n' && m->g->cflags®_NEWLINE) ||
739 (lastc == OUT && !(m->eflags®_NOTBOL)) ) {
743 if ( (c == '\n' && m->g->cflags®_NEWLINE) ||
744 (c == OUT && !(m->eflags®_NOTEOL)) ) {
745 flag = (flag == BOL) ? BOLEOL : EOL;
750 st = step(m->g, startst, stopst, st, flag, OUT, st);
754 /* how about a word boundary? */
755 if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) &&
756 (c != OUT && ISWORD(c)) ) {
759 if ( (lastc != OUT && ISWORD(lastc)) &&
760 (flag == EOL || (c != OUT && !ISWORD(c))) ) {
763 if (flag == BOW || flag == EOW) {
764 st = step(m->g, startst, stopst, st, flag, OUT, st);
769 if (ISSET(st, stopst) || p == stop)
770 break; /* NOTE BREAK OUT */
772 /* no, we must deal with this character */
776 st = step(m->g, startst, stopst, tmp, 0, c, st);
778 assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st));
782 assert(coldp != NULL);
784 if (ISSET(st, stopst))
791 - slow - step through the string more deliberately
792 == static const RCHAR_T *slow(register struct match *m, const RCHAR_T *start, \
793 == const RCHAR_T *stop, sopno startst, sopno stopst);
795 static const RCHAR_T * /* where it ended */
796 slow(m, start, stop, startst, stopst)
797 register struct match *m;
798 const RCHAR_T *start;
803 register states st = m->st;
804 register states empty = m->empty;
805 register states tmp = m->tmp;
806 register const RCHAR_T *p = start;
807 register RCHAR_T c = (start == m->beginp) ? OUT : *(start-1);
808 register RCHAR_T lastc; /* previous c */
811 register const RCHAR_T *matchp; /* last p at which a match ended */
813 AT("slow", start, stop, startst, stopst);
816 SP("sstart", st, *p);
817 st = step(m->g, startst, stopst, st, NOTHING, OUT, st);
822 c = (p == m->endp) ? OUT : *p;
824 /* is there an EOL and/or BOL between lastc and c? */
827 if ( (lastc == '\n' && m->g->cflags®_NEWLINE) ||
828 (lastc == OUT && !(m->eflags®_NOTBOL)) ) {
832 if ( (c == '\n' && m->g->cflags®_NEWLINE) ||
833 (c == OUT && !(m->eflags®_NOTEOL)) ) {
834 flag = (flag == BOL) ? BOLEOL : EOL;
839 st = step(m->g, startst, stopst, st, flag, OUT, st);
840 SP("sboleol", st, c);
843 /* how about a word boundary? */
844 if ( (flag == BOL || (lastc != OUT && !ISWORD(lastc))) &&
845 (c != OUT && ISWORD(c)) ) {
848 if ( (lastc != OUT && ISWORD(lastc)) &&
849 (flag == EOL || (c != OUT && !ISWORD(c))) ) {
852 if (flag == BOW || flag == EOW) {
853 st = step(m->g, startst, stopst, st, flag, OUT, st);
854 SP("sboweow", st, c);
858 if (ISSET(st, stopst))
860 if (EQ(st, empty) || p == stop)
861 break; /* NOTE BREAK OUT */
863 /* no, we must deal with this character */
867 st = step(m->g, startst, stopst, tmp, 0, c, st);
869 assert(EQ(step(m->g, startst, stopst, st, NOTHING, OUT, st), st));
878 - step - map set of states reachable before char to set reachable after
879 == static states step(register struct re_guts *g, sopno start, sopno stop, \
880 == register states bef, int flag, RCHAR_T ch, register states aft);
882 == #define EOL (BOL+1)
883 == #define BOLEOL (BOL+2)
884 == #define NOTHING (BOL+3)
885 == #define BOW (BOL+4)
886 == #define EOW (BOL+5)
889 step(g, start, stop, bef, flag, ch, aft)
890 register struct re_guts *g;
891 sopno start; /* start state within strip */
892 sopno stop; /* state after stop state within strip */
893 register states bef; /* states reachable before */
894 int flag; /* NONCHAR flag */
895 RCHAR_T ch; /* character code */
896 register states aft; /* states already known reachable after */
902 register onestate here; /* note, macros know this name */
906 for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
908 d = g->stripdata[pc];
911 assert(pc == stop-1);
914 /* only characters can match */
915 assert(!flag || ch != d);
920 if (flag == BOL || flag == BOLEOL)
924 if (flag == EOL || flag == BOLEOL)
941 if (!flag && CHIN(cs, ch))
944 case OBACK_: /* ignored here */
948 case OPLUS_: /* forward, this is just an empty */
951 case O_PLUS: /* both forward and back */
953 i = ISSETBACK(aft, d);
955 if (!i && ISSETBACK(aft, d)) {
956 /* oho, must reconsider loop body */
961 case OQUEST_: /* two branches, both forward */
965 case O_QUEST: /* just an empty */
968 case OLPAREN: /* not significant here */
972 case OCH_: /* mark the first two branches */
974 assert(OP(g->strip[pc+d]) == OOR2);
977 case OOR1: /* done a branch, find the O_CH */
978 if (ISSTATEIN(aft, here)) {
979 for (look = 1; /**/; look += d) {
980 s = g->strip[pc+look];
981 d = g->stripdata[pc+look];
989 case OOR2: /* propagate OCH_'s marking */
991 if (g->strip[pc+d] != O_CH) {
992 assert(g->strip[pc+d] == OOR2);
996 case O_CH: /* just empty */
999 default: /* ooooops... */
1010 - print - print a set of states
1012 == static void print(struct match *m, char *caption, states st, \
1013 == int ch, FILE *d);
1017 print(m, caption, st, ch, d)
1024 register struct re_guts *g = m->g;
1026 register int first = 1;
1028 if (!(m->eflags®_TRACE))
1031 fprintf(d, "%s", caption);
1033 fprintf(d, " %s", pchar(ch));
1034 for (i = 0; i < g->nstates; i++)
1036 fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
1043 - at - print current situation
1045 == static void at(struct match *m, char *title, char *start, char *stop, \
1046 == sopno startst, sopno stopst);
1050 at(m, title, start, stop, startst, stopst)
1058 if (!(m->eflags®_TRACE))
1061 printf("%s %s-", title, pchar(*start));
1062 printf("%s ", pchar(*stop));
1063 printf("%ld-%ld\n", (long)startst, (long)stopst);
1067 #define PCHARDONE /* never again */
1069 - pchar - make a character printable
1071 == static char *pchar(int ch);
1074 * Is this identical to regchar() over in debug.c? Well, yes. But a
1075 * duplicate here avoids having a debugging-capable regexec.o tied to
1076 * a matching debug.o, and this is convenient. It all disappears in
1077 * the non-debug compilation anyway, so it doesn't matter much.
1079 static char * /* -> representation */
1083 static char pbuf[10];
1085 if (isprint(ch) || ch == ' ')
1086 snprintf(pbuf, sizeof(pbuf), "%c", ch);
1088 snprintf(pbuf, sizeof(pbuf), "\\%o", ch);