2 * The matching engine and friends. This file is #included by regexec.c
3 * after suitable #defines of a variety of macros used herein, so that
4 * different state representations can be used without duplicating masses
9 #define matcher smatcher
12 #define dissect sdissect
13 #define backref sbackref
20 #define matcher lmatcher
23 #define dissect ldissect
24 #define backref lbackref
31 /* another structure passed up and down to avoid zillions of parameters */
35 my_regmatch_t
*pmatch
; /* [nsub+1] (0 element unused) */
36 char *offp
; /* offsets work from here */
37 char *beginp
; /* start of string -- virtual NUL precedes */
38 char *endp
; /* end of string -- virtual NUL here */
39 char *coldp
; /* can be no match starting before here */
40 char **lastpos
; /* [nplus+1] */
42 states st
; /* current states */
43 states fresh
; /* states for a fresh start */
44 states tmp
; /* temporary */
45 states empty
; /* empty set of states */
51 #define SP(t, s, c) print(m, t, s, c, stdout)
52 #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
53 #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); }
55 #define SP(t, s, c) /* nothing */
56 #define AT(t, p1, p2, s1, s2) /* nothing */
57 #define NOTE(s) /* nothing */
61 - matcher - the actual matching engine
62 == static int matcher(register struct re_guts *g, char *string, \
63 == size_t nmatch, regmatch_t pmatch[], int eflags);
65 static int /* 0 success, REG_NOMATCH failure */
66 matcher(charset
,g
, str
, nmatch
, pmatch
, eflags
)
67 CHARSET_INFO
*charset
;
68 register struct re_guts
*g
;
71 my_regmatch_t pmatch
[];
77 register struct match
*m
= &mv
;
79 register const sopno gf
= g
->firststate
+1; /* +1 for OEND */
80 register const sopno gl
= g
->laststate
;
84 /* simplify the situation where possible */
85 if (g
->cflags
®_NOSUB
)
87 if (eflags
®_STARTEND
) {
88 start
= str
+ pmatch
[0].rm_so
;
89 stop
= str
+ pmatch
[0].rm_eo
;
92 stop
= start
+ strlen(start
);
97 /* prescreening; this does wonders for this rather slow code */
98 if (g
->must
!= NULL
) {
99 for (dp
= start
; dp
< stop
; dp
++)
100 if (*dp
== g
->must
[0] && stop
- dp
>= g
->mlen
&&
101 memcmp(dp
, g
->must
, (size_t)g
->mlen
) == 0)
103 if (dp
== stop
) /* we didn't find g->must */
107 /* match struct setup */
122 /* this loop does only one repetition except for backrefs */
124 endp
= fast(charset
, m
, start
, stop
, gf
, gl
);
125 if (endp
== NULL
) { /* a miss */
126 if (m
->pmatch
!= NULL
)
127 free((char *)m
->pmatch
);
128 if (m
->lastpos
!= NULL
)
129 free((char *)m
->lastpos
);
133 if (nmatch
== 0 && !g
->backrefs
)
134 break; /* no further info needed */
137 assert(m
->coldp
!= NULL
);
139 NOTE("finding start");
140 endp
= slow(charset
, m
, m
->coldp
, stop
, gf
, gl
);
143 assert(m
->coldp
< m
->endp
);
146 if (nmatch
== 1 && !g
->backrefs
)
147 break; /* no further info needed */
149 /* oh my, he wants the subexpressions... */
150 if (m
->pmatch
== NULL
)
151 m
->pmatch
= (my_regmatch_t
*)malloc((m
->g
->nsub
+ 1) *
152 sizeof(my_regmatch_t
));
153 if (m
->pmatch
== NULL
) {
154 if (m
->lastpos
!= NULL
)
155 free((char *)m
->lastpos
);
159 for (i
= 1; i
<= m
->g
->nsub
; i
++)
160 m
->pmatch
[i
].rm_so
= m
->pmatch
[i
].rm_eo
= -1;
161 if (!g
->backrefs
&& !(m
->eflags
®_BACKR
)) {
163 dp
= dissect(charset
, m
, m
->coldp
, endp
, gf
, gl
);
165 if (g
->nplus
> 0 && m
->lastpos
== NULL
)
166 m
->lastpos
= (char **)malloc((g
->nplus
+1) *
168 if (g
->nplus
> 0 && m
->lastpos
== NULL
) {
173 NOTE("backref dissect");
174 dp
= backref(charset
, m
, m
->coldp
, endp
, gf
, gl
, (sopno
)0);
179 /* uh-oh... we couldn't find a subexpression-level match */
180 assert(g
->backrefs
); /* must be back references doing it */
181 assert(g
->nplus
== 0 || m
->lastpos
!= NULL
);
183 if (dp
!= NULL
|| endp
<= m
->coldp
)
186 endp
= slow(charset
, m
, m
->coldp
, endp
-1, gf
, gl
);
189 /* try it on a shorter possibility */
191 for (i
= 1; i
<= m
->g
->nsub
; i
++) {
192 assert(m
->pmatch
[i
].rm_so
== -1);
193 assert(m
->pmatch
[i
].rm_eo
== -1);
196 NOTE("backoff dissect");
197 dp
= backref(charset
, m
, m
->coldp
, endp
, gf
, gl
, (sopno
)0);
199 assert(dp
== NULL
|| dp
== endp
);
200 if (dp
!= NULL
) /* found a shorter one */
203 /* despite initial appearances, there is no match here */
205 start
= m
->coldp
+ 1; /* recycle starting later */
206 assert(start
<= stop
);
209 /* fill in the details if requested */
211 pmatch
[0].rm_so
= m
->coldp
- m
->offp
;
212 pmatch
[0].rm_eo
= endp
- m
->offp
;
215 assert(m
->pmatch
!= NULL
);
216 for (i
= 1; i
< nmatch
; i
++)
218 pmatch
[i
] = m
->pmatch
[i
];
220 pmatch
[i
].rm_so
= -1;
221 pmatch
[i
].rm_eo
= -1;
225 if (m
->pmatch
!= NULL
)
226 free((char *)m
->pmatch
);
227 if (m
->lastpos
!= NULL
)
228 free((char *)m
->lastpos
);
234 - dissect - figure out what matched what, no back references
235 == static char *dissect(register struct match *m, char *start, \
236 == char *stop, sopno startst, sopno stopst);
238 static char * /* == stop (success) always */
239 dissect(charset
, m
, start
, stop
, startst
, stopst
)
240 CHARSET_INFO
*charset
;
241 register struct match
*m
;
248 register sopno ss
; /* start sop of current subRE */
249 register sopno es
; /* end sop of current subRE */
250 register char *sp
; /* start of string matched by it */
251 register char *stp
; /* string matched by it cannot pass here */
252 register char *rest
; /* start of rest of string */
253 register char *tail
; /* string unmatched by rest of RE */
254 register sopno ssub
; /* start sop of subsubRE */
255 register sopno esub
; /* end sop of subsubRE */
256 register char *ssp
; /* start of string matched by subsubRE */
257 register char *sep
; /* end of string matched by subsubRE */
258 register char *oldssp
; /* previous ssp */
260 AT("diss", start
, stop
, startst
, stopst
);
262 for (ss
= startst
; ss
< stopst
; ss
= es
) {
263 /* identify end of subRE */
265 switch (OP(m
->g
->strip
[es
])) {
268 es
+= OPND(m
->g
->strip
[es
]);
271 while (OP(m
->g
->strip
[es
]) != O_CH
)
272 es
+= OPND(m
->g
->strip
[es
]);
277 /* figure out what it matched */
278 switch (OP(m
->g
->strip
[ss
])) {
298 /* cases where length of match is hard to find */
302 /* how long could this one be? */
303 rest
= slow(charset
, m
, sp
, stp
, ss
, es
);
304 assert(rest
!= NULL
); /* it did match */
305 /* could the rest match the rest? */
306 tail
= slow(charset
, m
, rest
, stop
, es
, stopst
);
309 /* no -- try a shorter match for this one */
311 assert(stp
>= sp
); /* it did work */
315 /* did innards match? */
316 if (slow(charset
, m
, sp
, rest
, ssub
, esub
) != NULL
)
317 sp
= dissect(charset
, m
, sp
, rest
, ssub
, esub
);
324 /* how long could this one be? */
325 rest
= slow(charset
, m
, sp
, stp
, ss
, es
);
326 assert(rest
!= NULL
); /* it did match */
327 /* could the rest match the rest? */
328 tail
= slow(charset
, m
, rest
, stop
, es
, stopst
);
331 /* no -- try a shorter match for this one */
333 assert(stp
>= sp
); /* it did work */
339 for (;;) { /* find last match of innards */
340 sep
= slow(charset
, m
, ssp
, rest
, ssub
, esub
);
341 if (sep
== NULL
|| sep
== ssp
)
342 break; /* failed or matched null */
343 oldssp
= ssp
; /* on to next try */
347 /* last successful match */
351 assert(sep
== rest
); /* must exhaust substring */
352 assert(slow(charset
, m
, ssp
, sep
, ssub
, esub
) == rest
);
353 sp
= dissect(charset
, m
, ssp
, sep
, ssub
, esub
);
360 /* how long could this one be? */
361 rest
= slow(charset
, m
, sp
, stp
, ss
, es
);
362 assert(rest
!= NULL
); /* it did match */
363 /* could the rest match the rest? */
364 tail
= slow(charset
, m
, rest
, stop
, es
, stopst
);
367 /* no -- try a shorter match for this one */
369 assert(stp
>= sp
); /* it did work */
372 esub
= ss
+ OPND(m
->g
->strip
[ss
]) - 1;
373 assert(OP(m
->g
->strip
[esub
]) == OOR1
);
374 for (;;) { /* find first matching branch */
375 if (slow(charset
, m
, sp
, rest
, ssub
, esub
) == rest
)
376 break; /* it matched all of it */
377 /* that one missed, try next one */
378 assert(OP(m
->g
->strip
[esub
]) == OOR1
);
380 assert(OP(m
->g
->strip
[esub
]) == OOR2
);
382 esub
+= OPND(m
->g
->strip
[esub
]);
383 if (OP(m
->g
->strip
[esub
]) == OOR2
)
386 assert(OP(m
->g
->strip
[esub
]) == O_CH
);
388 sp
= dissect(charset
, m
, sp
, rest
, ssub
, esub
);
400 i
= OPND(m
->g
->strip
[ss
]);
401 assert(0 < i
&& i
<= m
->g
->nsub
);
402 m
->pmatch
[i
].rm_so
= sp
- m
->offp
;
405 i
= OPND(m
->g
->strip
[ss
]);
406 assert(0 < i
&& i
<= m
->g
->nsub
);
407 m
->pmatch
[i
].rm_eo
= sp
- m
->offp
;
420 - backref - figure out what matched what, figuring in back references
421 == static char *backref(register struct match *m, char *start, \
422 == char *stop, sopno startst, sopno stopst, sopno lev);
424 static char * /* == stop (success) or NULL (failure) */
425 backref(charset
,m
, start
, stop
, startst
, stopst
, lev
)
426 CHARSET_INFO
*charset
;
427 register struct match
*m
;
432 sopno lev
; /* PLUS nesting level */
435 register sopno ss
; /* start sop of current subRE */
436 register char *sp
; /* start of string matched by it */
437 register sopno ssub
; /* start sop of subsubRE */
438 register sopno esub
; /* end sop of subsubRE */
439 register char *ssp
; /* start of string matched by subsubRE */
444 register regoff_t offsave
;
447 AT("back", start
, stop
, startst
, stopst
);
450 /* get as far as we can with easy stuff */
452 for (ss
= startst
; !hard
&& ss
< stopst
; ss
++)
453 switch (OP(s
= m
->g
->strip
[ss
])) {
455 if (sp
== stop
|| *sp
++ != (char)OPND(s
))
464 cs
= &m
->g
->sets
[OPND(s
)];
465 if (sp
== stop
|| !CHIN(cs
, *sp
++))
469 if ( (sp
== m
->beginp
&& !(m
->eflags
®_NOTBOL
)) ||
470 (sp
< m
->endp
&& *(sp
-1) == '\n' &&
471 (m
->g
->cflags
®_NEWLINE
)) )
477 if ( (sp
== m
->endp
&& !(m
->eflags
®_NOTEOL
)) ||
478 (sp
< m
->endp
&& *sp
== '\n' &&
479 (m
->g
->cflags
®_NEWLINE
)) )
485 if (( (sp
== m
->beginp
&& !(m
->eflags
®_NOTBOL
)) ||
486 (sp
< m
->endp
&& *(sp
-1) == '\n' &&
487 (m
->g
->cflags
®_NEWLINE
)) ||
489 !ISWORD(charset
,*(sp
-1))) ) &&
490 (sp
< m
->endp
&& ISWORD(charset
,*sp
)) )
496 if (( (sp
== m
->endp
&& !(m
->eflags
®_NOTEOL
)) ||
497 (sp
< m
->endp
&& *sp
== '\n' &&
498 (m
->g
->cflags
®_NEWLINE
)) ||
499 (sp
< m
->endp
&& !ISWORD(charset
,*sp
)) ) &&
500 (sp
> m
->beginp
&& ISWORD(charset
,*(sp
-1))) )
507 case OOR1
: /* matches null but needs to skip */
511 assert(OP(s
) == OOR2
);
513 } while (OP(s
= m
->g
->strip
[ss
]) != O_CH
);
514 /* note that the ss++ gets us past the O_CH */
516 default: /* have to make a choice */
520 if (!hard
) { /* that was it! */
525 ss
--; /* adjust for the for's final increment */
528 AT("hard", sp
, stop
, ss
, stopst
);
531 case OBACK_
: /* the vilest depths */
533 assert(0 < i
&& i
<= m
->g
->nsub
);
534 if (m
->pmatch
[i
].rm_eo
== -1)
536 assert(m
->pmatch
[i
].rm_so
!= -1);
537 len
= m
->pmatch
[i
].rm_eo
- m
->pmatch
[i
].rm_so
;
538 assert((size_t) (stop
- m
->beginp
) >= len
);
540 return(NULL
); /* not enough left to match */
541 ssp
= m
->offp
+ m
->pmatch
[i
].rm_so
;
542 if (memcmp(sp
, ssp
, len
) != 0)
544 while (m
->g
->strip
[ss
] != SOP(O_BACK
, i
))
546 return(backref(charset
, m
, sp
+len
, stop
, ss
+1, stopst
, lev
));
548 case OQUEST_
: /* to null or not */
549 dp
= backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
);
551 return(dp
); /* not */
552 return(backref(charset
, m
, sp
, stop
, ss
+OPND(s
)+1, stopst
, lev
));
555 assert(m
->lastpos
!= NULL
);
556 assert(lev
+1 <= m
->g
->nplus
);
557 m
->lastpos
[lev
+1] = sp
;
558 return(backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
+1));
561 if (sp
== m
->lastpos
[lev
]) /* last pass matched null */
562 return(backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
-1));
563 /* try another pass */
564 m
->lastpos
[lev
] = sp
;
565 dp
= backref(charset
, m
, sp
, stop
, ss
-OPND(s
)+1, stopst
, lev
);
567 return(backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
-1));
571 case OCH_
: /* find the right one, if any */
573 esub
= ss
+ OPND(s
) - 1;
574 assert(OP(m
->g
->strip
[esub
]) == OOR1
);
575 for (;;) { /* find first matching branch */
576 dp
= backref(charset
, m
, sp
, stop
, ssub
, esub
, lev
);
579 /* that one missed, try next one */
580 if (OP(m
->g
->strip
[esub
]) == O_CH
)
581 return(NULL
); /* there is none */
583 assert(OP(m
->g
->strip
[esub
]) == OOR2
);
585 esub
+= OPND(m
->g
->strip
[esub
]);
586 if (OP(m
->g
->strip
[esub
]) == OOR2
)
589 assert(OP(m
->g
->strip
[esub
]) == O_CH
);
592 case OLPAREN
: /* must undo assignment if rest fails */
594 assert(0 < i
&& i
<= m
->g
->nsub
);
595 offsave
= m
->pmatch
[i
].rm_so
;
596 m
->pmatch
[i
].rm_so
= sp
- m
->offp
;
597 dp
= backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
);
600 m
->pmatch
[i
].rm_so
= offsave
;
603 case ORPAREN
: /* must undo assignment if rest fails */
605 assert(0 < i
&& i
<= m
->g
->nsub
);
606 offsave
= m
->pmatch
[i
].rm_eo
;
607 m
->pmatch
[i
].rm_eo
= sp
- m
->offp
;
608 dp
= backref(charset
, m
, sp
, stop
, ss
+1, stopst
, lev
);
611 m
->pmatch
[i
].rm_eo
= offsave
;
622 return 0; /* Keep gcc happy */
626 - fast - step through the string at top speed
627 == static char *fast(register struct match *m, char *start, \
628 == char *stop, sopno startst, sopno stopst);
630 static char * /* where tentative match ended, or NULL */
631 fast(charset
, m
, start
, stop
, startst
, stopst
)
632 CHARSET_INFO
*charset
;
633 register struct match
*m
;
639 register states st
= m
->st
;
640 register states fresh
= m
->fresh
;
641 register states tmp
= m
->tmp
;
642 register char *p
= start
;
643 register int c
= (start
== m
->beginp
) ? OUT
: *(start
-1);
644 register int lastc
; /* previous c */
647 register char *coldp
; /* last p after which no match was underway */
651 st
= step(m
->g
, startst
, stopst
, st
, NOTHING
, st
);
658 c
= (p
== m
->endp
) ? OUT
: *p
;
662 /* is there an EOL and/or BOL between lastc and c? */
665 if ( (lastc
== '\n' && m
->g
->cflags
®_NEWLINE
) ||
666 (lastc
== OUT
&& !(m
->eflags
®_NOTBOL
)) ) {
670 if ( (c
== '\n' && m
->g
->cflags
®_NEWLINE
) ||
671 (c
== OUT
&& !(m
->eflags
®_NOTEOL
)) ) {
672 flagch
= (flagch
== BOL
) ? BOLEOL
: EOL
;
677 st
= step(m
->g
, startst
, stopst
, st
, flagch
, st
);
681 /* how about a word boundary? */
682 if ( (flagch
== BOL
|| (lastc
!= OUT
&& !ISWORD(charset
,lastc
))) &&
683 (c
!= OUT
&& ISWORD(charset
,c
)) ) {
686 if ( (lastc
!= OUT
&& ISWORD(charset
,lastc
)) &&
687 (flagch
== EOL
|| (c
!= OUT
&& !ISWORD(charset
,c
))) ) {
690 if (flagch
== BOW
|| flagch
== EOW
) {
691 st
= step(m
->g
, startst
, stopst
, st
, flagch
, st
);
696 if (ISSET(st
, stopst
) || p
== stop
)
697 break; /* NOTE BREAK OUT */
699 /* no, we must deal with this character */
703 st
= step(m
->g
, startst
, stopst
, tmp
, c
, st
);
705 assert(EQ(step(m
->g
, startst
, stopst
, st
, NOTHING
, st
), st
));
709 assert(coldp
!= NULL
);
711 if (ISSET(st
, stopst
))
718 - slow - step through the string more deliberately
719 == static char *slow(register struct match *m, char *start, \
720 == char *stop, sopno startst, sopno stopst);
722 static char * /* where it ended */
723 slow(charset
, m
, start
, stop
, startst
, stopst
)
724 CHARSET_INFO
*charset
;
725 register struct match
*m
;
731 register states st
= m
->st
;
732 register states empty
= m
->empty
;
733 register states tmp
= m
->tmp
;
734 register char *p
= start
;
735 register int c
= (start
== m
->beginp
) ? OUT
: *(start
-1);
736 register int lastc
; /* previous c */
739 register char *matchp
; /* last p at which a match ended */
741 AT("slow", start
, stop
, startst
, stopst
);
744 SP("sstart", st
, *p
);
745 st
= step(m
->g
, startst
, stopst
, st
, NOTHING
, st
);
750 c
= (p
== m
->endp
) ? OUT
: *p
;
752 /* is there an EOL and/or BOL between lastc and c? */
755 if ( (lastc
== '\n' && m
->g
->cflags
®_NEWLINE
) ||
756 (lastc
== OUT
&& !(m
->eflags
®_NOTBOL
)) ) {
760 if ( (c
== '\n' && m
->g
->cflags
®_NEWLINE
) ||
761 (c
== OUT
&& !(m
->eflags
®_NOTEOL
)) ) {
762 flagch
= (flagch
== BOL
) ? BOLEOL
: EOL
;
767 st
= step(m
->g
, startst
, stopst
, st
, flagch
, st
);
768 SP("sboleol", st
, c
);
771 /* how about a word boundary? */
772 if ( (flagch
== BOL
|| (lastc
!= OUT
&& !ISWORD(charset
,lastc
))) &&
773 (c
!= OUT
&& ISWORD(charset
,c
)) ) {
776 if ( (lastc
!= OUT
&& ISWORD(charset
,lastc
)) &&
777 (flagch
== EOL
|| (c
!= OUT
&& !ISWORD(charset
,c
))) ) {
780 if (flagch
== BOW
|| flagch
== EOW
) {
781 st
= step(m
->g
, startst
, stopst
, st
, flagch
, st
);
782 SP("sboweow", st
, c
);
786 if (ISSET(st
, stopst
))
788 if (EQ(st
, empty
) || p
== stop
)
789 break; /* NOTE BREAK OUT */
791 /* no, we must deal with this character */
795 st
= step(m
->g
, startst
, stopst
, tmp
, c
, st
);
797 assert(EQ(step(m
->g
, startst
, stopst
, st
, NOTHING
, st
), st
));
806 - step - map set of states reachable before char to set reachable after
807 == static states step(register struct re_guts *g, sopno start, sopno stop, \
808 == register states bef, int ch, register states aft);
809 == #define BOL (OUT+1)
810 == #define EOL (BOL+1)
811 == #define BOLEOL (BOL+2)
812 == #define NOTHING (BOL+3)
813 == #define BOW (BOL+4)
814 == #define EOW (BOL+5)
815 == #define CODEMAX (BOL+5) // highest code used
816 == #define NONCHAR(c) ((c) > CHAR_MAX)
817 == #define NNONCHAR (CODEMAX-CHAR_MAX)
820 step(g
, start
, stop
, bef
, ch
, aft
)
821 register struct re_guts
*g
;
822 sopno start
; /* start state within strip */
823 sopno stop
; /* state after stop state within strip */
824 register states bef
; /* states reachable before */
825 int ch
; /* character or NONCHAR code */
826 register states aft
; /* states already known reachable after */
831 register onestate here
; /* note, macros know this name */
833 register onestate i
; /* Changed from int by Monty */
835 for (pc
= start
, INIT(here
, pc
); pc
!= stop
; pc
++, INC(here
)) {
839 assert(pc
== stop
-1);
842 /* only characters can match */
843 assert(!NONCHAR(ch
) || ch
!= (char)OPND(s
));
844 if (ch
== (char)OPND(s
))
848 if (ch
== BOL
|| ch
== BOLEOL
)
852 if (ch
== EOL
|| ch
== BOLEOL
)
868 cs
= &g
->sets
[OPND(s
)];
869 if (!NONCHAR(ch
) && CHIN(cs
, ch
))
872 case OBACK_
: /* ignored here */
876 case OPLUS_
: /* forward, this is just an empty */
879 case O_PLUS
: /* both forward and back */
881 i
= ISSETBACK(aft
, OPND(s
));
882 BACK(aft
, aft
, OPND(s
));
883 if (!i
&& ISSETBACK(aft
, OPND(s
))) {
884 /* oho, must reconsider loop body */
889 case OQUEST_
: /* two branches, both forward */
891 FWD(aft
, aft
, OPND(s
));
893 case O_QUEST
: /* just an empty */
896 case OLPAREN
: /* not significant here */
900 case OCH_
: /* mark the first two branches */
902 assert(OP(g
->strip
[pc
+OPND(s
)]) == OOR2
);
903 FWD(aft
, aft
, OPND(s
));
905 case OOR1
: /* done a branch, find the O_CH */
906 if (ISSTATEIN(aft
, here
)) {
908 OP(s
= g
->strip
[pc
+look
]) != O_CH
;
910 assert(OP(s
) == OOR2
);
914 case OOR2
: /* propagate OCH_'s marking */
916 if (OP(g
->strip
[pc
+OPND(s
)]) != O_CH
) {
917 assert(OP(g
->strip
[pc
+OPND(s
)]) == OOR2
);
918 FWD(aft
, aft
, OPND(s
));
921 case O_CH
: /* just empty */
924 default: /* ooooops... */
935 - print - print a set of states
937 == static void print(struct match *m, char *caption, states st, \
942 print(m
, caption
, st
, ch
, d
)
949 register struct re_guts
*g
= m
->g
;
951 register int first
= 1;
954 if (!(m
->eflags
®_TRACE
))
957 fprintf(d
, "%s", caption
);
959 fprintf(d
, " %s", printchar(ch
,buf
));
960 for (i
= 0; i
< g
->nstates
; i
++)
962 fprintf(d
, "%s%d", (first
) ? "\t" : ", ", i
);
969 - at - print current situation
971 == static void at(struct match *m, char *title, char *start, char *stop, \
972 == sopno startst, sopno stopst);
976 at(m
, title
, start
, stop
, startst
, stopst
)
985 if (!(m
->eflags
®_TRACE
))
988 printf("%s %s-", title
, printchar(*start
,buf
));
989 printf("%s ", printchar(*stop
,buf
));
990 printf("%ld-%ld\n", (long)startst
, (long)stopst
,buf
);
994 #define PCHARDONE /* never again */
996 - printchar - make a character printable
998 == static char *printchar(int ch);
1001 * Is this identical to regchar() over in debug.c? Well, yes. But a
1002 * duplicate here avoids having a debugging-capable regexec.o tied to
1003 * a matching debug.o, and this is convenient. It all disappears in
1004 * the non-debug compilation anyway, so it doesn't matter much.
1006 static char * /* -> representation */
1011 if (isprint(ch
) || ch
== ' ')
1012 sprintf(pbuf
, "%c", ch
);
1014 sprintf(pbuf
, "\\%o", ch
);