/******************************************************************************
 JRegex.cc

	JRegex is the JCore regular-expression pattern-matching class.  It provides
	regular expression-based search and replace facilities with a convenient,
	safe interface which is idiomatic in both C++ and JCore.
	
	JRegex uses a JIndexRange-oriented interface.  This means that JRegex can
	do in-place search and replace on very large strings without copying more
	text than is necessary (and in fact was originally designed for use in a
	text editor whose buffers are single strings and can contain megabytes).

	JCore Regex Extensions

	JRegex normally provides some simple extensions to the regular
	expression language provided by regex; see SetNoJExtended and
	JSubstitute for details.  However, normal C-style backslash escapes for
	special characters like '\n' are still not expanded, because in many
	context (notably C++ source) this is done by some other tool.  If you
	need to do this yourself it is probably because you are allowing your
	users to type in a regular expression string, in which case you
	probably need fine control over which escapes can be used ('\0' or '\b'
	are often inappropriate, for example), which would be clumsy to supply
	in JRegex.  Instead JRegex can be queried for the objects it uses to
	interpolate matches and to expand excapes so they can be customized as
	necessary.

	USAGE:

	In spite of the number of methods defined, usage is straightforward.  A
	pattern is set with the constructor or the SetPattern method.  Matches are
	then performed with Match... and friends, while replacement is performed
	with the Replace method.  See the notes on the individual functions for
	details.  The apparent complexity of the class derives from the large number
	of convenience functions in the Match... family.  Most of them are written
	in terms of a small number of fundamental operations, and could easily have
	been written by the client.  In other words, while JRegex has a large
	"surface area" (Brad Cox's term for a class with a large public interface),
	once a small number are understood the usage of the others will be obvious.
	The number of methods that must be understood to use JRegex can be as small
	as two for simple problems.

	The best way to understand JRegex is to start by using it with only two
	methods, SetPattern and Match(JCharacter*).  Then add Match(JCharacter*,
	JIndexRange*), and then Match(JCharacter*, JArray<JIndexRange>*).  At
	this point the entire match interface should be readily understood.  After
	adding SetReplacePattern and Replace to your reportoire, the rest of the
	interface is just customization, information, and extra Match functions you
	can learn as needed.

	Unfortunately the test suite is quite involved and not really a good way
	to learn by example.  Example code needs to be supplied soon.

	DESIGN:

	JRegex uses a dollar sign '$' for match interpolations.  Backslashes
	are used in some tools, but for several reasons it is better for both
	user and implementor to use a different symbol for character escapes
	and for match interpolation.  One is that dollar signs avoid the
	'backslashitis' which results in source code because C already expands
	them (of course, you still have to deal with this problem for character
	escapes).  They also correspond to the preferred usage in Perl,
	arguably the premier regex tool.

	The Match functions assert that a pattern has successfully been set.
	It might be more forgiving to simply return an error condition instead.
	This would, however considerably complicate the Match interface, and I
	don't think it's worth it.  It is infeasible to simply have a default
	pattern because there is no clear choice and this would only make
	things more confusing.  Just check to see that it set before calling a
	Match... function.

	Replace could assert or return an error value if called before a
	successful call to SetReplacePattern rather than assuming a default
	value of ""; again, this would crud up the code.  At some point, the
	complexity inherent in error checking is as error prone as not having
	the error checking, and I feel it is important to keep the basic JRegex
	interface clean, so the error return solution is not feasible.  The
	assert solution is a feasible alternative, and can easily be adopted if
	there is an outcry.  However, the empty string is an obvious choice, so
	the current system should be as clear as having JString's default
	constructor set its value to "".  Underuse of defaults can be almost as
	bad as overuse.

	IMPLEMENTATION:

	JRegex is really a (somewhat complex) layer over Henry Spencer's (new
	DFA, not old NFA) regex package.  It provides an improved, native C++
	interface, but the real work is underneath, in regex.  Thanks, Henry.

	JRegex was written with the intention of making it fully NULL-safe
	sometime in the future.  Some things are safe now, but the
	function-level documentation mostly refers to whether the function
	*interface* is NULL-safe; the internal implementations may still not
	be.  The actual behaviors with NULLs embedded in patterns, strings,
	replacement patterns, and as replacement metacharacters are almost
	completely untested so far, as nobody has actually needed this
	capability.  Anywhere the notes say a something is NULL-safe this
	should be read as "this is *rumored* to be NULL-safe."  Sorry about the
	vagueness, but as no one has actually needed this yet it hasn't been
	worth implementing, and you're welcome to regard it as entirely
	NULL-unsafe for now.

	The private RegExec function asserts that it did not run out of memory
	or get passed an invalid argument.  I think JRegex can guarantee that
	regex is never fed an invalid argument, so this is probably fine.

	Finally, there is one restriction inherent in the underlying regex
	package: backreferences are supported with basic but not extended
	expressions (yet).

	JRegex version: 1.1.5

	regex version: alpha 3.6

	BASE CLASS = <NONE>

	Copyright © 1997 by Dustin Laurence.  All rights reserved.
	
	Base code generated by Codemill v0.1.0

 *****************************************************************************/

// Debug
#include <iostream.h>

//Class Header
#include <JRegex.h>

#include <JSubstitute.h>
#include <JInterpolate.h>

#include <jAssert.h>

	// Constants
	const JCharacter* JRegex::kError = "Error::JRegex";

	// Changable static data
//	JInterpolate* JRegex::theInterpolator = NULL;

//	JSubstitute* JRegex::theEscapeEngine = NULL;

	// regex utilities
	static void MakeRangeArray(JIndexRange subMatchArray[], JSize size,
	                      regmatch_t pmatch[], JSize subCount);
	static void MakeRangeList(JArray<JIndexRange>* subMatchList,
	                     regmatch_t pmatch[], JSize subCount);

	// Constant static data (i.e. ordinary file scope constants)
	// WARNING: JRegex assumes that REG_PEND is *always* set, so it must
	//          always be in the defaults list!
	static const int defaultCFlags = REG_NEWLINE | REG_PEND;
	static const int defaultEFlags = 0;
	static const JRegex::Dialect defaultDialect = JRegex::kExtended;

	// JAFL 5/11/98
	const JString JRegex::theSpecialCharList = ".[]\\?*+{}|()^$";

/******************************************************************************
 Constructor

	The form which takes a pattern argument automatically does a SetPattern,
	which is convenient.  However, it also asserts that this pattern was
	successfully compiled, which can be rather inconvenient if you make a
	mistake.  So don't make mistakes (or don't use that constructor). :-)

 *****************************************************************************/

