Blame src/lib/libast/regex/regcomp.c

Packit 992a25
/***********************************************************************
Packit 992a25
*                                                                      *
Packit 992a25
*               This software is part of the ast package               *
Packit 992a25
*          Copyright (c) 1985-2012 AT&T Intellectual Property          *
Packit 992a25
*                      and is licensed under the                       *
Packit 992a25
*                 Eclipse Public License, Version 1.0                  *
Packit 992a25
*                    by AT&T Intellectual Property                     *
Packit 992a25
*                                                                      *
Packit 992a25
*                A copy of the License is available at                 *
Packit 992a25
*          http://www.eclipse.org/org/documents/epl-v10.html           *
Packit 992a25
*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
Packit 992a25
*                                                                      *
Packit 992a25
*              Information and Software Systems Research               *
Packit 992a25
*                            AT&T Research                             *
Packit 992a25
*                           Florham Park NJ                            *
Packit 992a25
*                                                                      *
Packit 992a25
*                 Glenn Fowler <gsf@research.att.com>                  *
Packit 992a25
*                  David Korn <dgk@research.att.com>                   *
Packit 992a25
*                   Phong Vo <kpv@research.att.com>                    *
Packit 992a25
*                                                                      *
Packit 992a25
***********************************************************************/
Packit 992a25
#pragma prototyped
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * posix regex compiler
Packit 992a25
 */
Packit 992a25
Packit 992a25
#include "reglib.h"
Packit 992a25
Packit 992a25
#if _PACKAGE_ast
Packit 992a25
#include "lclib.h"
Packit 992a25
#endif
Packit 992a25
Packit 992a25
#define serialize		re_serialize	/* hp.ia64 <unistd.h>! */
Packit 992a25
Packit 992a25
#define C_ESC			(-1)
Packit 992a25
#define C_MB			(-2)
Packit 992a25
Packit 992a25
#if _AST_REGEX_DEBUG
Packit 992a25
Packit 992a25
#define DEBUG_TEST(f,y,n)	((debug&(debug_flag=f))?(y):(n))
Packit 992a25
#define DEBUG_CODE(f,y,n)	do if(debug&(f)){y}else{n} while(0)
Packit 992a25
#define DEBUG_INIT()		do { char* t; if (!debug) { debug = 0x80000000; if (t = getenv("_AST_regex_comp_debug")) debug |= strtoul(t, NiL, 0); } } while (0)
Packit 992a25
Packit 992a25
static unsigned long	debug;
Packit 992a25
static unsigned long	debug_flag;
Packit 992a25
Packit 992a25
#else
Packit 992a25
Packit 992a25
#define DEBUG_INIT()
Packit 992a25
#define DEBUG_TEST(f,y,n)	(n)
Packit 992a25
#define DEBUG_CODE(f,y,n)	do {n} while(0)
Packit 992a25
Packit 992a25
#endif
Packit 992a25
Packit 992a25
#if _PACKAGE_ast
Packit 992a25
Packit 992a25
typedef struct Cchr_s
Packit 992a25
{
Packit 992a25
	Dtlink_t	lnk;
Packit 992a25
	unsigned char	nam[2];
Packit 992a25
	Ckey_t		key;
Packit 992a25
} Cchr_t;
Packit 992a25
Packit 992a25
#endif
Packit 992a25
Packit 992a25
#define eat(p)		do{if ((p)->token.push)(p)->token.push=0;else (p)->cursor+=(p)->token.len;}while (0)
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * determine whether greedy matching will work, i.e. produce
Packit 992a25
 * the best match first.  such expressions are "easy", and
Packit 992a25
 * need no backtracking once a complete match is found.  
Packit 992a25
 * if an expression has backreferences or alts it's hard
Packit 992a25
 * else if it has only one closure it's easy
Packit 992a25
 * else if all closures are simple (i.e. one-character) it's easy
Packit 992a25
 * else it's hard.
Packit 992a25
 */
Packit 992a25
Packit 992a25
typedef struct Stats_s
Packit 992a25
{
Packit 992a25
	unsigned long	l;	/* min length to left of x		*/
Packit 992a25
	unsigned long	k;	/* min length to left of y		*/
Packit 992a25
	unsigned long	m;	/* min length				*/
Packit 992a25
	unsigned long	n;	/* max length				*/
Packit 992a25
	unsigned short	a;	/* number of alternations		*/
Packit 992a25
	unsigned short	b;	/* number of backrefs			*/
Packit 992a25
	unsigned short	c;	/* number of closures			*/
Packit 992a25
	unsigned short	e;	/* $					*/
Packit 992a25
	unsigned short	i;	/* number of negations			*/
Packit 992a25
	unsigned short	p;	/* number of named subexpressions	*/
Packit 992a25
	unsigned short	s;	/* number of simple closures		*/
Packit 992a25
	unsigned short	t;	/* number of tries			*/
Packit 992a25
	unsigned short	u;	/* number of unnamed subexpressions	*/
Packit 992a25
	Rex_t*		x;	/* max length REX_STRING		*/
Packit 992a25
	Rex_t*		y;	/* max length REX_TRIE			*/
Packit 992a25
} Stats_t;
Packit 992a25
Packit 992a25
typedef struct Token_s
Packit 992a25
{
Packit 992a25
	unsigned long	min;
Packit 992a25
	unsigned long	max;
Packit 992a25
	short		lex;
Packit 992a25
	short		len;
Packit 992a25
	short		esc;
Packit 992a25
	short		att;
Packit 992a25
	short		push;
Packit 992a25
} Token_t;
Packit 992a25
Packit 992a25
typedef struct Cenv_s
Packit 992a25
{
Packit 992a25
	int		delimiter;	/* pattern delimiter		*/
Packit 992a25
	int		error;		/* last error			*/
Packit 992a25
	int		explicit;	/* explicit match on this char	*/
Packit 992a25
	int		mappeddot;	/* inverse mapped '.'		*/
Packit 992a25
	int		mappednewline;	/* inverse mapped '\n'		*/
Packit 992a25
	int		mappedslash;	/* inverse mapped '/'		*/
Packit 992a25
	regflags_t	flags;		/* flags arg to regcomp		*/
Packit 992a25
	int		type;		/* BRE,ERE,ARE,SRE,KRE		*/
Packit 992a25
	unsigned char*	cursor;		/* curent point in re		*/
Packit 992a25
	unsigned char*	pattern;	/* the original pattern		*/
Packit 992a25
	unsigned char*	literal;	/* literal restart pattern	*/
Packit 992a25
	int		parno;		/* number of last open paren	*/
Packit 992a25
	int		parnest;	/* paren nest count		*/
Packit 992a25
	int		posixkludge; 	/* to make * nonspecial		*/
Packit 992a25
	Token_t		token;		/* token lookahead		*/
Packit 992a25
	Stats_t		stats;		/* RE statistics		*/
Packit 992a25
	int		terminator;	/* pattern terminator		*/
Packit 992a25
	Rex_t*		paren[2*(BACK_REF_MAX+2)];
Packit 992a25
					/* paren[i]!=0 if \i defined	*/
Packit 992a25
	regex_t*	regex;		/* user handle			*/
Packit 992a25
	regdisc_t*	disc;		/* user discipline		*/
Packit 992a25
	unsigned char*	map;		/* external to native ccode map	*/
Packit 992a25
	unsigned char*	MAP;		/* fold and/or map		*/
Packit 992a25
} Cenv_t;
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * allocate a new Rex_t node
Packit 992a25
 */
Packit 992a25
Packit 992a25
#if _BLD_DEBUG
Packit 992a25
#define node(a,b,c,d,e)	node(a,b,c,d,e, const char* file, unsigned int line)
Packit 992a25
#endif
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
node(Cenv_t* env, int type, int lo, int hi, size_t extra)
Packit 992a25
{
Packit 992a25
	register Rex_t*	e;
Packit 992a25
Packit 992a25
	DEBUG_TEST(0x0800,(sfprintf(sfstdout, "%s:%d node(%d,%d,%d,%u)\n", file, line, type, lo, hi, sizeof(Rex_t) + extra)),(0));
Packit 992a25
	if (e = (Rex_t*)alloc(env->disc, 0, sizeof(Rex_t) + extra))
Packit 992a25
	{
Packit 992a25
		memset(e, 0, sizeof(Rex_t) + extra);
Packit 992a25
		e->type = type;
Packit 992a25
		e->marked = 0;
Packit 992a25
		e->lo = lo;
Packit 992a25
		e->hi = hi;
Packit 992a25
		e->flags = env->flags;
Packit 992a25
		e->map = (e->flags & REG_ICASE) ? env->MAP : env->map;
Packit 992a25
		e->explicit = env->explicit;
Packit 992a25
		if (extra)
Packit 992a25
			e->re.data = (char*)e + sizeof(Rex_t);
Packit 992a25
	}
Packit 992a25
	return e;
Packit 992a25
}
Packit 992a25
Packit 992a25
#if _BLD_DEBUG
Packit 992a25
#undef	node
Packit 992a25
#define node(a,b,c,d,e)	node(a,b,c,d,e,__FILE__,__LINE__)
Packit 992a25
#endif
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * free a Trie_node_t node
Packit 992a25
 */
