Added showdebug command.
Also:
* Added an exported constructor to RChildProcess so the iProcess handle was set to zero on construction.
* Fixed bug in fshell_builddocs script that created HTML relative links with backslashes instead of forward slashes.
// settings.cpp
//
// Copyright (c) 2009 - 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/settings.h>
using namespace LtkUtils;
void Panic(TSettingPanic aReason)
{
User::Panic(KSettingPanic, aReason);
}
void RemoveSpaces(TDes& aDes)
{
for (TInt i=aDes.Length()-1; i>=0; --i)
{
if (TChar(aDes[i]).IsSpace()) aDes.Delete(i, 1);
}
}
/*
List of valid values for a boolean. Values interpreted as false, true, false, true, etc.
i.e. even poitions are false, odd true.
*/
_LIT(KBoolValues, "0,1,off,on,no,yes,false,true");
void HandleLineL(const TDesC& aLine, MValueHandler& aValueHandler, TErrorContext aErrorContext)
{
if (aLine.Length() == 0) return;
if (aLine[0] == '#') // comment
{
aValueHandler.HandleCommentL(aLine.Mid(1), aErrorContext);
}
else
{
TLex lex(aLine);
lex.SkipSpaceAndMark();
lex.SkipCharacters();
TPtrC id(lex.MarkedToken());
lex.SkipSpace();
TPtrC value(lex.Remainder());
if (id.Length())
{
aValueHandler.HandleValueL(id, value, aErrorContext, EFalse);
}
}
}
_LIT(KNewLine, "\n");
EXPORT_C void LtkUtils::ReadIniFileL(const TDesC& aFilename, MValueHandler& aValueHandler, TErrorContext aErrorContext, TFileNotFoundAction aNotFoundAction)
{
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
IoUtils::TFileName2 fn(aFilename);
TInt err = fn.FindFile(fs);
if ((err == KErrNotFound) && (aNotFoundAction == ESucceedIfFileNotFound))
{
CleanupStack::PopAndDestroy(&fs);
return;
}
StaticLeaveIfErr(err, _L("%SCannot find file '%S'"), &aErrorContext, &fn);
RFile file;
StaticLeaveIfErr(file.Open(fs, fn, EFileRead | EFileShareReadersOnly), _L("%SCannot open file '%S'"), &aErrorContext, &fn);
CleanupClosePushL(file);
IoUtils::CTextBuffer* buf = IoUtils::CTextBuffer::NewLC(0x40);
TErrorContext context(fn);
TBuf8<0x40> readBuf;
do
{
TInt lineEnd;
do
{
const TDesC& des(buf->Descriptor());
lineEnd = des.Find(KNewLine);
if (lineEnd != KErrNotFound)
{
TPtrC line(des.Left(lineEnd));
if (line.Length() > 0)
{
if (line[line.Length()-1] == '\r') line.Set(line.Left(line.Length()-1));
HandleLineL(line, aValueHandler, context);
}
buf->Delete(0, lineEnd+1);
context.NextLine();
}
} while (lineEnd != KErrNotFound);
User::LeaveIfError(file.Read(readBuf));
buf->AppendL(readBuf);
}
while (readBuf.Length() > 0);
CleanupStack::PopAndDestroy(3, &fs); // buf, file, fs
}
EXPORT_C void LtkUtils::ReadIniFileL(RIoReadHandle& aReadHandle, MValueHandler& aValueHandler)
{
RBuf lineBuf;
lineBuf.CreateL(0x100);
CleanupClosePushL(lineBuf);
aReadHandle.SetReadModeL(RIoReadHandle::ELine);
TName name;
aReadHandle.ObjectNameL(name);
TInt err;
TErrorContext context(name);
while ((err = aReadHandle.Read(lineBuf))==KErrNone)
{
HandleLineL(lineBuf, aValueHandler, context);
context.NextLine();
}
if (err!=KErrEof) User::LeaveIfError(err);
CleanupStack::PopAndDestroy(&lineBuf);
}
TInt ValueLineNumberOrder(const CValue& aRodger, const CValue& aMinnie)
{
return aRodger.LineNumber() - aMinnie.LineNumber();
}
EXPORT_C void LtkUtils::WriteIniFileL(const TDesC& aFilename, CIniReader& aValues)
{
RFs fs;
User::LeaveIfError(fs.Connect());
CleanupClosePushL(fs);
RFile file;
StaticLeaveIfErr(file.Replace(fs, aFilename, EFileWrite | EFileShareExclusive), _L("Cannot open '%S' for writing"), &aFilename);
CleanupClosePushL(file);
IoUtils::CTextFormatter* formatter = IoUtils::CTextFormatter::NewLC(KMaxTInt);
aValues.AppendFirstLineL(formatter);
RPointerArray<CValue> values;
CleanupClosePushL(values);
aValues.GetValuesL(values);
values.Sort(TLinearOrder<CValue>(ValueLineNumberOrder));
IoUtils::CTextBuffer* buf = IoUtils::CTextBuffer::NewLC(0x20);
for (TInt i=0; i<values.Count(); ++i)
{
buf->AppendFormatL(_L("%S\t%S\r\n"), &values[i]->Id(), &values[i]->Value());
}
formatter->TabulateL(0, 4, buf->Descriptor(), IoUtils::EIgnoreAvailableWidth);
User::LeaveIfError(file.Write(formatter->Collapse()));
CleanupStack::PopAndDestroy(5, &fs); // fs, file, values, buf, formatter
}
//______________________________________________________________________________
// TErrorContext
EXPORT_C TErrorContext::TErrorContext()
: iFilename(KNullDesC), iLineNumber(0)
{
}
EXPORT_C TErrorContext::TErrorContext(const TDesC& aFilename)
: iFilename(aFilename), iLineNumber(1)
{
}
EXPORT_C void TErrorContext::NextLine()
{
iLineNumber++;
}
EXPORT_C TInt TErrorContext::LineNumber()
{
return iLineNumber;
}
EXPORT_C const TDesC& TErrorContext::StringLC()
{
_LIT(KErrorContextFmt, "%S:%d: ");
if (iFilename.Length() && iLineNumber>0)
{
HBufC* string = HBufC::NewLC(iFilename.Length()+0x10);
string->Des().AppendFormat(KErrorContextFmt, &iFilename, iLineNumber);
return *string;
}
else
{
CleanupStack::PushL((void*)NULL);
return KNullDesC;
}
}
//______________________________________________________________________________
// CValue
EXPORT_C CValue* CValue::NewL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
{
CValue* self = CValue::NewLC(aId, aValue, aErrorContext);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CValue* CValue::NewLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
{
CValue* self = new(ELeave)CValue(aErrorContext);
CleanupStack::PushL(self);
self->ConstructL(aId, aValue);
return self;
}
EXPORT_C CValue::~CValue()
{
iId.Close();
iValue.Close();
}
EXPORT_C const TDesC& CValue::Id() const
{
return iId;
}
EXPORT_C const TDesC& CValue::Value() const
{
return iValue;
}
EXPORT_C void CValue::SetL(const TDesC& aNewValue, TErrorContext aErrorContext)
{
if (iValue.MaxLength() < aNewValue.Length())
{
RBuf newValue;
newValue.CreateL(aNewValue.Length());
newValue.Swap(iValue);
newValue.Close();
}
if (aErrorContext.LineNumber() > 0) iLineNumber = aErrorContext.LineNumber();
iValue.Copy(aNewValue);
}
EXPORT_C TInt CValue::LineNumber() const
{
return iLineNumber;
}
EXPORT_C TInt CValue::AsInt(TInt& aInt) const
{
TLex lex(iValue);
TInt err = lex.Val(aInt);
if (err == KErrNone)
{
if (lex.Remainder().Length()) err = KErrArgument;
}
return err;
}
EXPORT_C TInt CValue::AsBool(TBool& aBool) const
{
IoUtils::TEnum truth(KBoolValues);
TInt i;
TInt err = truth.Parse(iValue, i);
if (err==KErrNone)
{
aBool = i & 0x01;
}
return err;
}
EXPORT_C TInt CValue::AsIntL() const
{
TInt i;
StaticLeaveIfErr(AsInt(i), _L("'%S' value '%S' is not a valid integer"), &iId ,&iValue);
return i;
}
EXPORT_C TBool CValue::AsBoolL() const
{
TBool b;
StaticLeaveIfErr(AsBool(b), _L("'%S' value '%S' is not a valid boolean"), &iId, &iValue);
return b;
}
CValue::CValue(TErrorContext aErrorContext)
: iLineNumber(aErrorContext.LineNumber())
{
}
void CValue::ConstructL(const TDesC& aId, const TDesC& aValue)
{
iId.CreateL(aId);
iValue.CreateL(aValue);
}
//______________________________________________________________________________
// CIniReader
EXPORT_C CIniReader* CIniReader::NewL(const TDesC& aFilename, TErrorContext aErrorContext)
{
CIniReader* self = new(ELeave)CIniReader();
CleanupStack::PushL(self);
ReadIniFileL(aFilename, *self, aErrorContext, EFailIfFileNotFound);
CleanupStack::Pop(self);
return self;
}
CIniReader::CIniReader()
{
}
EXPORT_C CIniReader::~CIniReader()
{
TPtrHashMapIter<TDesC, CValue> iter(iValues);
while (iter.NextValue())
{
const CValue* val = iter.CurrentValue();
iter.RemoveCurrent();
delete val;
}
iValues.Close();
iFirstLineComment.Close();
}
EXPORT_C const TDesC* CIniReader::GetValue(const TDesC& aId) const
{
const CValue* value = iValues.Find(aId);
if (value)
{
return &value->Value();
}
else
{
return NULL;
}
}
EXPORT_C void CIniReader::GetValuesL(RPointerArray<CValue>& aValues)
{
TPtrHashMapIter<TDesC, CValue> iter(iValues);
while (iter.NextValue())
{
if (IncludeValue(iter.CurrentValue())) aValues.AppendL(iter.CurrentValue());
}
}
EXPORT_C void CIniReader::GetValuesL(RPointerArray<const CValue>& aValues) const
{
TPtrHashMapIter<TDesC, CValue> iter(iValues);
while (iter.NextValue())
{
if (IncludeValue(iter.CurrentValue())) aValues.AppendL(iter.CurrentValue());
}
}
EXPORT_C void CIniReader::GetIdsL(RArray<const TPtrC>& aIds) const
{
TPtrHashMapIter<TDesC, CValue> iter(iValues);
while (iter.NextValue())
{
aIds.AppendL(*iter.CurrentKey());
}
}
EXPORT_C void CIniReader::SetValueL(const TDesC& aId, const TDesC& aValue)
{
CValue* value = iValues.Find(aId);
if (value)
{
value->SetL(aValue, TErrorContext());
}
else
{
HandleValueL(aId, aValue, TErrorContext(), ETrue);
}
}
EXPORT_C void CIniReader::RemoveValueL(const TDesC& aId)
{
CValue* value = iValues.Find(aId);
if (value)
{
DoRemoveL(value);
}
}
void CIniReader::DoRemoveL(CValue* aValue)
{
iValues.Remove(&aValue->Id());
delete aValue;
}
void CIniReader::AppendFirstLineL(IoUtils::CTextFormatter* aFormatter)
{
if (iFirstLineComment.Length())
{
aFormatter->AppendFormatL(_L("#%S\r\n"), &iFirstLineComment);
}
}
void CIniReader::HandleValueL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext, TBool aOverwrite)
{
CValue* value = iValues.Find(aId);
if (!value)
{
value = CreateValueLC(aId, aValue, aErrorContext);
iValues.InsertL(&value->Id(), value);
CleanupStack::Pop(value);
}
else
{
if (aOverwrite)
{
value->SetL(aValue, aErrorContext);
}
// else ignore the duplicate value
}
}
void CIniReader::HandleCommentL(const TDesC& aComment, TErrorContext aErrorContext)
{
if (aErrorContext.LineNumber() == 1)
{
iFirstLineComment.Close();
iFirstLineComment.CreateL(aComment);
HandleFirstLineCommentL(iFirstLineComment, aErrorContext);
}
}
CValue* CIniReader::CreateValueLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
{
return CValue::NewLC(aId, aValue, aErrorContext);
}
//______________________________________________________________________________
// CSetting
EXPORT_C CSetting* CSetting::NewL(TSettingType aType, const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
{
CSetting* self = CSetting::NewLC(aType, aId, aName, aDescription, aDefault, aEnumValues, aErrorContext);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CSetting* CSetting::NewLC(TSettingType aType, const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
{
CSetting* self = new(ELeave)CSetting(aType);
CleanupStack::PushL(self);
self->ConstructL(aId, aName, aDescription, aDefault, aEnumValues, aErrorContext);
return self;
}
EXPORT_C CSetting::~CSetting()
{
iName.Close();
iDescription.Close();
iEnumValues.Close();
iDefault.Close();
}
EXPORT_C void CSetting::SetL(const TDesC& aNewValue, TErrorContext aErrorContext)
{
TInt value = ParseL(aNewValue, aErrorContext);
switch (iType)
{
case ETypeEnum:
{
CValue::SetL(iEnum.GetString(value), aErrorContext);
iIntValue = value;
}
break;
case ETypeFilename:
case ETypeString:
CValue::SetL(aNewValue, aErrorContext);
break;
case ETypeInteger:
{
CValue::SetL(aNewValue, aErrorContext);
iIntValue = value;
}
break;
case ETypeBoolean:
{
IoUtils::TEnum truth(KBoolValues);
TInt value = truth.ParseL(aNewValue); // even false, odd true
CValue::SetL(truth.GetString(value), aErrorContext);
iIntValue = (value & 0x01) ? (TBool)ETrue : EFalse;
}
break;
}
iIsSet = ETrue;
}
TInt CSetting::ParseL(const TDesC& aValue, TErrorContext aErrorContext)
{
switch (iType)
{
case ETypeEnum:
return iEnum.ParseL(aValue);
case ETypeFilename:
case ETypeString:
return 0;
case ETypeInteger:
{
TLex lex(aValue);
TInt value;
lex.SkipSpace();
StaticLeaveIfErr(lex.Val(value), _L("%S'%S' value '%S' is not a valid integer"), &aErrorContext.StringLC(), &Id(), &aValue);
lex.SkipSpace();
if (lex.Remainder().Length()) StaticLeaveIfErr(KErrArgument, _L("%S'%S' value '%S' is not a valid integer"), &aErrorContext.StringLC(), &Id(), &aValue);
return value;
}
case ETypeBoolean:
{
TInt value = iEnum.ParseL(aValue); // even false, odd true
return (value & 0x01) ? (TBool)ETrue : EFalse;
}
}
return 0;
}
_LIT(KIntFormat, "%d");
EXPORT_C void CSetting::SetL(TInt aNewValue)
{
switch (iType)
{
case ETypeEnum:
{
IoUtils::TEnum _enum(iEnumValues);
CValue::SetL(_enum.GetString(aNewValue), TErrorContext());
iIntValue = aNewValue;
}
break;
case ETypeFilename:
case ETypeString:
case ETypeInteger:
{
TBuf<0x10> buf;
buf.AppendFormat(KIntFormat, aNewValue);
CValue::SetL(buf, TErrorContext());
if (iType == ETypeInteger)
{
iIntValue = aNewValue;
}
}
break;
case ETypeBoolean:
{
CValue::SetL(iEnum.GetString(aNewValue ? 1 : 0), TErrorContext());
iIntValue = aNewValue;
}
break;
}
iIsSet = ETrue;
}
EXPORT_C TInt CSetting::AsInt(TInt& aInt) const
{
if (iType == ETypeEnum || iType == ETypeInteger)
{
aInt = AsInt();
return KErrNone;
}
else return CValue::AsInt(aInt);
}
EXPORT_C TInt CSetting::AsBool(TBool& aBool) const
{
if (iType == ETypeBoolean)
{
aBool = AsBool();
return KErrNone;
}
else return CValue::AsBool(aBool);
}
EXPORT_C TInt CSetting::AsInt() const
{
__ASSERT_ALWAYS(iType == ETypeEnum || iType == ETypeInteger, Panic(EInvalidType));
return iIntValue;
}
EXPORT_C TBool CSetting::AsBool() const
{
__ASSERT_ALWAYS(iType == ETypeBoolean, Panic(EInvalidType));
return iIntValue;
}
EXPORT_C TBool CSetting::IsSet() const
{
return iIsSet;
}
EXPORT_C void CSetting::ClearL()
{
if (IsSet())
{
SetL(iDefault);
iIsSet = EFalse;
}
}
EXPORT_C const TDesC& CSetting::Name()
{
return iName;
}
EXPORT_C const TDesC& CSetting::Description()
{
return iDescription;
}
CSetting::CSetting(TSettingType aType)
: CValue(TErrorContext()), iType(aType), iEnum(KNullDesC)
{
}
void CSetting::ConstructL(const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
{
CValue::ConstructL(aId, KNullDesC);
iName.CreateL(aName);
iDescription.CreateL(aDescription);
if (iType == ETypeEnum)
{
iEnumValues.CreateL(aEnumValues);
RemoveSpaces(iEnumValues);
new(&iEnum)IoUtils::TEnum(iEnumValues); // in-place construct
}
else if (iType == ETypeBoolean)
{
new(&iEnum)IoUtils::TEnum(KBoolValues);
}
iDefaultInt = ParseL(aDefault, aErrorContext);
iDefault.CreateL(aDefault);
iIntValue = iDefaultInt;
CValue::SetL(iDefault, TErrorContext());
}
//______________________________________________________________________________
// CIniFile
EXPORT_C CIniFile* CIniFile::NewL(const TDesC& aIniFile, const TDesC& aInfoFile)
{
CIniFile* self = new(ELeave)CIniFile();
CleanupStack::PushL(self);
self->ConstructL(aIniFile, aInfoFile);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CIniFile::~CIniFile()
{
delete iInfoFile;
iFilename.Close();
}
EXPORT_C CSetting* CIniFile::GetSetting(const TDesC& aId)
{
return (CSetting*)iValues.Find(aId);
}
EXPORT_C const TDesC& CIniFile::GetString(const TDesC& aId)
{
CSetting* setting = GetSetting(aId);
__ASSERT_ALWAYS(setting, Panic(ENotDefined));
return setting->Value();
}
EXPORT_C TInt CIniFile::GetInt(const TDesC& aId)
{
CSetting* setting = GetSetting(aId);
__ASSERT_ALWAYS(setting, Panic(ENotDefined));
return setting->AsInt();
}
EXPORT_C TBool CIniFile::GetBool(const TDesC& aId)
{
CSetting* setting = GetSetting(aId);
__ASSERT_ALWAYS(setting, Panic(ENotDefined));
return setting->AsBool();
}
EXPORT_C void CIniFile::SetL(const TDesC& aId, const TDesC& aString)
{
CSetting* setting = GetSetting(aId);
__ASSERT_ALWAYS(setting, Panic(ENotDefined));
setting->SetL(aString, TErrorContext());
}
EXPORT_C void CIniFile::SetL(const TDesC& aId, TInt aInt)
{
CSetting* setting = GetSetting(aId);
__ASSERT_ALWAYS(setting, Panic(ENotDefined));
setting->SetL(aInt);
}
CValue* CIniFile::CreateValueLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
{
ASSERT(0);
CSetting* setting = CSetting::NewLC(ETypeString, aId, aId, KNullDesC, KNullDesC, KNullDesC, aErrorContext);
setting->SetL(aValue, aErrorContext);
return setting;
}
void CIniFile::HandleValueL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext, TBool aOverwrite)
{
if (!iInfoFile) StaticLeaveIfErr(KErrCorrupt, _L("%SNo description file has been specified"), &aErrorContext.StringLC());
CSetting* setting = GetSetting(aId);
if (setting)
{
if (setting->IsSet() && (!aOverwrite))
{
StaticLeaveIfErr(KErrAlreadyExists, _L("%Sid '%S' already defined on line %d"), &aErrorContext.StringLC(), &aId, setting->LineNumber());
}
setting->SetL(aValue, aErrorContext);
}
else
{
StaticLeaveIfErr(KErrCorrupt, _L("%Sid '%S' not recognised"), &aErrorContext.StringLC(), &aId);
}
}
_LIT(KFirstLineCommentMatch, "!iniedit ");
_LIT(KOptionInfoFile, "-i");
void CIniFile::HandleFirstLineCommentL(const TDesC& aComment, TErrorContext aErrorContext)
{
if (!iInfoFile)
{
if (aComment.Left(KFirstLineCommentMatch().Length()).CompareF(KFirstLineCommentMatch)==0)
{
//TODO see if we can do something better here, maybe reusing CCommandBase's option parsing?
// remove the matched string, without the wildcard
TLex lex(aComment.Mid(KFirstLineCommentMatch().Length()));
lex.SkipSpace();
while (!lex.Eos())
{
TPtrC next(lex.NextToken());
lex.SkipSpace();
if (next.Compare(KOptionInfoFile)==0 && !lex.Eos())
{
TPtrC infoFile(lex.NextToken());
lex.SkipSpace();
ReadInfoFileL(infoFile, aErrorContext);
}
}
}
}
}
TBool CIniFile::IncludeValue(const CValue* aValue) const
{
return ((const CSetting*)aValue)->IsSet();
}
void CIniFile::DoRemoveL(CValue* aValue)
{
static_cast<CSetting*>(aValue)->ClearL();
}
CIniFile::CIniFile()
{
}
_LIT(KSpace, " ");
void CIniFile::ConstructL(const TDesC& aIniFile, const TDesC& aInfoFile)
{
if (aInfoFile.Length()!=0)
{
ReadInfoFileL(aInfoFile, TErrorContext());
}
ReadIniFileL(aIniFile, *this, TErrorContext(), aIniFile.Length() ? ESucceedIfFileNotFound : EFailIfFileNotFound);
iFilename.CreateL(aIniFile);
if ((iFirstLineComment.Length()==0) && (aInfoFile.Length()!=0))
{
// construct the first line comment if it doesn't exist in the file, and we have an IDF file
iFirstLineComment.Close();
iFirstLineComment.CreateL(aInfoFile.Length() + KFirstLineCommentMatch().Length() + KOptionInfoFile().Length() + 1);
iFirstLineComment.Append(KFirstLineCommentMatch);
iFirstLineComment.Append(KOptionInfoFile);
iFirstLineComment.Append(KSpace);
iFirstLineComment.Append(aInfoFile);
}
}
_LIT(KDot, ".");
_LIT(KNameFmt, "%S.name");
_LIT(KDescriptionFmt, "%S.description");
_LIT(KEnumValuesFmt, "%S.values");
_LIT(KDefaultFmt, "%S.default");
_LIT(KTypeEnum, "enum,filename,string,integer,boolean");
void CIniFile::ReadInfoFileL(const TDesC& aFilename, TErrorContext aErrorContext)
{
if (iInfoFile) return;
iInfoFile = CIniReader::NewL(aFilename, aErrorContext);
IoUtils::TEnum typeEnum(KTypeEnum);
IoUtils::CTextBuffer* idBuf = IoUtils::CTextBuffer::NewLC(8);
RArray<const TPtrC> ids;
CleanupClosePushL(ids);
iInfoFile->GetIdsL(ids);
for (TInt i=0; i<ids.Count(); ++i)
{
if (ids[i].Find(KDot) == KErrNotFound)
{
const TDesC& id = ids[i];
TSettingType type = (TSettingType)typeEnum.ParseL(*iInfoFile->GetValue(id));
idBuf->Reset();
idBuf->AppendFormatL(KNameFmt, &id);
const TDesC* name = iInfoFile->GetValue(idBuf->Descriptor());
idBuf->Reset();
idBuf->AppendFormatL(KDescriptionFmt, &id);
const TDesC* description = iInfoFile->GetValue(idBuf->Descriptor());
idBuf->Reset();
idBuf->AppendFormatL(KDefaultFmt, &id);
const TDesC* defaultValue = iInfoFile->GetValue(idBuf->Descriptor());
const TDesC* enumValues = NULL;
if (type == ETypeEnum)
{
idBuf->Reset();
idBuf->AppendFormatL(KEnumValuesFmt, &id);
enumValues = iInfoFile->GetValue(idBuf->Descriptor());
if (!enumValues) StaticLeaveIfErr(KErrCorrupt, _L("%S: enum '%S' doesn't have any values specified (%S.values not defined)"), &aFilename, &id, &id);
}
CSetting* setting = CSetting::NewLC(type, id, name ? *name : id, description ? *description : KNullDesC, defaultValue ? *defaultValue : KNullDesC, enumValues ? *enumValues : KNullDesC, aErrorContext);
iValues.InsertL(&setting->Id(), setting);
CleanupStack::Pop();
}
}
CleanupStack::PopAndDestroy(2, idBuf);// idBuf, ids
}
EXPORT_C void CIniFile::WriteL()
{
IoUtils::TFileName2 iniFile(iFilename);
RFs fs; User::LeaveIfError(fs.Connect());
TInt err = iniFile.FindFile(fs);
if (err==KErrNotFound)
{
if (iniFile.Length()==0) User::Leave(KErrBadName);
if (iniFile[0] != '\\') iniFile.Insert(0, _L("\\"));
iniFile.Insert(0, _L("C:"));
err = fs.MkDirAll(iniFile);
if (err== KErrAlreadyExists) err=KErrNone;
}
fs.Close();
User::LeaveIfError(err);
WriteIniFileL(iniFile, *this);
}