JRegex::JRegex()
	:
	itsPattern(),
	itsNULLCount(0),
//	itsRegex(), // It's Spencer's struct, we don't know the fields
	itsCFlags(defaultCFlags),
	itsEFlags(defaultEFlags),
	itsReplacePattern(NULL),
	itsInterpolator(NULL),
	itsEscapeEngine(NULL),
	itsState(kEmpty),
	itsNoJExtendedFlag(kFalse),
	itsLiteralReplaceFlag(kFalse),
	itsMatchCaseFlag(kFalse)
{
	Allocate();
	SetDialect(defaultDialect);
}


JRegex::JRegex
	(
	const JCharacter* pattern,
	const JBoolean    useJExtended // = kFalse
	)
	:
	itsPattern(),
	itsNULLCount(0),
//	itsRegex(), // It's Spencer's struct, we don't know the fields
	itsCFlags(defaultCFlags),
	itsEFlags(defaultEFlags),
	itsReplacePattern(NULL),
	itsInterpolator(NULL),
	itsEscapeEngine(NULL),
	itsState(kEmpty),
	itsNoJExtendedFlag(useJExtended),
	itsLiteralReplaceFlag(kFalse),
	itsMatchCaseFlag(kFalse)
{
	Allocate();
	SetDialect(defaultDialect);

	SetPatternOrDie(pattern); // Nothing else to do in a constructor
}


JRegex::JRegex
	(
	const JCharacter* pattern,
	const JSize       length,
	const JBoolean    useJExtended // = kFalse
	)
	:
	itsPattern(),
	itsNULLCount(0),
//	itsRegex(), // It's Spencer's struct, we don't know the fields
	itsCFlags(defaultCFlags),
	itsEFlags(defaultEFlags),
	itsReplacePattern(NULL),
	itsInterpolator(NULL),
	itsEscapeEngine(NULL),
	itsState(kEmpty),
	itsNoJExtendedFlag(useJExtended),
	itsLiteralReplaceFlag(kFalse),
	itsMatchCaseFlag(kFalse)
{
	Allocate();
	SetDialect(defaultDialect);

	SetPatternOrDie(pattern, length); // Nothing else to do in a constructor
}


// Copy constructor
JRegex::JRegex
	(
	const JRegex& source
	)
	:
	itsPattern(),
	itsNULLCount( static_cast<JSize>(-1) ), // Garbage, will be recalculated by SetPattern
//	itsRegex(), // It's Spencer's struct, we don't know the fields
	itsCFlags(source.itsCFlags),
	itsEFlags(source.itsEFlags),
	itsReplacePattern(NULL),
	itsInterpolator(NULL),
	itsEscapeEngine(NULL),
	itsState(kEmpty),
	itsNoJExtendedFlag(source.itsNoJExtendedFlag),
	itsLiteralReplaceFlag(source.itsLiteralReplaceFlag),
	itsMatchCaseFlag(source.itsMatchCaseFlag)
{
	Allocate();

	CopyPatternRegex(source);
	assert(itsNULLCount == source.itsNULLCount); // Paranoid consistency check :-)
}


void
JRegex::Allocate()
{
	itsReplacePattern = new JString;
	assert(itsReplacePattern != NULL);

	// itsInterpolator is not created until needed

	itsEscapeEngine = new JSubstitute;
	assert(itsEscapeEngine != NULL);
	itsEscapeEngine->SetPureEscapeEngine();
	itsEscapeEngine->IgnoreUnrecognized();
	itsEscapeEngine->SetRegexExtensions();

	#ifdef	JRE_ALLOC_CHECK
	numRegexAlloc = 0;
	#endif
}

/******************************************************************************
 Destructor

 *****************************************************************************/

JRegex::~JRegex()
{
	if (itsState != kEmpty)
		{
		RegFree();
		}

	delete itsReplacePattern;
	itsReplacePattern = NULL;

	delete itsInterpolator;
	delete itsEscapeEngine;
}

/******************************************************************************
 assignment operator

 *****************************************************************************/

const JRegex&
JRegex::operator=
	(
	const JRegex& source
	)
{
	if (&source != this)
		{
		itsCFlags = source.itsCFlags;
		itsEFlags = source.itsEFlags;
		CopyPatternRegex(source);
		}
	return *this;
}

/******************************************************************************
 SetPattern

	Sets 'pattern' as the regular expression for subsequent matches.
	Returns kFalse if the pattern could not be compiled, kTrue otherwise.
	If the compile fails the pattern remains set until the next call to
	SetPattern(); it can be examined with GetPattern() and an attempt to
	recompile can be made by changing the dialect with SetDialect() or
	RestoreDefaults().

	The versions which take a JString or a pointer and a length allow
	compilation of patterns which contain NULL (and also allow the
	programmer to get the length wrong and write a pattern which matches
	random garbage or seg faults, so be careful) or are not NULL
	terminated.  The pointer only form obviously allows neither pathology.

 *****************************************************************************/

JError
JRegex::SetPattern
	(
	const JCharacter* pattern
	)
{
	return SetPattern(pattern, strlen(pattern));
}


JError
JRegex::SetPattern
	(
	const JCharacter* pattern,
	const JSize       length
	)
{
	CopyPattern(pattern, length);
	return RegComp();
}


JError
JRegex::SetPattern
	(
	const JString& pattern
	)
{
	return SetPattern(pattern, pattern.GetLength());
}

/******************************************************************************
 SetPatternOrDie

	All forms are like the corresponding SetPattern forms, but they assert that
	the set succeeds.  A minor convenience, since a set followed by an assert
	seems to happen pretty frequently.

 *****************************************************************************/

void
JRegex::SetPatternOrDie
	(
	const JCharacter* pattern
	)
{
	const JError error = SetPattern(pattern);
	assert_ok( error );
}


void
JRegex::SetPatternOrDie
	(
	const JCharacter* pattern,
	const JSize       length
	)
{
	const JError error = SetPattern(pattern, length);
	assert_ok( error );
}


void
JRegex::SetPatternOrDie
	(
	const JString& pattern
	)
{
	const JError error = SetPattern(pattern);
	assert_ok( error );
}

