commands/kerninfo/kerninfo.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 37 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
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.

// 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
		}
	}