Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// 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);
}