libraries/iosrv/client/env.cpp
changeset 0 7f656887cf89
child 78 b3ffff030d5c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/iosrv/client/env.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,542 @@
+// 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);
+	}
+