/* 
Known bugs:
	Does not handle strings starting with \B
	Does not handle a(.*)b correctly 
  
    [\x20-\x60]%a%false
\b = word boundary
\B = not word boundary

  \r\n\t  cr lf tab 

This is a regular expression library, it's not 100% legit but it's
fast and reliable and I understand it.

regcomp takes a regular expression and compiles it into 
a linked list of objects, each object is one of:
	a single character match
	a mask of characters (char set) to match
	a list of objects to match
	...
The regexec applies teh given compiled objects to a string
and returns true or false if it matches.

*/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#ifdef TESTONLY
//#include "dmalloc.h"
#endif
#include "regex.h"
#define BFSZ 1000
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif

#ifndef TESTING
#define printf imsg
#else
#define imsg printf
#endif

#define dbg if (debug)

static int debug = FALSE;
int reg_test_file(char *fname);
int imsg(const char * arg_list, ...);
#ifdef TESTING
int main(int argc, char *argv[])
{
	int r;
	char bf[BFSZ];
	char *s=bf;
	regex_t reg;
	debug = TRUE;
	if (argc<2) {
		printf("Usage: regexp -file x.dat\n");
		printf("Usage: regexp -speed x.dat\n");
//		return 0;
	}
	if (argc>1) if (strcmp(argv[1],"-file")==0) {
		reg_test_file(argv[2]);
		return 0;
	}
	printf("Enter test expression ? ");
	gets(bf);
	r = regcomp(&reg,bf,0);
	reg_show(reg.list);
	printf("Enter test string ? ");
	gets(bf);
	r = reg_find_start(s,&reg);
	if (r) {dbg printf("Matched ok\n");}
	else {dbg printf("Didn't match\n");}
	return 0;
}
#endif
#define SEP "%"
int reg_test_file(char *fname)
{
	FILE *f;
	regex_t reg;
	char exp[BFSZ];
	char data[BFSZ];
	char bf[BFSZ];
	char *s=bf;
	int expect;
	int r;

	debug = TRUE;
	f = fopen(fname,"r");
	if (f==NULL) {perror(fname); return 0;}
	for (;!feof(f);) {
		if (fgets(bf,BFSZ-1,f)==NULL) break;
		s = strtok(bf,SEP); if (s==NULL) continue;
		strcpy(exp,s);
		s = strtok(NULL,SEP); if (s==NULL) continue;
		strcpy(data,s);
		s = strtok(NULL,"\r\n"); if (s==NULL) continue;
		if (strcmp(s,"true")==0) expect=TRUE;
		else expect=FALSE;
		
		printf("%s!%s!%s\n",exp,data,s);
		r = regcomp(&reg,exp,0);
		reg_show(reg.list);
		strcpy(bf,data); s = bf;

		r = reg_find_start(s,&reg);
		regfree(&reg);
		if (r) {dbg printf("Matched ok\n");}
		else {dbg printf("Didn't match\n");}
		if (r!=expect) {
			printf("----------------------------FAILED\n");
			printf("%s!%s!%d\n",exp,data,expect);
			exit(0);
		}
	}
	fclose(f);
#ifdef TESTONLY
/*	d_check();*/
#endif
	return 0;
}
Obj * reg_newobj(void)
{
	Obj *a;
	a = malloc(sizeof(Obj));
	if (a==NULL) abort();
	memset(a,0,sizeof(Obj));
	a->c = '*';
	return a;
}
int reg_setdebug(int x)
{
	debug = x;
	return TRUE;
}
static int rcode;
static unsigned char *bol;
static int icase;
static unsigned char *best;
static unsigned char xisword[MAXCHAR];
static int done_init;
int regcomp(regex_t *reg, char *zin, int flags)
{
	int i;
	unsigned char *in= (unsigned char *) zin;
	unsigned char fake[2];
	unsigned char mask[MAXCHAR];
	Obj *ocopy;
	unsigned char *incopy;
	int x;

	if (!done_init) {
		done_init = TRUE;
		for (i=0; i<MAXCHAR; i++) {
			if ((i>='a') && (i<='z')) xisword[i] = TRUE;
			if ((i>='A') && (i<='Z')) xisword[i] = TRUE;
			if ((i>='0') && (i<='9')) xisword[i] = TRUE;
			if (i=='_') xisword[i] = TRUE;
		}
	}
	rcode = 0;
	reg->list = r_comp_all(&in);
	reg->list->icase = ((flags & REG_ICASE)>0);
	icase = reg->list->icase;
	x = debug;
	debug = FALSE;
	for (i=1; i<255; i++) {
		mask[i] = FALSE;
		fake[0] = (unsigned char) i;
		fake[1] = 0;
		bol = fake;
		ocopy = reg->list;
		incopy = fake; best = incopy;
		reg_match(&incopy,&ocopy);
		if (best!=fake) {
			mask[i] = TRUE;
			if (x) printf("Mask %c\n",i);
		}
	}
	debug = x;
	reg->list->mask = malloc(MAXCHAR);
	memcpy(reg->list->mask,mask,MAXCHAR);		

	return rcode;
}
static int dep;
Obj *r_comp_all(unsigned char **in)
{
	unsigned char *s;
	Obj *o,*t,*list;
	o = list = reg_newobj();
	dbg printf("Root object %p\n",o);
	o->type = T_OR;
	dep++;
	if (dep>400) {
		dep--;
		imsg("r_comp_all stack overflow");
		return NULL;
	}
	for (s=*in;*s!=0;) {
		t = r_comp_any(&s);
		if (t!=NULL) reg_show_obj(t);

		if (t==NULL) break;
		if (t->type==T_OR_TOP) {
			dbg imsg("[%d] Pointing new %p to %p\n",dep,t,list);
			t->type = T_OR;
			t->or = list;
			list = t;
			o = t;
			dbg imsg("[%d] lastT=%p %s\n",dep,o,rtype[o->type]);
		} else {
			if (o->next!=NULL) {
				printf("Pointer not null %p next=%p new=%p\n",o,o->next,t);
				exit(0);
			}
			dbg imsg("[%d] Adding %p to %p, type %s\n",dep,t,o,rtype[o->type]);
			o->next = t;
			o = o->next;
			dbg imsg("[%d] last=%p %s\n",dep,o,rtype[o->type]);
		}
	}
	dep--;
	*in = s;
	return list;
}
static char failmsg[BFSZ];
char *reg_error(void)
{
	return failmsg;
}
int regerror(int e, regex_t *reg, char *bf, int bfsz)
{
	strncpy(bf,failmsg,bfsz-2);
	return 0;
}
void reg_freeobj(Obj *o)
{
	if (o->mask!=NULL) free(o->mask);
	dbg printf("Free %p %c\n",o,o->c);
	free(o);
}
int regfree_list(Obj *o);
int regfree(regex_t *reg)
{
	dbg imsg("regfree(%p)\n",reg->list);
	regfree_list(reg->list);
	reg->list = NULL;
	return TRUE;
}
int regfree_list(Obj *o)
{
	Obj *next;
	dbg imsg("regfree_list %p\n",o);
	for (;o!=NULL;o=next) {
		next = o->next;
		if ((o->type==T_OR) ||(o->type==T_GROUP) || (o->type==T_NOT)) {
			regfree_list(o->or);
		}
		reg_freeobj(o);	
	}
	return TRUE;
}
int regexec(regex_t *reg, char *in, int xx, char *yy, int zz)
{
	char *s;
	icase = reg->list->icase;
	s = reg_find(in,reg);
	if (s==NULL) return TRUE;
	return FALSE;
}

