#include <../../nrnconf.h>
/* /local/src/master/nrn/src/oc/regexp.c,v 1.1.1.1 1994/10/12 17:22:13 hines Exp */
/*
regexp.c,v
 * Revision 1.1.1.1  1994/10/12  17:22:13  hines
 * NEURON 3.0 distribution
 *
 * Revision 2.19  93/02/02  10:34:37  hines
 * static functions declared before used
 * 
 * Revision 1.3  92/07/31  12:11:31  hines
 * following merged from hoc
 * The regular expression has been augmented with
 * {istart-iend} where istart and iend are integers. The expression matches
 * any integer that falls in this range.
 * 
 * Revision 1.2  92/01/30  08:17:19  hines
 * bug fixes found in hoc incorporated. if()return, no else, objectcenter
 * warnings.
 * 
 * Revision 1.1  91/10/11  11:12:16  hines
 * Initial revision
 * 
 * Revision 3.108  90/10/24  09:44:14  hines
 * saber warnings gone
 * 
 * Revision 3.58  90/05/17  16:30:52  jamie
 * changed global functions to start with hoc_
 * moved regexp.c from project 'neuron' to 'hoc'
 * 
 * Revision 1.25  89/08/31  10:28:46  mlh
 * regular expressions for issection()
 * differences between standard regular expressions are:
 * allways match from beginning to end of target (implicit ^ and $)
 * change [] to <>
 * eliminate \(
 * 
 * Revision 1.2  89/08/31  09:22:17  mlh
 * works as in e.c and lint free
 * 
 * Revision 1.1  89/08/31  08:24:59  mlh
 * Initial revision
 * 
*/

/* regular expression match for section names
   grabbed prototype from e.c
   Use by first compiling the search string with hoc_regexp_compile(pattern)
   Then checking target strings one at a time with hoc_regexp_search(target)
*/

#include <stdio.h>
#include "hocdec.h"
#define CABLESECTION	1
/* Always match from beginning of string (implicit ^),
   Always match end of string (implicit $),
   change [] to <>,
   eliminate \(
*/

#define	STAR	01
#define	SUFF	'.'
#define	TILDE	'~'

#define EREGEXP	24
#define	error(enum)	hoc_execerror("search string format error", pattern)
#define	CBRA	1
#define	CCHR	2
#define	CDOT	4
#define	CCL	6
#define	NCCL	8
#define	CDOL	10
#define	CEOF	11
#define	CKET	12
#if CABLESECTION
#define INTRANGE 14
#endif
#define	NBRA	5
#define	ESIZE	128
#define eof	'\0'
static char	expbuf[ESIZE+4];
static char	*pattern = "";
static char	*loc1;
static char	*loc2;
static char	*locs;
static char	*braslist[NBRA];
static char	*braelist[NBRA];
static int	circfl;
#if CABLESECTION
static int	int_range_start[NBRA];
static int	int_range_stop[NBRA];
#endif

static int advance(char* lp, char* ep);
static int hoc_cclass(char* set, char c, int af);

