libraries/iosrv/client/env.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
child 95 b3ffff030d5c
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// env.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 "ioutils.h"
#include "command_base.h"
#include <fshell/stringhash.h>
#include <fshell/ltkutils.h>
#include <fshell/descriptorutils.h>

using namespace IoUtils;
using LtkUtils::RStringHash;
using LtkUtils::TStringHashIter;

#define iVars (*reinterpret_cast<RStringHash<HBufC*>*>(iVarsImpl))
#define ConstVarsFor(x) (*reinterpret_cast<const RStringHash<HBufC*>*>((x)->iVarsImpl))
#define iConstVars ConstVarsFor(this)

//
// Constants.
//

_LIT(KEnvPwd, "PWD");
_LIT(KDefaultPwd, "c:\\");
_LIT(KChildError, "?");
_LIT(KEnvEscapeChar, "ESCAPE");

//
// CEnvironment.
//

EXPORT_C CEnvironment* CEnvironment::NewL()
	{
	CEnvironment* self = new(ELeave) CEnvironment();
	CleanupStack::PushL(self);
	self->ConstructL();
	self->SetPwdL(KDefaultPwd);
	self->SetL(KChildError, KErrNone);
	CleanupStack::Pop(self);
	return self;
	}

EXPORT_C CEnvironment* CEnvironment::NewL(const CEnvironment& aEnv)
	{
	CEnvironment* self = CEnvironment::NewL();
	CleanupStack::PushL(self);
	self->CopyL(aEnv);
	CleanupStack::Pop(self);
	return self;
	}

EXPORT_C CEnvironment* CEnvironment::CreateSharedEnvironmentL()
	{
	CEnvironment* newenv = new(ELeave) CEnvironment(this);
	CleanupStack::PushL(newenv);
	newenv->ConstructL();
	CleanupStack::Pop(newenv);
	return newenv;
	}

EXPORT_C CEnvironment::~CEnvironment()
	{
	RemoveAll();
	iLock.Close();
	}

EXPORT_C void CEnvironment::RemoveAll()
	{
	// Note this doesn't affect iParentEnv
	if (iLock.Handle())
		{
		iLock.Wait();
		TStringHashIter<HBufC*> iter(iVars);
		while (iter.NextValue() != NULL)
			{
			delete *iter.CurrentValue();
			}
		iVars.Close();
		iLock.Signal();
		}
	}

CEnvironment::CEnvironment()
	{
	__ASSERT_COMPILE(sizeof(iVarsImpl) == sizeof(RStringHash<HBufC*>));
	// Have to placement new iVars because we hide the type
	new(iVarsImpl) RStringHash<HBufC*>;
	}

CEnvironment::CEnvironment(CEnvironment* aParentEnv)
	: iParentEnv(aParentEnv)
	{
	new(iVarsImpl) RStringHash<HBufC*>;
	}

void CEnvironment::ConstructL()
	{
	User::LeaveIfError(iLock.CreateLocal());
	}

void CEnvironment::Lock() const
	{
	iLock.Wait();
	if (iParentEnv) iParentEnv->iLock.Wait();
	}

void CEnvironment::Unlock() const
	{
	if (iParentEnv) iParentEnv->iLock.Signal();
	iLock.Signal();
	}

void CEnvironment::WaitLC() const
	{
	Lock();
	CleanupStack::PushL(TCleanupItem(Signal, const_cast<CEnvironment*>(this)));
	}

void CEnvironment::Signal(TAny* aSelf)
	{
	static_cast<CEnvironment*>(aSelf)->Unlock();
	}

EXPORT_C void CEnvironment::SetL(const TDesC& aKey, TInt aValue)
	{
	TBuf<32> buf;
	buf.AppendNum(aValue);
	SetL(aKey, buf);
	}

EXPORT_C void CEnvironment::SetL(const TDesC& aKey, const TDesC& aValue)
	{
	WaitLC();

	HBufC** valPtr = iVars.Find(aKey);
	HBufC* currentValue = NULL;
	if (valPtr) currentValue = *valPtr;

	if (valPtr == NULL && iParentEnv)
		{
		// If we don't have it, and we have a parent env, we should pass the request through to it.
		iParentEnv->SetL(aKey, aValue);
		}
	else
		{
		if (currentValue)
			{
			// If we already have a value in the hash, just update it if possible
			TPtr ptr = currentValue->Des();
			if (ptr.MaxLength() >= aValue.Length())
				{
				ptr.Copy(aValue);
				CleanupStack::PopAndDestroy(); // Release lock
				return;
				}
			}
		}
	
	HBufC* newVal = aValue.AllocLC();
	iVars.InsertL(aKey, newVal);
	delete currentValue;
	CleanupStack::Pop(newVal);
	CleanupStack::PopAndDestroy(); // Release lock
	}

HBufC* CEnvironment::Get(const TDesC& aKey) const
	{
	HBufC*const* valPtr = iConstVars.Find(aKey);
	if (valPtr == NULL && iParentEnv)
		{
		return iParentEnv->Get(aKey);
		}
	else if (valPtr)
		{
		return *valPtr;
		}
	else
		{
		return NULL;
		}
	}

