/*	Copyright (c) 1990 UNIX System Laboratories, Inc.	*/
/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF     	*/
/*	UNIX System Laboratories, Inc.                     	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"@(#)sti:form/regex.c	1.2"

/*
	this code was taken from REGCMP(3X)
*/
/*VARARGS*/
/*ARGSUSED*/

#define SSIZE	50
#define TGRP	48
#define A256	01
#define A512	02
#define A768	03
#define	NBRA	10
#define CIRCFL	32
#define	EOF	-1

#define	CBRA	60
#define GRP	40
#define SGRP	56
#define PGRP	68
#define EGRP	44
#define RNGE	03
#define	CCHR	20
#define	CDOT	64
#define	CCL	24
#define	NCCL	8
#define	CDOL	28
#define	CEOF	52
#define	CKET	12

#define	STAR	01
#define PLUS	02
#define MINUS	16
char	*__braslist[NBRA];
char	*__braelist[NBRA];
char	*__loc1;
int	__bravar[NBRA];
int	*__st[SSIZE + 1];
int	*__eptr_,*__lptr_;
int	__cflg;
char *
regex(addrc,addrl,a1,a2,a3,a4,a5) char *addrc, *addrl, *a1, *a2, *a3, *a4, *a5;
{
	int cur,in;
	register int *adx;
	register char *p1, *p2;

	for(in=0;in<NBRA;in++) {
		__braslist[in] = 0;
		__bravar[in] = -1;
	}
	__cflg = 0;
	cur = __execute(addrc,addrl);
	adx = (int *)&a1;
	for(in=0;in<NBRA;in++) {
		if ((p1 = __braslist[in]) && (__bravar[in] >= 0)) {
			p2 = (char *)adx[__bravar[in]];
			while(p1 < __braelist[in]) *p2++ = *p1++;
			*p2 = '\0';
		}
	}
	if (!__cflg) return (addrl==(char *)cur)?(char *)0:(char *)cur;
	else return (char *)cur;
}

__execute(addrc,addrl)
char *addrc,*addrl;
{
	register char *p1, *p2, c;
	int i;

	p1 = addrl;
	p2 = addrc;
	__eptr_ = (int *)&__st[SSIZE];
	__lptr_ = (int *)&__st[0];
	if (*p2==CIRCFL) {
		__loc1 = p1;
		return (i=__advance(p1,++p2))?i:(int)addrl;
	}
	/* fast check for first character */
	if (*p2==CCHR) {
		c = p2[1];
		do {
			if (*p1!=c)
				continue;
			__eptr_ = (int *)&__st[SSIZE];
			__lptr_ = (int *)&__st[0];
			if (i=__advance(p1, p2))  {
				__loc1 = p1;
				return(i);
			}
		} while (*p1++);
		return((int)addrl);
	}
	/* regular algorithm */
	do {
	__eptr_ = (int *)&__st[SSIZE];
	__lptr_ = (int *)&__st[0];
		if (i=__advance(p1, p2))  {
			__loc1 = p1;
			return(i);
		}
	} while (*p1++);
	return((int)addrl);
}

