Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// parser.cpp
//
// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <fshell/ioutils.h>
#include <fshell/ltkutils.h>
#include "parser.h"
#include "fshell.h"
#include "lexer.h"
#include "command_factory.h"
//
// Globals.
//
_LIT(KChildError, "?");
_LIT(KPipe, "|");
_LIT(KDoublePipe, "||");
_LIT(KRedirectStdinFromFile, "<");
_LIT(KRedirectStdoutToFile1, ">");
_LIT(KRedirectStdoutToFile2, "1>");
_LIT(KRedirectStdoutToFileAppend1, ">>");
_LIT(KRedirectStdoutToFileAppend2, "1>>");
_LIT(KRedirectStdoutToStderr, "1>&2");
_LIT(KRedirectStderrToFile, "2>");
_LIT(KRedirectStderrToFileAppend, "2>>");
_LIT(KRedirectStderrToStdout, "2>&1");
_LIT(KAmpersand, "&");
_LIT(KDoubleAmpersand, "&&");
_LIT(KAmpersandPipe, "&|");
_LIT(KNewLine1, "\r");
_LIT(KNewLine2, "\n");
_LIT(KNewLine3, "\r\n");
_LIT(KNewLine4, "\n\r");
_LIT(KSemicolon, ";");
_LIT(KDollar, "$");
void MParserObserver::AboutToExecuteLine(const TDesC&, const TDesC&)
{
}
void MParserObserver::LineReturned(TInt)
{
}
CParser* CParser::NewL(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver)
{
CParser* self = new(ELeave) CParser(aMode, aDes, aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
CParser::~CParser()
{
delete iForegroundPipeLine;
iBackgroundPipeLines.ResetAndDestroy();
delete iLexer1;
delete iLexer2;
delete iCompletionCallBack;
delete iNextPipeLineCallBack;
delete iExitCallBack;
if (iOwnsIoHandles)
{
iStdin.Close();
iStdout.Close();
iStderr.Close();
}
}
CParser::CParser(TUint aMode, const TDesC& aDes, RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MParserObserver* aObserver)
: iMode(aMode), iData(aDes), iIoSession(aIoSession), iStdin(aStdin), iStdout(aStdout), iStderr(aStderr), iEnv(aEnv), iFactory(aFactory), iObserver(aObserver), iCompletionError(aStderr, aEnv), iNextLineNumber(1)
{
}
void CParser::ConstructL()
{
if (iObserver)
{
iCompletionCallBack = new(ELeave) CAsyncCallBack(TCallBack(CompletionCallBack, this), CActive::EPriorityStandard);
}
iNextPipeLineCallBack = new(ELeave) CAsyncCallBack(TCallBack(NextCallBack, this), CActive::EPriorityStandard);
iLexer1 = CLexer::NewL(CLexer::EHandleSingleQuotes | CLexer::EHandleDoubleQuotes | CLexer::EHandleComments);
iLexer1->DefineTokenTypeL(TToken::EDoublePipe, KDoublePipe);
iLexer1->DefineTokenTypeL(TToken::EDoubleAmpersand, KDoubleAmpersand);
iLexer1->DefineTokenTypeL(TToken::EAmpersandPipe, KAmpersandPipe);
iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine1);
iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine2);
iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine3);
iLexer1->DefineTokenTypeL(TToken::ENewLine, KNewLine4);
iLexer1->DefineTokenTypeL(TToken::ESemicolon, KSemicolon);
iLexer1->Set(iData, iEnv.EscapeChar());
iLexer2 = CLexer::NewL(CLexer::EHandleSingleQuotes | CLexer::EHandleDoubleQuotes);
iLexer2->DefineTokenTypeL(TToken::EPipe, KPipe);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdinFromFile, KRedirectStdinFromFile);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdoutToFile, KRedirectStdoutToFile1);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdoutToFile, KRedirectStdoutToFile2);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdoutToFileAppend, KRedirectStdoutToFileAppend1);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdoutToFileAppend, KRedirectStdoutToFileAppend2);
iLexer2->DefineTokenTypeL(TToken::ERedirectStdoutToStderr, KRedirectStdoutToStderr);
iLexer2->DefineTokenTypeL(TToken::ERedirectStderrToFile, KRedirectStderrToFile);
iLexer2->DefineTokenTypeL(TToken::ERedirectStderrToFileAppend, KRedirectStderrToFileAppend);
iLexer2->DefineTokenTypeL(TToken::ERedirectStderrToStdout, KRedirectStderrToStdout);
iLexer2->DefineTokenTypeL(TToken::EAmpersand, KAmpersand);
if (iMode & EExportLineNumbers)
{
iEnv.SetL(KScriptLine, iNextLineNumber++);
}
if (iMode & EKeepGoing)
{
iEnv.SetL(KKeepGoing, 1);
}
}
void CParser::Start()
{
CreateNextPipeLine(NULL);
}
void CParser::Start(TBool& aIsForeground)
{
CreateNextPipeLine(&aIsForeground);
}
void CParser::Kill()
{
iAbort = ETrue;
if (iForegroundPipeLine)
{
iForegroundPipeLine->Kill();
}
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
iBackgroundPipeLines[i]->Kill();
}
}
TInt CParser::Suspend()
{
TInt ret = KErrNone;
if (iForegroundPipeLine)
{
TInt err = iForegroundPipeLine->Suspend();
if (err)
{
ret = err;
}
}
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
TInt err = iBackgroundPipeLines[i]->Suspend();
if (err && (ret == KErrNone))
{
ret = err;
}
}
return ret;
}
TInt CParser::Resume()
{
TInt ret = KErrNone;
if (iForegroundPipeLine)
{
TInt err = iForegroundPipeLine->Resume();
if (err)
{
ret = err;
}
}
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
TInt err = iBackgroundPipeLines[i]->Resume();
if (err && (ret == KErrNone))
{
ret = err;
}
}
return ret;
}
TInt CParser::BringToForeground()
{
if (iForegroundPipeLine)
{
return iForegroundPipeLine->BringToForeground();
}
else if (iBackgroundPipeLines.Count() == 1)
{
return iBackgroundPipeLines[0]->BringToForeground();
}
return KErrGeneral;
}
void CParser::SendToBackground()
{
if (iForegroundPipeLine)
{
iForegroundPipeLine->SendToBackground();
}
}
TInt CParser::Reattach(RIoEndPoint& aStdinEndPoint, RIoEndPoint& aStdoutEndPoint, RIoEndPoint& aStderrEndPoint)
{
RIoReadHandle stdin;
RIoWriteHandle stdout;
RIoWriteHandle stderr;
TInt err = stdin.Create(iIoSession);
if (err == KErrNone)
{
err = stdout.Create(iIoSession);
if (err == KErrNone)
{
err = stderr.Create(iIoSession);
if (err == KErrNone)
{
err = aStdinEndPoint.Attach(stdin, RIoEndPoint::EBackground);
if (err == KErrNone)
{
err = aStdoutEndPoint.Attach(stdout);
if (err == KErrNone)
{
err = aStderrEndPoint.Attach(stderr);
if (err == KErrNone)
{
if (iForegroundPipeLine)
{
err = iForegroundPipeLine->Reattach(aStdinEndPoint, aStdoutEndPoint, aStderrEndPoint);
}
if (err == KErrNone)
{
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
err = iBackgroundPipeLines[i]->Reattach(aStdinEndPoint, aStdoutEndPoint, aStderrEndPoint);
if (err)
{
break;
}
}
}
}
}
}
}
}
}
if (err == KErrNone)
{
iStdin = stdin;
iStdout = stdout;
iStderr = stderr;
iOwnsIoHandles = ETrue;
}
else
{
stdin.Close();
stdout.Close();
stderr.Close();
}
return err;
}
TBool CParser::IsDisownable() const
{
if (iForegroundPipeLine && !iForegroundPipeLine->IsDisownable())
{
return EFalse;
}
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
if (!(iBackgroundPipeLines[i]->IsDisownable()))
{
return EFalse;
}
}
return ETrue;
}
void CParser::Disown()
{
if (iForegroundPipeLine)
{
iForegroundPipeLine->Disown();
}
const TInt numBackground = iBackgroundPipeLines.Count();
for (TInt i = 0; i < numBackground; ++i)
{
iBackgroundPipeLines[i]->Disown();
}
}
TBool HandleRedirectionL(TToken::TType aTokenType, const TDesC& aCwd, CLexer& aLexer, RPipeSection& aPipeSection)
{
RPipeSection::TRedirection* redirection;
switch (aTokenType)
{
case TToken::ERedirectStdinFromFile:
{
redirection = &aPipeSection.iStdinRedirection;
break;
}
case TToken::ERedirectStdoutToFile:
case TToken::ERedirectStdoutToFileAppend:
case TToken::ERedirectStdoutToStderr:
{
redirection = &aPipeSection.iStdoutRedirection;
break;
}
case TToken::ERedirectStderrToFile:
case TToken::ERedirectStderrToFileAppend:
case TToken::ERedirectStderrToStdout:
{
redirection = &aPipeSection.iStderrRedirection;
break;
}
default:
{
redirection = NULL;
ASSERT(EFalse);
}
}
if (aTokenType == TToken::ERedirectStderrToStdout)
{
redirection->iType = RPipeSection::TRedirection::EHandle;
redirection->iHandle = RPipeSection::TRedirection::EStdout;
}
else if (aTokenType == TToken::ERedirectStdoutToStderr)
{
redirection->iType = RPipeSection::TRedirection::EHandle;
redirection->iHandle = RPipeSection::TRedirection::EStderr;
}
else
{
if (aLexer.More())
{
redirection->iType = ((aTokenType == TToken::ERedirectStdoutToFileAppend) || (aTokenType == TToken::ERedirectStderrToFileAppend)) ? RPipeSection::TRedirection::EFileAppend : RPipeSection::TRedirection::EFile;
TToken fileName(aLexer.NextToken());
redirection->SetFileNameL(aCwd, fileName.String());
}
else
{
return EFalse;
}
}
return ETrue;
}
void CleanupPipeSectionsArray(TAny* aArray)
{
RArray<RPipeSection>* array = static_cast<RArray<RPipeSection>*>(aArray);
const TInt numSections = array->Count();
for (TInt i = 0; i < numSections; ++i)
{
(*array)[i].Close();
}
array->Close();
}
void CParser::CreateNextPipeLine(TBool* aIsForeground)
{
TRAPD(err, CreateNextPipeLineL(aIsForeground));
if (err && iObserver)
{
iCompletionError.Set(err, TError::EFailedToCreatePipeLine);
iCompletionCallBack->CallBack();
}
}
void CParser::CreateNextPipeLineL(TBool* aIsForeground)
{
// Parsing is now carried out in three main steps:
//
// 1) Use iLexer1 to find the next "pipe-line's worth" of data (carried out by FindNextPipeLine).
// 2) Expand environment variables in this data into a new HBufC ('expandedPipeLine' returned by ExpandVariablesLC).
// 3) Use iLexer2 to parse the data in this expanded descriptor.
if (aIsForeground)
{
*aIsForeground = ETrue;
}
TPtrC pipeLineData;
TBool reachedLineEnd(EFalse);
FindNextPipeLineL(pipeLineData, iCondition, reachedLineEnd);
HBufC* expandedPipeLine = ExpandVariablesLC(pipeLineData);
iLexer2->Set(*expandedPipeLine, iEnv.EscapeChar());
const TDesC& cwd = iEnv.Pwd();
RArray<RPipeSection> pipeSections;
CleanupStack::PushL(TCleanupItem(CleanupPipeSectionsArray, &pipeSections));
RPipeSection pipeSection;
CleanupClosePushL(pipeSection);
TInt offset = iLexer2->CurrentOffset();
TBool background(EFalse);
while (iLexer2->More())
{
TToken token(iLexer2->NextToken());
switch (token.Type())
{
case TToken::EPipe:
{
pipeSection.iFullName.Set(iData.Ptr() + offset, iLexer2->CurrentOffset() - offset - token.String().Length());
offset = iLexer2->CurrentOffset();
User::LeaveIfError(pipeSections.Append(pipeSection));
new(&pipeSection) RPipeSection;
break;
}
case TToken::EAmpersand:
{
background = ETrue;
break;
}
case TToken::ERedirectStdinFromFile:
case TToken::ERedirectStdoutToFile:
case TToken::ERedirectStdoutToFileAppend:
case TToken::ERedirectStdoutToStderr:
case TToken::ERedirectStderrToFile:
case TToken::ERedirectStderrToFileAppend:
case TToken::ERedirectStderrToStdout:
{
if (HandleRedirectionL(token.Type(), cwd, *iLexer2, pipeSection))
{
break;
}
// Deliberate fall through - if it wasn't possible to handle the redirection, treat token as a string.
}
case TToken::EString:
default:
{
if (token.String().Length() > 0)
{
if (pipeSection.iCommandName.Length() == 0)
{
pipeSection.iCommandName.Set(token.String());
}
else
{
User::LeaveIfError(pipeSection.iCommandArguments.Append(TPtrC(token.String())));
}
}
break;
}
}
}
if (pipeSection.iCommandName.Length() > 0)
{
_LIT(KExit, "exit");
if ((pipeSections.Count() == 0) && (pipeSection.iCommandName.CompareF(KExit) == 0) && (pipeSection.iCommandArguments.Count() == 0))
{
// Special case the handling of 'exit'. This allows the concept of 'local commands' (i.e. commands that run in either fshell's main
// thread or in the thread belonging to a 'source' or 'debug' command) to be dropped. That's a good thing, because local commands
// can't synchronously interact with iosrv without risk of deadlock when two or more thread commands are run in a pipe-line.
CleanupStack::PopAndDestroy(2, &pipeSections);
if (CActiveScheduler::Current()->StackDepth() > 0)
{
CActiveScheduler::Stop();
}
else
{
// The active scheduler hasn't been started yet. Probably because someone is doing something crazy like 'fshell -e exit'.
iExitCallBack = new(ELeave) CAsyncCallBack(TCallBack(ExitCallBack, this), CActive::EPriorityStandard);
iExitCallBack->Call();
}
}
else
{
pipeSection.iFullName.Set(iData.Ptr() + offset, iLexer2->CurrentOffset() - offset);
User::LeaveIfError(pipeSections.Append(pipeSection));
CleanupStack::Pop(&pipeSection);
if ((iMode & EDebug) && iObserver)
{
iObserver->AboutToExecuteLine(pipeLineData, *expandedPipeLine);
}
if (background)
{
CPipeLine* pipeLine = CPipeLine::NewLC(iIoSession, iStdin, iStdout, iStderr, iEnv, iFactory, pipeSections, background, this, iCompletionError);
User::LeaveIfError(iBackgroundPipeLines.Append(pipeLine));
CleanupStack::Pop(pipeLine);
}
else
{
ASSERT(iForegroundPipeLine == NULL);
iForegroundPipeLine = CPipeLine::NewL(iIoSession, iStdin, iStdout, iStderr, iEnv, iFactory, pipeSections, background, this, iCompletionError);
}
CleanupStack::PopAndDestroy(&pipeSections);
if (aIsForeground && !iLexer1->More())
{
*aIsForeground = !background;
}
if (background && iLexer1->More())
{
iNextPipeLineCallBack->Call();
}
}
}
else
{
if (iObserver && (iForegroundPipeLine == NULL) && (iBackgroundPipeLines.Count() == 0))
{
iCompletionCallBack->CallBack();
}
CleanupStack::PopAndDestroy(2, &pipeSections);
}
CleanupStack::PopAndDestroy(expandedPipeLine);
if (reachedLineEnd && (iMode & EExportLineNumbers))
{
iEnv.SetL(KScriptLine, iNextLineNumber++);
}
}
void CParser::FindNextPipeLineL(TPtrC& aData, TCondition& aCondition, TBool& aReachedLineEnd)
{
aReachedLineEnd = EFalse;
aCondition = ENone;
TInt startOffset = iLexer1->CurrentOffset();
TInt endOffset = -1;
TBool foundSomething(EFalse);
while (iLexer1->More())
{
TBool finished(EFalse);
TToken token(iLexer1->NextToken());
switch (token.Type())
{
case TToken::EString:
{
foundSomething = ETrue;
endOffset = iLexer1->CurrentOffset();
break;
}
case TToken::EDoublePipe:
{
finished = ETrue;
aCondition = EOr;
break;
}
case TToken::EDoubleAmpersand:
{
finished = ETrue;
aCondition = EAnd;
break;
}
case TToken::EAmpersandPipe:
{
finished = ETrue;
aCondition = EAndOr;
break;
}
case TToken::ENull:
case TToken::ENewLine:
{
if (foundSomething)
{
// Leave it to CreateNextPipeLineL to increment SCRIPT_LINE when it's finished building the pipe-line.
aReachedLineEnd = ETrue;
}
else
{
// Reached the end of a comment line - increment SCRIPT_LINE.
if (iMode & EExportLineNumbers)
{
iEnv.SetL(KScriptLine, iNextLineNumber++);
}
}
// Deliberate fall through.
}
case TToken::ESemicolon:
{
if (foundSomething)
{
finished = ETrue;
}
else
{
// Nothing on this line - adjust 'startOffset' to pretend it doesn't exist.
startOffset = iLexer1->CurrentOffset();
}
break;
}
default:
{
ASSERT(EFalse);
break;
}
}
if (finished)
{
break;
}
}
if (foundSomething)
{
aData.Set(iData.Ptr() + startOffset, endOffset - startOffset);
}
else
{
aData.Set(KNullDesC);
}
}
HBufC* ExpandVariablesLC(const TDesC& aData, CLexer& aLexer, IoUtils::CEnvironment& aEnv, TBool aEscape)
{
TChar escapeChar = aEnv.EscapeChar();
RArray<TInt> charsToEscape;
CleanupClosePushL(charsToEscape);
HBufC* buf = aData.AllocLC();
// Repeatedly check the data for environment variable tokens. This is done in a loop
// because there could be variables within variables and we want to expand them all.
aLexer.Set(*buf, escapeChar);
FOREVER
{
TToken token(aLexer.NextToken());
if (token.Type() == TToken::ENull)
{
break;
}
else if (token.Type() == TToken::EVariable)
{
const TDesC& val = aEnv.GetAsDesL(token.String().Mid(1));
TPtr bufPtr(buf->Des());
const TInt freeSpace = bufPtr.MaxLength() - bufPtr.Length();
TInt requiredSpace = val.Length() - token.String().Length();
if (aEscape)
{
charsToEscape.Reset();
TLex lex(val);
while (!lex.Eos())
{
TChar c = lex.Get();
if ((c == aEnv.EscapeChar()) || (c == '\"'))
{
charsToEscape.AppendL(token.Position() + lex.Offset() - 1);
++requiredSpace;
}
}
}
if (requiredSpace > freeSpace)
{
HBufC* oldBuf = buf;
buf = buf->ReAllocL(bufPtr.MaxLength() + requiredSpace - freeSpace);
CleanupStack::Pop(oldBuf);
CleanupStack::PushL(buf);
bufPtr.Set(buf->Des());
}
bufPtr.Replace(token.Position(), token.String().Length(), val);
if (aEscape)
{
TPtrC escape((TUint16*)&escapeChar, 1);
while (charsToEscape.Count() > 0)
{
bufPtr.Insert(charsToEscape[charsToEscape.Count() - 1], escape);
charsToEscape.Remove(charsToEscape.Count() - 1);
}
}
aLexer.Set(*buf, escapeChar);
}
}
CleanupStack::Pop(buf);
CleanupStack::PopAndDestroy(&charsToEscape);
CleanupStack::PushL(buf);
return buf;
}
HBufC* CParser::ExpandVariablesLC(const TDesC& aData)
{
CLexer* lexer1 = CLexer::NewLC(CLexer::EHandleSingleQuotes | CLexer::EHandleDoubleQuotes | CLexer::EHandleComments);
CLexer* lexer2 = CLexer::NewLC(0);
// Populate 'lexer2' with a token definition for each environment variable (preceded with '$').
RPointerArray<HBufC> keys;
LtkUtils::CleanupResetAndDestroyPushL(keys);
iEnv.GetKeysL(keys);
const TInt numVars = keys.Count();
for (TInt i = 0; i < numVars; ++i)
{
keys[i] = keys[i]->ReAllocL(keys[i]->Length() + KDollar().Length());
keys[i]->Des().Insert(0, KDollar);
lexer2->DefineTokenTypeL(TToken::EVariable, *keys[i]);
}
HBufC* buf = aData.AllocLC();
lexer1->Set(*buf, iEnv.EscapeChar());
FOREVER
{
TToken token(lexer1->NextToken());
if (token.Type() == TToken::ENull)
{
break;
}
else if (token.Type() == TToken::EString)
{
if (token.String()[0] != '\'')
{
HBufC* expandedString = ::ExpandVariablesLC(token.String(), *lexer2, iEnv, token.String()[0] == '\"');
if (*expandedString != token.String())
{
TPtr bufPtr(buf->Des());
const TInt freeSpace = bufPtr.MaxLength() - bufPtr.Length();
const TInt requiredSpace = expandedString->Length() - token.String().Length();
if (requiredSpace > freeSpace)
{
HBufC* oldBuf = buf;
buf = buf->ReAllocL(bufPtr.MaxLength() + requiredSpace - freeSpace);
CleanupStack::Pop(expandedString);
CleanupStack::Pop(oldBuf);
CleanupStack::PushL(buf);
CleanupStack::PushL(expandedString);
bufPtr.Set(buf->Des());
}
bufPtr.Replace(token.Position(), token.String().Length(), *expandedString);
lexer1->Set(*buf, iEnv.EscapeChar());
}
CleanupStack::PopAndDestroy(expandedString);
}
}
}
CleanupStack::Pop(buf);
CleanupStack::PopAndDestroy(3, lexer1);
CleanupStack::PushL(buf);
return buf;
}
TInt CParser::SkipLineRemainder()
{
while (iLexer1->More())
{
TToken token(iLexer1->NextToken());
if (token.Type() == TToken::ENewLine)
{
if (iMode & EExportLineNumbers)
{
// can we do something better with errors here?
TRAPD(err, iEnv.SetL(KScriptLine, iNextLineNumber++));
if (err!=KErrNone)
{
iCompletionError.Set(err, TError::EFailedToSetScriptLineVar);
return err;
}
}
break;
}
}
return KErrNone;
}
void CParser::SkipToEnd()
{
while (iLexer1->More())
{
iLexer1->NextToken();
}
}
TInt CParser::CompletionCallBack(TAny* aSelf)
{
CParser* self = static_cast<CParser*>(aSelf);
self->iObserver->HandleParserComplete(*self, self->iCompletionError);
return KErrNone;
}
TInt CParser::NextCallBack(TAny* aSelf)
{
CParser* self = static_cast<CParser*>(aSelf);
self->CreateNextPipeLine(NULL);
return KErrNone;
}
TInt CParser::ExitCallBack(TAny*)
{
CActiveScheduler::Stop();
return KErrNone;
}
void CParser::HandlePipeLineComplete(CPipeLine& aPipeLine, const TError& aError)
{
TRAPD(err, iEnv.SetL(KChildError, aError.Error()));
if (err)
{
iCompletionError.Set(err, TError::EFailedToSetChildErrorVar);
iCompletionCallBack->CallBack();
return;
}
if ((iMode & EDebug) && iObserver)
{
iObserver->LineReturned(aError.Error());
}
if (iForegroundPipeLine == &aPipeLine)
{
switch (iCondition)
{
case ENone:
{
if ((aError.Error() != KErrNone) && !(iMode & EKeepGoing))
{
// Bail out of script if an error is found that isn't "handled" by an "&&" or and "||".
SkipToEnd();
iCompletionError.Set(aError);
}
break;
}
case EAnd:
{
if (iAbort)
{
SkipToEnd();
}
else if (aError.Error() != KErrNone)
{
TInt err = SkipLineRemainder();
if (err!=KErrNone) SkipToEnd();
}
break;
}
case EOr:
{
if (iAbort)
{
SkipToEnd();
}
else if (aError.Error() == KErrNone)
{
TInt err = SkipLineRemainder();
if (err!=KErrNone) SkipToEnd();
}
break;
}
case EAndOr:
{
if (iAbort)
{
SkipToEnd();
}
break;
}
default:
{
ASSERT(EFalse);
}
}
delete iForegroundPipeLine;
iForegroundPipeLine = NULL;
if (iLexer1->More())
{
iNextPipeLineCallBack->Call();
}
}
else
{
TInt pos = iBackgroundPipeLines.Find(&aPipeLine);
ASSERT(pos >= 0);
iBackgroundPipeLines.Remove(pos);
if (aError.Error() != KErrNone)
{
iCompletionError.Set(aError);
}
delete &aPipeLine;
}
if (iObserver && !iLexer1->More() && (iForegroundPipeLine == NULL) && (iBackgroundPipeLines.Count() == 0))
{
iCompletionCallBack->CallBack();
}
}