HBufC* CEnvironment::GetL(const TDesC& aKey) const
	{
	HBufC* var = Get(aKey);
	if (var == NULL) User::Leave(KErrNotFound);
	return var;
	}

EXPORT_C TInt CEnvironment::GetAsInt(const TDesC& aKey) const
	{
	Lock();
	HBufC* var = Get(aKey);
	__ASSERT_ALWAYS(var, Panic(EEnvVarNotFound1));
	TLex lex(*var);
	TInt result = 0;
	lex.Val(result);
	Unlock();
	return result;
	}

EXPORT_C TInt CEnvironment::GetAsIntL(const TDesC& aKey) const
	{
	WaitLC();
	HBufC* var = GetL(aKey);
	TLex lex(*var);
	TInt ret = 0;
	lex.Val(ret);
	CleanupStack::PopAndDestroy(); // Release lock
	return ret;
	}

EXPORT_C const TDesC& CEnvironment::GetAsDes(const TDesC& aKey) const
	{
	Lock();
	HBufC* var = Get(aKey);
	__ASSERT_ALWAYS(var, Panic(EEnvVarNotFound2));
	Unlock();
	return *var;
	}

EXPORT_C const TDesC& CEnvironment::GetAsDesL(const TDesC& aKey) const
	{
	WaitLC();
	const TDesC& des = *GetL(aKey);
	CleanupStack::PopAndDestroy(); // Release lock
	return des;
	}

EXPORT_C TInt CEnvironment::Remove(const TDesC& aKey)
	{
	Lock();
	HBufC** valPtr = iVars.Find(aKey);

	TInt ret = KErrNone;
	if (valPtr == NULL && iParentEnv)
		{
		// Not in ours, look at parent env
		ret = iParentEnv->Remove(aKey);
		}
	else if (valPtr && *valPtr)
		{
		// In ours
		delete *valPtr;
		if (iParentEnv)
			{
			// Need to remember we've removed it
			*valPtr = NULL;
			}
		else
			{
			iVars.Remove(aKey);
			}
		}
	else
		{
		// Not in ours and no parent env, or in ours and null
		ret = KErrNotFound;
		}

	Unlock();
	return ret;
	}

EXPORT_C void CEnvironment::RemoveL(const TDesC& aKey)
	{
	User::LeaveIfError(Remove(aKey));
	}

void CEnvironment::CopyL(const CEnvironment& aEnv)
	{
	RemoveAll();
	WaitLC();
	aEnv.WaitLC();

	RPointerArray<HBufC> keys;
	LtkUtils::CleanupResetAndDestroyPushL(keys);
	aEnv.GetKeysL(keys);
	for (TInt i = 0; i < keys.Count(); i++)
		{
		SetL(*keys[i], aEnv.GetAsDes(*keys[i]));
		}

	CleanupStack::PopAndDestroy(3); // keys, WaitLC x 2.
	}

class TDesRead
	{
public:
	TDesRead(const TDesC8& aDes);
	TInt32 ReadInt32();
	TPtrC ReadDes();
private:
	const TDesC8& iDes;
	TInt iPos;
	};
class TDesWrite
	{
public:
	TDesWrite(LtkUtils::RLtkBuf8& aDes);
	void WriteL(TInt32 aInt);
	void WriteL(const TDesC& aDes);
private:
	LtkUtils::RLtkBuf8& iDes;
	};

EXPORT_C void CEnvironment::InternalizeL(const TDesC8& aDes)
	{
	WaitLC();

	TDesRead desRead(aDes);
	TInt varCount = desRead.ReadInt32();
	while (varCount--)
		{
		TPtrC key = desRead.ReadDes();
		TPtrC val = desRead.ReadDes();
		SetL(key, val);
		}

	CleanupStack::PopAndDestroy(); // Release lock
	}

EXPORT_C HBufC8* CEnvironment::ExternalizeLC() const
	{
	WaitLC();
	LtkUtils::RLtkBuf8 buf;
	CleanupClosePushL(buf);
	TDesWrite desWrite(buf);

	RPointerArray<HBufC> keys;
	LtkUtils::CleanupResetAndDestroyPushL(keys);
	GetKeysL(keys);
	desWrite.WriteL(keys.Count());
	for (TInt i = 0; i < keys.Count(); i++)
		{
		desWrite.WriteL(*keys[i]);
		desWrite.WriteL(GetAsDes(*keys[i]));
		}
	CleanupStack::PopAndDestroy(&keys);
	CleanupStack::Pop(&buf);
	CleanupStack::PopAndDestroy(); // Release lock
	HBufC8* res = buf.ToHBuf();
	CleanupStack::PushL(res);
	return res;
	}

TInt StringCompare(const HBufC& aLeft, const HBufC& aRight)
	{
	return aLeft.Compare(aRight);
	}

