1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin 
24da2e3ebdSchin /*
25da2e3ebdSchin  * posix regex executor
26da2e3ebdSchin  * single sized-record interface
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include "reglib.h"
30da2e3ebdSchin 
31da2e3ebdSchin #if _AST_REGEX_DEBUG
32da2e3ebdSchin 
33da2e3ebdSchin #define DEBUG_TEST(f,y,n)	((debug&(debug_flag=f))?(y):(n))
34da2e3ebdSchin #define DEBUG_CODE(f,y,n)	do if(debug&(f)){y}else{n} while(0)
35da2e3ebdSchin #define DEBUG_INIT()		do { char* t; if (!debug) { debug = 0x80000000; if (t = getenv("_AST_regex_exec_debug")) debug |= strtoul(t, NiL, 0); } } while (0)
36da2e3ebdSchin 
37da2e3ebdSchin static unsigned long	debug;
38da2e3ebdSchin static unsigned long	debug_flag;
39da2e3ebdSchin 
40da2e3ebdSchin static const char*	rexnames[] =
41da2e3ebdSchin {
42da2e3ebdSchin 	"REX_NULL",
43da2e3ebdSchin 	"REX_ALT",
44da2e3ebdSchin 	"REX_ALT_CATCH",
45da2e3ebdSchin 	"REX_BACK",
46da2e3ebdSchin 	"REX_BEG",
47da2e3ebdSchin 	"REX_BEG_STR",
48da2e3ebdSchin 	"REX_BM",
49da2e3ebdSchin 	"REX_CAT",
50da2e3ebdSchin 	"REX_CLASS",
51da2e3ebdSchin 	"REX_COLL_CLASS",
52da2e3ebdSchin 	"REX_CONJ",
53da2e3ebdSchin 	"REX_CONJ_LEFT",
54da2e3ebdSchin 	"REX_CONJ_RIGHT",
55da2e3ebdSchin 	"REX_DONE",
56da2e3ebdSchin 	"REX_DOT",
57da2e3ebdSchin 	"REX_END",
58da2e3ebdSchin 	"REX_END_STR",
59da2e3ebdSchin 	"REX_EXEC",
60da2e3ebdSchin 	"REX_FIN_STR",
61da2e3ebdSchin 	"REX_GROUP",
62da2e3ebdSchin 	"REX_GROUP_CATCH",
63da2e3ebdSchin 	"REX_GROUP_AHEAD",
64da2e3ebdSchin 	"REX_GROUP_AHEAD_CATCH",
65da2e3ebdSchin 	"REX_GROUP_AHEAD_NOT",
66da2e3ebdSchin 	"REX_GROUP_BEHIND",
67da2e3ebdSchin 	"REX_GROUP_BEHIND_CATCH",
68da2e3ebdSchin 	"REX_GROUP_BEHIND_NOT",
69da2e3ebdSchin 	"REX_GROUP_BEHIND_NOT_CATCH",
70da2e3ebdSchin 	"REX_GROUP_COND",
71da2e3ebdSchin 	"REX_GROUP_COND_CATCH",
72da2e3ebdSchin 	"REX_GROUP_CUT",
73da2e3ebdSchin 	"REX_GROUP_CUT_CATCH",
74da2e3ebdSchin 	"REX_KMP",
75da2e3ebdSchin 	"REX_NEG",
76da2e3ebdSchin 	"REX_NEG_CATCH",
77da2e3ebdSchin 	"REX_NEST",
78da2e3ebdSchin 	"REX_ONECHAR",
79da2e3ebdSchin 	"REX_REP",
80da2e3ebdSchin 	"REX_REP_CATCH",
81da2e3ebdSchin 	"REX_STRING",
82da2e3ebdSchin 	"REX_TRIE",
83da2e3ebdSchin 	"REX_WBEG",
84da2e3ebdSchin 	"REX_WEND",
85da2e3ebdSchin 	"REX_WORD",
86da2e3ebdSchin 	"REX_WORD_NOT"
87da2e3ebdSchin };
88da2e3ebdSchin 
rexname(Rex_t * rex)89da2e3ebdSchin static const char* rexname(Rex_t* rex)
90da2e3ebdSchin {
91da2e3ebdSchin 	if (!rex)
92da2e3ebdSchin 		return "NIL";
93da2e3ebdSchin 	if (rex->type >= elementsof(rexnames))
94da2e3ebdSchin 		return "ERROR";
95da2e3ebdSchin 	return rexnames[rex->type];
96da2e3ebdSchin }
97da2e3ebdSchin 
98da2e3ebdSchin #else
99da2e3ebdSchin 
100da2e3ebdSchin #define DEBUG_INIT()
101da2e3ebdSchin #define DEBUG_TEST(f,y,n)	(n)
102da2e3ebdSchin #define DEBUG_CODE(f,y,n)	do {n} while(0)
103da2e3ebdSchin 
104da2e3ebdSchin #endif
105da2e3ebdSchin 
106da2e3ebdSchin #define BEG_ALT		1	/* beginning of an alt			*/
107da2e3ebdSchin #define BEG_ONE		2	/* beginning of one iteration of a rep	*/
108da2e3ebdSchin #define BEG_REP		3	/* beginning of a repetition		*/
109da2e3ebdSchin #define BEG_SUB		4	/* beginning of a subexpression		*/
110da2e3ebdSchin #define END_ANY		5	/* end of any of above			*/
111da2e3ebdSchin 
112da2e3ebdSchin /*
113da2e3ebdSchin  * returns from parse()
114da2e3ebdSchin  */
115da2e3ebdSchin 
116da2e3ebdSchin #define NONE		0	/* no parse found			*/
117da2e3ebdSchin #define GOOD		1	/* some parse was found			*/
118da2e3ebdSchin #define CUT		2	/* no match and no backtrack		*/
119da2e3ebdSchin #define BEST		3	/* an unbeatable parse was found	*/
120da2e3ebdSchin #define BAD		4	/* error ocurred			*/
121da2e3ebdSchin 
122da2e3ebdSchin /*
123da2e3ebdSchin  * REG_SHELL_DOT test
124da2e3ebdSchin  */
125da2e3ebdSchin 
126da2e3ebdSchin #define LEADING(e,r,s)	(*(s)==(e)->leading&&((s)==(e)->beg||*((s)-1)==(r)->explicit))
127da2e3ebdSchin 
128da2e3ebdSchin /*
129da2e3ebdSchin  * Pos_t is for comparing parses. An entry is made in the
130da2e3ebdSchin  * array at the beginning and at the end of each Group_t,
131da2e3ebdSchin  * each iteration in a Group_t, and each Binary_t.
132da2e3ebdSchin  */
133da2e3ebdSchin 
134da2e3ebdSchin typedef struct
135da2e3ebdSchin {
136da2e3ebdSchin 	unsigned char*	p;		/* where in string		*/
137da2e3ebdSchin 	size_t		length;		/* length in string		*/
138da2e3ebdSchin 	short		serial;		/* preorder subpattern number	*/
139da2e3ebdSchin 	short		be;		/* which end of pair		*/
140da2e3ebdSchin } Pos_t;
141da2e3ebdSchin 
142da2e3ebdSchin /* ===== begin library support ===== */
143da2e3ebdSchin 
144da2e3ebdSchin #define vector(t,v,i)	(((i)<(v)->max)?(t*)((v)->vec+(i)*(v)->siz):(t*)vecseek(&(v),i))
145da2e3ebdSchin 
146da2e3ebdSchin static Vector_t*
vecopen(int inc,int siz)147da2e3ebdSchin vecopen(int inc, int siz)
148da2e3ebdSchin {
149da2e3ebdSchin 	Vector_t*	v;
150da2e3ebdSchin 	Stk_t*		sp;
151da2e3ebdSchin 
152da2e3ebdSchin 	if (inc <= 0)
153da2e3ebdSchin 		inc = 16;
154da2e3ebdSchin 	if (!(sp = stkopen(STK_SMALL|STK_NULL)))
155da2e3ebdSchin 		return 0;
156da2e3ebdSchin 	if (!(v = (Vector_t*)stkseek(sp, sizeof(Vector_t) + inc * siz)))
157da2e3ebdSchin 	{
158da2e3ebdSchin 		stkclose(sp);
159da2e3ebdSchin 		return 0;
160da2e3ebdSchin 	}
161da2e3ebdSchin 	v->stk = sp;
162da2e3ebdSchin 	v->vec = (char*)v + sizeof(Vector_t);
163da2e3ebdSchin 	v->max = v->inc = inc;
164da2e3ebdSchin 	v->siz = siz;
165da2e3ebdSchin 	v->cur = 0;
166da2e3ebdSchin 	return v;
167da2e3ebdSchin }
168da2e3ebdSchin 
169da2e3ebdSchin static void*
vecseek(Vector_t ** p,int index)170da2e3ebdSchin vecseek(Vector_t** p, int index)
171da2e3ebdSchin {
172da2e3ebdSchin 	Vector_t*	v = *p;
173da2e3ebdSchin 
174da2e3ebdSchin 	if (index >= v->max)
175da2e3ebdSchin 	{
176da2e3ebdSchin 		while ((v->max += v->inc) <= index);
177da2e3ebdSchin 		if (!(v = (Vector_t*)stkseek(v->stk, sizeof(Vector_t) + v->max * v->siz)))
178da2e3ebdSchin 			return 0;
179da2e3ebdSchin 		*p = v;
180da2e3ebdSchin 		v->vec = (char*)v + sizeof(Vector_t);
181da2e3ebdSchin 	}
182da2e3ebdSchin 	return v->vec + index * v->siz;
183da2e3ebdSchin }
184da2e3ebdSchin 
185da2e3ebdSchin static void
vecclose(Vector_t * v)186da2e3ebdSchin vecclose(Vector_t* v)
187da2e3ebdSchin {
188da2e3ebdSchin 	if (v)
189da2e3ebdSchin 		stkclose(v->stk);
190da2e3ebdSchin }
191da2e3ebdSchin 
192da2e3ebdSchin typedef struct
193da2e3ebdSchin {
194da2e3ebdSchin 	Stk_pos_t	pos;
195da2e3ebdSchin 	char		data[1];
196da2e3ebdSchin } Stk_frame_t;
197da2e3ebdSchin 
198da2e3ebdSchin #define stknew(s,p)	((p)->offset=stktell(s),(p)->base=stkfreeze(s,0))
199da2e3ebdSchin #define stkold(s,p)	stkset(s,(p)->base,(p)->offset)
200da2e3ebdSchin 
201da2e3ebdSchin #define stkframe(s)	(*((Stk_frame_t**)stktop(s)-1))
202da2e3ebdSchin #define stkdata(s,t)	((t*)stkframe(s)->data)
203da2e3ebdSchin #define stkpop(s)	stkold(s,&(stkframe(s)->pos))
204da2e3ebdSchin 
205da2e3ebdSchin static void*
stkpush(Stk_t * sp,size_t size)206da2e3ebdSchin stkpush(Stk_t* sp, size_t size)
207da2e3ebdSchin {
208da2e3ebdSchin 	Stk_frame_t*	f;
209da2e3ebdSchin 	Stk_pos_t	p;
210da2e3ebdSchin 
211da2e3ebdSchin 	stknew(sp, &p);
212da2e3ebdSchin 	size = sizeof(Stk_frame_t) + sizeof(size_t) + size - 1;
213da2e3ebdSchin 	if (!(f = (Stk_frame_t*)stkalloc(sp, sizeof(Stk_frame_t) + sizeof(Stk_frame_t*) + size - 1)))
214da2e3ebdSchin 		return 0;
215da2e3ebdSchin 	f->pos = p;
216da2e3ebdSchin 	stkframe(sp) = f;
217da2e3ebdSchin 	return f->data;
218da2e3ebdSchin }
219da2e3ebdSchin 
220da2e3ebdSchin /* ===== end library support ===== */
221da2e3ebdSchin 
222da2e3ebdSchin /*
223da2e3ebdSchin  * Match_frame_t is for saving and restoring match records
224da2e3ebdSchin  * around alternate attempts, so that fossils will not be
225da2e3ebdSchin  * left in the match array.  These are the only entries in
226da2e3ebdSchin  * the match array that are not otherwise guaranteed to
227da2e3ebdSchin  * have current data in them when they get used.
228da2e3ebdSchin  */
229da2e3ebdSchin 
230da2e3ebdSchin typedef struct
231da2e3ebdSchin {
232da2e3ebdSchin 	size_t			size;
233da2e3ebdSchin 	regmatch_t*		match;
234da2e3ebdSchin 	regmatch_t		save[1];
235da2e3ebdSchin } Match_frame_t;
236da2e3ebdSchin 
237da2e3ebdSchin #define matchpush(e,x)	((x)->re.group.number?_matchpush(e,x):0)
238*b30d1939SAndy Fiddaman #define matchcopy(e,x)	do if ((x)->re.group.number) { Match_frame_t* fp = (void*)stkframe(stkstd)->data; memcpy(fp->match, fp->save, fp->size); } while (0)
239*b30d1939SAndy Fiddaman #define matchpop(e,x)	do if ((x)->re.group.number) { Match_frame_t* fp = (void*)stkframe(stkstd)->data; memcpy(fp->match, fp->save, fp->size); stkpop(stkstd); } while (0)
240da2e3ebdSchin 
241da2e3ebdSchin #define pospop(e)	(--(e)->pos->cur)
242da2e3ebdSchin 
243da2e3ebdSchin /*
244da2e3ebdSchin  * allocate a frame and push a match onto the stack
245da2e3ebdSchin  */
246da2e3ebdSchin 
247da2e3ebdSchin static int
_matchpush(Env_t * env,Rex_t * rex)248da2e3ebdSchin _matchpush(Env_t* env, Rex_t* rex)
249da2e3ebdSchin {
250da2e3ebdSchin 	Match_frame_t*	f;
251da2e3ebdSchin 	regmatch_t*	m;
252da2e3ebdSchin 	regmatch_t*	e;
253da2e3ebdSchin 	regmatch_t*	s;
254da2e3ebdSchin 	int		num;
255da2e3ebdSchin 
256da2e3ebdSchin 	if (rex->re.group.number <= 0 || (num = rex->re.group.last - rex->re.group.number + 1) <= 0)
257da2e3ebdSchin 		num = 0;
258da2e3ebdSchin 	if (!(f = (Match_frame_t*)stkpush(stkstd, sizeof(Match_frame_t) + (num - 1) * sizeof(regmatch_t))))
259da2e3ebdSchin 	{
260da2e3ebdSchin 		env->error = REG_ESPACE;
261da2e3ebdSchin 		return 1;
262da2e3ebdSchin 	}
263da2e3ebdSchin 	f->size = num * sizeof(regmatch_t);
264da2e3ebdSchin 	f->match = m = env->match + rex->re.group.number;
265da2e3ebdSchin 	e = m + num;
266da2e3ebdSchin 	s = f->save;
267da2e3ebdSchin 	while (m < e)
268da2e3ebdSchin 	{
269da2e3ebdSchin 		*s++ = *m;
270da2e3ebdSchin 		*m++ = state.nomatch;
271da2e3ebdSchin 	}
272da2e3ebdSchin 	return 0;
273da2e3ebdSchin }
274da2e3ebdSchin 
275da2e3ebdSchin /*
276da2e3ebdSchin  * allocate a frame and push a pos onto the stack
277da2e3ebdSchin  */
278da2e3ebdSchin 
279da2e3ebdSchin static int
pospush(Env_t * env,Rex_t * rex,unsigned char * p,int be)280da2e3ebdSchin pospush(Env_t* env, Rex_t* rex, unsigned char* p, int be)
281da2e3ebdSchin {
282da2e3ebdSchin 	Pos_t*	pos;
283da2e3ebdSchin 
284da2e3ebdSchin 	if (!(pos = vector(Pos_t, env->pos, env->pos->cur)))
285da2e3ebdSchin 	{
286da2e3ebdSchin 		env->error = REG_ESPACE;
287da2e3ebdSchin 		return 1;
288da2e3ebdSchin 	}
289da2e3ebdSchin 	pos->serial = rex->serial;
290da2e3ebdSchin 	pos->p = p;
291da2e3ebdSchin 	pos->be = be;
292da2e3ebdSchin 	env->pos->cur++;
293da2e3ebdSchin 	return 0;
294da2e3ebdSchin }
295da2e3ebdSchin 
296da2e3ebdSchin /*
297da2e3ebdSchin  * two matches are known to have the same length
298da2e3ebdSchin  * os is start of old pos array, ns is start of new,
299da2e3ebdSchin  * oend and nend are end+1 pointers to ends of arrays.
300da2e3ebdSchin  * oe and ne are ends (not end+1) of subarrays.
301da2e3ebdSchin  * returns 1 if new is better, -1 if old, else 0.
302da2e3ebdSchin  */
303da2e3ebdSchin 
304da2e3ebdSchin static int
better(Env_t * env,Pos_t * os,Pos_t * ns,Pos_t * oend,Pos_t * nend,int level)305da2e3ebdSchin better(Env_t* env, Pos_t* os, Pos_t* ns, Pos_t* oend, Pos_t* nend, int level)
306da2e3ebdSchin {
307da2e3ebdSchin 	Pos_t*	oe;
308da2e3ebdSchin 	Pos_t*	ne;
309da2e3ebdSchin 	int	k;
310da2e3ebdSchin 	int	n;
311da2e3ebdSchin 
312da2e3ebdSchin 	if (env->error)
313da2e3ebdSchin 		return -1;
314da2e3ebdSchin 	for (;;)
315da2e3ebdSchin 	{
316da2e3ebdSchin 		DEBUG_CODE(0x0080,{sfprintf(sfstdout, "   %-*.*sold ", (level + 3) * 4, (level + 3) * 4, "");for (oe = os; oe < oend; oe++)sfprintf(sfstdout, "<%d,%d,%d>", oe->p - env->beg, oe->serial, oe->be);sfprintf(sfstdout, "\n   %-*.*snew ", (level + 3) * 4, (level + 3) * 4, "");for (oe = ns; oe < nend; oe++)sfprintf(sfstdout, "<%d,%d,%d>", oe->p - env->beg, oe->serial, oe->be);sfprintf(sfstdout, "\n");},{0;});
317da2e3ebdSchin 		if (ns >= nend)
318da2e3ebdSchin 			return DEBUG_TEST(0x8000,(os < oend),(0));
319da2e3ebdSchin 		if (os >= oend)
320da2e3ebdSchin 			return DEBUG_TEST(0x8000,(-1),(1));
321da2e3ebdSchin 		n = os->serial;
322da2e3ebdSchin 		if (ns->serial > n)
323da2e3ebdSchin 			return -1;
324da2e3ebdSchin 		if (n > ns->serial)
325da2e3ebdSchin 		{
326da2e3ebdSchin 			env->error = REG_PANIC;
327da2e3ebdSchin 			return -1;
328da2e3ebdSchin 		}
329da2e3ebdSchin 		if (ns->p > os->p)
330da2e3ebdSchin 			return 1;
331da2e3ebdSchin 		if (os->p > ns->p)
332da2e3ebdSchin 			return -1;
333da2e3ebdSchin 		oe = os;
334da2e3ebdSchin 		k = 0;
335da2e3ebdSchin 		for (;;)
336da2e3ebdSchin 			if ((++oe)->serial == n)
337da2e3ebdSchin 			{
338da2e3ebdSchin 				if (oe->be != END_ANY)
339da2e3ebdSchin 					k++;
340da2e3ebdSchin 				else if (k-- <= 0)
341da2e3ebdSchin 					break;
342da2e3ebdSchin 			}
343da2e3ebdSchin 		ne = ns;
344da2e3ebdSchin 		k = 0;
345da2e3ebdSchin 		for (;;)
346da2e3ebdSchin 			if ((++ne)->serial == n)
347da2e3ebdSchin 			{
348da2e3ebdSchin 				if (ne->be != END_ANY)
349da2e3ebdSchin 					k++;
350da2e3ebdSchin 				else if (k-- <= 0)
351da2e3ebdSchin 					break;
352da2e3ebdSchin 			}
353da2e3ebdSchin 		if (ne->p > oe->p)
354da2e3ebdSchin 			return 1;
355da2e3ebdSchin 		if (oe->p > ne->p)
356da2e3ebdSchin 			return -1;
357da2e3ebdSchin 		if (k = better(env, os + 1, ns + 1, oe, ne, level + 1))
358da2e3ebdSchin 			return k;
359da2e3ebdSchin 		os = oe + 1;
360da2e3ebdSchin 		ns = ne + 1;
361da2e3ebdSchin 	}
362da2e3ebdSchin }
363da2e3ebdSchin 
3647c2fbfb3SApril Chin #if _AST_REGEX_DEBUG
3657c2fbfb3SApril Chin 
3667c2fbfb3SApril Chin static void
showmatch(regmatch_t * p)3677c2fbfb3SApril Chin showmatch(regmatch_t* p)
3687c2fbfb3SApril Chin {
3697c2fbfb3SApril Chin 	sfputc(sfstdout, '(');
3707c2fbfb3SApril Chin 	if (p->rm_so < 0)
3717c2fbfb3SApril Chin 		sfputc(sfstdout, '?');
3727c2fbfb3SApril Chin 	else
373*b30d1939SAndy Fiddaman 		sfprintf(sfstdout, "%z", p->rm_so);
3747c2fbfb3SApril Chin 	sfputc(sfstdout, ',');
3757c2fbfb3SApril Chin 	if (p->rm_eo < 0)
3767c2fbfb3SApril Chin 		sfputc(sfstdout, '?');
3777c2fbfb3SApril Chin 	else
378*b30d1939SAndy Fiddaman 		sfprintf(sfstdout, "%z", p->rm_eo);
3797c2fbfb3SApril Chin 	sfputc(sfstdout, ')');
3807c2fbfb3SApril Chin }
3817c2fbfb3SApril Chin 
3827c2fbfb3SApril Chin static int
_better(Env_t * env,Pos_t * os,Pos_t * ns,Pos_t * oend,Pos_t * nend,int level)3837c2fbfb3SApril Chin _better(Env_t* env, Pos_t* os, Pos_t* ns, Pos_t* oend, Pos_t* nend, int level)
3847c2fbfb3SApril Chin {
3857c2fbfb3SApril Chin 	int	i;
3867c2fbfb3SApril Chin 
3877c2fbfb3SApril Chin 	DEBUG_CODE(0x0040,{sfprintf(sfstdout, "AHA better old ");for (i = 0; i <= env->nsub; i++)showmatch(&env->best[i]);sfprintf(sfstdout, "\n           new ");for (i = 0; i <= env->nsub; i++)showmatch(&env->match[i]);sfprintf(sfstdout, "\n");},{0;});
3887c2fbfb3SApril Chin 	i = better(env, os, ns, oend, nend, 0);
3897c2fbfb3SApril Chin 	DEBUG_TEST(0x0040,(sfprintf(sfstdout, "           %s\n", i <= 0 ? "OLD" : "NEW")),(0));
3907c2fbfb3SApril Chin 	return i;
3917c2fbfb3SApril Chin }
3927c2fbfb3SApril Chin 
3937c2fbfb3SApril Chin #define better	_better
3947c2fbfb3SApril Chin 
3957c2fbfb3SApril Chin #endif
396da2e3ebdSchin 
397da2e3ebdSchin #define follow(e,r,c,s)	((r)->next?parse(e,(r)->next,c,s):(c)?parse(e,c,0,s):BEST)
398da2e3ebdSchin 
399da2e3ebdSchin static int		parse(Env_t*, Rex_t*, Rex_t*, unsigned char*);
400da2e3ebdSchin 
401da2e3ebdSchin static int
parserep(Env_t * env,Rex_t * rex,Rex_t * cont,unsigned char * s,int n)402da2e3ebdSchin parserep(Env_t* env, Rex_t* rex, Rex_t* cont, unsigned char* s, int n)
403da2e3ebdSchin {
404da2e3ebdSchin 	int	i;
405da2e3ebdSchin 	int	r = NONE;
406da2e3ebdSchin 	Rex_t	catcher;
407da2e3ebdSchin 
40834f9b3eeSRoland Mainz 	DEBUG_TEST(0x0010,(sfprintf(sfstdout, "AHA#%04d 0x%04x parserep %s %d %d %d %d `%-.*s'\n", __LINE__, debug_flag, rexname(rex->re.group.expr.rex), rex->re.group.number, rex->lo, n, rex->hi, env->end - s, s)),(0));
409da2e3ebdSchin 	if ((rex->flags & REG_MINIMAL) && n >= rex->lo && n < rex->hi)
410da2e3ebdSchin 	{
411da2e3ebdSchin 		if (env->stack && pospush(env, rex, s, END_ANY))
412da2e3ebdSchin 			return BAD;
413da2e3ebdSchin 		i = follow(env, rex, cont, s);
414da2e3ebdSchin 		if (env->stack)
415da2e3ebdSchin 			pospop(env);
416da2e3ebdSchin 		switch (i)
417da2e3ebdSchin 		{
418da2e3ebdSchin 		case BAD:
419da2e3ebdSchin 			return BAD;
420da2e3ebdSchin 		case CUT:
421da2e3ebdSchin 			return CUT;
422da2e3ebdSchin 		case BEST:
423da2e3ebdSchin 		case GOOD:
424da2e3ebdSchin 			return BEST;
425da2e3ebdSchin 		}
426da2e3ebdSchin 	}
427da2e3ebdSchin 	if (n < rex->hi)
428da2e3ebdSchin 	{
429da2e3ebdSchin 		catcher.type = REX_REP_CATCH;
430da2e3ebdSchin 		catcher.serial = rex->serial;
431da2e3ebdSchin 		catcher.re.rep_catch.ref = rex;
432da2e3ebdSchin 		catcher.re.rep_catch.cont = cont;
433da2e3ebdSchin 		catcher.re.rep_catch.beg = s;
434da2e3ebdSchin 		catcher.re.rep_catch.n = n + 1;
435da2e3ebdSchin 		catcher.next = rex->next;
436da2e3ebdSchin 		if (n == 0)
437da2e3ebdSchin 			rex->re.rep_catch.beg = s;
438da2e3ebdSchin 		if (env->stack)
439da2e3ebdSchin 		{
440da2e3ebdSchin 			if (matchpush(env, rex))
441da2e3ebdSchin 				return BAD;
442da2e3ebdSchin 			if (pospush(env, rex, s, BEG_ONE))
443da2e3ebdSchin 				return BAD;
444*b30d1939SAndy Fiddaman DEBUG_TEST(0x0004,(sfprintf(sfstdout,"AHA#%04d 0x%04x PUSH %d   (%z,%z)(%z,%z)(%z,%z) (%z,%z)(%z,%z)(%z,%z)\n", __LINE__, debug_flag, rex->re.group.number, env->best[0].rm_so, env->best[0].rm_eo, env->best[1].rm_so, env->best[1].rm_eo, env->best[2].rm_so, env->best[2].rm_eo, env->match[0].rm_so, env->match[0].rm_eo, env->match[1].rm_so, env->match[1].rm_eo, env->match[2].rm_so, env->match[2].rm_eo)),(0));
445da2e3ebdSchin 		}
446da2e3ebdSchin 		r = parse(env, rex->re.group.expr.rex, &catcher, s);
44734f9b3eeSRoland Mainz 		DEBUG_TEST(0x0010,(sfprintf(sfstdout, "AHA#%04d 0x%04x parserep parse %d %d `%-.*s'\n", __LINE__, debug_flag, rex->re.group.number, r, env->end - s, s)),(0));
448da2e3ebdSchin 		if (env->stack)
449da2e3ebdSchin 		{
450da2e3ebdSchin 			pospop(env);
451da2e3ebdSchin 			matchpop(env, rex);
452*b30d1939SAndy Fiddaman DEBUG_TEST(0x0004,(sfprintf(sfstdout,"AHA#%04d 0x%04x POP  %d %d (%z,%z)(%z,%z)(%z,%z) (%z,%z)(%z,%z)(%z,%z)\n", __LINE__, debug_flag, rex->re.group.number, r, env->best[0].rm_so, env->best[0].rm_eo, env->best[1].rm_so, env->best[1].rm_eo, env->best[2].rm_so, env->best[2].rm_eo, env->match[0].rm_so, env->match[0].rm_eo, env->match[1].rm_so, env->match[1].rm_eo, env->match[2].rm_so, env->match[2].rm_eo)),(0));
453da2e3ebdSchin 		}
454da2e3ebdSchin 		switch (r)
455da2e3ebdSchin 		{
456da2e3ebdSchin 		case BAD:
457da2e3ebdSchin 			return BAD;
458da2e3ebdSchin 		case BEST:
459da2e3ebdSchin 			return BEST;
460da2e3ebdSchin 		case CUT:
461da2e3ebdSchin 			r = NONE;
462da2e3ebdSchin 			break;
463da2e3ebdSchin 		case GOOD:
464da2e3ebdSchin 			if (rex->flags & REG_MINIMAL)
465da2e3ebdSchin 				return BEST;
466da2e3ebdSchin 			r = GOOD;
467da2e3ebdSchin 			break;
468da2e3ebdSchin 		}
469da2e3ebdSchin 	}
470da2e3ebdSchin 	if (n < rex->lo)
471da2e3ebdSchin 		return r;
472da2e3ebdSchin 	if (!(rex->flags & REG_MINIMAL) || n >= rex->hi)
473da2e3ebdSchin 	{
474da2e3ebdSchin 		if (env->stack && pospush(env, rex, s, END_ANY))
475da2e3ebdSchin 			return BAD;
476da2e3ebdSchin 		i = follow(env, rex, cont, s);
477da2e3ebdSchin 		if (env->stack)
478da2e3ebdSchin 			pospop(env);
479da2e3ebdSchin 		switch (i)
480da2e3ebdSchin 		{
481da2e3ebdSchin 		case BAD:
482da2e3ebdSchin 			r = BAD;
483da2e3ebdSchin 			break;
484da2e3ebdSchin 		case CUT:
485da2e3ebdSchin 			r = CUT;
486da2e3ebdSchin 			break;
487da2e3ebdSchin 		case BEST:
488da2e3ebdSchin 			r = BEST;
489da2e3ebdSchin 			break;
490da2e3ebdSchin 		case GOOD:
491da2e3ebdSchin 			r = (rex->flags & REG_MINIMAL) ? BEST : GOOD;
492da2e3ebdSchin 			break;
493da2e3ebdSchin 		}
494da2e3ebdSchin 	}
495da2e3ebdSchin 	return r;
496da2e3ebdSchin }
497da2e3ebdSchin 
498da2e3ebdSchin static int
parsetrie(Env_t * env,Trie_node_t * x,Rex_t * rex,Rex_t * cont,unsigned char * s)499da2e3ebdSchin parsetrie(Env_t* env, Trie_node_t* x, Rex_t* rex, Rex_t* cont, unsigned char* s)
500da2e3ebdSchin {
501da2e3ebdSchin 	unsigned char*	p;
502da2e3ebdSchin 	int		r;
503da2e3ebdSchin 
504da2e3ebdSchin 	if (p = rex->map)
505da2e3ebdSchin 	{
506da2e3ebdSchin 		for (;;)
507da2e3ebdSchin 		{
508da2e3ebdSchin 			if (s >= env->end)
509da2e3ebdSchin 				return NONE;
510da2e3ebdSchin 			while (x->c != p[*s])
511da2e3ebdSchin 				if (!(x = x->sib))
512da2e3ebdSchin 					return NONE;
513da2e3ebdSchin 			if (x->end)
514da2e3ebdSchin 				break;
515da2e3ebdSchin 			x = x->son;
516da2e3ebdSchin 			s++;
517da2e3ebdSchin 		}
518da2e3ebdSchin 	}
519da2e3ebdSchin 	else
520da2e3ebdSchin 	{
521da2e3ebdSchin 		for (;;)
522da2e3ebdSchin 		{
523da2e3ebdSchin 			if (s >= env->end)
524da2e3ebdSchin 				return NONE;
525da2e3ebdSchin 			while (x->c != *s)
526da2e3ebdSchin 				if (!(x = x->sib))
527da2e3ebdSchin 					return NONE;
528da2e3ebdSchin 			if (x->end)
529da2e3ebdSchin 				break;
530da2e3ebdSchin 			x = x->son;
531da2e3ebdSchin 			s++;
532da2e3ebdSchin 		}
533da2e3ebdSchin 	}
534da2e3ebdSchin 	s++;
535da2e3ebdSchin 	if (rex->flags & REG_MINIMAL)
536da2e3ebdSchin 		switch (follow(env, rex, cont, s))
537da2e3ebdSchin 		{
538da2e3ebdSchin 		case BAD:
539da2e3ebdSchin 			return BAD;
540da2e3ebdSchin 		case CUT:
541da2e3ebdSchin 			return CUT;
542da2e3ebdSchin 		case BEST:
543da2e3ebdSchin 		case GOOD:
544da2e3ebdSchin 			return BEST;
545da2e3ebdSchin 		}
546da2e3ebdSchin 	if (x->son)
547da2e3ebdSchin 		switch (parsetrie(env, x->son, rex, cont, s))
548da2e3ebdSchin 		{
549da2e3ebdSchin 		case BAD:
550da2e3ebdSchin 			return BAD;
551da2e3ebdSchin 		case CUT:
552da2e3ebdSchin 			return CUT;
553da2e3ebdSchin 		case BEST:
554da2e3ebdSchin 			return BEST;
555da2e3ebdSchin 		case GOOD:
556da2e3ebdSchin 			if (rex->flags & REG_MINIMAL)
557da2e3ebdSchin 				return BEST;
558da2e3ebdSchin 			r = GOOD;
559da2e3ebdSchin 			break;
560da2e3ebdSchin 		default:
561da2e3ebdSchin 			r = NONE;
562da2e3ebdSchin 			break;
563da2e3ebdSchin 		}
564da2e3ebdSchin 	else
565da2e3ebdSchin 		r = NONE;
566da2e3ebdSchin 	if (!(rex->flags & REG_MINIMAL))
567da2e3ebdSchin 		switch (follow(env, rex, cont, s))
568da2e3ebdSchin 		{
569da2e3ebdSchin 		case BAD:
570da2e3ebdSchin 			return BAD;
571da2e3ebdSchin 		case CUT:
572da2e3ebdSchin 			return CUT;
573da2e3ebdSchin 		case BEST:
574da2e3ebdSchin 			return BEST;
575da2e3ebdSchin 		case GOOD:
576da2e3ebdSchin 			return GOOD;
577da2e3ebdSchin 	}
578da2e3ebdSchin 	return r;
579da2e3ebdSchin }
580da2e3ebdSchin 
581da2e3ebdSchin static int
collelt(register Celt_t * ce,char * key,int c,int x)582da2e3ebdSchin collelt(register Celt_t* ce, char* key, int c, int x)
583da2e3ebdSchin {
584da2e3ebdSchin 	Ckey_t	elt;
585da2e3ebdSchin 
586da2e3ebdSchin 	mbxfrm(elt, key, COLL_KEY_MAX);
587da2e3ebdSchin 	for (;; ce++)
588da2e3ebdSchin 	{
589da2e3ebdSchin 		switch (ce->typ)
590da2e3ebdSchin 		{
591da2e3ebdSchin 		case COLL_call:
592da2e3ebdSchin 			if (!x && (*ce->fun)(c))
593da2e3ebdSchin 				return 1;
594da2e3ebdSchin 			continue;
595da2e3ebdSchin 		case COLL_char:
596da2e3ebdSchin 			if (!strcmp((char*)ce->beg, (char*)elt))
597da2e3ebdSchin 				return 1;
598da2e3ebdSchin 			continue;
599da2e3ebdSchin 		case COLL_range:
600da2e3ebdSchin 			if (strcmp((char*)ce->beg, (char*)elt) <= ce->min && strcmp((char*)elt, (char*)ce->end) <= ce->max)
601da2e3ebdSchin 				return 1;
602da2e3ebdSchin 			continue;
603da2e3ebdSchin 		case COLL_range_lc:
604da2e3ebdSchin 			if (strcmp((char*)ce->beg, (char*)elt) <= ce->min && strcmp((char*)elt, (char*)ce->end) <= ce->max && (iswlower(c) || !iswupper(c)))
605da2e3ebdSchin 				return 1;
606da2e3ebdSchin 			continue;
607da2e3ebdSchin 		case COLL_range_uc:
608da2e3ebdSchin 			if (strcmp((char*)ce->beg, (char*)elt) <= ce->min && strcmp((char*)elt, (char*)ce->end) <= ce->max && (iswupper(c) || !iswlower(c)))
609da2e3ebdSchin 				return 1;
610da2e3ebdSchin 			continue;
611da2e3ebdSchin 		}
612da2e3ebdSchin 		break;
613da2e3ebdSchin 	}
614da2e3ebdSchin 	return 0;
615da2e3ebdSchin }
616da2e3ebdSchin 
617da2e3ebdSchin static int
collic(register Celt_t * ce,char * key,register char * nxt,int c,int x)618da2e3ebdSchin collic(register Celt_t* ce, char* key, register char* nxt, int c, int x)
619da2e3ebdSchin {
620da2e3ebdSchin 	if (!x)
621da2e3ebdSchin 	{
622da2e3ebdSchin 		if (collelt(ce, key, c, x))
623da2e3ebdSchin 			return 1;
624da2e3ebdSchin 		if (iswlower(c))
625da2e3ebdSchin 			c = towupper(c);
626da2e3ebdSchin 		else if (iswupper(c))
627da2e3ebdSchin 			c = towlower(c);
628da2e3ebdSchin 		else
629da2e3ebdSchin 			return 0;
6303e14f97fSRoger A. Faulkner 		x = mbconv(key, c);
631da2e3ebdSchin 		key[x] = 0;
632da2e3ebdSchin 		return collelt(ce, key, c, 0);
633da2e3ebdSchin 	}
634da2e3ebdSchin 	while (*nxt)
635da2e3ebdSchin 	{
636da2e3ebdSchin 		if (collic(ce, key, nxt + 1, c, x))
637da2e3ebdSchin 			return 1;
638da2e3ebdSchin 		if (islower(*nxt))
639da2e3ebdSchin 			*nxt = toupper(*nxt);
640da2e3ebdSchin 		else if (isupper(*nxt))
641da2e3ebdSchin 			*nxt = tolower(*nxt);
642da2e3ebdSchin 		else
643da2e3ebdSchin 			return 0;
644da2e3ebdSchin 		nxt++;
645da2e3ebdSchin 	}
646da2e3ebdSchin 	return collelt(ce, key, c, x);
647da2e3ebdSchin }
648da2e3ebdSchin 
649da2e3ebdSchin static int
collmatch(Rex_t * rex,unsigned char * s,unsigned char * e,unsigned char ** p)650da2e3ebdSchin collmatch(Rex_t* rex, unsigned char* s, unsigned char* e, unsigned char** p)
651da2e3ebdSchin {
652da2e3ebdSchin 	unsigned char*		t;
653da2e3ebdSchin 	wchar_t			c;
654da2e3ebdSchin 	int			w;
655da2e3ebdSchin 	int			r;
656da2e3ebdSchin 	int			x;
657da2e3ebdSchin 	int			ic;
658da2e3ebdSchin 	Ckey_t			key;
659da2e3ebdSchin 	Ckey_t			elt;
660da2e3ebdSchin 
661da2e3ebdSchin 	ic = (rex->flags & REG_ICASE);
662da2e3ebdSchin 	if ((w = MBSIZE(s)) > 1)
663da2e3ebdSchin 	{
664da2e3ebdSchin 		memcpy((char*)key, (char*)s, w);
665da2e3ebdSchin 		key[w] = 0;
666da2e3ebdSchin 		t = s;
667da2e3ebdSchin 		c = mbchar(t);
668da2e3ebdSchin #if !_lib_wctype
669da2e3ebdSchin 		c &= 0xff;
670da2e3ebdSchin #endif
671da2e3ebdSchin 		x = 0;
672da2e3ebdSchin 	}
673da2e3ebdSchin 	else
674da2e3ebdSchin 	{
675da2e3ebdSchin 		c = s[0];
676da2e3ebdSchin 		if (ic && isupper(c))
677da2e3ebdSchin 			c = tolower(c);
678da2e3ebdSchin 		key[0] = c;
679da2e3ebdSchin 		key[1] = 0;
680da2e3ebdSchin 		if (isalpha(c))
681da2e3ebdSchin 		{
682da2e3ebdSchin 			x = e - s;
683da2e3ebdSchin 			if (x > COLL_KEY_MAX)
684da2e3ebdSchin 				x = COLL_KEY_MAX;
685da2e3ebdSchin 			while (w < x)
686da2e3ebdSchin 			{
687da2e3ebdSchin 				c = s[w];
688da2e3ebdSchin 				if (!isalpha(c))
689da2e3ebdSchin 					break;
690da2e3ebdSchin 				r = mbxfrm(elt, key, COLL_KEY_MAX);
691da2e3ebdSchin 				if (ic && isupper(c))
692da2e3ebdSchin 					c = tolower(c);
693da2e3ebdSchin 				key[w] = c;
694da2e3ebdSchin 				key[w + 1] = 0;
695da2e3ebdSchin 				if (mbxfrm(elt, key, COLL_KEY_MAX) != r)
696da2e3ebdSchin 					break;
697da2e3ebdSchin 				w++;
698da2e3ebdSchin 			}
699da2e3ebdSchin 		}
700da2e3ebdSchin 		key[w] = 0;
701da2e3ebdSchin 		c = key[0];
702da2e3ebdSchin 		x = w - 1;
703da2e3ebdSchin 	}
704da2e3ebdSchin 	r = 1;
705da2e3ebdSchin 	for (;;)
706da2e3ebdSchin 	{
707da2e3ebdSchin 		if (ic ? collic(rex->re.collate.elements, (char*)key, (char*)key, c, x) : collelt(rex->re.collate.elements, (char*)key, c, x))
708da2e3ebdSchin 			break;
709da2e3ebdSchin 		if (!x)
710da2e3ebdSchin 		{
711da2e3ebdSchin 			r = 0;
712da2e3ebdSchin 			break;
713da2e3ebdSchin 		}
714da2e3ebdSchin 		w = x--;
715da2e3ebdSchin 		key[w] = 0;
716da2e3ebdSchin 	}
717da2e3ebdSchin 	*p = s + w;
718da2e3ebdSchin 	return rex->re.collate.invert ? !r : r;
719da2e3ebdSchin }
720da2e3ebdSchin 
721da2e3ebdSchin static unsigned char*
nestmatch(register unsigned char * s,register unsigned char * e,const unsigned short * type,register int co)722da2e3ebdSchin nestmatch(register unsigned char* s, register unsigned char* e, const unsigned short* type, register int co)
723da2e3ebdSchin {
724da2e3ebdSchin 	register int	c;
725da2e3ebdSchin 	register int	cc;
726da2e3ebdSchin 	unsigned int	n;
727da2e3ebdSchin 	int		oc;
728da2e3ebdSchin 
729da2e3ebdSchin 	if (type[co] & (REX_NEST_literal|REX_NEST_quote))
730da2e3ebdSchin 	{
731da2e3ebdSchin 		n = (type[co] & REX_NEST_literal) ? REX_NEST_terminator : (REX_NEST_escape|REX_NEST_terminator);
732da2e3ebdSchin 		while (s < e)
733da2e3ebdSchin 		{
734da2e3ebdSchin 			c = *s++;
735da2e3ebdSchin 			if (c == co)
736da2e3ebdSchin 				return s;
737da2e3ebdSchin 			else if (type[c] & n)
738da2e3ebdSchin 			{
739da2e3ebdSchin 				if (s >= e || (type[c] & REX_NEST_terminator))
740da2e3ebdSchin 					break;
741da2e3ebdSchin 				s++;
742da2e3ebdSchin 			}
743da2e3ebdSchin 		}
744da2e3ebdSchin 	}
745da2e3ebdSchin 	else
746da2e3ebdSchin 	{
747da2e3ebdSchin 		cc = type[co] >> REX_NEST_SHIFT;
748da2e3ebdSchin 		oc = type[co] & (REX_NEST_open|REX_NEST_close);
749da2e3ebdSchin 		n = 1;
750da2e3ebdSchin 		while (s < e)
751da2e3ebdSchin 		{
752da2e3ebdSchin 			c = *s++;
753da2e3ebdSchin 			switch (type[c] & (REX_NEST_escape|REX_NEST_open|REX_NEST_close|REX_NEST_delimiter|REX_NEST_separator|REX_NEST_terminator))
754da2e3ebdSchin 			{
755da2e3ebdSchin 			case REX_NEST_delimiter:
756da2e3ebdSchin 			case REX_NEST_terminator:
757da2e3ebdSchin 				return oc ? 0 : s;
758da2e3ebdSchin 			case REX_NEST_separator:
759da2e3ebdSchin 				if (!oc)
760da2e3ebdSchin 					return s;
761da2e3ebdSchin 				break;
762da2e3ebdSchin 			case REX_NEST_escape:
763da2e3ebdSchin 				if (s >= e)
764da2e3ebdSchin 					return 0;
765da2e3ebdSchin 				s++;
766da2e3ebdSchin 				break;
767da2e3ebdSchin 			case REX_NEST_open|REX_NEST_close:
768da2e3ebdSchin 				if (c == cc)
769da2e3ebdSchin 				{
770da2e3ebdSchin 					if (!--n)
771da2e3ebdSchin 						return s;
772da2e3ebdSchin 				}
773da2e3ebdSchin 				/*FALLTHROUGH*/
774da2e3ebdSchin 			case REX_NEST_open:
775da2e3ebdSchin 				if (c == co)
776da2e3ebdSchin 				{
777da2e3ebdSchin 					if (!++n)
778da2e3ebdSchin 						return 0;
779da2e3ebdSchin 				}
780da2e3ebdSchin 				else if (!(s = nestmatch(s, e, type, c)))
781da2e3ebdSchin 					return 0;
782da2e3ebdSchin 				break;
783da2e3ebdSchin 			case REX_NEST_close:
784da2e3ebdSchin 				if (c != cc)
785da2e3ebdSchin 					return 0;
786da2e3ebdSchin 				if (!--n)
787da2e3ebdSchin 					return s;
788da2e3ebdSchin 				break;
789da2e3ebdSchin 			}
790da2e3ebdSchin 		}
791da2e3ebdSchin 		return (oc || !(type[UCHAR_MAX+1] & REX_NEST_terminator)) ? 0 : s;
792da2e3ebdSchin 	}
793da2e3ebdSchin 	return 0;
794da2e3ebdSchin }
795da2e3ebdSchin 
796da2e3ebdSchin static int
parse(Env_t * env,Rex_t * rex,Rex_t * cont,unsigned char * s)797da2e3ebdSchin parse(Env_t* env, Rex_t* rex, Rex_t* cont, unsigned char* s)
798da2e3ebdSchin {
799da2e3ebdSchin 	int		c;
800da2e3ebdSchin 	int		d;
801da2e3ebdSchin 	int		m;
802da2e3ebdSchin 	int		r;
803*b30d1939SAndy Fiddaman 	ssize_t		i;
804*b30d1939SAndy Fiddaman 	ssize_t		n;
805da2e3ebdSchin 	int*		f;
806da2e3ebdSchin 	unsigned char*	p;
807da2e3ebdSchin 	unsigned char*	t;
808da2e3ebdSchin 	unsigned char*	b;
809da2e3ebdSchin 	unsigned char*	e;
810da2e3ebdSchin 	char*		u;
811da2e3ebdSchin 	regmatch_t*	o;
812da2e3ebdSchin 	Trie_node_t*	x;
813da2e3ebdSchin 	Rex_t*		q;
814da2e3ebdSchin 	Rex_t		catcher;
815da2e3ebdSchin 	Rex_t		next;
816da2e3ebdSchin 
817da2e3ebdSchin 	for (;;)
818da2e3ebdSchin 	{
819da2e3ebdSchin DEBUG_TEST(0x0008,(sfprintf(sfstdout, "AHA#%04d 0x%04x parse %s `%-.*s'\n", __LINE__, debug_flag, rexname(rex), env->end - s, s)),(0));
820da2e3ebdSchin 		switch (rex->type)
821da2e3ebdSchin 		{
822da2e3ebdSchin 		case REX_ALT:
823da2e3ebdSchin 			if (env->stack)
824da2e3ebdSchin 			{
825da2e3ebdSchin 				if (matchpush(env, rex))
826da2e3ebdSchin 					return BAD;
827da2e3ebdSchin 				if (pospush(env, rex, s, BEG_ALT))
828da2e3ebdSchin 					return BAD;
829da2e3ebdSchin 				catcher.type = REX_ALT_CATCH;
830da2e3ebdSchin 				catcher.serial = rex->serial;
831da2e3ebdSchin 				catcher.re.alt_catch.cont = cont;
832da2e3ebdSchin 				catcher.next = rex->next;
833da2e3ebdSchin 				r = parse(env, rex->re.group.expr.binary.left, &catcher, s);
834da2e3ebdSchin 				if (r < BEST || (rex->flags & REG_MINIMAL))
835da2e3ebdSchin 				{
836da2e3ebdSchin 					matchcopy(env, rex);
837da2e3ebdSchin 					((Pos_t*)env->pos->vec + env->pos->cur - 1)->serial = catcher.serial = rex->re.group.expr.binary.serial;
838da2e3ebdSchin 					n = parse(env, rex->re.group.expr.binary.right, &catcher, s);
839da2e3ebdSchin 					if (n != NONE)
840da2e3ebdSchin 						r = n;
841da2e3ebdSchin 				}
842da2e3ebdSchin 				pospop(env);
843da2e3ebdSchin 				matchpop(env, rex);
844da2e3ebdSchin 			}
845da2e3ebdSchin 			else
846da2e3ebdSchin 			{
847da2e3ebdSchin 				if ((r = parse(env, rex->re.group.expr.binary.left, cont, s)) == NONE)
848da2e3ebdSchin 					r = parse(env, rex->re.group.expr.binary.right, cont, s);
849da2e3ebdSchin 				if (r == GOOD)
850da2e3ebdSchin 					r = BEST;
851da2e3ebdSchin 			}
852da2e3ebdSchin 			return r;
853da2e3ebdSchin 		case REX_ALT_CATCH:
854da2e3ebdSchin 			if (pospush(env, rex, s, END_ANY))
855da2e3ebdSchin 				return BAD;
856da2e3ebdSchin 			r = follow(env, rex, rex->re.alt_catch.cont, s);
857da2e3ebdSchin 			pospop(env);
858da2e3ebdSchin 			return r;
859da2e3ebdSchin 		case REX_BACK:
860da2e3ebdSchin 			o = &env->match[rex->lo];
861da2e3ebdSchin 			if (o->rm_so < 0)
862da2e3ebdSchin 				return NONE;
863da2e3ebdSchin 			i = o->rm_eo - o->rm_so;
864da2e3ebdSchin 			e = s + i;
865da2e3ebdSchin 			if (e > env->end)
866da2e3ebdSchin 				return NONE;
867da2e3ebdSchin 			t = env->beg + o->rm_so;
868da2e3ebdSchin 			if (!(p = rex->map))
869da2e3ebdSchin 			{
870da2e3ebdSchin 				while (s < e)
871da2e3ebdSchin 					if (*s++ != *t++)
872da2e3ebdSchin 						return NONE;
873da2e3ebdSchin 			}
874da2e3ebdSchin 			else if (!mbwide())
875da2e3ebdSchin 			{
876da2e3ebdSchin 				while (s < e)
877da2e3ebdSchin 					if (p[*s++] != p[*t++])
878da2e3ebdSchin 						return NONE;
879da2e3ebdSchin 			}
880da2e3ebdSchin 			else
881da2e3ebdSchin 			{
882da2e3ebdSchin 				while (s < e)
883da2e3ebdSchin 				{
884da2e3ebdSchin 					c = mbchar(s);
885da2e3ebdSchin 					d = mbchar(t);
886da2e3ebdSchin 					if (towupper(c) != towupper(d))
887da2e3ebdSchin 						return NONE;
888da2e3ebdSchin 				}
889da2e3ebdSchin 			}
890da2e3ebdSchin 			break;
891da2e3ebdSchin 		case REX_BEG:
892da2e3ebdSchin 			if ((!(rex->flags & REG_NEWLINE) || s <= env->beg || *(s - 1) != '\n') && ((env->flags & REG_NOTBOL) || s != env->beg))
893da2e3ebdSchin 				return NONE;
894da2e3ebdSchin 			break;
895da2e3ebdSchin 		case REX_CLASS:
896da2e3ebdSchin 			if (LEADING(env, rex, s))
897da2e3ebdSchin 				return NONE;
898da2e3ebdSchin 			n = rex->hi;
899da2e3ebdSchin 			if (n > env->end - s)
900da2e3ebdSchin 				n = env->end - s;
901da2e3ebdSchin 			m = rex->lo;
902da2e3ebdSchin 			if (m > n)
903da2e3ebdSchin 				return NONE;
904da2e3ebdSchin 			r = NONE;
905da2e3ebdSchin 			if (!(rex->flags & REG_MINIMAL))
906da2e3ebdSchin 			{
907da2e3ebdSchin 				for (i = 0; i < n; i++)
908da2e3ebdSchin 					if (!settst(rex->re.charclass, s[i]))
909da2e3ebdSchin 					{
910da2e3ebdSchin 						n = i;
911da2e3ebdSchin 						break;
912da2e3ebdSchin 					}
913da2e3ebdSchin 				for (s += n; n-- >= m; s--)
914da2e3ebdSchin 					switch (follow(env, rex, cont, s))
915da2e3ebdSchin 					{
916da2e3ebdSchin 					case BAD:
917da2e3ebdSchin 						return BAD;
918da2e3ebdSchin 					case CUT:
919da2e3ebdSchin 						return CUT;
920da2e3ebdSchin 					case BEST:
921da2e3ebdSchin 						return BEST;
922da2e3ebdSchin 					case GOOD:
923da2e3ebdSchin 						r = GOOD;
924da2e3ebdSchin 						break;
925da2e3ebdSchin 					}
926da2e3ebdSchin 			}
927da2e3ebdSchin 			else
928da2e3ebdSchin 			{
929da2e3ebdSchin 				for (e = s + m; s < e; s++)
930da2e3ebdSchin 					if (!settst(rex->re.charclass, *s))
931da2e3ebdSchin 						return r;
932da2e3ebdSchin 				e += n - m;
933da2e3ebdSchin 				for (;;)
934da2e3ebdSchin 				{
935da2e3ebdSchin 					switch (follow(env, rex, cont, s))
936da2e3ebdSchin 					{
937da2e3ebdSchin 					case BAD:
938da2e3ebdSchin 						return BAD;
939da2e3ebdSchin 					case CUT:
940da2e3ebdSchin 						return CUT;
941da2e3ebdSchin 					case BEST:
942da2e3ebdSchin 					case GOOD:
943da2e3ebdSchin 						return BEST;
944da2e3ebdSchin 					}
945da2e3ebdSchin 					if (s >= e || !settst(rex->re.charclass, *s))
946da2e3ebdSchin 						break;
947da2e3ebdSchin 					s++;
948da2e3ebdSchin 				}
949da2e3ebdSchin 			}
950da2e3ebdSchin 			return r;
951da2e3ebdSchin 		case REX_COLL_CLASS:
952da2e3ebdSchin 			if (LEADING(env, rex, s))
953da2e3ebdSchin 				return NONE;
954da2e3ebdSchin 			n = rex->hi;
955da2e3ebdSchin 			if (n > env->end - s)
956da2e3ebdSchin 				n = env->end - s;
957da2e3ebdSchin 			m = rex->lo;
958da2e3ebdSchin 			if (m > n)
959da2e3ebdSchin 				return NONE;
960da2e3ebdSchin 			r = NONE;
961da2e3ebdSchin 			e = env->end;
962da2e3ebdSchin 			if (!(rex->flags & REG_MINIMAL))
963da2e3ebdSchin 			{
964da2e3ebdSchin 				if (!(b = (unsigned char*)stkpush(stkstd, n)))
965da2e3ebdSchin 				{
966da2e3ebdSchin 					env->error = REG_ESPACE;
967da2e3ebdSchin 					return BAD;
968da2e3ebdSchin 				}
969da2e3ebdSchin 				for (i = 0; s < e && i < n && collmatch(rex, s, e, &t); i++)
970da2e3ebdSchin 				{
971da2e3ebdSchin 					b[i] = t - s;
972da2e3ebdSchin 					s = t;
973da2e3ebdSchin 				}
974da2e3ebdSchin 				for (; i-- >= rex->lo; s -= b[i])
975da2e3ebdSchin 					switch (follow(env, rex, cont, s))
976da2e3ebdSchin 					{
977da2e3ebdSchin 					case BAD:
978da2e3ebdSchin 						stkpop(stkstd);
979da2e3ebdSchin 						return BAD;
980da2e3ebdSchin 					case CUT:
981da2e3ebdSchin 						stkpop(stkstd);
982da2e3ebdSchin 						return CUT;
983da2e3ebdSchin 					case BEST:
984da2e3ebdSchin 						stkpop(stkstd);
985da2e3ebdSchin 						return BEST;
986da2e3ebdSchin 					case GOOD:
987da2e3ebdSchin 						r = GOOD;
988da2e3ebdSchin 						break;
989da2e3ebdSchin 					}
990da2e3ebdSchin 				stkpop(stkstd);
991da2e3ebdSchin 			}
992da2e3ebdSchin 			else
993da2e3ebdSchin 			{
994da2e3ebdSchin 				for (i = 0; i < m && s < e; i++, s = t)
995da2e3ebdSchin 					if (!collmatch(rex, s, e, &t))
996da2e3ebdSchin 						return r;
997da2e3ebdSchin 				while (i++ <= n)
998da2e3ebdSchin 				{
999da2e3ebdSchin 					switch (follow(env, rex, cont, s))
1000da2e3ebdSchin 					{
1001da2e3ebdSchin 					case BAD:
1002da2e3ebdSchin 						return BAD;
1003da2e3ebdSchin 					case CUT:
1004da2e3ebdSchin 						return CUT;
1005da2e3ebdSchin 					case BEST:
1006da2e3ebdSchin 					case GOOD:
1007da2e3ebdSchin 						return BEST;
1008da2e3ebdSchin 					}
1009da2e3ebdSchin 					if (s >= e || !collmatch(rex, s, e, &s))
1010da2e3ebdSchin 						break;
1011da2e3ebdSchin 				}
1012da2e3ebdSchin 			}
1013da2e3ebdSchin 			return r;
1014da2e3ebdSchin 		case REX_CONJ:
1015da2e3ebdSchin 			next.type = REX_CONJ_RIGHT;
1016da2e3ebdSchin 			next.re.conj_right.cont = cont;
1017da2e3ebdSchin 			next.next = rex->next;
1018da2e3ebdSchin 			catcher.type = REX_CONJ_LEFT;
1019da2e3ebdSchin 			catcher.re.conj_left.right = rex->re.group.expr.binary.right;
1020da2e3ebdSchin 			catcher.re.conj_left.cont = &next;
1021da2e3ebdSchin 			catcher.re.conj_left.beg = s;
1022da2e3ebdSchin 			catcher.next = 0;
1023da2e3ebdSchin 			return parse(env, rex->re.group.expr.binary.left, &catcher, s);
1024da2e3ebdSchin 		case REX_CONJ_LEFT:
1025da2e3ebdSchin 			rex->re.conj_left.cont->re.conj_right.end = s;
1026da2e3ebdSchin 			cont = rex->re.conj_left.cont;
1027da2e3ebdSchin 			s = rex->re.conj_left.beg;
1028da2e3ebdSchin 			rex = rex->re.conj_left.right;
1029da2e3ebdSchin 			continue;
1030da2e3ebdSchin 		case REX_CONJ_RIGHT:
1031da2e3ebdSchin 			if (rex->re.conj_right.end != s)
1032da2e3ebdSchin 				return NONE;
1033da2e3ebdSchin 			cont = rex->re.conj_right.cont;
1034da2e3ebdSchin 			break;
1035da2e3ebdSchin 		case REX_DONE:
1036da2e3ebdSchin 			if (!env->stack)
1037da2e3ebdSchin 				return BEST;
1038da2e3ebdSchin 			n = s - env->beg;
1039da2e3ebdSchin 			r = env->nsub;
1040*b30d1939SAndy Fiddaman 			DEBUG_TEST(0x0100,(sfprintf(sfstdout,"AHA#%04d 0x%04x %s (%z,%z)(%z,%z)(%z,%z)(%z,%z) (%z,%z)(%z,%z)\n", __LINE__, debug_flag, rexname(rex), env->best[0].rm_so, env->best[0].rm_eo, env->best[1].rm_so, env->best[1].rm_eo, env->best[2].rm_so, env->best[2].rm_eo, env->best[3].rm_so, env->best[3].rm_eo, env->match[0].rm_so, env->match[0].rm_eo, env->match[1].rm_so, env->match[1].rm_eo)),(0));
1041da2e3ebdSchin 			if ((i = env->best[0].rm_eo) >= 0)
1042da2e3ebdSchin 			{
1043da2e3ebdSchin 				if (rex->flags & REG_MINIMAL)
1044da2e3ebdSchin 				{
1045da2e3ebdSchin 					if (n > i)
1046da2e3ebdSchin 						return GOOD;
1047da2e3ebdSchin 				}
1048da2e3ebdSchin 				else
1049da2e3ebdSchin 				{
1050da2e3ebdSchin 					if (n < i)
1051da2e3ebdSchin 						return GOOD;
1052da2e3ebdSchin 				}
1053da2e3ebdSchin 				if (n == i && better(env,
1054da2e3ebdSchin 						     (Pos_t*)env->bestpos->vec,
1055da2e3ebdSchin 				   		     (Pos_t*)env->pos->vec,
1056da2e3ebdSchin 				   		     (Pos_t*)env->bestpos->vec+env->bestpos->cur,
1057da2e3ebdSchin 				   		     (Pos_t*)env->pos->vec+env->pos->cur,
1058da2e3ebdSchin 						     0) <= 0)
1059da2e3ebdSchin 					return GOOD;
1060da2e3ebdSchin 			}
1061da2e3ebdSchin 			env->best[0].rm_eo = n;
1062da2e3ebdSchin 			memcpy(&env->best[1], &env->match[1], r * sizeof(regmatch_t));
1063da2e3ebdSchin 			n = env->pos->cur;
1064da2e3ebdSchin 			if (!vector(Pos_t, env->bestpos, n))
1065da2e3ebdSchin 			{
1066da2e3ebdSchin 				env->error = REG_ESPACE;
1067da2e3ebdSchin 				return BAD;
1068da2e3ebdSchin 			}
1069da2e3ebdSchin 			env->bestpos->cur = n;
1070da2e3ebdSchin 			memcpy(env->bestpos->vec, env->pos->vec, n * sizeof(Pos_t));
1071*b30d1939SAndy Fiddaman 			DEBUG_TEST(0x0100,(sfprintf(sfstdout,"AHA#%04d 0x%04x %s (%z,%z)(%z,%z)(%z,%z)(%z,%z) (%z,%z)(%z,%z)\n", __LINE__, debug_flag, rexname(rex), env->best[0].rm_so, env->best[0].rm_eo, env->best[1].rm_so, env->best[1].rm_eo, env->best[2].rm_so, env->best[2].rm_eo, env->best[3].rm_so, env->best[3].rm_eo, env->match[0].rm_so, env->match[0].rm_eo, env->match[1].rm_so, env->match[1].rm_eo)),(0));
1072da2e3ebdSchin 			return GOOD;
1073da2e3ebdSchin 		case REX_DOT:
1074da2e3ebdSchin 			if (LEADING(env, rex, s))
1075da2e3ebdSchin 				return NONE;
1076da2e3ebdSchin 			n = rex->hi;
1077da2e3ebdSchin 			if (n > env->end - s)
1078da2e3ebdSchin 				n = env->end - s;
1079da2e3ebdSchin 			m = rex->lo;
1080da2e3ebdSchin 			if (m > n)
1081da2e3ebdSchin 				return NONE;
1082da2e3ebdSchin 			if ((c = rex->explicit) >= 0 && !mbwide())
1083da2e3ebdSchin 				for (i = 0; i < n; i++)
1084da2e3ebdSchin 					if (s[i] == c)
1085da2e3ebdSchin 					{
1086da2e3ebdSchin 						n = i;
1087da2e3ebdSchin 						break;
1088da2e3ebdSchin 					}
1089da2e3ebdSchin 			r = NONE;
1090da2e3ebdSchin 			if (!(rex->flags & REG_MINIMAL))
1091da2e3ebdSchin 			{
1092da2e3ebdSchin 				if (!mbwide())
1093da2e3ebdSchin 				{
1094da2e3ebdSchin 					for (s += n; n-- >= m; s--)
1095da2e3ebdSchin 						switch (follow(env, rex, cont, s))
1096da2e3ebdSchin 						{
1097da2e3ebdSchin 						case BAD:
1098da2e3ebdSchin 							return BAD;
1099da2e3ebdSchin 						case CUT:
1100da2e3ebdSchin 							return CUT;
1101da2e3ebdSchin 						case BEST:
1102da2e3ebdSchin 							return BEST;
1103da2e3ebdSchin 						case GOOD:
1104da2e3ebdSchin 							r = GOOD;
1105da2e3ebdSchin 							break;
1106da2e3ebdSchin 						}
1107da2e3ebdSchin 				}
1108da2e3ebdSchin 				else
1109da2e3ebdSchin 				{
1110da2e3ebdSchin 					if (!(b = (unsigned char*)stkpush(stkstd, n)))
1111da2e3ebdSchin 					{
1112da2e3ebdSchin 						env->error = REG_ESPACE;
1113da2e3ebdSchin 						return BAD;
1114da2e3ebdSchin 					}
1115da2e3ebdSchin 					e = env->end;
1116da2e3ebdSchin 					for (i = 0; s < e && i < n && *s != c; i++)
1117da2e3ebdSchin 						s += b[i] = MBSIZE(s);
1118da2e3ebdSchin 					for (; i-- >= m; s -= b[i])
1119da2e3ebdSchin 						switch (follow(env, rex, cont, s))
1120da2e3ebdSchin 						{
1121da2e3ebdSchin 						case BAD:
1122da2e3ebdSchin 							stkpop(stkstd);
1123da2e3ebdSchin 							return BAD;
1124da2e3ebdSchin 						case CUT:
1125da2e3ebdSchin 							stkpop(stkstd);
1126da2e3ebdSchin 							return CUT;
1127da2e3ebdSchin 						case BEST:
1128da2e3ebdSchin 							stkpop(stkstd);
1129da2e3ebdSchin 							return BEST;
1130da2e3ebdSchin 						case GOOD:
1131da2e3ebdSchin 							r = GOOD;
1132da2e3ebdSchin 							break;
1133da2e3ebdSchin 						}
1134da2e3ebdSchin 					stkpop(stkstd);
1135da2e3ebdSchin 				}
1136da2e3ebdSchin 			}
1137da2e3ebdSchin 			else
1138da2e3ebdSchin 			{
1139da2e3ebdSchin 				if (!mbwide())
1140da2e3ebdSchin 				{
1141da2e3ebdSchin 					e = s + n;
1142da2e3ebdSchin 					for (s += m; s <= e; s++)
1143da2e3ebdSchin 						switch (follow(env, rex, cont, s))
1144da2e3ebdSchin 						{
1145da2e3ebdSchin 						case BAD:
1146da2e3ebdSchin 							return BAD;
1147da2e3ebdSchin 						case CUT:
1148da2e3ebdSchin 							return CUT;
1149da2e3ebdSchin 						case BEST:
1150da2e3ebdSchin 						case GOOD:
1151da2e3ebdSchin 							return BEST;
1152da2e3ebdSchin 						}
1153da2e3ebdSchin 				}
1154da2e3ebdSchin 				else
1155da2e3ebdSchin 				{
1156da2e3ebdSchin 					e = env->end;
1157da2e3ebdSchin 					for (i = 0; s < e && i < m && *s != c; i++)
1158da2e3ebdSchin 						s += MBSIZE(s);
1159da2e3ebdSchin 					if (i >= m)
1160da2e3ebdSchin 						for (; s <= e && i <= n; s += MBSIZE(s), i++)
1161da2e3ebdSchin 							switch (follow(env, rex, cont, s))
1162da2e3ebdSchin 							{
1163da2e3ebdSchin 							case BAD:
1164da2e3ebdSchin 								return BAD;
1165da2e3ebdSchin 							case CUT:
1166da2e3ebdSchin 								return CUT;
1167da2e3ebdSchin 							case BEST:
1168da2e3ebdSchin 							case GOOD:
1169da2e3ebdSchin 								return BEST;
1170da2e3ebdSchin 							}
1171da2e3ebdSchin 				}
1172da2e3ebdSchin 			}
1173da2e3ebdSchin 			return r;
1174da2e3ebdSchin 		case REX_END:
1175da2e3ebdSchin 			if ((!(rex->flags & REG_NEWLINE) || *s != '\n') && ((env->flags & REG_NOTEOL) || s < env->end))
1176da2e3ebdSchin 				return NONE;
1177da2e3ebdSchin 			break;
1178da2e3ebdSchin 		case REX_GROUP:
1179da2e3ebdSchin DEBUG_TEST(0x0200,(sfprintf(sfstdout,"AHA#%04d 0x%04x parse %s `%-.*s'\n", __LINE__, debug_flag, rexname(rex), env->end - s, s)),(0));
1180da2e3ebdSchin 			if (env->stack)
1181da2e3ebdSchin 			{
1182da2e3ebdSchin 				if (rex->re.group.number)
1183da2e3ebdSchin 					env->match[rex->re.group.number].rm_so = s - env->beg;
1184da2e3ebdSchin 				if (pospush(env, rex, s, BEG_SUB))
1185da2e3ebdSchin 					return BAD;
1186da2e3ebdSchin 				catcher.re.group_catch.eo = rex->re.group.number ? &env->match[rex->re.group.number].rm_eo : (regoff_t*)0;
1187da2e3ebdSchin 			}
1188da2e3ebdSchin 			catcher.type = REX_GROUP_CATCH;
1189da2e3ebdSchin 			catcher.serial = rex->serial;
1190da2e3ebdSchin 			catcher.re.group_catch.cont = cont;
1191da2e3ebdSchin 			catcher.next = rex->next;
1192da2e3ebdSchin 			r = parse(env, rex->re.group.expr.rex, &catcher, s);
1193da2e3ebdSchin 			if (env->stack)
1194da2e3ebdSchin 			{
1195da2e3ebdSchin 				pospop(env);
1196da2e3ebdSchin 				if (rex->re.group.number)
1197da2e3ebdSchin 					env->match[rex->re.group.number].rm_so = -1;
1198da2e3ebdSchin 			}
1199da2e3ebdSchin 			return r;
1200da2e3ebdSchin 		case REX_GROUP_CATCH:
1201da2e3ebdSchin DEBUG_TEST(0x0200,(sfprintf(sfstdout,"AHA#%04d 0x%04x parse %s=>%s `%-.*s'\n", __LINE__, debug_flag, rexname(rex), rexname(rex->re.group_catch.cont), env->end - s, s)),(0));
1202da2e3ebdSchin 			if (env->stack)
1203da2e3ebdSchin 			{
1204da2e3ebdSchin 				if (rex->re.group_catch.eo)
1205da2e3ebdSchin 					*rex->re.group_catch.eo = s - env->beg;
1206da2e3ebdSchin 				if (pospush(env, rex, s, END_ANY))
1207da2e3ebdSchin 					return BAD;
1208da2e3ebdSchin 			}
1209da2e3ebdSchin 			r = follow(env, rex, rex->re.group_catch.cont, s);
1210da2e3ebdSchin 			if (env->stack)
1211da2e3ebdSchin 			{
1212da2e3ebdSchin 				pospop(env);
1213da2e3ebdSchin 				if (rex->re.group_catch.eo)
1214da2e3ebdSchin 					*rex->re.group_catch.eo = -1;
1215da2e3ebdSchin 			}
1216da2e3ebdSchin 			return r;
1217da2e3ebdSchin 		case REX_GROUP_AHEAD:
1218da2e3ebdSchin 			catcher.type = REX_GROUP_AHEAD_CATCH;
1219da2e3ebdSchin 			catcher.flags = rex->flags;
1220da2e3ebdSchin 			catcher.serial = rex->serial;
1221da2e3ebdSchin 			catcher.re.rep_catch.beg = s;
1222da2e3ebdSchin 			catcher.re.rep_catch.cont = cont;
1223da2e3ebdSchin 			catcher.next = rex->next;
1224da2e3ebdSchin 			return parse(env, rex->re.group.expr.rex, &catcher, s);
1225da2e3ebdSchin 		case REX_GROUP_AHEAD_CATCH:
1226da2e3ebdSchin 			return follow(env, rex, rex->re.rep_catch.cont, rex->re.rep_catch.beg);
1227da2e3ebdSchin 		case REX_GROUP_AHEAD_NOT:
1228da2e3ebdSchin 			r = parse(env, rex->re.group.expr.rex, NiL, s);
1229da2e3ebdSchin 			if (r == NONE)
1230da2e3ebdSchin 				r = follow(env, rex, cont, s);
1231da2e3ebdSchin 			else if (r != BAD)
1232da2e3ebdSchin 				r = NONE;
1233da2e3ebdSchin 			return r;
1234da2e3ebdSchin 		case REX_GROUP_BEHIND:
1235da2e3ebdSchin 			if ((s - env->beg) < rex->re.group.size)
1236da2e3ebdSchin 				return NONE;
1237da2e3ebdSchin 			catcher.type = REX_GROUP_BEHIND_CATCH;
1238da2e3ebdSchin 			catcher.flags = rex->flags;
1239da2e3ebdSchin 			catcher.serial = rex->serial;
1240da2e3ebdSchin 			catcher.re.behind_catch.beg = s;
1241da2e3ebdSchin 			catcher.re.behind_catch.end = e = env->end;
1242da2e3ebdSchin 			catcher.re.behind_catch.cont = cont;
1243da2e3ebdSchin 			catcher.next = rex->next;
1244da2e3ebdSchin 			for (t = s - rex->re.group.size; t >= env->beg; t--)
1245da2e3ebdSchin 			{
1246da2e3ebdSchin 				env->end = s;
1247da2e3ebdSchin 				r = parse(env, rex->re.group.expr.rex, &catcher, t);
1248da2e3ebdSchin 				env->end = e;
1249da2e3ebdSchin 				if (r != NONE)
1250da2e3ebdSchin 					return r;
1251da2e3ebdSchin 			}
1252da2e3ebdSchin 			return NONE;
1253da2e3ebdSchin 		case REX_GROUP_BEHIND_CATCH:
1254da2e3ebdSchin 			if (s != rex->re.behind_catch.beg)
1255da2e3ebdSchin 				return NONE;
1256da2e3ebdSchin 			env->end = rex->re.behind_catch.end;
1257da2e3ebdSchin 			return follow(env, rex, rex->re.behind_catch.cont, rex->re.behind_catch.beg);
1258da2e3ebdSchin 		case REX_GROUP_BEHIND_NOT:
1259da2e3ebdSchin 			if ((s - env->beg) < rex->re.group.size)
1260da2e3ebdSchin 				r = NONE;
1261da2e3ebdSchin 			else
1262da2e3ebdSchin 			{
1263da2e3ebdSchin 				catcher.type = REX_GROUP_BEHIND_NOT_CATCH;
1264da2e3ebdSchin 				catcher.re.neg_catch.beg = s;
1265da2e3ebdSchin 				catcher.next = 0;
1266da2e3ebdSchin 				e = env->end;
1267da2e3ebdSchin 				env->end = s;
1268da2e3ebdSchin 				for (t = s - rex->re.group.size; t >= env->beg; t--)
1269da2e3ebdSchin 				{
1270da2e3ebdSchin 					r = parse(env, rex->re.group.expr.rex, &catcher, t);
1271da2e3ebdSchin 					if (r != NONE)
1272da2e3ebdSchin 						break;
1273da2e3ebdSchin 				}
1274da2e3ebdSchin 				env->end = e;
1275da2e3ebdSchin 			}
1276da2e3ebdSchin 			if (r == NONE)
1277da2e3ebdSchin 				r = follow(env, rex, cont, s);
1278da2e3ebdSchin 			else if (r != BAD)
1279da2e3ebdSchin 				r = NONE;
1280da2e3ebdSchin 			return r;
1281da2e3ebdSchin 		case REX_GROUP_BEHIND_NOT_CATCH:
1282da2e3ebdSchin 			return s == rex->re.neg_catch.beg ? GOOD : NONE;
1283da2e3ebdSchin 		case REX_GROUP_COND:
1284da2e3ebdSchin 			if (q = rex->re.group.expr.binary.right)
1285da2e3ebdSchin 			{
1286da2e3ebdSchin 				catcher.re.cond_catch.next[0] = q->re.group.expr.binary.right;
1287da2e3ebdSchin 				catcher.re.cond_catch.next[1] = q->re.group.expr.binary.left;
1288da2e3ebdSchin 			}
1289da2e3ebdSchin 			else
1290da2e3ebdSchin 				catcher.re.cond_catch.next[0] = catcher.re.cond_catch.next[1] = 0;
1291da2e3ebdSchin 			if (q = rex->re.group.expr.binary.left)
1292da2e3ebdSchin 			{
1293da2e3ebdSchin 				catcher.type = REX_GROUP_COND_CATCH;
1294da2e3ebdSchin 				catcher.flags = rex->flags;
1295da2e3ebdSchin 				catcher.serial = rex->serial;
1296da2e3ebdSchin 				catcher.re.cond_catch.yes = 0;
1297da2e3ebdSchin 				catcher.re.cond_catch.beg = s;
1298da2e3ebdSchin 				catcher.re.cond_catch.cont = cont;
1299da2e3ebdSchin 				catcher.next = rex->next;
1300da2e3ebdSchin 				r = parse(env, q, &catcher, s);
1301da2e3ebdSchin 				if (r == BAD || catcher.re.cond_catch.yes)
1302da2e3ebdSchin 					return r;
1303da2e3ebdSchin 			}
1304da2e3ebdSchin 			else if (!rex->re.group.size || rex->re.group.size > 0 && env->match[rex->re.group.size].rm_so >= 0)
1305da2e3ebdSchin 				r = GOOD;
1306da2e3ebdSchin 			else
1307da2e3ebdSchin 				r = NONE;
1308da2e3ebdSchin 			if (q = catcher.re.cond_catch.next[r != NONE])
1309da2e3ebdSchin 			{
1310da2e3ebdSchin 				catcher.type = REX_CAT;
1311da2e3ebdSchin 				catcher.flags = q->flags;
1312da2e3ebdSchin 				catcher.serial = q->serial;
1313da2e3ebdSchin 				catcher.re.group_catch.cont = cont;
1314da2e3ebdSchin 				catcher.next = rex->next;
1315da2e3ebdSchin 				return parse(env, q, &catcher, s);
1316da2e3ebdSchin 			}
1317da2e3ebdSchin 			return follow(env, rex, cont, s);
1318da2e3ebdSchin 		case REX_GROUP_COND_CATCH:
1319da2e3ebdSchin 			rex->re.cond_catch.yes = 1;
1320da2e3ebdSchin 			catcher.type = REX_CAT;
1321da2e3ebdSchin 			catcher.flags = rex->flags;
1322da2e3ebdSchin 			catcher.serial = rex->serial;
1323da2e3ebdSchin 			catcher.re.group_catch.cont = rex->re.cond_catch.cont;
1324da2e3ebdSchin 			catcher.next = rex->next;
1325da2e3ebdSchin 			return parse(env, rex->re.cond_catch.next[1], &catcher, rex->re.cond_catch.beg);
1326da2e3ebdSchin 		case REX_CAT:
1327da2e3ebdSchin 			return follow(env, rex, rex->re.group_catch.cont, s);
1328da2e3ebdSchin 		case REX_GROUP_CUT:
1329da2e3ebdSchin 			catcher.type = REX_GROUP_CUT_CATCH;
1330da2e3ebdSchin 			catcher.flags = rex->flags;
1331da2e3ebdSchin 			catcher.serial = rex->serial;
1332da2e3ebdSchin 			catcher.re.group_catch.cont = cont;
1333da2e3ebdSchin 			catcher.next = rex->next;
1334da2e3ebdSchin 			return parse(env, rex->re.group.expr.rex, &catcher, s);
1335da2e3ebdSchin 		case REX_GROUP_CUT_CATCH:
1336da2e3ebdSchin 			switch (r = follow(env, rex, rex->re.group_catch.cont, s))
1337da2e3ebdSchin 			{
1338da2e3ebdSchin 			case GOOD:
1339da2e3ebdSchin 				r = BEST;
1340da2e3ebdSchin 				break;
1341da2e3ebdSchin 			case NONE:
1342da2e3ebdSchin 				r = CUT;
1343da2e3ebdSchin 				break;
1344da2e3ebdSchin 			}
1345da2e3ebdSchin 			return r;
1346da2e3ebdSchin 		case REX_KMP:
1347da2e3ebdSchin 			f = rex->re.string.fail;
1348da2e3ebdSchin 			b = rex->re.string.base;
1349da2e3ebdSchin 			n = rex->re.string.size;
1350da2e3ebdSchin 			t = s;
1351da2e3ebdSchin 			e = env->end;
1352da2e3ebdSchin 			if (p = rex->map)
1353da2e3ebdSchin 			{
1354da2e3ebdSchin 				while (t + n <= e)
1355da2e3ebdSchin 				{
1356da2e3ebdSchin 					for (i = -1; t < e; t++)
1357da2e3ebdSchin 					{
1358da2e3ebdSchin 						while (i >= 0 && b[i+1] != p[*t])
1359da2e3ebdSchin 							i = f[i];
1360da2e3ebdSchin 						if (b[i+1] == p[*t])
1361da2e3ebdSchin 							i++;
1362da2e3ebdSchin 						if (i + 1 == n)
1363da2e3ebdSchin 						{
1364da2e3ebdSchin 							t++;
1365da2e3ebdSchin 							if (env->stack)
1366da2e3ebdSchin 								env->best[0].rm_so = t - s - n;
1367da2e3ebdSchin 							switch (follow(env, rex, cont, t))
1368da2e3ebdSchin 							{
1369da2e3ebdSchin 							case BAD:
1370da2e3ebdSchin 								return BAD;
1371da2e3ebdSchin 							case CUT:
1372da2e3ebdSchin 								return CUT;
1373da2e3ebdSchin 							case BEST:
1374da2e3ebdSchin 							case GOOD:
1375da2e3ebdSchin 								return BEST;
1376da2e3ebdSchin 							}
1377da2e3ebdSchin 							t -= n - 1;
1378da2e3ebdSchin 							break;
1379da2e3ebdSchin 						}
1380da2e3ebdSchin 					}
1381da2e3ebdSchin 				}
1382da2e3ebdSchin 			}
1383da2e3ebdSchin 			else
1384da2e3ebdSchin 			{
1385da2e3ebdSchin 				while (t + n <= e)
1386da2e3ebdSchin 				{
1387da2e3ebdSchin 					for (i = -1; t < e; t++)
1388da2e3ebdSchin 					{
1389da2e3ebdSchin 						while (i >= 0 && b[i+1] != *t)
1390da2e3ebdSchin 							i = f[i];
1391da2e3ebdSchin 						if (b[i+1] == *t)
1392da2e3ebdSchin 							i++;
1393da2e3ebdSchin 						if (i + 1 == n)
1394da2e3ebdSchin 						{
1395da2e3ebdSchin 							t++;
1396da2e3ebdSchin 							if (env->stack)
1397da2e3ebdSchin 								env->best[0].rm_so = t - s - n;
1398da2e3ebdSchin 							switch (follow(env, rex, cont, t))
1399da2e3ebdSchin 							{
1400da2e3ebdSchin 							case BAD:
1401da2e3ebdSchin 								return BAD;
1402da2e3ebdSchin 							case CUT:
1403da2e3ebdSchin 								return CUT;
1404da2e3ebdSchin 							case BEST:
1405da2e3ebdSchin 							case GOOD:
1406da2e3ebdSchin 								return BEST;
1407da2e3ebdSchin 							}
1408da2e3ebdSchin 							t -= n - 1;
1409da2e3ebdSchin 							break;
1410da2e3ebdSchin 						}
1411da2e3ebdSchin 					}
1412da2e3ebdSchin 				}
1413da2e3ebdSchin 			}
1414da2e3ebdSchin 			return NONE;
1415da2e3ebdSchin 		case REX_NEG:
1416da2e3ebdSchin 			if (LEADING(env, rex, s))
1417da2e3ebdSchin 				return NONE;
1418da2e3ebdSchin 			i = env->end - s;
1419da2e3ebdSchin 			n = ((i + 7) >> 3) + 1;
1420da2e3ebdSchin 			catcher.type = REX_NEG_CATCH;
1421da2e3ebdSchin 			catcher.re.neg_catch.beg = s;
1422da2e3ebdSchin 			if (!(p = (unsigned char*)stkpush(stkstd, n)))
1423da2e3ebdSchin 				return BAD;
1424da2e3ebdSchin 			memset(catcher.re.neg_catch.index = p, 0, n);
1425da2e3ebdSchin 			catcher.next = rex->next;
1426da2e3ebdSchin 			if (parse(env, rex->re.group.expr.rex, &catcher, s) == BAD)
1427da2e3ebdSchin 				r = BAD;
1428da2e3ebdSchin 			else
1429da2e3ebdSchin 			{
1430da2e3ebdSchin 				r = NONE;
1431da2e3ebdSchin 				for (; i >= 0; i--)
1432da2e3ebdSchin 					if (!bittst(p, i))
1433da2e3ebdSchin 					{
1434da2e3ebdSchin 						switch (follow(env, rex, cont, s + i))
1435da2e3ebdSchin 						{
1436da2e3ebdSchin 						case BAD:
1437da2e3ebdSchin 							r = BAD;
1438da2e3ebdSchin 							break;
1439da2e3ebdSchin 						case BEST:
1440da2e3ebdSchin 							r = BEST;
1441da2e3ebdSchin 							break;
1442da2e3ebdSchin 						case CUT:
1443da2e3ebdSchin 							r = CUT;
1444da2e3ebdSchin 							break;
1445da2e3ebdSchin 						case GOOD:
1446da2e3ebdSchin 							r = GOOD;
1447da2e3ebdSchin 							/*FALLTHROUGH*/
1448da2e3ebdSchin 						default:
1449da2e3ebdSchin 							continue;
1450da2e3ebdSchin 						}
1451da2e3ebdSchin 						break;
1452da2e3ebdSchin 					}
1453da2e3ebdSchin 			}
1454da2e3ebdSchin 			stkpop(stkstd);
1455da2e3ebdSchin 			return r;
1456da2e3ebdSchin 		case REX_NEG_CATCH:
1457da2e3ebdSchin 			bitset(rex->re.neg_catch.index, s - rex->re.neg_catch.beg);
1458da2e3ebdSchin 			return NONE;
1459da2e3ebdSchin 		case REX_NEST:
14607c2fbfb3SApril Chin 			if (s >= env->end)
14617c2fbfb3SApril Chin 				return NONE;
1462da2e3ebdSchin 			do
1463da2e3ebdSchin 			{
1464da2e3ebdSchin 				if ((c = *s++) == rex->re.nest.primary)
1465da2e3ebdSchin 				{
1466da2e3ebdSchin 					if (s >= env->end || !(s = nestmatch(s, env->end, rex->re.nest.type, c)))
1467da2e3ebdSchin 						return NONE;
1468da2e3ebdSchin 					break;
1469da2e3ebdSchin 				}
1470da2e3ebdSchin 				if (rex->re.nest.primary >= 0)
1471da2e3ebdSchin 					return NONE;
1472da2e3ebdSchin 			    	if (rex->re.nest.type[c] & (REX_NEST_delimiter|REX_NEST_separator|REX_NEST_terminator))
1473da2e3ebdSchin 					break;
1474da2e3ebdSchin 			    	if (!(s = nestmatch(s, env->end, rex->re.nest.type, c)))
1475da2e3ebdSchin 					return NONE;
1476da2e3ebdSchin 			} while (s < env->end && !(rex->re.nest.type[*(s-1)] & (REX_NEST_delimiter|REX_NEST_separator|REX_NEST_terminator)));
1477da2e3ebdSchin 			break;
1478da2e3ebdSchin 		case REX_NULL:
1479da2e3ebdSchin 			break;
1480da2e3ebdSchin 		case REX_ONECHAR:
1481da2e3ebdSchin 			n = rex->hi;
1482da2e3ebdSchin 			if (n > env->end - s)
1483da2e3ebdSchin 				n = env->end - s;
1484da2e3ebdSchin 			m = rex->lo;
1485da2e3ebdSchin 			if (m > n)
1486da2e3ebdSchin 				return NONE;
1487da2e3ebdSchin 			r = NONE;
1488da2e3ebdSchin 			c = rex->re.onechar;
1489da2e3ebdSchin 			if (!(rex->flags & REG_MINIMAL))
1490da2e3ebdSchin 			{
1491da2e3ebdSchin 				if (!mbwide())
1492da2e3ebdSchin 				{
1493da2e3ebdSchin 					if (p = rex->map)
1494da2e3ebdSchin 					{
1495da2e3ebdSchin 						for (i = 0; i < n; i++, s++)
1496da2e3ebdSchin 							if (p[*s] != c)
1497da2e3ebdSchin 								break;
1498da2e3ebdSchin 					}
1499da2e3ebdSchin 					else
1500da2e3ebdSchin 					{
1501da2e3ebdSchin 						for (i = 0; i < n; i++, s++)
1502da2e3ebdSchin 							if (*s != c)
1503da2e3ebdSchin 								break;
1504da2e3ebdSchin 					}
1505da2e3ebdSchin 					for (; i-- >= m; s--)
1506da2e3ebdSchin 						switch (follow(env, rex, cont, s))
1507da2e3ebdSchin 						{
1508da2e3ebdSchin 						case BAD:
1509da2e3ebdSchin 							return BAD;
1510da2e3ebdSchin 						case BEST:
1511da2e3ebdSchin 							return BEST;
1512da2e3ebdSchin 						case CUT:
1513da2e3ebdSchin 							return CUT;
1514da2e3ebdSchin 						case GOOD:
1515da2e3ebdSchin 							r = GOOD;
1516da2e3ebdSchin 							break;
1517da2e3ebdSchin 						}
1518da2e3ebdSchin 				}
1519da2e3ebdSchin 				else
1520da2e3ebdSchin 				{
1521da2e3ebdSchin 					if (!(b = (unsigned char*)stkpush(stkstd, n)))
1522da2e3ebdSchin 					{
1523da2e3ebdSchin 						env->error = REG_ESPACE;
1524da2e3ebdSchin 						return BAD;
1525da2e3ebdSchin 					}
1526da2e3ebdSchin 					e = env->end;
1527da2e3ebdSchin 					if (!(rex->flags & REG_ICASE))
1528da2e3ebdSchin 					{
1529da2e3ebdSchin 						for (i = 0; s < e && i < n; i++, s = t)
1530da2e3ebdSchin 						{
1531da2e3ebdSchin 							t = s;
1532da2e3ebdSchin 							if (mbchar(t) != c)
1533da2e3ebdSchin 								break;
1534da2e3ebdSchin 							b[i] = t - s;
1535da2e3ebdSchin 						}
1536da2e3ebdSchin 					}
1537da2e3ebdSchin 					else
1538da2e3ebdSchin 					{
1539da2e3ebdSchin 						for (i = 0; s < e && i < n; i++, s = t)
1540da2e3ebdSchin 						{
1541da2e3ebdSchin 							t = s;
1542da2e3ebdSchin 							if (towupper(mbchar(t)) != c)
1543da2e3ebdSchin 								break;
1544da2e3ebdSchin 							b[i] = t - s;
1545da2e3ebdSchin 						}
1546da2e3ebdSchin 					}
1547da2e3ebdSchin 					for (; i-- >= m; s -= b[i])
1548da2e3ebdSchin 						switch (follow(env, rex, cont, s))
1549da2e3ebdSchin 						{
1550da2e3ebdSchin 						case BAD:
1551da2e3ebdSchin 							stkpop(stkstd);
1552da2e3ebdSchin 							return BAD;
1553da2e3ebdSchin 						case BEST:
1554da2e3ebdSchin 							stkpop(stkstd);
1555da2e3ebdSchin 							return BEST;
1556da2e3ebdSchin 						case CUT:
1557da2e3ebdSchin 							stkpop(stkstd);
1558da2e3ebdSchin 							return CUT;
1559da2e3ebdSchin 						case GOOD:
1560da2e3ebdSchin 							r = GOOD;
1561da2e3ebdSchin 							break;
1562da2e3ebdSchin 						}
1563da2e3ebdSchin 					stkpop(stkstd);
1564da2e3ebdSchin 				}
1565da2e3ebdSchin 			}
1566da2e3ebdSchin 			else
1567da2e3ebdSchin 			{
1568da2e3ebdSchin 				if (!mbwide())
1569da2e3ebdSchin 				{
1570da2e3ebdSchin 					e = s + m;
1571da2e3ebdSchin 					if (p = rex->map)
1572da2e3ebdSchin 					{
1573da2e3ebdSchin 						for (; s < e; s++)
1574da2e3ebdSchin 							if (p[*s] != c)
1575da2e3ebdSchin 								return r;
1576da2e3ebdSchin 						e += n - m;
1577da2e3ebdSchin 						for (;;)
1578da2e3ebdSchin 						{
1579da2e3ebdSchin 							switch (follow(env, rex, cont, s))
1580da2e3ebdSchin 							{
1581da2e3ebdSchin 							case BAD:
1582da2e3ebdSchin 								return BAD;
1583da2e3ebdSchin 							case CUT:
1584da2e3ebdSchin 								return CUT;
1585da2e3ebdSchin 							case BEST:
1586da2e3ebdSchin 							case GOOD:
1587da2e3ebdSchin 								return BEST;
1588da2e3ebdSchin 							}
1589da2e3ebdSchin 							if (s >= e || p[*s++] != c)
1590da2e3ebdSchin 								break;
1591da2e3ebdSchin 						}
1592da2e3ebdSchin 					}
1593da2e3ebdSchin 					else
1594da2e3ebdSchin 					{
1595da2e3ebdSchin 						for (; s < e; s++)
1596da2e3ebdSchin 							if (*s != c)
1597da2e3ebdSchin 								return r;
1598da2e3ebdSchin 						e += n - m;
1599da2e3ebdSchin 						for (;;)
1600da2e3ebdSchin 						{
1601da2e3ebdSchin 							switch (follow(env, rex, cont, s))
1602da2e3ebdSchin 							{
1603da2e3ebdSchin 							case BAD:
1604da2e3ebdSchin 								return BAD;
1605da2e3ebdSchin 							case CUT:
1606da2e3ebdSchin 								return CUT;
1607da2e3ebdSchin 							case BEST:
1608da2e3ebdSchin 							case GOOD:
1609da2e3ebdSchin 								return BEST;
1610da2e3ebdSchin 							}
1611da2e3ebdSchin 							if (s >= e || *s++ != c)
1612da2e3ebdSchin 								break;
1613da2e3ebdSchin 						}
1614da2e3ebdSchin 					}
1615da2e3ebdSchin 				}
1616da2e3ebdSchin 				else
1617da2e3ebdSchin 				{
1618*b30d1939SAndy Fiddaman 					e = env->end;
1619da2e3ebdSchin 					if (!(rex->flags & REG_ICASE))
1620da2e3ebdSchin 					{
1621da2e3ebdSchin 						for (i = 0; i < m && s < e; i++, s = t)
1622da2e3ebdSchin 						{
1623da2e3ebdSchin 							t = s;
1624da2e3ebdSchin 							if (mbchar(t) != c)
1625da2e3ebdSchin 								return r;
1626da2e3ebdSchin 						}
1627da2e3ebdSchin 						while (i++ <= n)
1628da2e3ebdSchin 						{
1629da2e3ebdSchin 							switch (follow(env, rex, cont, s))
1630da2e3ebdSchin 							{
1631da2e3ebdSchin 							case BAD:
1632da2e3ebdSchin 								return BAD;
1633da2e3ebdSchin 							case CUT:
1634da2e3ebdSchin 								return CUT;
1635da2e3ebdSchin 							case BEST:
1636da2e3ebdSchin 							case GOOD:
1637da2e3ebdSchin 								return BEST;
1638da2e3ebdSchin 							}
1639da2e3ebdSchin 							if (s >= e || mbchar(s) != c)
1640da2e3ebdSchin 								break;
1641da2e3ebdSchin 						}
1642da2e3ebdSchin 					}
1643da2e3ebdSchin 					else
1644da2e3ebdSchin 					{
1645da2e3ebdSchin 						for (i = 0; i < m && s < e; i++, s = t)
1646da2e3ebdSchin 						{
1647da2e3ebdSchin 							t = s;
1648da2e3ebdSchin 							if (towupper(mbchar(t)) != c)
1649da2e3ebdSchin 								return r;
1650da2e3ebdSchin 						}
1651da2e3ebdSchin 						while (i++ <= n)
1652da2e3ebdSchin 						{
1653da2e3ebdSchin 							switch (follow(env, rex, cont, s))
1654da2e3ebdSchin 							{
1655da2e3ebdSchin 							case BAD:
1656da2e3ebdSchin 								return BAD;
1657da2e3ebdSchin 							case CUT:
1658da2e3ebdSchin 								return CUT;
1659da2e3ebdSchin 							case BEST:
1660da2e3ebdSchin 							case GOOD:
1661da2e3ebdSchin 								return BEST;
1662da2e3ebdSchin 							}
1663da2e3ebdSchin 							if (s >= e || towupper(mbchar(s)) != c)
1664da2e3ebdSchin 								break;
1665da2e3ebdSchin 						}
1666da2e3ebdSchin 					}
1667da2e3ebdSchin 				}
1668da2e3ebdSchin 			}
1669da2e3ebdSchin 			return r;
1670da2e3ebdSchin 		case REX_REP:
1671da2e3ebdSchin 			if (env->stack && pospush(env, rex, s, BEG_REP))
1672da2e3ebdSchin 				return BAD;
1673da2e3ebdSchin 			r = parserep(env, rex, cont, s, 0);
1674da2e3ebdSchin 			if (env->stack)
1675da2e3ebdSchin 				pospop(env);
1676da2e3ebdSchin 			return r;
1677da2e3ebdSchin 		case REX_REP_CATCH:
1678da2e3ebdSchin 			DEBUG_TEST(0x0020,(sfprintf(sfstdout, "AHA#%04d 0x%04x %s n %d len %d s `%-.*s'\n", __LINE__, debug_flag, rexname(rex), rex->re.rep_catch.n, s - rex->re.rep_catch.beg, env->end - s, s)),(0));
1679da2e3ebdSchin 			if (env->stack && pospush(env, rex, s, END_ANY))
1680da2e3ebdSchin 				return BAD;
1681da2e3ebdSchin 			if (s == rex->re.rep_catch.beg && rex->re.rep_catch.n > rex->re.rep_catch.ref->lo)
1682da2e3ebdSchin 			{
1683da2e3ebdSchin 				/*
1684da2e3ebdSchin 				 * optional empty iteration
1685da2e3ebdSchin 				 */
1686da2e3ebdSchin 
1687da2e3ebdSchin DEBUG_TEST(0x0002,(sfprintf(sfstdout, "AHA#%04d %p re.group.back=%d re.group.expr.rex=%s\n", __LINE__, rex->re.rep_catch.ref->re.group.expr.rex, rex->re.rep_catch.ref->re.group.expr.rex->re.group.back, rexname(rex->re.rep_catch.ref->re.group.expr.rex))),(0));
1688da2e3ebdSchin 				if (!env->stack || s != rex->re.rep_catch.ref->re.rep_catch.beg && !rex->re.rep_catch.ref->re.group.expr.rex->re.group.back)
1689da2e3ebdSchin 					r = NONE;
1690da2e3ebdSchin 				else if (pospush(env, rex, s, END_ANY))
1691da2e3ebdSchin 					r = BAD;
1692da2e3ebdSchin 				else
1693da2e3ebdSchin 				{
1694da2e3ebdSchin 					r = follow(env, rex, rex->re.rep_catch.cont, s);
1695da2e3ebdSchin 					pospop(env);
1696da2e3ebdSchin 				}
1697da2e3ebdSchin 			}
1698da2e3ebdSchin 			else
1699da2e3ebdSchin 				r = parserep(env, rex->re.rep_catch.ref, rex->re.rep_catch.cont, s, rex->re.rep_catch.n);
1700da2e3ebdSchin 			if (env->stack)
1701da2e3ebdSchin 				pospop(env);
1702da2e3ebdSchin 			return r;
1703da2e3ebdSchin 		case REX_STRING:
1704da2e3ebdSchin DEBUG_TEST(0x0200,(sfprintf(sfstdout,"AHA#%04d 0x%04x parse %s \"%-.*s\" `%-.*s'\n", __LINE__, debug_flag, rexname(rex), rex->re.string.size, rex->re.string.base, env->end - s, s)),(0));
1705da2e3ebdSchin 			if (rex->re.string.size > (env->end - s))
1706da2e3ebdSchin 				return NONE;
1707da2e3ebdSchin 			t = rex->re.string.base;
1708da2e3ebdSchin 			e = t + rex->re.string.size;
1709da2e3ebdSchin 			if (!(p = rex->map))
1710da2e3ebdSchin 			{
1711da2e3ebdSchin 				while (t < e)
1712da2e3ebdSchin 					if (*s++ != *t++)
1713da2e3ebdSchin 						return NONE;
1714da2e3ebdSchin 			}
1715da2e3ebdSchin 			else if (!mbwide())
1716da2e3ebdSchin 			{
1717da2e3ebdSchin 				while (t < e)
1718da2e3ebdSchin 					if (p[*s++] != *t++)
1719da2e3ebdSchin 						return NONE;
1720da2e3ebdSchin 			}
1721da2e3ebdSchin 			else
1722da2e3ebdSchin 			{
1723da2e3ebdSchin 				while (t < e)
1724da2e3ebdSchin 				{
1725da2e3ebdSchin 					c = mbchar(s);
1726da2e3ebdSchin 					d = mbchar(t);
1727da2e3ebdSchin 					if (towupper(c) != d)
1728da2e3ebdSchin 						return NONE;
1729da2e3ebdSchin 				}
1730da2e3ebdSchin 			}
1731da2e3ebdSchin 			break;
1732da2e3ebdSchin 		case REX_TRIE:
1733da2e3ebdSchin 			if (((s + rex->re.trie.min) > env->end) || !(x = rex->re.trie.root[rex->map ? rex->map[*s] : *s]))
1734da2e3ebdSchin 				return NONE;
1735da2e3ebdSchin 			return parsetrie(env, x, rex, cont, s);
1736da2e3ebdSchin 		case REX_EXEC:
1737da2e3ebdSchin 			u = 0;
1738da2e3ebdSchin 			r = (*env->disc->re_execf)(env->regex, rex->re.exec.data, rex->re.exec.text, rex->re.exec.size, (const char*)s, env->end - s, &u, env->disc);
1739da2e3ebdSchin 			e = (unsigned char*)u;
1740da2e3ebdSchin 			if (e >= s && e <= env->end)
1741da2e3ebdSchin 				s = e;
1742da2e3ebdSchin 			switch (r)
1743da2e3ebdSchin 			{
1744da2e3ebdSchin 			case 0:
1745da2e3ebdSchin 				break;
1746da2e3ebdSchin 			case REG_NOMATCH:
1747da2e3ebdSchin 				return NONE;
1748da2e3ebdSchin 			default:
1749da2e3ebdSchin 				env->error = r;
1750da2e3ebdSchin 				return BAD;
1751da2e3ebdSchin 			}
1752da2e3ebdSchin 			break;
1753da2e3ebdSchin 		case REX_WBEG:
1754da2e3ebdSchin 			if (!isword(*s) || s > env->beg && isword(*(s - 1)))
1755da2e3ebdSchin 				return NONE;
1756da2e3ebdSchin 			break;
1757da2e3ebdSchin 		case REX_WEND:
1758da2e3ebdSchin 			if (isword(*s) || s > env->beg && !isword(*(s - 1)))
1759da2e3ebdSchin 				return NONE;
1760da2e3ebdSchin 			break;
1761da2e3ebdSchin 		case REX_WORD:
1762da2e3ebdSchin 			if (s > env->beg && isword(*(s - 1)) == isword(*s))
1763da2e3ebdSchin 				return NONE;
1764da2e3ebdSchin 			break;
1765da2e3ebdSchin 		case REX_WORD_NOT:
1766da2e3ebdSchin 			if (s == env->beg || isword(*(s - 1)) != isword(*s))
1767da2e3ebdSchin 				return NONE;
1768da2e3ebdSchin 			break;
1769da2e3ebdSchin 		case REX_BEG_STR:
1770da2e3ebdSchin 			if (s != env->beg)
1771da2e3ebdSchin 				return NONE;
1772da2e3ebdSchin 			break;
1773da2e3ebdSchin 		case REX_END_STR:
1774da2e3ebdSchin 			for (t = s; t < env->end && *t == '\n'; t++);
1775da2e3ebdSchin 			if (t < env->end)
1776da2e3ebdSchin 				return NONE;
1777da2e3ebdSchin 			break;
1778da2e3ebdSchin 		case REX_FIN_STR:
1779da2e3ebdSchin 			if (s < env->end)
1780da2e3ebdSchin 				return NONE;
1781da2e3ebdSchin 			break;
1782da2e3ebdSchin 		}
1783da2e3ebdSchin 		if (!(rex = rex->next))
1784da2e3ebdSchin 		{
1785da2e3ebdSchin 			if (!(rex = cont))
1786da2e3ebdSchin 				break;
1787da2e3ebdSchin 			cont = 0;
1788da2e3ebdSchin 		}
1789da2e3ebdSchin 	}
1790da2e3ebdSchin 	return GOOD;
1791da2e3ebdSchin }
1792da2e3ebdSchin 
1793da2e3ebdSchin #if _AST_REGEX_DEBUG
1794da2e3ebdSchin 
1795da2e3ebdSchin static void
listnode(Rex_t * e,int level)1796da2e3ebdSchin listnode(Rex_t* e, int level)
1797da2e3ebdSchin {
1798da2e3ebdSchin 	int	i;
1799da2e3ebdSchin 
1800da2e3ebdSchin 	if (e)
1801da2e3ebdSchin 	{
1802da2e3ebdSchin 		do
1803da2e3ebdSchin 		{
1804da2e3ebdSchin 			for (i = 0; i < level; i++)
1805da2e3ebdSchin 				sfprintf(sfstderr, "  ");
1806da2e3ebdSchin 			sfprintf(sfstderr, "%s\n", rexname(e));
1807da2e3ebdSchin 			switch (e->type)
1808da2e3ebdSchin 			{
1809da2e3ebdSchin 			case REX_ALT:
1810da2e3ebdSchin 			case REX_CONJ:
1811da2e3ebdSchin 				listnode(e->re.group.expr.binary.left, level + 1);
1812da2e3ebdSchin 				listnode(e->re.group.expr.binary.right, level + 1);
1813da2e3ebdSchin 				break;
1814da2e3ebdSchin 			case REX_GROUP:
1815da2e3ebdSchin 			case REX_GROUP_AHEAD:
1816da2e3ebdSchin 			case REX_GROUP_AHEAD_NOT:
1817da2e3ebdSchin 			case REX_GROUP_BEHIND:
1818da2e3ebdSchin 			case REX_GROUP_BEHIND_NOT:
1819da2e3ebdSchin 			case REX_GROUP_CUT:
1820da2e3ebdSchin 			case REX_NEG:
1821da2e3ebdSchin 			case REX_REP:
1822da2e3ebdSchin 				listnode(e->re.group.expr.rex, level + 1);
1823da2e3ebdSchin 				break;
1824da2e3ebdSchin 			}
1825da2e3ebdSchin 		} while (e = e->next);
1826da2e3ebdSchin 	}
1827da2e3ebdSchin }
1828da2e3ebdSchin 
1829da2e3ebdSchin static int
list(Env_t * env,Rex_t * rex)1830da2e3ebdSchin list(Env_t* env, Rex_t* rex)
1831da2e3ebdSchin {
1832da2e3ebdSchin 	sfprintf(sfstderr, "AHA regex hard=%d stack=%p\n", env->hard, env->stack);
1833da2e3ebdSchin 	if (rex)
1834da2e3ebdSchin 		listnode(rex, 1);
1835da2e3ebdSchin 	return 0;
1836da2e3ebdSchin }
1837da2e3ebdSchin 
1838da2e3ebdSchin #endif
1839da2e3ebdSchin 
1840da2e3ebdSchin /*
1841da2e3ebdSchin  * returning REG_BADPAT or REG_ESPACE is not explicitly
1842da2e3ebdSchin  * countenanced by the standard
1843da2e3ebdSchin  */
1844da2e3ebdSchin 
1845da2e3ebdSchin int
regnexec(const regex_t * p,const char * s,size_t len,size_t nmatch,regmatch_t * match,regflags_t flags)1846da2e3ebdSchin regnexec(const regex_t* p, const char* s, size_t len, size_t nmatch, regmatch_t* match, regflags_t flags)
1847da2e3ebdSchin {
1848*b30d1939SAndy Fiddaman 	register ssize_t	n;
1849*b30d1939SAndy Fiddaman 	register int		i;
1850*b30d1939SAndy Fiddaman 	int			j;
1851*b30d1939SAndy Fiddaman 	int			k;
1852*b30d1939SAndy Fiddaman 	int			m;
1853*b30d1939SAndy Fiddaman 	int			advance;
1854*b30d1939SAndy Fiddaman 	Env_t*			env;
1855*b30d1939SAndy Fiddaman 	Rex_t*			e;
1856da2e3ebdSchin 
1857da2e3ebdSchin 	DEBUG_INIT();
1858da2e3ebdSchin 	DEBUG_TEST(0x0001,(sfprintf(sfstdout, "AHA#%04d 0x%04x regnexec %d 0x%08x `%-.*s'\n", __LINE__, debug_flag, nmatch, flags, len, s)),(0));
1859da2e3ebdSchin 	if (!p || !(env = p->env))
1860da2e3ebdSchin 		return REG_BADPAT;
1861da2e3ebdSchin 	if (!s)
1862da2e3ebdSchin 		return fatal(env->disc, REG_BADPAT, NiL);
1863da2e3ebdSchin 	if (len < env->min)
1864da2e3ebdSchin 	{
1865da2e3ebdSchin 		DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d REG_NOMATCH %d %d\n", __LINE__, len, env->min)),(0));
1866da2e3ebdSchin 		return REG_NOMATCH;
1867da2e3ebdSchin 	}
1868da2e3ebdSchin 	env->regex = p;
1869da2e3ebdSchin 	env->beg = (unsigned char*)s;
1870da2e3ebdSchin 	env->end = env->beg + len;
1871da2e3ebdSchin 	stknew(stkstd, &env->stk);
1872da2e3ebdSchin 	env->flags &= ~REG_EXEC;
1873da2e3ebdSchin 	env->flags |= (flags & REG_EXEC);
1874da2e3ebdSchin 	advance = 0;
1875da2e3ebdSchin 	if (env->stack = env->hard || !(env->flags & REG_NOSUB) && nmatch)
1876da2e3ebdSchin 	{
1877da2e3ebdSchin 		n = env->nsub;
1878da2e3ebdSchin 		if (!(env->match = (regmatch_t*)stkpush(stkstd, 2 * (n + 1) * sizeof(regmatch_t))) ||
1879da2e3ebdSchin 		    !env->pos && !(env->pos = vecopen(16, sizeof(Pos_t))) ||
1880da2e3ebdSchin 		    !env->bestpos && !(env->bestpos = vecopen(16, sizeof(Pos_t))))
1881da2e3ebdSchin 		{
1882da2e3ebdSchin 			k = REG_ESPACE;
1883da2e3ebdSchin 			goto done;
1884da2e3ebdSchin 		}
1885da2e3ebdSchin 		env->pos->cur = env->bestpos->cur = 0;
1886da2e3ebdSchin 		env->best = &env->match[n + 1];
1887da2e3ebdSchin 		env->best[0].rm_so = 0;
1888da2e3ebdSchin 		env->best[0].rm_eo = -1;
1889da2e3ebdSchin 		for (i = 0; i <= n; i++)
1890da2e3ebdSchin 			env->match[i] = state.nomatch;
1891da2e3ebdSchin 		if (flags & REG_ADVANCE)
1892da2e3ebdSchin 			advance = 1;
1893da2e3ebdSchin 	}
1894da2e3ebdSchin 	DEBUG_TEST(0x1000,(list(env,env->rex)),(0));
1895da2e3ebdSchin 	k = REG_NOMATCH;
1896da2e3ebdSchin 	if ((e = env->rex)->type == REX_BM)
1897da2e3ebdSchin 	{
1898da2e3ebdSchin 		DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d REX_BM\n", __LINE__)),(0));
1899da2e3ebdSchin 		if (len < e->re.bm.right)
1900da2e3ebdSchin 		{
1901da2e3ebdSchin 			DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d REG_NOMATCH %d %d\n", __LINE__, len, e->re.bm.right)),(0));
1902da2e3ebdSchin 			goto done;
1903da2e3ebdSchin 		}
1904da2e3ebdSchin 		else if (!(flags & REG_LEFT))
1905da2e3ebdSchin 		{
1906da2e3ebdSchin 			register unsigned char*	buf = (unsigned char*)s;
1907da2e3ebdSchin 			register size_t		index = e->re.bm.left + e->re.bm.size;
1908da2e3ebdSchin 			register size_t		mid = len - e->re.bm.right;
1909da2e3ebdSchin 			register size_t*	skip = e->re.bm.skip;
1910da2e3ebdSchin 			register size_t*	fail = e->re.bm.fail;
1911da2e3ebdSchin 			register Bm_mask_t**	mask = e->re.bm.mask;
1912da2e3ebdSchin 			Bm_mask_t		m;
1913da2e3ebdSchin 			size_t			x;
1914da2e3ebdSchin 
1915da2e3ebdSchin 			DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d REX_BM len=%d right=%d left=%d size=%d %d %d\n", __LINE__, len, e->re.bm.right, e->re.bm.left, e->re.bm.size, index, mid)),(0));
1916da2e3ebdSchin 			for (;;)
1917da2e3ebdSchin 			{
1918da2e3ebdSchin 				while ((index += skip[buf[index]]) < mid);
1919da2e3ebdSchin 				if (index < HIT)
1920da2e3ebdSchin 				{
1921da2e3ebdSchin 					DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d REG_NOMATCH %d %d\n", __LINE__, index, HIT)),(0));
1922da2e3ebdSchin 					goto done;
1923da2e3ebdSchin 				}
1924da2e3ebdSchin 				index -= HIT;
1925da2e3ebdSchin 				m = mask[n = e->re.bm.size - 1][buf[index]];
1926da2e3ebdSchin 				do
1927da2e3ebdSchin 				{
1928da2e3ebdSchin 					if (!n--)
1929da2e3ebdSchin 					{
1930da2e3ebdSchin 						if (e->re.bm.back < 0)
1931da2e3ebdSchin 							goto possible;
1932da2e3ebdSchin 						if (advance)
1933da2e3ebdSchin 						{
1934da2e3ebdSchin 							i = index - e->re.bm.back;
1935da2e3ebdSchin 							s += i;
1936da2e3ebdSchin 							if (env->stack)
1937da2e3ebdSchin 								env->best[0].rm_so += i;
1938da2e3ebdSchin 							goto possible;
1939da2e3ebdSchin 						}
1940da2e3ebdSchin 						x = index;
1941da2e3ebdSchin 						if (index < e->re.bm.back)
1942da2e3ebdSchin 							index = 0;
1943da2e3ebdSchin 						else
1944da2e3ebdSchin 							index -= e->re.bm.back;
1945da2e3ebdSchin 						while (index <= x)
1946da2e3ebdSchin 						{
1947da2e3ebdSchin 							if ((i = parse(env, e->next, &env->done, buf + index)) != NONE)
1948da2e3ebdSchin 							{
1949da2e3ebdSchin 								if (env->stack)
1950da2e3ebdSchin 									env->best[0].rm_so = index;
1951da2e3ebdSchin 								n = env->nsub;
1952da2e3ebdSchin 								goto hit;
1953da2e3ebdSchin 							}
1954da2e3ebdSchin 							index++;
1955da2e3ebdSchin 						}
1956da2e3ebdSchin 						index += e->re.bm.size;
1957da2e3ebdSchin 						break;
1958da2e3ebdSchin 					}
1959da2e3ebdSchin 				} while (m &= mask[n][buf[--index]]);
1960da2e3ebdSchin 				if ((index += fail[n + 1]) >= len)
1961da2e3ebdSchin 					goto done;
1962da2e3ebdSchin 			}
1963da2e3ebdSchin 		}
1964da2e3ebdSchin  possible:
1965da2e3ebdSchin 		n = env->nsub;
1966da2e3ebdSchin 		e = e->next;
1967da2e3ebdSchin 	}
1968da2e3ebdSchin 	j = env->once || (flags & REG_LEFT);
1969da2e3ebdSchin 	DEBUG_TEST(0x0080,(sfprintf(sfstdout, "AHA#%04d parse once=%d\n", __LINE__, j)),(0));
1970da2e3ebdSchin 	while ((i = parse(env, e, &env->done, (unsigned char*)s)) == NONE || advance && !env->best[0].rm_eo && !(advance = 0))
1971da2e3ebdSchin 	{
1972da2e3ebdSchin 		if (j)
1973da2e3ebdSchin 			goto done;
1974da2e3ebdSchin 		i = MBSIZE(s);
1975da2e3ebdSchin 		s += i;
1976da2e3ebdSchin 		if ((unsigned char*)s > env->end - env->min)
1977da2e3ebdSchin 			goto done;
1978da2e3ebdSchin 		if (env->stack)
1979da2e3ebdSchin 			env->best[0].rm_so += i;
1980da2e3ebdSchin 	}
1981da2e3ebdSchin 	if ((flags & REG_LEFT) && env->stack && env->best[0].rm_so)
1982da2e3ebdSchin 		goto done;
1983da2e3ebdSchin  hit:
1984da2e3ebdSchin 	if (k = env->error)
1985da2e3ebdSchin 		goto done;
1986da2e3ebdSchin 	if (i == CUT)
1987da2e3ebdSchin 	{
1988da2e3ebdSchin 		k = env->error = REG_NOMATCH;
1989da2e3ebdSchin 		goto done;
1990da2e3ebdSchin 	}
1991da2e3ebdSchin 	if (!(env->flags & REG_NOSUB))
1992da2e3ebdSchin 	{
1993da2e3ebdSchin 		k = (env->flags & (REG_SHELL|REG_AUGMENTED)) == (REG_SHELL|REG_AUGMENTED);
1994da2e3ebdSchin 		for (i = j = m = 0; j < nmatch; i++)
1995da2e3ebdSchin 			if (!i || !k || (i & 1))
1996da2e3ebdSchin 			{
1997da2e3ebdSchin 				if (i > n)
1998da2e3ebdSchin 					match[j] = state.nomatch;
1999da2e3ebdSchin 				else
2000da2e3ebdSchin 					match[m = j] = env->best[i];
2001da2e3ebdSchin 				j++;
2002da2e3ebdSchin 			}
2003da2e3ebdSchin 		if (k)
2004da2e3ebdSchin 		{
2005da2e3ebdSchin 			while (m > 0 && match[m].rm_so == -1 && match[m].rm_eo == -1)
2006da2e3ebdSchin 				m--;
2007da2e3ebdSchin 			((regex_t*)p)->re_nsub = m;
2008da2e3ebdSchin 		}
2009da2e3ebdSchin 	}
2010da2e3ebdSchin 	k = 0;
2011da2e3ebdSchin  done:
2012da2e3ebdSchin 	stkold(stkstd, &env->stk);
2013da2e3ebdSchin 	env->stk.base = 0;
2014da2e3ebdSchin 	if (k > REG_NOMATCH)
2015da2e3ebdSchin 		fatal(p->env->disc, k, NiL);
2016da2e3ebdSchin 	return k;
2017da2e3ebdSchin }
2018da2e3ebdSchin 
2019da2e3ebdSchin void
regfree(regex_t * p)2020da2e3ebdSchin regfree(regex_t* p)
2021da2e3ebdSchin {
2022da2e3ebdSchin 	Env_t*	env;
2023da2e3ebdSchin 
2024da2e3ebdSchin 	if (p && (env = p->env))
2025da2e3ebdSchin 	{
2026da2e3ebdSchin #if _REG_subcomp
2027da2e3ebdSchin 		if (env->sub)
2028da2e3ebdSchin 		{
2029da2e3ebdSchin 			regsubfree(p);
2030da2e3ebdSchin 			p->re_sub = 0;
2031da2e3ebdSchin 		}
2032da2e3ebdSchin #endif
2033da2e3ebdSchin 		p->env = 0;
2034da2e3ebdSchin 		if (--env->refs <= 0 && !(env->disc->re_flags & REG_NOFREE))
2035da2e3ebdSchin 		{
2036da2e3ebdSchin 			drop(env->disc, env->rex);
2037da2e3ebdSchin 			if (env->pos)
2038da2e3ebdSchin 				vecclose(env->pos);
2039da2e3ebdSchin 			if (env->bestpos)
2040da2e3ebdSchin 				vecclose(env->bestpos);
2041da2e3ebdSchin 			if (env->stk.base)
2042da2e3ebdSchin 				stkold(stkstd, &env->stk);
2043da2e3ebdSchin 			alloc(env->disc, env, 0);
2044da2e3ebdSchin 		}
2045da2e3ebdSchin 	}
2046da2e3ebdSchin }
2047*b30d1939SAndy Fiddaman 
2048*b30d1939SAndy Fiddaman /*
2049*b30d1939SAndy Fiddaman  * 20120528: regoff_t changed from int to ssize_t
2050*b30d1939SAndy Fiddaman  */
2051*b30d1939SAndy Fiddaman 
2052*b30d1939SAndy Fiddaman #if defined(__EXPORT__)
2053*b30d1939SAndy Fiddaman #define extern		__EXPORT__
2054*b30d1939SAndy Fiddaman #endif
2055*b30d1939SAndy Fiddaman 
2056*b30d1939SAndy Fiddaman #undef	regnexec
2057*b30d1939SAndy Fiddaman #if _map_libc
2058*b30d1939SAndy Fiddaman #define regnexec	_ast_regnexec
2059*b30d1939SAndy Fiddaman #endif
2060*b30d1939SAndy Fiddaman 
2061*b30d1939SAndy Fiddaman extern int
regnexec(const regex_t * p,const char * s,size_t len,size_t nmatch,oldregmatch_t * oldmatch,regflags_t flags)2062*b30d1939SAndy Fiddaman regnexec(const regex_t* p, const char* s, size_t len, size_t nmatch, oldregmatch_t* oldmatch, regflags_t flags)
2063*b30d1939SAndy Fiddaman {
2064*b30d1939SAndy Fiddaman 	if (oldmatch)
2065*b30d1939SAndy Fiddaman 	{
2066*b30d1939SAndy Fiddaman 		regmatch_t*	match;
2067*b30d1939SAndy Fiddaman 		ssize_t		i;
2068*b30d1939SAndy Fiddaman 		int		r;
2069*b30d1939SAndy Fiddaman 
2070*b30d1939SAndy Fiddaman 		if (!(match = oldof(0, regmatch_t, nmatch, 0)))
2071*b30d1939SAndy Fiddaman 			return -1;
2072*b30d1939SAndy Fiddaman 		if (!(r = regnexec_20120528(p, s, len, nmatch, match, flags)))
2073*b30d1939SAndy Fiddaman 			for (i = 0; i < nmatch; i++)
2074*b30d1939SAndy Fiddaman 			{
2075*b30d1939SAndy Fiddaman 				oldmatch[i].rm_so = match[i].rm_so;
2076*b30d1939SAndy Fiddaman 				oldmatch[i].rm_eo = match[i].rm_eo;
2077*b30d1939SAndy Fiddaman 			}
2078*b30d1939SAndy Fiddaman 		free(match);
2079*b30d1939SAndy Fiddaman 		return r;
2080*b30d1939SAndy Fiddaman 	}
2081*b30d1939SAndy Fiddaman 	return regnexec_20120528(p, s, len, 0, NiL, flags);
2082*b30d1939SAndy Fiddaman }
2083