__advance(alp, aep)
{
	register char *lp, *ep, *curlp;
	char *sep,*dp;
	int i,lcnt,dcnt,gflg;

	lp = (char *)alp;
	ep = (char *)aep;
	gflg = 0;
	for (;;) {
		switch(*ep++) {

	case CCHR:
		if (*ep++ == *lp++)
			continue;
		return(0);

	case EGRP|RNGE:
		return((int)lp);
	case EGRP:
	case GRP:
		ep++;
		continue;

	case EGRP|STAR:
		(void)__xpop(0);
	case EGRP|PLUS:
		(void)__xpush(0,++ep);
		return((int)lp);

	case CDOT:
		if (*lp++)
			continue;
		return(0);

	case CDOL:
		if (*lp==0)
			continue;
		lp++;
		return(0);

	case CEOF:
		__cflg = 1;
		return((int)lp);

	case TGRP:
	case TGRP|A768:
	case TGRP|A512:
	case TGRP|A256:
		i = (((ep[-1]&03)<<8) + (*ep)&0377);
		ep++;
		(void)__xpush(0,ep + i + 2);
		(void)__xpush(0,++ep);
		(void)__xpush(0,++ep);
		gflg = 1;
		(void)__getrnge(&lcnt,&dcnt,&ep[i]);
		while(lcnt--)
			if (!(lp=(char *)__advance(lp,ep)))
				return(0);
		(void)__xpush(1,curlp=lp);
		while(dcnt--)
			if(!(dp=(char *)__advance(lp,ep))) break;
			else (void)__xpush(1,lp=dp);
		ep = (char *)__xpop(0);
		goto star;
	case CCHR|RNGE:
		sep = ep++;
		(void)__getrnge(&lcnt,&dcnt,ep);
		while(lcnt--)
			if(*lp++!=*sep) return(0);
		curlp = lp;
		while(dcnt--)
			if(*lp++!=*sep) break;
		if (dcnt < 0) lp++;
		ep += 2;
		goto star;
	case CDOT|RNGE:
		(void)__getrnge(&lcnt,&dcnt,ep);
		while(lcnt--)
			if(*lp++ == '\0') return(0);
		curlp = lp;
		while(dcnt--)
			if(*lp++ == '\0') break;
		if (dcnt < 0) lp++;
		ep += 2;
		goto star;
	case CCL|RNGE:
	case NCCL|RNGE:
		(void)__getrnge(&lcnt,&dcnt,(ep + (*ep&0377)));
		while(lcnt--)
			if(!__cclass(ep,*lp++,ep[-1]==(CCL|RNGE))) return(0);
		curlp = lp;
		while(dcnt--)
			if(!__cclass(ep,*lp++,ep[-1]==(CCL|RNGE))) break;
		if (dcnt < 0) lp++;
		ep += (*ep + 2);
		goto star;
	case CCL:
		if (__cclass(ep, *lp++, 1)) {
			ep += *ep;
			continue;
		}
		return(0);

	case NCCL:
		if (__cclass(ep, *lp++, 0)) {
			ep += *ep;
			continue;
		}
		return(0);

	case CBRA:
		__braslist[*ep++] = lp;
		continue;

	case CKET:
		__braelist[*ep] = lp;
		__bravar[*ep] = ep[1];
		ep += 2;
		continue;

	case CDOT|PLUS:
		if (*lp++ == '\0') return(0);
	case CDOT|STAR:
		curlp = lp;
		while (*lp++);
		goto star;

	case CCHR|PLUS:
		if (*lp++ != *ep) return(0);
	case CCHR|STAR:
		curlp = lp;
		while (*lp++ == *ep);
		ep++;
		goto star;

	case PGRP:
	case PGRP|A256:
	case PGRP|A512:
	case PGRP|A768:
		if (!(lp=(char *)__advance(lp,ep+1))) return(0);
	case SGRP|A768:
	case SGRP|A512:
	case SGRP|A256:
	case SGRP:
		i = (((ep[-1]&03) << 8) + (*ep&0377));
		ep++;
		(void)__xpush(0,ep + i);
		(void)__xpush(1,curlp=lp);
		while (i=__advance(lp,ep))
			(void)__xpush(1,lp=(char *)i);
		ep = (char *)__xpop(0);
		gflg = 1;
		goto star;

	case CCL|PLUS:
	case NCCL|PLUS:
		if (!__cclass(ep,*lp++,ep[-1]==(CCL|PLUS))) return(0);
	case CCL|STAR:
	case NCCL|STAR:
		curlp = lp;
		while (__cclass(ep, *lp++, ((ep[-1]==(CCL|STAR)) || (ep[-1]==(CCL|PLUS)))));
		ep += *ep;
		goto star;

	star:
		do {
			if(!gflg) lp--;
			else if (!(lp=(char *)__xpop(1))) break;
			if (i=__advance(lp, ep)) 
				return(i);
		} while (lp > curlp);
		return(0);

	default:
		return(0);
	}
	}
}
__cclass(aset, ac, af)
{
	register char *set, c;
	register n;

	set = (char *)aset;
	if ((c = ac) == 0)
		return(0);
	n = *set++;
	while (--n) {
		if (*set == MINUS) {
			if ((set[2] - set[1]) < 0) return(0);
			if (*++set <= c) {
				if (c <= *++set)
					return(af);
			}
			else ++set;
			++set;
			n -= 2;
			continue;
		}
		if (*set++ == c)
			return(af);
	}
	return(!af);
}
__xpush(i,p) int i; char *p;
{
	if (__lptr_ >= __eptr_) {(void)write(2,"stack overflow\n",15);exit(1);}
	if (i) *__lptr_++ = (int)p;
	else   *__eptr_-- = (int)p;
	return(1);
}
__xpop(i) int i;
{
	if (i)
		return (__lptr_ < (int *)&__st[0])?0:*--__lptr_;
	else
		return (__eptr_ > (int *)&__st[SSIZE])?0:*++__eptr_;
}
__getrnge(i,j,k) int *i,*j; char *k;
{
	*i = (*k++&0377);
	if (*k == (char)-1) *j = 20000;
	else *j = ((*k&0377) - *i);
	return(1);
}
