libraries/ltkutils/src/settings.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // settings.cpp
       
     2 // 
       
     3 // Copyright (c) 2009 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/ioutils.h>
       
    14 #include <fshell/settings.h>
       
    15 
       
    16 using namespace LtkUtils;
       
    17 	
       
    18 void Panic(TSettingPanic aReason)
       
    19 	{
       
    20 	User::Panic(KSettingPanic, aReason);
       
    21 	}
       
    22 
       
    23 void RemoveSpaces(TDes& aDes)
       
    24 	{
       
    25 	for (TInt i=aDes.Length()-1; i>=0; --i)
       
    26 		{
       
    27 		if (TChar(aDes[i]).IsSpace()) aDes.Delete(i, 1);
       
    28 		}
       
    29 	}
       
    30 	
       
    31 /*
       
    32 List of valid values for a boolean. Values interpreted as false, true, false, true, etc.
       
    33 i.e. even poitions are false, odd true.
       
    34 */
       
    35 _LIT(KBoolValues, "0,1,off,on,no,yes,false,true");
       
    36 	
       
    37 
       
    38 void HandleLineL(const TDesC& aLine, MValueHandler& aValueHandler, TErrorContext aErrorContext)
       
    39 	{
       
    40 	if (aLine.Length() == 0) return;
       
    41 	if (aLine[0] == '#') // comment
       
    42 		{
       
    43 		aValueHandler.HandleCommentL(aLine.Mid(1), aErrorContext);
       
    44 		}
       
    45 	else
       
    46 		{
       
    47 		TLex lex(aLine);
       
    48 		lex.SkipSpaceAndMark();
       
    49 		lex.SkipCharacters();
       
    50 		TPtrC id(lex.MarkedToken());
       
    51 		lex.SkipSpace();
       
    52 		TPtrC value(lex.Remainder());
       
    53 		if (id.Length())
       
    54 			{
       
    55 			aValueHandler.HandleValueL(id, value, aErrorContext, EFalse);
       
    56 			}
       
    57 		}
       
    58 	}
       
    59 	
       
    60 
       
    61 	
       
    62 _LIT(KNewLine, "\n");
       
    63 
       
    64 EXPORT_C void LtkUtils::ReadIniFileL(const TDesC& aFilename, MValueHandler& aValueHandler, TErrorContext aErrorContext, TFileNotFoundAction aNotFoundAction)
       
    65 	{
       
    66 	RFs fs;
       
    67 	User::LeaveIfError(fs.Connect());
       
    68 	CleanupClosePushL(fs);
       
    69 	
       
    70 	IoUtils::TFileName2 fn(aFilename);
       
    71 	TInt err = fn.FindFile(fs);
       
    72 	if ((err == KErrNotFound) && (aNotFoundAction == ESucceedIfFileNotFound))
       
    73 		{
       
    74 		CleanupStack::PopAndDestroy(&fs);
       
    75 		return;
       
    76 		}
       
    77 	StaticLeaveIfErr(err, _L("%SCannot find file '%S'"), &aErrorContext, &fn);
       
    78 	
       
    79 	RFile file;
       
    80 	StaticLeaveIfErr(file.Open(fs, fn, EFileRead | EFileShareReadersOnly), _L("%SCannot open file '%S'"), &aErrorContext, &fn);
       
    81 	CleanupClosePushL(file);
       
    82 	
       
    83 	IoUtils::CTextBuffer* buf = IoUtils::CTextBuffer::NewLC(0x40);
       
    84 	
       
    85 	TErrorContext context(fn);
       
    86 	TBuf8<0x40> readBuf;
       
    87 	do
       
    88 		{
       
    89 		TInt lineEnd;
       
    90 		do 
       
    91 			{
       
    92 			const TDesC& des(buf->Descriptor());
       
    93 			lineEnd = des.Find(KNewLine);
       
    94 			if (lineEnd != KErrNotFound)
       
    95 				{
       
    96 				TPtrC line(des.Left(lineEnd));
       
    97 				if (line.Length() > 0)
       
    98 					{
       
    99 					if (line[line.Length()-1] == '\r') line.Set(line.Left(line.Length()-1));
       
   100 					HandleLineL(line, aValueHandler, context);					
       
   101 					}
       
   102 				buf->Delete(0, lineEnd+1);
       
   103 				context.NextLine();
       
   104 				}
       
   105 			} while (lineEnd != KErrNotFound);
       
   106 		
       
   107 		
       
   108 		User::LeaveIfError(file.Read(readBuf));
       
   109 		buf->AppendL(readBuf);
       
   110 		}
       
   111 	while (readBuf.Length() > 0);
       
   112 	
       
   113 	
       
   114 	CleanupStack::PopAndDestroy(3, &fs); // buf, file, fs
       
   115 	}
       
   116 	
       
   117 EXPORT_C void LtkUtils::ReadIniFileL(RIoReadHandle& aReadHandle, MValueHandler& aValueHandler)
       
   118 	{
       
   119 	RBuf lineBuf;
       
   120 	lineBuf.CreateL(0x100);
       
   121 	CleanupClosePushL(lineBuf);
       
   122 	aReadHandle.SetReadModeL(RIoReadHandle::ELine);
       
   123 	TName name;
       
   124 	aReadHandle.ObjectNameL(name);
       
   125 	
       
   126 	TInt err;
       
   127 	TErrorContext context(name);
       
   128 	while ((err = aReadHandle.Read(lineBuf))==KErrNone)
       
   129 		{
       
   130 		HandleLineL(lineBuf, aValueHandler, context);
       
   131 		context.NextLine();
       
   132 		}
       
   133 	if (err!=KErrEof) User::LeaveIfError(err);
       
   134 	
       
   135 	CleanupStack::PopAndDestroy(&lineBuf);
       
   136 	}
       
   137 	
       
   138 TInt ValueLineNumberOrder(const CValue& aRodger, const CValue& aMinnie)
       
   139 	{
       
   140 	return aRodger.LineNumber() - aMinnie.LineNumber();
       
   141 	}
       
   142 	
       
   143 EXPORT_C void LtkUtils::WriteIniFileL(const TDesC& aFilename, CIniReader& aValues)
       
   144 	{
       
   145 	RFs fs;
       
   146 	User::LeaveIfError(fs.Connect());
       
   147 	CleanupClosePushL(fs);
       
   148 
       
   149 	RFile file;
       
   150 	StaticLeaveIfErr(file.Replace(fs, aFilename, EFileWrite | EFileShareExclusive), _L("Cannot open '%S' for writing"), &aFilename);
       
   151 	CleanupClosePushL(file);
       
   152 	
       
   153 
       
   154 	IoUtils::CTextFormatter* formatter = IoUtils::CTextFormatter::NewLC(KMaxTInt);
       
   155 	aValues.AppendFirstLineL(formatter);
       
   156 
       
   157 	RPointerArray<CValue> values;
       
   158 	CleanupClosePushL(values);
       
   159 	aValues.GetValuesL(values);
       
   160 	values.Sort(TLinearOrder<CValue>(ValueLineNumberOrder));
       
   161 	
       
   162 	IoUtils::CTextBuffer* buf = IoUtils::CTextBuffer::NewLC(0x20);	
       
   163 	for (TInt i=0; i<values.Count(); ++i)
       
   164 		{
       
   165 		buf->AppendFormatL(_L("%S\t%S\r\n"), &values[i]->Id(), &values[i]->Value());
       
   166 		}
       
   167 
       
   168 	formatter->TabulateL(0, 4, buf->Descriptor(), IoUtils::EIgnoreAvailableWidth);
       
   169 	
       
   170 	User::LeaveIfError(file.Write(formatter->Collapse()));
       
   171 	
       
   172 	CleanupStack::PopAndDestroy(5, &fs); // fs, file, values, buf, formatter
       
   173 	}
       
   174 	
       
   175 //______________________________________________________________________________
       
   176 //						TErrorContext
       
   177 EXPORT_C TErrorContext::TErrorContext()
       
   178 	: iFilename(KNullDesC), iLineNumber(0)
       
   179 	{
       
   180 	}
       
   181 
       
   182 EXPORT_C TErrorContext::TErrorContext(const TDesC& aFilename)
       
   183 	: iFilename(aFilename), iLineNumber(1)
       
   184 	{
       
   185 	}
       
   186 
       
   187 EXPORT_C void TErrorContext::NextLine()
       
   188 	{
       
   189 	iLineNumber++;
       
   190 	}
       
   191 
       
   192 EXPORT_C TInt TErrorContext::LineNumber()
       
   193 	{
       
   194 	return iLineNumber;
       
   195 	}
       
   196 
       
   197 EXPORT_C const TDesC& TErrorContext::StringLC()
       
   198 	{
       
   199 	_LIT(KErrorContextFmt, "%S:%d: ");
       
   200 	if (iFilename.Length() && iLineNumber>0)
       
   201 		{
       
   202 		HBufC* string = HBufC::NewLC(iFilename.Length()+0x10);
       
   203 		string->Des().AppendFormat(KErrorContextFmt, &iFilename, iLineNumber);
       
   204 		return *string;
       
   205 		}
       
   206 	else
       
   207 		{
       
   208 		CleanupStack::PushL((void*)NULL);
       
   209 		return KNullDesC;
       
   210 		}
       
   211 	
       
   212 	}
       
   213 
       
   214 	
       
   215 //______________________________________________________________________________
       
   216 //						CValue
       
   217 EXPORT_C CValue* CValue::NewL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
       
   218 	{
       
   219 	CValue* self = CValue::NewLC(aId, aValue, aErrorContext);
       
   220 	CleanupStack::Pop(self);
       
   221 	return self;
       
   222 	}
       
   223 
       
   224 EXPORT_C CValue* CValue::NewLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
       
   225 	{
       
   226 	CValue* self = new(ELeave)CValue(aErrorContext);
       
   227 	CleanupStack::PushL(self);
       
   228 	self->ConstructL(aId, aValue);
       
   229 	return self;
       
   230 	}
       
   231 
       
   232 EXPORT_C CValue::~CValue()
       
   233 	{
       
   234 	iId.Close();
       
   235 	iValue.Close();
       
   236 	}
       
   237 
       
   238 EXPORT_C const TDesC& CValue::Id() const
       
   239 	{
       
   240 	return iId;
       
   241 	}
       
   242 
       
   243 EXPORT_C const TDesC& CValue::Value() const
       
   244 	{
       
   245 	return iValue;
       
   246 	}
       
   247 
       
   248 EXPORT_C void CValue::SetL(const TDesC& aNewValue, TErrorContext aErrorContext)
       
   249 	{
       
   250 	if (iValue.MaxLength() < aNewValue.Length())
       
   251 		{
       
   252 		RBuf newValue;
       
   253 		newValue.CreateL(aNewValue.Length());
       
   254 		newValue.Swap(iValue);
       
   255 		newValue.Close();
       
   256 		}
       
   257 	if (aErrorContext.LineNumber() > 0) iLineNumber = aErrorContext.LineNumber();
       
   258 	iValue.Copy(aNewValue);
       
   259 	}
       
   260 	
       
   261 EXPORT_C TInt CValue::LineNumber() const
       
   262 	{
       
   263 	return iLineNumber;
       
   264 	}
       
   265 	
       
   266 EXPORT_C TInt CValue::AsInt(TInt& aInt) const
       
   267 	{
       
   268 	TLex lex(iValue);
       
   269 	TInt err = lex.Val(aInt);
       
   270 	if (err == KErrNone)
       
   271 		{
       
   272 		if (lex.Remainder().Length()) err = KErrArgument;
       
   273 		}
       
   274 	return err;
       
   275 	}
       
   276 
       
   277 EXPORT_C TInt CValue::AsBool(TBool& aBool) const
       
   278 	{
       
   279 	IoUtils::TEnum truth(KBoolValues);
       
   280 	TInt i;
       
   281 	TInt err = truth.Parse(iValue, i);
       
   282 	if (err==KErrNone)
       
   283 		{
       
   284 		aBool = i & 0x01;
       
   285 		}
       
   286 	return err;
       
   287 	}
       
   288 	
       
   289 EXPORT_C TInt CValue::AsIntL() const
       
   290 	{
       
   291 	TInt i;
       
   292 	StaticLeaveIfErr(AsInt(i), _L("'%S' value '%S' is not a valid integer"), &iId ,&iValue);
       
   293 	return i;
       
   294 	}
       
   295 	
       
   296 EXPORT_C TBool CValue::AsBoolL() const
       
   297 	{
       
   298 	TBool b;
       
   299 	StaticLeaveIfErr(AsBool(b), _L("'%S' value '%S' is not a valid boolean"), &iId, &iValue);
       
   300 	return b;
       
   301 	}
       
   302 
       
   303 
       
   304 CValue::CValue(TErrorContext aErrorContext)
       
   305 	: iLineNumber(aErrorContext.LineNumber())
       
   306 	{
       
   307 	}
       
   308 
       
   309 void CValue::ConstructL(const TDesC& aId, const TDesC& aValue)
       
   310 	{
       
   311 	iId.CreateL(aId);
       
   312 	iValue.CreateL(aValue);
       
   313 	}
       
   314 	
       
   315 //______________________________________________________________________________
       
   316 //						CIniReader
       
   317 EXPORT_C CIniReader* CIniReader::NewL(const TDesC& aFilename, TErrorContext aErrorContext)
       
   318 	{
       
   319 	CIniReader* self = new(ELeave)CIniReader();
       
   320 	CleanupStack::PushL(self);
       
   321 	ReadIniFileL(aFilename, *self, aErrorContext, EFailIfFileNotFound);
       
   322 	CleanupStack::Pop(self);
       
   323 	return self;
       
   324 	}
       
   325 	
       
   326 CIniReader::CIniReader()
       
   327 	{
       
   328 	}
       
   329 
       
   330 EXPORT_C CIniReader::~CIniReader()
       
   331 	{
       
   332 	TPtrHashMapIter<TDesC, CValue> iter(iValues);
       
   333 	while (iter.NextValue())
       
   334 		{
       
   335 		const CValue* val = iter.CurrentValue();
       
   336 		iter.RemoveCurrent();
       
   337 		delete val;
       
   338 		}
       
   339 	iValues.Close();
       
   340 	iFirstLineComment.Close();
       
   341 	}
       
   342 
       
   343 EXPORT_C const TDesC* CIniReader::GetValue(const TDesC& aId) const
       
   344 	{
       
   345 	const CValue* value = iValues.Find(aId);
       
   346 	if (value)
       
   347 		{
       
   348 		return &value->Value();
       
   349 		}
       
   350 	else
       
   351 		{
       
   352 		return NULL;
       
   353 		}
       
   354 	}
       
   355 
       
   356 
       
   357 EXPORT_C void CIniReader::GetValuesL(RPointerArray<CValue>& aValues)
       
   358 	{
       
   359 	TPtrHashMapIter<TDesC, CValue> iter(iValues);
       
   360 	while (iter.NextValue())
       
   361 		{
       
   362 		if (IncludeValue(iter.CurrentValue())) aValues.AppendL(iter.CurrentValue());
       
   363 		}
       
   364 	}
       
   365 	
       
   366 EXPORT_C void CIniReader::GetValuesL(RPointerArray<const CValue>& aValues) const
       
   367 	{
       
   368 	TPtrHashMapIter<TDesC, CValue> iter(iValues);
       
   369 	while (iter.NextValue())
       
   370 		{
       
   371 		if (IncludeValue(iter.CurrentValue())) aValues.AppendL(iter.CurrentValue());
       
   372 		}
       
   373 	}
       
   374 
       
   375 	
       
   376 EXPORT_C void CIniReader::GetIdsL(RArray<const TPtrC>& aIds) const
       
   377 	{
       
   378 	TPtrHashMapIter<TDesC, CValue> iter(iValues);
       
   379 	while (iter.NextValue())
       
   380 		{
       
   381 		aIds.AppendL(*iter.CurrentKey());
       
   382 		}
       
   383 	}
       
   384 	
       
   385 EXPORT_C void CIniReader::SetValueL(const TDesC& aId, const TDesC& aValue)
       
   386 	{
       
   387 	CValue* value = iValues.Find(aId);
       
   388 	if (value)
       
   389 		{
       
   390 		value->SetL(aValue, TErrorContext());
       
   391 		}
       
   392 	else
       
   393 		{
       
   394 		HandleValueL(aId, aValue, TErrorContext(), ETrue);
       
   395 		}
       
   396 	}
       
   397 	
       
   398 EXPORT_C void CIniReader::RemoveValueL(const TDesC& aId)
       
   399 	{
       
   400 	CValue* value = iValues.Find(aId);
       
   401 	if (value)
       
   402 		{
       
   403 		DoRemoveL(value);
       
   404 		}
       
   405 	}
       
   406 	
       
   407 void CIniReader::DoRemoveL(CValue* aValue)
       
   408 	{
       
   409 	iValues.Remove(&aValue->Id());
       
   410 	delete aValue;
       
   411 	}
       
   412 	
       
   413 void CIniReader::AppendFirstLineL(IoUtils::CTextFormatter* aFormatter)
       
   414 	{
       
   415 	if (iFirstLineComment.Length())
       
   416 		{
       
   417 		aFormatter->AppendFormatL(_L("#%S\r\n"), &iFirstLineComment);
       
   418 		}
       
   419 	}
       
   420 	
       
   421 void CIniReader::HandleValueL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext, TBool aOverwrite)
       
   422 	{
       
   423 	CValue* value = iValues.Find(aId);
       
   424 	if (!value)
       
   425 		{
       
   426 		value = CreateValueLC(aId, aValue, aErrorContext);
       
   427 		iValues.InsertL(&value->Id(), value);
       
   428 		CleanupStack::Pop(value);
       
   429 		}
       
   430 	else
       
   431 		{
       
   432 		if (aOverwrite)
       
   433 			{
       
   434 			value->SetL(aValue, aErrorContext);
       
   435 			}
       
   436 		// else ignore the duplicate value
       
   437 		}
       
   438 	}
       
   439 	
       
   440 void CIniReader::HandleCommentL(const TDesC& aComment, TErrorContext aErrorContext)
       
   441 	{
       
   442 	if (aErrorContext.LineNumber() == 1)
       
   443 		{
       
   444 		iFirstLineComment.Close();
       
   445 		iFirstLineComment.CreateL(aComment);
       
   446 		HandleFirstLineCommentL(iFirstLineComment, aErrorContext);
       
   447 		}
       
   448 	}
       
   449 	
       
   450 CValue* CIniReader::CreateValueLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
       
   451 	{
       
   452 	return CValue::NewLC(aId, aValue, aErrorContext);
       
   453 	}
       
   454 
       
   455 //______________________________________________________________________________
       
   456 //						CSetting
       
   457 EXPORT_C CSetting* CSetting::NewL(TSettingType aType, const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
       
   458 	{
       
   459 	CSetting* self = CSetting::NewLC(aType, aId, aName, aDescription, aDefault, aEnumValues, aErrorContext);
       
   460 	CleanupStack::Pop(self);
       
   461 	return self;
       
   462 	}
       
   463 	
       
   464 EXPORT_C CSetting* CSetting::NewLC(TSettingType aType, const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
       
   465 	{
       
   466 	CSetting* self = new(ELeave)CSetting(aType);
       
   467 	CleanupStack::PushL(self);
       
   468 	self->ConstructL(aId, aName, aDescription, aDefault, aEnumValues, aErrorContext);
       
   469 	return self;
       
   470 	}
       
   471 	
       
   472 EXPORT_C CSetting::~CSetting()
       
   473 	{
       
   474 	iName.Close();
       
   475 	iDescription.Close();
       
   476 	iEnumValues.Close();
       
   477 	iDefault.Close();
       
   478 	}
       
   479 
       
   480 EXPORT_C void CSetting::SetL(const TDesC& aNewValue, TErrorContext aErrorContext)
       
   481 	{
       
   482 	TInt value = ParseL(aNewValue, aErrorContext);
       
   483 	switch (iType)
       
   484 		{
       
   485 	case ETypeEnum:
       
   486 			{
       
   487 			CValue::SetL(iEnum.GetString(value), aErrorContext);
       
   488 			iIntValue = value;
       
   489 			}
       
   490 		break;
       
   491 	case ETypeFilename:
       
   492 	case ETypeString:
       
   493 		CValue::SetL(aNewValue, aErrorContext);
       
   494 		break;
       
   495 	case ETypeInteger:
       
   496 			{
       
   497 			CValue::SetL(aNewValue, aErrorContext);
       
   498 			iIntValue = value;
       
   499 			}
       
   500 		break;
       
   501 	case ETypeBoolean:
       
   502 			{
       
   503 			IoUtils::TEnum truth(KBoolValues);
       
   504 			TInt value = truth.ParseL(aNewValue); // even false, odd true
       
   505 			CValue::SetL(truth.GetString(value), aErrorContext);
       
   506 			iIntValue = (value & 0x01) ? (TBool)ETrue : EFalse;
       
   507 			}
       
   508 		break;
       
   509 		}
       
   510 	iIsSet = ETrue;
       
   511 	}
       
   512 	
       
   513 TInt CSetting::ParseL(const TDesC& aValue, TErrorContext aErrorContext)
       
   514 	{
       
   515 	switch (iType)
       
   516 		{
       
   517 	case ETypeEnum:
       
   518 			return iEnum.ParseL(aValue);
       
   519 	case ETypeFilename:
       
   520 	case ETypeString:
       
   521 		return 0;
       
   522 	case ETypeInteger:
       
   523 			{
       
   524 			TLex lex(aValue);
       
   525 			TInt value;
       
   526 			lex.SkipSpace();
       
   527 			StaticLeaveIfErr(lex.Val(value), _L("%S'%S' value '%S' is not a valid integer"), &aErrorContext.StringLC(), &Id(), &aValue);
       
   528 			lex.SkipSpace();
       
   529 			if (lex.Remainder().Length()) StaticLeaveIfErr(KErrArgument, _L("%S'%S' value '%S' is not a valid integer"), &aErrorContext.StringLC(), &Id(), &aValue);
       
   530 			return value;
       
   531 			}
       
   532 	case ETypeBoolean:
       
   533 			{
       
   534 			TInt value = iEnum.ParseL(aValue); // even false, odd true
       
   535 			return (value & 0x01) ? (TBool)ETrue : EFalse;
       
   536 			}
       
   537 		}
       
   538 	return 0;
       
   539 	}
       
   540 	
       
   541 _LIT(KIntFormat, "%d");
       
   542 	
       
   543 EXPORT_C void CSetting::SetL(TInt aNewValue)
       
   544 	{
       
   545 	switch (iType)
       
   546 		{
       
   547 	case ETypeEnum:
       
   548 			{
       
   549 			IoUtils::TEnum _enum(iEnumValues);
       
   550 			CValue::SetL(_enum.GetString(aNewValue), TErrorContext());
       
   551 			iIntValue = aNewValue;
       
   552 			}
       
   553 		break;
       
   554 	case ETypeFilename:
       
   555 	case ETypeString:
       
   556 	case ETypeInteger:
       
   557 			{
       
   558 			TBuf<0x10> buf;
       
   559 			buf.AppendFormat(KIntFormat, aNewValue);
       
   560 			CValue::SetL(buf, TErrorContext());
       
   561 			if (iType == ETypeInteger)
       
   562 				{
       
   563 				iIntValue = aNewValue;
       
   564 				}
       
   565 			}
       
   566 		break;
       
   567 	case ETypeBoolean:
       
   568 			{
       
   569 			CValue::SetL(iEnum.GetString(aNewValue ? 1 : 0), TErrorContext());
       
   570 			iIntValue = aNewValue;
       
   571 			}
       
   572 		break;
       
   573 		}
       
   574 	iIsSet = ETrue;
       
   575 	}
       
   576 	
       
   577 EXPORT_C TInt CSetting::AsInt(TInt& aInt) const
       
   578 	{
       
   579 	if (iType == ETypeEnum || iType == ETypeInteger)
       
   580 		{
       
   581 		aInt = AsInt();
       
   582 		return KErrNone;
       
   583 		}
       
   584 	else return CValue::AsInt(aInt);
       
   585 	}
       
   586 	
       
   587 EXPORT_C TInt CSetting::AsBool(TBool& aBool) const
       
   588 	{
       
   589 	if (iType == ETypeBoolean)
       
   590 		{
       
   591 		aBool = AsBool();
       
   592 		return KErrNone;
       
   593 		}
       
   594 	else return CValue::AsBool(aBool);
       
   595 	}
       
   596 
       
   597 EXPORT_C TInt CSetting::AsInt() const
       
   598 	{
       
   599 	__ASSERT_ALWAYS(iType == ETypeEnum || iType == ETypeInteger, Panic(EInvalidType));
       
   600 	return iIntValue;
       
   601 	}
       
   602 	
       
   603 EXPORT_C TBool CSetting::AsBool() const
       
   604 	{
       
   605 	__ASSERT_ALWAYS(iType == ETypeBoolean, Panic(EInvalidType));
       
   606 	return iIntValue;
       
   607 	}
       
   608 	
       
   609 EXPORT_C TBool CSetting::IsSet() const
       
   610 	{
       
   611 	return iIsSet;
       
   612 	}
       
   613 	
       
   614 EXPORT_C void CSetting::ClearL()
       
   615 	{
       
   616 	if (IsSet())
       
   617 		{
       
   618 		SetL(iDefault);
       
   619 		iIsSet = EFalse;
       
   620 		}
       
   621 	}
       
   622 	
       
   623 EXPORT_C const TDesC& CSetting::Name()
       
   624 	{
       
   625 	return iName;
       
   626 	}
       
   627 	
       
   628 EXPORT_C const TDesC& CSetting::Description()
       
   629 	{
       
   630 	return iDescription;
       
   631 	}
       
   632 
       
   633 CSetting::CSetting(TSettingType aType)
       
   634 	: CValue(TErrorContext()), iType(aType), iEnum(KNullDesC)
       
   635 	{
       
   636 	}
       
   637 
       
   638 void CSetting::ConstructL(const TDesC& aId, const TDesC& aName, const TDesC& aDescription, const TDesC& aDefault, const TDesC& aEnumValues, TErrorContext aErrorContext)
       
   639 	{
       
   640 	CValue::ConstructL(aId, KNullDesC);
       
   641 	iName.CreateL(aName);
       
   642 	iDescription.CreateL(aDescription);
       
   643 	
       
   644 	if (iType == ETypeEnum)
       
   645 		{
       
   646 		iEnumValues.CreateL(aEnumValues);
       
   647 		RemoveSpaces(iEnumValues);
       
   648 		new(&iEnum)IoUtils::TEnum(iEnumValues); // in-place construct
       
   649 		}
       
   650 	else if (iType == ETypeBoolean)
       
   651 		{
       
   652 		new(&iEnum)IoUtils::TEnum(KBoolValues);
       
   653 		}
       
   654 
       
   655 	iDefaultInt = ParseL(aDefault, aErrorContext);
       
   656 	iDefault.CreateL(aDefault);
       
   657 	
       
   658 	iIntValue = iDefaultInt;
       
   659 	CValue::SetL(iDefault, TErrorContext());
       
   660 	}
       
   661 
       
   662 	
       
   663 //______________________________________________________________________________
       
   664 //						CIniFile
       
   665 EXPORT_C CIniFile* CIniFile::NewL(const TDesC& aIniFile, const TDesC& aInfoFile)
       
   666 	{
       
   667 	CIniFile* self = new(ELeave)CIniFile();
       
   668 	CleanupStack::PushL(self);
       
   669 	self->ConstructL(aIniFile, aInfoFile);
       
   670 	CleanupStack::Pop(self);
       
   671 	return self;
       
   672 	}
       
   673 
       
   674 EXPORT_C CIniFile::~CIniFile()
       
   675 	{
       
   676 	delete iInfoFile;
       
   677 	iFilename.Close();
       
   678 	}
       
   679 
       
   680 EXPORT_C CSetting* CIniFile::GetSetting(const TDesC& aId)
       
   681 	{
       
   682 	return (CSetting*)iValues.Find(aId);
       
   683 	}
       
   684 	
       
   685 EXPORT_C const TDesC& CIniFile::GetString(const TDesC& aId)
       
   686 	{
       
   687 	CSetting* setting = GetSetting(aId);
       
   688 	__ASSERT_ALWAYS(setting, Panic(ENotDefined));
       
   689 	return setting->Value();
       
   690 	}
       
   691 	
       
   692 EXPORT_C TInt CIniFile::GetInt(const TDesC& aId)
       
   693 	{
       
   694 	CSetting* setting = GetSetting(aId);
       
   695 	__ASSERT_ALWAYS(setting, Panic(ENotDefined));
       
   696 	return setting->AsInt();
       
   697 	}
       
   698 	
       
   699 EXPORT_C TBool CIniFile::GetBool(const TDesC& aId)
       
   700 	{
       
   701 	CSetting* setting = GetSetting(aId);
       
   702 	__ASSERT_ALWAYS(setting, Panic(ENotDefined));
       
   703 	return setting->AsBool();
       
   704 	}
       
   705 	
       
   706 EXPORT_C void CIniFile::SetL(const TDesC& aId, const TDesC& aString)
       
   707 	{
       
   708 	CSetting* setting = GetSetting(aId);
       
   709 	__ASSERT_ALWAYS(setting, Panic(ENotDefined));
       
   710 	setting->SetL(aString, TErrorContext());
       
   711 	}
       
   712 	
       
   713 EXPORT_C void CIniFile::SetL(const TDesC& aId, TInt aInt)
       
   714 	{
       
   715 	CSetting* setting = GetSetting(aId);
       
   716 	__ASSERT_ALWAYS(setting, Panic(ENotDefined));
       
   717 	setting->SetL(aInt);
       
   718 	}
       
   719 
       
   720 CValue* CIniFile::CreateValueLC(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext)
       
   721 	{
       
   722 	ASSERT(0);
       
   723 	CSetting* setting = CSetting::NewLC(ETypeString, aId, aId, KNullDesC, KNullDesC, KNullDesC, aErrorContext);
       
   724 	setting->SetL(aValue, aErrorContext);
       
   725 	return setting;
       
   726 	}
       
   727 
       
   728 void CIniFile::HandleValueL(const TDesC& aId, const TDesC& aValue, TErrorContext aErrorContext, TBool aOverwrite)
       
   729 	{
       
   730 	if (!iInfoFile) StaticLeaveIfErr(KErrCorrupt, _L("%SNo description file has been specified"), &aErrorContext.StringLC());
       
   731 	CSetting* setting = GetSetting(aId);
       
   732 	if (setting)
       
   733 		{
       
   734 		if (setting->IsSet() && (!aOverwrite))
       
   735 			{
       
   736 			StaticLeaveIfErr(KErrAlreadyExists, _L("%Sid '%S' already defined on line %d"), &aErrorContext.StringLC(), &aId, setting->LineNumber());
       
   737 			}
       
   738 		setting->SetL(aValue, aErrorContext);
       
   739 		}
       
   740 	else
       
   741 		{
       
   742 		StaticLeaveIfErr(KErrCorrupt, _L("%Sid '%S' not recognised"), &aErrorContext.StringLC(), &aId);
       
   743 		}
       
   744 	}
       
   745 	
       
   746 _LIT(KFirstLineCommentMatch, "!iniedit ");
       
   747 _LIT(KOptionInfoFile, "-i");
       
   748 
       
   749 void CIniFile::HandleFirstLineCommentL(const TDesC& aComment, TErrorContext aErrorContext)
       
   750 	{
       
   751 	if (!iInfoFile)
       
   752 		{
       
   753 		if (aComment.Left(KFirstLineCommentMatch().Length()).CompareF(KFirstLineCommentMatch)==0)
       
   754 			{
       
   755 			//TODO see if we can do something better here, maybe reusing CCommandBase's option parsing?
       
   756 					// remove the matched string, without the wildcard
       
   757 			TLex lex(aComment.Mid(KFirstLineCommentMatch().Length()));
       
   758 			lex.SkipSpace();
       
   759 			while (!lex.Eos())
       
   760 				{
       
   761 				TPtrC next(lex.NextToken());
       
   762 				lex.SkipSpace();
       
   763 				if (next.Compare(KOptionInfoFile)==0 && !lex.Eos())
       
   764 					{
       
   765 					TPtrC infoFile(lex.NextToken());
       
   766 					lex.SkipSpace();
       
   767 					
       
   768 					ReadInfoFileL(infoFile, aErrorContext);					
       
   769 					}
       
   770 				}
       
   771 			}
       
   772 		}
       
   773 	}
       
   774 	
       
   775 TBool CIniFile::IncludeValue(const CValue* aValue) const
       
   776 	{
       
   777 	return ((const CSetting*)aValue)->IsSet();
       
   778 	}
       
   779 	
       
   780 void CIniFile::DoRemoveL(CValue* aValue)
       
   781 	{
       
   782 	static_cast<CSetting*>(aValue)->ClearL();
       
   783 	}
       
   784 
       
   785 CIniFile::CIniFile()
       
   786 	{
       
   787 	}
       
   788 	
       
   789 _LIT(KSpace, " ");
       
   790 
       
   791 void CIniFile::ConstructL(const TDesC& aIniFile, const TDesC& aInfoFile)
       
   792 	{
       
   793 	if (aInfoFile.Length()!=0)
       
   794 		{
       
   795 		ReadInfoFileL(aInfoFile, TErrorContext());
       
   796 		
       
   797 		}
       
   798 	ReadIniFileL(aIniFile, *this, TErrorContext(), aIniFile.Length() ? ESucceedIfFileNotFound : EFailIfFileNotFound);
       
   799 	iFilename.CreateL(aIniFile);
       
   800 	
       
   801 	if ((iFirstLineComment.Length()==0) && (aInfoFile.Length()!=0))
       
   802 		{
       
   803 		// construct the first line comment if it doesn't exist in the file, and we have an IDF file
       
   804 		iFirstLineComment.Close();
       
   805 		iFirstLineComment.CreateL(aInfoFile.Length() + KFirstLineCommentMatch().Length() + KOptionInfoFile().Length() + 1);
       
   806 		iFirstLineComment.Append(KFirstLineCommentMatch);
       
   807 		iFirstLineComment.Append(KOptionInfoFile);
       
   808 		iFirstLineComment.Append(KSpace);
       
   809 		iFirstLineComment.Append(aInfoFile);
       
   810 		}
       
   811 	}
       
   812 
       
   813 _LIT(KDot, ".");
       
   814 _LIT(KNameFmt, "%S.name");
       
   815 _LIT(KDescriptionFmt, "%S.description");
       
   816 _LIT(KEnumValuesFmt, "%S.values");
       
   817 _LIT(KDefaultFmt, "%S.default");
       
   818 _LIT(KTypeEnum, "enum,filename,string,integer,boolean");
       
   819 
       
   820 void CIniFile::ReadInfoFileL(const TDesC& aFilename, TErrorContext aErrorContext)
       
   821 	{
       
   822 	if (iInfoFile) return;
       
   823 	iInfoFile = CIniReader::NewL(aFilename, aErrorContext);
       
   824 	IoUtils::TEnum typeEnum(KTypeEnum);
       
   825 	IoUtils::CTextBuffer* idBuf = IoUtils::CTextBuffer::NewLC(8);
       
   826 	
       
   827 	RArray<const TPtrC> ids;
       
   828 	CleanupClosePushL(ids);
       
   829 	iInfoFile->GetIdsL(ids);
       
   830 	
       
   831 	for (TInt i=0; i<ids.Count(); ++i)
       
   832 		{
       
   833 		if (ids[i].Find(KDot) == KErrNotFound)
       
   834 			{
       
   835 			const TDesC& id = ids[i];
       
   836 			
       
   837 			TSettingType type = (TSettingType)typeEnum.ParseL(*iInfoFile->GetValue(id));
       
   838 			
       
   839 			idBuf->Reset();
       
   840 			idBuf->AppendFormatL(KNameFmt, &id);
       
   841 			const TDesC* name = iInfoFile->GetValue(idBuf->Descriptor());
       
   842 			
       
   843 			idBuf->Reset();
       
   844 			idBuf->AppendFormatL(KDescriptionFmt, &id);
       
   845 			const TDesC* description = iInfoFile->GetValue(idBuf->Descriptor());
       
   846 			
       
   847 			idBuf->Reset();
       
   848 			idBuf->AppendFormatL(KDefaultFmt, &id);
       
   849 			const TDesC* defaultValue = iInfoFile->GetValue(idBuf->Descriptor());
       
   850 			
       
   851 			const TDesC* enumValues = NULL;
       
   852 			if (type == ETypeEnum)
       
   853 				{
       
   854 				idBuf->Reset();
       
   855 				idBuf->AppendFormatL(KEnumValuesFmt, &id);
       
   856 				enumValues = iInfoFile->GetValue(idBuf->Descriptor());
       
   857 				if (!enumValues) StaticLeaveIfErr(KErrCorrupt, _L("%S: enum '%S' doesn't have any values specified (%S.values not defined)"), &aFilename, &id, &id);
       
   858 				}
       
   859 				
       
   860 			CSetting* setting = CSetting::NewLC(type, id, name ? *name : id, description ? *description : KNullDesC, defaultValue ? *defaultValue : KNullDesC, enumValues ? *enumValues : KNullDesC, aErrorContext);
       
   861 			iValues.InsertL(&setting->Id(), setting);
       
   862 			CleanupStack::Pop();			
       
   863 			}
       
   864 		}
       
   865 	
       
   866 	CleanupStack::PopAndDestroy(2, idBuf);// idBuf, ids
       
   867 	}
       
   868 	
       
   869 EXPORT_C void CIniFile::WriteL()
       
   870 	{
       
   871 	IoUtils::TFileName2 iniFile(iFilename);
       
   872 	
       
   873 	RFs fs; User::LeaveIfError(fs.Connect());
       
   874 	TInt err = iniFile.FindFile(fs);
       
   875 	
       
   876 	if (err==KErrNotFound)
       
   877 		{
       
   878 		if (iniFile.Length()==0) User::Leave(KErrBadName);
       
   879 		if (iniFile[0] != '\\') iniFile.Insert(0, _L("\\"));
       
   880 		iniFile.Insert(0, _L("C:"));
       
   881 		
       
   882 		err = fs.MkDirAll(iniFile);
       
   883 		if (err== KErrAlreadyExists) err=KErrNone;		
       
   884 		}
       
   885 
       
   886 	fs.Close();
       
   887 	User::LeaveIfError(err);
       
   888 	
       
   889 	WriteIniFileL(iniFile, *this);
       
   890 	}
       
   891 
       
   892