/******************************************************************************
 SetNoJExtended

	The NoJExtended flag turns off the JCore extensions to the regular
	expression language.  It defaults to false, so the JCore extensions
	(actually they or variants are quite common in regular expression
	tools) are active (unless the dialect is kLiteral, obviously).  If set
	to true, the following constructs (actually defined in JSubstitute.cc)
	will not work:

		"\d"   a digit, [0-9]
		"\D"   a non-digit
		"\w"   a word character, [a-zA-Z0-9_]
		"\W"   a non-word character
		"\s"   a whitespace character, [ \f\n\r\t\v]
		"\S"   a non-whitespace character
		"\<"   an anchor just before a word (between \w and \W)
		"\>"   an anchor just after a word (between \W and \w)

	For more information, see the JSubstitute documentation (which is where
	these shorthands are actually implemented).

	Note that these are implemented by the escape engine and are set on
	every compile, so that changing their values directly through the
	engine rather than with this function has no effect.  At the moment,
	they are all or nothing.

 *****************************************************************************/

void
JRegex::SetNoJExtended
	(
	const JBoolean yesNo // = kTrue
	)
{
	if (itsNoJExtendedFlag != yesNo)
		{
		itsNoJExtendedFlag = yesNo;

		if (itsState == kReady && GetDialect() != kLiteral)
			{
			itsState = kRecompile;
			}
		}
}

/******************************************************************************
 GetSubCount

	Returns the number of parenthesized subexpressions in the compiled expression.
	Returns zero if there is no compiled expression, if the expression has no
	subexpressions, or if the expression was compiled with SetMatchOnly().

 *****************************************************************************/

JSize
JRegex::GetSubCount() const
{
	if (IsMatchOnly() || itsState == kEmpty || itsState == kCannotCompile)
		{
		return 0;
		}
	else
		{
		// Recompile if we see the impossible flag value set by SetCompileOption
		if (itsRegex.re_nsub == static_cast<size_t>(-1) )
			{
			JRegex* mutate = const_cast<JRegex*>(this);
			mutate->CompileOrDie();
			}

		return itsRegex.re_nsub;
		}
}

#if JRE_MAGIC
/******************************************************************************
 New Match and friends

 *****************************************************************************/

/******************************************************************************
 Match

 *****************************************************************************/

JRegex::JRegexMagic
JRegex::Match
	(
	const JCharacter* string
	)
	const
{
    return JRegexMagic(this, string);
}
#endif

/******************************************************************************
 Match and friends

	The Match family performs various kinds of searches on strings specified
	in various ways, and return various kinds of information.  A successful
	SetPattern() is required before their use.  There are a large number of
	them for convenience, but they can be understood systematically:

	There are four ways to specify the string to be searched.  The first three
	ways use a standard null-terminated string.  The Match(...) functions
	search the entire string, while the MatchFrom(...) functions search from
	a given index to the end of the string and the
	MatchAfter(...) functions search starting after a given subrange.  Finally,
	the MatchWithin(...) functions search only within a given subrange--they
	also allow nulls to be embedded in the string and treat them as ordinary
	characters, since there is no need for a null terminator to determine where
	the Match should stop.  The performance difference between these cases is
	negligible.

	Note that the MatchFrom and MatchAfter functions do not check that their
	index argument is actually within the string because this would be too
	costly on a very large string, while the MatchWithin functions cannot because
	they treat NULL as an ordinary character.  This makes it easy to specify a
	search which goes outside the intended string and gives surprising results
	or seg faults.  Be careful with these types of searches.

	There are three basic kinds of searches: report on the first match, report
	on the last match, and an iterated search for all matches.  Since in
	reality all searches are start to finish, the latter two are implemented
	internally in terms of the first (and therefore obviously are more costly).

	There are three basic types of information which can be returned about
	each match.  The simplest is whether it occured, or a count of matches
	if for an iterated search.  The second is the range(s) which the pattern
	matched, or (leave the parameter unchanged if no match was found), and the
	third is to also report the range(s) where each parenthesized subexpression
	matched.  Obtaining match ranges is expensive in terms of performance,
	obtaining subexpression matches is moreso.

 *****************************************************************************/

/******************************************************************************

	The following functions simply return kTrue if there is at least one match
	in a string, which can be specified in various ways.  They may all be
	called even when MatchOnly has been specified.

 *****************************************************************************/

#if !JRE_MAGIC
/******************************************************************************
 Match

 *****************************************************************************/

JBoolean
JRegex::Match
	(
	const JCharacter* string
	)
	const
{
	return MatchBase(string, NULL, 0);
}
#endif

/******************************************************************************
 MatchFrom

 *****************************************************************************/

JBoolean
JRegex::MatchFrom
	(
	const JCharacter* string,
	const JIndex      index
	)
	const
{
	return MatchWithin(string, JIndexRange(index, strlen(string) ) );
}

/******************************************************************************
 MatchAfter

 *****************************************************************************/

JBoolean
JRegex::MatchAfter
	(
	const JCharacter*  string,
	const JIndexRange& range
	)
	const
{
	return MatchFrom(string, range.last+1);
}

/******************************************************************************
 MatchWithin

 *****************************************************************************/

JBoolean
JRegex::MatchWithin
	(
	const JCharacter*  string,
	const JIndexRange& range
	)
	const
{
	regmatch_t pmatch;
	return MatchWithinBase(string, range, &pmatch, 0);
}

/******************************************************************************

 	Iterator versions

 *****************************************************************************/

/******************************************************************************
 MatchAll

	Perhaps inobviously, may NOT be called if SetMatchOnly is true (because
	internally it must obtain the region matched so it knows where to start
	looking for the next).

 *****************************************************************************/

JSize
JRegex::MatchAll
	(
	const JCharacter* string
	)
	const
{
	JIndexRange match(1,0);
	JSize matchCount = 0;

	while (MatchAfter(string, match, &match))
		{
		if ( match.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if (string[match.first-1] == '\0')
				{
				break; // Avoid calling MatchAfter with match beyond end of string
				}
			else
				{
				match += 1;
				}
			}
		matchCount++;
		}
	return matchCount;
}

/******************************************************************************

	The following functions return the substring range which contains the
	first match in the specified string.  Naturally, they may not be called
	when MatchOnly is set.

 *****************************************************************************/

#if !JRE_MAGIC
/******************************************************************************
 Match

 *****************************************************************************/

JBoolean
JRegex::Match
	(
	const JCharacter* string,
	JIndexRange*      match
	)
	const
{
	assert(match != NULL);
	assert( !IsMatchOnly() );

	regmatch_t pmatch;
	JBoolean success = MatchBase(string, &pmatch, 1);

	if (success)
		{
		*match = pmatch;
		}

	return success;
}
#endif

/******************************************************************************
 MatchFrom

 *****************************************************************************/

