libraries/spcre/test/src/spcreconsole.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// spcreconsole.cpp
//
// Copyright (c) 2005 - 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sanjay Ghemawat
//
// Heavily refactored for Symbian OS by Accenture.


#include <e32base.h>
#include <e32std.h>
#include <e32math.h>
#include <e32cons.h>			// Console
#include <bacline.h>
#include <cregex.h>
#include <tregexarg.h>
#include <tregexoptions.h>

//  Constants
_LIT(KTextConsoleTitle, "Console");
_LIT(KTextFailed, " failed, leave code = %d\n");
_LIT(KTextPressAnyKey, "[press any key]\n");
//  Global Variables
LOCAL_D CConsoleBase* console; // write all messages to this
TBool verboseMode = EFalse;

//  Local Functions

// CHECK dies with a fatal error if condition is not true.  It is *not*
// controlled by NDEBUG, so the check will be executed regardless of
// compilation mode.  Therefore, it is safe to do things like:
//    CHECK_EQ(fp->Write(x), 4)
#define CHECK(condition)								\
	{													\
	if (!(condition))									\
		{                                   			\
		_LIT(KCondition, #condition);					\
		console->Printf(_L("%d: Check failed: %S\n"),	\
						__LINE__, &KCondition());		\
		User::Leave(KErrGeneral);						\
		}												\
	}

#define CHECK_EQ(a, b)   CHECK(a == b)

static void Timing1L(TInt aNumIters)
	{
	console->Printf(_L("Test Timing 1, %d iterations.\n"), aNumIters);
	
	// Same pattern lots of times
	_LIT8(KPattern, "ruby:\\d+");
	_LIT8(KString,"ruby:1234");
	CRegEx* pattern = CRegEx::NewLC(KPattern());

	for (TInt j = aNumIters; j > 0; j--)
		{
		CHECK(pattern->FullMatchL(KString()));
		}
	CleanupStack::PopAndDestroy(pattern);
	}

static void Timing2L(TInt aNumIters)
	{
	console->Printf(_L("Test Timing 2, %d iterations.\n"), aNumIters);
	// Same pattern lots of times
	_LIT8(KPattern, "ruby:(\\d+)");
	_LIT8(KString,"ruby:1234");
	CRegEx* pattern = CRegEx::NewLC(KPattern());

	TInt i;
	for (TInt j = aNumIters; j > 0; j--)
		{
		CHECK(pattern->FullMatchL(KString(), &i));
		CHECK_EQ(i, 1234);
		}
	CleanupStack::PopAndDestroy(pattern);
	}

static void Timing3L(TInt aNumIters)
	{
	console->Printf(_L("Test Timing 3, %d iterations.\n"), aNumIters);
	_LIT8(KLine, "this is another line\n");
	HBufC8* text = HBufC8::NewLC(KLine().Length() * aNumIters);
	TPtr8 pText = text->Des();

	for (int j = aNumIters; j > 0; j--)
		{
		pText.Append(KLine());
		}

	CRegEx* lineMatcher = CRegEx::NewLC(_L8(".*\n"));

	TInt counter = 0;
	while (lineMatcher->ConsumeL(pText))
		{
		counter++;
		}
	CleanupStack::PopAndDestroy(2, text);
	CHECK_EQ(counter, aNumIters);
	console->Printf(_L("Matched %d lines\n"), counter);
	}


static void RadixTestsL()
	{
	console->Write(_L("Testing hex\n"));

	#define CHECK_HEX(type, value) 										\
		{																\
		type v;															\
		CRegEx* re = CRegEx::NewLC(_L8("([0-9a-fA-F]+)[uUlL]*"));		\
		CHECK(re->FullMatchL(_L8(#value), Hex(&v)));					\
		CHECK_EQ(v, 0x ## value);										\
		CleanupStack::PopAndDestroy(re);								\
		re = NULL;														\
		}

	CHECK_HEX(TInt64,     2baddeadbeefLL);
	CHECK_HEX(TUint8,     abU);
	CHECK_HEX(TUint16,    2badU);
	CHECK_HEX(TUint32,    deadbeefUL);
	CHECK_HEX(TUint,      cafebabeU);
	#undef CHECK_HEX

	console->Write(_L("Testing octal\n"));

	#define CHECK_OCTAL(type, value) 									\
		{																\
		type v;															\
		CRegEx* re = CRegEx::NewLC(_L8("([0-7]+)[uUlL]*"));				\
		CHECK(re->FullMatchL(_L8(#value), Octal(&v)));					\
		CHECK_EQ(v, 0 ## value);										\
		CleanupStack::PopAndDestroy(re);								\
		re = NULL;														\
		}

	CHECK_OCTAL(TInt64,		777777777777LL);
	CHECK_OCTAL(TUint8,		177U);
	CHECK_OCTAL(TUint16,	177777U);
	CHECK_OCTAL(TUint32,	3777777777UL);
	CHECK_OCTAL(TUint,		3777777777U);
	#undef CHECK_OCTAL

	console->Write(_L("Testing decimal\n"));
	
	#define CHECK_DECIMAL(type, value) 									\
		{																\
		type v;															\
		CRegEx* re = CRegEx::NewLC(_L8("(-?[0-9]+)[uUlL]*"));			\
		CHECK(re->FullMatchL(_L8(#value), &v));							\
		CHECK_EQ(v, value);												\
		CleanupStack::PopAndDestroy(re);								\
		re = NULL;														\
		}	
	
	CHECK_DECIMAL(TInt8,	-1);
	CHECK_DECIMAL(TUint8,	1U);
	CHECK_DECIMAL(TInt16,	-9999);
	CHECK_DECIMAL(TUint16,	9999U);
	CHECK_DECIMAL(TInt32,	-123456L);
	CHECK_DECIMAL(TUint32,	123456U);
	CHECK_DECIMAL(TInt64,	1234567890123456789LL);
	CHECK_DECIMAL(TInt,		-1234567890);
	CHECK_DECIMAL(TUint,	1234567890U);
	#undef CHECK_DECIMAL
}

static void TestReplaceL()
	{
	console->Write(_L("Testing ReplaceL\n"));

	struct ReplaceTest
		{
		TBuf8<32>	iRegExp;
		TBuf8<32>	iRewrite;
		TBuf8<64>	iOriginal;
		TBuf8<64>	iSingle;
		TBuf8<64>	iGlobal;
		TInt		iGlobalCount; // the expected return value from ReplaceAll
		};
	
	static const ReplaceTest tests[] =
	{
		// Test 1
		{
		_L8("(qu|[b-df-hj-np-tv-z]*)([a-z]+)"),
		_L8("\\2\\1ay"),
		_L8("the quick brown fox jumps over the lazy dogs."),
		_L8("ethay quick brown fox jumps over the lazy dogs."),
		_L8("ethay ickquay ownbray oxfay umpsjay overay ethay azylay ogsday."),
		9
		},
		// Test 2
		{
		_L8("\\w+"),
		_L8("\\0-NOSPAM"),
		_L8("paul.haahr@google.com"),
		_L8("paul-NOSPAM.haahr@google.com"),
		_L8("paul-NOSPAM.haahr-NOSPAM@google-NOSPAM.com-NOSPAM"),
		4
		},
		// Test 3
		{_L8("^"),
		_L8("(START)"),
		_L8("foo"),
		_L8("(START)foo"),
		_L8("(START)foo"),
		1
		},
		// Test 4
		{
		_L8("^"),
		_L8("(START)"),
		_L8(""),
		_L8("(START)"),
		_L8("(START)"),
		1
		},
		// Test 5
		{
		_L8("$"),
		_L8("(END)"),
		_L8(""),
		_L8("(END)"),
		_L8("(END)"),
		1
		},
		// Test 6
		{
		_L8("b"),
		_L8("bb"),
		_L8("ababababab"),
		_L8("abbabababab"),
		_L8("abbabbabbabbabb"),
		5
		},
		// Test 7
		{
		_L8("b"),
		_L8("bb"),
		_L8("bbbbbb"),
		_L8("bbbbbbb"),
		_L8("bbbbbbbbbbbb"),
		6
		},
		// Test 8
		{_L8("b+"),
		_L8("bb"),
		_L8("bbbbbb"),
		_L8("bb"),
		_L8("bb"),
		1
		},
		// Test 9
		{
		_L8("b*"),
		_L8("bb"),
		_L8("bbbbbb"),
		_L8("bb"),
		_L8("bb"),
		1
		},
		// Test 10
		{
		_L8("b*"),
		_L8("bb"),
		_L8("aaaaa"),
		_L8("bbaaaaa"),
		_L8("bbabbabbabbabbabb"),
		6
		},
		// Test 11
		{
		_L8("b*"),
		_L8("bb"),
		_L8("aa\naa\n"),
		_L8("bbaa\naa\n"),
		_L8("bbabbabb\nbbabbabb\nbb"),
		7
		},
		// Test 12
		{
		_L8("b*"),
		_L8("bb"),
		_L8("aa\raa\r"),
		_L8("bbaa\raa\r"),
		_L8("bbabbabb\rbbabbabb\rbb"),
		7
		},
		// Test 13
		{
		_L8("b*"),
		_L8("bb"),
		_L8("aa\r\naa\r\n"),
		_L8("bbaa\r\naa\r\n"),
		_L8("bbabbabb\r\nbbabbabb\r\nbb"),
		7
		},
#ifdef SUPPORT_UTF8
		// Test 14
		{	
		_L8("b*"),
		_L8("bb"),
		_L8("\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8"),   // utf8
		_L8("bb\xE3\x83\x9B\xE3\x83\xBC\xE3\x83\xA0\xE3\x81\xB8"),
		_L8("bb\xE3\x83\x9B""bb""\xE3\x83\xBC""bb""\xE3\x83\xA0""bb""\xE3\x81\xB8""bb"),
		5
		},
		// Test 15
		{
		_L8("b*"),
		_L8("bb"),
		_L8("\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n"),   // utf8
		_L8("bb\xE3\x83\x9B\r\n\xE3\x83\xBC\r\xE3\x83\xA0\n\xE3\x81\xB8\r\n"),
		_L8("bb\xE3\x83\x9B""bb\r\nbb""\xE3\x83\xBC""bb\rbb""\xE3\x83\xA0""bb\nbb""\xE3\x81\xB8""bb\r\nbb"),
		9
		},
#endif
		{
		KNullDesC8(),
		KNullDesC8(),
		KNullDesC8(),
		KNullDesC8(),
		KNullDesC8(),
		-1
		}
	};

#ifdef SUPPORT_UTF8
	const TBool supportUtf8 = ETrue;
#else
	const TBool supportUtf8 = EFalse;
#endif
  
	CRegEx* re = NULL;
	TRegExOptions options = TRegExOptions(EPcreNewlineCrLf);
	options.SetUtf8(supportUtf8);	
	TInt i =0;
	for (const ReplaceTest* t = tests; t->iGlobalCount > -1; ++t)
		{		
		console->Printf(_L("Replace Test %d\n"), ++i);
		re = CRegEx::NewLC(t->iRegExp, options);
		CHECK_EQ(re->Error(), KErrNone);
		TBuf8<64> one(t->iOriginal);
		CHECK(re->ReplaceL(t->iRewrite, one));
		CHECK_EQ(one, t->iSingle);
		TBuf8<64> all(t->iOriginal);
		const TInt replaceCount = re->GlobalReplaceL(t->iRewrite, all);
		CHECK_EQ(all, t->iGlobal);
		CHECK_EQ(replaceCount, t->iGlobalCount);		
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}

	// One final test: test \r\n replacement when we're not in CRLF mode
	{
	TRegExOptions options2 = TRegExOptions(EPcreNewlineCr);
	options2.SetUtf8(supportUtf8);
	re = CRegEx::NewLC(_L8("b*"), options2);
	CHECK_EQ(re->Error(), KErrNone);
	TBuf8<32> all(_L8("aa\r\naa\r\n"));
	CHECK_EQ(re->GlobalReplaceL(_L8("bb"), all), 9);
	CHECK_EQ(all, _L8("bbabbabb\rbb\nbbabbabb\rbb\nbb"));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	}
	{
	TRegExOptions options3 = TRegExOptions(EPcreNewlineLf);
	options3.SetUtf8(supportUtf8);
	re = CRegEx::NewLC(_L8("b*"), options3);
	CHECK_EQ(re->Error(), KErrNone);
	TBuf8<32> all(_L8("aa\r\naa\r\n"));
	CHECK_EQ(re->GlobalReplaceL(_L8("bb"), all), 9);
	CHECK_EQ(all, _L8("bbabbabb\rbb\nbbabbabb\rbb\nbb"));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	}

	// TODO: test what happens when no PCRE_NEWLINE_* flag is set.
	//       Alas, the answer depends on how pcre was compiled.
}

static void TestExtractL()
	{
	console->Write(_L("Testing ExtractL\n"));

	TBuf8<32> s;	
	CRegEx* re = NULL;
	
	re = CRegEx::NewLC(_L8("(.*)@([^.]*)"));
	CHECK(re->ExtractL(_L8("\\2!\\1"), _L8("boris@kremvax.ru"), s));
	CHECK_EQ(s, _L8("kremvax!boris"));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	// check the RE interface as well
	re = CRegEx::NewLC(_L8(".*"));
	CHECK(re->ExtractL(_L8("'\\0'"), _L8("foo"), s));
	CHECK_EQ(s, _L8("'foo'"));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("bar"));
	CHECK(!re->ExtractL(_L8("'\\0'"), _L8("baz"), s));
	CHECK_EQ(s, _L8("'foo'"));
	CleanupStack::PopAndDestroy(re);
	}

static void TestConsumeL()
	{
	console->Write(_L("Testing ConsumeL\n"));

	TBuf8<3> word;
	TBuf8<24> input(_L8("   aaa b!@#$@#$cccc"));

	// matches a word, possibly proceeded by whitespace
	CRegEx* re = CRegEx::NewLC(_L8("\\s*(\\w+)"));
	CHECK(re->ConsumeL(input, &word));
	CHECK_EQ(word, _L8("aaa"));
	CHECK(re->ConsumeL(input, &word));
	CHECK_EQ(word, _L8("b"));
	CHECK(!re->ConsumeL(input, &word));
	CleanupStack::PopAndDestroy(re);
	}

static void TestFindAndConsumeL()
	{
	console->Write(_L("Testing FindAndConsumeL\n"));

	TBuf8<4> word;
	TBuf8<24> input(_L8("   aaa b!@#$@#$cccc"));

	CRegEx* re = CRegEx::NewLC(_L8("(\\w+)")); // matches a word
	CHECK(re->FindAndConsumeL(input, &word));
	CHECK_EQ(word, _L8("aaa"));
	CHECK(re->FindAndConsumeL(input, &word));
	CHECK_EQ(word, _L8("b"));
	CHECK(re->FindAndConsumeL(input, &word));
	CHECK_EQ(word, _L8("cccc"));
	CHECK(!re->FindAndConsumeL(input, &word));
	CleanupStack::PopAndDestroy(re);
	}

static void TestMatchNumberPeculiarityL()
	{
	console->Write(_L("Testing match-number peculiarity\n"));

	TBuf8<3> word1;
	TBuf8<3> word2;
	TBuf8<3> word3;

	CRegEx* re = CRegEx::NewLC(_L8("(foo)|(bar)|(baz)"));
	CHECK(re->PartialMatchL(_L8("foo"), &word1, &word2, &word3));
	CHECK_EQ(word1, _L8("foo"));
	CHECK_EQ(word2, KNullDesC8());
	CHECK_EQ(word3, KNullDesC8());
	CHECK(re->PartialMatchL(_L8("bar"), &word1, &word2, &word3));
	CHECK_EQ(word1, KNullDesC8());
	CHECK_EQ(word2, _L8("bar"));
	CHECK_EQ(word3, KNullDesC8());
	CHECK(re->PartialMatchL(_L8("baz"), &word1, &word2, &word3));
	CHECK_EQ(word1, KNullDesC8());
	CHECK_EQ(word2, KNullDesC8());
	CHECK_EQ(word3, _L8("baz"));
	CHECK(!re->PartialMatchL(_L8("f"), &word1, &word2, &word3));

	CleanupStack::PopAndDestroy(re);
	re = NULL;

	TBuf8<12> a;
	re = CRegEx::NewLC(_L8("(foo)|hello"));
	CHECK(re->FullMatchL(_L8("hello"), &a));
	CHECK_EQ(a, KNullDesC8());
	CleanupStack::PopAndDestroy(re);
	}

static void TestRecursionL()
	{
	console->Write(_L("Testing recursion\n"));
	
	// Get one string that passes (sometimes), one that never does.
	TBuf8<12> good(_L8("abcdefghijk"));
	TBuf8<12> bad(_L8("acdefghijkl"));

	// According to pcretest, matching text_good against (\w+)*b
	// requires match_limit of at least 8192, and match_recursion_limit
	// of at least 37.

	TRegExOptions optionsMatchLimit;
	optionsMatchLimit.SetMatchLimit(8192);
	
	CRegEx* re = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMatchLimit);
	CHECK(re->PartialMatchL(good));
	CHECK(re->PartialMatchL(bad) == EFalse);
	CHECK(re->FullMatchL(good) == EFalse);
	CHECK(re->FullMatchL(bad) == EFalse);	
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	optionsMatchLimit.SetMatchLimit(1024);
	CRegEx* re2 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMatchLimit);
	CHECK(re2->PartialMatchL(good) == EFalse);   // because of match_limit
	CHECK(re2->PartialMatchL(bad) == EFalse);
	CHECK(re2->FullMatchL(good) == EFalse);
	CHECK(re2->FullMatchL(bad) == EFalse);
	CleanupStack::PopAndDestroy(re2);
	re2 = NULL;
	
	TRegExOptions optionsMathLimitRecursion;
	optionsMathLimitRecursion.SetMatchLimitRecursion(50);
	CRegEx* re3 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMathLimitRecursion);
	CHECK(re3->PartialMatchL(good));
	CHECK(re3->PartialMatchL(bad) == EFalse);
	CHECK(re3->FullMatchL(good) == EFalse);
	CHECK(re3->FullMatchL(bad) == EFalse);
	CleanupStack::PopAndDestroy(re3);
	re3 = NULL;
	
	optionsMathLimitRecursion.SetMatchLimitRecursion(10);
	CRegEx* re4 = CRegEx::NewLC(_L8("(\\w+)*b"), optionsMathLimitRecursion);
	CHECK(re4->PartialMatchL(good) == EFalse);
	CHECK(re4->PartialMatchL(bad) == EFalse);
	CHECK(re4->FullMatchL(good) == EFalse);
	CHECK(re4->FullMatchL(bad) == EFalse);
	CleanupStack::PopAndDestroy(re4);
	re4 = NULL;	
	}

// A meta-quoted string, interpreted as a pattern, should always match
// the original unquoted string.
static void TestQuoteMetaL(const TDesC8& aUnquoted, TRegExOptions aOptions =
		TRegExOptions())
	{
	HBufC8* quoted = CRegEx::QuoteMetaL(aUnquoted);
	CleanupStack::PushL(quoted);

	CRegEx* re = CRegEx::NewLC(*quoted, aOptions);
	CHECK(re->FullMatchL(aUnquoted));
	CleanupStack::PopAndDestroy(2, quoted); // re
	}

// A string containing meaningful regexp characters, which is then meta-
// quoted, should not generally match a string the unquoted string does.
static void NegativeTestQuoteMetaL(const TDesC8& aUnquoted,
		const TDesC8& aNotMatch, TRegExOptions aOptions = TRegExOptions())
	{
	HBufC8* quoted = CRegEx::QuoteMetaL(aUnquoted);
	CleanupStack::PushL(quoted);

	CRegEx* re = CRegEx::NewLC(*quoted, aOptions);
	CHECK(!re->FullMatchL(aNotMatch));
	CleanupStack::PopAndDestroy(2, quoted); // re
	}

// Tests that quoted meta characters match their original strings,
// and that a few things that shouldn't match indeed do not.
static void TestQuotaMetaSimpleL()
	{
	TestQuoteMetaL(_L8("foo"));
	TestQuoteMetaL(_L8("foo.bar"));
	TestQuoteMetaL(_L8("foo\\.bar"));
	TestQuoteMetaL(_L8("[1-9]"));
	TestQuoteMetaL(_L8("1.5-2.0?"));
	TestQuoteMetaL(_L8("\\d"));
	TestQuoteMetaL(_L8("Who doesn't like ice cream?"));
	TestQuoteMetaL(_L8("((a|b)c?d*e+[f-h]i)"));
	TestQuoteMetaL(_L8("((?!)xxx).*yyy"));
	TestQuoteMetaL(_L8("(["));
	TestQuoteMetaL(_L8("foo\0bar"));
	}

static void TestQuoteMetaSimpleNegativeL()
	{
	NegativeTestQuoteMetaL(_L8("foo"), _L8("bar"));
	NegativeTestQuoteMetaL(_L8("..."), _L8("bar"));
	NegativeTestQuoteMetaL(_L8("\\."), _L8("."));
	NegativeTestQuoteMetaL(_L8("\\."), _L8(".."));
	NegativeTestQuoteMetaL(_L8("(a)"), _L8("a"));
	NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("a"));
	NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("(a)"));
	NegativeTestQuoteMetaL(_L8("(a|b)"), _L8("a|b"));
	NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("0"));
	NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("0-9"));
	NegativeTestQuoteMetaL(_L8("[0-9]"), _L8("[9]"));
	NegativeTestQuoteMetaL(_L8("((?!)xxx)"), _L8("xxx"));
	}

static void TestQuoteMetaLatin1L()
	{
	TestQuoteMetaL(_L8("3\xb2 = 9"));
	}


static void TestQuoteMetaUtf8L()
	{
#ifdef SUPPORT_UTF8
	TRegExOptions options;
	options.SetUtf8(ETrue);
	TestQuoteMetaL(_L8("Pl\xc3\xa1\x63ido Domingo"), options);
	TestQuoteMetaL(_L8("xyz"), options);            // No fancy utf8
	TestQuoteMetaL(_L8("\xc2\xb0"), options);       // 2-byte utf8 (degree symbol)
	TestQuoteMetaL(_L8("27\xc2\xb0 degrees"), options);  // As a middle character
	TestQuoteMetaL(_L8("\xe2\x80\xb3"), options);   // 3-byte utf8 (double prime)
	TestQuoteMetaL(_L8("\xf0\x9d\x85\x9f"), options); // 4-byte utf8 (music note)
	TestQuoteMetaL(_L8("27\xc2\xb0")); // Interpreted as Latin-1, but should still work
	NegativeTestQuoteMetaL(_L8("27\xc2\xb0"),               // 2-byte utf (degree symbol)
			_L8("27\\\xc2\\\xb0"),
			options);
#endif
	}


static void TestQuoteMetaAllL()
	{
	console->Write(_L("Testing QuoteMeta\n"));

	TestQuotaMetaSimpleL();
	TestQuoteMetaSimpleNegativeL();
	TestQuoteMetaLatin1L();
	TestQuoteMetaUtf8L();
	}

//
// Options tests contributed by
// Giuseppe Maxia, CTO, Stardata s.r.l.
// July 2005
//
static void GetOneOptionResultL(
                const TDesC& aOptionName,
                const TDesC8& aRegEx,
                const TDesC8& aString,
                TRegExOptions& aOptions,
                TBool aFull,
                const TDesC8& aExpected)
	{
	console->Printf(_L("Testing Option <%S>\n"), &aOptionName);
	
	if(verboseMode)
		{
		TBuf<32> str;
		str.Copy(aString);
		TBuf<32> rx;
		rx.Copy(aRegEx);
		TBuf<32> expected;
		expected.Copy(aExpected);

		console->Printf(_L("/%S/ finds \"%S\" within \"%S\" \n"), &rx, &expected, &str);
		}
	
  TBuf8<32> captured;
  CRegEx* re = CRegEx::NewLC(aRegEx, aOptions);
  
  if (aFull)
	  {
	  CHECK(re->FullMatchL(aString, &captured));
	  }    
  else
	  {
	  CHECK(re->PartialMatchL(aString, &captured));
	  }   
  CHECK_EQ(captured, aExpected);
  
  CleanupStack::PopAndDestroy(re);
}

static void TestOneOptionL(
                const TDesC& aOptionName,
                const TDesC8& aRegEx,
                const TDesC8& aString,
                const TRegExOptions& aOptions,
                TBool aFull,
                TBool aAssertive = ETrue)
	{
	
	console->Printf(_L("Testing Option <%S>\n"), &aOptionName);
	if(verboseMode)
		{
		_LIT(KMatches, "matches");
		_LIT(KNoMatch, "doesn't match");
		TBuf<32> str;
		str.Copy(aString);
		TBuf<64> rx;
		rx.Copy(aRegEx);
		
		console->Printf(_L("'%S' %S /%S/ \n"),
	                  &str,
	                  (aAssertive? &KMatches() : &KNoMatch()),
	                  &rx);	
		}

	CRegEx* re = NULL;
	TRAPD(err, re = CRegEx::NewLC(aRegEx, aOptions); CleanupStack::Pop());
	
	if(err)
		{
		CHECK_EQ(aAssertive, EFalse);
		return;
		}
	
	CleanupStack::PushL(re);
	
	if (aAssertive)
		{
		if (aFull)
			{
			CHECK(re->FullMatchL(aString));
			}     
		else
			{
			CHECK(re->PartialMatchL(aString));
			}
		}
	else
		{
		if (aFull)
			{
			CHECK(!re->FullMatchL(aString));
			}		  
		else
			{
			CHECK(!re->PartialMatchL(aString));
			}
		}
	CleanupStack::PopAndDestroy(re);	
	}

static void TestCaseLessL()
	{
	TRegExOptions options;
	TRegExOptions options2;
	TRegExOptions caseless;
	caseless.SetCaseless(ETrue);

	options.SetCaseless(ETrue);
	TestOneOptionL(_L("CASELESS (class)"), _L8("HELLO"), _L8("hello"), options, EFalse);
	TestOneOptionL(_L("CASELESS (class2)"), _L8("HELLO"), _L8("hello"), options2.SetCaseless(ETrue), EFalse);
	TestOneOptionL(_L("CASELESS (class)"), _L8("^[A-Z]+$"), _L8("Hello"), options, EFalse);

	TestOneOptionL(_L("CASELESS (function)"), _L8("HELLO"), _L8("hello"), caseless, EFalse);
	TestOneOptionL(_L("CASELESS (function)"), _L8("^[A-Z]+$"), _L8("Hello"), caseless, EFalse);
	options.SetCaseless(EFalse);
	TestOneOptionL(_L("no CASELESS"), _L8("HELLO"), _L8("hello"), options, EFalse, EFalse);
	}

static void TestMultilineL()
	{
	TRegExOptions options;
	TRegExOptions options2;
	TRegExOptions multiline;
	multiline.SetMultiline(ETrue);

	TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world\n"));

	options.SetMultiline(ETrue);
	TestOneOptionL(_L("MULTILINE (class)"), _L8("^cruel$"), str, options, EFalse);
	TestOneOptionL(_L("MULTILINE (class2)"), _L8("^cruel$"), str, options2.SetMultiline(ETrue), EFalse);
	TestOneOptionL(_L("MULTILINE (function)"), _L8("^cruel$"), str, multiline, EFalse);
	options.SetMultiline(EFalse);
	TestOneOptionL(_L("no MULTILINE"), _L8("^cruel$"), str, options, EFalse, EFalse);
	}

static void TestDotAllL()
	{
	TRegExOptions options;
	TRegExOptions options2;
	TRegExOptions dotAll;
	dotAll.SetDotAll(ETrue);

	TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world"));

	options.SetDotAll(ETrue);
	TestOneOptionL(_L("DOTALL (class)"), _L8("HELLO.*world"),str, options, ETrue);
	TestOneOptionL(_L("DOTALL (class2)"), _L8("HELLO.*world"),str, options2.SetDotAll(ETrue), ETrue);
	TestOneOptionL(_L("DOTALL (function)"), _L8("HELLO.*world"),str, dotAll, ETrue);
	options.SetDotAll(EFalse);
	TestOneOptionL(_L("no DOTALL"), _L8("HELLO.*world"),str, options, ETrue, EFalse);
	}

static void TestDollarEndOnlyL()
	{
	TRegExOptions options;
	TRegExOptions options2;
	TRegExOptions dollarEndOnly;
	dollarEndOnly.SetDollarEndOnly(ETrue);

	TBuf8<32> str(_L8("HELLO world\n"));

	TestOneOptionL(_L("no DOLLAR_ENDONLY"), _L8("world$"), str, options, EFalse);
	options.SetDollarEndOnly(ETrue);
	TestOneOptionL(_L("DOLLAR_ENDONLY 1"), _L8("world$"), str, options, EFalse, EFalse);
	TestOneOptionL(_L("DOLLAR_ENDONLY 2"), _L8("world$"), str, options2.SetDollarEndOnly(ETrue), EFalse, EFalse);
	}


static void TestExtraL()
	{	
	TRegExOptions options;

	TBuf8<32> str(_L8("HELLO"));
	options.SetExtra(ETrue);
	TestOneOptionL(_L("EXTRA 1"), _L8("\\HELL\\O"), str, options, ETrue, EFalse );
	TestOneOptionL(_L("EXTRA 2"), _L8("\\HELL\\O"), str, TRegExOptions().SetExtra(ETrue), ETrue, EFalse );
	options.SetExtra(EFalse);
	TestOneOptionL(_L("no EXTRA"), _L8("\\HELL\\O"), str, options, ETrue );
	}

static void TestExtendedL()
	{
	TRegExOptions options;
	TRegExOptions options2;
	TRegExOptions extended;
	extended.SetExtended(ETrue);

	TBuf8<32> str(_L8("HELLO world"));

	options.SetExtended(ETrue);
	TestOneOptionL(_L("EXTENDED (class)"), _L8("HELLO world"), str, options, EFalse, EFalse);
	TestOneOptionL(_L("EXTENDED (class2)"), _L8("HELLO world"), str, options2.SetExtended(ETrue), EFalse, EFalse);
	TestOneOptionL(_L("EXTENDED (class)"), _L8("^ HE L{2} O \\s+        \\w+ $      "), str, options, EFalse);

	TestOneOptionL(_L("EXTENDED (function)"), _L8("HELLO world"), str, extended, EFalse, EFalse);
	TestOneOptionL(_L("EXTENDED (function)"), _L8("^ HE L{2} O \\s+        \\w+ $      "), str, extended, EFalse);

	options.SetExtended(EFalse);
	TestOneOptionL(_L("no EXTENDED"), _L8("HELLO world"), str, options, EFalse);
	}

static void TestNoAutoCaptureL()
	{
	TRegExOptions options;
	TBuf8<32> str(_L8("HELLO world"));
	TBuf8<5> captured;
	console->Write(_L("Testing Option <no NO_AUTO_CAPTURE>\n"));
	if (verboseMode)
		{
		console->Write(_L("parentheses capture text\n"));
		}

	CRegEx* re = CRegEx::NewLC(_L8("(world|universe)$"), options);
	CHECK(re->ExtractL(_L8("\\1"), str , captured));
	CHECK_EQ(captured, _L8("world"));
	options.SetNoAutoCapture(ETrue);
	console->Write(_L("testing Option <NO_AUTO_CAPTURE>\n"));

	if (verboseMode)
		{
		console->Write(_L("parentheses do not capture text\n"));
		}

	re->ExtractL(_L8("\\1"),str, captured);
	CHECK_EQ(captured, _L8("world"));
	
	CleanupStack::PopAndDestroy(re);
	}

static void TestUngreedyL()
	{
	TRegExOptions options;
	TRegExOptions ungreedy;
	ungreedy.SetUngreedy(ETrue);

	TBuf8<32> str(_L8("HELLO, 'this' is the 'world'"));

	options.SetUngreedy(ETrue);
	GetOneOptionResultL(_L("UNGREEDY 1"), _L8("('.*')"), str, options, EFalse, _L8("'this'") );
	GetOneOptionResultL(_L("UNGREEDY 2"), _L8("('.*')"), str, ungreedy, EFalse, _L8("'this'") );
	GetOneOptionResultL(_L("UNGREEDY"), _L8("('.*?')"), str, options, EFalse, _L8("'this' is the 'world'") );

	options.SetUngreedy(EFalse);
	GetOneOptionResultL(_L("no UNGREEDY"), _L8("('.*')"), str, options, EFalse, _L8("'this' is the 'world'") );
	GetOneOptionResultL(_L("no UNGREEDY"), _L8("('.*?')"), str, options, EFalse, _L8("'this'") );
	}

static void TestAllOptionsL()
	{
	TBuf8<32> str(_L8("HELLO\n" "cruel\n" "world"));
	TRegExOptions options;
	options.SetAllOptions(EPcreCaseless | EPcreDotAll);

	TestOneOptionL(_L("all_options (CASELESS|DOTALL)"), _L8("^hello.*WORLD"), str , options, EFalse);
	options.SetAllOptions(0);
	TestOneOptionL(_L("all_options (0)"), _L8("^hello.*WORLD"), str , options, EFalse, EFalse);
	options.SetAllOptions(EPcreMultiline | EPcreExtended);

	TestOneOptionL(_L("all_options (MULTILINE|EXTENDED)"), _L8(" ^ c r u e l $ "), str, options, EFalse);
	TestOneOptionL(_L("all_options (MULTILINE|EXTENDED) with constructor"),
	_L8(" ^ c r u e l $ "),
	str,
	TRegExOptions(EPcreMultiline | EPcreExtended),
	EFalse);

	TRegExOptions multilineExtended = TRegExOptions().SetMultiline(ETrue);
	multilineExtended.SetExtended(ETrue);

	TestOneOptionL(_L("all_options (MULTILINE|EXTENDED) with concatenation"),
	_L8(" ^ c r u e l $ "),
	str,
	multilineExtended, EFalse);

	options.SetAllOptions(0);
	TestOneOptionL(_L("all_options (0)"), _L8("^ c r u e l $"), str, options, EFalse, EFalse);
	}

static void TestOptionsL()
	{
	console->Write(_L("Testing Options\n"));
	TestCaseLessL();
	TestMultilineL();
	TestDotAllL();
	TestDollarEndOnlyL();
	TestExtendedL();
	TestNoAutoCaptureL();
	TestUngreedyL();
	TestExtraL();
	TestAllOptionsL();
	}


LOCAL_C void MainL()
	{
	
	_LIT(KTimingArg1, "timing1");
	_LIT(KTimingArg2, "timing2");
	_LIT(KTimingArg3, "timing3");
	
	CCommandLineArguments* args = CCommandLineArguments::NewLC();

	// Treat any flag as --help
	if(args->Count() > 1 && args->Arg(1)[0] == '-')
		{
		console->Printf(_L("Usage: %S [%S|%S|%S num-iters]\n"), &(args->Arg(0)), &KTimingArg1(), &KTimingArg2(), &KTimingArg3());
		console->Write(_L("If 'timingX ###' is specified, run the given timing test\n"));
		console->Write(_L("with the given number of iterations, rather than running\n"));
		console->Write(_L("the default corectness test.\n"));
		CleanupStack::PopAndDestroy(args);
		return;		
		}
	if(args->Count() > 1)
		{
		if(args->Count() == 2)
			{
			console->Write(_L("timing mode needs a num-iters argument\n"));
			CleanupStack::PopAndDestroy(args);
			return;			
			}
		
		TLex lex(args->Arg(2));
		TInt iters;
		TInt err = lex.Val(iters);
		
		if(err || iters == 0)
			{
			CleanupStack::PopAndDestroy(args);
			return;	
			}
		
		if(args->Arg(1) == KTimingArg1)
			{
			Timing1L(iters);
			}
		else if(args->Arg(1) == KTimingArg2)
			{
			Timing2L(iters);
			}
		else if(args->Arg(1) == KTimingArg3)
			{
			Timing3L(iters);
			}		
		else
			{
			console->Printf(_L("Unknown argument '%S'\n"), &(args->Arg(1)));
			}
		CleanupStack::PopAndDestroy(args);
		return;			
		}
	CleanupStack::PopAndDestroy(args);
	
	console->Write(_L("Testing FullMatch\n"));

	CRegEx* re = NULL;
	TInt i;
	TBuf8<10> s;
	
	/***** FullMatch with no args *****/
	re = CRegEx::NewLC(_L8("h.*o"));
	CHECK(re->FullMatchL(_L8("hello")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("h.*o")); // Must be anchored at front
	CHECK(!re->FullMatchL(_L8("othello")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("h.*o")); // Must be anchored at end
	CHECK(!re->FullMatchL(_L8("hello!")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("a*")); // Fullmatch with normal op
	CHECK(re->FullMatchL(_L8("aaaa")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("a*?")); // Fullmatch with nongreedy op
	CHECK(re->FullMatchL(_L8("aaaa")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("a*?\\z")); // Two unusual ops
	CHECK(re->FullMatchL(_L8("aaaa")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	/***** FullMatch with args *****/

	// Zero-arg
	re = CRegEx::NewLC(_L8("\\d+"));
	CHECK(re->FullMatchL(_L8("1001")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	// Single-arg
	re = CRegEx::NewLC(_L8("(\\d+)"));
	CHECK(re->FullMatchL(_L8("1001"), &i));
	CHECK_EQ(i, 1001);
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(-?\\d+)"));
	CHECK(re->FullMatchL(_L8("-123"), &i));
	CHECK_EQ(i, -123);
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("()\\d+"));
	CHECK(!re->FullMatchL(_L8("10"), &i));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(\\d+)"));
	CHECK(!re->FullMatchL(_L8("1234567890123456789012345678901234567890"), &i));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	// Digits surrounding integer-arg
	re = CRegEx::NewLC(_L8("1(\\d*)4"));
	CHECK(re->FullMatchL(_L8("1234"), &i));
	CHECK_EQ(i, 23);
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(\\d)\\d+"));
	CHECK(re->FullMatchL(_L8("1234"), &i));
	CHECK_EQ(i, 1);
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(-\\d)\\d+"));
	CHECK(re->FullMatchL(_L8("-1234"), &i));
	CHECK_EQ(i, -1);
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(\\d)"));
	CHECK(re->PartialMatchL(_L8("1234"), &i));
	CHECK_EQ(i, 1);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("(-\\d)"));
	CHECK(re->PartialMatchL(_L8("-1234"), &i));
	CHECK_EQ(i, -1);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	// String-arg
	re = CRegEx::NewLC(_L8("h(.*)o"));
	CHECK(re->PartialMatchL(_L8("hello"), &s));
	CHECK_EQ(s, _L8("ell"));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	// Multi-arg
	re = CRegEx::NewLC(_L8("(\\w+):(\\d+)"));
	CHECK(re->PartialMatchL(_L8("ruby:1234"), &s, &i));
	CHECK_EQ(s.Length(), 4);
	CHECK_EQ(s, _L8("ruby"));
	CHECK_EQ(i, 1234);
	CleanupStack::PopAndDestroy(re);
	re = NULL;		

	// Ignore non-void* NULL arg
	re = CRegEx::NewLC(_L8("he(.*)lo"));
	CHECK(re->FullMatchL(_L8("hello"), (TDes8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("123"), (TInt8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;			

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("12345"), (TInt16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;			

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("1234567890"), (TInt32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;			

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("1234567890123456"), (TInt64*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("1234567890"), (TInt*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("123"), (TUint8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("12345"), (TUint16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("1234567890"), (TUint32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("1234567890"), (TUint*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal64*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(re->FullMatchL(_L8("123.4567890123456"), (TReal*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	// Fail on non-void* NULL arg if the match doesn't parse for the given type.
	re = CRegEx::NewLC(_L8("h(.*)lo"));
	CHECK(!re->FullMatchL(_L8("hello"), &s, (TDes8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TInt8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TInt16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TInt32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TInt64*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TInt*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TUint8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TUint16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TUint32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TUint*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TReal32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TReal64*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("hello"), (TReal*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("1234"), (TInt8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("123456"), (TInt16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("12345678901"), (TInt32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("12345678901"), (TInt*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("1234"), (TUint8*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("123456"), (TUint16*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("12345678901"), (TUint32*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(.*)"));
	CHECK(!re->FullMatchL(_L8("12345678901"), (TUint*)NULL));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	

	// Ignored arg
	re = CRegEx::NewLC(_L8("(\\w+)(:)(\\d+)"));
	CHECK(re->FullMatchL(_L8("ruby:1234"), &s, (TAny*)NULL, &i));
	CleanupStack::PopAndDestroy(re);
	CHECK_EQ(s, _L8("ruby"));
	CHECK_EQ(i, 1234);
	re = NULL;		

// Type tests
		{
		TChar c;
		re = CRegEx::NewLC(_L8("(H)ello"));
		CHECK(re->FullMatchL(_L8("Hello"), &c));
		CHECK_EQ(c, 'H');
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TInt8 v;
		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("127"), &v));
		CHECK_EQ(v, KMaxTInt8);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-128"), &v));
		CHECK_EQ(v, KMinTInt8);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("128"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-129"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TUint8 v;
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("128"), &v));
		CHECK_EQ(v, KMaxTInt8 + 1);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("255"), &v));
		CHECK_EQ(v, KMaxTUint8);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("256"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("-100"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TInt16 v;
		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("32767"), &v));
		CHECK_EQ(v, KMaxTInt16);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-32768"), &v));
		CHECK_EQ(v, KMinTInt16);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("32768"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-32769"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TUint16 v;
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("32767"), &v));
		CHECK_EQ(v, KMaxTInt16);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("65535"), &v));
		CHECK_EQ(v, KMaxTUint16);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("655356"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("-100"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;		
		}		
		{
		TInt32 v;
		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("2147483647"), &v));
		CHECK_EQ(v, KMaxTInt32);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-2147483648"), &v));
		CHECK_EQ(v, KMinTInt32);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("2147483648"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-2147483649"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}	
		{
		TUint32 v;
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("2147483647"), &v));
		CHECK_EQ(v, KMaxTInt32);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("4294967295"), &v));
		CHECK_EQ(v, KMaxTUint32);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("4294967296"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("-100"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;		
		}
		{
		TInt64 v;
		// Note  TLex treats TInt64 as unsigned
		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("9223372036854775807"), &v));
		CHECK_EQ(v, KMaxTInt64);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-100"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-9223372036854775808"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("9223372036854775808"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-9223372036854775809"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TInt v;
		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("2147483647"), &v));
		CHECK_EQ(v, KMaxTInt);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(re->FullMatchL(_L8("-2147483648"), &v));
		CHECK_EQ(v, KMinTInt);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("2147483648"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(-?\\d+)"));
		CHECK(!re->FullMatchL(_L8("-2147483649"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}	
		{
		TUint v;
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);		
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("2147483647"), &v));
		CHECK_EQ(v, KMaxTInt);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(re->FullMatchL(_L8("4294967295"), &v));
		CHECK_EQ(v, KMaxTUint);		
		CleanupStack::PopAndDestroy(re);

		re = NULL;

		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("4294967296"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		
		re = CRegEx::NewLC(_L8("(\\d+)"));
		CHECK(!re->FullMatchL(_L8("-100"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;		
		}		
		{
		TReal32 v;
		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("3.4028234663852885981170418348452e+38"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("-1.17549435E-38f"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		{
		TReal64 v;
		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("100"), &v));
		CHECK_EQ(v, 100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("-100"), &v));
		CHECK_EQ(v, -100);
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("1.7976931348623157E+308"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;

		re = CRegEx::NewLC(_L8("(.*)"));
		CHECK(re->FullMatchL(_L8("-2.2250738585072015E-308"), &v));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		
	// Check that matching is fully anchored
	re = CRegEx::NewLC(_L8("(\\d+)"));
	CHECK(!re->FullMatchL(_L8("x1001"), &i));
	CleanupStack::PopAndDestroy(re);
	re = NULL;	
	
	re = CRegEx::NewLC(_L8("(\\d+)"));
	CHECK(!re->FullMatchL(_L8("1001x"), &i));
	CleanupStack::PopAndDestroy(re);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("x(\\d+)"));
	CHECK(re->FullMatchL(_L8("x1001"), &i));
	CleanupStack::PopAndDestroy(re);
	CHECK_EQ(i, 1001);
	re = NULL;		
	
	re = CRegEx::NewLC(_L8("(\\d+)x"));
	CHECK(re->FullMatchL(_L8("1001x"), &i));
	CleanupStack::PopAndDestroy(re);
	CHECK_EQ(i, 1001);
	re = NULL;
	
	// Braces
	re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}"));
	CHECK(re->FullMatchL(_L8("0abcd")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}"));
	CHECK(re->FullMatchL(_L8("0abcde")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("[0-9a-f+.-]{5,}"));
	CHECK(!re->FullMatchL(_L8("0abc")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	// Complicated RE
	re = CRegEx::NewLC(_L8("foo|bar|[A-Z]"));
	CHECK(re->FullMatchL(_L8("foo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("foo|bar|[A-Z]"));
	CHECK(re->FullMatchL(_L8("bar")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("foo|bar|[A-Z]"));
	CHECK(re->FullMatchL(_L8("X")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	re = CRegEx::NewLC(_L8("foo|bar|[A-Z]"));
	CHECK(!re->FullMatchL(_L8("XY")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	
	// Check full-match handling (needs '$' tacked on internally)
	re = CRegEx::NewLC(_L8("fo|foo"));
	CHECK(re->FullMatchL(_L8("fo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("fo|foo"));
	CHECK(re->FullMatchL(_L8("foo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("fo|foo$"));
	CHECK(re->FullMatchL(_L8("fo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("fo|foo$"));
	CHECK(re->FullMatchL(_L8("foo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("foo$"));
	CHECK(re->FullMatchL(_L8("foo")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("foo\\$"));
	CHECK(!re->FullMatchL(_L8("foo$bar")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("fo|bar"));
	CHECK(!re->FullMatchL(_L8("fox")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	// Uncomment the following if we change the handling of '$' to
	// prevent it from matching a trailing newline
	if (false)
		{
		// Check that we don't get bitten by pcre's special handling of a
		// '\n' at the end of the string matching '$'
		re = CRegEx::NewLC(_L8("foo$"));
		CHECK(!re->PartialMatchL(_L8("foo\n")));
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}

	// Number of args
	TInt a[16];

	re = CRegEx::NewLC(_L8(""));
	CHECK(re->FullMatchL(_L8("")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d){1}"));
	CHECK(re->FullMatchL(_L8("1"), &a[0]));
	CHECK_EQ(a[0], 1);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("12"), &a[0], &a[1]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("123"), &a[0], &a[1], &a[2]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("1234"), &a[0], &a[1], &a[2], &a[3]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CHECK_EQ(a[3], 4);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	// Currently maximum args == 4
	/*
	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("12345"), &a[0], &a[1], &a[2], &a[3], &a[4]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CHECK_EQ(a[3], 4);
	CHECK_EQ(a[4], 5);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("123456"), &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CHECK_EQ(a[3], 4);
	CHECK_EQ(a[4], 5);
	CHECK_EQ(a[5], 6);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re = CRegEx::NewLC(_L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("1234567"), &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CHECK_EQ(a[3], 4);
	CHECK_EQ(a[4], 5);
	CHECK_EQ(a[5], 6);
	CHECK_EQ(a[6], 7);
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	memset(a, 0, sizeof(0));
	re
			= CRegEx::NewLC(
					_L8("(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)"));
	CHECK(re->FullMatchL(_L8("1234567890123456"), &a[0], &a[1], &a[2], &a[3],
					&a[4], &a[5], &a[6], &a[7],
					&a[8], &a[9], &a[10], &a[11],
					&a[12],&a[13], &a[14], &a[15]));
	CHECK_EQ(a[0], 1);
	CHECK_EQ(a[1], 2);
	CHECK_EQ(a[2], 3);
	CHECK_EQ(a[3], 4);
	CHECK_EQ(a[4], 5);
	CHECK_EQ(a[5], 6);
	CHECK_EQ(a[6], 7);
	CHECK_EQ(a[7], 8);
	CHECK_EQ(a[8], 9);
	CHECK_EQ(a[9], 0);
	CHECK_EQ(a[10], 1);
	CHECK_EQ(a[11], 2);
	CHECK_EQ(a[12], 3);
	CHECK_EQ(a[13], 4);
	CHECK_EQ(a[14], 5);
	CHECK_EQ(a[15], 6);
	CleanupStack::PopAndDestroy(re);
	re = NULL;
	 */
	
	/***** PartialMatch *****/
	console->Write(_L("Testing PartialMatch\n"));

	re = CRegEx::NewLC(_L8("h.*o"));
	CHECK(re->PartialMatchL(_L8("hello")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("h.*o"));
	CHECK(re->PartialMatchL(_L8("othello")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("h.*o"));
	CHECK(re->PartialMatchL(_L8("hello!")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	re = CRegEx::NewLC(_L8("((((((((((((((((((((x))))))))))))))))))))"));
	CHECK(re->PartialMatchL(_L8("x")));
	CleanupStack::PopAndDestroy(re);
	re = NULL;

	/***** other tests *****/

	RadixTestsL();
	TestReplaceL();
	TestExtractL();
	TestConsumeL();
	TestFindAndConsumeL();
	TestQuoteMetaAllL();
	TestMatchNumberPeculiarityL();
	
	// Check the pattern() accessor
		{
		_LIT8(KPattern, "http://([^/]+)/.*");
		re = CRegEx::NewLC(KPattern());
		CHECK_EQ(KPattern(), re->Pattern());
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}	
		// Check RE error field.
		{
		re = CRegEx::NewLC(_L8("foo"));
		CHECK_EQ(re->Error(), KErrNone);  // Must have no error
		CleanupStack::PopAndDestroy(re);
		re = NULL;
		}
		
#ifdef SUPPORT_UTF8
	  // Check UTF-8 handling
		{
		console->Write(_L("Testing UTF-8 handling\n"));

		// Three Japanese characters (nihongo)
		TBuf8<9> utf8String(_L8("\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"));
		TBuf8<5> utf8Pattern(_L8(".\xE6\x9C\xAC."));
		TRegExOptions utf8Options;
		utf8Options.SetUtf8(ETrue);	
	
		// Both should match in either mode, bytes or UTF-8
		CRegEx* re_test1 = CRegEx::NewLC(_L8("........."));
		CHECK(re_test1->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test1);
		re_test1 = NULL;
		
		CRegEx* re_test2 = CRegEx::NewLC(_L8("..."), utf8Options);
		CHECK(re_test2->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test2);
		re_test2 = NULL;		

		// Check that '.' matches one byte or UTF-8 character
		// according to the mode.
		TBuf8<3> ss;
		
		CRegEx* re_test3 = CRegEx::NewLC(_L8("(.)"));
		CHECK(re_test3->PartialMatchL(utf8String, &ss));
		CHECK_EQ(ss, _L8("\xE6"));
		CleanupStack::PopAndDestroy(re_test3);
		re_test3 = NULL;	
		
		CRegEx* re_test4 = CRegEx::NewLC(_L8("(.)"), utf8Options);
		CHECK(re_test4->PartialMatchL(utf8String, &ss));
		CHECK_EQ(ss, _L8("\xE6\x97\xA5"));
		CleanupStack::PopAndDestroy(re_test4);
		re_test4 = NULL;	
		
		// Check that string matches itself in either mode
		CRegEx* re_test5 = CRegEx::NewLC(utf8String);
		CHECK(re_test5->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test5);
		re_test5 = NULL;	
		
		CRegEx* re_test6 = CRegEx::NewLC(utf8String, utf8Options);
		CHECK(re_test6->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test6);
		re_test6 = NULL;			
		
		// Check that pattern matches string only in UTF8 mode
		CRegEx* re_test7 = CRegEx::NewLC(utf8Pattern);
		CHECK(!re_test7->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test7);
		re_test7 = NULL;
		
		CRegEx* re_test8 = CRegEx::NewLC(utf8Pattern, utf8Options);
		CHECK(re_test8->FullMatchL(utf8String));
		CleanupStack::PopAndDestroy(re_test8);
		re_test8 = NULL;
		}

	// Check that ungreedy, UTF8 regular expressions don't match when they
	// oughtn't -- see bug 82246.
		{
		// This code always worked.
		_LIT8(KPattern, "\\w+X");
		_LIT8(KTarget, "a aX");

		TRegExOptions utf8Options;
		utf8Options.SetUtf8(ETrue);	
		
		CRegEx* matchSentence = CRegEx::NewLC(KPattern());
		CHECK(!matchSentence->FullMatchL(KTarget()));
		CleanupStack::PopAndDestroy(matchSentence);
		matchSentence = NULL;
		
		CRegEx* matchSentenceRe = CRegEx::NewLC(KPattern(), utf8Options);
		CHECK(!matchSentenceRe->FullMatchL(KTarget()));
		CleanupStack::PopAndDestroy(matchSentenceRe);
		matchSentenceRe = NULL;
		}
		{
		_LIT8(KPattern, "(?U)\\w+X");
		_LIT8(KTarget, "a aX");

		TRegExOptions utf8Options;
		utf8Options.SetUtf8(ETrue);	
		
		CRegEx* matchSentence = CRegEx::NewLC(KPattern());
		CHECK(!matchSentence->FullMatchL(KTarget()));
		CleanupStack::PopAndDestroy(matchSentence);
		matchSentence = NULL;
		
		CRegEx* matchSentenceRe = CRegEx::NewLC(KPattern(), utf8Options);
		CHECK(!matchSentenceRe->FullMatchL(KTarget()));
		CleanupStack::PopAndDestroy(matchSentenceRe);
		matchSentenceRe = NULL;
		}
		
#endif  /* def SUPPORT_UTF8 */	

  console->Write(_L("Testing error reporting\n"));
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a\\1")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a[x")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a[z-a]")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a[[:foobar:]]")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a(b")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  {
	  TRAPD(err, re = CRegEx::NewLC(_L8("a\\")); CleanupStack::PopAndDestroy());
	  CHECK(err != KErrNone);
	  re = NULL;
	  }
	  
	  // Test that recursion is stopped
	  TestRecursionL();
	  
	  // Test Options
	  TestOptionsL();

	  // Done
	  console->Write(_L("OK\n"));
	}
LOCAL_C void DoStartL()
	{
	// Create active scheduler (to run active objects)
	CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
	CleanupStack::PushL(scheduler);
	CActiveScheduler::Install(scheduler);

	MainL();

	// Delete active scheduler
	CleanupStack::PopAndDestroy(scheduler);
	}

//  Global Functions

GLDEF_C TInt E32Main()
	{
	// Create cleanup stack
	__UHEAP_MARK;
	CTrapCleanup* cleanup = CTrapCleanup::New();
	// Create output console
	TRAPD(createError, console = Console::NewL(KTextConsoleTitle, TSize(
							KConsFullScreen, KConsFullScreen)));
	if (createError)
		return createError;
	// Run application code inside TRAP harness, wait keypress when terminated
	TRAPD(mainError, DoStartL());
	if (mainError)
		console->Printf(KTextFailed, mainError);
	console->Printf(KTextPressAnyKey);
	console->Getch();

	delete console;
	delete cleanup;
	__UHEAP_MARKEND;
	return KErrNone;
	}