Packit 992a25
Packit 992a25
static void
Packit 992a25
triedrop(regdisc_t* disc, Trie_node_t* e)
Packit 992a25
{
Packit 992a25
	if (e)
Packit 992a25
	{
Packit 992a25
		triedrop(disc, e->son);
Packit 992a25
		triedrop(disc, e->sib);
Packit 992a25
		alloc(disc, e, 0);
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * free a Rex_t node
Packit 992a25
 */
Packit 992a25
Packit 992a25
void
Packit 992a25
drop(regdisc_t* disc, Rex_t* e)
Packit 992a25
{
Packit 992a25
	int	i;
Packit 992a25
	Rex_t*	x;
Packit 992a25
Packit 992a25
	if (e && !(disc->re_flags & REG_NOFREE))
Packit 992a25
		do
Packit 992a25
		{
Packit 992a25
			switch (e->type)
Packit 992a25
			{
Packit 992a25
			case REX_ALT:
Packit 992a25
			case REX_CONJ:
Packit 992a25
				drop(disc, e->re.group.expr.binary.left);
Packit 992a25
				drop(disc, e->re.group.expr.binary.right);
Packit 992a25
				break;
Packit 992a25
			case REX_GROUP:
Packit 992a25
			case REX_GROUP_AHEAD:
Packit 992a25
			case REX_GROUP_AHEAD_NOT:
Packit 992a25
			case REX_GROUP_BEHIND:
Packit 992a25
			case REX_GROUP_BEHIND_NOT:
Packit 992a25
			case REX_GROUP_CUT:
Packit 992a25
			case REX_NEG:
Packit 992a25
			case REX_REP:
Packit 992a25
				drop(disc, e->re.group.expr.rex);
Packit 992a25
				break;
Packit 992a25
			case REX_TRIE:
Packit 992a25
				for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
					triedrop(disc, e->re.trie.root[i]);
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			x = e->next;
Packit 992a25
			alloc(disc, e, 0);
Packit 992a25
		} while (e = x);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * mark e and descendants minimal
Packit 992a25
 */
Packit 992a25
Packit 992a25
static void
Packit 992a25
mark(register Rex_t* e, int set)
Packit 992a25
{
Packit 992a25
	if (e && !e->marked)
Packit 992a25
		do
Packit 992a25
		{
Packit 992a25
			e->marked = 1;
Packit 992a25
			if (set)
Packit 992a25
				e->flags |= REG_MINIMAL;
Packit 992a25
			else
Packit 992a25
				e->flags &= ~REG_MINIMAL;
Packit 992a25
			switch (e->type)
Packit 992a25
			{
Packit 992a25
			case REX_ALT:
Packit 992a25
			case REX_CONJ:
Packit 992a25
			case REX_GROUP_COND:
Packit 992a25
				if (e->re.group.expr.binary.left)
Packit 992a25
					mark(e->re.group.expr.binary.left, set);
Packit 992a25
				if (e->re.group.expr.binary.right)
Packit 992a25
					mark(e->re.group.expr.binary.right, set);
Packit 992a25
				break;
Packit 992a25
			case REX_GROUP:
Packit 992a25
			case REX_GROUP_AHEAD:
Packit 992a25
			case REX_GROUP_AHEAD_NOT:
Packit 992a25
			case REX_GROUP_BEHIND:
Packit 992a25
			case REX_GROUP_BEHIND_NOT:
Packit 992a25
			case REX_GROUP_CUT:
Packit 992a25
			case REX_NEG:
Packit 992a25
			case REX_REP:
Packit 992a25
			case REX_TRIE:
Packit 992a25
				mark(e->re.group.expr.rex, set);
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
		} while (e = e->next);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * assign subexpression numbers by a preorder tree walk
Packit 992a25
 */
Packit 992a25
Packit 992a25
static int
Packit 992a25
serialize(Cenv_t* env, Rex_t* e, int n)
Packit 992a25
{
Packit 992a25
	do
Packit 992a25
	{
Packit 992a25
		e->serial = n++;
Packit 992a25
		switch (e->type)
Packit 992a25
		{
Packit 992a25
		case REX_ALT:
Packit 992a25
		case REX_GROUP_COND:
Packit 992a25
			if (e->re.group.expr.binary.left)
Packit 992a25
				n = serialize(env, e->re.group.expr.binary.left, n);
Packit 992a25
			e->re.group.expr.binary.serial = n++;
Packit 992a25
			if (e->re.group.expr.binary.right)
Packit 992a25
				n = serialize(env, e->re.group.expr.binary.right, n);
Packit 992a25
			break;
Packit 992a25
		case REX_CONJ:
Packit 992a25
			n = serialize(env, e->re.group.expr.binary.left, n);
Packit 992a25
			n = serialize(env, e->re.group.expr.binary.right, n);
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP:
Packit 992a25
		case REX_GROUP_AHEAD:
Packit 992a25
		case REX_GROUP_AHEAD_NOT:
Packit 992a25
		case REX_GROUP_BEHIND:
Packit 992a25
		case REX_GROUP_BEHIND_NOT:
Packit 992a25
		case REX_GROUP_CUT:
Packit 992a25
		case REX_NEG:
Packit 992a25
		case REX_REP:
Packit 992a25
			n = serialize(env, e->re.group.expr.rex, n);
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
	} while (e = e->next);
Packit 992a25
	return n;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * catenate e and f into a sequence, collapsing them if possible
Packit 992a25
 */
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
cat(Cenv_t* env, Rex_t* e, Rex_t* f)
Packit 992a25
{
Packit 992a25
	Rex_t*	g;
Packit 992a25
Packit 992a25
	if (!f)
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	if (e->type == REX_NULL)
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		return f;
Packit 992a25
	}
Packit 992a25
	if (f->type == REX_NULL)
Packit 992a25
	{
Packit 992a25
		g = f->next;
Packit 992a25
		f->next = 0;
Packit 992a25
		drop(env->disc, f);
Packit 992a25
		f = g;
Packit 992a25
	}
Packit 992a25
	else if (e->type == REX_DOT && f->type == REX_DOT)
Packit 992a25
	{
Packit 992a25
		unsigned int	m = e->lo + f->lo;
Packit 992a25
		unsigned int	n = e->hi + f->hi;
Packit 992a25
Packit 992a25
		if (m <= RE_DUP_MAX)
Packit 992a25
		{
Packit 992a25
			if (e->hi > RE_DUP_MAX || f->hi > RE_DUP_MAX)
Packit 992a25
			{
Packit 992a25
				n = RE_DUP_INF;	
Packit 992a25
				goto combine;
Packit 992a25
			}
Packit 992a25
			else if (n <= RE_DUP_MAX)
Packit 992a25
			{
Packit 992a25
			combine:
Packit 992a25
				e->lo = m;
Packit 992a25
				e->hi = n;
Packit 992a25
				g = f->next;
Packit 992a25
				f->next = 0;
Packit 992a25
				drop(env->disc, f);
Packit 992a25
				f = g;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	e->next = f;
Packit 992a25
	return e;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * collect re statistics
Packit 992a25
 */
Packit 992a25
Packit 992a25
static int
Packit 992a25
stats(register Cenv_t* env, register Rex_t* e)
Packit 992a25
{
Packit 992a25
	register unsigned long	n;
Packit 992a25
	register unsigned long	m;
Packit 992a25
	unsigned long		cm;
Packit 992a25
	unsigned long		nm;
Packit 992a25
	unsigned long		cn;
Packit 992a25
	unsigned long		nn;
Packit 992a25
	unsigned long		l;
Packit 992a25
	unsigned long		k;
Packit 992a25
	unsigned long		t;
Packit 992a25
	Rex_t*			q;
Packit 992a25
	Rex_t*			x;
Packit 992a25
	Rex_t*			y;
Packit 992a25
	unsigned char		c;
Packit 992a25
	unsigned char		b;
Packit 992a25
Packit 992a25
	do
Packit 992a25
	{
Packit 992a25
		switch (e->type)
Packit 992a25
		{
Packit 992a25
		case REX_ALT:
Packit 992a25
			x = env->stats.x;
Packit 992a25
			l = env->stats.l;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			k = env->stats.k;
Packit 992a25
			t = env->stats.t;
Packit 992a25
			if (++env->stats.a <= 0)
Packit 992a25
				return 1;
Packit 992a25
			cm = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			cn = env->stats.n;
Packit 992a25
			env->stats.n = 0;
Packit 992a25
			if (stats(env, e->re.group.expr.binary.left))
Packit 992a25
				return 1;
Packit 992a25
			m = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			n = env->stats.n;
Packit 992a25
			env->stats.n = 0;
Packit 992a25
			if (e->re.group.expr.binary.right && stats(env, e->re.group.expr.binary.right))
Packit 992a25
				return 1;
Packit 992a25
			if (env->stats.m > m)
Packit 992a25
				env->stats.m = m;
Packit 992a25
			else
Packit 992a25
				m = env->stats.m;
Packit 992a25
			if ((env->stats.m += cm) < m)
Packit 992a25
				return 1;
Packit 992a25
			if (env->stats.n < n)
Packit 992a25
				env->stats.n = n;
Packit 992a25
			else
Packit 992a25
				n = env->stats.n;
Packit 992a25
			if ((env->stats.n += cn) < n)
Packit 992a25
				return 1;
Packit 992a25
			env->stats.x = x;
Packit 992a25
			env->stats.l = l;
Packit 992a25
			env->stats.y = y;
Packit 992a25
			env->stats.k = k;
Packit 992a25
			env->stats.t = t;
Packit 992a25
			break;
Packit 992a25
		case REX_BACK:
Packit 992a25
			if (++env->stats.b <= 0)
Packit 992a25
				return 1;
Packit 992a25
			break;
Packit 992a25
		case REX_CLASS:
Packit 992a25
		case REX_COLL_CLASS:
Packit 992a25
		case REX_DOT:
Packit 992a25
		case REX_ONECHAR:
Packit 992a25
			n = env->stats.m;
Packit 992a25
			if ((env->stats.m += e->lo) < n)
Packit 992a25
				return 1;
Packit 992a25
			if (e->hi != RE_DUP_INF)
Packit 992a25
			{
Packit 992a25
				n = env->stats.n;
Packit 992a25
				if ((env->stats.n += e->hi) < n)
Packit 992a25
					return 1;
Packit 992a25
			}
Packit 992a25
			if (e->lo != e->hi)
Packit 992a25
			{
Packit 992a25
				if (++env->stats.c <= 0)
Packit 992a25
					return 1;
Packit 992a25
				if (++env->stats.s <= 0)
Packit 992a25
					return 1;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case REX_CONJ:
Packit 992a25
			cm = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			cn = env->stats.n;
Packit 992a25
			env->stats.n = 0;
Packit 992a25
			if (stats(env, e->re.group.expr.binary.left))
Packit 992a25
				return 1;
Packit 992a25
			nm = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			nn = env->stats.n;
Packit 992a25
			env->stats.n = 0;
Packit 992a25
			if (stats(env, e->re.group.expr.binary.right))
Packit 992a25
				return 1;
Packit 992a25
			if (env->stats.m < nm)
Packit 992a25
				env->stats.m = nm;
Packit 992a25
			else
Packit 992a25
				nm = env->stats.m;
Packit 992a25
			if ((env->stats.m += cm) < nm)
Packit 992a25
				return 1;
Packit 992a25
			if (env->stats.n < nn)
Packit 992a25
				env->stats.n = nn;
Packit 992a25
			else
Packit 992a25
				nn = env->stats.n;
Packit 992a25
			if ((env->stats.n += cn) < nn)
Packit 992a25
				return 1;
Packit 992a25
			break;
Packit 992a25
		case REX_END:
Packit 992a25
			env->stats.e = 1;
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP:
Packit 992a25
			if (e->re.group.number && ++env->stats.p <= 0 || !e->re.group.number && ++env->stats.u <= 0)
Packit 992a25
				return 1;
Packit 992a25
			if (stats(env, e->re.group.expr.rex))
Packit 992a25
				return 1;
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP_AHEAD:
Packit 992a25
		case REX_GROUP_AHEAD_NOT:
Packit 992a25
		case REX_GROUP_BEHIND:
Packit 992a25
		case REX_GROUP_BEHIND_NOT:
Packit 992a25
			m = env->stats.m;
Packit 992a25
			n = env->stats.n;
Packit 992a25
			x = env->stats.x;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			if (stats(env, e->re.group.expr.rex))
Packit 992a25
				return 1;
Packit 992a25
			env->stats.m = m;
Packit 992a25
			env->stats.n = n;
Packit 992a25
			env->stats.x = x;
Packit 992a25
			env->stats.y = y;
Packit 992a25
			switch (e->type)
Packit 992a25
			{
Packit 992a25
			case REX_GROUP_AHEAD:
Packit 992a25
			case REX_GROUP_BEHIND:
Packit 992a25
				if (++env->stats.u <= 0)
Packit 992a25
					return 1;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP_COND:
Packit 992a25
			if (++env->stats.u <= 0)
Packit 992a25
				return 1;
Packit 992a25
			m = env->stats.m;
Packit 992a25
			n = env->stats.n;
Packit 992a25
			x = env->stats.x;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			if (e->re.group.size > 0 && ++env->stats.b <= 0)
Packit 992a25
				return 1;
Packit 992a25
			if (e->re.group.expr.binary.left && stats(env, e->re.group.expr.binary.left))
Packit 992a25
				return 1;
Packit 992a25
			if (q = e->re.group.expr.binary.right)
Packit 992a25
			{
Packit 992a25
				if (q->re.group.expr.binary.left && stats(env, q->re.group.expr.binary.left))
Packit 992a25
					return 1;
Packit 992a25
				if (q->re.group.expr.binary.right && stats(env, q->re.group.expr.binary.right))
Packit 992a25
					return 1;
Packit 992a25
			}
Packit 992a25
			env->stats.m = m;
Packit 992a25
			env->stats.n = n;
Packit 992a25
			env->stats.x = x;
Packit 992a25
			env->stats.y = y;
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP_CUT:
Packit 992a25
			if (++env->stats.u <= 0)
Packit 992a25
				return 1;
Packit 992a25
			m = env->stats.m;
Packit 992a25
			n = env->stats.n;
Packit 992a25
			x = env->stats.x;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			if (stats(env, e->re.group.expr.rex))
Packit 992a25
				return 1;
Packit 992a25
			env->stats.m = m;
Packit 992a25
			env->stats.n = n;
Packit 992a25
			env->stats.x = x;
Packit 992a25
			env->stats.y = y;
Packit 992a25
			break;
Packit 992a25
		case REX_NEG:
Packit 992a25
			env->stats.i++;
Packit 992a25
			x = env->stats.x;
Packit 992a25
			l = env->stats.l;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			k = env->stats.k;
Packit 992a25
			t = env->stats.t;
Packit 992a25
			cm = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			if (stats(env, e->re.group.expr.rex))
Packit 992a25
				return 1;
Packit 992a25
			env->stats.m = !env->stats.m;
Packit 992a25
			if ((env->stats.m += cm) < cm)
Packit 992a25
				return 1;
Packit 992a25
			env->stats.x = x;
Packit 992a25
			env->stats.l = l;
Packit 992a25
			env->stats.y = y;
Packit 992a25
			env->stats.k = k;
Packit 992a25
			env->stats.t = t;
Packit 992a25
			break;
Packit 992a25
		case REX_REP:
Packit 992a25
			x = env->stats.x;
Packit 992a25
			l = env->stats.l;
Packit 992a25
			y = env->stats.y;
Packit 992a25
			k = env->stats.k;
Packit 992a25
			t = env->stats.t;
Packit 992a25
			if (++env->stats.c <= 0)
Packit 992a25
				return 1;
Packit 992a25
			b = env->stats.b;
Packit 992a25
			c = env->stats.c;
Packit 992a25
			cm = env->stats.m;
Packit 992a25
			env->stats.m = 0;
Packit 992a25
			if (stats(env, e->re.group.expr.rex))
Packit 992a25
				return 1;
Packit 992a25
			if (env->stats.m == 1 && b == env->stats.b && c == env->stats.c && ++env->stats.s <= 0)
Packit 992a25
				return 1;
Packit 992a25
			if (e->lo < 1)
Packit 992a25
			{
Packit 992a25
				env->stats.x = x;
Packit 992a25
				env->stats.l = l;
Packit 992a25
				env->stats.y = y;
Packit 992a25
				env->stats.k = k;
Packit 992a25
				env->stats.t = t;
Packit 992a25
				env->stats.m = cm;
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				m = env->stats.m;
Packit 992a25
				if ((env->stats.m *= e->lo) > 0 && env->stats.m < m)
Packit 992a25
					return 1;
Packit 992a25
				m = env->stats.m;
Packit 992a25
				if ((env->stats.m += cm) < m)
Packit 992a25
					return 1;
Packit 992a25
				if (env->stats.x != x)
Packit 992a25
					env->stats.l = cm;
Packit 992a25
				if (env->stats.y != y)
Packit 992a25
					env->stats.k = cm;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case REX_STRING:
Packit 992a25
			if (!e->map)
Packit 992a25
			{
Packit 992a25
				cm = env->stats.m;
Packit 992a25
				if ((env->stats.m += e->re.string.size) < cm)
Packit 992a25
					return 1;
Packit 992a25
				cn = env->stats.n;
Packit 992a25
				if ((env->stats.n += e->re.string.size) < cn)
Packit 992a25
					return 1;
Packit 992a25
				if (!env->stats.x || env->stats.x->re.string.size < e->re.string.size)
Packit 992a25
				{
Packit 992a25
					env->stats.x = e;
Packit 992a25
					env->stats.l = cm;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		case REX_TRIE:
Packit 992a25
			if (++env->stats.s <= 0)
Packit 992a25
				return 1;
Packit 992a25
			cm = env->stats.m;
Packit 992a25
			if ((env->stats.m += e->re.trie.min) < cm)
Packit 992a25
				return 1;
Packit 992a25
			cn = env->stats.n;
Packit 992a25
			if ((env->stats.n += e->re.trie.max) < cn)
Packit 992a25
				return 1;
Packit 992a25
			env->stats.t++;
Packit 992a25
			if (!env->stats.y || env->stats.y->re.trie.min < e->re.trie.min)
Packit 992a25
			{
Packit 992a25
				env->stats.y = e;
Packit 992a25
				env->stats.k = cm;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
	} while (e = e->next);
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
static int	token(Cenv_t*);
Packit 992a25
Packit 992a25
static int
Packit 992a25
magic(register Cenv_t* env, register int c, int escaped)
Packit 992a25
{
Packit 992a25
	register char*	sp;
Packit 992a25
	register int	n;
Packit 992a25
	int		o = c;
Packit 992a25
	int		e = env->error;
Packit 992a25
	int		l = env->token.len;
Packit 992a25
	short*		mp;
Packit 992a25
	char*		ep;
Packit 992a25
Packit 992a25
	if (mp = state.magic[c])
Packit 992a25
	{
Packit 992a25
		c = mp[env->type+escaped];
Packit 992a25
		if (c >= T_META)
Packit 992a25
		{
Packit 992a25
			sp = (char*)env->cursor + env->token.len;
Packit 992a25
			switch (c)
Packit 992a25
			{
Packit 992a25
			case T_LEFT:
Packit 992a25
				n = 0;
Packit 992a25
				ep = sp;
Packit 992a25
				while (*sp >= '0' && *sp <= '9')
Packit 992a25
				{
Packit 992a25
					if (n > (INT_MAX / 10))
Packit 992a25
					{
Packit 992a25
						env->error = REG_BADBR;
Packit 992a25
						goto bad;
Packit 992a25
					}
Packit 992a25
					n = n * 10 + *sp++ - '0';
Packit 992a25
				}
Packit 992a25
				if (sp == ep)
Packit 992a25
				{
Packit 992a25
					if (env->type < SRE || *sp != ',')
Packit 992a25
					{
Packit 992a25
						env->error = *sp ? REG_BADBR : REG_EBRACE;
Packit 992a25
						goto bad;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (n > RE_DUP_MAX)
Packit 992a25
				{
Packit 992a25
					env->error = REG_BADBR;
Packit 992a25
					goto bad;
Packit 992a25
				}
Packit 992a25
				env->token.min = n;
Packit 992a25
				if (*sp == ',')
Packit 992a25
				{
Packit 992a25
					n = 0;
Packit 992a25
					ep = ++sp;
Packit 992a25
					while (*sp >= '0' && *sp <= '9')
Packit 992a25
					{
Packit 992a25
						if (n > (INT_MAX / 10))
Packit 992a25
						{
Packit 992a25
							env->error = REG_BADBR;
Packit 992a25
							goto bad;
Packit 992a25
						}
Packit 992a25
						n = n * 10 + *sp++ - '0';
Packit 992a25
					}
Packit 992a25
					if (sp == ep)
Packit 992a25
						n = RE_DUP_INF;
Packit 992a25
					else if (n < env->token.min)
Packit 992a25
					{
Packit 992a25
						env->error = REG_BADBR;
Packit 992a25
						goto bad;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				env->token.max = n;
Packit 992a25
				switch (*sp)
Packit 992a25
				{
Packit 992a25
				case 0:
Packit 992a25
					env->error = REG_EBRACE;
Packit 992a25
					goto bad;
Packit 992a25
				case '\\':
Packit 992a25
					if (!escaped)
Packit 992a25
					{
Packit 992a25
						env->error = REG_BADBR;
Packit 992a25
						goto bad;
Packit 992a25
					}
Packit 992a25
					sp++;
Packit 992a25
					break;
Packit 992a25
				default:
Packit 992a25
					if (escaped)
Packit 992a25
					{
Packit 992a25
						env->error = REG_BADBR;
Packit 992a25
						goto bad;
Packit 992a25
					}
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
				switch (*sp++)
Packit 992a25
				{
Packit 992a25
				case 0:
Packit 992a25
					env->error = REG_EBRACE;
Packit 992a25
					goto bad;
Packit 992a25
				case '}':
Packit 992a25
					break;
Packit 992a25
				default:
Packit 992a25
					env->error = REG_BADBR;
Packit 992a25
					goto bad;
Packit 992a25
				}
Packit 992a25
				env->token.len = sp - (char*)env->cursor;
Packit 992a25
				break;
Packit 992a25
			case T_RIGHT:
Packit 992a25
				env->error = REG_EBRACE;
Packit 992a25
				goto bad;
Packit 992a25
			case T_OPEN:
Packit 992a25
				if (env->type < SRE && *sp == '?')
Packit 992a25
				{
Packit 992a25
					env->token.len++;
Packit 992a25
					env->token.lex = 0;
Packit 992a25
					goto group;
Packit 992a25
				}
Packit 992a25
				break;
Packit 992a25
			case T_ESCAPE:
Packit 992a25
				c = chresc(sp - 2, &ep);
Packit 992a25
				if (ep < sp)
Packit 992a25
					goto bad;
Packit 992a25
				env->token.len += ep - sp;
Packit 992a25
				if (c >= T_META)
Packit 992a25
				{
Packit 992a25
					env->token.lex = c;
Packit 992a25
					c = C_ESC;
Packit 992a25
				}
Packit 992a25
				return c;
Packit 992a25
			case T_BACK+0:
Packit 992a25
			case T_BACK+1:
Packit 992a25
			case T_BACK+2:
Packit 992a25
			case T_BACK+3:
Packit 992a25
			case T_BACK+4:
Packit 992a25
			case T_BACK+5:
Packit 992a25
			case T_BACK+6:
Packit 992a25
			case T_BACK+7:
Packit 992a25
				n = chresc(sp - 2, &ep);
Packit 992a25
				if (ep > sp + 1)
Packit 992a25
				{
Packit 992a25
					env->token.len += ep - sp;
Packit 992a25
					return n;
Packit 992a25
				}
Packit 992a25
				/*FALLTHROUGH*/
Packit 992a25
			case T_BACK+8:
Packit 992a25
			case T_BACK+9:
Packit 992a25
				if (env->type == SRE || c == T_BACK && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
				{
Packit 992a25
					env->error = REG_BADESC;
Packit 992a25
					goto bad;
Packit 992a25
				}
Packit 992a25
				if ((env->flags & REG_MULTIREF) && isdigit(*sp))
Packit 992a25
				{
Packit 992a25
					c = (c - T_BACK) * 10 + (*sp - '0');
Packit 992a25
					if (c > 0 && c <= env->parno && env->paren[c])
Packit 992a25
						c += T_BACK;
Packit 992a25
					else
Packit 992a25
						c = chresc(sp - 2, &ep);
Packit 992a25
					env->token.len++;
Packit 992a25
				}
Packit 992a25
				if (c == T_BACK)
Packit 992a25
					c = 0;
Packit 992a25
				break;
Packit 992a25
			case T_BAD:
Packit 992a25
				if (escaped == 1 && (env->flags & (REG_LENIENT|REG_REGEXP)) && (c = mp[env->type+escaped+2]) >= T_META)
Packit 992a25
					return c;
Packit 992a25
				goto bad;
Packit 992a25
			}
Packit 992a25
			if (env->type >= SRE)
Packit 992a25
			{
Packit 992a25
				if (c == T_DOT)
Packit 992a25
					c = '.';
Packit 992a25
				else if (c < T_OPEN)
Packit 992a25
				{
Packit 992a25
					if (env->type == KRE && *(env->cursor + env->token.len) == '-' && *(env->cursor + env->token.len + 1) == '(')
Packit 992a25
					{
Packit 992a25
						env->token.len++;
Packit 992a25
						env->token.att = 1;
Packit 992a25
					}
Packit 992a25
					if (env->type == KRE && *(env->cursor + env->token.len) == '(')
Packit 992a25
					{
Packit 992a25
						env->token.len++;
Packit 992a25
						switch (c)
Packit 992a25
						{
Packit 992a25
						case T_AT:
Packit 992a25
							break;
Packit 992a25
						case T_PERCENT:
Packit 992a25
							env->token.lex = c;
Packit 992a25
							goto group;
Packit 992a25
						case T_TILDE:
Packit 992a25
							env->token.lex = 0;
Packit 992a25
							goto group;
Packit 992a25
						default:
Packit 992a25
							env->token.lex = c;
Packit 992a25
							break;
Packit 992a25
						}
Packit 992a25
						c = T_OPEN;
Packit 992a25
					}
Packit 992a25
					else if (c == T_STAR)
Packit 992a25
						c = T_DOTSTAR;
Packit 992a25
					else if (c == T_QUES)
Packit 992a25
						c = T_DOT;
Packit 992a25
					else
Packit 992a25
					{
Packit 992a25
						c = o;
Packit 992a25
						env->token.len = l;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (c > T_BACK)
Packit 992a25
				{
Packit 992a25
					c = (c - T_BACK) * 2 - 1;
Packit 992a25
					c = (c > env->parno || !env->paren[c]) ? o : T_BACK + c;
Packit 992a25
				}
Packit 992a25
				else if (env->type == KRE && !env->parnest && (env->flags & REG_SHELL_GROUP))
Packit 992a25
				{
Packit 992a25
					if (c == T_AND)
Packit 992a25
						c = '&';
Packit 992a25
					else if (c == T_BAR)
Packit 992a25
						c = '|';
Packit 992a25
					else if (c == T_OPEN)
Packit 992a25
						c = '(';
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	else if (escaped == 2)
Packit 992a25
	{
Packit 992a25
		if (env->type >= SRE && !(env->flags & REG_SHELL_ESCAPED) || (env->flags & REG_ESCAPE) && (c == '[' || c == '-' || c == ']' || env->delimiter && c == env->delimiter))
Packit 992a25
			/*ok*/;
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			env->error = REG_BADESC;
Packit 992a25
			goto bad;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	else if (escaped && !(env->flags & (REG_LENIENT|REG_REGEXP)) && c != ']')
Packit 992a25
	{
Packit 992a25
		env->error = REG_BADESC;
Packit 992a25
		goto bad;
Packit 992a25
	}
Packit 992a25
	return c;
Packit 992a25
 group:
Packit 992a25
	sp = (char*)env->cursor + env->token.len;
Packit 992a25
	switch (*sp++)
Packit 992a25
	{
Packit 992a25
	case ')':
Packit 992a25
		break;
Packit 992a25
	case '#':
Packit 992a25
		for (;;)
Packit 992a25
		{
Packit 992a25
			switch (*sp++)
Packit 992a25
			{
Packit 992a25
			case 0:
Packit 992a25
				env->error = REG_EPAREN;
Packit 992a25
				return T_BAD;
Packit 992a25
			case ')':
Packit 992a25
				break;
Packit 992a25
			default:
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		break;
Packit 992a25
	default:
Packit 992a25
		return T_GROUP;
Packit 992a25
	}
Packit 992a25
	env->cursor = (unsigned char*)sp;
Packit 992a25
	return token(env);
Packit 992a25
 bad:
Packit 992a25
	if (escaped == 2)
Packit 992a25
		env->error = e;
Packit 992a25
	else if (env->flags & (REG_LENIENT|REG_REGEXP))
Packit 992a25
		return o;
Packit 992a25
	else if (escaped == 1 && !env->error)
Packit 992a25
	{
Packit 992a25
		if (mp || o == ']')
Packit 992a25
			return o;
Packit 992a25
		env->error = REG_BADESC;
Packit 992a25
	}
Packit 992a25
	return T_BAD;
Packit 992a25
}
Packit 992a25
Packit 992a25
static int
Packit 992a25
token(register Cenv_t* env)
Packit 992a25
{
Packit 992a25
	int	c;
Packit 992a25
	int	posixkludge;
Packit 992a25
Packit 992a25
	if (env->token.push)
Packit 992a25
		return env->token.lex;
Packit 992a25
	env->token.att = env->token.esc = 0;
Packit 992a25
	if ((env->token.len = MBSIZE(env->cursor)) > 1)
Packit 992a25
		return env->token.lex = C_MB;
Packit 992a25
	env->token.lex = 0;
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		c = *env->cursor;
Packit 992a25
		if (c == 0 || c == env->delimiter || c == env->terminator)
Packit 992a25
			return T_END;
Packit 992a25
		if (!(env->flags & REG_COMMENT))
Packit 992a25
			break;
Packit 992a25
		if (c == '#')
Packit 992a25
		{
Packit 992a25
			do
Packit 992a25
			{
Packit 992a25
				c = *++env->cursor;
Packit 992a25
				if (c == 0 || c == env->delimiter)
Packit 992a25
					return T_END;
Packit 992a25
			} while (c != '\n');
Packit 992a25
		}
Packit 992a25
		else if (!isspace(c))
Packit 992a25
			break;
Packit 992a25
		env->cursor++;
Packit 992a25
	}
Packit 992a25
	if (c == '\n' && (env->flags & REG_MULTIPLE) && !env->delimiter)
Packit 992a25
	{
Packit 992a25
		if (env->parnest)
Packit 992a25
		{
Packit 992a25
			env->error = REG_EPAREN;
Packit 992a25
			return T_BAD;
Packit 992a25
		}
Packit 992a25
		env->parno = 0;
Packit 992a25
		env->pattern = env->cursor + 1;
Packit 992a25
		return T_BAR;
Packit 992a25
	}
Packit 992a25
	if (env->flags & REG_LITERAL)
Packit 992a25
		return c;
Packit 992a25
	if (posixkludge = env->posixkludge)
Packit 992a25
	{
Packit 992a25
		env->posixkludge = 0;
Packit 992a25
		if (c == '*')
Packit 992a25
			return c;
Packit 992a25
	}
Packit 992a25
	if (c == '\\')
Packit 992a25
	{
Packit 992a25
		if (env->flags & REG_SHELL_ESCAPED)
Packit 992a25
			return c;
Packit 992a25
		if (!(c = *(env->cursor + 1)) || c == env->terminator)
Packit 992a25
		{
Packit 992a25
			if (env->flags & (REG_LENIENT|REG_REGEXP))
Packit 992a25
			{
Packit 992a25
				if (c)
Packit 992a25
				{
Packit 992a25
					env->token.esc = env->token.len;
Packit 992a25
					env->token.len += MBSIZE(env->cursor + 1);
Packit 992a25
					return c;
Packit 992a25
				}
Packit 992a25
				return '\\';
Packit 992a25
			}
Packit 992a25
			env->error = REG_EESCAPE;
Packit 992a25
			return T_BAD;
Packit 992a25
		}
Packit 992a25
		env->token.esc = env->token.len;
Packit 992a25
		env->token.len += MBSIZE(env->cursor + 1);
Packit 992a25
		if (env->delimiter && c == 'n')
Packit 992a25
			return '\n';
Packit 992a25
		else if (c == env->delimiter)
Packit 992a25
			return magic(env, c, 0);
Packit 992a25
		else if (c == '(' && env->type == BRE)
Packit 992a25
			env->posixkludge = 1;
Packit 992a25
		else if (c == ')' && env->type == BRE && env->parnest <= 0)
Packit 992a25
		{
Packit 992a25
			env->error = REG_EPAREN;
Packit 992a25
			return T_BAD;
Packit 992a25
		}
Packit 992a25
		else if (isspace(c) && (env->flags & REG_COMMENT))
Packit 992a25
			return c;
Packit 992a25
		return magic(env, c, 1);
Packit 992a25
	}
Packit 992a25
	else if (c == '$')
Packit 992a25
	{
Packit 992a25
		if (env->type == BRE && (*(env->cursor + 1) == 0 || *(env->cursor + 1) == env->delimiter || *(env->cursor + 1) == env->terminator || *(env->cursor + 1) == '\\' && *(env->cursor + 2) == ')') || (env->flags & REG_MULTIPLE) && *(env->cursor + 1) == '\n')
Packit 992a25
			return T_DOLL;
Packit 992a25
	}
Packit 992a25
	else if (c == '^')
Packit 992a25
	{
Packit 992a25
		if (env->type == BRE && (env->cursor == env->pattern || posixkludge == 1))
Packit 992a25
		{
Packit 992a25
			env->posixkludge = 2;
Packit 992a25
			return T_CFLX;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	else if (c == ')')
Packit 992a25
	{
Packit 992a25
		if (env->type != BRE && env->parnest <= 0)
Packit 992a25
			return c;
Packit 992a25
	}
Packit 992a25
	else if (c == '/' && env->explicit == env->mappedslash)
Packit 992a25
	{
Packit 992a25
		while (*(env->cursor + env->token.len) == c)
Packit 992a25
			env->token.len++;
Packit 992a25
		return T_SLASHPLUS;
Packit 992a25
	}
Packit 992a25
	return magic(env, c, 0);
Packit 992a25
}
Packit 992a25
Packit 992a25
static Celt_t*
Packit 992a25
col(Celt_t* ce, int ic, unsigned char* bp, int bw, int bc, unsigned char* ep, int ew, int ec)
Packit 992a25
{
Packit 992a25
	register char*		s;
Packit 992a25
	register unsigned char*	k;
Packit 992a25
	register unsigned char*	e;
Packit 992a25
	register int		c;
Packit 992a25
	register int		cc;
Packit 992a25
	int			bt;
Packit 992a25
	int			et;
Packit 992a25
	Ckey_t			key;
Packit 992a25
Packit 992a25
	cc = 0;
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		k = key;
Packit 992a25
		if (bw == 1)
Packit 992a25
		{
Packit 992a25
			c = bc;
Packit 992a25
			if (ic)
Packit 992a25
			{
Packit 992a25
				if (isupper(c))
Packit 992a25
				{
Packit 992a25
					c = tolower(c);
Packit 992a25
					cc = -1;
Packit 992a25
				}
Packit 992a25
				else if (islower(c))
Packit 992a25
				{
Packit 992a25
					c = toupper(c);
Packit 992a25
					cc = -1;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			*k++ = c;
Packit 992a25
		}
Packit 992a25
		else if (bw < COLL_KEY_MAX)
Packit 992a25
		{
Packit 992a25
			s = (char*)bp;
Packit 992a25
			if (ic)
Packit 992a25
			{
Packit 992a25
				c = mbchar(s);
Packit 992a25
				if (iswupper(c))
Packit 992a25
				{
Packit 992a25
					c = towlower(c);
Packit 992a25
					cc = 1;
Packit 992a25
				}
Packit 992a25
				else if (iswlower(c))
Packit 992a25
				{
Packit 992a25
					c = towupper(c);
Packit 992a25
					cc = 1;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			if (cc > 0)
Packit 992a25
			{
Packit 992a25
				cc = -1;
Packit 992a25
				k += mbconv((char*)k, c);
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
				for (e = k + bw; k < e; *k++ = *s++);
Packit 992a25
		}
Packit 992a25
		*k = 0;
Packit 992a25
		mbxfrm(ce->beg, key, COLL_KEY_MAX);
Packit 992a25
		if (ep)
Packit 992a25
		{
Packit 992a25
			k = key;
Packit 992a25
			c = mbchar(k);
Packit 992a25
			if (iswupper(c))
Packit 992a25
				bt = COLL_range_uc;
Packit 992a25
			else if (iswlower(c))
Packit 992a25
				bt = COLL_range_lc;
Packit 992a25
			else
Packit 992a25
				bt = COLL_range;
Packit 992a25
			k = key;
Packit 992a25
			if (ew == 1)
Packit 992a25
			{
Packit 992a25
				c = ec;
Packit 992a25
				if (ic)
Packit 992a25
				{
Packit 992a25
					if (isupper(c))
Packit 992a25
					{
Packit 992a25
						c = tolower(c);
Packit 992a25
						cc = -1;
Packit 992a25
					}
Packit 992a25
					else if (islower(c))
Packit 992a25
					{
Packit 992a25
						c = toupper(c);
Packit 992a25
						cc = -1;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				*k++ = c;
Packit 992a25
			}
Packit 992a25
			else if (ew < COLL_KEY_MAX)
Packit 992a25
			{
Packit 992a25
				s = (char*)ep;
Packit 992a25
				if (ic)
Packit 992a25
				{
Packit 992a25
					c = mbchar(s);
Packit 992a25
					if (iswupper(c))
Packit 992a25
					{
Packit 992a25
						c = towlower(c);
Packit 992a25
						cc = 1;
Packit 992a25
					}
Packit 992a25
					else if (iswlower(c))
Packit 992a25
					{
Packit 992a25
						c = towupper(c);
Packit 992a25
						cc = 1;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				if (cc > 0)
Packit 992a25
				{
Packit 992a25
					cc = -1;
Packit 992a25
					k += mbconv((char*)k, c);
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
					for (e = k + ew; k < e; *k++ = *s++);
Packit 992a25
			}
Packit 992a25
			*k = 0;
Packit 992a25
			mbxfrm(ce->end, key, COLL_KEY_MAX);
Packit 992a25
			k = key;
Packit 992a25
			c = mbchar(k);
Packit 992a25
			if (iswupper(c))
Packit 992a25
				et = COLL_range_uc;
Packit 992a25
			else if (iswlower(c))
Packit 992a25
				et = COLL_range_lc;
Packit 992a25
			else
Packit 992a25
				et = COLL_range;
Packit 992a25
			ce->typ = bt == et ? bt : COLL_range;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			ce->typ = COLL_char;
Packit 992a25
		ce++;
Packit 992a25
		if (!ic || !cc)
Packit 992a25
			break;
Packit 992a25
		ic = 0;
Packit 992a25
	}
Packit 992a25
	return ce;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
bra(Cenv_t* env)
Packit 992a25
{
Packit 992a25
	Rex_t*		e;
Packit 992a25
	int		c;
Packit 992a25
	int		i;
Packit 992a25
	int		w;
Packit 992a25
	int		neg;
Packit 992a25
	int		last;
Packit 992a25
	int		inrange;
Packit 992a25
	int		complicated;
Packit 992a25
	int		collate;
Packit 992a25
	int		elements;
Packit 992a25
	unsigned char*	first;
Packit 992a25
	unsigned char*	start;
Packit 992a25
	unsigned char*	begin;
Packit 992a25
	unsigned char*	s;
Packit 992a25
	regclass_t	f;
Packit 992a25
	unsigned char	buf[4 * (COLL_KEY_MAX + 1)];
Packit 992a25
#if _PACKAGE_ast
Packit 992a25
	int		ic;
Packit 992a25
	char		mbc[COLL_KEY_MAX + 1];
Packit 992a25
#endif
Packit 992a25
Packit 992a25
	if (!(e = node(env, REX_CLASS, 1, 1, sizeof(Set_t))))
Packit 992a25
		return 0;
Packit 992a25
	collate = complicated = elements = 0;
Packit 992a25
	if (*env->cursor == '^' || env->type >= SRE && *env->cursor == '!')
Packit 992a25
	{
Packit 992a25
		env->cursor++;
Packit 992a25
		complicated = neg = 1;
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		neg = 0;
Packit 992a25
	first = env->cursor;
Packit 992a25
	start = first + MBSIZE(first);
Packit 992a25
	if (*env->cursor == 0 || *(env->cursor + 1) == 0 || *env->cursor == env->terminator || *(env->cursor + 1) == env->terminator || (env->flags & REG_ESCAPE) && (*env->cursor == env->delimiter || *env->cursor != '\\' && *(env->cursor + 1) == env->delimiter))
Packit 992a25
		goto error;
Packit 992a25
	begin = env->cursor + MBSIZE(env->cursor);
Packit 992a25
Packit 992a25
	/*
Packit 992a25
	 * inrange: 0=no, 1=possibly, 2=definitely
Packit 992a25
	 */
Packit 992a25
Packit 992a25
	inrange = 0;
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		if (!(c = *env->cursor) || c == env->terminator || c == env->delimiter && (env->flags & REG_ESCAPE))
Packit 992a25
			goto error;
Packit 992a25
		env->cursor += (w = MBSIZE(env->cursor));
Packit 992a25
		if (c == '\\' && ((env->flags & REG_CLASS_ESCAPE) || *env->cursor == env->delimiter && (env->flags & REG_ESCAPE)))
Packit 992a25
		{
Packit 992a25
			if (*env->cursor)
Packit 992a25
			{
Packit 992a25
				if (*env->cursor == 'n')
Packit 992a25
				{
Packit 992a25
					env->cursor++;
Packit 992a25
					c = '\n';
Packit 992a25
				}
Packit 992a25
				else if (env->type < SRE || !(env->flags & REG_SHELL_ESCAPED))
Packit 992a25
				{
Packit 992a25
					env->token.len = 1;
Packit 992a25
					w = magic(env, *env->cursor, 2);
Packit 992a25
					if (env->token.len > 1 || w != T_BAD)
Packit 992a25
					{
Packit 992a25
						if (env->token.len == 1 && (f = classfun(w)))
Packit 992a25
						{
Packit 992a25
							if (inrange > 1)
Packit 992a25
							{
Packit 992a25
								if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
									goto erange;
Packit 992a25
								inrange = 0;
Packit 992a25
							}
Packit 992a25
							env->cursor++;
Packit 992a25
							for (c = 0; c <= UCHAR_MAX; c++)
Packit 992a25
								if ((*f)(c))
Packit 992a25
									setadd(e->re.charclass, c);
Packit 992a25
							complicated++;
Packit 992a25
							elements++;
Packit 992a25
							continue;
Packit 992a25
						}
Packit 992a25
						if (env->token.len > 1 || w >= 0 && w < T_META)
Packit 992a25
						{
Packit 992a25
							c = w;
Packit 992a25
							if (c > UCHAR_MAX)
Packit 992a25
							{
Packit 992a25
								if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)) && !mbwide())
Packit 992a25
									goto erange;
Packit 992a25
								c = UCHAR_MAX;
Packit 992a25
							}
Packit 992a25
							env->cursor += env->token.len;
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if (c == ']')
Packit 992a25
		{
Packit 992a25
			if (env->cursor == begin)
Packit 992a25
			{
Packit 992a25
				last = c;
Packit 992a25
				inrange = 1;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			if (inrange != 0)
Packit 992a25
			{
Packit 992a25
				setadd(e->re.charclass, last);
Packit 992a25
				elements++;
Packit 992a25
				if (inrange == 2)
Packit 992a25
				{
Packit 992a25
					setadd(e->re.charclass, '-');
Packit 992a25
					elements++;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		else if (c == '-')
Packit 992a25
		{
Packit 992a25
			if (!inrange && env->cursor != begin && *env->cursor != ']')
Packit 992a25
			{
Packit 992a25
				if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
					goto erange;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			else if (inrange == 1)
Packit 992a25
			{
Packit 992a25
				inrange = 2;
Packit 992a25
				complicated++;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if (c == '[')
Packit 992a25
		{
Packit 992a25
			switch (*env->cursor)
Packit 992a25
			{
Packit 992a25
			case 0:
Packit 992a25
				goto error;
Packit 992a25
			case ':':
Packit 992a25
				if (env->flags & REG_REGEXP)
Packit 992a25
					goto normal;
Packit 992a25
				if (inrange == 1)
Packit 992a25
				{
Packit 992a25
					setadd(e->re.charclass, last);
Packit 992a25
					elements++;
Packit 992a25
				}
Packit 992a25
				if (!(f = regclass((char*)env->cursor, (char**)&env->cursor)))
Packit 992a25
				{
Packit 992a25
					if (env->cursor == start && (c = *(env->cursor + 1)))
Packit 992a25
					{
Packit 992a25
						s = start = env->cursor + 1;
Packit 992a25
						while (*++s && *s != ':');
Packit 992a25
						if (*s == ':' && *(s + 1) == ']' && *(s + 2) == ']')
Packit 992a25
						{
Packit 992a25
							if ((i = (s - start)) == 1)
Packit 992a25
							{
Packit 992a25
								switch (c)
Packit 992a25
								{
Packit 992a25
								case '<':
Packit 992a25
									i = REX_WBEG;
Packit 992a25
									break;
Packit 992a25
								case '>':
Packit 992a25
									i = REX_WEND;
Packit 992a25
									break;
Packit 992a25
								default:
Packit 992a25
									i = 0;
Packit 992a25
									break;
Packit 992a25
								}
Packit 992a25
								if (i)
Packit 992a25
								{
Packit 992a25
									env->cursor = s + 3;
Packit 992a25
									drop(env->disc, e);
Packit 992a25
									return node(env, i, 0, 0, 0);
Packit 992a25
								}
Packit 992a25
							}
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
					env->error = REG_ECTYPE;
Packit 992a25
					goto error;
Packit 992a25
				}
Packit 992a25
				for (c = 0; c <= UCHAR_MAX; c++)
Packit 992a25
					if ((*f)(c))
Packit 992a25
						setadd(e->re.charclass, c);
Packit 992a25
				inrange = 0;
Packit 992a25
				complicated++;
Packit 992a25
				elements++;
Packit 992a25
				continue;
Packit 992a25
			case '=':
Packit 992a25
				if (env->flags & REG_REGEXP)
Packit 992a25
					goto normal;
Packit 992a25
				if (inrange == 2)
Packit 992a25
					goto erange;
Packit 992a25
				if (inrange == 1)
Packit 992a25
				{
Packit 992a25
					setadd(e->re.charclass, last);
Packit 992a25
					elements++;
Packit 992a25
				}
Packit 992a25
				if ((c = regcollate((char*)env->cursor, (char**)&env->cursor, (char*)buf, sizeof(buf), NiL)) < 0)
Packit 992a25
					goto ecollate;
Packit 992a25
				if (c > 1)
Packit 992a25
					collate++;
Packit 992a25
				else
Packit 992a25
					setadd(e->re.charclass, buf[0]);
Packit 992a25
				c = buf[0];
Packit 992a25
				inrange = 0;
Packit 992a25
				complicated++;
Packit 992a25
				elements++;
Packit 992a25
				continue;
Packit 992a25
			case '.':
Packit 992a25
				if (env->flags & REG_REGEXP)
Packit 992a25
					goto normal;
Packit 992a25
				if ((c = regcollate((char*)env->cursor, (char**)&env->cursor, (char*)buf, sizeof(buf), NiL)) < 0)
Packit 992a25
					goto ecollate;
Packit 992a25
				if (c > 1)
Packit 992a25
					collate++;
Packit 992a25
				c = buf[0];
Packit 992a25
				complicated++;
Packit 992a25
				break;
Packit 992a25
			default:
Packit 992a25
			normal:
Packit 992a25
				if (*env->cursor == env->terminator || *env->cursor == env->delimiter && (env->flags & REG_ESCAPE))
Packit 992a25
					goto error;
Packit 992a25
				break;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else if (w > 1)
Packit 992a25
			complicated++;
Packit 992a25
		if (inrange == 2)
Packit 992a25
		{
Packit 992a25
			if (last <= c)
Packit 992a25
			{
Packit 992a25
				for (i = last; i <= c; i++)
Packit 992a25
					setadd(e->re.charclass, i);
Packit 992a25
				inrange = env->type >= SRE || (env->flags & (REG_LENIENT|REG_REGEXP));
Packit 992a25
				elements += 2;
Packit 992a25
			}
Packit 992a25
			else if (env->type >= SRE)
Packit 992a25
			{
Packit 992a25
				setadd(e->re.charclass, last);
Packit 992a25
				setadd(e->re.charclass, c);
Packit 992a25
				elements += 2;
Packit 992a25
				inrange = 1;
Packit 992a25
			}
Packit 992a25
			else if (!(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
				goto erange;
Packit 992a25
			else
Packit 992a25
				inrange = 0;
Packit 992a25
		}
Packit 992a25
		else if (inrange == 1)
Packit 992a25
		{
Packit 992a25
			setadd(e->re.charclass, last);
Packit 992a25
			elements++;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			inrange = 1;
Packit 992a25
		last = c;
Packit 992a25
	}
Packit 992a25
#if _PACKAGE_ast
Packit 992a25
	if (complicated && mbcoll())
Packit 992a25
	{
Packit 992a25
		Dt_t*			dt;
Packit 992a25
		Cchr_t*			cc;
Packit 992a25
		Cchr_t*			tc;
Packit 992a25
		Cchr_t*			xc;
Packit 992a25
		Celt_t*			ce;
Packit 992a25
		Cchr_t			key;
Packit 992a25
		int			rw;
Packit 992a25
		int			rc;
Packit 992a25
		wchar_t			wc;
Packit 992a25
		unsigned char*		rp;
Packit 992a25
		unsigned char*		pp;
Packit 992a25
		char			cb[2][COLL_KEY_MAX+1];
Packit 992a25
Packit 992a25
		static Dtdisc_t		disc;
Packit 992a25
Packit 992a25
		static const char	primary[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Packit 992a25
Packit 992a25
		if (!(dt = (Dt_t*)LCINFO(AST_LC_COLLATE)->data))
Packit 992a25
		{
Packit 992a25
			disc.key = offsetof(Cchr_t, key);
Packit 992a25
			if ((cc = newof(0, Cchr_t, elementsof(primary), 0)) && (dt = dtopen(&disc, Dtoset)))
Packit 992a25
			{
Packit 992a25
				for (i = 0; i < elementsof(primary) - 1; i++, cc++)
Packit 992a25
				{
Packit 992a25
					cc->nam[0] = primary[i];
Packit 992a25
					mbxfrm(cc->key, cc->nam, COLL_KEY_MAX);
Packit 992a25
					dtinsert(dt, cc);
Packit 992a25
				}
Packit 992a25
				for (i = 0; i < elementsof(cc->key); i++)
Packit 992a25
					cc->key[i] = ~0;
Packit 992a25
				dtinsert(dt, cc);
Packit 992a25
				LCINFO(AST_LC_COLLATE)->data = (void*)dt;
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				if (cc)
Packit 992a25
					free(cc);
Packit 992a25
				drop(env->disc, e);
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		if (dt)
Packit 992a25
		{
Packit 992a25
			drop(env->disc, e);
Packit 992a25
			if (ic = env->flags & REG_ICASE)
Packit 992a25
				elements *= 2;
Packit 992a25
			if (!(e = node(env, REX_COLL_CLASS, 1, 1, (elements + 3) * sizeof(Celt_t))))
Packit 992a25
				return 0;
Packit 992a25
			ce = (Celt_t*)e->re.data;
Packit 992a25
			e->re.collate.invert = neg;
Packit 992a25
			e->re.collate.elements = ce;
Packit 992a25
			env->cursor = first;
Packit 992a25
			inrange = 0;
Packit 992a25
			for (;;)
Packit 992a25
			{
Packit 992a25
				if ((c = *env->cursor) == 0 || c == env->terminator || (env->flags & REG_ESCAPE) && c == env->delimiter)
Packit 992a25
					goto error;
Packit 992a25
				pp = env->cursor;
Packit 992a25
				env->cursor += (w = MBSIZE(env->cursor));
Packit 992a25
				if (c == '\\' && ((env->flags & REG_CLASS_ESCAPE) || *env->cursor == env->delimiter && (env->flags & REG_ESCAPE)))
Packit 992a25
				{
Packit 992a25
					if (*env->cursor)
Packit 992a25
					{
Packit 992a25
						if (*env->cursor == 'n')
Packit 992a25
						{
Packit 992a25
							pp = env->cursor++;
Packit 992a25
							c = '\n';
Packit 992a25
						}
Packit 992a25
						else if (env->type < SRE || !(env->flags & REG_SHELL_ESCAPED))
Packit 992a25
						{
Packit 992a25
							env->token.len = 1;
Packit 992a25
							w = magic(env, *env->cursor, 2);
Packit 992a25
							if (env->token.len > 1 || w != T_BAD)
Packit 992a25
							{
Packit 992a25
								if (env->token.len == 1 && (f = classfun(w)))
Packit 992a25
								{
Packit 992a25
									if (inrange > 1)
Packit 992a25
									{
Packit 992a25
										if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
											goto erange;
Packit 992a25
										inrange = 0;
Packit 992a25
									}
Packit 992a25
									env->cursor++;
Packit 992a25
									ce->fun = f;
Packit 992a25
									ce->typ = COLL_call;
Packit 992a25
									ce++;
Packit 992a25
									continue;
Packit 992a25
								}
Packit 992a25
								if (env->token.len > 1 || w >= 0 && w < T_META)
Packit 992a25
								{
Packit 992a25
									c = w;
Packit 992a25
									w = mbconv(mbc, c);
Packit 992a25
									pp = (unsigned char*)mbc;
Packit 992a25
									env->cursor += env->token.len;
Packit 992a25
								}
Packit 992a25
							}
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (c == ']')
Packit 992a25
				{
Packit 992a25
					if (env->cursor == begin)
Packit 992a25
					{
Packit 992a25
						rp = pp;
Packit 992a25
						rw = w;
Packit 992a25
						inrange = 1;
Packit 992a25
						continue;
Packit 992a25
					}
Packit 992a25
					if (inrange != 0)
Packit 992a25
					{
Packit 992a25
						ce = col(ce, ic, rp, rw, rc, NiL, 0, 0);
Packit 992a25
						if (inrange == 2)
Packit 992a25
							ce = col(ce, ic, NiL, 1, '-', NiL, 0, 0);
Packit 992a25
					}
Packit 992a25
					break;
Packit 992a25
				}
Packit 992a25
				else if (c == '-')
Packit 992a25
				{
Packit 992a25
					if (!inrange && env->cursor != begin && *env->cursor != ']')
Packit 992a25
					{
Packit 992a25
						if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
							goto erange;
Packit 992a25
						continue;
Packit 992a25
					}
Packit 992a25
					else if (inrange == 1)
Packit 992a25
					{
Packit 992a25
						inrange = 2;
Packit 992a25
						continue;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
				else if (c == '[')
Packit 992a25
				{
Packit 992a25
					switch (*env->cursor)
Packit 992a25
					{
Packit 992a25
					case 0:
Packit 992a25
						goto error;
Packit 992a25
					case ':':
Packit 992a25
						if (env->flags & REG_REGEXP)
Packit 992a25
							goto complicated_normal;
Packit 992a25
						if (inrange == 1)
Packit 992a25
							ce = col(ce, ic, rp, rw, rc, NiL, 0, 0);
Packit 992a25
						if (!(f = regclass((char*)env->cursor, (char**)&env->cursor)))
Packit 992a25
						{
Packit 992a25
							if (env->cursor == start && (c = *(env->cursor + 1)) && *(env->cursor + 2) == ':' && *(env->cursor + 3) == ']' && *(env->cursor + 4) == ']')
Packit 992a25
							{
Packit 992a25
								switch (c)
Packit 992a25
								{
Packit 992a25
								case '<':
Packit 992a25
									i = REX_WBEG;
Packit 992a25
									break;
Packit 992a25
								case '>':
Packit 992a25
									i = REX_WEND;
Packit 992a25
									break;
Packit 992a25
								default:
Packit 992a25
									i = 0;
Packit 992a25
									break;
Packit 992a25
								}
Packit 992a25
								if (i)
Packit 992a25
								{
Packit 992a25
									env->cursor += 5;
Packit 992a25
									drop(env->disc, e);
Packit 992a25
									return node(env, i, 0, 0, 0);
Packit 992a25
								}
Packit 992a25
							}
Packit 992a25
							env->error = REG_ECTYPE;
Packit 992a25
							goto error;
Packit 992a25
						}
Packit 992a25
						ce->fun = f;
Packit 992a25
						ce->typ = COLL_call;
Packit 992a25
						ce++;
Packit 992a25
						inrange = 0;
Packit 992a25
						continue;
Packit 992a25
					case '=':
Packit 992a25
						if (env->flags & REG_REGEXP)
Packit 992a25
							goto complicated_normal;
Packit 992a25
						if (inrange == 2)
Packit 992a25
							goto erange;
Packit 992a25
						if (inrange == 1)
Packit 992a25
							ce = col(ce, ic, rp, rw, rc, NiL, 0, 0);
Packit 992a25
						pp = (unsigned char*)cb[inrange];
Packit 992a25
						rp = env->cursor + 1;
Packit 992a25
						if ((rw = regcollate((char*)env->cursor, (char**)&env->cursor, (char*)pp, COLL_KEY_MAX, &wc)) < 0)
Packit 992a25
							goto ecollate;
Packit 992a25
						c = 0;
Packit 992a25
						if (ic)
Packit 992a25
						{
Packit 992a25
							if (iswupper(wc))
Packit 992a25
							{
Packit 992a25
								wc = towlower(wc);
Packit 992a25
								rw = mbconv((char*)pp, wc);
Packit 992a25
								c = 'u';
Packit 992a25
							}
Packit 992a25
							else if (iswlower(wc))
Packit 992a25
								c = 'l';
Packit 992a25
						}
Packit 992a25
						i = 1;
Packit 992a25
						for (;;)
Packit 992a25
						{
Packit 992a25
							mbxfrm(key.key, (char*)pp, COLL_KEY_MAX);
Packit 992a25
							if (!(cc = (Cchr_t*)dtsearch(dt, &key)) && !(cc = (Cchr_t*)dtprev(dt, &key)))
Packit 992a25
							{
Packit 992a25
								if (i)
Packit 992a25
								{
Packit 992a25
									c = *pp;
Packit 992a25
									goto singleton;
Packit 992a25
								}
Packit 992a25
								goto ecollate;
Packit 992a25
							}
Packit 992a25
							xc = (tc = (Cchr_t*)dtprev(dt, cc)) && !strcasecmp((char*)tc->nam, (char*)cc->nam) ? tc : cc;
Packit 992a25
							if (c == 'l' || c == 'L' && !(c = 0))
Packit 992a25
								ce->typ = COLL_range_lc;
Packit 992a25
							else if (c == 'u' || c == 'U' && !(c = 0))
Packit 992a25
								ce->typ = COLL_range_uc;
Packit 992a25
							else
Packit 992a25
								ce->typ = COLL_range;
Packit 992a25
							strcpy((char*)ce->beg, (char*)xc->key);
Packit 992a25
							if (!(cc = (Cchr_t*)dtnext(dt, cc)))
Packit 992a25
							{
Packit 992a25
								if (i)
Packit 992a25
								{
Packit 992a25
									c = *pp;
Packit 992a25
									goto singleton;
Packit 992a25
								}
Packit 992a25
								goto ecollate;
Packit 992a25
							}
Packit 992a25
							if (!strcasecmp((char*)xc->nam, (char*)cc->nam) && (tc = (Cchr_t*)dtnext(dt, cc)))
Packit 992a25
								cc = tc;
Packit 992a25
							strcpy((char*)ce->end, (char*)cc->key);
Packit 992a25
							ce->max = -1;
Packit 992a25
							ce++;
Packit 992a25
							if (!c)
Packit 992a25
								break;
Packit 992a25
							if (c == 'u')
Packit 992a25
							{
Packit 992a25
								wc = towlower(wc);
Packit 992a25
								c = 'L';
Packit 992a25
							}
Packit 992a25
							else
Packit 992a25
							{
Packit 992a25
								wc = towupper(wc);
Packit 992a25
								c = 'U';
Packit 992a25
							}
Packit 992a25
							rw = mbconv((char*)pp, wc);
Packit 992a25
							i = 0;
Packit 992a25
						}
Packit 992a25
						inrange = 0;
Packit 992a25
						c = *pp;
Packit 992a25
						continue;
Packit 992a25
					case '.':
Packit 992a25
						if (env->flags & REG_REGEXP)
Packit 992a25
							goto complicated_normal;
Packit 992a25
						pp = (unsigned char*)cb[inrange];
Packit 992a25
						if ((w = regcollate((char*)env->cursor, (char**)&env->cursor, (char*)pp, COLL_KEY_MAX, NiL)) < 0)
Packit 992a25
							goto ecollate;
Packit 992a25
						c = *pp;
Packit 992a25
						break;
Packit 992a25
					default:
Packit 992a25
					complicated_normal:
Packit 992a25
						if (*env->cursor == env->terminator || *env->cursor == env->delimiter && (env->flags & REG_ESCAPE))
Packit 992a25
							goto error;
Packit 992a25
						break;
Packit 992a25
					}
Packit 992a25
				}
Packit 992a25
			singleton:
Packit 992a25
				if (inrange == 2)
Packit 992a25
				{
Packit 992a25
					ce = col(ce, ic, rp, rw, rc, pp, w, c);
Packit 992a25
					if (strcmp((char*)ce->beg, (char*)ce->end) > 0)
Packit 992a25
					{
Packit 992a25
						if (env->type < SRE && !(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
							goto erange;
Packit 992a25
						(ce-1)->typ = COLL_char;
Packit 992a25
						strcpy((char*)ce->beg, (char*)(ce-1)->end);
Packit 992a25
						ce->typ = COLL_char;
Packit 992a25
						ce++;
Packit 992a25
					}
Packit 992a25
					inrange = env->type >= SRE || (env->flags & (REG_LENIENT|REG_REGEXP));
Packit 992a25
				}
Packit 992a25
				else if (inrange == 1)
Packit 992a25
					ce = col(ce, ic, rp, rw, rc, NiL, 0, 0);
Packit 992a25
				else
Packit 992a25
					inrange = 1;
Packit 992a25
				rp = pp;
Packit 992a25
				rw = w;
Packit 992a25
				rc = c;
Packit 992a25
			}
Packit 992a25
			ce->typ = COLL_end;
Packit 992a25
			return e;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
#endif
Packit 992a25
	if (collate)
Packit 992a25
		goto ecollate;
Packit 992a25
	if (env->flags & REG_ICASE)
Packit 992a25
		for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
			if (settst(e->re.charclass, i))
Packit 992a25
			{
Packit 992a25
				if (isupper(i))
Packit 992a25
					c = tolower(i);
Packit 992a25
				else if (islower(i))
Packit 992a25
					c = toupper(i);
Packit 992a25
				else
Packit 992a25
					continue;
Packit 992a25
				setadd(e->re.charclass, c);
Packit 992a25
			}
Packit 992a25
	if (neg)
Packit 992a25
	{
Packit 992a25
		for (i = 0; i < elementsof(e->re.charclass->bits); i++)
Packit 992a25
			e->re.charclass->bits[i] ^= ~0;
Packit 992a25
		if (env->explicit >= 0)
Packit 992a25
			setclr(e->re.charclass, env->explicit);
Packit 992a25
	}
Packit 992a25
	return e;
Packit 992a25
 ecollate:
Packit 992a25
	env->error = REG_ECOLLATE;
Packit 992a25
	goto error;
Packit 992a25
 erange:
Packit 992a25
	env->error = REG_ERANGE;
Packit 992a25
 error:
Packit 992a25
	drop(env->disc, e);
Packit 992a25
	if (!env->error)
Packit 992a25
		env->error = REG_EBRACK;
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
ccl(Cenv_t* env, int type)
Packit 992a25
{
Packit 992a25
	int		i;
Packit 992a25
	Rex_t*		e;
Packit 992a25
	Celt_t*		ce;
Packit 992a25
	regclass_t	f;
Packit 992a25
Packit 992a25
	if (!(f = classfun(type)))
Packit 992a25
	{
Packit 992a25
		env->error = REG_BADESC;
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	if (!mbcoll())
Packit 992a25
	{
Packit 992a25
		if (!(e = node(env, REX_CLASS, 1, 1, sizeof(Set_t))))
Packit 992a25
			return 0;
Packit 992a25
		for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
			if ((*f)(i))
Packit 992a25
				setadd(e->re.charclass, i);
Packit 992a25
		if (env->explicit >= 0)
Packit 992a25
			setclr(e->re.charclass, env->explicit);
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		if (!(e = node(env, REX_COLL_CLASS, 1, 1, 2 * sizeof(Celt_t))))
Packit 992a25
			return 0;
Packit 992a25
		ce = (Celt_t*)e->re.data;
Packit 992a25
		e->re.collate.invert = 0;
Packit 992a25
		e->re.collate.elements = ce;
Packit 992a25
		ce->fun = f;
Packit 992a25
		ce->typ = COLL_call;
Packit 992a25
		ce++;
Packit 992a25
		ce->typ = COLL_end;
Packit 992a25
	}
Packit 992a25
	return e;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
rep(Cenv_t* env, Rex_t* e, int number, int last)
Packit 992a25
{
Packit 992a25
	Rex_t*		f;
Packit 992a25
	unsigned long	m = 0;
Packit 992a25
	unsigned long	n = RE_DUP_INF;
Packit 992a25
	int		minimal = -1;
Packit 992a25
Packit 992a25
	if (!e)
Packit 992a25
		return 0;
Packit 992a25
	switch (token(env))
Packit 992a25
	{
Packit 992a25
	case T_BANG:
Packit 992a25
		eat(env);
Packit 992a25
		if (!(f = node(env, REX_NEG, m, n, 0)))
Packit 992a25
		{
Packit 992a25
			drop(env->disc, e);
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		f->re.group.expr.rex = e;
Packit 992a25
		return f;
Packit 992a25
	case T_QUES:
Packit 992a25
		eat(env);
Packit 992a25
		n = 1;
Packit 992a25
		break;
Packit 992a25
	case T_STAR:
Packit 992a25
		eat(env);
Packit 992a25
		break;
Packit 992a25
	case T_PLUS:
Packit 992a25
		eat(env);
Packit 992a25
		m = 1;
Packit 992a25
		break;
Packit 992a25
	case T_LEFT:
Packit 992a25
		eat(env);
Packit 992a25
		m = env->token.min;
Packit 992a25
		n = env->token.max;
Packit 992a25
		break;
Packit 992a25
	default:
Packit 992a25
		return e;
Packit 992a25
	}
Packit 992a25
	if (env->token.att)
Packit 992a25
		minimal = 1;
Packit 992a25
	else if (env->type < SRE)
Packit 992a25
		switch (token(env))
Packit 992a25
		{
Packit 992a25
		case T_QUES:
Packit 992a25
			eat(env);
Packit 992a25
			minimal = !(env->flags & REG_MINIMAL);
Packit 992a25
			break;
Packit 992a25
		case T_STAR: /*AST*/
Packit 992a25
			eat(env);
Packit 992a25
			minimal = !!(env->flags & REG_MINIMAL);
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
	switch (e->type)
Packit 992a25
	{
Packit 992a25
	case REX_DOT:
Packit 992a25
	case REX_CLASS:
Packit 992a25
	case REX_COLL_CLASS:
Packit 992a25
	case REX_ONECHAR:
Packit 992a25
		e->lo = m;
Packit 992a25
		e->hi = n;
Packit 992a25
		if (minimal >= 0)
Packit 992a25
			mark(e, minimal);
Packit 992a25
		return e;
Packit 992a25
#if HUH_2002_08_07
Packit 992a25
	case REX_BEG:
Packit 992a25
#endif
Packit 992a25
	case REX_BEG_STR:
Packit 992a25
	case REX_END_STR:
Packit 992a25
	case REX_FIN_STR:
Packit 992a25
	case REX_WBEG:
Packit 992a25
	case REX_WEND:
Packit 992a25
	case REX_WORD:
Packit 992a25
	case REX_WORD_NOT:
Packit 992a25
		env->error = REG_BADRPT;
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	if (m == 1 && n == 1)
Packit 992a25
	{
Packit 992a25
		if (minimal >= 0)
Packit 992a25
			mark(e, minimal);
Packit 992a25
		return e;
Packit 992a25
	}
Packit 992a25
	if (!(f = node(env, REX_REP, m, n, 0)))
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	f->re.group.expr.rex = e;
Packit 992a25
	f->re.group.number = number;
Packit 992a25
	f->re.group.last = last;
Packit 992a25
	if (minimal >= 0)
Packit 992a25
		mark(f, minimal);
Packit 992a25
	if (m <= n && n)
Packit 992a25
	{
Packit 992a25
		for (; e && e->type >= REX_GROUP && e->type <= REX_GROUP_CUT; e = e->re.group.expr.rex);
Packit 992a25
		if (e && e->type == REX_NEG)
Packit 992a25
			f->type = REX_GROUP;
Packit 992a25
	}
Packit 992a25
	return f;
Packit 992a25
}
Packit 992a25
Packit 992a25
static int
Packit 992a25
isstring(Rex_t* e)
Packit 992a25
{
Packit 992a25
	switch (e->type)
Packit 992a25
	{
Packit 992a25
	case REX_ONECHAR:
Packit 992a25
		return e->lo == 1 && e->hi == 1;
Packit 992a25
	case REX_STRING:
Packit 992a25
		return 1;
Packit 992a25
	}
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Trie_node_t*
Packit 992a25
trienode(Cenv_t* env, int c)
Packit 992a25
{
Packit 992a25
	Trie_node_t*	t;
Packit 992a25
Packit 992a25
	if (t = (Trie_node_t*)alloc(env->disc, 0, sizeof(Trie_node_t)))
Packit 992a25
	{
Packit 992a25
		memset(t, 0, sizeof(Trie_node_t));
Packit 992a25
		t->c = c;
Packit 992a25
	}
Packit 992a25
	return t;
Packit 992a25
}
Packit 992a25
Packit 992a25
static int
Packit 992a25
insert(Cenv_t* env, Rex_t* f, Rex_t* g)
Packit 992a25
{
Packit 992a25
	unsigned char*	s;
Packit 992a25
	unsigned char*	e;
Packit 992a25
	Trie_node_t*	t;
Packit 992a25
	int		len;
Packit 992a25
	unsigned char	tmp[2];
Packit 992a25
Packit 992a25
	switch (f->type)
Packit 992a25
	{
Packit 992a25
	case REX_ONECHAR:
Packit 992a25
		*(s = tmp) = f->re.onechar;
Packit 992a25
		e = s + 1;
Packit 992a25
		break;
Packit 992a25
	case REX_STRING:
Packit 992a25
		s = f->re.string.base;
Packit 992a25
		e = s + f->re.string.size;
Packit 992a25
		break;
Packit 992a25
	default:
Packit 992a25
		return 1;
Packit 992a25
	}
Packit 992a25
	if (!(t = g->re.trie.root[*s]) && !(t = g->re.trie.root[*s] = trienode(env, *s)))
Packit 992a25
		return 1;
Packit 992a25
	for (len = 1;;)
Packit 992a25
	{
Packit 992a25
		if (t->c == *s)
Packit 992a25
		{
Packit 992a25
			if (++s >= e)
Packit 992a25
				break;
Packit 992a25
			if (!t->son && !(t->son = trienode(env, *s)))
Packit 992a25
				return 1;
Packit 992a25
			t = t->son;
Packit 992a25
			len++;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			if (!t->sib && !(t->sib = trienode(env, *s)))
Packit 992a25
				return 1;
Packit 992a25
			t = t->sib;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	if (g->re.trie.min > len)
Packit 992a25
		g->re.trie.min = len;
Packit 992a25
	if (g->re.trie.max < len)
Packit 992a25
		g->re.trie.max = len;
Packit 992a25
	t->end = 1;
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * trie() tries to combine nontrivial e and f into a REX_TRIE
Packit 992a25
 * unless 0 is returned, e and f are deleted as far as possible
Packit 992a25
 * also called by regcomb
Packit 992a25
 */
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
trie(Cenv_t* env, Rex_t* e, Rex_t* f)
Packit 992a25
{
Packit 992a25
	Rex_t*	g;
Packit 992a25
Packit 992a25
	if (e->next || f->next || !isstring(e) || e->flags != f->flags)
Packit 992a25
		return 0;
Packit 992a25
	if (isstring(f))
Packit 992a25
	{
Packit 992a25
		if (!(g = node(env, REX_TRIE, 0, 0, (UCHAR_MAX + 1) * sizeof(Trie_node_t*))))
Packit 992a25
			return 0;
Packit 992a25
		g->re.trie.min = INT_MAX;
Packit 992a25
		if (insert(env, f, g))
Packit 992a25
			goto nospace;
Packit 992a25
		drop(env->disc, f);
Packit 992a25
	}
Packit 992a25
	else if (f->type != REX_TRIE)
Packit 992a25
		return 0;
Packit 992a25
	else
Packit 992a25
		g = f;
Packit 992a25
	if (insert(env, e, g))
Packit 992a25
		goto nospace;
Packit 992a25
	drop(env->disc, e);
Packit 992a25
	return g;
Packit 992a25
 nospace:
Packit 992a25
	if (g != f)
Packit 992a25
		drop(env->disc, g);
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*		alt(Cenv_t*, int, int);
Packit 992a25
Packit 992a25
static int
Packit 992a25
chr(register Cenv_t* env, int* escaped)
Packit 992a25
{
Packit 992a25
	unsigned char*	p;
Packit 992a25
	int		c;
Packit 992a25
Packit 992a25
	*escaped = 0;
Packit 992a25
	if (!(c = *env->cursor))
Packit 992a25
		return -1;
Packit 992a25
	env->cursor++;
Packit 992a25
	if (c == '\\')
Packit 992a25
	{
Packit 992a25
		if (env->flags & REG_SHELL_ESCAPED)
Packit 992a25
			return c;
Packit 992a25
		if (!(c = *(env->cursor + 1)) || c == env->terminator)
Packit 992a25
		{
Packit 992a25
			if (env->flags & (REG_LENIENT|REG_REGEXP))
Packit 992a25
				return c ? c : '\\';
Packit 992a25
			env->error = REG_EESCAPE;
Packit 992a25
			return -1;
Packit 992a25
		}
Packit 992a25
		p = env->cursor;
Packit 992a25
		c = chresc((char*)env->cursor - 1, (char**)&env->cursor);
Packit 992a25
		*escaped = env->cursor - p;
Packit 992a25
	}
Packit 992a25
	return c;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * open the perly gates
Packit 992a25
 */
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
grp(Cenv_t* env, int parno)
Packit 992a25
{
Packit 992a25
	Rex_t*		e;
Packit 992a25
	Rex_t*		f;
Packit 992a25
	int		c;
Packit 992a25
	int		g;
Packit 992a25
	int		i;
Packit 992a25
	int		n;
Packit 992a25
	int		x;
Packit 992a25
	int		esc;
Packit 992a25
	int		typ;
Packit 992a25
	int		beg;
Packit 992a25
	unsigned char*	p;
Packit 992a25
Packit 992a25
	g = env->flags;
Packit 992a25
	beg = env->pattern == env->cursor - env->token.len;
Packit 992a25
	if (!(c = env->token.lex) && (c = *env->cursor))
Packit 992a25
		env->cursor++;
Packit 992a25
	env->token.len = 0;
Packit 992a25
	env->parnest++;
Packit 992a25
	typ = -1;
Packit 992a25
	switch (c)
Packit 992a25
	{
Packit 992a25
	case '-':
Packit 992a25
	case '+':
Packit 992a25
	case 'a':
Packit 992a25
	case 'g':
Packit 992a25
	case 'i':
Packit 992a25
	case 'l':
Packit 992a25
	case 'm':
Packit 992a25
	case 'p':
Packit 992a25
	case 'r':
Packit 992a25
	case 's':
Packit 992a25
	case 'x':
Packit 992a25
	case 'A':
Packit 992a25
	case 'B':
Packit 992a25
	case 'E':
Packit 992a25
	case 'F':
Packit 992a25
	case 'G':
Packit 992a25
	case 'I':
Packit 992a25
	case 'K':
Packit 992a25
	case 'L':
Packit 992a25
	case 'M':	/* glob(3) */
Packit 992a25
	case 'N':	/* glob(3) */
Packit 992a25
	case 'O':	/* glob(3) */
Packit 992a25
	case 'P':
Packit 992a25
	case 'R':	/* pcre */
Packit 992a25
	case 'S':
Packit 992a25
	case 'U':	/* pcre */
Packit 992a25
	case 'V':
Packit 992a25
	case 'X':	/* pcre */
Packit 992a25
		x = REX_GROUP;
Packit 992a25
		i = 1;
Packit 992a25
		env->token.push = 1;
Packit 992a25
		for (;;)
Packit 992a25
		{
Packit 992a25
			switch (c)
Packit 992a25
			{
Packit 992a25
			case ')':
Packit 992a25
				if (!(env->flags & REG_LITERAL))
Packit 992a25
				{
Packit 992a25
					env->error = REG_BADRPT;
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				/*FALLTHROUGH*/
Packit 992a25
			case 0:
Packit 992a25
			case T_CLOSE:
Packit 992a25
				x = 0;
Packit 992a25
				goto done;
Packit 992a25
			case ':':
Packit 992a25
				eat(env);
Packit 992a25
				if (token(env) == T_CLOSE)
Packit 992a25
					x = 0;
Packit 992a25
				goto done;
Packit 992a25
			case '-':
Packit 992a25
				i = 0;
Packit 992a25
				break;
Packit 992a25
			case '+':
Packit 992a25
				i = 1;
Packit 992a25
				break;
Packit 992a25
			case 'a':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= (REG_LEFT|REG_RIGHT);
Packit 992a25
				else
Packit 992a25
					env->flags &= ~(REG_LEFT|REG_RIGHT);
Packit 992a25
				break;
Packit 992a25
			case 'g':
Packit 992a25
				if (i)
Packit 992a25
					env->flags &= ~REG_MINIMAL;
Packit 992a25
				else
Packit 992a25
					env->flags |= REG_MINIMAL;
Packit 992a25
				break;
Packit 992a25
			case 'i':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_ICASE;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_ICASE;
Packit 992a25
				break;
Packit 992a25
			case 'l':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_LEFT;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_LEFT;
Packit 992a25
				break;
Packit 992a25
			case 'm':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_NEWLINE;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_NEWLINE;
Packit 992a25
				env->explicit = (env->flags & (REG_NEWLINE|REG_SPAN)) == REG_NEWLINE ? env->mappednewline : -1;
Packit 992a25
				break;
Packit 992a25
			case 'p':
Packit 992a25
				if (i)
Packit 992a25
					env->flags &= ~REG_LENIENT;
Packit 992a25
				else
Packit 992a25
					env->flags |= REG_LENIENT;
Packit 992a25
				break;
Packit 992a25
			case 'r':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_RIGHT;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_RIGHT;
Packit 992a25
				break;
Packit 992a25
			case 's':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_SPAN;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_SPAN;
Packit 992a25
				env->explicit = (env->flags & (REG_NEWLINE|REG_SPAN)) == REG_NEWLINE ? env->mappednewline : -1;
Packit 992a25
				break;
Packit 992a25
			case 'x':
Packit 992a25
				if (i)
Packit 992a25
					env->flags |= REG_COMMENT;
Packit 992a25
				else
Packit 992a25
					env->flags &= ~REG_COMMENT;
Packit 992a25
				break;
Packit 992a25
			case 'X':
Packit 992a25
				if (typ >= 0 || env->type == ERE && (env->flags & REG_CLASS_ESCAPE))
Packit 992a25
					break; /* PCRE_EXTRA */
Packit 992a25
				/*FALLTHROUGH*/
Packit 992a25
			case 'A':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_AUGMENTED|REG_EXTENDED;
Packit 992a25
				typ = ARE;
Packit 992a25
				break;
Packit 992a25
			case 'B':
Packit 992a25
			case 'G':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				typ = BRE;
Packit 992a25
				break;
Packit 992a25
			case 'E':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_EXTENDED;
Packit 992a25
				typ = ERE;
Packit 992a25
				break;
Packit 992a25
			case 'F':
Packit 992a25
			case 'L':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_LITERAL;
Packit 992a25
				typ = ERE;
Packit 992a25
				break;
Packit 992a25
			case 'K':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_AUGMENTED|REG_SHELL|REG_LEFT|REG_RIGHT;
Packit 992a25
				typ = KRE;
Packit 992a25
				break;
Packit 992a25
			case 'M':
Packit 992a25
				/* used by caller to disable glob(3) GLOB_BRACE */
Packit 992a25
				break;
Packit 992a25
			case 'N':
Packit 992a25
				/* used by caller to disable glob(3) GLOB_NOCHECK */
Packit 992a25
				break;
Packit 992a25
			case 'O':
Packit 992a25
				/* used by caller to disable glob(3) GLOB_STARSTAR */
Packit 992a25
				break;
Packit 992a25
			case 'P':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_EXTENDED|REG_CLASS_ESCAPE;
Packit 992a25
				typ = ERE;
Packit 992a25
				break;
Packit 992a25
			case 'S':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_SHELL|REG_LEFT|REG_RIGHT;
Packit 992a25
				typ = SRE;
Packit 992a25
				break;
Packit 992a25
			case 'U': /* PCRE_UNGREEDY */
Packit 992a25
				if (typ >= 0 || env->type == ERE && (env->flags & REG_CLASS_ESCAPE))
Packit 992a25
				{
Packit 992a25
					if (i)
Packit 992a25
						env->flags |= REG_MINIMAL;
Packit 992a25
					else
Packit 992a25
						env->flags &= ~REG_MINIMAL;
Packit 992a25
				}
Packit 992a25
				break;
Packit 992a25
			case 'V':
Packit 992a25
				env->flags &= ~(REG_AUGMENTED|REG_EXTENDED|REG_LITERAL|REG_REGEXP|REG_SHELL|REG_LEFT|REG_RIGHT);
Packit 992a25
				env->flags |= REG_REGEXP;
Packit 992a25
				typ = BRE;
Packit 992a25
				break;
Packit 992a25
			default:
Packit 992a25
				env->error = REG_BADRPT;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			eat(env);
Packit 992a25
			c = token(env);
Packit 992a25
		}
Packit 992a25
	done:
Packit 992a25
		break;
Packit 992a25
	case ':':
Packit 992a25
		x = REX_GROUP;
Packit 992a25
		break;
Packit 992a25
	case '=':
Packit 992a25
		x = REX_GROUP_AHEAD;
Packit 992a25
		break;
Packit 992a25
	case '!':
Packit 992a25
		x = REX_GROUP_AHEAD_NOT;
Packit 992a25
		break;
Packit 992a25
	case '<':
Packit 992a25
		switch (token(env))
Packit 992a25
		{
Packit 992a25
		case '=':
Packit 992a25
			x = REX_GROUP_BEHIND;
Packit 992a25
			break;
Packit 992a25
		case '!':
Packit 992a25
		case T_BANG:
Packit 992a25
			x = REX_GROUP_BEHIND_NOT;
Packit 992a25
			break;
Packit 992a25
		default:
Packit 992a25
			env->error = REG_BADRPT;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		eat(env);
Packit 992a25
		break;
Packit 992a25
	case '>':
Packit 992a25
		x = REX_GROUP_CUT;
Packit 992a25
		break;
Packit 992a25
	case '%':
Packit 992a25
	case T_PERCENT:
Packit 992a25
		e = node(env, REX_NEST, 0, 0, (UCHAR_MAX + 1) * sizeof(unsigned short));
Packit 992a25
		e->re.nest.primary = isalnum(*env->cursor) ? -1 : *env->cursor;
Packit 992a25
		n = 1;
Packit 992a25
		for (;;)
Packit 992a25
		{
Packit 992a25
			switch (i = chr(env, &esc))
Packit 992a25
			{
Packit 992a25
			case -1:
Packit 992a25
			case 0:
Packit 992a25
			invalid:
Packit 992a25
				env->cursor -= esc + 1;
Packit 992a25
				env->error = REG_EPAREN;
Packit 992a25
				return 0;
Packit 992a25
			case 'D':
Packit 992a25
				x = REX_NEST_delimiter;
Packit 992a25
				/*FALLTHROUGH*/
Packit 992a25
			delimiter:
Packit 992a25
				if ((i = chr(env, &esc)) < 0)
Packit 992a25
					goto invalid;
Packit 992a25
				if (e->re.nest.type[i] & ~x)
Packit 992a25
					goto invalid;
Packit 992a25
				e->re.nest.type[i] = x;
Packit 992a25
				continue;
Packit 992a25
			case 'E':
Packit 992a25
				x = REX_NEST_escape;
Packit 992a25
				goto delimiter;
Packit 992a25
			case 'L':
Packit 992a25
				x = REX_NEST_literal;
Packit 992a25
				goto quote;
Packit 992a25
			case 'O':
Packit 992a25
				switch (i = chr(env, &esc))
Packit 992a25
				{
Packit 992a25
				case 'T':
Packit 992a25
					e->re.nest.type[UCHAR_MAX+1] |= REX_NEST_terminator;
Packit 992a25
					break;
Packit 992a25
				default:
Packit 992a25
					goto invalid;
Packit 992a25
				}
Packit 992a25
				continue;
Packit 992a25
			case 'Q':
Packit 992a25
				x = REX_NEST_quote;
Packit 992a25
				/*FALLTHROUGH*/
Packit 992a25
			quote:
Packit 992a25
				if ((i = chr(env, &esc)) < 0)
Packit 992a25
					goto invalid;
Packit 992a25
				if (e->re.nest.type[i] & ~x)
Packit 992a25
					goto invalid;
Packit 992a25
				e->re.nest.type[i] = x|REX_NEST_open|REX_NEST_close|(i<
Packit 992a25
				continue;
Packit 992a25
			case 'S':
Packit 992a25
				x = REX_NEST_separator;
Packit 992a25
				goto delimiter;
Packit 992a25
			case 'T':
Packit 992a25
				x = REX_NEST_terminator;
Packit 992a25
				goto delimiter;
Packit 992a25
			case '|':
Packit 992a25
			case '&':
Packit 992a25
				if (!esc)
Packit 992a25
					goto invalid;
Packit 992a25
				goto nesting;
Packit 992a25
			case '(':
Packit 992a25
				if (!esc)
Packit 992a25
					n++;
Packit 992a25
				goto nesting;
Packit 992a25
			case ')':
Packit 992a25
				if (!esc && !--n)
Packit 992a25
					break;
Packit 992a25
				goto nesting;
Packit 992a25
			default:
Packit 992a25
			nesting:
Packit 992a25
				if (isalnum(i) || (e->re.nest.type[i] & (REX_NEST_close|REX_NEST_escape|REX_NEST_literal|REX_NEST_quote|REX_NEST_delimiter|REX_NEST_separator|REX_NEST_terminator)))
Packit 992a25
					goto invalid;
Packit 992a25
				e->re.nest.type[i] = REX_NEST_open;
Packit 992a25
				if ((x = chr(env, &esc)) < 0 || (e->re.nest.type[x] & (REX_NEST_close|REX_NEST_escape|REX_NEST_delimiter|REX_NEST_separator|REX_NEST_terminator)))
Packit 992a25
					goto invalid;
Packit 992a25
				if (!esc)
Packit 992a25
				{
Packit 992a25
					if (x == ')' && !--n)
Packit 992a25
						goto invalid;
Packit 992a25
					else if (x == '(')
Packit 992a25
						n++;
Packit 992a25
				}
Packit 992a25
				e->re.nest.type[x] |= REX_NEST_close;
Packit 992a25
				e->re.nest.type[i] |= x << REX_NEST_SHIFT;
Packit 992a25
				continue;
Packit 992a25
			}
Packit 992a25
			break;
Packit 992a25
		}
Packit 992a25
		env->parnest--;
Packit 992a25
		if (c == T_PERCENT)
Packit 992a25
			for (n = 0; n < 2; n++)
Packit 992a25
			{
Packit 992a25
				parno = ++env->parno;
Packit 992a25
				if (!(f = node(env, REX_GROUP, 0, 0, 0)))
Packit 992a25
				{
Packit 992a25
					drop(env->disc, e);
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				if (parno < elementsof(env->paren))
Packit 992a25
					env->paren[parno] = f;
Packit 992a25
				f->re.group.back = 0;
Packit 992a25
				f->re.group.number = parno;
Packit 992a25
				f->re.group.expr.rex = e;
Packit 992a25
				e = f;
Packit 992a25
			}
Packit 992a25
		return e;
Packit 992a25
	case '(':
Packit 992a25
		c = 0;
Packit 992a25
		if (isdigit(*env->cursor))
Packit 992a25
		{
Packit 992a25
			f = 0;
Packit 992a25
			do
Packit 992a25
			{
Packit 992a25
				if (c > (INT_MAX / 10))
Packit 992a25
				{
Packit 992a25
					env->error = REG_BADRPT;
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				c = c * 10 + (*env->cursor++ - '0');
Packit 992a25
			} while (isdigit(*env->cursor));
Packit 992a25
			if (*env->cursor++ != ')')
Packit 992a25
			{
Packit 992a25
				env->error = REG_BADRPT;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			if (c && env->type >= SRE)
Packit 992a25
				c = c * 2 - 1;
Packit 992a25
			if (!c || c > env->parno || !env->paren[c])
Packit 992a25
			{
Packit 992a25
				if (!(env->flags & (REG_LENIENT|REG_REGEXP)))
Packit 992a25
				{
Packit 992a25
					env->error = REG_ESUBREG;
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				if (c)
Packit 992a25
					c = -1;
Packit 992a25
			}
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
		{
Packit 992a25
			if (env->type < SRE && *env->cursor++ != '?')
Packit 992a25
			{
Packit 992a25
				env->error = REG_BADRPT;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			if (!(f = grp(env, parno + 1)) && env->error)
Packit 992a25
				return 0;
Packit 992a25
		}
Packit 992a25
		if (!(e = node(env, REX_GROUP_COND, 0, 0, 0)))
Packit 992a25
		{
Packit 992a25
			drop(env->disc, f);
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		e->re.group.size = c;
Packit 992a25
		e->re.group.expr.binary.left = f;
Packit 992a25
		if (!(e->re.group.expr.binary.right = alt(env, parno, 1)))
Packit 992a25
		{
Packit 992a25
			drop(env->disc, e);
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		if (token(env) != T_CLOSE)
Packit 992a25
		{
Packit 992a25
			env->error = REG_EPAREN;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		eat(env);
Packit 992a25
		env->parnest--;
Packit 992a25
		return rep(env, e, parno, parno);
Packit 992a25
	case '{':
Packit 992a25
		p = env->cursor;
Packit 992a25
		n = 1;
Packit 992a25
		while (c = *env->cursor)
Packit 992a25
		{
Packit 992a25
			if (c == '\\' && *(env->cursor + 1))
Packit 992a25
				env->cursor++;
Packit 992a25
			else if (c == '{')
Packit 992a25
				n++;
Packit 992a25
			else if (c == '}' && !--n)
Packit 992a25
				break;
Packit 992a25
			else if (c == env->delimiter || c == env->terminator)
Packit 992a25
				break;
Packit 992a25
			env->cursor++;
Packit 992a25
		}
Packit 992a25
		if (c != '}')
Packit 992a25
		{
Packit 992a25
			env->error = REG_EBRACE;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		if (*++env->cursor != ')')
Packit 992a25
		{
Packit 992a25
			env->error = REG_EPAREN;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		env->cursor++;
Packit 992a25
		env->parnest--;
Packit 992a25
		if (env->disc->re_version < REG_VERSION_EXEC)
Packit 992a25
		{
Packit 992a25
			env->error = REG_BADRPT;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		if (!env->disc->re_execf)
Packit 992a25
			return 0;
Packit 992a25
		if (!(e = node(env, REX_EXEC, 0, 0, 0)))
Packit 992a25
			return 0;
Packit 992a25
		e->re.exec.text = (const char*)p;
Packit 992a25
		e->re.exec.size = env->cursor - p - 2;
Packit 992a25
		if (!env->disc->re_compf)
Packit 992a25
			e->re.exec.data = 0;
Packit 992a25
		else
Packit 992a25
			e->re.exec.data = (*env->disc->re_compf)(env->regex, e->re.exec.text, e->re.exec.size, env->disc);
Packit 992a25
		return e;
Packit 992a25
	case '0': case '1': case '2': case '3': case '4':
Packit 992a25
	case '5': case '6': case '7': case '8': case '9':
Packit 992a25
		c -= '0';
Packit 992a25
		while (isdigit(*env->cursor))
Packit 992a25
		{
Packit 992a25
			if (c > (INT_MAX / 10))
Packit 992a25
			{
Packit 992a25
				env->error = REG_ESUBREG;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			c = c * 10 + *env->cursor++ - '0';
Packit 992a25
		}
Packit 992a25
		if (*env->cursor == ')')
Packit 992a25
		{
Packit 992a25
			env->cursor++;
Packit 992a25
			env->parnest--;
Packit 992a25
			env->token.len = 1;
Packit 992a25
			if (c > env->parno || !env->paren[c])
Packit 992a25
			{
Packit 992a25
				env->error = REG_ESUBREG;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			env->paren[c]->re.group.back = 1;
Packit 992a25
			return rep(env, node(env, REX_BACK, c, 0, 0), 0, 0);
Packit 992a25
		}
Packit 992a25
		/*FALLTHROUGH*/
Packit 992a25
	default:
Packit 992a25
		env->error = REG_BADRPT;
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	p = env->pattern;
Packit 992a25
	i = env->type;
Packit 992a25
	if (x)
Packit 992a25
	{
Packit 992a25
		if (typ >= 0)
Packit 992a25
			env->type = typ;
Packit 992a25
		if (!(e = alt(env, parno, 0)))
Packit 992a25
			goto nope;
Packit 992a25
		env->flags = g;
Packit 992a25
		env->type = i;
Packit 992a25
	}
Packit 992a25
	c = token(env);
Packit 992a25
	env->parnest--;
Packit 992a25
	if (c != T_CLOSE && (!(env->flags & REG_LITERAL) || c != ')'))
Packit 992a25
	{
Packit 992a25
		env->error = REG_EPAREN;
Packit 992a25
		goto nope;
Packit 992a25
	}
Packit 992a25
	eat(env);
Packit 992a25
	if (typ >= 0 && beg)
Packit 992a25
		env->pattern = env->cursor;
Packit 992a25
	if (!x)
Packit 992a25
	{
Packit 992a25
		if (typ >= 0)
Packit 992a25
			env->type = typ;
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	if (!(f = node(env, x, 0, 0, 0)))
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		goto nope;
Packit 992a25
	}
Packit 992a25
	f->re.group.expr.rex = e;
Packit 992a25
	if (x == REX_GROUP_BEHIND || x == REX_GROUP_BEHIND_NOT)
Packit 992a25
	{
Packit 992a25
		if (stats(env, e))
Packit 992a25
		{
Packit 992a25
			drop(env->disc, f);
Packit 992a25
			if (!env->error)
Packit 992a25
				env->error = REG_ECOUNT;
Packit 992a25
			goto nope;
Packit 992a25
		}
Packit 992a25
		f->re.group.size = env->stats.m;
Packit 992a25
		memset(&env->stats, 0, sizeof(env->stats));
Packit 992a25
	}
Packit 992a25
	switch (x)
Packit 992a25
	{
Packit 992a25
	case REX_GROUP:
Packit 992a25
	case REX_GROUP_CUT:
Packit 992a25
		f = rep(env, f, parno, env->parno);
Packit 992a25
		break;
Packit 992a25
	}
Packit 992a25
	if (f)
Packit 992a25
		return f;
Packit 992a25
 nope:
Packit 992a25
	env->flags = g;
Packit 992a25
	env->pattern = p;
Packit 992a25
	env->type = i;
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
seq(Cenv_t* env)
Packit 992a25
{
Packit 992a25
	Rex_t*		e;
Packit 992a25
	Rex_t*		f;
Packit 992a25
	Token_t		tok;
Packit 992a25
	int		c;
Packit 992a25
	int		i;
Packit 992a25
	int		n;
Packit 992a25
	int		x;
Packit 992a25
	int		parno;
Packit 992a25
	int		type;
Packit 992a25
	regflags_t	flags;
Packit 992a25
	unsigned char*	s;
Packit 992a25
	unsigned char*	p;
Packit 992a25
	unsigned char*	t;
Packit 992a25
	unsigned char*	u;
Packit 992a25
	unsigned char	buf[256];
Packit 992a25
Packit 992a25
	for (;;)
Packit 992a25
	{
Packit 992a25
		s = buf;
Packit 992a25
		while ((c = token(env)) < T_META && s < &buf[sizeof(buf) - env->token.len])
Packit 992a25
		{	
Packit 992a25
			x = c;
Packit 992a25
			p = env->cursor;
Packit 992a25
			if (c >= 0)
Packit 992a25
			{
Packit 992a25
				n = 1;
Packit 992a25
				*s++ = (env->flags & REG_ICASE) ? toupper(c) : c;
Packit 992a25
			}
Packit 992a25
			else if (c == C_ESC || (env->flags & REG_ICASE))
Packit 992a25
			{
Packit 992a25
				c = (c == C_ESC) ? env->token.lex : mbchar(p);
Packit 992a25
				if (env->flags & REG_ICASE)
Packit 992a25
					c = towupper(c);
Packit 992a25
				if ((&buf[sizeof(buf)] - s) < MB_CUR_MAX)
Packit 992a25
					break;
Packit 992a25
				if ((n = mbconv((char*)s, c)) < 0)
Packit 992a25
					*s++ = c;
Packit 992a25
				else if (n)
Packit 992a25
					s += n;
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					n = 1;
Packit 992a25
					*s++ = 0;
Packit 992a25
				}
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				n = env->token.len - env->token.esc;
Packit 992a25
				for (t = p, u = s + n; s < u; *s++ = *t++);
Packit 992a25
			}
Packit 992a25
			eat(env);
Packit 992a25
		}
Packit 992a25
		if (c == T_BAD)
Packit 992a25
			return 0;
Packit 992a25
		if (s > buf)
Packit 992a25
			switch (c)
Packit 992a25
			{
Packit 992a25
			case T_STAR:
Packit 992a25
			case T_PLUS:
Packit 992a25
			case T_LEFT:
Packit 992a25
			case T_QUES:
Packit 992a25
			case T_BANG:
Packit 992a25
				if ((s -= n) == buf)
Packit 992a25
					e = 0;
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					i = s - buf;
Packit 992a25
					if (!(e = node(env, REX_STRING, 0, 0, i)))
Packit 992a25
						return 0;
Packit 992a25
					memcpy((char*)(e->re.string.base = (unsigned char*)e->re.data), (char*)buf, i);
Packit 992a25
					e->re.string.size = i;
Packit 992a25
				}
Packit 992a25
				if (x >= 0)
Packit 992a25
				{
Packit 992a25
					if (!(f = node(env, REX_ONECHAR, 1, 1, 0)))
Packit 992a25
					{
Packit 992a25
						drop(env->disc, e);
Packit 992a25
						return 0;
Packit 992a25
					}
Packit 992a25
					f->re.onechar = (env->flags & REG_ICASE) ? toupper(x) : x;
Packit 992a25
				}
Packit 992a25
				else
Packit 992a25
				{
Packit 992a25
					if (!(f = node(env, REX_STRING, 0, 0, n)))
Packit 992a25
						return 0;
Packit 992a25
					memcpy((char*)(f->re.string.base = (unsigned char*)f->re.data), (char*)p, n);
Packit 992a25
					f->re.string.size = n;
Packit 992a25
				}
Packit 992a25
				if (!(f = rep(env, f, 0, 0)) || !(f = cat(env, f, seq(env))))
Packit 992a25
				{
Packit 992a25
					drop(env->disc, e);
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				if (e)
Packit 992a25
					f = cat(env, e, f);
Packit 992a25
				return f;
Packit 992a25
			default:
Packit 992a25
				c = s - buf;
Packit 992a25
				if (!(e = node(env, REX_STRING, 0, 0, c)))
Packit 992a25
					return 0;
Packit 992a25
				memcpy((char*)(e->re.string.base = (unsigned char*)e->re.data), (char*)buf, c);
Packit 992a25
				e->re.string.size = c;
Packit 992a25
				return cat(env, e, seq(env));
Packit 992a25
			}
Packit 992a25
		else if (c > T_BACK)
Packit 992a25
		{
Packit 992a25
			eat(env);
Packit 992a25
			c -= T_BACK;
Packit 992a25
			if (c > env->parno || !env->paren[c])
Packit 992a25
			{
Packit 992a25
				env->error = REG_ESUBREG;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
			env->paren[c]->re.group.back = 1;
Packit 992a25
			e = rep(env, node(env, REX_BACK, c, 0, 0), 0, 0);
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			switch (c)
Packit 992a25
			{
Packit 992a25
			case T_AND:
Packit 992a25
			case T_CLOSE:
Packit 992a25
			case T_BAR:
Packit 992a25
			case T_END:
Packit 992a25
				return node(env, REX_NULL, 0, 0, 0);
Packit 992a25
			case T_DOLL:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_END, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_CFLX:
Packit 992a25
				eat(env);
Packit 992a25
				if ((e = node(env, REX_BEG, 0, 0, 0)) && (env->flags & REG_EXTENDED))
Packit 992a25
					e = rep(env, e, 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_OPEN:
Packit 992a25
				tok = env->token;
Packit 992a25
				eat(env);
Packit 992a25
				flags = env->flags;
Packit 992a25
				type = env->type;
Packit 992a25
				if (env->token.att)
Packit 992a25
					env->flags |= REG_MINIMAL;
Packit 992a25
				env->parnest++;
Packit 992a25
				if (env->type == KRE)
Packit 992a25
					++env->parno;
Packit 992a25
				parno = ++env->parno;
Packit 992a25
				if (!(e = alt(env, parno + 1, 0)))
Packit 992a25
					break;
Packit 992a25
				if (e->type == REX_NULL && env->type == ERE && !(env->flags & (REG_NULL|REG_REGEXP)))
Packit 992a25
				{
Packit 992a25
					drop(env->disc, e);
Packit 992a25
					env->error = (*env->cursor == 0 || *env->cursor == env->delimiter || *env->cursor == env->terminator) ? REG_EPAREN : REG_ENULL;
Packit 992a25
					return 0;
Packit 992a25
				} 
Packit 992a25
				if (token(env) != T_CLOSE)
Packit 992a25
				{
Packit 992a25
					drop(env->disc, e);
Packit 992a25
					env->error = REG_EPAREN;
Packit 992a25
					return 0;
Packit 992a25
				} 
Packit 992a25
				env->parnest--;
Packit 992a25
				eat(env);
Packit 992a25
				if (!(f = node(env, REX_GROUP, 0, 0, 0)))
Packit 992a25
				{
Packit 992a25
					drop(env->disc, e);
Packit 992a25
					return 0;
Packit 992a25
				}
Packit 992a25
				if (parno < elementsof(env->paren))
Packit 992a25
					env->paren[parno] = f;
Packit 992a25
				f->re.group.back = 0;
Packit 992a25
				f->re.group.number = parno;
Packit 992a25
				f->re.group.expr.rex = e;
Packit 992a25
				if (tok.lex)
Packit 992a25
				{
Packit 992a25
					tok.push = 1;
Packit 992a25
					env->token = tok;
Packit 992a25
				}
Packit 992a25
				if (!(e = rep(env, f, parno, env->parno)))
Packit 992a25
					return 0;
Packit 992a25
				if (env->type == KRE)
Packit 992a25
				{
Packit 992a25
					if (!(f = node(env, REX_GROUP, 0, 0, 0)))
Packit 992a25
					{
Packit 992a25
						drop(env->disc, e);
Packit 992a25
						return 0;
Packit 992a25
					}
Packit 992a25
					if (--parno < elementsof(env->paren))
Packit 992a25
						env->paren[parno] = f;
Packit 992a25
					f->re.group.back = 0;
Packit 992a25
					f->re.group.number = parno;
Packit 992a25
					f->re.group.expr.rex = e;
Packit 992a25
					e = f;
Packit 992a25
				}
Packit 992a25
				env->flags = flags;
Packit 992a25
				env->type = type;
Packit 992a25
				break;
Packit 992a25
			case T_GROUP:
Packit 992a25
				p = env->cursor;
Packit 992a25
				eat(env);
Packit 992a25
				flags = env->flags;
Packit 992a25
				type = env->type;
Packit 992a25
				if (!(e = grp(env, env->parno + 1)))
Packit 992a25
				{
Packit 992a25
					if (env->error)
Packit 992a25
						return 0;
Packit 992a25
					if (env->literal == env->pattern && env->literal == p)
Packit 992a25
						env->literal = env->cursor;
Packit 992a25
					continue;
Packit 992a25
				}
Packit 992a25
				env->flags = flags;
Packit 992a25
				env->type = type;
Packit 992a25
				break;
Packit 992a25
			case T_BRA:
Packit 992a25
				eat(env);
Packit 992a25
				if (e = bra(env))
Packit 992a25
					e = rep(env, e, 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_ALNUM:
Packit 992a25
			case T_ALNUM_NOT:
Packit 992a25
			case T_DIGIT:
Packit 992a25
			case T_DIGIT_NOT:
Packit 992a25
			case T_SPACE:
Packit 992a25
			case T_SPACE_NOT:
Packit 992a25
				eat(env);
Packit 992a25
				if (e = ccl(env, c))
Packit 992a25
					e = rep(env, e, 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_LT:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_WBEG, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_GT:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_WEND, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_DOT:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_DOT, 1, 1, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_DOTSTAR:
Packit 992a25
				eat(env);
Packit 992a25
				env->token.lex = T_STAR;
Packit 992a25
				env->token.push = 1;
Packit 992a25
				e = rep(env, node(env, REX_DOT, 1, 1, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_SLASHPLUS:
Packit 992a25
				eat(env);
Packit 992a25
				env->token.lex = T_PLUS;
Packit 992a25
				env->token.push = 1;
Packit 992a25
				if (e = node(env, REX_ONECHAR, 1, 1, 0))
Packit 992a25
				{
Packit 992a25
					e->re.onechar = '/';
Packit 992a25
					e = rep(env, e, 0, 0);
Packit 992a25
				}
Packit 992a25
				break;
Packit 992a25
			case T_WORD:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_WORD, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_WORD_NOT:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_WORD_NOT, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_BEG_STR:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_BEG_STR, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_END_STR:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_END_STR, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			case T_FIN_STR:
Packit 992a25
				eat(env);
Packit 992a25
				e = rep(env, node(env, REX_FIN_STR, 0, 0, 0), 0, 0);
Packit 992a25
				break;
Packit 992a25
			default:
Packit 992a25
				env->error = REG_BADRPT;
Packit 992a25
				return 0;
Packit 992a25
			}
Packit 992a25
		if (e && *env->cursor != 0 && *env->cursor != env->delimiter && *env->cursor != env->terminator)
Packit 992a25
			e = cat(env, e, seq(env));
Packit 992a25
		return e;
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
con(Cenv_t* env)
Packit 992a25
{
Packit 992a25
	Rex_t*	e;
Packit 992a25
	Rex_t*	f;
Packit 992a25
	Rex_t*	g;
Packit 992a25
Packit 992a25
	if (!(e = seq(env)) || !(env->flags & REG_AUGMENTED) || token(env) != T_AND)
Packit 992a25
		return e;
Packit 992a25
	eat(env);
Packit 992a25
	if (!(f = con(env)))
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	if (!(g = node(env, REX_CONJ, 0, 0, 0)))
Packit 992a25
	{
Packit 992a25
		drop(env->disc, e);
Packit 992a25
		drop(env->disc, f);
Packit 992a25
		return 0;
Packit 992a25
	}
Packit 992a25
	g->re.group.expr.binary.left = e;
Packit 992a25
	g->re.group.expr.binary.right = f;
Packit 992a25
	return g;
Packit 992a25
}
Packit 992a25
Packit 992a25
static Rex_t*
Packit 992a25
alt(Cenv_t* env, int number, int cond)
Packit 992a25
{
Packit 992a25
	Rex_t*	e;
Packit 992a25
	Rex_t*	f;
Packit 992a25
	Rex_t*	g;
Packit 992a25
Packit 992a25
	if (!(e = con(env)))
Packit 992a25
		return 0;
Packit 992a25
	else if (token(env) != T_BAR)
Packit 992a25
	{
Packit 992a25
		if (!cond)
Packit 992a25
			return e;
Packit 992a25
		f = 0;
Packit 992a25
		if (e->type == REX_NULL)
Packit 992a25
			goto bad;
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		eat(env);
Packit 992a25
		if (!(f = alt(env, number, 0)))
Packit 992a25
		{
Packit 992a25
			drop(env->disc, e);
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		if ((e->type == REX_NULL || f->type == REX_NULL) && !(env->flags & (REG_NULL|REG_REGEXP)))
Packit 992a25
			goto bad;
Packit 992a25
		if (!cond && (g = trie(env, e, f)))
Packit 992a25
			return g;
Packit 992a25
	}
Packit 992a25
	if (!(g = node(env, REX_ALT, 0, 0, 0)))
Packit 992a25
	{
Packit 992a25
		env->error = REG_ESPACE;
Packit 992a25
		goto bad;
Packit 992a25
	}
Packit 992a25
	g->re.group.number = number;
Packit 992a25
	g->re.group.last = env->parno;
Packit 992a25
	g->re.group.expr.binary.left = e;
Packit 992a25
	g->re.group.expr.binary.right = f;
Packit 992a25
	return g;
Packit 992a25
 bad:
Packit 992a25
	drop(env->disc, e);
Packit 992a25
	drop(env->disc, f);
Packit 992a25
	if (!env->error)
Packit 992a25
		env->error = REG_ENULL;
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * add v to REX_BM tables
Packit 992a25
 */
Packit 992a25
Packit 992a25
static void
Packit 992a25
bmstr(Cenv_t* env, register Rex_t* a, unsigned char* v, int n, Bm_mask_t b)
Packit 992a25
{
Packit 992a25
	int	c;
Packit 992a25
	int	m;
Packit 992a25
	size_t	z;
Packit 992a25
Packit 992a25
	for (m = 0; m < n; m++)
Packit 992a25
	{
Packit 992a25
		if (!(z = n - m - 1))
Packit 992a25
			z = HIT;
Packit 992a25
		c = v[m];
Packit 992a25
		a->re.bm.mask[m][c] |= b;
Packit 992a25
		if (z == HIT || !a->re.bm.skip[c] || a->re.bm.skip[c] > z && a->re.bm.skip[c] < HIT)
Packit 992a25
			a->re.bm.skip[c] = z;
Packit 992a25
		if (a->flags & REG_ICASE)
Packit 992a25
		{
Packit 992a25
			if (isupper(c))
Packit 992a25
				c = tolower(c);
Packit 992a25
			else if (islower(c))
Packit 992a25
				c = toupper(c);
Packit 992a25
			else
Packit 992a25
				continue;
Packit 992a25
			a->re.bm.mask[m][c] |= b;
Packit 992a25
			if (z == HIT || !a->re.bm.skip[c] || a->re.bm.skip[c] > z && a->re.bm.skip[c] < HIT)
Packit 992a25
				a->re.bm.skip[c] = z;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * set up BM table from trie
Packit 992a25
 */
Packit 992a25
Packit 992a25
static int
Packit 992a25
bmtrie(Cenv_t* env, Rex_t* a, unsigned char* v, Trie_node_t* x, int n, int m, Bm_mask_t b)
Packit 992a25
{
Packit 992a25
	do
Packit 992a25
	{
Packit 992a25
		v[m] = x->c;
Packit 992a25
		if (m >= (n - 1))
Packit 992a25
		{
Packit 992a25
			bmstr(env, a, v, n, b);
Packit 992a25
			if (!(b <<= 1))
Packit 992a25
			{
Packit 992a25
				b = 1;
Packit 992a25
				a->re.bm.complete = 0;
Packit 992a25
			}
Packit 992a25
			else if (x->son)
Packit 992a25
				a->re.bm.complete = 0;
Packit 992a25
		}
Packit 992a25
		else if (x->son)
Packit 992a25
			b = bmtrie(env, a, v, x->son, n, m + 1, b);
Packit 992a25
	} while (x = x->sib);
Packit 992a25
	return b;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * rewrite the expression tree for some special cases
Packit 992a25
 * 1. it is a null expression - illegal
Packit 992a25
 * 2. max length fixed string found -- use BM algorithm
Packit 992a25
 * 3. it begins with an unanchored string - use KMP algorithm
Packit 992a25
 * 0 returned on success
Packit 992a25
 */		
Packit 992a25
Packit 992a25
static int
Packit 992a25
special(Cenv_t* env, regex_t* p)
Packit 992a25
{
Packit 992a25
	Rex_t*		a;
Packit 992a25
	Rex_t*		e;
Packit 992a25
	Rex_t*		t;
Packit 992a25
	Rex_t*		x;
Packit 992a25
	Rex_t*		y;
Packit 992a25
	unsigned char*	s;
Packit 992a25
	int*		f;
Packit 992a25
	int		n;
Packit 992a25
	int		m;
Packit 992a25
	int		k;
Packit 992a25
Packit 992a25
	DEBUG_INIT();
Packit 992a25
	if (e = p->env->rex)
Packit 992a25
	{
Packit 992a25
		if ((x = env->stats.x) && x->re.string.size < 3)
Packit 992a25
			x = 0;
Packit 992a25
		if ((t = env->stats.y) && t->re.trie.min < 3)
Packit 992a25
			t = 0;
Packit 992a25
		if (x && t)
Packit 992a25
		{
Packit 992a25
			if (x->re.string.size >= t->re.trie.min)
Packit 992a25
				t = 0;
Packit 992a25
			else
Packit 992a25
				x = 0;
Packit 992a25
		}
Packit 992a25
		if (x || t)
Packit 992a25
		{
Packit 992a25
			Bm_mask_t**	mask;
Packit 992a25
			Bm_mask_t*	h;
Packit 992a25
			unsigned char*	v;
Packit 992a25
			size_t*		q;
Packit 992a25
			size_t		l;
Packit 992a25
			int		i;
Packit 992a25
			int		j;
Packit 992a25
Packit 992a25
			if (x)
Packit 992a25
			{
Packit 992a25
				y = x;
Packit 992a25
				n = m = x->re.string.size;
Packit 992a25
				l = env->stats.l;
Packit 992a25
			}
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				y = t;
Packit 992a25
				n = t->re.trie.min;
Packit 992a25
				m = t->re.trie.max;
Packit 992a25
				l = env->stats.k;
Packit 992a25
			}
Packit 992a25
			if (!(q = (size_t*)alloc(env->disc, 0, (n + 1) * sizeof(size_t))))
Packit 992a25
				return 1;
Packit 992a25
			if (!(a = node(env, REX_BM, 0, 0, n * (sizeof(Bm_mask_t*) + (UCHAR_MAX + 1) * sizeof(Bm_mask_t)) + (UCHAR_MAX + n + 2) * sizeof(size_t))))
Packit 992a25
			{
Packit 992a25
				alloc(env->disc, q, 0);
Packit 992a25
				return 1;
Packit 992a25
			}
Packit 992a25
			a->flags = y->flags;
Packit 992a25
			a->map = y->map;
Packit 992a25
			a->re.bm.size = n;
Packit 992a25
			a->re.bm.back = (y == e || y == e->re.group.expr.rex) ? (m - n) : -1;
Packit 992a25
			a->re.bm.left = l - 1;
Packit 992a25
			a->re.bm.right = env->stats.m - l - n;
Packit 992a25
			a->re.bm.complete = (env->stats.e || y != e && (e->type != REX_GROUP || y != e->re.group.expr.rex) || e->next || ((a->re.bm.left + a->re.bm.right) >= 0)) ? 0 : n;
Packit 992a25
			h = (Bm_mask_t*)&a->re.bm.mask[n];
Packit 992a25
			a->re.bm.skip = (size_t*)(h + n * (UCHAR_MAX + 1));
Packit 992a25
			a->re.bm.fail = &a->re.bm.skip[UCHAR_MAX + 1];
Packit 992a25
			for (m = 0; m <= UCHAR_MAX; m++)
Packit 992a25
				a->re.bm.skip[m] = n;
Packit 992a25
			a->re.bm.skip[0] = a->re.bm.skip[env->mappednewline] = (y->next && y->next->type == REX_END) ? HIT : (n + a->re.bm.left);
Packit 992a25
			for (i = 1; i <= n; i++)
Packit 992a25
				a->re.bm.fail[i] = 2 * n - i;
Packit 992a25
			mask = a->re.bm.mask;
Packit 992a25
			for (m = 0; m < n; m++)
Packit 992a25
			{
Packit 992a25
				mask[m] = h;
Packit 992a25
				h += UCHAR_MAX + 1;
Packit 992a25
			}
Packit 992a25
			if (x)
Packit 992a25
				bmstr(env, a, x->re.string.base, n, 1);
Packit 992a25
			else
Packit 992a25
			{
Packit 992a25
				v = (unsigned char*)q;
Packit 992a25
				memset(v, 0, n);
Packit 992a25
				m = 1;
Packit 992a25
				for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
					if (t->re.trie.root[i])
Packit 992a25
						m = bmtrie(env, a, v, t->re.trie.root[i], n, 0, m);
Packit 992a25
			}
Packit 992a25
			mask--;
Packit 992a25
			memset(q, 0, n * sizeof(*q));
Packit 992a25
			for (k = (j = n) + 1; j > 0; j--, k--)
Packit 992a25
			{
Packit 992a25
				DEBUG_TEST(0x0010,(sfprintf(sfstderr, "BM#0: k=%d j=%d\n", k, j)),(0));
Packit 992a25
				for (q[j] = k; k <= n; k = q[k])
Packit 992a25
				{
Packit 992a25
					for (m = 0; m <= UCHAR_MAX; m++)
Packit 992a25
						if (mask[k][m] == mask[j][m])
Packit 992a25
						{
Packit 992a25
							DEBUG_TEST(0x0010,sfprintf(sfstderr, "CUT1: mask[%d][%c]=mask[%d][%c]\n", k, m, j, m), (0));
Packit 992a25
							goto cut;
Packit 992a25
						}
Packit 992a25
					DEBUG_TEST(0x0010,sfprintf(sfstderr, "BM#2: fail[%d]=%d => %d\n", k, a->re.bm.fail[k], (a->re.bm.fail[k] > n - j) ? (n - j) : a->re.bm.fail[k]), (0));
Packit 992a25
					if (a->re.bm.fail[k] > n - j)
Packit 992a25
						a->re.bm.fail[k] = n - j;
Packit 992a25
				}
Packit 992a25
			cut:	;
Packit 992a25
			}
Packit 992a25
			for (i = 1; i <= n; i++)
Packit 992a25
				if (a->re.bm.fail[i] > n + k - i)
Packit 992a25
				{
Packit 992a25
					DEBUG_TEST(0x0010,sfprintf(sfstderr, "BM#4: fail[%d]=%d => %d\n", i, a->re.bm.fail[i], n + k - i), (0));
Packit 992a25
					a->re.bm.fail[i] = n + k - i;
Packit 992a25
				}
Packit 992a25
#if _AST_REGEX_DEBUG
Packit 992a25
			if (DEBUG_TEST(0x0020,(1),(0)))
Packit 992a25
			{
Packit 992a25
				sfprintf(sfstderr, "STAT: complete=%d n=%d k=%d l=%d r=%d y=%d:%d e=%d:%d\n", a->re.bm.complete, n, k, a->re.bm.left, a->re.bm.right, y->type, y->next ? y->next->type : 0, e->type, e->next ? e->next->type : 0);
Packit 992a25
				for (m = 0; m < n; m++)
Packit 992a25
					for (i = 1; i <= UCHAR_MAX; i++)
Packit 992a25
						if (a->re.bm.mask[m][i])
Packit 992a25
							sfprintf(sfstderr, "MASK: [%d]['%c'] = %032..2u\n", m, i, a->re.bm.mask[m][i]);
Packit 992a25
				for (i = ' '; i <= UCHAR_MAX; i++)
Packit 992a25
					if (a->re.bm.skip[i] >= HIT)
Packit 992a25
						sfprintf(sfstderr, "SKIP: ['%c'] =   *\n", i);
Packit 992a25
					else if (a->re.bm.skip[i] > 0 && a->re.bm.skip[i] < n)
Packit 992a25
						sfprintf(sfstderr, "SKIP: ['%c'] = %3d\n", i, a->re.bm.skip[i]);
Packit 992a25
				for (j = 31; j >= 0; j--)
Packit 992a25
				{
Packit 992a25
					sfprintf(sfstderr, "      ");
Packit 992a25
				next:
Packit 992a25
					for (m = 0; m < n; m++)
Packit 992a25
					{
Packit 992a25
						for (i = 0040; i < 0177; i++)
Packit 992a25
							if (a->re.bm.mask[m][i] & (1 << j))
Packit 992a25
							{
Packit 992a25
								sfprintf(sfstderr, "  %c", i);
Packit 992a25
								break;
Packit 992a25
							}
Packit 992a25
						if (i >= 0177)
Packit 992a25
						{
Packit 992a25
							if (j > 0)
Packit 992a25
							{
Packit 992a25
								j--;
Packit 992a25
								goto next;
Packit 992a25
							}
Packit 992a25
							sfprintf(sfstderr, "  ?");
Packit 992a25
						}
Packit 992a25
					}
Packit 992a25
					sfprintf(sfstderr, "\n");
Packit 992a25
				}
Packit 992a25
				sfprintf(sfstderr, "FAIL: ");
Packit 992a25
				for (m = 1; m <= n; m++)
Packit 992a25
					sfprintf(sfstderr, "%3d", a->re.bm.fail[m]);
Packit 992a25
				sfprintf(sfstderr, "\n");
Packit 992a25
			}
Packit 992a25
#endif
Packit 992a25
			alloc(env->disc, q, 0);
Packit 992a25
			a->next = e;
Packit 992a25
			p->env->rex = a;
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
		switch (e->type)
Packit 992a25
		{
Packit 992a25
		case REX_BEG:
Packit 992a25
			if (env->flags & REG_NEWLINE)
Packit 992a25
				return 0;
Packit 992a25
			break;
Packit 992a25
		case REX_GROUP:
Packit 992a25
			if (env->stats.b)
Packit 992a25
				return 0;
Packit 992a25
			e = e->re.group.expr.rex;
Packit 992a25
			if (e->type != REX_DOT)
Packit 992a25
				return 0;
Packit 992a25
			/*FALLTHROUGH*/
Packit 992a25
		case REX_DOT:
Packit 992a25
			if (e->lo == 0 && e->hi == RE_DUP_INF)
Packit 992a25
				break;
Packit 992a25
			return 0;
Packit 992a25
		case REX_NULL:
Packit 992a25
			if (env->flags & (REG_NULL|REG_REGEXP))
Packit 992a25
				break;
Packit 992a25
			env->error = REG_ENULL;
Packit 992a25
			return 1;
Packit 992a25
		case REX_STRING:
Packit 992a25
			if ((env->flags & (REG_LEFT|REG_LITERAL|REG_RIGHT)) || e->map)
Packit 992a25
				return 0;
Packit 992a25
			s = e->re.string.base;
Packit 992a25
			n = e->re.string.size;
Packit 992a25
			if (!(a = node(env, REX_KMP, 0, 0, n * (sizeof(int*) + 1))))
Packit 992a25
				return 1;
Packit 992a25
			a->flags = e->flags;
Packit 992a25
			a->map = e->map;
Packit 992a25
			f = a->re.string.fail;
Packit 992a25
			memcpy((char*)(a->re.string.base = (unsigned char*)&f[n]), (char*)s, n);
Packit 992a25
			s = a->re.string.base;
Packit 992a25
			a->re.string.size = n;
Packit 992a25
			f[0] = m = -1;
Packit 992a25
			for (k = 1; k < n; k++)
Packit 992a25
			{
Packit 992a25
				while (m >= 0 && s[m+1] != s[k])
Packit 992a25
					m = f[m];
Packit 992a25
				if (s[m+1] == s[k])
Packit 992a25
					m++;
Packit 992a25
				f[k] = m;
Packit 992a25
			}
Packit 992a25
			a->next = e->next;
Packit 992a25
			p->env->rex = a;
Packit 992a25
			e->next = 0;
Packit 992a25
			drop(env->disc, e);
Packit 992a25
			break;
Packit 992a25
		default:
Packit 992a25
			return 0;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	p->env->once = 1;
Packit 992a25
	return 0;
Packit 992a25
}		
Packit 992a25
Packit 992a25
int
Packit 992a25
regcomp(regex_t* p, const char* pattern, regflags_t flags)
Packit 992a25
{
Packit 992a25
	Rex_t*			e;
Packit 992a25
	Rex_t*			f;
Packit 992a25
	regdisc_t*		disc;
Packit 992a25
	unsigned char*		fold;
Packit 992a25
	int			i;
Packit 992a25
	Cenv_t			env;
Packit 992a25
Packit 992a25
	if (!p)
Packit 992a25
		return REG_BADPAT;
Packit 992a25
	if (flags & REG_DISCIPLINE)
Packit 992a25
	{
Packit 992a25
		flags &= ~REG_DISCIPLINE;
Packit 992a25
		disc = p->re_disc;
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		disc = &state.disc;
Packit 992a25
	if (!disc->re_errorlevel)
Packit 992a25
		disc->re_errorlevel = 2;
Packit 992a25
	p->env = 0;
Packit 992a25
	if (!pattern)
Packit 992a25
		return fatal(disc, REG_BADPAT, pattern);
Packit 992a25
	if (!state.initialized)
Packit 992a25
	{
Packit 992a25
		state.initialized = 1;
Packit 992a25
		for (i = 0; i < elementsof(state.escape); i++)
Packit 992a25
			state.magic[state.escape[i].key] = state.escape[i].val;
Packit 992a25
	}
Packit 992a25
	if (!(fold = (unsigned char*)LCINFO(AST_LC_CTYPE)->data))
Packit 992a25
	{
Packit 992a25
		if (!(fold = newof(0, unsigned char, UCHAR_MAX, 1)))
Packit 992a25
			return fatal(disc, REG_ESPACE, pattern);
Packit 992a25
		for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
			fold[i] = toupper(i);
Packit 992a25
		LCINFO(AST_LC_CTYPE)->data = (void*)fold;
Packit 992a25
	}
Packit 992a25
 again:
Packit 992a25
	if (!(p->env = (Env_t*)alloc(disc, 0, sizeof(Env_t))))
Packit 992a25
		return fatal(disc, REG_ESPACE, pattern);
Packit 992a25
	memset(p->env, 0, sizeof(*p->env));
Packit 992a25
	memset(&env, 0, sizeof(env));
Packit 992a25
	env.regex = p;
Packit 992a25
	env.flags = flags;
Packit 992a25
	env.disc = p->env->disc = disc;
Packit 992a25
	if (env.flags & REG_AUGMENTED)
Packit 992a25
		env.flags |= REG_EXTENDED;
Packit 992a25
	env.mappeddot = '.';
Packit 992a25
	env.mappednewline = '\n';
Packit 992a25
	env.mappedslash = '/';
Packit 992a25
	if (disc->re_version >= REG_VERSION_MAP && disc->re_map)
Packit 992a25
	{
Packit 992a25
		env.map = disc->re_map;
Packit 992a25
		env.MAP = p->env->fold;
Packit 992a25
		for (i = 0; i <= UCHAR_MAX; i++)
Packit 992a25
		{
Packit 992a25
			env.MAP[i] = fold[env.map[i]];
Packit 992a25
			if (env.map[i] == '.')
Packit 992a25
				env.mappeddot = i;
Packit 992a25
			if (env.map[i] == '\n')
Packit 992a25
				env.mappednewline = i;
Packit 992a25
			if (env.map[i] == '/')
Packit 992a25
				env.mappedslash = i;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		env.MAP = fold;
Packit 992a25
	env.type = (env.flags & REG_AUGMENTED) ? ARE : (env.flags & REG_EXTENDED) ? ERE : BRE;
Packit 992a25
	env.explicit = -1;
Packit 992a25
	if (env.flags & REG_SHELL)
Packit 992a25
	{
Packit 992a25
		if (env.flags & REG_SHELL_PATH)
Packit 992a25
			env.explicit = env.mappedslash;
Packit 992a25
		if (!(env.flags & REG_SHELL_ESCAPED))
Packit 992a25
			env.flags |= REG_CLASS_ESCAPE;
Packit 992a25
		env.flags |= REG_LENIENT|REG_NULL;
Packit 992a25
		env.type = env.type == BRE ? SRE : KRE;
Packit 992a25
	}
Packit 992a25
	else
Packit 992a25
		env.flags &= ~(REG_SHELL_DOT|REG_SHELL_ESCAPED|REG_SHELL_GROUP|REG_SHELL_PATH);
Packit 992a25
	if ((env.flags & (REG_NEWLINE|REG_SPAN)) == REG_NEWLINE)
Packit 992a25
		env.explicit = env.mappednewline;
Packit 992a25
	p->env->leading = (env.flags & REG_SHELL_DOT) ? env.mappeddot : -1;
Packit 992a25
	env.posixkludge = !(env.flags & (REG_EXTENDED|REG_SHELL));
Packit 992a25
	env.token.lex = 0;
Packit 992a25
	env.token.push = 0;
Packit 992a25
	if (env.flags & REG_DELIMITED)
Packit 992a25
	{
Packit 992a25
		switch (env.delimiter = *pattern++)
Packit 992a25
		{
Packit 992a25
		case 0:
Packit 992a25
		case '\\':
Packit 992a25
		case '\n':
Packit 992a25
		case '\r':
Packit 992a25
			env.error = REG_EDELIM;
Packit 992a25
			goto bad;
Packit 992a25
		}
Packit 992a25
		env.terminator = '\n';
Packit 992a25
	}
Packit 992a25
	env.literal = env.pattern = env.cursor = (unsigned char*)pattern;
Packit 992a25
	if (!(p->env->rex = alt(&env, 1, 0)))
Packit 992a25
		goto bad;
Packit 992a25
	if (env.parnest)
Packit 992a25
	{
Packit 992a25
		env.error = REG_EPAREN;
Packit 992a25
		goto bad;
Packit 992a25
	}
Packit 992a25
	if ((env.flags & REG_LEFT) && p->env->rex->type != REX_BEG)
Packit 992a25
	{
Packit 992a25
		if (p->env->rex->type == REX_ALT)
Packit 992a25
			env.flags &= ~REG_FIRST;
Packit 992a25
		if (!(e = node(&env, REX_BEG, 0, 0, 0)))
Packit 992a25
		{
Packit 992a25
			regfree(p);
Packit 992a25
			return fatal(disc, REG_ESPACE, pattern);
Packit 992a25
		}
Packit 992a25
		e->next = p->env->rex;
Packit 992a25
		p->env->rex = e;
Packit 992a25
		p->env->once = 1;
Packit 992a25
	}
Packit 992a25
	for (e = p->env->rex; e->next; e = e->next);
Packit 992a25
	p->env->done.type = REX_DONE;
Packit 992a25
	p->env->done.flags = e->flags;
Packit 992a25
	if ((env.flags & REG_RIGHT) && e->type != REX_END)
Packit 992a25
	{
Packit 992a25
		if (p->env->rex->type == REX_ALT)
Packit 992a25
			env.flags &= ~REG_FIRST;
Packit 992a25
		if (!(f = node(&env, REX_END, 0, 0, 0)))
Packit 992a25
		{
Packit 992a25
			regfree(p);
Packit 992a25
			return fatal(disc, REG_ESPACE, pattern);
Packit 992a25
		}
Packit 992a25
		f->flags = e->flags;
Packit 992a25
		f->map = e->map;
Packit 992a25
		e->next = f;
Packit 992a25
	}
Packit 992a25
	if (stats(&env, p->env->rex))
Packit 992a25
	{
Packit 992a25
		if (!env.error)
Packit 992a25
			env.error = REG_ECOUNT;
Packit 992a25
		goto bad;
Packit 992a25
	}
Packit 992a25
	if (env.stats.b)
Packit 992a25
		p->env->hard = p->env->separate = 1;
Packit 992a25
	else if (!(env.flags & REG_FIRST) && (env.stats.a || env.stats.c > 1 && env.stats.c != env.stats.s || env.stats.t && (env.stats.t > 1 || env.stats.a || env.stats.c)))
Packit 992a25
		p->env->hard = 1;
Packit 992a25
	if (p->env->hard || env.stats.c || env.stats.i)
Packit 992a25
		p->env->stats.re_min = p->env->stats.re_max = -1;
Packit 992a25
	else
Packit 992a25
	{
Packit 992a25
		if (!(p->env->stats.re_min = env.stats.m))
Packit 992a25
			p->env->stats.re_min = -1;
Packit 992a25
		if (!(p->env->stats.re_max = env.stats.n))
Packit 992a25
			p->env->stats.re_max = -1;
Packit 992a25
	}
Packit 992a25
	if (special(&env, p))
Packit 992a25
		goto bad;
Packit 992a25
	serialize(&env, p->env->rex, 1);
Packit 992a25
	p->re_nsub = env.stats.p;
Packit 992a25
	if (env.type == KRE)
Packit 992a25
		p->re_nsub /= 2;
Packit 992a25
	if (env.flags & REG_DELIMITED)
Packit 992a25
	{
Packit 992a25
		p->re_npat = env.cursor - env.pattern + 1;
Packit 992a25
		if (*env.cursor == env.delimiter)
Packit 992a25
			p->re_npat++;
Packit 992a25
		else if (env.flags & REG_MUSTDELIM)
Packit 992a25
		{
Packit 992a25
			env.error = REG_EDELIM;
Packit 992a25
			goto bad;
Packit 992a25
		}
Packit 992a25
		else
Packit 992a25
			env.flags &= ~REG_DELIMITED;
Packit 992a25
	}
Packit 992a25
	p->env->explicit = env.explicit;
Packit 992a25
	p->env->flags = env.flags & REG_COMP;
Packit 992a25
	p->env->min = env.stats.m;
Packit 992a25
	p->env->nsub = env.stats.p + env.stats.u;
Packit 992a25
	p->env->refs = 1;
Packit 992a25
	return 0;
Packit 992a25
 bad:
Packit 992a25
	regfree(p);
Packit 992a25
	if (!env.error)
Packit 992a25
		env.error = REG_ESPACE;
Packit 992a25
	if (env.type >= SRE && env.error != REG_ESPACE && !(flags & REG_LITERAL))
Packit 992a25
	{
Packit 992a25
		flags |= REG_LITERAL;
Packit 992a25
		pattern = (const char*)env.literal;
Packit 992a25
		goto again;
Packit 992a25
	}
Packit 992a25
	return fatal(disc, env.error, pattern);
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * regcomp() on sized pattern
Packit 992a25
 * the lazy way around adding and checking env.end
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
regncomp(regex_t* p, const char* pattern, size_t size, regflags_t flags)
Packit 992a25
{
Packit 992a25
	char*	s;
Packit 992a25
	int	r;
Packit 992a25
Packit 992a25
	if (!(s = malloc(size + 1)))
Packit 992a25
		return fatal((flags & REG_DISCIPLINE) ? p->re_disc : &state.disc, REG_ESPACE, pattern);
Packit 992a25
	memcpy(s, pattern, size);
Packit 992a25
	s[size] = 0;
Packit 992a25
	r = regcomp(p, s, flags);
Packit 992a25
	free(s);
Packit 992a25
	return r;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * combine two compiled regular expressions if possible,
Packit 992a25
 * replacing first with the combination and freeing second.
Packit 992a25
 * return 0 on success.
Packit 992a25
 * the only combinations handled are building a Trie
Packit 992a25
 * from String|Kmp|Trie and String|Kmp
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
regcomb(regex_t* p, regex_t* q)
Packit 992a25
{
Packit 992a25
	Rex_t*	e = p->env->rex;
Packit 992a25
	Rex_t*	f = q->env->rex;
Packit 992a25
	Rex_t*	g;
Packit 992a25
	Rex_t*	h;
Packit 992a25
	Cenv_t	env;
Packit 992a25
Packit 992a25
	if (!e || !f)
Packit 992a25
		return fatal(p->env->disc, REG_BADPAT, NiL);
Packit 992a25
	if (p->env->separate || q->env->separate)
Packit 992a25
		return REG_ESUBREG;
Packit 992a25
	memset(&env, 0, sizeof(env));
Packit 992a25
	env.disc = p->env->disc;
Packit 992a25
	if (e->type == REX_BM)
Packit 992a25
	{
Packit 992a25
		p->env->rex = e->next;
Packit 992a25
		e->next = 0;
Packit 992a25
		drop(env.disc, e);
Packit 992a25
		e = p->env->rex;
Packit 992a25
	}
Packit 992a25
	if (f->type == REX_BM)
Packit 992a25
	{
Packit 992a25
		q->env->rex = f->next;
Packit 992a25
		f->next = 0;
Packit 992a25
		drop(env.disc, f);
Packit 992a25
		f = q->env->rex;
Packit 992a25
	}
Packit 992a25
	if (e->type == REX_BEG && f->type == REX_BEG)
Packit 992a25
	{
Packit 992a25
		p->env->flags |= REG_LEFT;
Packit 992a25
		p->env->rex = e->next;
Packit 992a25
		e->next = 0;
Packit 992a25
		drop(env.disc, e);
Packit 992a25
		e = p->env->rex;
Packit 992a25
		q->env->rex = f->next;
Packit 992a25
		f->next = 0;
Packit 992a25
		drop(env.disc, f);
Packit 992a25
		f = q->env->rex;
Packit 992a25
	}
Packit 992a25
	for (g = e; g->next; g = g->next);
Packit 992a25
	for (h = f; h->next; h = h->next);
Packit 992a25
	if (g->next && g->next->type == REX_END && h->next && h->next->type == REX_END)
Packit 992a25
	{
Packit 992a25
		p->env->flags |= REG_RIGHT;
Packit 992a25
		drop(env.disc, g->next);
Packit 992a25
		g->next = 0;
Packit 992a25
		drop(env.disc, h->next);
Packit 992a25
		h->next = 0;
Packit 992a25
	}
Packit 992a25
	if (!(g = trie(&env, f, e)))
Packit 992a25
		return fatal(p->env->disc, REG_BADPAT, NiL);
Packit 992a25
	p->env->rex = g;
Packit 992a25
	if (!q->env->once)
Packit 992a25
		p->env->once = 0;
Packit 992a25
	q->env->rex = 0;
Packit 992a25
	if (p->env->flags & REG_LEFT)
Packit 992a25
	{
Packit 992a25
		if (!(e = node(&env, REX_BEG, 0, 0, 0)))
Packit 992a25
		{
Packit 992a25
			regfree(p);
Packit 992a25
			return fatal(p->env->disc, REG_ESPACE, NiL);
Packit 992a25
		}
Packit 992a25
		e->next = p->env->rex;
Packit 992a25
		p->env->rex = e;
Packit 992a25
		p->env->once = 1;
Packit 992a25
	}
Packit 992a25
	if (p->env->flags & REG_RIGHT)
Packit 992a25
	{
Packit 992a25
		for (f = p->env->rex; f->next; f = f->next);
Packit 992a25
		if (f->type != REX_END)
Packit 992a25
		{
Packit 992a25
			if (!(e = node(&env, REX_END, 0, 0, 0)))
Packit 992a25
			{
Packit 992a25
				regfree(p);
Packit 992a25
				return fatal(p->env->disc, REG_ESPACE, NiL);
Packit 992a25
			}
Packit 992a25
			f->next = e;
Packit 992a25
		}
Packit 992a25
	}
Packit 992a25
	env.explicit = p->env->explicit;
Packit 992a25
	env.flags = p->env->flags;
Packit 992a25
	env.disc = p->env->disc;
Packit 992a25
	if (stats(&env, p->env->rex))
Packit 992a25
	{
Packit 992a25
		regfree(p);
Packit 992a25
		return fatal(p->env->disc, env.error ? env.error : REG_ECOUNT, NiL);
Packit 992a25
	}
Packit 992a25
	if (special(&env, p))
Packit 992a25
	{
Packit 992a25
		regfree(p);
Packit 992a25
		return fatal(p->env->disc, env.error ? env.error : REG_ESPACE, NiL);
Packit 992a25
	}
Packit 992a25
	p->env->min = g->re.trie.min;
Packit 992a25
	return 0;
Packit 992a25
}
Packit 992a25
Packit 992a25
/*
Packit 992a25
 * copy a reference of p into q
Packit 992a25
 * p and q may then have separate regsubcomp() instantiations
Packit 992a25
 */
Packit 992a25
Packit 992a25
int
Packit 992a25
regdup(regex_t* p, regex_t* q)
Packit 992a25
{
Packit 992a25
	if (!p || !q)
Packit 992a25
		return REG_BADPAT;
Packit 992a25
	*q = *p;
Packit 992a25
	p->env->refs++;
Packit 992a25
	q->re_sub = 0;
Packit 992a25
	return 0;
Packit 992a25
}