diff -r 000000000000 -r 7f656887cf89 core/src/parser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/parser.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,904 @@ +// 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 +#include +#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* array = static_cast*>(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 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 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 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(aSelf); + self->iObserver->HandleParserComplete(*self, self->iCompletionError); + return KErrNone; + } + +TInt CParser::NextCallBack(TAny* aSelf) + { + CParser* self = static_cast(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(); + } + } +