sl@0: /*
sl@0: * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
sl@0: * All rights reserved.
sl@0: * This component and the accompanying materials are made available
sl@0: * under the terms of the License "Eclipse Public License v1.0"
sl@0: * which accompanies this distribution, and is available
sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: *
sl@0: * Initial Contributors:
sl@0: * Nokia Corporation - initial contribution.
sl@0: *
sl@0: * Contributors:
sl@0: *
sl@0: * Description: 
sl@0: *
sl@0: */
sl@0: 
sl@0: 
sl@0: #include "StateMachine.h"
sl@0: 
sl@0: // CStateMachine
sl@0: CStateMachine::CStateMachine(TInt aMaxNumberChars, TInt aMaxNumberStates) : iMaxNumberChars(static_cast<TInt>(aMaxNumberChars)),
sl@0: 																			iMaxNumberStates(static_cast<TInt>(aMaxNumberStates))
sl@0: {
sl@0: }
sl@0: 
sl@0: CStateMachine* CStateMachine::NewL(TInt aMaxNumberChars, TInt aMaxNumberStates)
sl@0: {
sl@0: 	CStateMachine* s = NewLC(aMaxNumberChars, aMaxNumberStates);
sl@0: 	CleanupStack::Pop();
sl@0: 	return s;
sl@0: }
sl@0: 
sl@0: CStateMachine* CStateMachine::NewLC(TInt aMaxNumberChars, TInt aMaxNumberStates)
sl@0: {
sl@0: 	CStateMachine* s = new(ELeave)CStateMachine(aMaxNumberChars, aMaxNumberStates);
sl@0: 	CleanupStack::PushL(s);
sl@0: 	s->ConstructL();
sl@0: 	return s;
sl@0: }
sl@0: 
sl@0: CStateMachine::~CStateMachine()
sl@0: {
sl@0: 	for(TInt i = 0; i < iMaxNumberChars; ++i)
sl@0: 		delete iStateTable[i];
sl@0: 	
sl@0: 	delete iStateTable;
sl@0: }
sl@0: 
sl@0: void CStateMachine::ConstructL()
sl@0: {
sl@0: 	iStateTable = new TInt*[iMaxNumberChars];	
sl@0: 
sl@0: 	for(TInt i = 0; i < iMaxNumberChars; ++i)
sl@0: 	{
sl@0: 		iStateTable[i] = new TInt[iMaxNumberStates];
sl@0: 		for(TInt j = 0; j < iMaxNumberStates; j++)
sl@0: 			iStateTable[i][j] = 0;
sl@0: 	}
sl@0: }
sl@0: 
sl@0: void CStateMachine::AddStateTransistionL(TChar aChar, TInt aState, TInt aNextState)
sl@0: {
sl@0: 	RArray<TInt> Dummy;
sl@0: 	TInt CharIndex = MapIndex(aChar, Dummy);
sl@0: 	Dummy.Close();
sl@0: 	
sl@0: 	AddStateTransistionL(CharIndex, aState, aNextState);
sl@0: }
sl@0: 
sl@0: void CStateMachine::AddStateTransistionL(TInt aIndex, TInt aState, TInt aNextState)
sl@0: {
sl@0:     if(aIndex < 0 || aIndex > iMaxNumberChars || aState > iMaxNumberStates || aNextState > iMaxNumberStates)
sl@0: 		User::Leave(KErrGeneral);
sl@0: 
sl@0: 	iStateTable[static_cast<TInt>(aIndex)][static_cast<TInt>(aState)] = static_cast<TInt>(aNextState);
sl@0: }
sl@0: 
sl@0: TBool CStateMachine::Matches(const TDesC& aString)
sl@0: {
sl@0: 	// Walk the state table and return true if the string matches the pattern.
sl@0: 	
sl@0: 	TInt			nTableState = KStateNoMatch;
sl@0: 	RArray<TInt>	arrIndices;
sl@0: 	TBool			bFound = EFalse;
sl@0: 
sl@0: 	for(TInt nStringIndex = 0; nStringIndex < aString.Length(); ++nStringIndex)
sl@0: 	{
sl@0: 		arrIndices.Reset();
sl@0: 		
sl@0: 		TChar	charChar = aString[nStringIndex];
sl@0: 		TInt	nTableIndex = MapIndex(charChar, arrIndices);
sl@0: 
sl@0: 		if(nTableIndex == -1) 
sl@0: 			return EFalse;
sl@0: 		
sl@0: 		TInt nCount = arrIndices.Count();
sl@0: 		
sl@0: 		if(nCount)
sl@0: 		{
sl@0: 			for(TInt i = 0; i < nCount; i++)
sl@0: 			{
sl@0: 				nTableIndex = arrIndices[i];
sl@0: 				TInt NewTableState = iStateTable[nTableIndex][nTableState];
sl@0: 				
sl@0: 				if( NewTableState != KStateNoMatch || 
sl@0: 					(NewTableState == KStateNoMatch && i == (arrIndices.Count() - 1)) ||
sl@0: 					NewTableState == KStateMatched)
sl@0: 				{
sl@0: 					nTableState = NewTableState;
sl@0: 					break;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 		else
sl@0: 		{
sl@0: 			nTableState = iStateTable[nTableIndex][nTableState];
sl@0: 		}
sl@0: 
sl@0: 		if(nTableState == KStateNoMatch)
sl@0: 			break;
sl@0: 
sl@0: 		if(nTableState == KStateMatched)
sl@0: 		{
sl@0: 			bFound = ETrue;
sl@0: 			break;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 	arrIndices.Close();
sl@0: 	
sl@0: 	return bFound;
sl@0: }
sl@0: 
sl@0: TInt CStateMachine::MapIndex(TChar aChar, RArray<TInt>& aIndices)
sl@0: {
sl@0:     // Check the type of aChar and return the relevant index or indicies
sl@0: 	if(aChar.IsDigit())
sl@0: 	{
sl@0: 		TInt nIndex = static_cast<TInt>(aChar.GetNumericValue());
sl@0: 		
sl@0: 		TInt ret = KErrNone;
sl@0: 		ret |= aIndices.Append(nIndex);
sl@0: 		ret |= aIndices.Append(KCharacterDot);
sl@0: 		__ASSERT_DEBUG(!ret, User::Panic(_L("RArray append failure"), ret));
sl@0: 		if (KErrNone != ret) return ret;
sl@0: 
sl@0: 		return nIndex;
sl@0: 	}
sl@0: 
sl@0: 	if(aChar == '+')	return KCharacterPlus;
sl@0: 	if(aChar == '.')	return KCharacterDot;
sl@0: 
sl@0:     return -1;  // TO DO : define 
sl@0: }
sl@0: 
sl@0: void CStateMachine::GetWildcardVersionOfPattern( 
sl@0:     TText aWildcardChar, 
sl@0:     TDes& aWildcardedPattern ) const
sl@0:     {
sl@0:     aWildcardedPattern.SetLength(0);
sl@0:     TInt maxLength = aWildcardedPattern.MaxLength();
sl@0:     // There is a column in the StateTable for each character in the regular expression. The first character
sl@0:     // of the regexp in column [0], last in column [Length()-1]
sl@0:     // The non-zero values found within a column of the StateTable represent the characters
sl@0:     // that are valid at that position in a candidate match.
sl@0:     // An example pattern is calculated by examining the StateTable.
sl@0:     // For each column, count the number of matching ( i.e. not KStateNoMatch) states
sl@0:     // If only one, then place that character in the example pattern.
sl@0:     // If more than one, put the wildcard in.
sl@0:     for(TInt stateIndex = 0; stateIndex < iMaxNumberStates && stateIndex < maxLength; stateIndex++)
sl@0:         {
sl@0:         TInt matches = 0;
sl@0:         TInt matchedIndex = -1;
sl@0:         for (TInt charIndex = 0; charIndex < iMaxNumberChars; charIndex++ )
sl@0:             {
sl@0:             TInt nextState = iStateTable[charIndex][stateIndex];
sl@0: 
sl@0:             if ( nextState != KStateNoMatch )
sl@0:                 {
sl@0:                 matches++;
sl@0:                 matchedIndex = charIndex;
sl@0:                 if (matches > 1 )
sl@0:                     break;
sl@0:                 }
sl@0:             }
sl@0:         if ( matches == 0 ) // Have found an empty column.  Unused part of state machine. Stop filling
sl@0:             {
sl@0:             break;
sl@0:             }
sl@0:         else if ( matches > 1 )
sl@0:             aWildcardedPattern.Append(aWildcardChar);
sl@0:         else
sl@0:             {
sl@0:             if ( 0 <= matchedIndex && matchedIndex <= 9 ) // Must be a numeric digit
sl@0:                 {
sl@0:                 aWildcardedPattern.Append((TText)(matchedIndex+'0'));
sl@0:                 }
sl@0:             else if ( matchedIndex == KCharacterDot )
sl@0:                 {
sl@0:                 aWildcardedPattern.Append(aWildcardChar);
sl@0:                 }
sl@0:             else if ( matchedIndex == KCharacterPlus )
sl@0:                 {
sl@0:                 aWildcardedPattern.Append('+');
sl@0:                 }
sl@0:             else
sl@0:                 {
sl@0:                 aWildcardedPattern.Append(aWildcardChar);
sl@0:                 }
sl@0:             }
sl@0:         }
sl@0: 
sl@0:     }
sl@0: // End of File
sl@0: