#import <RCString.h>
/*
    Copyright (C) 1992. Bruce Ediger.

      This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Library General Public License.
*/

#ifdef BSD_REGEXP
#import <regex.h>
#endif

#ifdef GNU_REGEXP
// This part is very dependant on directory setup.
// You'll have to modify it.
#import <sys/types.h>
#import "regex-0.11/regex.h"
#endif

//
// implementation of methods having to do with regular expressions
//

@implementation RCString (Regex)

- objectMatching:(char *)aRegex
{
	RCString *orNewString = NULL;
	char *bprString = NULL;

	if (aRegex && (bprString = [self subStringMatching:(char *)aRegex]))
	{
		if ((orNewString = [[RCString alloc] init]))
		{
			orNewString->p->s = bprString;
			orNewString->p->l = strlen(bprString) + 1;
			orNewString->p->n = 1;
		}
	}

	return orNewString;
}

- (char *)subStringMatching:(char *)abvRegex
{
	char *bprString = NULL;
#ifdef BSD_REGEXP

	if (abvRegex == NULL)
		return NULL;  // ???

	if (p && p->s && p->l > 1) {
		struct regex *spRegex;
		// compile regular expression
		spRegex = (struct regex *)re_compile(abvRegex, yCaseSensitive?0:1);
		if (spRegex == NULL)
			return NULL;

		// check match
		if (re_match(p->s,  spRegex) == 1) {
			// Got a match.
			int iMatchLen = (int)spRegex->end - (int)spRegex->start;
			if (iMatchLen > 0) {
				bprString = malloc(iMatchLen + 1);
				if (bprString) {
					bcopy((char *)spRegex->start, bprString, iMatchLen);
					bprString[iMatchLen] = '\0';
				}
			}
		} // else, no match, return NULL;
		free(spRegex);  // spRegex guaranteed non-NULL
	}

#endif

#ifdef GNU_REGEXP
	// uses the Posix regular expression interface to GNU regex-0.11
	regex_t    tsRegex;
	regmatch_t tvMatchBuffer[2];

	if (abvRegex == NULL)
		return FALSE;  // ???

	// initialize the regex_t struct
	tsRegex.translate = 0;
	tsRegex.fastmap = 0;
	tsRegex.buffer = 0;
	tsRegex.allocated = 0;

	if (regcomp(&tsRegex, abvRegex, REG_NEWLINE) != 0) {
		// pattern compilation failed
		// could attempt some corrective action
		return FALSE;
	} else {
		if (p && p->s && p->l > 1
			&& (regexec(&tsRegex, p->s, 1, tvMatchBuffer, 0) == 0))
		{
			// found a match, allocate string and copy matched string
			int iMatchLen = tvMatchBuffer[0].rm_eo - tvMatchBuffer[0].rm_so;
			if ((bprString = malloc(iMatchLen + 1))) {
				bcopy(&(p->s[tvMatchBuffer[0].rm_so]), bprString, iMatchLen);
				bprString[iMatchLen] = '\0';
			}
		} // else, return is already NULL
	}

	regfree(&tsRegex);
#endif
	return bprString;
}

- (BOOL)matches:(char *)abvRegex
{
	BOOL yrRetval = FALSE;

#ifdef BSD_REGEXP

	if (abvRegex == NULL)
		return FALSE;  // ???

	if (p && p->s && p->l > 1) {
		struct regex *spRegex;
		// compile regular expression
		spRegex = (struct regex *)re_compile(abvRegex, yCaseSensitive?0:1);
		if (spRegex == NULL)
			return FALSE;

		// check match
		if (re_match(p->s,  spRegex) == 1)
			yrRetval = TRUE;

		free(spRegex);
	} // else, return is already FALSE

#endif

#ifdef GNU_REGEXP
	// use the Posix regular expression interface to GNU regex-0.11
	regex_t    tsRegex;
	regmatch_t tvMatchBuffer[2];

	if (abvRegex == NULL)
		return FALSE;  // ???

	// initialize the regex_t struct
	tsRegex.translate = 0;
	tsRegex.fastmap = 0;
	tsRegex.buffer = 0;
	tsRegex.allocated = 0;

	if (regcomp(&tsRegex, abvRegex, REG_NEWLINE) != 0) {
		// pattern compilation failed
		// could attempt some corrective action
		return FALSE;
	} else {
		if (p && p->s && p->l > 1
			&& (regexec(&tsRegex, p->s, 1, tvMatchBuffer, 0) == 0))
					yrRetval = TRUE;
		// else, return is already FALSE
	}

	regfree(&tsRegex);
#endif

	return yrRetval;
}

- replaceSubStringMatching:(char *)abvRegex with:(char *)aString
{
#ifdef BSD_REGEXP
	if (abvRegex != NULL && p && p->s && p->l > 1) {

		struct regex *spRegex;

		// compile regular expression
		spRegex = (struct regex *)re_compile(abvRegex, yCaseSensitive?0:1);

		// check match
		if (aString && spRegex != NULL && re_match(p->s,  spRegex) == 1)
		{
			// Got a match.
			[self replaceStringAt:((int)spRegex->start - (int)p->s)
				extent:((int)spRegex->end - (int)spRegex->start)
				with:aString];
		} // else, no match

		if (spRegex) free(spRegex); 
	}
#endif

#ifdef GNU_REGEXP
	// uses the Posix regular expression interface to GNU regex-0.11
	if (abvRegex) {
		regex_t    tsRegex;
		regmatch_t tvMatchBuffer[2];

		if (regcomp(&tsRegex, abvRegex, REG_NEWLINE) != 0) {
			// pattern compilation failed
			// could attempt some corrective action
			[self error:"Compiling a Posix regular expression"];
		} else {
			// initialize the regex_t struct
			tsRegex.translate = 0;
			tsRegex.fastmap = 0;
			tsRegex.buffer = 0;
			tsRegex.allocated = 0;

			if (p && p->s && p->l > 1
				&& (regexec(&tsRegex, p->s, 1, tvMatchBuffer, 0) == 0))
			{
				// found a match
				[self replaceStringAt:tvMatchBuffer[0].rm_so
					extent:(tvMatchBuffer[0].rm_eo - tvMatchBuffer[0].rm_so)
					with:aString];
			} // else, no change to internal string rep
		}

		regfree(&tsRegex);
	}
#endif
	return self;
}

@end