int r_comp_modifier(Obj *o, unsigned char **in)
{
	unsigned char c =  **in;
	unsigned char *s;
	o->min = o->max = 1;
	switch (c) {
	case '*': /* . zero or more of last char */
		o->min = 0;
		o->max = 9999;
		(*in)++;
		break;
	case '?': /* . zero or one of last char */
		o->min = 0;
		o->max = 1;
		(*in)++;
		break;
	case '+': /* . One or more of last char */
		o->min = 1;
		o->max = 9999;
		(*in)++;
		break;
	case '{': /* . Number or range of last char */
		s = *in;
		o->min = atoi((char * ) (s+1));
		o->max = o->min;
		for (;*s!=0;s++) {
			if (*s==',') o->max = atoi((char *)(s+1));
			if (*s=='}') break;
		}
		if (*s != '}') rfail("No right brace found %s",*in);
		else s++;
		*in = s;
		break;
	}	
	return TRUE;
}
/*
\s [ \t]
\S [^ \t]
\d [0-9]
\D [^0-9]
*/
unsigned char get_hex(unsigned char *s)
{
	char bf[10];
	int x;
	strncpy(bf,s,2); bf[2] = 0;
	sscanf(bf,"%x",&x);
	return (unsigned char ) x;
}
Obj *r_comp_any(unsigned char **in)
{
	unsigned char c =  **in;
	unsigned char *s;
	Obj *o,*o2;
	o = reg_newobj();
	dbg printf("comp_any %c  %p  %s\n",c,o,*in);
	(*in)++;

	switch (c) {
	case '.': /* . (period) represents any one character.*/
		o->type = T_ANY;
		r_comp_modifier(o,in);
		return o;
	case '[': /* . start of a set or ^ not set */
		o->type = T_MASK;
		r_comp_set(o,in);
		r_comp_modifier(o,in);
		break;
	case '\\': /* . next character literal or special */
		if ((*in)[0]=='s') {
			o->type = T_MASK;
			s = (unsigned char *) " \t]";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='S') {
			o->type = T_MASK;
			s = (unsigned char *) "^ \t]";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='w') {
			o->type = T_MASK;
			s = (unsigned char *) "0-9a-zA-Z_]";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='W') {
			o->type = T_MASK;
			s = (unsigned char *) "^0-9a-zA-Z_";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='d') {
			o->type = T_MASK;
			s = (unsigned char *) "0-9]";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='D') {
			o->type = T_MASK;
			s = (unsigned char *) "^0-9]";
			r_comp_set(o,&s);
			(*in)++;
			r_comp_modifier(o,in);
		} else if ((*in)[0]=='b') {
			o->type = T_BOUNDARY;
			(*in)++;
		} else if ((*in)[0]=='B') {
			o->type = T_NBOUNDARY;
			(*in)++;
		} else if ((*in)[0]=='<') {
			o->type = T_BEGIN_WORD;
			(*in)++;
		} else if ((*in)[0]=='>') {
			o->type = T_END_WORD;
			(*in)++;
		} else if ((*in)[0]=='x') {
			o->type = T_CHAR;
			(*in)++; /* skip the x */ 
			o->c = get_hex(*in);
			(*in) += 2;
			r_comp_modifier(o,in);
			return o;
		} else if ((*in)[0]=='r') {
			o->type = T_CHAR;
			o->c = '\r';
			(*in)++;
			r_comp_modifier(o,in);
			return o;
		} else if ((*in)[0]=='n') {
			o->type = T_CHAR;
			o->c = '\n';
			(*in)++;
			r_comp_modifier(o,in);
			return o;
		} else if ((*in)[0]=='t') {
			o->type = T_CHAR;
			o->c = '\t';
			(*in)++;
			r_comp_modifier(o,in);
			return o;
		} else {		
			o->type = T_CHAR;
			o->c = **in;
			(*in)++;
			r_comp_modifier(o,in);
			return o;
		}
		break;
	case '^': /* . start of line  */
		o->type = T_START;
		r_comp_modifier(o,in);
		break;
	case '$': /* . end of line  */
		o->type = T_END;
		r_comp_modifier(o,in);
		break;
	case '|': /* . Or   */
		/*if (**in=='(') (*in)++;*/
		o->type = T_OR_TOP;	  
		break;
	case '(': /* . Or list */
		  /* (?!=lookahead  (?:=normal*/
		if (((*in)[0]=='?') && ((*in)[1]=='!')) {
			(*in) += 2;
			o2 = r_comp_all(in);
			o->or = o2;
			o->type = T_NOT;
		} else {
			if (((*in)[0]=='?') && ((*in)[1]==':')) (*in) += 2;
			o2 = r_comp_all(in);
			o->or = o2;
			o->type = T_GROUP;
			r_comp_modifier(o,in);
		}
		break;
	case ')': /* . Or list "...)|(..." or "...)"   */
		reg_freeobj(o);
		return NULL;
		/*if (**in!='|') {
			return NULL;
		}
		o->type = T_OR_TOP;
		(*in)+=2;
		*/
		break;
	default:
		o->type = T_CHAR;
		o->c = c;
		dbg imsg("New Object %p c=%c\n",o,c);
		r_comp_modifier(o,in);
		break;
	}
	return o;
}

