First submission to Symbian Foundation staging server.
// server_command.cpp
//
// Copyright (c) 2009 - 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/line_editor.h>
#include "command_base.h"
using namespace IoUtils;
//
// Constants.
//
_LIT(KTab, "\t");
_LIT(KSpace, " ");
_LIT(KNewLine, "\r\n");
_LIT(KHelpCommandName, "help");
// used for sorting RArray<TPtrC>'s
TInt PtrOrder(const TPtrC& aDennis, const TPtrC& aGnasher)
{
return aDennis.Compare(aGnasher);
}
//
// TServerCommandId.
//
EXPORT_C TServerCommandId::TServerCommandId()
: iId(0)
{
}
EXPORT_C TServerCommandId::TServerCommandId(TUint aValue)
: iId(aValue)
{
}
EXPORT_C TUint TServerCommandId::Value() const
{
return iId;
}
EXPORT_C void TServerCommandId::Set(const TServerCommandId& aId)
{
iId = aId.iId;
}
EXPORT_C TBool TServerCommandId::operator==(const TServerCommandId& aId) const
{
return (iId == aId.iId);
}
//
// CServerCommandBase.
//
EXPORT_C CServerCommandBase::~CServerCommandBase()
{
}
EXPORT_C const TServerCommandId& CServerCommandBase::Id() const
{
return iId;
}
EXPORT_C void CServerCommandBase::SetId(const TServerCommandId& aId)
{
iId.Set(aId);
}
EXPORT_C void CServerCommandBase::SetFactory(CServerCommandFactory& aFactory)
{
iFactory = &aFactory;
}
EXPORT_C CServerCommandBase::CServerCommandBase()
{
}
EXPORT_C CServerCommandBase::CServerCommandBase(TUint aFlags)
: CCommandBase(aFlags)
{
}
EXPORT_C CServerCommandFactory& CServerCommandBase::Factory()
{
__ASSERT_ALWAYS(iFactory, Panic(ENoFactory));
return *iFactory;
}
EXPORT_C void CServerCommandBase::PrintList(TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
if (iReporter)
{
iReporter->ReportList(iId, aFmt, aList);
}
else
{
CCommandBase::PrintList(aFmt, aList);
}
}
EXPORT_C void CServerCommandBase::PrintList(TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
{
if (iReporter)
{
iReporter->ReportList(iId, aFmt, aList);
}
else
{
CCommandBase::PrintList(aFmt, aList);
}
}
EXPORT_C void CServerCommandBase::PrintErrorList(TInt aError, TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
if (iReporter)
{
iReporter->ReportErrorList(iId, aError, aFmt, aList);
}
else
{
CCommandBase::PrintErrorList(aError, aFmt, aList);
}
}
EXPORT_C void CServerCommandBase::PrintWarningList(TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
if (iReporter)
{
iReporter->ReportWarningList(iId, aFmt, aList);
}
else
{
CCommandBase::PrintWarningList(aFmt, aList);
}
}
void CServerCommandBase::SetReporter(MServerCommandReporter* aReporter)
{
iReporter = aReporter;
}
//
// CHelpCommand.
//
NONSHARABLE_CLASS(CHelpCommand) : public CServerCommandBase
{
public:
static CServerCommandBase* NewLC();
~CHelpCommand();
static const TDesC& NameS();
private:
CHelpCommand();
void ConstructL();
void GenerateTextL(const CServerCommandFactory& aFactory, TInt aIndent = 0);
HBufC* FullCommandNameLC() const;
void Write(TInt aIndent, const TDesC& aCommandName);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual const TDesC& Description() const;
virtual void DoRunL();
private:
CTextBuffer* iBuffer;
CTextFormatter* iFormatter;
RArray<TPtrC> iCommandNameStack;
RFile iPodIndex;
};
CServerCommandBase* CHelpCommand::NewLC()
{
CHelpCommand* self = new(ELeave) CHelpCommand();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CHelpCommand::~CHelpCommand()
{
delete iBuffer;
delete iFormatter;
iPodIndex.Close();
iCommandNameStack.Close();
}
const TDesC& CHelpCommand::NameS()
{
return KHelpCommandName;
}
CHelpCommand::CHelpCommand()
{
}
void CHelpCommand::ConstructL()
{
BaseConstructL();
}
const TDesC& CHelpCommand::Name() const
{
return KHelpCommandName;
}
const TDesC& CHelpCommand::Description() const
{
_LIT(KDescription, "List the commands the amsrv supports.");
return KDescription;
}
void CHelpCommand::GenerateTextL(const CServerCommandFactory& aFactory, TInt aIndent)
{
RArray<TPtrC> commands;
CleanupClosePushL(commands);
aFactory.ListCommandsL(commands);
commands.Sort(TLinearOrder<TPtrC>(PtrOrder));
const TInt numCommands = commands.Count();
for (TInt i = 0; i < numCommands; ++i)
{
const TDesC& commandName = commands[i];
Write(aIndent, commandName);
const CServerCommandConstructor& cmnd = aFactory.GetSubCommandL(commandName);
if (cmnd.IsFactory())
{
GenerateTextL((const CServerCommandFactory&)cmnd, aIndent+1);
}
}
CleanupStack::PopAndDestroy();
}
HBufC* CHelpCommand::FullCommandNameLC() const
{
const TInt numCommands = iCommandNameStack.Count();
TInt length = 0;
for (TInt i = 0; i < numCommands; ++i)
{
length += iCommandNameStack[i].Length();
if (i > 0)
{
++length;
}
}
HBufC* name = HBufC::NewLC(length);
TPtr namePtr(name->Des());
for (TInt i = 0; i < numCommands; ++i)
{
if (i > 0)
{
namePtr.Append('_');
}
namePtr.Append(iCommandNameStack[i]);
}
return name;
}
void CHelpCommand::Write(TInt aIndent, const TDesC& aCommandName)
{
_LIT(KIndent, " ");
if (iBuffer)
{
for (TInt j=0; j<aIndent; ++j)
{
iBuffer->AppendL(KIndent);
}
iBuffer->AppendL(aCommandName);
iBuffer->AppendL(KTab);
}
else
{
for (TInt j=0; j<aIndent; ++j)
{
CCommandBase::Write(KIndent);
}
CCommandBase::Write(aCommandName);
CCommandBase::Write(KNewLine);
}
}
void CHelpCommand::DoRunL()
{
if (Stdout().AttachedToConsole())
{
iBuffer = CTextBuffer::NewL(0x100);
iFormatter = CTextFormatter::NewL(Stdout());
}
GenerateTextL(Factory());
if (iBuffer)
{
iFormatter->ColumnizeL(0, 2, iBuffer->Descriptor());
CCommandBase::Write(iFormatter->Descriptor());
}
CCommandBase::Write(_L("\r\n"));
}
//
// CRootCommand.
//
NONSHARABLE_CLASS(CRootCommand) : public CBranchCommandBase
{
public:
static CRootCommand* NewL(CServerCommandFactory& aFactory);
~CRootCommand();
private:
CRootCommand();
void ConstructL(CServerCommandFactory& aFactory);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual const TDesC& Description() const;
private: // From CAmCmndParent.
virtual const TDesC& TypeDescription();
};
CRootCommand* CRootCommand::NewL(CServerCommandFactory& aFactory)
{
CRootCommand* root = new(ELeave)CRootCommand();
CleanupStack::PushL(root);
root->ConstructL(aFactory);
CleanupStack::Pop(root);
return root;
}
CRootCommand::~CRootCommand()
{
}
CRootCommand::CRootCommand()
{
}
void CRootCommand::ConstructL(CServerCommandFactory& aFactory)
{
SetFactory(aFactory);
}
const TDesC& CRootCommand::Name() const
{
_LIT(KCommandName, "root");
return KCommandName;
}
const TDesC& CRootCommand::Description() const
{
_LIT(KDescription, "A pseudo-command that is the ancestor of all other commands available in this server. Not intended to be run directly.");
return KDescription;
}
const TDesC& CRootCommand::TypeDescription()
{
return KNullDesC;
}
//
// CServerBase.
//
EXPORT_C CServerBase::~CServerBase()
{
delete iLineEditor;
delete iFactory;
}
EXPORT_C CServerBase::CServerBase(TUint aFlags, const TDesC& aPrompt, const TDesC& aCommandHistoryFileName)
: CCommandBase(aFlags), iPrompt(aPrompt), iCommandHistoryFileName(aCommandHistoryFileName), iWriterAdaptor(Stdout())
{
}
EXPORT_C CServerCommandFactory& CServerBase::Factory()
{
return *iFactory;
}
EXPORT_C void CServerBase::Exit(TInt aError)
{
iExitReason = aError;
iExit = ETrue;
}
EXPORT_C void CServerBase::BaseConstructL()
{
CCommandBase::BaseConstructL();
}
EXPORT_C void CServerBase::DoRunL()
{
iFactory = CServerCommandFactory::NewL(this, Cif());
iLineEditor = CLineEditor::NewL(FsL(), iWriterAdaptor, *this, *iFactory, iCommandHistoryFileName);
InitializeL();
RProcess::Rendezvous(KErrNone);
do
{
CheckNewConsoleLine();
Write(iPrompt);
ParseLineL(NextLineL());
}
while (!iExit);
Complete(iExitReason);
}
EXPORT_C void CServerBase::PrintList(TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
Report(TServerCommandId(), buf);
}
EXPORT_C void CServerBase::PrintList(TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
{
TOverflowTruncate8 overflow;
TBuf8<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
Report(TServerCommandId(), buf);
}
EXPORT_C void CServerBase::PrintErrorList(TInt aError, TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
if (!iErrorReported)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
ReportError(TServerCommandId(), aError, buf);
iErrorReported = ETrue;
}
}
EXPORT_C void CServerBase::PrintWarningList(TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
ReportWarning(TServerCommandId(), buf);
}
EXPORT_C void CServerBase::Report(const TServerCommandId& aId, TRefByValue<const TDesC> aFmt, ...)
{
VA_LIST list;
VA_START(list, aFmt);
ReportList(aId, aFmt, list);
VA_END(list);
}
EXPORT_C void CServerBase::ReportList(const TServerCommandId& aId, TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
Report(aId, buf);
}
EXPORT_C void CServerBase::Report(const TServerCommandId& aId, TRefByValue<const TDesC8> aFmt, ...)
{
VA_LIST list;
VA_START(list, aFmt);
ReportList(aId, aFmt, list);
VA_END(list);
}
EXPORT_C void CServerBase::ReportList(const TServerCommandId& aId, TRefByValue<const TDesC8> aFmt, VA_LIST& aList)
{
TOverflowTruncate8 overflow;
TBuf8<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
Report(aId, buf);
}
EXPORT_C void CServerBase::ReportWarning(const TServerCommandId& aId, TRefByValue<const TDesC> aFmt, ...)
{
VA_LIST list;
VA_START(list, aFmt);
ReportWarningList(aId, aFmt, list);
VA_END(list);
}
EXPORT_C void CServerBase::ReportWarningList(const TServerCommandId& aId, TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
ReportWarning(aId, buf);
}
EXPORT_C void CServerBase::ReportError(const TServerCommandId& aId, TInt aError, TRefByValue<const TDesC> aFmt, ...)
{
VA_LIST list;
VA_START(list, aFmt);
ReportErrorList(aId, aError, aFmt, list);
VA_END(list);
}
EXPORT_C void CServerBase::ReportErrorList(const TServerCommandId& aId, TInt aError, TRefByValue<const TDesC> aFmt, VA_LIST& aList)
{
if (!iErrorReported)
{
TOverflowTruncate overflow;
TBuf<0x100> buf;
buf.AppendFormatList(aFmt, aList, &overflow);
ReportError(aId, aError, buf);
iErrorReported = ETrue;
}
}
EXPORT_C void CServerBase::LeoHandleLine(const TDesC& aLine)
{
iLine = aLine;
iLineRead = ETrue;
}
void CServerBase::ParseLineL(const TDesC& aLine)
{
if (aLine.Length() > 0)
{
iErrorReported = EFalse;
CRootCommand* root = CRootCommand::NewL(Factory());
root->SetReporter(this);
root->RunCommand(IoSession(), Stdin(), Stdout(), Stderr(), &aLine, &Env(), NULL);
__ASSERT_ALWAYS(root->IsComplete(), Panic(EUnexpectedAsyncCommand));
delete root;
}
}
const TDesC& CServerBase::NextLineL()
{
retry:
iLine.Zero();
if (Stdin().AttachedToConsole())
{
iLineEditor->Start(KNullDesC);
iLineEditor->ReinstatePromptAndUserInput();
iLineRead = EFalse;
do
{
TRequestStatus status;
Stdin().WaitForKey(status);
User::WaitForRequest(status);
if (status.Int() == KErrNotSupported)
{
// Likely that we're no longer attached to a console and are instead attached to a pipe.
// Note, using "pcons" directly gives us a console, but using "am.exe" gives us a pipe.
iLineEditor->Abort();
goto retry;
}
User::LeaveIfError(status.Int());
iLineEditor->HandleKey(Stdin().KeyCode(), Stdin().KeyModifiers());
}
while (!iLineRead);
}
else
{
LeaveIfErr(Stdin().SetReadMode(RIoReadHandle::ELine), _L("Couldn't set stdin to line mode"));
Stdin().SetLineSeparatorL(KNewLine());
User::LeaveIfError(Stdin().Read(iLine));
}
iLine.TrimRight();
return iLine;
}
EXPORT_C void CServerBase::CheckNewConsoleLine()
{
if (Stdout().AttachedToConsole())
{
TPoint cursorPos(0, 0);
Stdout().GetCursorPos(cursorPos);
if (cursorPos.iX != 0)
{
Stdout().Write(KNewLine);
}
}
}
//
// CServerCommandConstructor.
//
EXPORT_C CServerCommandConstructor* CServerCommandConstructor::NewLC(const TDesC& aName, TServerCommandConstructor aConstructor, CServerCommandFactory& aFactory, MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
{
CServerCommandConstructor* self = new(ELeave)CServerCommandConstructor(aName, aConstructor, aFactory, aReporter, aCif);
CleanupStack::PushL(self);
return self;
}
EXPORT_C CServerCommandConstructor::~CServerCommandConstructor()
{
}
EXPORT_C const TPtrC& CServerCommandConstructor::Name() const
{
return iName;
}
EXPORT_C CServerCommandBase* CServerCommandConstructor::CreateImplementationLC() const
{
CServerCommandBase* commandBase = (*iConstructorLC)();
commandBase->SetReporter(iReporter);
commandBase->SetFactory(iFactory);
if (iCif)
{
commandBase->SetCif(*iCif);
}
return commandBase;
}
EXPORT_C TBool CServerCommandConstructor::IsFactory() const
{
return EFalse;
}
CServerCommandConstructor::CServerCommandConstructor(const TDesC& aName, TServerCommandConstructor aConstructor, CServerCommandFactory& aFactory, MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
: iName(aName), iConstructorLC(aConstructor), iFactory(aFactory), iReporter(aReporter), iCif(aCif)
{
}
TUint32 DefaultTPtrCHash(const TPtrC& aPtr)
{
return DefaultHash::Des16(aPtr);
}
TBool DefaultIdTPtrCRelation(const TPtrC& aPtr1, const TPtrC& aPtr2)
{
return DefaultIdentity::Des16(aPtr1, aPtr2);
}
//
// CServerCommandFactory.
//
EXPORT_C CServerCommandFactory* CServerCommandFactory::NewL(MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
{
CServerCommandFactory* self = new(ELeave)CServerCommandFactory(aReporter, aCif);
CleanupStack::PushL(self);
self->ConstructL(ERoot);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CServerCommandFactory* CServerCommandFactory::NewLC(const TDesC& aName, TServerCommandConstructor aConstructor, MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
{
CServerCommandFactory* self = new(ELeave)CServerCommandFactory(aName, aConstructor, aReporter, aCif);
CleanupStack::PushL(self);
self->ConstructL(EBranch);
return self;
}
EXPORT_C CServerCommandFactory::~CServerCommandFactory()
{
THashMapIter<const TPtrC, const CServerCommandConstructor*> iter(iSubCommands);
while (iter.NextKey())
{
delete *iter.CurrentValue();
}
iSubCommands.Close();
}
EXPORT_C const CServerCommandConstructor& CServerCommandFactory::GetSubCommandL(const TDesC& aName) const
{
const CServerCommandConstructor* cmnd = GetSubCommand(aName);
if (!cmnd)
{
if (iReporter)
{
iReporter->ReportError(TServerCommandId(), KErrNotFound, _L("Couldn't create command \"%S\""), &aName);
}
User::Leave(KErrNotFound);
}
return *cmnd;
}
const CServerCommandConstructor* CServerCommandFactory::GetSubCommand(const TDesC& aName) const
{
TPtrC name(aName);
const CServerCommandConstructor* const * cmnd = iSubCommands.Find(name);
if (!cmnd)
{
return NULL;
}
return *cmnd;
}
EXPORT_C TBool CServerCommandFactory::IsFactory() const
{
return ETrue;
}
EXPORT_C void CServerCommandFactory::AddSubCommandL(const CServerCommandConstructor* aCommand)
{
iSubCommands.InsertL(aCommand->Name(), aCommand);
}
CServerCommandFactory::CServerCommandFactory(MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
: CServerCommandConstructor(KNullDesC, NULL, *this, aReporter, aCif), iSubCommands(THashFunction32<const TPtrC>(&DefaultTPtrCHash), TIdentityRelation<const TPtrC>(&DefaultIdTPtrCRelation))
{
}
CServerCommandFactory::CServerCommandFactory(const TDesC& aName, TServerCommandConstructor aConstructor, MServerCommandReporter* aReporter, const CCommandInfoFile* aCif)
: CServerCommandConstructor(aName, aConstructor, *this, aReporter, aCif), iSubCommands(THashFunction32<const TPtrC>(&DefaultTPtrCHash), TIdentityRelation<const TPtrC>(&DefaultIdTPtrCRelation))
{
}
void CServerCommandFactory::ConstructL(TFactoryType aType)
{
if (aType == ERoot)
{
AddLeafCommandL<CHelpCommand>();
}
}
void CServerCommandFactory::LcCompleteLineL(TConsoleLine& aLine, const TChar&)
{
TLex lex(aLine.ContentsToCursor());
TInt pos = 0;
const CServerCommandFactory* factory = this;
do
{
lex.SkipSpaceAndMark();
pos = lex.Offset();
lex.SkipCharacters();
if (!lex.Eos())
{
const CServerCommandConstructor* command = GetSubCommand(lex.MarkedToken());
if (!command || !command->IsFactory())
{
User::Leave(KErrNotFound);
}
factory = static_cast<const CServerCommandFactory*>(command);
}
} while (!lex.Eos());
RArray<TPtrC> commands;
CleanupClosePushL(commands);
TPtrC partialCommandName(lex.MarkedToken());
factory->ListCommandsL(commands);
// Remove commands that don't match.
TInt i;
for (i = (commands.Count() - 1); i >= 0; --i)
{
if (commands[i].Find(partialCommandName) != 0)
{
commands.Remove(i);
}
}
if (commands.Count() > 0)
{
CompleteLineL(aLine, pos, commands);
}
CleanupStack::PopAndDestroy(&commands);
}
void CServerCommandFactory::CompleteLineL(TConsoleLine& aLine, TInt aPos, const RArray<TPtrC> aPossibilities) const
{
const TInt numPossibilities = aPossibilities.Count();
if (numPossibilities > 1)
{
// Fill out possibilities buffer.
IoUtils::CTextBuffer* possibilities = IoUtils::CTextBuffer::NewLC(0x100);
for (TInt i = 0; i < numPossibilities; ++i)
{
possibilities->AppendL(aPossibilities[i]);
if (i != (numPossibilities - 1))
{
possibilities->AppendL(KTab);
}
}
aLine.PrintCompletionPossibilitiesL(possibilities->Descriptor());
CleanupStack::PopAndDestroy(possibilities);
}
if (numPossibilities > 0)
{
IoUtils::CTextBuffer* completion = IoUtils::CTextBuffer::NewLC(0x100);
TPtrC commonChars(NULL, 0);
if (numPossibilities > 1)
{
// Find common leading characters of the possibilities.
TInt commonCharPos = -1;
TBool finished(EFalse);
do
{
++commonCharPos;
TChar character(0);
for (TInt i = 0; i < numPossibilities; ++i)
{
if (commonCharPos >= aPossibilities[i].Length())
{
finished = ETrue;
break;
}
else if (i == 0)
{
character = aPossibilities[0][commonCharPos];
character.Fold();
}
else
{
TChar c(aPossibilities[i][commonCharPos]);
c.Fold();
if (c != character)
{
finished = ETrue;
break;
}
}
}
}
while (!finished);
commonChars.Set(aPossibilities[0].Mid(0, commonCharPos));
}
else
{
commonChars.Set(aPossibilities[0]);
}
completion->AppendL(commonChars);
if (numPossibilities == 1)
{
completion->AppendL(KSpace);
}
if (completion->Descriptor().Length() > 0)
{
aLine.Replace(aPos, completion->Descriptor());
}
CleanupStack::PopAndDestroy(completion);
}
}
EXPORT_C void CServerCommandFactory::ListCommandsL(RArray<TPtrC>& aList) const
{
THashMapIter<const TPtrC, const CServerCommandConstructor*> iter(iSubCommands);
while (iter.NextKey())
{
aList.AppendL(*iter.CurrentKey());
}
aList.Sort(TLinearOrder<TPtrC>(PtrOrder));
}
//
// CBranchCommandBase.
//
EXPORT_C CBranchCommandBase::~CBranchCommandBase()
{
delete iSubCommandEnum;
delete iSubCommandArgs;
}
EXPORT_C CBranchCommandBase::CBranchCommandBase()
{
}
EXPORT_C void CBranchCommandBase::DoRunL()
{
TPtrC subCommandName(iArguments.AsString(&iType));
CServerCommandBase* subCommand = Factory().GetSubCommandL(subCommandName).CreateImplementationLC();
ConfigureSubCommand(*subCommand);
subCommand->RunCommand(IoSession(), Stdin(), Stdout(), Stderr(), iSubCommandArgs ? iSubCommandArgs : &KNullDesC, &Env(), NULL);
if (subCommand->IsComplete())
{
HandleSubCommandComplete(*subCommand);
CleanupStack::PopAndDestroy(subCommand);
}
else
{
HandleBackgroundSubCommand(*subCommand);
CleanupStack::Pop(subCommand);
}
}
void CBranchCommandBase::BuildEnumL()
{
_LIT(KComma, ",");
RArray<TPtrC> subCommands;
CleanupClosePushL(subCommands);
Factory().ListCommandsL(subCommands);
subCommands.Sort(TLinearOrder<TPtrC>(PtrOrder));
iSubCommandEnum = IoUtils::CTextBuffer::NewL(0x10);
for (TInt i=0; i<subCommands.Count(); ++i)
{
iSubCommandEnum->AppendL(subCommands[i]);
iSubCommandEnum->AppendL(KComma);
}
CleanupStack::PopAndDestroy(&subCommands);
}
EXPORT_C void CBranchCommandBase::ArgumentsL(RCommandArgumentList& aArguments)
{
_LIT(KArgType, "type");
_LIT(KArgArgs, "arguments");
if (!iSubCommandEnum)
{
BuildEnumL();
}
if (UsingCif())
{
aArguments.AppendEnumL((TInt&)iType, KArgType, iSubCommandEnum->Descriptor());
aArguments.AppendStringL(iSubCommandArgs, KArgArgs);
}
else
{
aArguments.AppendEnumL((TInt&)iType, KArgType, TypeDescription(), iSubCommandEnum->Descriptor());
_LIT(KArgArgsDescription, "A set of type-specific arguments and options.");
aArguments.AppendStringL(iSubCommandArgs, KArgArgs, KArgArgsDescription, KValueTypeFlagOptional | KValueTypeFlagLast);
}
}
EXPORT_C const TDesC& CBranchCommandBase::TypeDescription()
{
return KNullDesC;
}
EXPORT_C void CBranchCommandBase::ConfigureSubCommand(CServerCommandBase&)
{
}
EXPORT_C void CBranchCommandBase::HandleSubCommandComplete(CServerCommandBase& aCommand)
{
if (aCommand.CompletionReason() < 0)
{
PrintError(aCommand.CompletionReason(), _L("Couldn't run sub-command \"%S\" of command \"%S\""), &aCommand.Name(), &Name());
}
}
EXPORT_C void CBranchCommandBase::HandleBackgroundSubCommand(CServerCommandBase&)
{
}