JBoolean
JRegex::MatchFrom
	(
	const JCharacter* string,
	const JIndex      index,
	JIndexRange*      match
	)
	const
{
	return MatchWithin(string, JIndexRange(index, strlen(string) ), match);
}

/******************************************************************************
 MatchAfter

	Both ranges may be the same object, very useful in while loops.

 *****************************************************************************/

JBoolean
JRegex::MatchAfter
	(
	const JCharacter*  string,
	const JIndexRange& range,
	JIndexRange*       match
	)
	const
{
	return MatchFrom(string, range.last+1, match);
}

/******************************************************************************
 MatchWithin

 *****************************************************************************/

JBoolean
JRegex::MatchWithin
	(
	const JCharacter*  string,
	const JIndexRange& range,
	JIndexRange*       match
	)
	const
{
	assert(match != NULL);
	assert( !IsMatchOnly() );

	regmatch_t pmatch;
	JBoolean success = MatchWithinBase(string, range, &pmatch, 1);

	if (success)
		{
		*match = pmatch;
		}

	return success;
}

/******************************************************************************

	The following functions find the substring range which contains the last
	match in the specified string and return the number of matches in the
	string.

 *****************************************************************************/

/******************************************************************************
 MatchLast

 *****************************************************************************/

JSize
JRegex::MatchLast
	(
	const JCharacter* string,
	JIndexRange*      match
	)
	const
{
	assert(match != NULL);

	JIndexRange thisMatch(1, 0);
	JSize matchCount = 0;

	while (MatchAfter(string, thisMatch, &thisMatch))
		{
		if ( thisMatch.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if (string[thisMatch.first-1] == '\0')
				{
				break; // Avoid calling MatchAfter with match beyond end of string
				}
			else
				{
				thisMatch += 1;
				}
			}
		matchCount++;
		}
	if (matchCount > 0)
		{
		*match = thisMatch;
		}

	return matchCount;
}

/******************************************************************************
 MatchLastWithin

 *****************************************************************************/

JSize
JRegex::MatchLastWithin
	(
	const JCharacter*  string,
	const JIndexRange& range,
	JIndexRange*       match
	)
	const
{
	assert(match != NULL);
	assert( !IsMatchOnly() );

	JIndexRange searchRegion = range;
	JSize matchCount = 0;

	while ( MatchWithin(string, searchRegion, match) )
		{
		if ( match->IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if ( match->first > range.first )
				{
				break; // Avoid calling MatchWithin with match beyond end of string
				}
			else
				{
				*match += 1;
				}
			}
		matchCount++;
		searchRegion.first = match->last + 1;
		}

	return matchCount;
}

/******************************************************************************

 	Iterator versions

 *****************************************************************************/

/******************************************************************************
 MatchAll

	As above, but stores the first arraySize matches in matchArray (the total
	number of matches is still returned).  Extra matches are discarded, and
	extra elements of the array are set to (0,-1).  matchArray may be NULL iff
	arraySize == 0.

 *****************************************************************************/

JSize
JRegex::MatchAll
	(
	const JCharacter* string,
	JIndexRange       matchArray[],
	const JSize       arraySize
	)
	const
{
	assert(matchArray != NULL || arraySize == 0);

	JIndexRange match(1, 0);
	JSize matchCount = 0;

	while (MatchAfter(string, match, &match))
		{
		if (matchCount<=arraySize)
			{
			matchArray[matchCount] = match;
			}
		if ( match.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if (string[match.first-1] == '\0')
				{
				break; // Avoid calling MatchAfter with match beyond end of string
				}
			else
				{
				match += 1;
				}
			}
		matchCount++;
		}
	for (JIndex i=matchCount;i<arraySize;i++)
		{
		matchArray[i].SetToNothing();
		}
	return matchCount;
}

/******************************************************************************
 MatchAll

	As above, but stores all the matches in matchList, which may never be NULL.

 *****************************************************************************/

JSize
JRegex::MatchAll
	(
	const JCharacter*    string,
	JArray<JIndexRange>* matchList
	)
	const
{
	assert(matchList != NULL);

	matchList->RemoveAll();

	JIndexRange match(1, 0);
	JSize matchCount = 0;

	while (MatchAfter(string, match, &match))
		{
		matchList->AppendElement(match);
		if ( match.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if (string[match.first-1] == '\0')
				{
				break; // Avoid calling MatchAfter with match beyond end of string
				}
			else
				{
				match += 1;
				}
			}
		matchCount++;
		}
	return matchCount;
}

/******************************************************************************
 MatchAllWithin

 *****************************************************************************/

JSize
JRegex::MatchAllWithin
	(
	const JCharacter*    string,
	const JIndexRange&   range,
	JArray<JIndexRange>* matchList
	)
	const
{
	assert(matchList != NULL);
	assert( !IsMatchOnly() );

	JIndexRange match, searchRegion = range;
	JSize matchCount = 0;

	matchList->RemoveAll();

	while ( MatchWithin(string, searchRegion, &match) )
		{
		matchList->AppendElement(match);
		searchRegion.first = match.last + 1;
		if ( match.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if ( match.first > range.first )
				{
				break; // Avoid calling MatchWithin with match beyond end of string
				}
			else
				{
				match += 1;
				}
			}
		matchCount++;
		}

	return matchCount;
}

/******************************************************************************

	The following functions return a list of the ranges which matched the overall
	expression and all subexpressions in the specified string.

 *****************************************************************************/

/******************************************************************************
 Match

	As the previous, except that subMatch is an array of size JIndexRanges.
	subMatch[0] is set to the overall match, and the other elements are set to
	the first size-1 subexpressions matched.  If size > GetSubCount()+1 then the
	extra elements are set to nothing, (0,-1).  On failure, the array is not
	modified.  SubMatch may be NULL iff size == 0, and if the dialect is kLiteral
	all subexpressions will be nothing.

	Performance note: Getting the subexpression matches is still more expensive.

 *****************************************************************************/

JBoolean
JRegex::Match
	(
	const JCharacter* string,
	JIndexRange       subMatchArray[],
	const JSize       size
	)
	const
{
	assert(subMatchArray != NULL || size == 0);
	assert( !IsMatchOnly() );

	JSize subCount = GetSubCount();
	regmatch_t* pmatch = new regmatch_t[subCount+1];
	assert(pmatch != NULL);
	JBoolean success = MatchBase(string, pmatch, subCount+1);

	if (success)
		{
		MakeRangeArray(subMatchArray, size, pmatch, subCount);
		}

	delete[] pmatch;

	return success;
}

