Added --no-write to gobble, fixed crash in start --timeout.
Also changed help to output one command per line (instead of columnizing) if not attached to a console. It's the same as what ls does.
// kerninfo.cpp
//
// Copyright (c) 2008 - 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/memoryaccesscmd.h>
#include <fshell/qr3dll.h>
#include <fshell/ltkutils.h>
#include <fshell/descriptorutils.h>
#ifdef FSHELL_SPCRE_SUPPORT
#include <fshell/pcre/cregex.h>
#endif
using namespace IoUtils;
class CRegEx;
class CCmdKerninfo : public CMemoryAccessCommandBase
{
public:
static CCommandBase* NewLC();
~CCmdKerninfo();
private:
CCmdKerninfo();
TInt InfoL(TInt aIndex, TBool aUseId, TBool aVerbose);
void PrintInfoForL(TInt aIndex, TBool aUseId=EFalse);
static TBool SupportsIds(TKernelObjectType aType);
static void ChompBlankLines(TDes& aDes);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private:
TKernelObjectType iType;
TInt iObjectIndex;
TBool iVerbose;
TBool iVerboseMatch;
HBufC* iMatch;
HBufC* iRegexMatch;
CKernelObjectList* iModel;
RBuf iTitle, iInfo;
LtkUtils::RLtkBuf8 iNarrowBuf;
CRegEx* iRegex;
};
CCommandBase* CCmdKerninfo::NewLC()
{
CCmdKerninfo* self = new(ELeave) CCmdKerninfo();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdKerninfo::~CCmdKerninfo()
{
delete iModel;
iTitle.Close();
iInfo.Close();
iNarrowBuf.Close();
delete iMatch;
delete iRegexMatch;
#ifdef FSHELL_SPCRE_SUPPORT
delete iRegex;
#endif
}
CCmdKerninfo::CCmdKerninfo()
{
}
const TDesC& CCmdKerninfo::Name() const
{
_LIT(KName, "kerninfo");
return KName;
}
void CCmdKerninfo::ArgumentsL(RCommandArgumentList& aArguments)
{
aArguments.AppendEnumL((TInt&)iType, _L("object-type"));
aArguments.AppendIntL(iObjectIndex, _L("object-index"));
}
void CCmdKerninfo::OptionsL(RCommandOptionList& aOptions)
{
aOptions.AppendStringL(iMatch, _L("match"));
#ifdef FSHELL_SPCRE_SUPPORT
aOptions.AppendStringL(iRegexMatch, _L("regex-match"));
#endif
aOptions.AppendBoolL(iVerbose, _L("verbose"));
aOptions.AppendBoolL(iVerboseMatch, _L("verbosematch"));
}
EXE_BOILER_PLATE(CCmdKerninfo)
void CCmdKerninfo::DoRunL()
{
LoadMemoryAccessL();
iModel = CKernelObjectList::NewL(&iMemAccess);
iModel->SetCurrentType(iType);
TRAPL(iModel->RefreshDataL(), _L("Couldn't get model data"));
iTitle.CreateL(256);
iInfo.CreateL(256);
#ifdef FSHELL_SPCRE_SUPPORT
if (iRegexMatch)
{
if (iMatch) LeaveIfErr(KErrArgument, _L("Can't specify both --match and --regex-match, use one or the other"));
iRegex = CRegEx::NewL(*iRegexMatch, TRegExOptions(EPcreExtended|EPcreNewlineAny));
}
#endif
if (iVerboseMatch) iVerbose = ETrue; // verbosematch implies verbose
const TInt n = iModel->Count();
TBool listAll = !iArguments.IsPresent(&iObjectIndex);
if (listAll)
{
for (TInt i = 0; i < n; i++)
{
PrintInfoForL(i);
}
}
else
{
TBool usingId = SupportsIds(iType);
if (!usingId && (iObjectIndex < 0 || iObjectIndex >= n))
{
LeaveIfErr(KErrArgument, _L("Bad argument %d. Number of objects in this category: %d"), iObjectIndex, n);
}
PrintInfoForL(iObjectIndex, usingId);
}
}
TInt CCmdKerninfo::InfoL(TInt aIndex, TBool aUseId, TBool aVerbose)
{
TInt err = KErrNone;
TInt itemid = 0;
if (aUseId)
{
TRAP(err, iModel->GetInfoByIdL(aIndex, aVerbose, iTitle, iInfo));
}
else
{
TRAP(err, itemid = iModel->GetInfoByIndexL(aIndex, aVerbose, iTitle, iInfo));
}
LeaveIfErr(err, _L("Couldn't get info for item %d"), aIndex);
return itemid;
}
void CCmdKerninfo::PrintInfoForL(TInt aIndex, TBool aUseId /* =EFalse */)
{
TInt itemid = 0;
if (iMatch || iRegexMatch)
{
// Filter out anything not matching iMatch/iRegexMatch
// Unless --verbosematch is specified, match on the non-verbose (but display the verbose if specified). This is because calculating the verbose can be really slow so don't do it until we know we match.
itemid = InfoL(aIndex, aUseId, (TBool)iVerboseMatch);
const TDesC& toMatchAgainst = iVerboseMatch ? iInfo : iTitle;
TBool match = EFalse;
if (iMatch)
{
match = (toMatchAgainst.MatchF(*iMatch) != KErrNotFound);
}
#ifdef FSHELL_SPCRE_SUPPORT
else if (iRegexMatch)
{
iNarrowBuf.Zero();
iNarrowBuf.AppendL(toMatchAgainst);
match = iRegex->PartialMatchL(iNarrowBuf);
}
#endif
if (!match) return;
}
if ((!iMatch && !iRegexMatch) || (iVerbose && !iVerboseMatch))
{
// Need to get info for first time (if !iMatch) or re-get the verbose info (in the case of we just did a match on the non-verbose info)
itemid = InfoL(aIndex, aUseId, iVerbose);
}
TInt idxToDisplay = (SupportsIds(iType) && !aUseId) ? itemid : aIndex;
if (iVerbose)
{
// In verbose mode the title is always just "Process info" (etc) so no point displaying it
Printf(_L("%d:\n"), idxToDisplay);
ChompBlankLines(iInfo); // When doing a verbose listing (specially multiple ones) it's easier to remove the blank lines that the model adds for readability in the QResources dialog
Write(iInfo);
Write(_L("\n\n"));
}
else
{
Printf(_L("%d: %S\t%S\n"), idxToDisplay, &iTitle, &iInfo);
}
}
TBool CCmdKerninfo::SupportsIds(TKernelObjectType aType)
{
// These types can (and should) be looked up directly by id and not by index into the list.
return (aType == EListThread || aType == EListProcess || aType == EListHal);
}
void CCmdKerninfo::ChompBlankLines(TDes& aDes)
{
_LIT(KLfLf, "\n\n");
TInt found;
while ((found = aDes.Find(KLfLf)) != KErrNotFound)
{
aDes.Delete(found, 1); // Nuke one of the newlines
}
}