/*
Deal with [afasfdasda-z1-3]
Deal with and [^afasfdasda-z1-3]
*/
int r_comp_set(Obj *o,unsigned char **in)
{
	char mask[MAXCHAR];
	unsigned char *s;
	unsigned int k;
	unsigned char c,c2;
	int i;
	int isnot=FALSE;
	for (i=0; i<MAXCHAR; i++) mask[i] = FALSE;
	if (**in=='^') {isnot=TRUE; (*in)++;}
	for (s=*in; *s!=0; s++) {
		if (*s==']') {s++; break;}
		c = *s;
		if (c=='\\') {
			s++;
			c = *s;
			if (c=='r') c = '\r';
			if (c=='n') c = '\n';
			if (c=='t') c = '\t';
			if (c=='x') {
				c = get_hex(s+1);
				s++;
				if (*s!=0) s++;
			}
		}
		mask[c] = TRUE;
		if (s[1]=='-') {
			s += 2;
			c2 = *s;
			if (c2=='\\') {
				s++;
				c2 = *s;
				if (c2=='r') c2 = '\r';
				if (c2=='n') c2 = '\n';
				if (c2=='t') c2 = '\t';
				if (c2=='x') {
					c2 = get_hex(s+1);
					s++;
					if (*s!=0) s++;
				}
			}
			for (k=c;k<=c2;k++) {
				if (k>=MAXCHAR) break;
				if (k<0) break;
				mask[k] = TRUE;
			}
		}
		if (*s==0) break;
	}
	*in = s;
	if (isnot) {
		for (i=0; i<MAXCHAR; i++) mask[i] = (char) (!mask[i]);
	}
	o->mask = malloc(MAXCHAR);
	memcpy(o->mask,mask,MAXCHAR);
	return TRUE;
}
static int depth;
void reg_show(Obj *o)
{
	depth++;
	if (o==NULL) {depth--; return;}
	dbg printf("Show object List %p type=%s (%c)\n",o,rtype[o->type],o->c);
	for (;o!=NULL;o=o->next) {
		reg_show_obj(o);	
		if ((o->type==T_GROUP) ||(o->type==T_OR) || (o->type==T_NOT)) {
			reg_show(o->or);
		}
	}
	depth--;
}
void reg_show_obj(Obj *o)
{
	dbg printf("%p %d Obj type=%s, c='%c' %d-%d mask %p, or=%p next=%p\n",
		o,depth,rtype[o->type],o->c,o->min,o->max,o->mask,o->or,o->next);
}
#ifdef WIN32
#define vsnprintf _vsnprintf
#endif
#ifdef OS2
#define vsnprintf _vbprintf
#endif
int rfail(const char * arg_list, ...)
{
        va_list arg_ptr;
        char *format;
        va_start(arg_ptr, arg_list);
        format = (char *) arg_list;
        vsnprintf(failmsg,400, format, arg_ptr);
	rcode = 1;
	return 0;
}
char *reg_find(char *xin, regex_t *r)
{
	Obj *ocopy;
	unsigned char *incopy;
	unsigned char *mask;
	unsigned char *in= (unsigned char *) xin;
	bol = in;

	mask = 	r->list->mask;
	strcpy(failmsg,"None");
	for (;*in!=0;in++) {
		if (mask[(unsigned char) (*in)]) { 
			ocopy = r->list;
			incopy = in;
			dbg imsg("=======reg_find_mask(%s)\n",in);
			if (reg_match(&incopy,&ocopy)) {
				strncpy(failmsg,(char *) in,30);
				failmsg[20] = 0;
				return (char *) in;
			}
		}
	}
	return NULL;
}
int reg_find_start(char *in, regex_t *r)
{
	Obj *ocopy;
	unsigned char *incopy;
	bol = (unsigned char *) in;
	ocopy = r->list;
	incopy = (unsigned char *) in;
	if (reg_match(&incopy,&ocopy)) return TRUE;
	return FALSE;
}
int reg_match(unsigned char **in,Obj **o)
{
	Obj *ocopy;
	int r;
	if (*o==NULL) {
		printf("End of objects\n");
		if (best<(*in)) best = *in;
		return TRUE;
	}
	depth++;
	if (depth>500) {
		imsg("Stack overflow in reg_match()\n");
		depth--;
		return FALSE;
	}
	dbg printf("reg_match(%d) (%s)\n",depth,*in);
	for (;*o!=NULL;) {
		if ((*o)->type==T_OR) {
			ocopy = (*o)->or;
			if (ocopy!=NULL) {
				r = reg_match(in,&ocopy);
				if (r) {
					/* *o = ocopy;*/
					if (best<(*in)) best = *in;
					depth--;
					return TRUE;
				}
			}
			*o = (*o)->next;
			continue;
		}
		if (reg_match_list(in,o)) {
			if (best<(*in)) best = *in;
			depth--;
			return TRUE;	
		}
		else break;
	}
	if (best<(*in)) best = *in;
	depth--;
	return FALSE;
}
int reg_match_list(unsigned char **in, Obj **ocur)
{
	unsigned char *s,*ss;
	int r;
	s = *in;
	dbg printf("Match_list (%s)\n",*in);
	for (;(*ocur)!=NULL;) {
		ss = s;
		r = reg_match_one(&s,ocur);
		dbg printf("reg_match_one %d (%s) (%s)\n",r,ss,s);
		if (!r) {
			if (best<(s)) best = s;
			return FALSE;
		}
		/* /if (r) if (*s==0) break; */
	}
	dbg printf("reg_match_list_succeded\n");
	*in = s;	
	if (best<(*in)) best = *in;
	return TRUE;
}
int reg_match_next(unsigned char **in, Obj **o) 
{
	unsigned char *xin;
	int r;
	Obj *xo;
	xo = (*o)->next;
	xin = *in; /* ++xin; */
	r = reg_match(&xin,&xo);
	if (r) {
		*in = xin;
		*o = xo;
	}
	if (best<(xin)) best = xin;
	return r;
}
static const unsigned char charmap[] = {
        0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
        0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
        0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
        0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
        0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
        0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
        0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
        0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
        0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
        0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
        0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
        0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
        0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
        0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
        0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
        0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
        0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
        0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
        0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
        0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
        0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
        0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
        0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
        0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
        0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
        0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
        0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
        0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
        0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
        0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
        0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
        0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
};
int reg_match_one(unsigned char **in, Obj **ocur)
{
	unsigned char *s = (unsigned char *) *in;
	int i;
	Obj *ocopy;
	Obj *o = *ocur;
	unsigned char *ss;

	dbg printf("From (%s)\n",*in);
	reg_show_obj(o);

	switch (o->type) {
	case T_CHAR:
		for (i=0; i<o->max; i++) {
			if (icase) {
				if (charmap[s[i]]!=charmap[o->c]) break;
			} else {
				if (s[i]!=o->c) break; 
			}
			if (s[i]==0) break;
			dbg printf("%d t_char [%d]=%c == %c\n",depth,i,s[i],o->c);
			if (o->max>=(i+1)) if ((i)>=o->min) {
				dbg printf("%d Check rest of string %s\n",depth,*in);
				(*in) += i;
				if (reg_match_next(in,ocur)) return TRUE;
				(*in) -= i;
			}
			if (best<(*in)+i+1) best = *in+i+1;
		}
		dbg printf("%d t_char MATCHED SOME (%c) %d %p (%s)\n",depth,o->c,i,o,*in+i);
		if (i<o->min) return FALSE;
		*in += i;
		break;
	case T_MASK:
		for (i=0; i<o->max; i++) {
			if (s[i]==0) break;
			dbg printf("%d t_mask [%d]=%c =mask\n",depth,i,s[i]);
			if (!o->mask[s[i]]) break; 
			if (o->max>=(i+1)) if ((i)>=o->min) {
				(*in) += i;
				if (reg_match_next(in,ocur)) return TRUE;
				(*in) -= i;
			}
			if (best<(*in)+i+1) best = *in+i+1;
		}
		dbg printf("%d t_mask MATCHED SOME  %d (%s)\n",depth,i,*in+i);
		if (i<o->min) return FALSE;
		*in += i;
		break;
	case T_ANY:
		for (i=0; i<o->max; i++) {
			if (s[i]==0) break;
			dbg printf("%d t_any [%d]=%c \n",depth,i,s[i]);
			if (o->max>=(i+1)) if ((i)>=o->min) {
				(*in)+= i;
				dbg printf("---> %d t_any [%d]=%c rest (%s)\n",depth,i,s[i],*in);
				if (reg_match_next(in,ocur)) return TRUE;
				(*in)-= i;
			}
			if (best<(*in)+i+1) best = *in+i+1;
		}
		dbg printf("%d t_anyMATCHED SOME  %d (%s)\n",depth,i,*in+i);
		if (i<o->min) return FALSE;
		*in += i;
		break;
	case T_BOUNDARY: /*  \bcat\b  .cat.*/
		*ocur = (*ocur)->next;
		if (*in==bol) return TRUE;
		if (xisword[**in]!=xisword[*((*in)-1)]) return TRUE;
		return FALSE;
	case T_BEGIN_WORD: /*  \<cat  */
		*ocur = (*ocur)->next;
		if (*in==bol) if (xisword[**in]) return TRUE;
		if (xisword[**in]) if (!xisword[*((*in)-1)]) return TRUE;
		return FALSE;
	case T_END_WORD: /*  cat\>  */
		*ocur = (*ocur)->next;
		if (*in==bol) return FALSE;
		if (!xisword[**in]) if (xisword[*((*in)-1)]) return TRUE;
		return FALSE;
	case T_NBOUNDARY: /*  \bcat\b  .cat.*/
		*ocur = (*ocur)->next;
		if (*in==bol) return FALSE;
		if (xisword[**in]!=xisword[*((*in)-1)]) return FALSE;
		return TRUE;
	case T_START:
		*ocur = (*ocur)->next;
		if (*in!=bol) return FALSE;
		return TRUE;
	case T_END:
		if (s[0]==0) break;
		if (s[0]=='\r') break;
		if (s[0]=='\n') break;
		*ocur = (*ocur)->next;
		return FALSE;
	case T_NOT:
		ocopy = o->or;
		if (reg_match(&s,&ocopy)) {
			return FALSE;
		}
		*ocur = (*ocur)->next;
		return TRUE;
	case T_OR:
		ocopy = o;
		if (reg_match(&s,&ocopy)) {
			*in = s;
			/* *ocur = ocopy; */
			*ocur = (*ocur)->next;
			return TRUE;
		}
		*ocur = (*ocur)->next;
		return FALSE;
	case T_GROUP:
		for (i=0; i<o->max; i++) {
			dbg printf("%d t_group [%d]=%c \n",depth,i,s[i]);
			if (s[i]==0) break;
			if (o->max>=(i+1)) if ((i)>=o->min) {
				(*in) += i;
				if (reg_match_next(in,ocur)) return TRUE;
				(*in) -= i;
			}
			ss = s;
			ocopy = o->or;
			if (reg_match(&ss,&ocopy)) {
				s = ss;
			} else break;
			if (best<(s)) best = s;
		}
		if (i<o->min) return FALSE;
		*in = s;
		*ocur = (*ocur)->next;
		return TRUE;
	}
	*ocur = (*ocur)->next;
	return TRUE;
}

#undef printf
#ifdef TESTONLY
int imsg(const char * arg_list, ...)
#else 
int imsg_regex(const char * arg_list, ...)
#endif
{
        va_list arg_ptr;
        char *format;
	FILE *f;
	char output[BFSZ];
        va_start(arg_ptr, arg_list);
        format = (char *) arg_list;
        vsnprintf(output,400, format, arg_ptr);

	printf("%s",output);
	f = fopen("r.log","a");
	if (f==NULL) return 0;
	fprintf(f,"%s",output);
	fclose(f);
	return 0;
}
