telephonyprotocols/csdagt/script/SCOMMAND.CPP
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyprotocols/csdagt/script/SCOMMAND.CPP	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1397 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// NetDial Script Commands
+// 
+//
+
+/**
+ @file Scommand.cpp 
+*/
+
+#include "SSCRREAD.H"
+#include "SSCREXEC.H"
+#include "SIO.H"
+#include "SLOGGER.H"
+
+// Command names
+
+_LIT(KSetCommand,"SET");
+_LIT(KSendCommand,"SEND");
+_LIT(KWaitCommand,"WAIT");
+_LIT(KLoopCommand,"LOOP");
+_LIT(KGotoCommand,"GOTO");
+_LIT(KExitCommand,"EXIT");
+_LIT(KDTRCommand,"DTR");
+_LIT(KDropDTRCommand,"RAISE");
+_LIT(KRaiseDTRCommand,"DROP");
+_LIT(KReadCommand,"READ");
+_LIT(KCharmapCommand,"CHARMAP");
+_LIT(KTempVarName,"$$TMPVAR$$%d");	//< Temporary variable name
+
+// Characters used in scripts
+
+const TText KCommentChar='!';	
+const TText KPlusChar='+';
+const TText KQuoteChar='\"';
+const TText KOpenChevronChar='<';
+const TText KCloseChevronChar='>';
+const TText KOpenExprChar='{';
+const TText KCloseExprChar='}';
+const TText KEqualsChar='=';
+const TText KTabChar='\t';
+const TText KSpaceChar=' ';
+const TText KColonChar=':';
+const TText KOpenSquareBracketChar='[';
+const TText KCloseSquareBracketChar=']';
+const TInt KLabelArrayGranularity=5;
+const TInt32 KMinScriptInteger=0;
+const TInt32 KMaxScriptInteger=500000;
+const TReal KMinScriptReal=0.0;
+const TReal KMaxScriptReal=500000.0;
+const TInt KMinLoopCounter=1;
+const TInt KMaxLoopCounter=10000;
+
+//
+// Glossary
+// ========
+// String				- a text string enclosed in ".."
+// Character			- a single character expressed numnerically enclosed in <..>
+// Variable				- named variable (preset or set in script) ending in $
+// Expression			- any one of the three above
+// Compound expression	- a number of expressions concatenated with +
+// Token				- an expression, compound expression, label or command
+//
+
+//
+// CScriptCommandBase definitions
+//
+
+CScriptCommandBase::CScriptCommandBase(TScriptStatus& aStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+	: iScriptReader(aScriptReader), iVarMan(aVarMan), iCharConv(aCharConv), iTempVarNum(0), iStatus(aStatus)
+/**
+Constructor for CScriptCharacterConverter.
+*/
+	{}
+
+CScriptCommandBase::~CScriptCommandBase()
+/**
+Destructor.
+*/
+	{}
+
+void CScriptCommandBase::ConstructL()
+/**
+Instantiates member variables.
+*/
+	{}
+
+void CScriptCommandBase::Cleanup()
+/**
+Cleanup.
+*/
+	{}
+
+TPtrC CScriptCommandBase::ParseCompoundExpressionL(TInt& aOffset)
+/**
+Parses a compound string expression starting at aOffset into a single string
+constant and returns it.
+*/
+	{
+	TPtrC wholeExpr;
+	wholeExpr.Set(ParseExpressionL(aOffset));
+	TBuf<KMaxVarNameLength> varName;
+	varName.Format(KTempVarName,iTempVarNum++);
+	iVarMan->AddVariableL(varName,wholeExpr);
+	HBufC* val=NULL;
+	HBufC* oldVal=NULL;
+	
+	FOREVER
+		{
+		EatSpaces(aOffset);
+		if (aOffset>=iStatus.iLine.Length())
+			break;
+		if (iStatus.iLine[aOffset]!=KPlusChar)
+			break;
+		TPtrC nextExpr;
+		nextExpr.Set(ParseExpressionL(++aOffset));
+		val=HBufC::NewLC(wholeExpr.Length()+nextExpr.Length());
+		TPtr currentExpr(val->Des());
+		currentExpr.Append(wholeExpr);
+		currentExpr.Append(nextExpr);
+		varName.Format(KTempVarName,iTempVarNum++);
+		iVarMan->AddVariableL(varName,val->Des());
+		CleanupStack::Pop();
+		wholeExpr.Set(val->Des());
+		delete oldVal;
+		oldVal=val;
+		}
+
+	delete val;
+	User::LeaveIfError(iVarMan->FindVariable(varName,wholeExpr));
+	return wholeExpr;
+	}
+
+TPtrC CScriptCommandBase::ParseExpressionL(TInt& aOffset)
+/**
+Parses string expression starting at aOffset according to starting character
+and returns value.
+*/
+	{
+	EatSpaces(aOffset);
+	if(iStatus.iLine.Length()<=aOffset)
+		User::Leave(KErrNoExpression);
+
+	switch(iStatus.iLine[aOffset])		//switch(iLine[aOffset+1])
+		{
+	case KQuoteChar:
+		aOffset++;							// skip quote char
+		return ParseStringL(aOffset);
+	case KOpenChevronChar:
+		aOffset++;							// skip chevron char
+		return ParseCharacterL(aOffset);
+	default:
+		return ParseVariableL(aOffset);
+		}
+	}
+
+TPtrC CScriptCommandBase::ParseStringL(TInt& aOffset)
+/**
+Parses a string constant enclosed in "" and returns its value.
+*/
+	{
+	return ParseEnclosedStringL(aOffset,KQuoteChar,KErrMissingQuote);
+	}
+
+TPtrC CScriptCommandBase::ParseCharacterL(TInt& aOffset)
+/**
+Parses a character enclosed in <> and returns its value.
+*/
+	{
+	TPtrC charString=ParseEnclosedStringL(aOffset,KCloseChevronChar,KErrMissingChevron);
+	TRadix radix=EDecimal;
+	TInt len=charString.Length();
+	if (len>2)
+		{
+		if(charString[0]=='0')
+			{
+			switch(charString[1])
+				{
+			case 'x':
+			case 'X':
+				len-=2;
+				radix=EHex;
+				break;
+			case 'd':
+			case 'D':
+				len-=2;
+				radix=EDecimal;
+				break;
+			case 'o':
+			case 'O':
+				len-=2;
+				radix=EOctal;
+				break;
+			case 'b':
+			case 'B':
+				len-=2;
+				radix=EBinary;
+				break;
+			default:
+				break;
+				}
+			}
+		}
+
+	TLex lex(charString.Right(len));
+	TUint val=0;
+	if (lex.Val(val,radix)!=KErrNone)
+		User::Leave(KErrInvalidNumber);
+	TBuf<1> character=(TText*)&val;
+	TBuf<KMaxVarNameLength> varName;
+	varName.Format(KTempVarName,iTempVarNum++);
+	iVarMan->AddVariableL(varName,character);
+	TPtrC temp;
+	iVarMan->FindVariable(varName,temp);
+	return temp;
+	}
+
+TPtrC CScriptCommandBase::ParseVariableL(TInt& aOffset)
+/**
+Parses a variable and returns its value.
+*/
+	{
+	TInt end=FindTokenEnd(aOffset);
+	TPtrC varName=iStatus.iLine.Mid(aOffset,end-aOffset);
+	aOffset=end;
+	TPtrC varValue;
+	if (iVarMan->FindVariable(varName,varValue)==KErrNotFound)
+		{
+		if(!iStatus.iSkip)
+			User::Leave(KErrVariableNotFound);
+		return TPtrC();
+		}
+	return varValue;
+	}
+
+TInt32 CScriptCommandBase::ParseIntegerL(TInt& aOffset)
+/**
+Parses an integer and returns its value.
+*/
+	{
+	EatSpaces(aOffset);
+	TLex lex(iStatus.iLine);
+	lex.Inc(aOffset);
+	TInt32 val=0;
+	
+	if (lex.Val(val)!=KErrNone)
+		{
+		User::Leave(KErrInvalidNumber);
+		return KMinScriptInteger;
+		}
+
+	if ((val<KMinScriptInteger) || (val>KMaxScriptInteger))
+		{
+		User::Leave(KErrNumberOutOfRange);
+		return KMinScriptInteger;
+		}
+
+	aOffset=lex.Offset();
+	return val;
+	}
+
+TReal CScriptCommandBase::ParseRealL(TInt& aOffset)
+/**
+Parses a real number and returns its value.
+*/
+	{
+	EatSpaces(aOffset);
+	TLex lex(iStatus.iLine);
+	lex.Inc(aOffset);
+	TReal val=0.0;
+
+	if (lex.Val(val)!=KErrNone)
+		{	
+		User::Leave(KErrInvalidNumber);
+		return KMinScriptReal;
+		}
+	if ((val<KMinScriptReal) || (val>KMaxScriptReal))
+		{
+		User::Leave(KErrNumberOutOfRange);
+		return KMinScriptReal;
+		}
+
+	aOffset=lex.Offset();
+	return val;
+	}
+
+TPtrC CScriptCommandBase::ParseCharacterTypeL(TInt& aOffset)
+/**
+Parses character type.
+*/
+	{
+	EatSpaces(aOffset);
+
+	if(iStatus.iLine.Length()<=aOffset)		// nothing specified so assume default
+		return TPtrC();
+
+	TInt startChar=aOffset;
+	if (iStatus.iLine[startChar++]!=KOpenSquareBracketChar)
+		return TPtrC();				// No open bracket so assume default
+
+	aOffset=startChar;
+	return ParseEnclosedStringL(aOffset,KCloseSquareBracketChar,KErrMissingBracket);
+	}
+
+HBufC8* CScriptCommandBase::ConvertLC(const TDesC& aString,TInt& aOffset)
+/**
+Converts to correct character set.
+*/
+	{
+	TBuf<KMaxCharacterTypeLength> type=ParseCharacterTypeL(aOffset);
+	return iCharConv->ConvertLC(aString,type);
+	}
+
+TInt CScriptCommandBase::FindTokenEnd(TInt aOffset)
+/**
+Finds end of string beginning at aOffset and returns length.
+*/
+	{
+	__ASSERT_DEBUG(aOffset<=iStatus.iLine.Length(), NetDialPanic(EOffsetExceedsLineLength));
+
+	if(aOffset==iStatus.iLine.Length())
+		return aOffset;
+
+	TInt end;
+	for (end=aOffset; IsValidChar(iStatus.iLine[end]); end++)
+		{
+		if (end>=(iStatus.iLine.Length()-1))
+			{
+			end++;
+			break;
+			}
+		}
+	return end;
+	}
+
+TBool CScriptCommandBase::IsValidChar(const TText& aChar)
+/**
+Checks if aChar is a valid character in a script command.
+*/
+	{
+	return TChar(aChar).IsAlphaDigit() || (aChar==KDollarChar) || (aChar==KUnderscoreChar) || (aChar==KCommentChar);
+	}
+
+void CScriptCommandBase::EatSpaces(TInt& aOffset)
+/**
+Ignores spaces, tabs, line feeds and carriage returns and sets aOffset to 
+next non-blank character, or end of line
+*/
+	{
+	if(aOffset>=iStatus.iLine.Length())
+		return;
+
+	while((iStatus.iLine[aOffset]==KSpaceChar) || (iStatus.iLine[aOffset]==KTabChar) || (iStatus.iLine[aOffset]==KLineFeed) || (iStatus.iLine[aOffset]==KCarriageReturn))
+		{
+		aOffset++;
+		if(aOffset>=iStatus.iLine.Length())
+			break;
+		}
+	}
+
+void CScriptCommandBase::EatSpacesAndLinesL()
+/**
+Ignores spaces and empty lines and sets aOffset to next non-blank character.
+*/
+	{
+	EatSpaces(iStatus.iOffset);
+	while(iStatus.iOffset>=iStatus.iLine.Length())
+		{
+		User::LeaveIfError(iScriptReader->GetNextLine());		// This also resets iStatus.iOffset
+		EatSpaces(iStatus.iOffset);
+		}	
+	}
+
+void CScriptCommandBase::EatSpacesAndLinesAndCommentsL()
+/**
+Ignores spaces, empty lines and comments and sets aOffset to next non-blank or 
+non-comment character
+*/
+	{
+	EatSpacesAndLinesL();
+	while (iStatus.iLine[iStatus.iOffset]==KCommentChar)
+		{
+		iStatus.iOffset=iStatus.iLine.Length();
+		EatSpacesAndLinesL();		// this will reset iStatus.iOffset if necessary
+		}
+	}	
+
+TPtrC CScriptCommandBase::ParseEnclosedStringL(TInt& aOffset,TText aChar,TInt aError)
+/**
+Parses enclosed string
+*/
+	{
+	if(aOffset>=iStatus.iLine.Length())
+		User::Leave(aError);			// no end character before EOL
+	
+	TInt end=aOffset;
+	while (end<iStatus.iLine.Length())
+		{
+		if (iStatus.iLine[end]==aChar)
+			break;
+		end++;
+		}
+
+	if (end>=iStatus.iLine.Length())
+		User::Leave(aError);			// no end character before EOL
+
+	TInt start=aOffset;
+	aOffset=end+1;
+	return iStatus.iLine.Mid(start,end-start);
+	}
+
+//
+// CSetCommand definitions
+//
+
+CSetCommand* CSetCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+/**
+2 phased constructor for CSetCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CSetCommand object.
+*/
+	{
+	CSetCommand* c=new(ELeave) CSetCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CSetCommand::CSetCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv)
+/**
+Constructor for CSetCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+*/
+	{}
+
+CSetCommand::~CSetCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CSetCommand::ParseL()
+/**
+Parses a SET command. Determines variable name and value and adds to variable list.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KSetCommand)==KErrNone)
+		{
+		if (!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(KLogStringExecutingSet,"Script:\tExecuting Set");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),KLogStringExecutingSet());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		end=FindTokenEnd(iStatus.iOffset);
+		TPtrC varName=iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset);
+		EatSpaces(end);
+		if (iStatus.iLine[end++]!=KEqualsChar)
+			User::Leave(KErrNoEquals);
+		EatSpaces(end);
+		TPtrC value=ParseCompoundExpressionL(end);
+		if (!iStatus.iSkip)
+			{
+			iVarMan->AddVariableL(varName,value);
+			__FLOG_STMT(_LIT(KLogStringSetVar,"Script:\tSet Var: %S  To %S"));
+			__FLOG_STATIC2(KNetDialLogFolder(),KNetDialLogFile(),TRefByValue<const TDesC>(KLogStringSetVar()),&varName,&value);
+			}
+		iStatus.iOffset=end;
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+//
+// CSendCommand definitions
+//
+
+CSendCommand* CSendCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO)
+/**
+2 phased constructor for CSendCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CSendCommand object.
+*/
+	{
+	CSendCommand* c=new(ELeave) CSendCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv,aScriptIO);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CSendCommand::CSendCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iScriptIO(aScriptIO)
+/**
+Constructor for CSendCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+*/
+	{}
+
+CSendCommand::~CSendCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CSendCommand::ParseL()
+/**
+Parses SEND command.  Parses expression to send and sends it.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if(iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KSendCommand)==0)
+		{
+		if(!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(KLogStringExecutingSend,"Script:\tExecuting Send");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),KLogStringExecutingSend());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		TPtrC temp;
+		temp.Set(ParseCompoundExpressionL(iStatus.iOffset));
+		HBufC8* buf=ConvertLC(temp,iStatus.iOffset);
+		iSendString.Set(buf->Des());
+		if(!iStatus.iSkip)
+			{
+			iScriptIO->Write(iSendString);
+#ifdef __FLOG_ACTIVE
+			_LIT(KLogStringSending,"Script:\tSending %S");
+			TBuf16<KLogBufferSize> temp;
+			temp.Copy(iSendString.Left(Min(iSendString.Length(),KLogBufferSize)));
+			__FLOG_STATIC1(KNetDialLogFolder(),KNetDialLogFile(),TRefByValue<const TDesC>(KLogStringSending()),&temp);
+#endif
+			}
+		CleanupStack::PopAndDestroy();
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+//
+// CLabelSearch definitions
+//
+
+CLabelSearch* CLabelSearch::NewLC(const TDesC& aLabelName)
+/**
+2 phased constructor for CLabelSearch, first phase.
+
+@param aLabelName is label name.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CLabelSearch object.
+*/
+	{
+	CLabelSearch* label=new(ELeave) CLabelSearch();
+	CleanupStack::PushL(label);
+	label->ConstructL(aLabelName);
+	return label;
+	}
+
+CLabelSearch::CLabelSearch()
+	: iStatus(ENotFound), iPosition()
+/**
+Constructor for CLabelSearch, used in the first phase of construction.
+*/
+	{}
+
+void CLabelSearch::ConstructL(const TDesC& aLabelName)
+/**
+Instantiates member variables.
+*/
+	{
+	iChatString=NULL;
+	iLabelName=HBufC::NewL(aLabelName.Length());
+	(*iLabelName)=aLabelName;
+	}
+
+CLabelSearch::~CLabelSearch()
+/**
+Destructor.
+Don't delete iChatString - that is dealt with by CScriptIO.
+*/
+	{
+	delete iLabelName;
+	}
+
+void CLabelSearch::CreateCommChatStringL(const TDesC8& aDes,TBool aIsFolded)
+/**
+Creates CCommChatString object.
+*/
+	{
+	iChatString=CCommChatString::NewL(aDes,aIsFolded);
+	}
+
+//
+// CWaitCommand definitions
+//
+
+CWaitCommand* CWaitCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO,CScriptLabelMan* aLabelMan, CScriptExecutor* aScriptExec)
+/**
+2 phased constructor for CWaitCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+@param aLabelMan a pointer to label manager.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CWaitCommand object.
+*/
+	{
+	CWaitCommand* c=new(ELeave) CWaitCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv,aScriptIO,aLabelMan,aScriptExec);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CWaitCommand::CWaitCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO,CScriptLabelMan* aLabelMan, CScriptExecutor* aScriptExec)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iScriptIO(aScriptIO), iLabelMan(aLabelMan), iScriptExec(aScriptExec)
+/**
+Constructor for CWaitCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+@param aLabelMan a pointer to label manager.
+*/
+	{}
+
+CWaitCommand::~CWaitCommand()
+/**
+Destructor.
+Clears label array.
+*/
+	{
+	DeleteLabelArray();
+	}
+
+TBool CWaitCommand::ParseL()
+/**
+Parses WAIT command. Parse according to whether in skip mode or not.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KWaitCommand)==KErrNone)
+		{
+		iStatus.iOffset=end;
+		if (iStatus.iSkip)
+			ParseSkipL();
+		else
+			ParseActionL();
+		return ETrue;				// Consumed
+		}
+	return EFalse;					// Not Consumed
+	}
+
+void CWaitCommand::Cleanup()
+/**
+Cancels the read and clears out the labels
+*/
+	{
+	if (!iStatus.iSkip)
+		{
+		iScriptIO->Cancel();
+		DeleteLabelArray();
+		iLabelArray=NULL;
+		}
+	}
+
+void CWaitCommand::ParseActionL()
+/**
+Parses WAIT command when not in skip mode.  Parses wait period, strings and labels and 
+queue a read.
+*/
+	{
+	__FLOG_STMT(_LIT8(KLogStringExecutingWait,"Script:\tExecuting Wait");)
+	__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),KLogStringExecutingWait());
+	EatSpaces(iStatus.iOffset);
+	TReal waitPeriod=ParseRealL(iStatus.iOffset);
+	EatSpacesAndLinesAndCommentsL();
+	if (iStatus.iLine[iStatus.iOffset++]!=KOpenExprChar)
+		User::Leave(KErrNoOpenExpression);
+
+	iLabelArray=new(ELeave) CLabelSearchArray(KLabelArrayGranularity);
+	TBool completed=EFalse;
+	while(!completed)
+		{
+		EatSpacesAndLinesAndCommentsL();
+		if (iStatus.iLine[iStatus.iOffset]==KCloseExprChar)
+			{
+			completed=ETrue;
+			iStatus.iOffset++;
+			}
+		else
+			{
+			TPtrC temp=ParseCompoundExpressionL(iStatus.iOffset);
+			HBufC8* buf=ConvertLC(temp,iStatus.iOffset);
+			CLabelSearch* label=ParseLabelLC();
+			TPtrC8 waitString(buf->Des());	
+			label->CreateCommChatStringL(waitString,EFalse);
+			iLabelArray->AppendL(label);
+			// for logging
+			TBuf<KLogBufferSize> labelName;
+			labelName.Copy(label->LabelName().Left(Min(KLogBufferSize,label->LabelName().Length())));
+			//
+#ifdef __FLOG_ACTIVE
+			_LIT(KLogStringGog,"Script:\tIf %S is found, Goto %S");
+			TBuf16<KLogBufferSize> string;
+			string.Copy(waitString.Left(Min(waitString.Length(),KLogBufferSize)));
+			__FLOG_STATIC2(KNetDialLogFolder(),KNetDialLogFile(),TRefByValue<const TDesC>(KLogStringGog()),&string,&labelName);
+#endif
+			CleanupStack::Pop();			// label - will be deleted from array
+			CleanupStack::PopAndDestroy();	// buf - will have been copied into label array
+			}			
+		}
+	// Tell the script executor how long we are going to wait since it
+	// may need to force the server to resend the login prompt and will
+	// need to know how long to wait the second time around
+	iScriptExec->SetRetransmittedLoginTimeout(waitPeriod);
+	iScriptIO->Read(iLabelArray,waitPeriod);
+	}
+
+void CWaitCommand::ParseSkipL()
+/**
+Parses a WAIT command when in skip mode. Parses expressions and labels but do not queue read.
+*/
+	{
+	EatSpaces(iStatus.iOffset);
+	ParseRealL(iStatus.iOffset);					// ignore the actual value returned
+	EatSpacesAndLinesAndCommentsL();
+	if (iStatus.iLine[iStatus.iOffset++]!=KOpenExprChar)
+		User::Leave(KErrNoOpenExpression);
+
+	TBool completed=EFalse;
+	while (!completed)
+		{
+		EatSpacesAndLinesAndCommentsL();
+		if (iStatus.iLine[iStatus.iOffset]==KCloseExprChar)
+			{
+			completed=ETrue;
+			iStatus.iOffset++;
+			}
+		else
+			{
+			ParseCompoundExpressionL(iStatus.iOffset);			// ignore the return value in skip mode
+			ParseLabelLC();
+			CleanupStack::PopAndDestroy();				// ignore the label returned
+			}
+		}
+	}
+
+CLabelSearch* CWaitCommand::ParseLabelLC()
+/**
+Parses label.  Parses label name and looks for it in the label list.
+Returns results of search.
+*/
+	{
+	EatSpaces(iStatus.iOffset);
+	TInt start=iStatus.iOffset;
+	iStatus.iOffset=FindTokenEnd(start);
+	TPtrC var=iStatus.iLine.Mid(start,iStatus.iOffset-start);
+	CLabelSearch* labelSearch=CLabelSearch::NewLC(var);
+	TLinePosition pos;
+	if(iLabelMan->FindLabel(var,pos)==KErrNotFound)
+		{
+		pos.Reset();
+		labelSearch->Set(CLabelSearch::ENotFound,pos);
+		}
+	else
+		labelSearch->Set(CLabelSearch::EResolved,pos);
+	return labelSearch;
+	}
+
+TPtrC CWaitCommand::LabelFromIndexL(TInt aIndex)
+/**
+Gets label from array by index.
+*/
+	{
+	if ((aIndex<0) && (aIndex>iLabelArray->Count()))
+		User::Leave(KErrIllegalWaitLabelIndex);
+	return (*iLabelArray)[aIndex]->LabelName();
+	}
+
+void CWaitCommand::DeleteLabelArray()
+/**
+Deletes label array.
+*/
+	{
+	if (iLabelArray!=NULL)
+		{
+		TInt count=iLabelArray->Count();
+		for(TInt i=0; i<count; i++)
+			{
+			delete (*iLabelArray)[i];
+			}
+		iLabelArray->Delete(0,count);
+		delete iLabelArray;
+		}
+	}
+	
+//
+// CLoopCommand definitions
+//
+
+CLoopCommand* CLoopCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+/**
+2 phased constructor for CLoopCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CLoopCommand object.
+*/
+	{
+	CLoopCommand* c=new(ELeave) CLoopCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CLoopCommand::CLoopCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iLoop(EFalse)
+/**
+Constructor for CLoopCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+*/
+	{}
+
+CLoopCommand::~CLoopCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CLoopCommand::ParseL()
+/**
+Parses LOOP command. Checks how many times to loop and records position of beginning of loop.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KLoopCommand)==KErrNone)
+		{
+		if (iLoop)
+			User::Leave(KErrNestedLoop);
+		if (!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(KLogStringExecutingLoop,"Script:\tExecuting Loop");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),KLogStringExecutingLoop());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		iLoopCounter=ParseIntegerL(iStatus.iOffset);
+		if ((iLoopCounter<KMinLoopCounter) || (iLoopCounter>KMaxLoopCounter))
+			User::Leave(KErrLoopCounterOutOfRange);
+		EatSpacesAndLinesAndCommentsL();
+		if (iStatus.iLine[iStatus.iOffset++]!=KOpenExprChar)
+			User::Leave(KErrNoOpenExpression);
+		iLoop=ETrue;
+		iScriptReader->CurrentPos(iLoopPosition,iStatus.iOffset);
+		if (!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT(KLogStringLoopCounter,"Script:\tLoop Counter %d");)
+			__FLOG_STATIC1(KNetDialLogFolder(),KNetDialLogFile(),KLogStringLoopCounter(),iLoopCounter);
+			}
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+TBool CLoopCommand::CheckLoopL()
+/**
+Checks how many times loop has been executed and returns to beginning if necessary.
+*/
+	{
+	if (iLoop)
+		{
+		EatSpacesAndLinesAndCommentsL();
+		if(iStatus.iLine[iStatus.iOffset]==KCloseExprChar)
+			{
+			if((--iLoopCounter==0) || (iStatus.iSkip))
+				{
+				iLoop=EFalse;
+				iStatus.iOffset++;
+				}
+			else
+				{
+				iScriptReader->SetCurrentPos(iLoopPosition);
+				__FLOG_STMT(_LIT8(logString1,"Script:\tRepeat Loop");)
+				__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString1());
+				__FLOG_STMT(_LIT8(logString2,"Script:\tLoop Counter %d");)
+				__FLOG_STATIC1(KNetDialLogFolder(),KNetDialLogFile(),logString2(),iLoopCounter);
+				}
+			return ETrue;				// Consumed Something
+			}
+		}
+	return EFalse;						// Nothing doing...
+	}
+
+//
+// CGotoCommand definitions
+//
+
+CGotoCommand* CGotoCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptLabelMan* aLabelMan)
+/**
+2 phased constructor for CGotoCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aLabelMan a pointer to label manager.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CGotoCommand object.
+*/	
+	{
+	CGotoCommand* c=new(ELeave) CGotoCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv,aLabelMan);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CGotoCommand::CGotoCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptLabelMan* aLabelMan)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iLabelMan(aLabelMan)
+/**
+Constructor for CGotoCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aLabelMan a pointer to label manager.
+*/
+	{}
+
+CGotoCommand::~CGotoCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CGotoCommand::ParseL()
+/**
+Parses GOTO command. Parses label and goto label.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KGotoCommand)==KErrNone)
+		{
+		if(!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(logString,"Script:\tExecuting Goto");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		end=FindTokenEnd(iStatus.iOffset);
+		TPtrC var=iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset);
+	//	HBufC* labelName=HBufC::NewLC(var.Length());
+	//	(*labelName)=var;
+	//	GotoL(labelName->Des());
+	//	CleanupStack::PopAndDestroy();
+		Goto(var);
+		iStatus.iOffset=end;
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+void CGotoCommand::Goto(const TDesC& aLabelName)
+/**
+Finds label in those passed already, or skip lines until it is found.
+*/
+	{
+	TLinePosition pos;
+	if(!iStatus.iSkip)
+		{
+		if (iLabelMan->FindLabel(aLabelName,pos)==KErrNotFound)
+			{
+			iSearchName.Copy(aLabelName);
+			iStatus.iSkipModeToggleReq=ETrue;
+			__FLOG_STMT(_LIT(logString1,"Script:\tSearching for Label %S");)
+			__FLOG_STATIC1(KNetDialLogFolder(),KNetDialLogFile(),TRefByValue<const TDesC>(logString1()),&aLabelName);
+			__FLOG_STMT(_LIT8(logString2,"Script:\tEntering Skip Mode");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString2());
+			}
+		else
+			iScriptReader->SetCurrentPos(pos);
+		}
+	}
+
+TBool CGotoCommand::ParseLabelL()
+/**
+Parses label and adds it to label list. Compares label against one to be found.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt start=iStatus.iOffset;
+	TInt end=FindTokenEnd(start);
+	if ((iStatus.iLine.Length()>=(end+1)) && (iStatus.iLine[end]==KColonChar))
+		{
+		TLinePosition pos;
+		iScriptReader->CurrentPos(pos,end+1);
+		iLabelMan->AddLabelL(iStatus.iLine.Mid(start,end-start),pos);
+		iStatus.iOffset=++end;
+		TLinePosition dummyPos;
+		if (iStatus.iSkip && (iLabelMan->FindLabel(iSearchName,dummyPos)==KErrNone))
+			{
+			iStatus.iSkipModeToggleReq=ETrue;
+			__FLOG_STMT(_LIT8(logString,"Script:\tExiting Skip Mode");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString());
+			}
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+void CGotoCommand::ServiceSkipReqs()
+/**
+Toggles skip mode.
+*/
+	{
+	if(iStatus.iSkipModeToggleReq)
+		{
+		iStatus.iSkipModeToggleReq=EFalse;
+		iStatus.iSkip=!iStatus.iSkip;
+		}
+	}
+
+//
+// CDTRCommand definitions
+//
+
+CDTRCommand* CDTRCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO)
+/**
+2 phased constructor for CDTRCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CDTRCommand object.
+*/
+	{
+	CDTRCommand* c=new(ELeave) CDTRCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv,aScriptIO);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CDTRCommand::CDTRCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptIO* aScriptIO)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iScriptIO(aScriptIO)
+/**
+Constructor for CDTRCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptIO a pointer to serial comms I/O handler.
+*/
+	{}
+
+CDTRCommand::~CDTRCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CDTRCommand::ParseL()
+/**
+Parses DTR command. Drops or raises appropriately.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KDTRCommand)==KErrNone)
+		{
+		if(!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(logString1,"Script:\tExecuting DTR");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString1());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		end=FindTokenEnd(iStatus.iOffset);
+		if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KRaiseDTRCommand)==KErrNone)
+			{
+			if(!iStatus.iSkip)
+				{
+				__FLOG_STMT(_LIT8(logString2,"Script:\tRaising DTR");)
+				__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString2());
+				iScriptIO->RaiseDTR(NULL);
+				}	
+			}
+		else if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KDropDTRCommand)==KErrNone)
+			{
+			if(!iStatus.iSkip)
+				{
+				__FLOG_STMT(_LIT8(logString3,"Script:\tDropping DTR");)
+				__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString3());
+				iScriptIO->DropDTR(NULL);
+				}	
+			}
+		else
+			User::Leave(KErrNoDropOrRaise);
+		iStatus.iOffset=end;
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+//
+// CReadPCTCommand definitions
+//
+
+CReadPCTCommand* CReadPCTCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptExecutor* aScriptExec)
+/**
+2 phased constructor for CReadPCTCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptExec a pointer to script executioner.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CReadPCTCommand object.
+*/
+	{
+	CReadPCTCommand* c=new(ELeave) CReadPCTCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv,aScriptExec);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CReadPCTCommand::CReadPCTCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv,CScriptExecutor* aScriptExec)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv), iScriptExec(aScriptExec)
+/**
+Constructor for CDTRCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@param aScriptExec a pointer to script executioner.
+*/
+	{}
+
+CReadPCTCommand::~CReadPCTCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CReadPCTCommand::ParseL()
+/**
+Parses Read command.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KReadCommand)==KErrNone)
+		{
+		if (!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(logString,"Script:\tExecuting Read");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString());
+			iCharSet=ParseCharacterTypeL(iStatus.iOffset);
+			iScriptExec->ReadPct();
+			}
+		iStatus.iOffset=end;
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+TBool CReadPCTCommand::CheckReadL()
+/**
+Checks Read.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KReadCommand)==KErrNone)
+		return ETrue;
+	else
+		return EFalse;
+	}
+
+TPtrC CReadPCTCommand::CharSet()
+/**
+Returns used character set.
+*/
+	{
+	return iCharSet;
+	}
+
+//
+// CCharMapCommand definitions
+//
+
+CCharMapCommand* CCharMapCommand::NewL(TScriptStatus& aScriptStatus, CScriptReader* aScriptReader, CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+/**
+2 phased constructor for CCharMapCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CCharMapCommand object.
+*/
+	{
+	CCharMapCommand* c=new(ELeave) CCharMapCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CCharMapCommand::CCharMapCommand(TScriptStatus& aScriptStatus, CScriptReader* aScriptReader, CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv)
+/**
+Constructor for CCharMapCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+*/
+	{}
+
+CCharMapCommand::~CCharMapCommand()
+/**
+Destructor.
+*/
+	{}	
+
+TBool CCharMapCommand::ParseL()
+/**
+Parse.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KCharmapCommand)==KErrNone)
+		{
+		iStatus.iOffset=end;
+		if (!iStatus.iSkip)
+			{
+			iCharConv->SetDefaultCharSet(ParseCharacterTypeL(iStatus.iOffset));
+			}
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}
+
+//
+// CExitCommand definiton
+//
+
+CExitCommand* CExitCommand::NewL(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+/**
+2 phased constructor for CExitCommand, first phase.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+@exception Leaves if ConstructL() leaves, or not enough memory is available.
+@return a new CExitCommand object.
+*/
+	{
+	CExitCommand* c=new(ELeave) CExitCommand(aScriptStatus,aScriptReader,aVarMan,aCharConv);
+	CleanupStack::PushL(c);
+	c->ConstructL();
+	CleanupStack::Pop();
+	return c;
+	}
+
+CExitCommand::CExitCommand(TScriptStatus& aScriptStatus,CScriptReader* aScriptReader,CScriptVarMan* aVarMan,CScriptCharacterConverter* aCharConv)
+	: CScriptCommandBase(aScriptStatus,aScriptReader,aVarMan,aCharConv)
+/**
+Constructor for CExitCommand, used in the first phase of construction.
+
+@param aScriptStatus is script status.
+@param aScriptReader a pointer to script reader.
+@param aVarMan a pointer to variable manager.
+@param aCharConv a pointer to script character converter.
+*/
+	{}
+
+CExitCommand::~CExitCommand()
+/**
+Destructor.
+*/
+	{}
+
+TBool CExitCommand::ParseL()
+/**
+Parses EXIT command. Parses number or variable and leaves with the appropriate value.
+*/
+	{
+	EatSpacesAndLinesAndCommentsL();
+	TInt end=FindTokenEnd(iStatus.iOffset);
+	if (iStatus.iLine.Mid(iStatus.iOffset,end-iStatus.iOffset).CompareF(KExitCommand)==KErrNone)
+		{
+		if (!iStatus.iSkip)
+			{
+			__FLOG_STMT(_LIT8(logString1,"Script:\tExecuting Exit");)
+			__FLOG_STATIC(KNetDialLogFolder(),KNetDialLogFile(),logString1());
+			}
+		iStatus.iOffset=end;
+		EatSpaces(iStatus.iOffset);
+		TPtrC exitStatus;
+		TRAPD(ret,(exitStatus.Set(ParseCompoundExpressionL(iStatus.iOffset))));
+		if (!iStatus.iSkip)
+			{
+			if (ret==KErrNone)
+				{
+				TInt32 val;
+				TLex lex(exitStatus);
+				if(lex.Val(val)!=KErrNone)
+					User::Leave(KErrInvalidNumber);
+				if(val>0)
+					User::Leave(KErrNumberOutOfRange);
+				if(val==0)
+					val=(TInt32)KErrScriptCompleted;
+				User::Leave(val);
+				}
+			else if (ret==KErrNoExpression)
+				User::Leave(KErrScriptCompleted);
+			else
+				{
+				__FLOG_STMT(_LIT8(logString2,"Script:\tExit With Error %d");)
+				__FLOG_STATIC1(KNetDialLogFolder(),KNetDialLogFile(),TRefByValue<const TDesC8>(logString2()),ret);
+				User::Leave(ret);
+				}
+			}
+		return ETrue;		// Consumed
+		}
+	return EFalse;			// Not Consumed
+	}