/******************************************************************************
 Match

	As the previous, except that subMatchList is a JArray which will be set to
	a GetSubCount() length list of what each subexpression matched.  On failure,
	the list is not modified.  SubMatchList may never be NULL.

	Performance note: Getting the subexpression matches is still more expensive.

 *****************************************************************************/

JBoolean
JRegex::Match
	(
	const JCharacter*    string,
	JArray<JIndexRange>* subMatchList
	)
	const
{
	assert(subMatchList != NULL);
	assert( !IsMatchOnly() );

	JSize subCount = GetSubCount();
	regmatch_t* pmatch = new regmatch_t[subCount+1];
	assert(pmatch != NULL);
	JBoolean success = MatchBase(string, pmatch, subCount+1);

	if (success)
		{
		MakeRangeList(subMatchList, pmatch, subCount);
		}

	delete[] pmatch;

	return success;
}

/******************************************************************************
 MatchFrom

 *****************************************************************************/

JBoolean
JRegex::MatchFrom
	(
	const JCharacter*    string,
	const JIndex         index,
	JArray<JIndexRange>* subMatchList
	)
	const
{
	return MatchWithin(string, JIndexRange(index, strlen(string) ), subMatchList);
}

/******************************************************************************
 MatchAfter

 *****************************************************************************/

JBoolean
JRegex::MatchAfter
	(
	const JCharacter*    string,
	const JIndexRange&   range,
	JArray<JIndexRange>* subMatchList
	)
	const
{
	return MatchFrom(string, range.last+1, subMatchList);
}

/******************************************************************************
 MatchWithin

 *****************************************************************************/

JBoolean
JRegex::MatchWithin
	(
	const JCharacter*    string,
	const JIndexRange&   range,
	JArray<JIndexRange>* subMatchList
	)
	const
{
	assert(subMatchList != NULL);
	assert( !IsMatchOnly() );

	JSize subCount = GetSubCount();
	regmatch_t* pmatch = new regmatch_t[subCount+1];
	assert(pmatch != NULL);
	JBoolean success = MatchWithinBase(string, range, pmatch, subCount+1);

	if (success)
		{
		MakeRangeList(subMatchList, pmatch, subCount);
		}

	delete[] pmatch;

	return success;
}

/******************************************************************************
 MatchLastWithin

 *****************************************************************************/

JSize
JRegex::MatchLastWithin
	(
	const JCharacter*    string,
	const JIndexRange&   range,
	JArray<JIndexRange>* subMatchList
	)
	const
{
	assert(subMatchList != NULL);
	assert( !IsMatchOnly() );

	JIndexRange searchRegion = range;
	JSize matchCount = 0;
	JIndexRange match;

	while ( MatchWithin(string, searchRegion, &match) )
		{
		if ( match.IsEmpty() ) // Avoid infinite loop if get a null match!
			{
			if ( match.first > range.first )
				{
				break; // Avoid calling MatchWithin with match beyond end of string
				}
			else
				{
				match += 1;
				}
			}
		matchCount++;
		searchRegion.first = match.last + 1;
		}

	subMatchList->RemoveAll();
	if ( matchCount > 0 && !match.IsEmpty() )
		{
		const JBoolean found = MatchWithin(string, match, subMatchList);
		assert( found && match == subMatchList->GetFirstElement() );
		}
	else if ( matchCount > 0 )
		{
		subMatchList->AppendElement(match);
		}

	return matchCount;
}

/******************************************************************************
 MatchBackward

	MatchLast can be used to effectively search backwards, but by itself it is
	inefficient on large buffers because searches will start from the beginning.
	The MatchBackward functions attempt to provide a better algorithm for
	backwards searching on large buffers by a trial-and-error scheme.

	The first form is identical to MatchLast but (hopefully) faster.  The
	index is not included in the search range; in other words, the search
	is over the range (1, index-1).  Index may be any number from 1 to
	the length of the buffer plus 1 (but if it is 1 obviously all tests
	must fail). The caller must ensure that it is not too long.

	The second form is intended for repeated interactive searches.  The
	MatchBackward algorithm will often find several previous matches, and
	it is wasteful to throw them away and only report the last one.  The
	list is not guaranteed to have more than one element (zero if there is
	no match before the given point), but whatever it contains is
	guaranteed to be the previous matches in order *front to back*.  In
	other words, if it has three elements, the third element is the first
	one encountered going backwards from the given point, the second
	element is the second one encountered, and the first element is the
	third.  The return value is the number found.

	* The second form is untested because no one has really needed it yet.

 *****************************************************************************/

JBoolean
JRegex::MatchBackward
	(
	const JCharacter* string,
	const JIndex      index,
	JIndexRange*      match
	)
	const
{
	assert( !IsMatchOnly() );
	assert(match != NULL);
	assert(index > 0);

	// Need to find good values for these guys
	JSize decrement = 1000;
	const JSize multiplier = 10;

	JIndexRange searchRange;
	JInteger from = index;
	do
		{
		if (from == 1)
			{
			return kFalse; // We failed, and *match is unchanged
			}
		from = from - decrement;
		if (from < 1)
			{
			from = 1;
			}
		decrement *= multiplier;
		searchRange.Set(from, index-1);
		}
		while ( !MatchLastWithin(string, searchRange, match) );

	return kTrue; // We succeeded, and *match contains the match
}


JSize
JRegex::MatchBackward
	(
	const JCharacter*    string,
	const JIndex         index,
	JArray<JIndexRange>* matchList
	)
	const
{
	assert( !IsMatchOnly() );
	assert(matchList != NULL);
	assert(index > 0);

	// Need to find good values for these guys
	JSize decrement = 1000;
	const JSize multiplier = 10;

	JIndexRange searchRange;
	JSize numFound = 0;
	JInteger from = index;
	do
		{
		if (from == 1)
			{
			return 0; // We failed and *matchList is empty
			}
		from = from - decrement;
		if (from < 1)
			{
			from = 1;
			}
		decrement *= multiplier;
		searchRange.Set(from, index-1);
		numFound = MatchAllWithin(string, searchRange, matchList);
		}
		while (numFound == 0);

	return numFound; // We succeeded, and *matchList contains what we found
}

/******************************************************************************
 GetMatchInterpolator

 *****************************************************************************/

JInterpolate*
JRegex::GetMatchInterpolator()
	const
{
	if (itsInterpolator == NULL)
		{
		// This function is conceptually const

		JRegex* mutableThis = const_cast<JRegex*>(this);
		mutableThis->itsInterpolator = new JInterpolate();
		assert(itsInterpolator != NULL);
		}

	return itsInterpolator;
}

