diff -r 000000000000 -r 7f656887cf89 libraries/iosrv/client/env.cpp --- /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 +#include +#include + +using namespace IoUtils; +using LtkUtils::RStringHash; +using LtkUtils::TStringHashIter; + +#define iVars (*reinterpret_cast*>(iVarsImpl)) +#define ConstVarsFor(x) (*reinterpret_cast*>((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 iter(iVars); + while (iter.NextValue() != NULL) + { + delete *iter.CurrentValue(); + } + iVars.Close(); + iLock.Signal(); + } + } + +CEnvironment::CEnvironment() + { + __ASSERT_COMPILE(sizeof(iVarsImpl) == sizeof(RStringHash)); + // Have to placement new iVars because we hide the type + new(iVarsImpl) RStringHash; + } + +CEnvironment::CEnvironment(CEnvironment* aParentEnv) + : iParentEnv(aParentEnv) + { + new(iVarsImpl) RStringHash; + } + +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(this))); + } + +void CEnvironment::Signal(TAny* aSelf) + { + static_cast(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 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 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& aResult) const + { + WaitLC(); + aResult.ResetAndDestroy(); + TStringHashIter iter(iConstVars); + while (iter.NextValue() != NULL) + { + if (*iter.CurrentValue() != NULL) + { + HBufC* key = iter.CurrentKey()->AllocLC(); + aResult.AppendL(key); + CleanupStack::Pop(key); + } + } + + if (iParentEnv) + { + RPointerArray 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(&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 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 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); + } +