Pulled in from FCL: input, base64, fshell thread pool
Also:
* fed console size fixes
* fzip smoketest
* CBtraceAppStart
// 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);
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 (valPtr)
{
// The key is present in the hash.
HBufC* currentValue = *valPtr;
if (currentValue && (currentValue->Des().MaxLength() >= aValue.Length()))
{
// If the existing HBufC is big enough, simply copy.
// Note, currentValue will be NULL if this is the first time a 'local' variable is being set.
currentValue->Des().Copy(aValue);
}
else
{
// Otherwise allocate a new HBufC.
*valPtr = aValue.AllocL();
delete currentValue;
}
}
else
{
// New key.
HBufC* newVal = aValue.AllocLC();
iVars.InsertL(aKey, newVal);
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);
}