/******************************************************************************
 InterpolateMatches

	Given a list of substring ranges (matchList) and the string the ranges
	refer to (sourceString), InterpolateMatches builds and returns the
	actual replacement string the internal replace pattern, stored with a
	previous call to SetReplacePattern (default is "").  Presumably
	matchList is the list of subexpression matches from a search on
	sourceString, but this is not required.

	InterpolateMatches uses (a derived class of) JSubstitute to do the
	interpolation, and each JRegex has its own interpolation object which
	can be obtained with GetMatchInterpolator() to adjust how escape codes
	and variable patterns are recognized.  The default behavior for $
	patterns should rarely if ever need modification, but changing the
	escape codes can be very useful.  By default C escapes are not expanded
	since this is most convenient for patterns specified in source code; in
	user-specified patterns in interactive programs it may be better to add
	these escapes so that non-printing characters may be entered
	conveniently (the same is true for the search pattern escapes).

	The default $ pattern behavior is as follows.  A $ followed by a
	positive number N is replaced by the (N+1)st element of matchList
	(pedantically, the substring of sourceString referred to by the first
	element of matchList), counting from the beginning of the list.  A $
	followed by a negative number -N is replaced by the Nth element of
	matchList, *counting from the end of the list*.  If the number refers
	to an element which does not exist in matchList, the replacement string
	is "".  Replacement is done in one pass, so matches which contain '$N'
	are not subject to further replacement.  Maniacs who want a convenient
	way to, say, iterate until a fixed point is reached should contact the
	author.

	The above rules are easier to understand in the normal case where
	matchList was generated by a prevous match.  Then $0 is the entire
	match, while $1 is the first subexpression, $2 the second, and so forth
	up to $9, numbering subexpressions by counting left parentheses from
	left to right.  Similarly, $-1 is the last subexpression, $-2 is the
	second to the last, and so on.  If the pattern actually only contained
	four subexpressions, then $5 through $9 and $-6 through $-10 would be
	replaced by "", while both $0 and $-5 would be replaced by the overall
	match.  Similarly, both $1 and $-4 would be replaced by the first
	parenthesized subexpression, $2 and $-3) by the second, $3 and $-2 by
	the third, and finally $4 and $-1 by the fourth.

 *****************************************************************************/

JString
JRegex::InterpolateMatches
	(
	const JCharacter*          sourceString,
	const JArray<JIndexRange>& matchList
	)
	const
{
	assert(sourceString != NULL);

	JString replaceString = *itsReplacePattern;

	JInterpolate* interpolator = GetMatchInterpolator();
	interpolator->SetMatchResults(sourceString, &matchList);
	interpolator->Substitute(&replaceString);
	interpolator->SetMatchResults(NULL, NULL);

	if (itsMatchCaseFlag && !matchList.IsEmpty())
		{
		replaceString.MatchCase(sourceString, matchList.GetElement(1));
		}

	return replaceString;
}

/******************************************************************************
 Replace

	Replace() interpolates the regex's replacement pattern into string,
	using the results of a previous search on that same string.  This
	functionality could be duplicated by the client, but it would be much
	less convenient.  The JRegex property LiteralReplace controls whether
	match interpolation takes place.

	The three argument form which takes only ranges always substitutes the
	replacement pattern without first using InterpolateMatches, regardless
	of the value of ReplaceLiteral, and so only requires a simple range
	rather than a match list.  However, it is a deprecated function which
	will eventually go away.

 *****************************************************************************/

void
JRegex::Replace
	(
	JString*                   string,
	const JArray<JIndexRange>& matchList,
	JIndexRange*               newRange
	)
	const
{
	if (itsLiteralReplaceFlag)
		{
		Replace(string,
		        matchList.GetElement(1),
		        newRange);
		}
	else
		{
		assert(string != NULL);
		assert(newRange != NULL);

		string->ReplaceSubstring(matchList.GetElement(1),
		                         InterpolateMatches(*string, matchList),
		                         newRange);
		}
}


void
JRegex::Replace
	(
	JString*           string,
	const JIndexRange& oldRange,
	JIndexRange*       newRange
	)
	const
{
	assert(string != NULL);
	assert(newRange != NULL);

	string->ReplaceSubstring(oldRange,
	                         *itsReplacePattern,
	                         newRange);
}

/******************************************************************************
 SetDialect

	Controls which POSIX dialect is used: literal matches (the pattern is taken
	as a literal string with no metacharacters), basic expressions, or extended
	expressions (the default).

	Changing dialects triggers an immediate recompilation where there is any
	chance of failure, and the return code is the result of the compilation.
	The dialect stays set to the method argument; an error return simply
	indicates that the current pattern is not a legal regular expression in that
	dialect.

 *****************************************************************************/

JError
JRegex::SetDialect
	(
	const Dialect dialect
	)
{
	int oldCFlags = itsCFlags;

	switch (dialect)
	{
	case kLiteral: // Should always compile, so don't need to do it now
		SetCompileOption(REG_EXTENDED, kFalse);
		SetCompileOption(REG_NOSPEC, kTrue);
		break;
	case kBasic:
		SetCompileOption(REG_NOSPEC, kFalse);
		SetCompileOption(REG_EXTENDED, kFalse);
		break;
	case kExtended:
		SetCompileOption(REG_EXTENDED, kTrue);
		SetCompileOption(REG_NOSPEC, kFalse);
		break;
	default:
		assert(0); // Should never be reached!
		break;
	}

	JError error = JNoError();
	if (oldCFlags != itsCFlags && itsState != kEmpty)
		{
		error = RegComp();
		}

	return error;
}

/******************************************************************************
 GetDialect

 *****************************************************************************/

JRegex::Dialect
JRegex::GetDialect() const
{
	if ( RawGetOption(itsCFlags, REG_EXTENDED) )
		{
		if ( RawGetOption(itsCFlags, REG_NOSPEC) )
			{
			assert(0); // Should not be possible
			}
		return kExtended;
		}
	else
		{
		if ( RawGetOption(itsCFlags, REG_NOSPEC) )
			{
			return kLiteral;
			}
		else
			{
			return kBasic;
			}
		}
}

/******************************************************************************
 SetReplacePattern

	Sets the replacement pattern.  The return value is true if the
	replacement pattern is 'clean', that is if all $ signs are escaped or
	followed by a number (the exact definition is that used by the
	underlying JSubstitute match object), but this is only a convenience
	for interactive programs checking their user's input; the pattern is
	set whether it is clean or not.  IsCleanPattern() can be used to perform
	the same test without changing the pattern.

	The syntax of the replacement source is under the underlying
	JInterpolate object's control, but a summary of the default behavior is
	as follows.  The replacement metacharacter is '$', which marks the
	beginning of a replacement token.  'Unclean' replacement patterns are
	patterns which contain a metacharacter not immediately followed either
	by a second metacharacter or by an optional sign ('-' or '+') preceding
	one or more decimal digits.  All other patterns are 'clean'.  Clean
	patterns will be replaced by their corresponding match value, while
	unclean patterns are left intact except their '$' is removed; to insert
	a literal '$' preface it with a backslash.

	In other words, the only clean replacement tokens are those of the form
	'$[+-]?[0-9]+', and a replacement pattern is clean unless it contains
	at least one unclean replacement token.

	See InterpolateMatches for how the replacement pattern will be used.

	The default replace pattern is "", that is all matches are replaced by
	the empty string.  This simplifies the replace interface because there is
	always a valid replace string, but arguably makes it easier to screw up by
	forgetting to set the replace string.  If enough people complain that the
	benefits are not worth the drawbacks, this situation can change.

	As usual, the forms that take a JString or a JCharacter* and a length are
	NULL-safe.

	If an error is found, and errRange is not NULL, it is set to the
	offending range of characters.

 *****************************************************************************/

JError
JRegex::SetReplacePattern
	(
	const JString& pattern,
	JIndexRange*   errRange
	)
{
	*itsReplacePattern = pattern;

	JIndexRange r;
	if (errRange == NULL)
		{
		errRange = &r;
		}
	return (GetMatchInterpolator())->ContainsError(*itsReplacePattern, errRange);
}

/******************************************************************************
 RestoreDefaults

	Restores the default values of both the compile-time and run-time
	options and the replacement pattern.

	Performance note: changing this option can cause an immediate recompile if
	there is any chance of failure from changing dialects.  The return value
	is the result of the compilation.

 *****************************************************************************/

JError
JRegex::RestoreDefaults()
{
	itsEFlags = defaultEFlags;

	if (itsCFlags != defaultCFlags)
		{
		itsCFlags = defaultCFlags;

		if (itsState == kReady)
			{
			itsState = kRecompile;
			}
		}

	itsReplacePattern->Clear();

	return SetDialect(defaultDialect);
}

/******************************************************************************
 MatchBase (private)

	Ensures that the proper string description mode is set before the match.
	RegExec() should be called nowhere else except MatchWithinBase.

 *****************************************************************************/

JBoolean
JRegex::MatchBase
	(
	const JCharacter* string,
	regmatch_t pmatch[],
	const JSize nmatch
	)
	const
{
	JRegex* mutableThis = const_cast<JRegex*>(this);
	mutableThis->SetExecuteOption(REG_STARTEND, kFalse);

	return RegExec(string, pmatch, nmatch);
}

/******************************************************************************
 MatchWithinBase (private)

	Ensures that the proper string description mode is set before the match.
	RegExec() should be called nowhere else except MatchBase.

 *****************************************************************************/

JBoolean
JRegex::MatchWithinBase
	(
	const JCharacter*  string,
	const JIndexRange& range,
	regmatch_t         pmatch[],
	const JSize        nmatch
	)
	const
{
	JRegex* mutableThis = const_cast<JRegex*>(this);
	mutableThis->SetExecuteOption(REG_STARTEND, kTrue);

	pmatch[0] = range;

	return RegExec(string, pmatch, nmatch);
}

/******************************************************************************
 CopyPatternRegex (private)

	Takes care of transfering the pattern, regex, replace pattern, and
	itsCompiledFlag states (but not the options or ranges) from one JRegex to
	another.

 *****************************************************************************/

void
JRegex::CopyPatternRegex
	(
	const JRegex& source
	)
{
	if (source.itsState == kEmpty)
		{
		RegFree();
		}
	else if (source.itsState == kCannotCompile)
		{
		RegFree();
		CopyPattern(source);
		itsState = kCannotCompile;
		}
	else
		{
		// Should never fail if source has already compiled!
		SetPatternOrDie(source.itsPattern, source.itsPattern.GetLength() );
		}

	SetReplacePattern(*source.itsReplacePattern);
//	JBoolean set = SetReplacePattern(*source.itsReplacePattern);
//	assert( set );
}

/******************************************************************************
 CopyPattern (private)

	Copies 'pattern' into the pattern buffer.

	WARNING: It is possible for humans to become trapped in the pattern
	buffer at the whim of the Paramount scriptwriters; when this happens,
	rescue is temporarily impossible, and so only brief, half-hearted
	attempts should be made.  Rescue becomes possible only after further
	plot complications, generally at the last possible instant.

 *****************************************************************************/

void
JRegex::CopyPattern
	(
	const JCharacter* pattern,
	const JSize       length
	)
{
	itsPattern.Set(pattern, length);

	itsNULLCount = 0;
	for (JIndex i=0; i<length; i++)
		{
		if (pattern[i] == '\0')
			{
			itsNULLCount++;
			}
		}
}

void
JRegex::CopyPattern
	(
	const JRegex& source
	)
{
	itsPattern = source.itsPattern;

	itsNULLCount = source.itsNULLCount;
}

/******************************************************************************
 SetCompileOption (private)

 *****************************************************************************/

void
JRegex::SetCompileOption
	(
	const int      option,
	const JBoolean setClear
	)
{
	int oldCFlags = itsCFlags;

	RawSetOption(&itsCFlags, option, setClear);

	if (itsState == kReady && oldCFlags != itsCFlags)
		{
		itsState = kRecompile;

		if ( (oldCFlags&REG_NOSUB) && !(itsCFlags&REG_NOSUB) )
			{
			// Set ridiculous value as flag for GetSubCount() to recompile;
			// for compatibility with future regex versions we never trust
			// an nsub calculated by compiling with REG_NOSUB
			itsRegex.re_nsub = static_cast<size_t>(-1);
			}
		}
}

/******************************************************************************
 SetExecuteOption (private)

 *****************************************************************************/

void
JRegex::SetExecuteOption
	(
	const int      option,
	const JBoolean setClear
	)
{
	RawSetOption(&itsEFlags, option, setClear);
}

/******************************************************************************
 RawSetOption (private)

 *****************************************************************************/

void
JRegex::RawSetOption
	(
	int*           flags,
	const int      option,
	const JBoolean setClear
	)
{
	if (setClear)
		{
		*flags |= option;
		}
	else
		{
		*flags &= ~option;
		}
}

/******************************************************************************
 CompileOrDie (private)

 *****************************************************************************/

