diff -r 000000000000 -r 2e3d3ce01487 appfw/apparchitecture/apparc/APACMDLN.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/appfw/apparchitecture/apparc/APACMDLN.CPP Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,896 @@ +// Copyright (c) 1997-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: +// apacmdln.cpp +// + +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#if !defined(__APA_INTERNAL_H__) +#include "apainternal.h" +#endif +#endif //SYMBIAN_ENABLE_SPLIT_HEADERS + +#include +#include "APASTD.H" // Panics etc. +#include + +#include + +// comand line tokens +const TUint KApaCommandLetterOpen='O'; +const TUint KApaCommandLetterCreate='C'; +const TUint KApaCommandLetterRun='R'; +const TUint KApaCommandLetterBackground='B'; +const TUint KApaCommandLetterViewActivate='V'; +const TUint KApaCommandLetterRunWithoutViews='W'; +const TUint KApaCommandLetterBackgroundAndWithoutViews='A'; + +_LIT(KLitTokenServerDifferentiator, "-srvDfr="); +_LIT(KLitTokenDefaultScreenNumber, "-dsc="); +_LIT(KLitTokenParentWindowGroupID, "-prntwgid="); +_LIT(KLitTokenDebugMemFail, "-debugMemFail:"); +_LIT(KLitTokenAppStartupInstrumentationEventIdBase, "-appStartupInstrEvIdBase="); +_LIT(KLitTokenOpaqueData, "-opaque="); + +enum TProcessEnvironmentSots + { + EEnvironmentSlotUnused = 0, + EEnvironmentSlotMain = 1, + EEnvironmentSlotFsSession = 2, + EEnvironmentSlotFile = 3, + EFirstEnvironmentSlotForPublicUse = 8, + ENumberOfEnvironmentSlotsForPublicUse = 4 + }; + +enum TIpcMessageSlots + { + EIpcSlotMain = 0, + EIpcSlotFsSession = 1, + EIpcSlotFile = 2 + }; + + +// CApaCommandLine + +/** Private c'tor - initialize using NewLC() +@internalTechnology */ +CApaCommandLine::CApaCommandLine() : + iCommand(EApaCommandRun), iServerDifferentiator(0), iDefaultScreenNumber(KErrNotFound), + iParentWindowGroupID(0), iDebugMemFail(0), iAppStartupInstrumentationEventIdBase(0), + iFile(), iParentProcessId(KNullProcessId) + { + } + +/** Destructor. +Frees resources owned by the object prior to deletion. */ +EXPORT_C CApaCommandLine::~CApaCommandLine() + { + iDocumentName.Close(); + iExecutableName.Close(); + iOpaqueData.Close(); + iTailEnd.Close(); + iFile.Close(); + } + +/** Creates an empty command line object. +@return A pointer to the new command line object. */ +EXPORT_C CApaCommandLine* CApaCommandLine::NewL() + { + CApaCommandLine* self = CApaCommandLine::NewLC(); + CleanupStack::Pop(); + return self; + } + +/** Creates an empty command line object, and puts a pointer to it onto the cleanup stack. +@return A pointer to the new command line object. */ +EXPORT_C CApaCommandLine* CApaCommandLine::NewLC() + { + CApaCommandLine* self = new(ELeave) CApaCommandLine; + CleanupStack::PushL(self); + return self; + } + +EXPORT_C void CApaCommandLine::SetDocumentNameL(const TDesC& aDocName) +/** Sets the document name from the specified descriptor. + +If the document name has embedded spaces, then it must be enclosed within +quotation marks. + +@param aDocName A descriptor containing the document name. */ + { + RBuf documentName; + documentName.CreateL(aDocName); + + iDocumentName.Close(); // free any existing memory + iDocumentName.Assign(documentName); + } + +/** Gets the document name from the launch information. +@return A pointer descriptor representing the document name. The document +name is returned without any enclosing quotation marks. If the launch information +contains no document name, then the pointer descriptor has zero length. */ +EXPORT_C TPtrC CApaCommandLine::DocumentName() const + { + return iDocumentName; + } + +/** Sets the executable name from the specified descriptor. +@param aExecutableName A descriptor containing the executable name. */ +EXPORT_C void CApaCommandLine::SetExecutableNameL(const TDesC& aExecutableName) + { + RBuf executableName; + executableName.CreateL(aExecutableName); + + iExecutableName.Close(); // free any existing memory + iExecutableName.Assign(executableName); + } + +/** Gets the executable name from the launch information. +@return A pointer descriptor representing the executable name. */ +EXPORT_C TPtrC CApaCommandLine::ExecutableName() const + { + return iExecutableName; + } + +/** Sets the opaque-data from the specified 8-bit descriptor. + +This is called internally and populated from the data in the application's registration resource file, +i.e. from the resource indicated by the opaque_data field of the APP_REGISTRATION_INFO resource (if the +opaque_data field was non-zero). + +@param aOpaqueData An 8-bit descriptor containing the opaque-data. +*/ +EXPORT_C void CApaCommandLine::SetOpaqueDataL(const TDesC8& aOpaqueData) + { + RBuf8 opaqueData; + opaqueData.CreateL(aOpaqueData); + + iOpaqueData.Close(); // free any existing memory + iOpaqueData.Assign(opaqueData); + } + +/** Gets the opaque-data from the launch information. + +See the description of SetOpaqueDataL. By default, this attribute is an empty descriptor. + +@see SetOpaqueDataL +@return An 8-bit pointer descriptor representing the opaque-data. +*/ +EXPORT_C TPtrC8 CApaCommandLine::OpaqueData() const + { + return iOpaqueData; + } + +/** Sets the command code. + +The command code is used to indicate how an application is to be launched. + +@see TApaCommand +@param aCommand The command code. */ +EXPORT_C void CApaCommandLine::SetCommandL(TApaCommand aCommand) + { + iCommand = aCommand; + } + +/** Gets the command code from the launch information. + +See the description of SetCommandL. + +@see SetCommandL +@see TApaCommand +@return The command code. */ +EXPORT_C TApaCommand CApaCommandLine::Command() const + { + return iCommand; + } + +/** Sets the trailing data. + +The UI Framework provides a specific set of pre-defined command line +options. Additional user defined or pre-defined command line options, +may be passed to an application by setting the TailEnd. + +@param aTailEnd An 8 bit descriptor containing the trailing data. +@publishedAll */ +EXPORT_C void CApaCommandLine::SetTailEndL(const TDesC8& aTailEnd) + { + RBuf8 tailEnd; + tailEnd.CreateL(aTailEnd); + + iTailEnd.Close(); // free any existing memory + iTailEnd.Assign(tailEnd); + } + +/** Gets the trailing data from the launch information. + +See the description of SetTailEndL. + +@see SetTailEndL +@return A pointer descriptor representing the trailing data. If the launch +information contains no trailing data, then the pointer descriptor has zero +length. +@publishedAll */ +EXPORT_C TPtrC8 CApaCommandLine::TailEnd() const + { + return iTailEnd; + } + +/** Sets the file to be passed into the application (by handle). +This will then be retrieved by that application-process calling GetFileByHandleL(). + +@publishedPartner +@released +@param aFile The file object to be passed into the application. No transfer of this +object's ownership takes place in this function. */ +EXPORT_C void CApaCommandLine::SetFileByHandleL(const RFile& aFile) + { + __ASSERT_ALWAYS(aFile.SubSessionHandle() != KNullHandle, Panic(EPanicInvalidHandle)); + __ASSERT_ALWAYS(iFile.SubSessionHandle() == KNullHandle, Panic(EPanicHandleAlreadySet)); + + User::LeaveIfError(iFile.Duplicate(aFile)); + } + +/** Opens (by handle) the file that was passed into SetFileByHandleL by the process launching the local application. + +On entering this function, aFile must be non-open. It is recommended that aFile is +pushed onto the cleanup-stack (via CleanupClosePushL()) before this function is called. + +@publishedPartner +@released +@param aFile The file object to be set up from the handle passed into the application. The +caller has the responsibility to Close() this object, even if this function leaves. */ +EXPORT_C void CApaCommandLine::GetFileByHandleL(RFile& aFile) const + { + __ASSERT_ALWAYS(aFile.SubSessionHandle()==KNullHandle, Panic(EPanicHandleAlreadySet)); + + if (iFile.SubSessionHandle() != KNullHandle) + User::LeaveIfError(aFile.Duplicate(iFile)); + } + +/** Assigns a command line to a process (EKA2 only). + +This replaces the EKA1 method which involved retrieving the full command line (using +CApaCommandLine::FullCommandLine()) and passing it to the process (or thread on the +emulator). + +This function is used as follows (the order of the first 2 steps is irrelevant):- +- create the process and load the executable (RProcess::Create()), +- create the command line object (CApaCommandLine::NewLC()), and set it up using +the various setter functions, for instance SetDocumentNameL(), +- call SetProcessEnvironmentL() to assign the command line to the process, +- call Resume() on the process. + +Note that this sequence of steps bypasses the application architecture, and is +not recommended. RApaLsSession::StartApp() is the recommended way to +launch an application with a command line. + +@param aProcess The process to which the command line is assigned. +@leave KErrNotSupported This indicates that the function was called on EKA1. +@see RApaLsSession::StartApp() +*/ +EXPORT_C void CApaCommandLine::SetProcessEnvironmentL(RProcess& aProcess) const + { + HBufC8* const streamableAttributes = StreamableAttributesLC(); + User::LeaveIfError(aProcess.SetParameter(EEnvironmentSlotMain, *streamableAttributes)); + CleanupStack::PopAndDestroy(streamableAttributes); + + if (iFile.SubSessionHandle() != KNullHandle) + User::LeaveIfError(iFile.TransferToProcess(aProcess, EEnvironmentSlotFsSession, EEnvironmentSlotFile)); + } + +/** +@internalTechnology +*/ +EXPORT_C void CApaCommandLine::GetIpcArgsLC(TIpcArgs& aIpcArgs) const + { + aIpcArgs.Set(EIpcSlotMain, StreamableAttributesLC()); + if (iFile.SubSessionHandle() != KNullHandle) + User::LeaveIfError(iFile.TransferToServer(aIpcArgs, EIpcSlotFsSession, EIpcSlotFile)); + } + +/** +@internalTechnology +*/ +HBufC8* CApaCommandLine::StreamableAttributesLC() const + { + CBufFlat* const buffer = CBufFlat::NewL(128); + CleanupStack::PushL(buffer); + + RBufWriteStream writeStream; + writeStream.Truncate(*buffer); + ExternalizeL(writeStream); + writeStream.CommitL(); + HBufC8* const bufferAsDescriptor = buffer->Ptr(0).AllocL(); + + CleanupStack::PopAndDestroy(buffer); + + CleanupStack::PushL(bufferAsDescriptor); + return bufferAsDescriptor; + } + +/** Acts as a second constructor and completes a commandline object from +the aMessage object. +@internalTechnology */ +EXPORT_C void CApaCommandLine::ConstructCmdLineFromMessageL(const RMessage2& aMessage) + { + // Create a buffer of the right size and get the data from the RMessage2 + RBuf8 buffer; + buffer.CleanupClosePushL(); + buffer.CreateL(aMessage.GetDesLengthL(EIpcSlotMain)); + aMessage.ReadL(EIpcSlotMain, buffer); + + // Create a stream and use it to read the data from the buffer + RDesReadStream stream; + CleanupClosePushL(stream); + stream.Open(buffer); + InternalizeL(stream); + CleanupStack::PopAndDestroy(); // stream + + CleanupStack::PopAndDestroy(); // buffer + iFile.AdoptFromClient(aMessage, EIpcSlotFsSession, EIpcSlotFile); // ignore the returned error - assume it means that no file has been passed across + } + +/** Constructs a command line object. + +If command line information is provided in the environment-slots it creates command line object from +process environment-slots, else creates it from the information returned by User::CommandLine(). + +It can be called from a context where there is no CTrapCleanup. + +Calling this function more than once in a process is not supported and will result in an empty command +line being returned. If an application wants to inspect any part of its command line, it +should override CEikAppUi::ProcessCommandParametersL(CApaCommandLine& aCommandLine) and call the base +class implementation if required. + +@see CEikAppUi::ProcessCommandParametersL(CApaCommandLine& aCommandLine). +@param aCommandLine On return, a pointer to a newly constructed command line object. +@return KErrNone, if successful; otherwise one of the other system-wide error codes. +@internalTechnology */ +EXPORT_C TInt CApaCommandLine::GetCommandLineFromProcessEnvironment(CApaCommandLine*& aCommandLine) + { // static + aCommandLine = NULL; + CApaCommandLine* const commandLine = new CApaCommandLine; + if(!commandLine) + return KErrNoMemory; + + CTrapCleanup* trapCleanup = NULL; + if (!User::TrapHandler()) + { + trapCleanup = CTrapCleanup::New(); // we're being called from an environment without a cleanup-stack, so temporarily create one here + if(!trapCleanup) + { + delete commandLine; + return KErrNoMemory; + } + } + + TRAPD(error, commandLine->DoGetCommandLineFromProcessEnvironmentL()); + aCommandLine = commandLine; + delete trapCleanup; + return error; + } + +void CApaCommandLine::DoGetCommandLineFromProcessEnvironmentL() + { + const TInt bufLen = User::ParameterLength(EEnvironmentSlotMain); + if (bufLen == KErrNotFound) + { + RBuf commandLineString; + commandLineString.CleanupClosePushL(); + commandLineString.CreateL(User::CommandLineLength()); + User::CommandLine(commandLineString); + User::LeaveIfError(DoGetParametersFromCommandLineString(commandLineString)); + CleanupStack::PopAndDestroy(); // commandLineString + } + else + { + User::LeaveIfError(bufLen); // in case bufLen is some error other than KErrNotFound + RBuf8 buffer; + buffer.CleanupClosePushL(); + buffer.CreateL(bufLen); + + User::LeaveIfError(User::GetDesParameter(EEnvironmentSlotMain, buffer)); + RDesReadStream stream; + CleanupClosePushL(stream); + stream.Open(buffer); + InternalizeL(stream); + CleanupStack::PopAndDestroy(); // stream + + CleanupStack::PopAndDestroy(); // buffer + } + + iFile.AdoptFromCreator(EEnvironmentSlotFsSession, EEnvironmentSlotFile); // ignore the returned error - assume it means that no file has been passed across + } + +/** Sets the Parent Process ID for the Child Process launched with this command line. + +This establishes a Parent-Child relationship which ensures that the child process is +terminated when the parent terminates. + +@param aProcessId The Process ID. */ +EXPORT_C void CApaCommandLine::SetParentProcessId(TProcessId aProcessId) + { + iParentProcessId = aProcessId; + } + +/** Gets the Parent Process ID of the Child Process launched with this command line. + +See the description of SetParentProcessId. + +@see SetParentProcessId +@return The Parent Process ID. */ +EXPORT_C TProcessId CApaCommandLine::ParentProcessId() const + { + return iParentProcessId; + } + +void CApaCommandLine::ExternalizeL(RWriteStream& aStream) const + { + // iFile is not supported via RReadStream/RWriteStream + aStream << DocumentName(); + aStream << ExecutableName(); + aStream << OpaqueData(); + aStream << TailEnd(); + aStream.WriteInt32L(iCommand); + aStream.WriteInt32L(iServerDifferentiator); + aStream.WriteInt32L(iDefaultScreenNumber); + aStream.WriteInt32L(iParentWindowGroupID); + aStream.WriteInt32L(iDebugMemFail); + aStream.WriteInt32L(iAppStartupInstrumentationEventIdBase); + aStream.WriteInt32L(iParentProcessId); + } + +void CApaCommandLine::InternalizeL(RReadStream& aStream) + { + // iFile is not supported via RReadStream/RWriteStream + const TInt KMaxBufLength = 4000; + iDocumentName.Close(); // free any existing memory + iDocumentName.CreateL(aStream, KMaxBufLength); + iExecutableName.Close(); // free any existing memory + iExecutableName.CreateL(aStream, KMaxBufLength); + iOpaqueData.Close(); // free any existing memory + iOpaqueData.CreateL(aStream, KMaxBufLength); + iTailEnd.Close(); // free any existing memory + iTailEnd.CreateL(aStream, KMaxBufLength); + iCommand = static_cast(aStream.ReadInt32L()); + iServerDifferentiator = aStream.ReadInt32L(); + iDefaultScreenNumber = aStream.ReadInt32L(); + iParentWindowGroupID = aStream.ReadInt32L(); + iDebugMemFail = aStream.ReadInt32L(); + iAppStartupInstrumentationEventIdBase = aStream.ReadInt32L(); + iParentProcessId = aStream.ReadInt32L(); + } + +/** Sets that no server is required. + +The value of server differentiator is set to zero, to indicate that no server +is required. + +See the description of SetServerRequiredL. +@see SetServerRequiredL +*/ +EXPORT_C void CApaCommandLine::SetServerNotRequiredL() + { + SetServerDifferentiatorL(0); + } + +/** Sets the required server. + +The server differentiator is a number generated by the client that helps to uniquely +identify the server. It is used by an application to indicate whether a server should +be created and how it should be named. + +@param aServerDifferentiator A differentiator for the required server. +@see REikAppServiceBase::LaunchAppL() +*/ +EXPORT_C void CApaCommandLine::SetServerRequiredL(TUint aServerDifferentiator) + { + SetServerDifferentiatorL(aServerDifferentiator); + } + +/** +@see REikAppServiceBase::LaunchAppL() +@internalTechnology +*/ +void CApaCommandLine::SetServerDifferentiatorL(TUint aServerDifferentiator) + { + iServerDifferentiator = aServerDifferentiator; + } + +/** Gets the server differentiator. + +See the description of SetServerRequiredL. + +@see SetServerRequiredL +@return The non-zero differentiator for the server, else zero indicating a server +is not required. +@see REikAppServiceBase::LaunchAppL() */ +EXPORT_C TUint CApaCommandLine::ServerRequired() const + { + return iServerDifferentiator; + } + +/** Provides support for devices with more than one screen. A number representing the default +or startup screen may be passed to an application. +Screen numbers and characteristics are defined in the window server initialisation +file (wsini.ini). + +@param aDefaultScreenNumber The number of the default (startup) screen. +@publishedAll */ +EXPORT_C void CApaCommandLine::SetDefaultScreenL(TInt aDefaultScreenNumber) + { + __ASSERT_ALWAYS(aDefaultScreenNumber>=0, Panic(EPanicInvalidScreenNumber)); + iDefaultScreenNumber = aDefaultScreenNumber; + } + +/** Extracts and returns the default (startup) screen that was specified in the command line. + +@return A number representing the default (startup) screen. 0 (Zero) if nothing present. +@publishedAll */ +EXPORT_C TInt CApaCommandLine::DefaultScreen() const + { + return Max(0, iDefaultScreenNumber); + } + +/** +@publishedAll +*/ +EXPORT_C TBool CApaCommandLine::IsDefaultScreenSet() const + { + return (iDefaultScreenNumber != KErrNotFound); + } + +/** Sets the ID of the parent window-group - the application should create its own +window-group as a child off this parent. + +@param aParentWindowGroupID The ID of the parent window-group - the application +should create its window-group as a child off this parent. */ +EXPORT_C void CApaCommandLine::SetParentWindowGroupID(TInt aParentWindowGroupID) + { + iParentWindowGroupID = aParentWindowGroupID; + } + +/** Returns the ID of the parent window-group - the application should create its own +window-group as a child of this parent. + +@return The ID of the parent window-group - the application should create its +window-group as a child off this . */ +EXPORT_C TInt CApaCommandLine::ParentWindowGroupID() const + { + return iParentWindowGroupID; + } + +/** @internalAll */ +EXPORT_C void CApaCommandLine::SetDebugMemFailL(TInt aDebugMemFail) + { + iDebugMemFail = aDebugMemFail; + } + +/** @internalAll */ +EXPORT_C TInt CApaCommandLine::DebugMemFail() const + { + return iDebugMemFail; + } + +/** @internalAll */ +EXPORT_C void CApaCommandLine::SetAppStartupInstrumentationEventIdBaseL(TInt aAppStartupInstrumentationEventIdBase) + { + iAppStartupInstrumentationEventIdBase = aAppStartupInstrumentationEventIdBase; + } + +/** @internalAll */ +EXPORT_C TInt CApaCommandLine::AppStartupInstrumentationEventIdBase() const + { + return iAppStartupInstrumentationEventIdBase; + } + +/** Returns the index of a process environment-slot for public use (in other words, +one that is not used internally by CApaCommandLine). The number of slots available +for public use is returned from NumberOfEnvironmentSlotsForPublicUse(), (this value +may be increased over time). The returned value can then be passed into any of the +Open(TInt,...) functions on RSessionBase, RMutex, RChunk, RCondVar, etc, or into +User::GetTIntParameter(), User::GetDesParameter(), etc, depending on the type +of the object in that environment slot. + +@param aIndex The logical index of the public environment-slot. This must be greater +than or equal to zero, and less than the value returned from NumberOfEnvironmentSlotsForPublicUse(). +@return The physical index of an environment-slot in the local process. +@publishedAll +*/ +EXPORT_C TInt CApaCommandLine::EnvironmentSlotForPublicUse(TInt aIndex) + { // static + __ASSERT_ALWAYS((aIndex>=0) && (aIndex < ENumberOfEnvironmentSlotsForPublicUse), Panic(EPanicEnvironmentSlotNotForPublicUse)); + return EFirstEnvironmentSlotForPublicUse + aIndex; + } + +/** +The number of process environment-slot available for public use. +@publishedAll +*/ +EXPORT_C TInt CApaCommandLine::NumberOfEnvironmentSlotsForPublicUse() + { + return ENumberOfEnvironmentSlotsForPublicUse; + } + +// For use in CApaCommandLine::DoGetParametersFromCommandLineString() only. +struct SOption + { + const TDesC* iToken; + TInt* iResult; + TRadix iRadix; + HBufC8* iHBufC8Result; + }; + +TInt CApaCommandLine::DoGetParametersFromCommandLineString(const TDesC& aCmdLine) +// does the opposite of SetCmdLineL, i.e. sets iDocumentName, iExecutableName, iTailEnd, iCommand, iServerDifferentiator, iDefaultScreenNumber, iParentWindowGroupID , iDebugMemFail & iAppStartupInstrumentationEventIdBase from aCmdLine +// also sets iOpaqueData + { + const TInt cmdLength = aCmdLine.Length(); + TInt endLibNameOffset = cmdLength-1; + TInt endDocNameOffset = cmdLength-1; + + // these variables are all "shadows" of member variables - we'll set the member variables corresponding to these at the end of this function, once all memory-allocation has succeeded, to make this function atomic + HBufC* documentName = NULL; + HBufC* executableName = NULL; + HBufC8* tailEnd = NULL; + HBufC8* opaqueData = NULL; + + TApaCommand command = EApaCommandRun; + TInt serverDifferentiator = 0; + TInt defaultScreenNumber = KErrNotFound; + TInt parentWindowGroupID = 0; + TInt debugMemFail = 0; + TInt appStartupInstrumentationEventIdBase = 0; + TInt notUsed = 0; + + // Look for the name of the executable + executableName = NameOfExecutable(aCmdLine, endDocNameOffset); + if (!executableName) + { + delete executableName; + return KErrNoMemory; + } + + // Work out the type of command + const TInt offset = endDocNameOffset-endLibNameOffset; + if (offset > 1) + { + const TChar commandLetter = aCmdLine[endLibNameOffset+2]; + switch (commandLetter) + { + case KApaCommandLetterOpen: + command = EApaCommandOpen; + break; + case KApaCommandLetterCreate: + command = EApaCommandCreate; + break; + case KApaCommandLetterViewActivate: + command = EApaCommandViewActivate; + break; + case KApaCommandLetterRunWithoutViews: + command = EApaCommandRunWithoutViews; + break; + case KApaCommandLetterBackgroundAndWithoutViews: + command = EApaCommandBackgroundAndWithoutViews; + break; + case KApaCommandLetterRun: + default: + break; + case KApaCommandLetterBackground: + command = EApaCommandBackground; + break; + } + + // Get the name of the document file, if any. + if (offset > 2) + { + const TInt documentNameStartPosition = endLibNameOffset+3; + documentName = StripQuotes(aCmdLine.Mid(documentNameStartPosition, (endDocNameOffset+1)-documentNameStartPosition)).Alloc(); + if (!documentName) + { + delete executableName; + delete documentName; + return KErrNoMemory; + } + } + } + + // Translate the command line tokens into their corresponing options + const TInt KNumberOfSupportedOptions = 6; + TFixedArray optionArray; + optionArray[0].iToken = &KLitTokenServerDifferentiator; + optionArray[0].iResult = &serverDifferentiator; + optionArray[0].iRadix = EDecimal; + optionArray[1].iToken = &KLitTokenDefaultScreenNumber; + optionArray[1].iResult = &defaultScreenNumber; + optionArray[1].iRadix = EDecimal; + optionArray[2].iToken = &KLitTokenParentWindowGroupID; + optionArray[2].iResult = &parentWindowGroupID; + optionArray[2].iRadix = EDecimal; + optionArray[3].iToken = &KLitTokenDebugMemFail; + optionArray[3].iResult = &debugMemFail; + optionArray[3].iRadix = EHex; + optionArray[4].iToken = &KLitTokenAppStartupInstrumentationEventIdBase; + optionArray[4].iResult = &appStartupInstrumentationEventIdBase; + optionArray[4].iRadix = EDecimal; + optionArray[5].iToken = &KLitTokenOpaqueData; + optionArray[5].iResult = ¬Used; + optionArray[5].iRadix = EDecimal; // should not used if the command-line is well-formed + + TLex lex(aCmdLine.Mid(endDocNameOffset+1)); + lex.Mark(); + for (TInt optionIndex = 0; optionIndex < KNumberOfSupportedOptions; ++optionIndex) + { + lex.SkipSpace(); + const SOption& option = optionArray[optionIndex]; + const TPtrC remainder(lex.Remainder()); + __ASSERT_DEBUG(option.iToken, Panic(EDPanicInvalidToken)); + const TInt tokenLength = option.iToken->Length(); + if ((remainder.Length() >= tokenLength) && (remainder.Left(tokenLength).CompareF(*option.iToken) == 0)) + { + if (option.iToken == &KLitTokenOpaqueData) + { + TInt endOfOpaqueDataIndex = 0; + for (TInt i = tokenLength; i < remainder.Length(); ++i) + { + const TChar current = remainder[i]; + if (current == ' ') + { + endOfOpaqueDataIndex = i; + break; // parse no further + } + } + + if(endOfOpaqueDataIndex > tokenLength) + { + const TInt opaqueDataLength = endOfOpaqueDataIndex - tokenLength; + delete opaqueData; + opaqueData = TPtrC8(reinterpret_cast(remainder.Mid(tokenLength, opaqueDataLength).Ptr()),opaqueDataLength*sizeof(TText)).Alloc(); + if (!opaqueData) + { + delete executableName; + delete documentName; + delete opaqueData; + return KErrNoMemory; + } + + lex.Inc(tokenLength + opaqueDataLength); + lex.Mark(); + } + else + { + delete opaqueData; + delete documentName; + delete executableName; + delete tailEnd; + // invalid command line. copy TLex.Val behavior + return KErrGeneral; + } + } + else + { + ASSERT(option.iResult); + const TInt originalValue = *option.iResult; + lex.Inc(tokenLength); + TUint16 val = static_cast (*option.iResult); + if (lex.Val(val, option.iRadix) == KErrNone) + lex.Mark(); + else + *option.iResult = originalValue; + } + } + } + + lex.UnGetToMark(); + lex.SkipSpace(); + + // Get the tail end + const TPtrC remainder(lex.Remainder()); + const TInt lengthOfRemainder = remainder.Length(); + if (lengthOfRemainder > 0) + { + tailEnd = TPtrC8(reinterpret_cast(remainder.Ptr()),lengthOfRemainder*sizeof(TText)).Alloc(); + if (!tailEnd) + { + delete executableName; + delete documentName; + delete opaqueData; + delete tailEnd; + return KErrNoMemory; + } + } + + // Free any existing memory + iDocumentName.Close(); + iExecutableName.Close(); + iTailEnd.Close(); + iOpaqueData.Close(); + + // Set the member variables, as all memory-allocations have succeeded. + iDocumentName.Assign(documentName); + iExecutableName.Assign(executableName); + iTailEnd.Assign(tailEnd); + iOpaqueData.Assign(opaqueData); + iCommand = command; + iServerDifferentiator = serverDifferentiator; + iDefaultScreenNumber = defaultScreenNumber; + iParentWindowGroupID = parentWindowGroupID; + iDebugMemFail = debugMemFail; + iAppStartupInstrumentationEventIdBase = appStartupInstrumentationEventIdBase; + + return KErrNone; + } + +/** +Get the name of the executable from the command line string. +@internalTechnology +*/ +HBufC* CApaCommandLine::NameOfExecutable(const TDesC& aCmdLine, TInt& aEndDocNameOffset) + { + const TInt cmdLength = aCmdLine.Length(); + + TBool openQuote = EFalse; + TBool foundEndLibName = EFalse; + for (TInt i = 0; i < cmdLength; ++i) + { + const TChar current = aCmdLine[i]; + if (current=='"') + { + openQuote = !openQuote; + continue; + }; + + if ((current==' ') && !openQuote) + { + // space found outside of quotes + if (foundEndLibName) + { + aEndDocNameOffset = i-1; + break; // parse no further + } + + aEndDocNameOffset = i-1; + foundEndLibName = ETrue; + } + } + + return (aEndDocNameOffset > -1 ? StripQuotes(aCmdLine.Left(aEndDocNameOffset+1)) : KNullDesC()).Alloc(); + } + +/** +Strip all quates from the string. +*/ +TPtrC CApaCommandLine::StripQuotes(const TDesC& aDes) + // + // return aDes stripped of any enclosing quotes + // + { + TInt start = 0; + TInt end = aDes.Length()-1; + TPtrC ret; + if (end >= 0) + { + if (aDes[0] == '"') + start++; + + if (aDes[end] == '"') + end--; + + const TInt length = end-start+1; + if (length > 0) + ret.Set(aDes.Mid(start, length)); + } + + return ret; + } +