libraries/iosrv/client/command_info_file.cpp
changeset 0 7f656887cf89
child 70 b06038904ef8
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // command_info_file.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 <f32file.h>
       
    14 #include "ioutils.h"
       
    15 #include "command_base.h"
       
    16 
       
    17 _LIT(KCifExt, ".cif");
       
    18 _LIT(KCifPathVar, "CIF_PATH");
       
    19 _LIT(KCifPath, "\\resource\\cif\\fshell");
       
    20 _LIT(KEnumSeparator, ",");
       
    21 _LIT(KEnumQuote, "\"");
       
    22 _LIT(KNewLine, "\r\n");
       
    23 _LIT(KPartialCommandStart, "==");
       
    24 _LIT(KCommandStart, "\r\n==");
       
    25 _LIT(KCmndName, "name");
       
    26 _LIT(KCmndShortDescription, "short-description");
       
    27 _LIT(KCmndLongDescription, "long-description");
       
    28 _LIT(KCmndSeeAlso, "see-also");
       
    29 _LIT(KCmndCopyright, "copyright");
       
    30 _LIT(KCmndArgument, "argument");
       
    31 _LIT(KCmndOption, "option");
       
    32 _LIT(KCmndInclude, "include");
       
    33 _LIT(KCmndSubCommand, "sub-command");
       
    34 _LIT(KCmndEnumValue, "enum-value");
       
    35 _LIT(KCmndFlagOptional, "optional");
       
    36 _LIT(KCmndFlagMultiple, "multiple");
       
    37 _LIT(KCmndFlagLast, "last");
       
    38 _LIT(KTypeBool, "bool");
       
    39 _LIT(KTypeInt, "int");
       
    40 _LIT(KTypeUint, "uint");
       
    41 _LIT(KTypeString, "string");
       
    42 _LIT(KTypeFileName, "filename");
       
    43 _LIT(KTypeEnum, "enum");
       
    44 _LIT(KTypeReal, "real");
       
    45 _LIT(KTypeUint64, "uint64");
       
    46 _LIT(KTypeInt64, "int64");
       
    47 
       
    48 using namespace IoUtils;
       
    49 
       
    50 TInt SkipTo(TLex& aLex, const TDesC& aDes)
       
    51 	{
       
    52 	TInt ret = aLex.Remainder().Find(aDes);
       
    53 	if (ret >= 0)
       
    54 		{
       
    55 		aLex.Inc(ret);
       
    56 		return KErrNone;
       
    57 		}
       
    58 	return KErrNotFound;
       
    59 	}
       
    60 
       
    61 TInt SkipToEnd(TLex& aLex, const TDesC& aDes)
       
    62 	{
       
    63 	TInt ret = aLex.Remainder().Find(aDes);
       
    64 	if (ret >= 0)
       
    65 		{
       
    66 		aLex.Inc(ret + aDes.Length());
       
    67 		return KErrNone;
       
    68 		}
       
    69 	return KErrNotFound;
       
    70 	}
       
    71 
       
    72 TInt SkipToNextCommand(TLex& aLex)
       
    73 	{
       
    74 	if ((aLex.Offset() == 0) && (aLex.Remainder().Find(KPartialCommandStart) == 0))
       
    75 		{
       
    76 		return KErrNone;
       
    77 		}
       
    78 
       
    79 	return SkipTo(aLex, KCommandStart);
       
    80 	}
       
    81 
       
    82 TPtrC NextCommand(TLex& aLex)
       
    83 	{
       
    84 	TPtrC command;
       
    85 	if (SkipToNextCommand(aLex) == KErrNone)
       
    86 		{
       
    87 		SkipToEnd(aLex, KPartialCommandStart);
       
    88 		aLex.Mark();
       
    89 		aLex.SkipCharacters();
       
    90 		command.Set(aLex.MarkedToken());
       
    91 		}
       
    92 	else
       
    93 		{
       
    94 		aLex.Inc(aLex.Remainder().Length());
       
    95 		}
       
    96 	return command;
       
    97 	}
       
    98 
       
    99 TPtrC LineRemainder(TLex& aLex)
       
   100 	{
       
   101 	aLex.Mark();
       
   102 	if (SkipTo(aLex, KNewLine) == KErrNone)
       
   103 		{
       
   104 		return aLex.MarkedToken();
       
   105 		}
       
   106 	else
       
   107 		{
       
   108 		return aLex.Remainder();
       
   109 		}
       
   110 	}
       
   111 
       
   112 TPtrC NextWord(TLex& aLex)
       
   113 	{
       
   114 	aLex.SkipSpaceAndMark();
       
   115 	aLex.SkipCharacters();
       
   116 	TPtrC word(aLex.MarkedToken());
       
   117 	return word;
       
   118 	}
       
   119 
       
   120 TPtrC TextToNextCommand(TLex& aLex)
       
   121 	{
       
   122 	aLex.Mark();
       
   123 
       
   124 	if (SkipToNextCommand(aLex) != KErrNone)
       
   125 		{
       
   126 		aLex.Inc(aLex.Remainder().Length());
       
   127 		}
       
   128 
       
   129 	TLex lex(aLex.MarkedToken());
       
   130 	
       
   131 	// Strip leading white space.
       
   132 	while (!lex.Eos())
       
   133 		{
       
   134 		if (lex.Peek().IsSpace())
       
   135 			{
       
   136 			lex.Get();
       
   137 			}
       
   138 		else
       
   139 			{
       
   140 			break;
       
   141 			}
       
   142 		}
       
   143 	lex.Mark();
       
   144 	TInt startOffset = lex.Offset();
       
   145 
       
   146 	// Remove trailing white space.
       
   147 	lex.Inc(lex.Remainder().Length());
       
   148 	while (lex.Offset() > startOffset)
       
   149 		{
       
   150 		lex.UnGet();
       
   151 		if (!lex.Peek().IsSpace())
       
   152 			{
       
   153 			lex.Get();
       
   154 			break;
       
   155 			}
       
   156 		}
       
   157 
       
   158 	return lex.MarkedToken();
       
   159 	}
       
   160 
       
   161 void AppendL(RBuf& aBuf, const TDesC& aDes, TBool aQuote)
       
   162 	{
       
   163 	const TInt requiredSpace = aDes.Length() + ((aBuf.Length() == 0) ? 0 : KEnumSeparator().Length()) + (aQuote ? 2 : 0);
       
   164 	if ((aBuf.Length() + requiredSpace) > aBuf.MaxLength())
       
   165 		{
       
   166 		aBuf.ReAllocL(Max(aBuf.Length() * 2, aBuf.Length() + requiredSpace));
       
   167 		}
       
   168 	if (aBuf.Length() > 0)
       
   169 		{
       
   170 		aBuf.Append(KEnumSeparator);
       
   171 		}
       
   172 	if (aQuote)
       
   173 		{
       
   174 		aBuf.Append(KEnumQuote);
       
   175 		}
       
   176 	aBuf.Append(aDes);
       
   177 	if (aQuote)
       
   178 		{
       
   179 		aBuf.Append(KEnumQuote);
       
   180 		}
       
   181 	}
       
   182 
       
   183 void GetEnumValuesL(TLex& aLex, RBuf& aValues, RBuf& aDescriptions)
       
   184 	{
       
   185 	aValues.CreateL(0x100);
       
   186 	aDescriptions.CreateL(0x100);
       
   187 
       
   188 	while (!aLex.Eos())
       
   189 		{
       
   190 		TLexMark mark;
       
   191 		aLex.Mark(mark);
       
   192 		TPtrC command(NextCommand(aLex));
       
   193 		if (command == KCmndEnumValue)
       
   194 			{
       
   195 			TPtrC value(NextWord(aLex));
       
   196 			TPtrC description(TextToNextCommand(aLex));
       
   197 			if (value.Length() == 0)
       
   198 				{
       
   199 				User::Leave(KErrArgument);
       
   200 				}
       
   201 			AppendL(aValues, value, EFalse);
       
   202 			if (description.Length() > 0)
       
   203 				{
       
   204 				AppendL(aDescriptions, description, ETrue);
       
   205 				}
       
   206 			}
       
   207 		else
       
   208 			{
       
   209 			aLex.UnGetToMark(mark);
       
   210 			break;
       
   211 			}
       
   212 		}
       
   213 	}
       
   214 
       
   215 
       
   216 EXPORT_C CCommandInfoFile* CCommandInfoFile::NewL(RFs& aFs, const TDesC& aFileName)
       
   217 	{
       
   218 	CCommandInfoFile* self = new(ELeave) CCommandInfoFile(aFileName);
       
   219 	CleanupStack::PushL(self);
       
   220 	self->ConstructL(aFs);
       
   221 	CleanupStack::Pop(self);
       
   222 	return self;
       
   223 	}
       
   224 
       
   225 EXPORT_C CCommandInfoFile* CCommandInfoFile::NewL(RFs& aFs, const CEnvironment& aEnvironment, const TDesC& aCommandName)
       
   226 	{
       
   227 	TFileName2 fileName;
       
   228 	TRAPD(err, fileName.Copy(aEnvironment.GetAsDesL(KCifPathVar)));
       
   229 	if (err) fileName.Copy(KCifPath);
       
   230 
       
   231 	// Search the drive the command is running from first (rather than what the session path happens to be, which was the previous behaviour)
       
   232 	if (!fileName.HasDriveLetter()) fileName.Insert(0, _L("?:"));
       
   233 	fileName[0] = RProcess().FileName()[0];
       
   234 
       
   235 	fileName.AppendComponentL(aCommandName);
       
   236 	fileName.SetExtL(KCifExt);
       
   237 	StaticLeaveIfErr(fileName.FindFile(aFs), _L("Couldn't find \"%S\""), &fileName);
       
   238 
       
   239 	CCommandInfoFile* cif = CCommandInfoFile::NewL(aFs, fileName);
       
   240 	if (cif->Name() != aCommandName)
       
   241 		{
       
   242 		CleanupStack::PushL(cif);
       
   243 		StaticLeaveIfErr(KErrArgument, _L("Command named \"%S\" in implementation but \"%S\" in \"%S\""), &aCommandName, &cif->Name(), &fileName);
       
   244 		}
       
   245 	return cif;
       
   246 	}
       
   247 
       
   248 void CCommandInfoFile::ConstructL(RFs& aFs)
       
   249 	{
       
   250 	ReadFileL(aFs, iFileName);
       
   251 	}
       
   252 
       
   253 void CCommandInfoFile::ReadFileL(RFs& aFs, const TDesC& aFileName)
       
   254 	{
       
   255 	// Read the file into a buffer.
       
   256 	RFile file;
       
   257 	StaticLeaveIfErr(file.Open(aFs, aFileName, EFileRead | EFileShareReadersOnly), _L("Couldn't open '%S' for reading"), &aFileName);
       
   258 	CleanupClosePushL(file);
       
   259 	TInt fileSize;
       
   260 	User::LeaveIfError(file.Size(fileSize));
       
   261 	RBuf8 buf8;
       
   262 	buf8.CreateL(fileSize);
       
   263 	buf8.CleanupClosePushL();
       
   264 	User::LeaveIfError(file.Read(buf8));
       
   265 	RBuf& buf = NewBuffer();
       
   266 	buf.CreateL(fileSize);
       
   267 	buf.Copy(buf8);
       
   268 	CleanupStack::PopAndDestroy(2, &file);
       
   269 	TLex lex(buf);
       
   270 	while (!lex.Eos())
       
   271 		{
       
   272 		if (iProcessInclude || !iCurrentChild)
       
   273 			{
       
   274 			ReadDetailsL(lex, aFs, aFileName);
       
   275 			}
       
   276 		else
       
   277 			{
       
   278 			iCurrentChild->ReadDetailsL(lex, aFs, aFileName);
       
   279 			}
       
   280 		}
       
   281 	}
       
   282 
       
   283 void CCommandInfoFile::ReadDetailsL(TLex& aLex, RFs& aFs, const TDesC& aFileName)
       
   284 	{
       
   285 	SkipToNextCommand(aLex); // Ignore everything before the first '==' command.
       
   286 
       
   287 	while (!aLex.Eos())
       
   288 		{
       
   289 		TLexMark mark;
       
   290 		aLex.Mark(mark);
       
   291 		TPtrC command(NextCommand(aLex));
       
   292 		if (command == KNullDesC)
       
   293 			{
       
   294 			// Do nothing - we're at the end of the string.
       
   295 			}
       
   296 		else if (command == KCmndName)
       
   297 			{
       
   298 			aLex.SkipSpaceAndMark();
       
   299 			aLex.SkipCharacters();
       
   300 			iName.Set(aLex.MarkedToken());
       
   301 			}
       
   302 		else if (command == KCmndShortDescription)
       
   303 			{
       
   304 			iShortDescription.Set(TextToNextCommand(aLex));
       
   305 			}
       
   306 		else if (command == KCmndLongDescription)
       
   307 			{
       
   308 			iLongDescription.Set(TextToNextCommand(aLex));
       
   309 			}
       
   310 		else if (command == KCmndSeeAlso)
       
   311 			{
       
   312 			iSeeAlso.Set(TextToNextCommand(aLex));
       
   313 			}
       
   314 		else if (command == KCmndCopyright)
       
   315 			{
       
   316 			iCopyright.Set(TextToNextCommand(aLex));
       
   317 			}
       
   318 		else if (command == KCmndArgument)
       
   319 			{
       
   320 			ReadArgumentL(aLex, aFileName);
       
   321 			}
       
   322 		else if (command == KCmndOption)
       
   323 			{
       
   324 			ReadOptionL(aLex, aFileName);
       
   325 			}
       
   326 		else if (command == KCmndInclude)
       
   327 			{
       
   328 			if (iParent == NULL)
       
   329 				{
       
   330 				iProcessInclude = EFalse;
       
   331 				TLex lineLex(LineRemainder(aLex));
       
   332 				TPtrC fileName(NextWord(lineLex));
       
   333 				TFileName2* fullFileName = new(ELeave) TFileName2(aFileName);
       
   334 				CleanupStack::PushL(fullFileName);
       
   335 				fullFileName->SetNameAndExtL(fileName);
       
   336 				ReadFileL(aFs, *fullFileName);
       
   337 				CleanupStack::PopAndDestroy(fullFileName);
       
   338 				break;
       
   339 				}
       
   340 			else
       
   341 				{
       
   342 				// We're a sub-command. Let control return to the root to handle the include.
       
   343 				aLex.UnGetToMark(mark);
       
   344 				iParent->ProcessInclude(*this);
       
   345 				break;
       
   346 				}
       
   347 			}
       
   348 		else if (command == KCmndSubCommand)
       
   349 			{
       
   350 			if (iParent == NULL)
       
   351 				{
       
   352 				TLex lineLex(LineRemainder(aLex));
       
   353 				AddSubCommandL(lineLex, aLex, aFs, aFileName);
       
   354 				}
       
   355 			else
       
   356 				{
       
   357 				// We're a sub-command. Let control return to the root to handle the next sub-command.
       
   358 				aLex.UnGetToMark(mark);
       
   359 				iParent->ProcessNewChild();
       
   360 				break;
       
   361 				}
       
   362 			}
       
   363 		else
       
   364 			{
       
   365 			StaticLeaveIfErr(KErrArgument, _L("Unknown command \"%S\" in \"%S\""), &command, &aFileName);
       
   366 			}
       
   367 		}
       
   368 	}
       
   369 
       
   370 void CCommandInfoFile::ReadArgumentL(TLex& aLex, const TDesC& aFileName)
       
   371 	{
       
   372 	TLex lineLex(LineRemainder(aLex));
       
   373 	TUint flags = 0;
       
   374 	TBool multiple(EFalse);
       
   375 	TPtrC argType(NextWord(lineLex));
       
   376 	TPtrC argName(NextWord(lineLex));
       
   377 	TPtrC envVar;
       
   378 	while (!lineLex.Eos())
       
   379 		{
       
   380 		TPtrC word(NextWord(lineLex));
       
   381 		if (word == KCmndFlagOptional)
       
   382 			{
       
   383 			flags |= KValueTypeFlagOptional;
       
   384 			}
       
   385 		else if (word == KCmndFlagMultiple)
       
   386 			{
       
   387 			multiple = ETrue;
       
   388 			}
       
   389 		else if (word == KCmndFlagLast)
       
   390 			{
       
   391 			flags |= KValueTypeFlagLast;
       
   392 			}
       
   393 		else
       
   394 			{
       
   395 			envVar.Set(word);
       
   396 			}
       
   397 		}
       
   398 
       
   399 	if (argType.Length() == 0)
       
   400 		{
       
   401 		StaticLeaveIfErr(KErrArgument, _L("Argument missing type"));
       
   402 		}
       
   403 	else if (argName.Length() == 0)
       
   404 		{
       
   405 		StaticLeaveIfErr(KErrArgument, _L("Argument missing name"));
       
   406 		}
       
   407 	else
       
   408 		{
       
   409 		TPtrC argDescription = TextToNextCommand(aLex);
       
   410 		if (argType == KTypeEnum)
       
   411 			{
       
   412 			RBuf& enumValues = NewBuffer();
       
   413 			RBuf& enumDescriptions = NewBuffer();
       
   414 			GetEnumValuesL(aLex, enumValues, enumDescriptions);
       
   415 			if (multiple)
       
   416 				{
       
   417 				RArray<TInt> dummyArray;
       
   418 				if (enumDescriptions.Length() > 0)
       
   419 					{
       
   420 					iArguments.AppendEnumL(dummyArray, argName, argDescription, enumValues, enumDescriptions, flags, envVar);
       
   421 					}
       
   422 				else
       
   423 					{
       
   424 					iArguments.AppendEnumL(dummyArray, argName, argDescription, enumValues, flags, envVar);
       
   425 					}
       
   426 				}
       
   427 			else
       
   428 				{
       
   429 				TInt dummyInt;
       
   430 				if (enumDescriptions.Length() > 0)
       
   431 					{
       
   432 					iArguments.AppendEnumL(dummyInt, argName, argDescription, enumValues, enumDescriptions, flags, envVar);
       
   433 					}
       
   434 				else
       
   435 					{
       
   436 					iArguments.AppendEnumL(dummyInt, argName, argDescription, enumValues, flags, envVar);
       
   437 					}
       
   438 				}
       
   439 			}
       
   440 		else if (argType == KTypeInt)
       
   441 			{
       
   442 			if (multiple)
       
   443 				{
       
   444 				RArray<TInt> dummyArray;
       
   445 				iArguments.AppendIntL(dummyArray, argName, argDescription, flags, envVar);
       
   446 				}
       
   447 			else
       
   448 				{
       
   449 				TInt dummyInt;
       
   450 				iArguments.AppendIntL(dummyInt, argName, argDescription, flags, envVar);
       
   451 				}
       
   452 			}
       
   453 		else if (argType == KTypeUint)
       
   454 			{
       
   455 			if (multiple)
       
   456 				{
       
   457 				RArray<TUint> dummyArray;
       
   458 				iArguments.AppendUintL(dummyArray, argName, argDescription, flags, envVar);
       
   459 				}
       
   460 			else
       
   461 				{
       
   462 				TUint dummyUint;
       
   463 				iArguments.AppendUintL(dummyUint, argName, argDescription, flags, envVar);
       
   464 				}
       
   465 			}
       
   466 		else if (argType == KTypeString)
       
   467 			{
       
   468 			if (multiple)
       
   469 				{
       
   470 				RPointerArray<HBufC> dummyArray;
       
   471 				iArguments.AppendStringL(dummyArray, argName, argDescription, flags, envVar);
       
   472 				}
       
   473 			else
       
   474 				{
       
   475 				HBufC* dummyHBufC;
       
   476 				iArguments.AppendStringL(dummyHBufC, argName, argDescription, flags, envVar);
       
   477 				}
       
   478 			}
       
   479 		else if (argType == KTypeFileName)
       
   480 			{
       
   481 			if (multiple)
       
   482 				{
       
   483 				RArray<TFileName2> dummyArray;
       
   484 				iArguments.AppendFileNameL(dummyArray, argName, argDescription, flags, envVar);
       
   485 				}
       
   486 			else
       
   487 				{
       
   488 				TFileName2 dummyFileName;
       
   489 				iArguments.AppendFileNameL(dummyFileName, argName, argDescription, flags, envVar);
       
   490 				}
       
   491 			}
       
   492 		else if (argType == KTypeReal)
       
   493 			{
       
   494 			if (multiple)
       
   495 				{
       
   496 				RArray<TReal64> dummyArray;
       
   497 				iArguments.AppendRealL(dummyArray, argName, argDescription, flags, envVar);
       
   498 				}
       
   499 			else
       
   500 				{
       
   501 				TReal64 dummyReal;
       
   502 				iArguments.AppendRealL(dummyReal, argName, argDescription, flags, envVar);
       
   503 				}
       
   504 			}
       
   505 		else if (argType == KTypeUint64)
       
   506 			{
       
   507 			if (multiple)
       
   508 				{
       
   509 				RArray<TUint64> dummyArray;
       
   510 				iArguments.AppendUintL(dummyArray, argName, argDescription, flags, envVar);
       
   511 				}
       
   512 			else
       
   513 				{
       
   514 				TUint64 dummyUint64;
       
   515 				iArguments.AppendUintL(dummyUint64, argName, argDescription, flags, envVar);
       
   516 				}
       
   517 			}
       
   518 		else if (argType == KTypeInt64)
       
   519 			{
       
   520 			if (multiple)
       
   521 				{
       
   522 				RArray<TInt64> dummyArray;
       
   523 				iArguments.AppendIntL(dummyArray, argName, argDescription, flags, envVar);
       
   524 				}
       
   525 			else
       
   526 				{
       
   527 				TInt64 dummyInt64;
       
   528 				iArguments.AppendIntL(dummyInt64, argName, argDescription, flags, envVar);
       
   529 				}
       
   530 			}
       
   531 		else
       
   532 			{
       
   533 			StaticLeaveIfErr(KErrArgument, _L("Unknown argument type \"%S\" in \"%S\""), &argType, &aFileName);
       
   534 			}
       
   535 		}
       
   536 	}
       
   537 
       
   538 void CCommandInfoFile::ReadOptionL(TLex& aLex, const TDesC& aFileName)
       
   539 	{
       
   540 	TLex lineLex(LineRemainder(aLex));
       
   541 	TBool multiple(EFalse);
       
   542 	TPtrC optType(NextWord(lineLex));
       
   543 	TPtrC optShortName(NextWord(lineLex));
       
   544 	TPtrC optLongName(NextWord(lineLex));
       
   545 	TPtrC envVar;
       
   546 	while (!lineLex.Eos())
       
   547 		{
       
   548 		TPtrC word(NextWord(lineLex));
       
   549 		if (word == KCmndFlagMultiple)
       
   550 			{
       
   551 			multiple = ETrue;
       
   552 			}
       
   553 		else
       
   554 			{
       
   555 			envVar.Set(word);
       
   556 			}
       
   557 		}
       
   558 
       
   559 	if (optType.Length() == 0)
       
   560 		{
       
   561 		StaticLeaveIfErr(KErrArgument, _L("Option missing type"));
       
   562 		}
       
   563 	else if (optShortName.Length() == 0)
       
   564 		{
       
   565 		StaticLeaveIfErr(KErrArgument, _L("Option missing short name"));
       
   566 		}
       
   567 	else if (optShortName.Length() != 1)
       
   568 		{
       
   569 		StaticLeaveIfErr(KErrArgument, _L("Option short name not a single character"));
       
   570 		}
       
   571 	else if (optLongName.Length() == 0)
       
   572 		{
       
   573 		StaticLeaveIfErr(KErrArgument, _L("Option missing long name"));
       
   574 		}
       
   575 	else
       
   576 		{
       
   577 		TPtrC argDescription = TextToNextCommand(aLex);
       
   578 		if (optType == KTypeEnum)
       
   579 			{
       
   580 			RBuf& enumValues = NewBuffer();
       
   581 			RBuf& enumDescriptions = NewBuffer();
       
   582 			GetEnumValuesL(aLex, enumValues, enumDescriptions);
       
   583 			if (multiple)
       
   584 				{
       
   585 				RArray<TInt> dummyArray;
       
   586 				if (enumDescriptions.Length() > 0)
       
   587 					{
       
   588 					iOptions.AppendEnumL(dummyArray, optShortName[0], optLongName, argDescription, enumValues, enumDescriptions, 0, envVar);
       
   589 					}
       
   590 				else
       
   591 					{
       
   592 					iOptions.AppendEnumL(dummyArray, optShortName[0], optLongName, argDescription, enumValues, 0, envVar);
       
   593 					}
       
   594 				}
       
   595 			else
       
   596 				{
       
   597 				TInt dummyInt;
       
   598 				if (enumDescriptions.Length() > 0)
       
   599 					{
       
   600 					iOptions.AppendEnumL(dummyInt, optShortName[0], optLongName, argDescription, enumValues, enumDescriptions, 0, envVar);
       
   601 					}
       
   602 				else
       
   603 					{
       
   604 					iOptions.AppendEnumL(dummyInt, optShortName[0], optLongName, argDescription, enumValues, 0, envVar);
       
   605 					}
       
   606 				}
       
   607 			}
       
   608 		else if (optType == KTypeBool)
       
   609 			{
       
   610 			if (multiple)
       
   611 				{
       
   612 				RArray<TBool> dummyArray;
       
   613 				iOptions.AppendBoolL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   614 				}
       
   615 			else
       
   616 				{
       
   617 				TBool dummyBool;
       
   618 				iOptions.AppendBoolL(dummyBool, optShortName[0], optLongName, argDescription, 0, envVar);
       
   619 				}
       
   620 			}
       
   621 		else if (optType == KTypeInt)
       
   622 			{
       
   623 			if (multiple)
       
   624 				{
       
   625 				RArray<TInt> dummyArray;
       
   626 				iOptions.AppendIntL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   627 				}
       
   628 			else
       
   629 				{
       
   630 				TInt dummyInt;
       
   631 				iOptions.AppendIntL(dummyInt, optShortName[0], optLongName, argDescription, 0, envVar);
       
   632 				}
       
   633 			}
       
   634 		else if (optType == KTypeUint)
       
   635 			{
       
   636 			if (multiple)
       
   637 				{
       
   638 				RArray<TUint> dummyArray;
       
   639 				iOptions.AppendUintL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   640 				}
       
   641 			else
       
   642 				{
       
   643 				TUint dummyUint;
       
   644 				iOptions.AppendUintL(dummyUint, optShortName[0], optLongName, argDescription, 0, envVar);
       
   645 				}
       
   646 			}
       
   647 		else if (optType == KTypeString)
       
   648 			{
       
   649 			if (multiple)
       
   650 				{
       
   651 				RPointerArray<HBufC> dummyArray;
       
   652 				iOptions.AppendStringL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   653 				}
       
   654 			else
       
   655 				{
       
   656 				HBufC* dummyHBufC;
       
   657 				iOptions.AppendStringL(dummyHBufC, optShortName[0], optLongName, argDescription, 0, envVar);
       
   658 				}
       
   659 			}
       
   660 		else if (optType == KTypeFileName)
       
   661 			{
       
   662 			if (multiple)
       
   663 				{
       
   664 				RArray<TFileName2> dummyArray;
       
   665 				iOptions.AppendFileNameL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   666 				}
       
   667 			else
       
   668 				{
       
   669 				TFileName2 dummyFileName;
       
   670 				iOptions.AppendFileNameL(dummyFileName, optShortName[0], optLongName, argDescription, 0, envVar);
       
   671 				}
       
   672 			}
       
   673 		else if (optType == KTypeReal)
       
   674 			{
       
   675 			if (multiple)
       
   676 				{
       
   677 				RArray<TReal64> dummyArray;
       
   678 				iOptions.AppendRealL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   679 				}
       
   680 			else
       
   681 				{
       
   682 				TReal64 dummyReal;
       
   683 				iOptions.AppendRealL(dummyReal, optShortName[0], optLongName, argDescription, 0, envVar);
       
   684 				}
       
   685 			}
       
   686 		else if (optType == KTypeUint64)
       
   687 			{
       
   688 			if (multiple)
       
   689 				{
       
   690 				RArray<TUint64> dummyArray;
       
   691 				iOptions.AppendUintL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   692 				}
       
   693 			else
       
   694 				{
       
   695 				TUint64 dummyUint64;
       
   696 				iOptions.AppendUintL(dummyUint64, optShortName[0], optLongName, argDescription, 0, envVar);
       
   697 				}
       
   698 			}
       
   699 		else if (optType == KTypeInt64)
       
   700 			{
       
   701 			if (multiple)
       
   702 				{
       
   703 				RArray<TInt64> dummyArray;
       
   704 				iOptions.AppendIntL(dummyArray, optShortName[0], optLongName, argDescription, 0, envVar);
       
   705 				}
       
   706 			else
       
   707 				{
       
   708 				TInt64 dummyInt64;
       
   709 				iOptions.AppendIntL(dummyInt64, optShortName[0], optLongName, argDescription, 0, envVar);
       
   710 				}
       
   711 			}
       
   712 		else
       
   713 			{
       
   714 			StaticLeaveIfErr(KErrArgument, _L("Unknown option type \"%S\" in \"%S\""), &optType, &aFileName);
       
   715 			}
       
   716 		}
       
   717 	}
       
   718 
       
   719 void CCommandInfoFile::ProcessNewChild()
       
   720 	{
       
   721 	if (iParent)
       
   722 		{
       
   723 		iParent->ProcessNewChild();
       
   724 		}
       
   725 	else
       
   726 		{
       
   727 		ASSERT(!iProcessInclude);
       
   728 		iCurrentChild = NULL;
       
   729 		}
       
   730 	}
       
   731 
       
   732 void CCommandInfoFile::ProcessInclude(CCommandInfoFile& aChild)
       
   733 	{
       
   734 	if (iParent)
       
   735 		{
       
   736 		iParent->ProcessInclude(aChild);
       
   737 		}
       
   738 	else
       
   739 		{
       
   740 		iProcessInclude = ETrue;
       
   741 		iCurrentChild = &aChild;
       
   742 		}
       
   743 	}
       
   744 
       
   745 void CCommandInfoFile::AddSubCommandL(TLex& aNameLex, TLex& aDataLex, RFs& aFs, const TDesC& aFileName)
       
   746 	{
       
   747 	TPtrC subCommandName(NextWord(aNameLex));
       
   748 	TBool found(EFalse);
       
   749 	for (TInt i = (iChildren.Count() - 1); i >= 0; --i)
       
   750 		{
       
   751 		if (iChildren[i]->Name() == subCommandName)
       
   752 			{
       
   753 			iChildren[i]->AddSubCommandL(aNameLex, aDataLex, aFs, aFileName);
       
   754 			found = ETrue;
       
   755 			break;
       
   756 			}
       
   757 		}
       
   758 	__ASSERT_ALWAYS(found || (aNameLex.Remainder().Length() == 0), IoUtils::Panic(ECifSubCommandParentNotFound));
       
   759 	if (!found)
       
   760 		{
       
   761 		CCommandInfoFile* subCommand = new(ELeave) CCommandInfoFile(*this);
       
   762 		CleanupStack::PushL(subCommand);
       
   763 		subCommand->iName.Set(subCommandName);
       
   764 		subCommand->ReadDetailsL(aDataLex, aFs, aFileName);
       
   765 		iChildren.AppendL(subCommand);
       
   766 		CleanupStack::Pop(subCommand);
       
   767 		}
       
   768 	}
       
   769 
       
   770 RBuf& CCommandInfoFile::NewBuffer()
       
   771 	{
       
   772 	RBuf buf;
       
   773 	iBufs.AppendL(buf);
       
   774 	return iBufs[iBufs.Count() - 1];
       
   775 	}
       
   776 
       
   777 EXPORT_C CCommandInfoFile::~CCommandInfoFile()
       
   778 	{
       
   779 	iArguments.Close();
       
   780 	iOptions.Close();
       
   781 
       
   782 	const TInt numBufs = iBufs.Count();
       
   783 	for (TInt i = 0; i < numBufs; ++i)
       
   784 		{
       
   785 		iBufs[i].Close();
       
   786 		}
       
   787 	iBufs.Close();
       
   788 	iChildren.ResetAndDestroy();
       
   789 	}
       
   790 
       
   791 EXPORT_C const TDesC& CCommandInfoFile::Name() const
       
   792 	{
       
   793 	return iName;
       
   794 	}
       
   795 
       
   796 EXPORT_C const TDesC& CCommandInfoFile::ShortDescription() const
       
   797 	{
       
   798 	return iShortDescription;
       
   799 	}
       
   800 
       
   801 EXPORT_C const TDesC& CCommandInfoFile::LongDescription() const
       
   802 	{
       
   803 	return iLongDescription;
       
   804 	}
       
   805 
       
   806 EXPORT_C const TDesC& CCommandInfoFile::SeeAlso() const
       
   807 	{
       
   808 	return iSeeAlso;
       
   809 	}
       
   810 
       
   811 EXPORT_C const TDesC& CCommandInfoFile::Copyright() const
       
   812 	{
       
   813 	return iCopyright;
       
   814 	}
       
   815 
       
   816 EXPORT_C const RCommandArgumentList& CCommandInfoFile::Arguments()
       
   817 	{
       
   818 	return iArguments;
       
   819 	}
       
   820 
       
   821 EXPORT_C const RCommandOptionList& CCommandInfoFile::Options() const
       
   822 	{
       
   823 	return iOptions;
       
   824 	}
       
   825 
       
   826 template <class T> void CombineL(const T& aSourceList, T& aDestinationList, const TDesC& aListType, const TDesC& aCifName)
       
   827 	{
       
   828 	const TInt sourceCount = aSourceList.Count();
       
   829 	const TInt destinationCount = aDestinationList.Count();
       
   830 
       
   831 	if (sourceCount < destinationCount) // Note, allow the source to have more than the destination because some things are compile time configurable but CIF files don't support this.
       
   832 		{
       
   833 		StaticLeaveIfErr(KErrArgument, _L("%S count mismatch between \"%S\" (%d) and implementation (%d)"), &aListType, &aCifName, sourceCount, destinationCount);
       
   834 		}
       
   835 
       
   836 	for (TInt i = 0; i < destinationCount; ++i)
       
   837 		{
       
   838 		const TDesC& destinationName = aDestinationList[i].Name();
       
   839 		TInt sourcePos = aSourceList.Find(destinationName);
       
   840 		if (sourcePos < 0)
       
   841 			{
       
   842 			StaticLeaveIfErr(KErrArgument, _L("Couldn't find %S \"%S\" in \"%S\""), &aListType, &destinationName, &aCifName);
       
   843 			}
       
   844 
       
   845 		TUint sourceType = aSourceList[sourcePos].ValueType();
       
   846 		TUint sourceTypeForComparison = sourceType & ~(KValueTypeFlagOptional|KValueTypeFlagLast); // destType can't know about these flags, so clear them from sourceType so we don't have problems when destType doesn't set them
       
   847 		TUint destType = aDestinationList[i].ValueType();
       
   848 		if (sourceTypeForComparison != destType)
       
   849 			{
       
   850 			StaticLeaveIfErr(KErrArgument, _L("Type mismatch for %S '%S' between \"%S\" (0x%x) and implementation (0x%x)"), &aListType, &destinationName, &aCifName, sourceType, destType);
       
   851 			}
       
   852 		aDestinationList[i].Combine(aSourceList[sourcePos]);
       
   853 		}
       
   854 	}
       
   855 
       
   856 EXPORT_C void CCommandInfoFile::AssignL(RCommandArgumentList& aArguments, RCommandOptionList& aOptions) const
       
   857 	{
       
   858 	CombineL(iArguments, aArguments, _L("Argument"), iFileName);
       
   859 	CombineL(iOptions, aOptions, _L("Option"), iFileName);
       
   860 	}
       
   861 
       
   862 EXPORT_C TInt CCommandInfoFile::NumSubCommands() const
       
   863 	{
       
   864 	return iChildren.Count();
       
   865 	}
       
   866 
       
   867 EXPORT_C const CCommandInfoFile& CCommandInfoFile::SubCommand(TInt aIndex) const
       
   868 	{
       
   869 	return *(iChildren[aIndex]);
       
   870 	}
       
   871 
       
   872 EXPORT_C const CCommandInfoFile* CCommandInfoFile::SubCommand(const TDesC& aSubCommandName) const
       
   873 	{
       
   874 	for (TInt i = (NumSubCommands() - 1); i >= 0; --i)
       
   875 		{
       
   876 		const CCommandInfoFile& thisSubCommand = SubCommand(i);
       
   877 		if (thisSubCommand.Name() == aSubCommandName)
       
   878 			{
       
   879 			return &thisSubCommand;
       
   880 			}
       
   881 		}
       
   882 	return NULL;
       
   883 	}
       
   884 
       
   885 CCommandInfoFile::CCommandInfoFile(const TDesC& aFileName)
       
   886 	: iFileName(aFileName)
       
   887 	{
       
   888 	}
       
   889 
       
   890 CCommandInfoFile::CCommandInfoFile(CCommandInfoFile& aParent)
       
   891 	: iFileName(aParent.iFileName), iParent(&aParent)
       
   892 	{
       
   893 	}