void
JRegex::CompileOrDie()
{
	JError error = RegComp();
	assert_ok( error );
}

/******************************************************************************
 RegComp (private)

 *****************************************************************************/

JError
JRegex::RegComp()
{
	assert( RawGetOption(itsCFlags, REG_PEND) ); // Paranoia

	RegFree();

	if (itsNoJExtendedFlag || GetDialect() == kLiteral)
		{
		itsEscapeEngine->ClearRegexExtensions();
		}
	else
		{
		itsEscapeEngine->SetRegexExtensions();
		}

	JString pattern = itsPattern;

	itsEscapeEngine->Substitute(&pattern);

	itsRegex.re_endp = pattern.GetCString() + pattern.GetLength();
	int retVal = regcomp(&itsRegex, pattern, itsCFlags);

#if 0
	int retVal;
	if (!itsNoJExtendedFlag && GetDialect() != kLiteral)
		{
		JString pattern = itsPattern;

		// It's probably worth doing this on every compile to save the
		// space and complexity of a second cached string, particularly
		// since we've gone to so much trouble to minimize recompilation.

		itsEscapeEngine->Substitute(&pattern);

		itsRegex.re_endp = pattern.GetCString() + pattern.GetLength();
		retVal = regcomp(&itsRegex, pattern, itsCFlags);
		}
	else
		{
		itsRegex.re_endp = itsPattern.GetCString() + itsPattern.GetLength();
		retVal = regcomp(&itsRegex, itsPattern, itsCFlags);
		}
#endif

	if (retVal == 0)
		{
		#ifdef JRE_ALLOC_CHECK
		++numRegexAlloc;
		assert(numRegexAlloc == 1);
		#endif

		// I assume that nothing need be freed unless the compile succeeds
		itsState = kReady;

		return JNoError();
		}
	else
		{
		#ifdef JRE_PRINT_COMPILE_ERRORS
		char errbuf[100];
		regerror(retVal, &itsRegex, errbuf, 100);
		cout << "Compile error: " << errbuf << endl;
		#endif

		#ifdef JRE_ALLOC_CHECK
		assert(numRegexAlloc == 0);
		#endif

		return RegError(retVal);
		}
}

/******************************************************************************
 RegExec (private)

 *****************************************************************************/

JBoolean
JRegex::RegExec
	(
	const JCharacter* string,
	regmatch_t        pmatch[],
	const JSize       nmatch
	)
	const
{
	assert(string != NULL);
	assert(itsState != kEmpty && itsState != kCannotCompile);

	#ifdef JRE_ALLOC_CHECK
	assert(numRegexAlloc == 1);
	#endif

	if (itsState == kRecompile)
		{
		JRegex* mutate = const_cast<JRegex*>(this);
		mutate->CompileOrDie();
		}

	// Note: if the match fails, the value of pmatch is left unchanged
	int returnCode = regexec(&itsRegex, string, nmatch, pmatch, itsEFlags);

	if (returnCode == REG_NOMATCH)
		{
		return kFalse;
		}
	else if (returnCode == 0)
		{
		return kTrue;
		}
	else
		{
		assert(0);
		return kFalse;
		}
}

/******************************************************************************
 RegFree (private)

 *****************************************************************************/

void
JRegex::RegFree()
{
	if (itsState != kEmpty && itsState != kCannotCompile)
		{
		::regfree(&itsRegex);
		itsState = kCannotCompile;
		#ifdef JRE_ALLOC_CHECK
		numRegexAlloc--;
		#endif
		}

	#ifdef JRE_ALLOC_CHECK
	assert(numRegexAlloc == 0);
	#endif
}

/******************************************************************************
 RegError (private)

	Translates a regex error return code to a JRegexError object.  The type is
	kError and the value will be the full message returned.

	The type should be the short name returned by regerror when the code is
	ANDed with REG_ITOA, but JError would probably have to copy the type value
	as well.

 *****************************************************************************/

JError
JRegex::RegError
	(
	int errorCode
	)
{
	JSize msgLength = regerror(errorCode, &itsRegex, NULL, 0);
	JCharacter* msg = new JCharacter[msgLength];
	(void) regerror(errorCode, &itsRegex, msg, msgLength);

	JRegexError error(kError, msg);

	delete[] msg;

	return error;
}

/******************************************************************************
 MakeRangeArray (file scope)

 *****************************************************************************/

static void
MakeRangeArray
	(
	JIndexRange subMatchArray[],
	JSize       size,
	regmatch_t  pmatch[],
	JSize       subCount
	)
{
	JIndex i=0;
	while (i<size && i<=subCount)
		{
		subMatchArray[i] = pmatch[i];
		i++;
		}

	while (i<size)
		{
		subMatchArray[i].SetToNothing();
		i++;
		}
}

/******************************************************************************
 MakeRangeList (file scope)

 *****************************************************************************/

static void
MakeRangeList
	(
	JArray<JIndexRange>* subMatchList,
	regmatch_t           pmatch[],
	JSize                subCount
	)
{
	subMatchList->RemoveAll();
	for (JIndex i=0;i<=subCount;i++)
		{
		subMatchList->AppendElement( JIndexRange(pmatch[i]) );
		}
}

#if JRE_MAGIC
/******************************************************************************
 JRegexMagic.cc

 	JRegexMagic is a helper class for JRegex, and 

	BASE CLASS = <NONE>

 *****************************************************************************/

/******************************************************************************
 Constructor (private)

	All JRegexMagic constructors are private because only JRegex may
	instantiate it.

 *****************************************************************************/

JRegex::JRegexMagic::JRegexMagic
	(
	const JRegex*     regex,
	const JCharacter* string
	)
	:
	itsRegex(regex),
	itsCString(string)
{
}

/******************************************************************************
 Destructor

 *****************************************************************************/

JRegex::JRegexMagic::~JRegexMagic()
{
}

/******************************************************************************
 Conversions

 	General rules

 *****************************************************************************/

/******************************************************************************
 operator JBoolean()

 *****************************************************************************/

JRegex::JRegexMagic::operator bool() const
{
	return itsRegex->MatchBase(itsCString, NULL, 0);
}

/******************************************************************************
 operator JIndexRange()

 *****************************************************************************/

JRegex::JRegexMagic::operator JIndexRange() const
{
	assert( !itsRegex->IsMatchOnly() );

	regmatch_t pmatch;

	JBoolean success = itsRegex->MatchBase(itsCString, &pmatch, 1);

	if (success)
		{
		return pmatch;
		}
	else
		{
		return JIndexRange(); // pmatch has a random value
		}
}
#endif