void hoc_regexp_compile(const char* pat) {
	char *cp = (char*)pat;
	register int c;
	register char *ep;
	char *lastep=0;
#if (!CABLESECTION)
	char bracket[NBRA], *bracketp;
	int nbra;
#else
	int int_range_index = 0;
#endif
	int cclcnt;
	int tempc;

	
	if (!cp) {
		pattern = "";
		error(EREGEXP);
	}
	if (pattern == cp && strcmp(pattern, cp)) {
		/* if previous pattern != cp then may have been freed */
		return;
	}
	pattern = cp;
	ep = expbuf;
#if (!CABLESECTION)
	bracketp = bracket;
	nbra = 0;
#endif
	if ((c = *cp++)== '\n') {
		cp--;
		c = eof;
	}
	if (c==eof) {
		if (*ep==0)
			error(EREGEXP);
		return;
	}
#if CABLESECTION
	circfl = 1;
#else
	circfl = 0;
	if (c=='^') {
		c = *cp++;
		circfl++;
	}
#endif
	if (c=='*')
		goto cerror;
	cp--;
	for (;;) {
		if (ep >= &expbuf[ESIZE])
			goto cerror;
		c = *cp++;
		if (c=='\n') {
			cp--;
			c = eof;
		}
		if (c==eof) {
#if CABLESECTION
			*ep++ = CDOL;
#endif
			*ep++ = CEOF;
			return;
		}
		if (c!='*')
			lastep = ep;
		switch (c) {

		case '\\':
#if (!CABLESECTION)
			if ((c = *cp++)=='(') {
				if (nbra >= NBRA)
					goto cerror;
				*bracketp++ = nbra;
				*ep++ = CBRA;
				*ep++ = nbra++;
				continue;
			}
			if (c == ')') {
				if (bracketp <= bracket)
					goto cerror;
				*ep++ = CKET;
				*ep++ = *--bracketp;
				continue;
			}
#endif
			*ep++ = CCHR;
			if (c=='\n')
				goto cerror;
			*ep++ = c;
			continue;

		case '.':
			*ep++ = CDOT;
			continue;

		case '\n':
			goto cerror;

		case '*':
			if (*lastep==CBRA || *lastep==CKET)
				error(EREGEXP);
			*lastep |= STAR;
			continue;

#if (!CABLESECTION)
		case '$':
			tempc = *cp;
			if (tempc != eof && tempc != '\n')
				goto defchar;
			*ep++ = CDOL;
			continue;
#endif

#if CABLESECTION
		case '{':
		   { char* cp1 = cp;
			if (int_range_index >= NBRA)
				goto cerror;
			*ep++ = INTRANGE;
			do {
				if (!(*cp >= '0' && *cp <= '9') && *cp != '-') {
					error(EREGEXP);
				}
			}while (*(++cp) != '}');
			cp++;
			if (2 != sscanf(cp1, "%d-%d",
			   int_range_start + int_range_index,
			   int_range_stop + int_range_index)) {
			   	error(EREGEXP);
			}
			*ep++ = int_range_index++;
		   }
			continue;
#endif
#if CABLESECTION
		case '<':
#else
		case '[':
#endif
			*ep++ = CCL;
			*ep++ = 0;
			cclcnt = 1;
			if ((c = *cp++) == '^') {
				c = *cp++;
				ep[-2] = NCCL;
			}
			do {
				if (c == '\n')
					goto cerror;
/*
 *	Handle the escaped '-'
 */
				if (c == '-' && *(ep-1) == '\\')
					*(ep-1) = '-';
/*
 *	Handle ranges of characters (e.g. a-z)
 */
				else if (
					(tempc = *cp++) != ']' &&
					c == '-' && cclcnt > 1 &&
					tempc != '\n' &&
					(c = *(ep-1)) <= tempc
				) {
					while (++c <= tempc) {
						*ep++ = c;
						cclcnt++;
						if (ep >= &expbuf[ESIZE])
							goto cerror;
					}
				}
/*
 *	Normal case.  Add character to buffer
 */
				else {
					cp--;
					*ep++ = c;
					cclcnt++;
					if (ep >= &expbuf[ESIZE])
						goto cerror;
				}
#if CABLESECTION
			} while ((c = *cp++) != '>');
#else

			} while ((c = *cp++) != ']');
#endif
			lastep[1] = cclcnt;
			continue;

#if (!CABLESECTION)
		defchar:
#endif
		default:
			*ep++ = CCHR;
			*ep++ = c;
		}
	}
	cerror:
	expbuf[0] = 0;
	error(EREGEXP);
}

int
hoc_regexp_search(const char* tar) { /*return true if target matches pattern*/
	char *target = (char*)tar;
	register char *p1, *p2, c;

#if 1
	if (target == (char *)0) {
		return(0);
	}
	p1 = target;
	locs = (char *)0;
#else	/* in e, apparently for searches within or at begining of string */
	if (gf) {
		if (circfl)
			return(0);
		p1 = linebuf;
		p2 = genbuf;
		while (*p1++ = *p2++);
		locs = p1 = loc2;
	} else {
		if (addr==zero)
			return(0);
		p1 = getline(*addr);
		locs = NULL;
	}
#endif
	p2 = expbuf;
	if (circfl) {
		loc1 = p1;
		return(advance(p1, p2));
	}
	/* fast check for first character */
	if (*p2==CCHR) {
		c = p2[1];
		do {
			if (*p1!=c)
				continue;
			if (advance(p1, p2)) {
				loc1 = p1;
				return(1);
			}
		} while (*p1++);
		return(0);
	}
	/* regular algorithm */
	do {
		if (advance(p1, p2)) {
			loc1 = p1;
			return(1);
		}
	} while (*p1++);
	return(0);
}

static int advance(char* lp, char* ep)
{
	register char *curlp;

	for (;;) switch (*ep++) {

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

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

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

	case CEOF:
		loc2 = lp;
		return(1);

#if CABLESECTION
	case INTRANGE:
	   { int start, stop, num;
		start = int_range_start[*ep];
		stop = int_range_stop[*ep++];
		num = *lp++ - '0';
		if (num < 0 || num > 9) {
			return(0);
		}
		while(*lp >= '0' && *lp <= '9') {
			num = 10*num + *lp - '0';
			++lp;
		}
		if (num >= start && num <= stop) {
			continue;
		}
	   }
		return(0);
#endif

	case CCL:
		if (hoc_cclass(ep, *lp++, 1)) {
			ep += *ep;
			continue;
		}
		return(0);

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

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

	case CKET:
		braelist[*ep++] = lp;
		continue;

	case CDOT|STAR:
		curlp = lp;
		/*EMPTY*/
		while (*lp++);
		goto star;

	case CCHR|STAR:
		curlp = lp;
		/*EMPTY*/
		while (*lp++ == *ep);
		ep++;
		goto star;

	case CCL|STAR:
	case NCCL|STAR:
		curlp = lp;
		/*EMPTY*/
		while (hoc_cclass(ep, *lp++, ep[-1]==(CCL|STAR)));
		ep += *ep;
		goto star;

	star:
		do {
			lp--;
			if (lp==locs)
				break;
			if (advance(lp, ep))
				return(1);
		} while (lp > curlp);
		return(0);

	default:
		error(EREGEXP);
	}
}

static int hoc_cclass(char* set, char c, int af)
{
	register int n;

	if (c == 0)
		return(0);
	n = *set++;
	while (--n)
		if (*set++ == c)
			return(af);
	return(!af);
}