EXPORT_C void CEnvironment::GetKeysL(RPointerArray<HBufC>& aResult) const
	{
	WaitLC();
	aResult.ResetAndDestroy();
	TStringHashIter<HBufC*> iter(iConstVars);
	while (iter.NextValue() != NULL)
		{
		if (*iter.CurrentValue() != NULL)
			{
			HBufC* key = iter.CurrentKey()->AllocLC();
			aResult.AppendL(key);
			CleanupStack::Pop(key);
			}
		}
	
	if (iParentEnv)
		{
		RPointerArray<HBufC> parentKeys;
		LtkUtils::CleanupResetAndDestroyPushL(parentKeys);
		iParentEnv->GetKeysL(parentKeys);
		for (TInt i = parentKeys.Count()-1; i >= 0; i--)
			{
			HBufC* key = parentKeys[i];
			if (iConstVars.Find(*key) == NULL)
				{
				// Only add stuff in parent that isn't also in ours
				aResult.AppendL(key);
				parentKeys.Remove(i);
				}
			}
		CleanupStack::PopAndDestroy(&parentKeys);
		}

	// Make sure the resulting array is alphabetic, as RStringHash doesn't guarantee that (unlike RVarSet)
	aResult.Sort(TLinearOrder<HBufC>(&StringCompare));
	CleanupStack::PopAndDestroy(); // Release lock
	}

EXPORT_C TBool CEnvironment::IsDefined(const TDesC& aKey) const
	{
	iLock.Wait();
	TBool ret = (Get(aKey) != NULL);
	iLock.Signal();
	return ret;
	}

EXPORT_C TBool CEnvironment::IsInt(const TDesC& aKey) const
	{
	iLock.Wait();
	HBufC* val = Get(aKey);
	iLock.Signal();

	if (val == NULL) return EFalse;
	
	TLex lex(*val);
	TBool atLeastOneDigit(EFalse);
	while (!lex.Eos())
		{
		if (lex.Get().IsDigit())
			{
			atLeastOneDigit = ETrue;
			}
		else
			{
			return EFalse;
			}
		}
	return atLeastOneDigit;
	}

EXPORT_C TBool CEnvironment::IsDes(const TDesC& aKey) const
	{
	return IsDefined(aKey);
	}

EXPORT_C TInt CEnvironment::Count() const
	{
	iLock.Wait();
	TInt ret = iConstVars.Count();
	iLock.Signal();
	return ret;
	}

EXPORT_C void CEnvironment::SetPwdL(const TDesC& aPwd)
	{
	SetL(KEnvPwd, aPwd);
	}

EXPORT_C const TDesC& CEnvironment::Pwd() const
	{
	return GetAsDes(KEnvPwd);
	}

EXPORT_C TChar CEnvironment::EscapeChar() const
	{
	iLock.Wait();
	HBufC* var = Get(KEnvEscapeChar);
	TUint16 escape = '^';
	if (var)
		{
		escape = (*var)[0];
		}
	iLock.Signal();
	return TChar(escape);
	}

// Declare aKey so that changes aren't reflected in the parent environment
EXPORT_C void CEnvironment::SetLocalL(const TDesC& aKey)
	{
	if (iParentEnv == NULL)
		{
		// Nothing needed if there is no parent, then everything is effectively local anyway
		return;
		}

	WaitLC();
	HBufC** currentValPtr = iVars.Find(aKey);
	if (currentValPtr)
		{
		// It's already local
		CleanupStack::PopAndDestroy(); // Release lock
		return;
		}

	// Local vals start out undefined, regardless of what the parent's value is
	iVars.InsertL(aKey, NULL);

	CleanupStack::PopAndDestroy(); // Release lock
	}

//
// TDesRead.
//

TDesRead::TDesRead(const TDesC8& aDes)
	: iDes(aDes), iPos(0)
	{
	}

TInt32 TDesRead::ReadInt32()
	{
	TInt32 int32;
	TPckg<TInt32> intPckg(int32);
	intPckg.Copy(iDes.Mid(iPos, sizeof(TInt32)));
	iPos += sizeof(TInt32);
	return int32;
	}

TPtrC TDesRead::ReadDes()
	{
	const TInt length = ReadInt32();
	const TInt size = length * 2;
	if (iPos & 1) iPos++; // 16-bit descriptors are 2-byte aligned
	TPtrC8 ptr8 = iDes.Mid(iPos, size);
	TPtrC result((const TUint16*)ptr8.Ptr(), length);
	iPos += size;
	return result;
	}


//
// TDesWrite.
//

TDesWrite::TDesWrite(LtkUtils::RLtkBuf8& aDes)
	: iDes(aDes)
	{
	}

void TDesWrite::WriteL(TInt32 aInt)
	{
	TPckgC<TInt32> intPckg(aInt);
	iDes.AppendL(intPckg);
	}

void TDesWrite::WriteL(const TDesC& aDes)
	{
	WriteL(aDes.Length());
	if (iDes.Size() & 1) iDes.AppendL('.'); // Pad so the desc is 2-byte aligned
	TPtrC8 ptr((TUint8*)aDes.Ptr(), aDes.Size());
	iDes.AppendL(ptr);
	}