libraries/iosrv/client/text_formatter.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // text_formatter.cpp
       
     2 // 
       
     3 // Copyright (c) 2006 - 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 <e32base.h>
       
    14 #include "ioutils.h"
       
    15 #include "pod_lexer.h"
       
    16 #include "pod_formatter.h"
       
    17 
       
    18 using namespace IoUtils;
       
    19 
       
    20 
       
    21 //
       
    22 // Constants.
       
    23 //
       
    24 
       
    25 _LIT(KSpace, " ");
       
    26 _LIT(KNewLine, "\r\n");
       
    27 
       
    28 
       
    29 //
       
    30 // CTextBuffer.
       
    31 //
       
    32 
       
    33 EXPORT_C CTextBuffer* CTextBuffer::NewL(TInt aExpandSize)
       
    34 	{
       
    35 	CTextBuffer* self = CTextBuffer::NewLC(aExpandSize);
       
    36 	CleanupStack::Pop(self);
       
    37 	return self;
       
    38 	}
       
    39 
       
    40 EXPORT_C CTextBuffer* CTextBuffer::NewLC(TInt aExpandSize)
       
    41 	{
       
    42 	CTextBuffer* self = new(ELeave) CTextBuffer();
       
    43 	CleanupStack::PushL(self);
       
    44 	self->ConstructL(aExpandSize);
       
    45 	return self;
       
    46 	}
       
    47 
       
    48 EXPORT_C CTextBuffer::~CTextBuffer()
       
    49 	{
       
    50 	Cancel();
       
    51 	delete iBuf;
       
    52 	delete iScratchBuf;
       
    53 	delete iScratchBuf8;
       
    54 	iAttributes.Close();
       
    55 	}
       
    56 
       
    57 EXPORT_C void CTextBuffer::Zero()
       
    58 	{
       
    59 	iBuf->Delete(0, iBuf->Size());
       
    60 	iAttributes.Reset();
       
    61 	}
       
    62 
       
    63 EXPORT_C void CTextBuffer::Reset()
       
    64 	{
       
    65 	iBuf->Reset();
       
    66 	iAttributes.Reset();
       
    67 	}
       
    68 
       
    69 EXPORT_C void CTextBuffer::ResetText()
       
    70 	{
       
    71 	iBuf->Reset();
       
    72 	}
       
    73 
       
    74 EXPORT_C void CTextBuffer::SetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
       
    75 	{
       
    76 	const TInt numAttributes = iAttributes.Count();
       
    77 	if (numAttributes == 0)
       
    78 		{
       
    79 		if (Length() == 0)
       
    80 			{
       
    81 			TAttributes attributes(0, aAttributes, aForegroundColor, aBackgroundColor);
       
    82 			iAttributes.AppendL(attributes);
       
    83 			}
       
    84 		else
       
    85 			{
       
    86 			TAttributes attributes(Length(), aAttributes, aForegroundColor, aBackgroundColor);
       
    87 			if (!attributes.Matches(ConsoleAttributes::ENone, ConsoleAttributes::EUnchanged, ConsoleAttributes::EUnchanged))
       
    88 				{
       
    89 				TAttributes defaultAttributes(0, ConsoleAttributes::ENone, ConsoleAttributes::EUnchanged, ConsoleAttributes::EUnchanged);
       
    90 				iAttributes.AppendL(defaultAttributes);
       
    91 				TInt err = iAttributes.Append(attributes);
       
    92 				if (err != KErrNone)
       
    93 					{
       
    94 					iAttributes.Reset();
       
    95 					User::Leave(err);
       
    96 					}
       
    97 				}
       
    98 			}
       
    99 		}
       
   100 	else if (iAttributes[numAttributes - 1].Matches(aAttributes, aForegroundColor, aBackgroundColor))
       
   101 		{
       
   102 		// Do nothing.
       
   103 		}
       
   104 	else if (iAttributes[numAttributes - 1].iPosition == Length())
       
   105 		{
       
   106 		TAttributes& att = iAttributes[numAttributes - 1];
       
   107 		if (aAttributes & ConsoleAttributes::ENone)
       
   108 			{
       
   109 			att.iAttributes.iAttributes = aAttributes;
       
   110 			att.iAttributes.iForegroundColor = aForegroundColor;
       
   111 			att.iAttributes.iBackgroundColor = aBackgroundColor;
       
   112 			}
       
   113 		else
       
   114 			{
       
   115 			// Merge on top of existing attributes
       
   116 			att.iAttributes.iAttributes |= aAttributes;
       
   117 			if (aForegroundColor != ConsoleAttributes::EUnchanged) att.iAttributes.iForegroundColor = aForegroundColor;
       
   118 			if (aBackgroundColor != ConsoleAttributes::EUnchanged) att.iAttributes.iBackgroundColor = aBackgroundColor;
       
   119 			}
       
   120 		}
       
   121 	else
       
   122 		{
       
   123 		TAttributes attributes(Length(), aAttributes, aForegroundColor, aBackgroundColor);
       
   124 		iAttributes.AppendL(attributes);
       
   125 		}
       
   126 	}
       
   127 
       
   128 EXPORT_C void CTextBuffer::SetAttributesL(const ConsoleAttributes::TAttributes& aAttributes)
       
   129 	{
       
   130 	SetAttributesL(aAttributes.iAttributes, aAttributes.iForegroundColor, aAttributes.iBackgroundColor);
       
   131 	}
       
   132 
       
   133 EXPORT_C void CTextBuffer::GetCurrentAttributes(TUint& aAttributes, ConsoleAttributes::TColor& aForegroundColor, ConsoleAttributes::TColor& aBackgroundColor) const
       
   134 	{
       
   135 	if (iAttributes.Count() > 0)
       
   136 		{
       
   137 		const TAttributes& att = iAttributes[iAttributes.Count() - 1];
       
   138 		aAttributes = att.iAttributes.iAttributes;
       
   139 		aForegroundColor = att.iAttributes.iForegroundColor;
       
   140 		aBackgroundColor = att.iAttributes.iBackgroundColor;
       
   141 		}
       
   142 	else
       
   143 		{
       
   144 		aAttributes = ConsoleAttributes::ENone;
       
   145 		aForegroundColor = ConsoleAttributes::EUnchanged;
       
   146 		aBackgroundColor = ConsoleAttributes::EUnchanged;
       
   147 		}
       
   148 	}
       
   149 
       
   150 EXPORT_C void CTextBuffer::GetAttributes(TInt aPos, TUint& aAttributes, ConsoleAttributes::TColor& aForegroundColor, ConsoleAttributes::TColor& aBackgroundColor) const
       
   151 	{
       
   152 	ASSERT(aPos < Length());
       
   153 
       
   154 	aAttributes = ConsoleAttributes::ENone;
       
   155 	aForegroundColor = ConsoleAttributes::EUnchanged;
       
   156 	aBackgroundColor = ConsoleAttributes::EUnchanged;
       
   157 
       
   158 	const TInt numAttributes = iAttributes.Count();
       
   159 	for (TInt i = 0; i < numAttributes; ++i)
       
   160 		{
       
   161 		const TAttributes& att = iAttributes[i];
       
   162 		if (aPos < att.iPosition)
       
   163 			{
       
   164 			return;
       
   165 			}
       
   166 		else
       
   167 			{
       
   168 			aAttributes = att.iAttributes.iAttributes;
       
   169 			aForegroundColor = att.iAttributes.iForegroundColor;
       
   170 			aBackgroundColor = att.iAttributes.iBackgroundColor;
       
   171 			}
       
   172 		}
       
   173 	}
       
   174 
       
   175 EXPORT_C void CTextBuffer::AppendL(const TChar& aChar)
       
   176 	{
       
   177 	TUint16 ch = (TUint16)TUint(aChar); // We don't support surrogate pairs
       
   178 	iBuf->InsertL(iBuf->Size(), &ch, 2);
       
   179 	}
       
   180 
       
   181 EXPORT_C void CTextBuffer::AppendL(const TDesC& aText)
       
   182 	{
       
   183 	iBuf->InsertL(iBuf->Size(), aText.Ptr(), aText.Size());
       
   184 	}
       
   185 
       
   186 EXPORT_C void CTextBuffer::AppendL(const TDesC8& aText)
       
   187 	{
       
   188 	if (!iScratchBuf)
       
   189 		{
       
   190 		iScratchBuf = HBufC::NewL(Max(aText.Length(), 256));
       
   191 		}
       
   192 	if (iScratchBuf->Des().MaxLength() < aText.Length())
       
   193 		{
       
   194 		iScratchBuf = iScratchBuf->ReAllocL(Max(iScratchBuf->Des().MaxLength()*2, aText.Length()));
       
   195 		}
       
   196 	iScratchBuf->Des().Copy(aText);	
       
   197 	iBuf->InsertL(iBuf->Size(), iScratchBuf->Ptr(), iScratchBuf->Size());
       
   198 	}
       
   199 
       
   200 EXPORT_C void CTextBuffer::AppendL(const CTextBuffer& aText)
       
   201 	{
       
   202 	AppendL(aText, 0, aText.Length());
       
   203 	}
       
   204 
       
   205 EXPORT_C void CTextBuffer::AppendL(const CTextBuffer& aText, TInt aPosition)
       
   206 	{
       
   207 	AppendL(aText, aPosition, aText.Length() - aPosition);
       
   208 	}
       
   209 
       
   210 EXPORT_C void CTextBuffer::AppendL(const CTextBuffer& aText, TInt aPosition, TInt aLength)
       
   211 	{
       
   212 	const TInt numAttributes = aText.iAttributes.Count();
       
   213 	if (numAttributes > 0)
       
   214 		{
       
   215 		TInt textPos = 0;
       
   216 		TInt appendCount = 0;
       
   217 		TInt blockIndex = 0;
       
   218 		const TDesC* block = NULL;
       
   219 		do
       
   220 			{
       
   221 			TUint attributes;
       
   222 			ConsoleAttributes::TColor foregroundColor;
       
   223 			ConsoleAttributes::TColor backgroundColor;
       
   224 			aText.NextBlock(blockIndex, block, attributes, foregroundColor, backgroundColor);
       
   225 			if (block != NULL)
       
   226 				{
       
   227 				if ((textPos + block->Length()) > aPosition)
       
   228 					{
       
   229 					SetAttributesL(attributes, foregroundColor, backgroundColor);
       
   230 					TInt blockOffset = aPosition - textPos;
       
   231 					if (blockOffset < 0)
       
   232 						{
       
   233 						blockOffset = 0;
       
   234 						}
       
   235 					TPtrC appendBlock(block->Mid(blockOffset, Min(aLength - appendCount, block->Length() - blockOffset)));
       
   236 					AppendL(appendBlock);
       
   237 					appendCount += appendBlock.Length();
       
   238 					if (appendCount == aLength)
       
   239 						{
       
   240 						break;
       
   241 						}
       
   242 					}
       
   243 				textPos += block->Length();
       
   244 				}
       
   245 			}
       
   246 			while (block != NULL);
       
   247 		}
       
   248 	else
       
   249 		{
       
   250 		AppendL(aText.Descriptor().Mid(aPosition, aLength));
       
   251 		}
       
   252 	}
       
   253 
       
   254 EXPORT_C void CTextBuffer::AppendFormatL(TRefByValue<const TDesC> aFmt, ...)
       
   255 	{
       
   256 	VA_LIST list;
       
   257 	VA_START(list, aFmt);
       
   258 	AppendFormatListL(aFmt, list);
       
   259 	}
       
   260 
       
   261 EXPORT_C void CTextBuffer::AppendFormatListL(const TDesC16& aFmt, VA_LIST& aList)
       
   262 	{
       
   263 	TOverflowLeave overflow;
       
   264 	TInt err = KErrNone;
       
   265 	do
       
   266 		{
       
   267 		TPtr ptr(iScratchBuf->Des());
       
   268 		ptr.Zero();
       
   269 		TRAP(err, ptr.AppendFormatList(aFmt, aList, &overflow));
       
   270 		if (err == KErrOverflow)
       
   271 			{
       
   272 			iScratchBuf = iScratchBuf->ReAllocL(ptr.MaxLength() * 2);
       
   273 			}
       
   274 		}
       
   275 		while (err == KErrOverflow);
       
   276 
       
   277 	User::LeaveIfError(err);
       
   278 	iBuf->InsertL(iBuf->Size(), iScratchBuf->Ptr(), iScratchBuf->Size());
       
   279 	}
       
   280 	
       
   281 EXPORT_C void CTextBuffer::AppendFormatL(TRefByValue<const TDesC8> aFmt, ...)
       
   282 	{
       
   283 	VA_LIST list;
       
   284 	VA_START(list, aFmt);
       
   285 	AppendFormatListL(aFmt, list);
       
   286 	}
       
   287 	
       
   288 EXPORT_C void CTextBuffer::AppendFormatListL(const TDesC8& aFmt, VA_LIST& aList)
       
   289 	{
       
   290 	TOverflowLeave8 overflow;
       
   291 	TInt err = KErrNone;
       
   292 	if (!iScratchBuf8)
       
   293 		{
       
   294 		iScratchBuf8 = HBufC8::NewL(0x100);
       
   295 		}
       
   296 		
       
   297 	do
       
   298 		{
       
   299 		TPtr8 ptr(iScratchBuf8->Des());
       
   300 		ptr.Zero();
       
   301 		TRAP(err, ptr.AppendFormatList(aFmt, aList, &overflow));
       
   302 		if (err == KErrOverflow)
       
   303 			{
       
   304 			iScratchBuf8 = iScratchBuf8->ReAllocL(ptr.MaxLength() * 2);
       
   305 			}
       
   306 		}
       
   307 		while (err == KErrOverflow);
       
   308 
       
   309 	User::LeaveIfError(err);
       
   310 	
       
   311 	TPtr8 ptr(iScratchBuf8->Des());
       
   312 	if (iScratchBuf->Des().MaxLength() < ptr.Length())
       
   313 		{
       
   314 		iScratchBuf = iScratchBuf->ReAllocL(Max(iScratchBuf->Des().MaxLength()*2, ptr.Length()));
       
   315 		}
       
   316 	iScratchBuf->Des().Copy(*iScratchBuf8);	
       
   317 	
       
   318 	iBuf->InsertL(iBuf->Size(), iScratchBuf->Ptr(), iScratchBuf->Size());
       
   319 	}
       
   320 
       
   321 EXPORT_C void CTextBuffer::AppendHumanReadableSizeL(TInt aSize)
       
   322 	{
       
   323 	AppendHumanReadableSizeL(TInt64(aSize), EColumnAlignedRight);
       
   324 	}
       
   325 
       
   326 EXPORT_C void CTextBuffer::AppendHumanReadableSizeL(TInt64 aSize)
       
   327 	{
       
   328 	AppendHumanReadableSizeL(aSize, EColumnAlignedRight);
       
   329 	}
       
   330 
       
   331 EXPORT_C void CTextBuffer::AppendHumanReadableSizeL(TInt aSize, TAlignment aAlignment)
       
   332 	{
       
   333 	AppendHumanReadableSizeL(TInt64(aSize), aAlignment);
       
   334 	}
       
   335 
       
   336 EXPORT_C void CTextBuffer::AppendHumanReadableSizeL(TInt64 aSize, TAlignment aAlignment)
       
   337 	{
       
   338 	const TInt64 KB = 1024;
       
   339 	const TInt64 MB = KB * KB;
       
   340 	const TInt64 GB = MB * KB;
       
   341 	const TInt64 TB = GB * KB;
       
   342 	_LIT(KBytes, " B ");
       
   343 	_LIT(KKilobytes, " KB");
       
   344 	_LIT(KMegabytes, " MB");
       
   345 	_LIT(KGigabytes, " GB");
       
   346 	_LIT(KTerabytes, " TB");
       
   347 
       
   348 	_LIT(KLeftWhole, "%- 7.0f");
       
   349 	_LIT(KLeftFrac, "%- 7.2f");
       
   350 	_LIT(KRightWhole, "%+ 7.0f");
       
   351 	_LIT(KRightFrac, "%+ 7.2f");
       
   352 	_LIT(KNormalWhole, "%.0f");
       
   353 	_LIT(KNormalFrac, "%.2f");
       
   354 
       
   355 	const TDesC* suff = &KBytes;
       
   356 	TReal n = aSize;
       
   357 	TInt64 factor = 1;
       
   358 
       
   359 	TInt64 absSize = aSize;
       
   360 	if (absSize < 0) absSize = -absSize;
       
   361 
       
   362 	if (absSize >= TB)
       
   363 		{
       
   364 		suff = &KTerabytes;
       
   365 		factor = TB;
       
   366 		}
       
   367 	else if (absSize >= GB)
       
   368 		{
       
   369 		suff = &KGigabytes;
       
   370 		factor = GB;
       
   371 		}
       
   372 	else if (absSize >= MB)
       
   373 		{
       
   374 		suff = &KMegabytes;
       
   375 		factor = MB;
       
   376 		}
       
   377 	else if (absSize >= KB)
       
   378 		{
       
   379 		suff = &KKilobytes;
       
   380 		factor = KB;
       
   381 		}
       
   382 
       
   383 	n = n / (TReal)factor;
       
   384 	TBool wholeNumUnits = (absSize & (factor-1)) == 0; // ie aSize % factor == 0
       
   385 
       
   386 	const TDesC* fmt = NULL;
       
   387 	if (aAlignment == EColumnAlignedLeft)
       
   388 		{
       
   389 		fmt = wholeNumUnits ? &KLeftWhole : &KLeftFrac;
       
   390 		}
       
   391 	else if (aAlignment == EColumnAlignedRight)
       
   392 		{
       
   393 		fmt = wholeNumUnits ? &KRightWhole : &KRightFrac;
       
   394 		}
       
   395 	else
       
   396 		{
       
   397 		fmt = wholeNumUnits ? &KNormalWhole : &KNormalFrac;
       
   398 		}
       
   399 
       
   400 	AppendFormatL(*fmt, n);
       
   401 	AppendL(*suff);
       
   402 	}
       
   403 
       
   404 EXPORT_C void CTextBuffer::AppendSpacesL(TInt aCount)
       
   405 	{
       
   406 	ASSERT(aCount >= 0);
       
   407 	while (aCount > 0)
       
   408 		{
       
   409 		AppendL(KSpace);
       
   410 		--aCount;
       
   411 		}
       
   412 	}
       
   413 
       
   414 EXPORT_C void CTextBuffer::Delete(TInt aPos, TInt aLength)
       
   415 	{
       
   416 	//for (TInt i = 0; i < iAttributes.Count(); i++)
       
   417 	//	{
       
   418 	//	RDebug::Printf("attribute %d: pos %d", i, iAttributes[i].iPosition);
       
   419 	//	}
       
   420 
       
   421 	// Find the first and last attributes that are inside the delete region.
       
   422 	TInt firstAttribute = -1;
       
   423 	TInt lastAttribute = -1;
       
   424 	TInt numAttributes = iAttributes.Count();
       
   425 	for (TInt i = (numAttributes - 1); i >= 0; --i)
       
   426 		{
       
   427 		const TAttributes& thisAttribute = iAttributes[i];
       
   428 		if ((lastAttribute == -1) && (thisAttribute.iPosition >= aPos) && (thisAttribute.iPosition < aPos + aLength))
       
   429 			{
       
   430 			lastAttribute = i;
       
   431 			}
       
   432 		if (lastAttribute >= 0 && thisAttribute.iPosition >= aPos)
       
   433 			{
       
   434 			firstAttribute = i;
       
   435 			}
       
   436 		}
       
   437 	//RDebug::Printf("firstAttribute=%d lastAttribute=%d", firstAttribute, lastAttribute);
       
   438 
       
   439 	if ((lastAttribute > 0))
       
   440 		{
       
   441 		// Set the position of the last affected attribute to just after the deleted chunk.
       
   442 		iAttributes[lastAttribute].iPosition = aPos + aLength;
       
   443 
       
   444 		// Remove all but the last affected attribute. Need to keep the last affected attribute
       
   445 		// because it has an impact on the formatting of text that appears after the deleted chunk.
       
   446 		for (TInt i = (lastAttribute - 1); i >= firstAttribute; --i)
       
   447 			{
       
   448 			iAttributes.Remove(i);
       
   449 			}
       
   450 		}
       
   451 
       
   452 	// Update the positions of attributes after the block being deleted.
       
   453 	numAttributes = iAttributes.Count();
       
   454 	for (TInt i = Max(0, firstAttribute); i < numAttributes; ++i)
       
   455 		{
       
   456 		TAttributes& thisAttribute = iAttributes[i];
       
   457 		if (thisAttribute.iPosition >= aPos + aLength)
       
   458 			{
       
   459 			thisAttribute.iPosition -= aLength;
       
   460 			}
       
   461 		}
       
   462 	iBuf->Delete(aPos * 2, aLength * 2);
       
   463 	}
       
   464 
       
   465 EXPORT_C TInt CTextBuffer::Length() const
       
   466 	{
       
   467 	return iBuf->Size() / 2;
       
   468 	}
       
   469 
       
   470 EXPORT_C const TDesC& CTextBuffer::Descriptor() const
       
   471 	{
       
   472 	TPtr8 narrowPtr(iBuf->Ptr(0));
       
   473 	iPtr.Set((const TUint16 *)narrowPtr.Ptr(), narrowPtr.Length() / 2);
       
   474 	return iPtr;
       
   475 	}
       
   476 
       
   477 EXPORT_C const TDesC& CTextBuffer::Descriptor(TInt aPos, TInt aLength) const
       
   478 	{
       
   479 	TPtr8 narrowPtr(iBuf->Ptr(aPos * 2));
       
   480 	iPtr.Set((const TUint16 *)narrowPtr.Ptr(), aLength);
       
   481 	return iPtr;
       
   482 	}
       
   483 	
       
   484 EXPORT_C TPtrC8 CTextBuffer::Collapse()
       
   485 	{
       
   486 	TPtr8 narrowPtr(iBuf->Ptr(0));
       
   487 	TPtr ptr((TUint16 *)narrowPtr.Ptr(), narrowPtr.Length() / 2, narrowPtr.Length() / 2);
       
   488 	return ptr.Collapse();
       
   489 	}
       
   490 
       
   491 EXPORT_C TInt CTextBuffer::Write(RIoWriteHandle& aWriteHandle) const
       
   492 	{
       
   493 	return Write(aWriteHandle, 0, Length());
       
   494 	}
       
   495 
       
   496 EXPORT_C void CTextBuffer::Write(RIoWriteHandle& aWriteHandle, TRequestStatus& aStatus) const
       
   497 	{
       
   498 	Write(aWriteHandle, 0, Length(), aStatus);
       
   499 	}
       
   500 
       
   501 EXPORT_C TInt CTextBuffer::Write(RIoWriteHandle& aWriteHandle, TInt aPosition, TInt aLength) const
       
   502 	{
       
   503 	const TInt numAttributes = iAttributes.Count();
       
   504 	if ((aWriteHandle.AttachedToConsole() > 0) && (numAttributes > 0))
       
   505 		{
       
   506 		// Write the text buffer to the console a block at a time, updating the console's attributes at the beginning of each block.
       
   507 		TInt blockIndex = 0;
       
   508 		TInt textPos = 0;
       
   509 		TInt writeCount = 0;
       
   510 		const TDesC* block = NULL;
       
   511 		do
       
   512 			{
       
   513 			TUint attributes;
       
   514 			ConsoleAttributes::TColor foregroundColor;
       
   515 			ConsoleAttributes::TColor backgroundColor;
       
   516 			NextBlock(blockIndex, block, attributes, foregroundColor, backgroundColor);
       
   517 			if (block != NULL)
       
   518 				{
       
   519 				if ((textPos + block->Length()) > aPosition)
       
   520 					{
       
   521 					RIoConsoleWriteHandle(aWriteHandle).SetAttributes(attributes, foregroundColor, backgroundColor); // Ignore error - may not be supported.
       
   522 					TInt blockOffset = aPosition - textPos;
       
   523 					if (blockOffset < 0)
       
   524 						{
       
   525 						blockOffset = 0;
       
   526 						}
       
   527 					TPtrC toWrite(block->Mid(blockOffset, Min(aLength - writeCount, block->Length() - blockOffset)));
       
   528 					TInt err = aWriteHandle.Write(toWrite);
       
   529 					if (err)
       
   530 						{
       
   531 						return err;
       
   532 						}
       
   533 					writeCount += toWrite.Length();
       
   534 					if (writeCount == aLength)
       
   535 						{
       
   536 						break;
       
   537 						}
       
   538 					}
       
   539 				textPos += block->Length();
       
   540 				}
       
   541 			}
       
   542 			while (block != NULL);
       
   543 		}
       
   544 	else
       
   545 		{
       
   546 		return aWriteHandle.Write(Descriptor().Mid(aPosition, aLength));
       
   547 		}
       
   548 
       
   549 	return KErrNone;
       
   550 	}
       
   551 
       
   552 EXPORT_C void CTextBuffer::Write(RIoWriteHandle& aWriteHandle, TInt aPosition, TInt aLength, TRequestStatus& aStatus) const
       
   553 	{
       
   554 	const TInt numAttributes = iAttributes.Count();
       
   555 	if ((aWriteHandle.AttachedToConsole() > 0) && (numAttributes > 0))
       
   556 		{
       
   557 		// Write the text buffer asynchronously to the console a block at a time, updating the console's attributes at the beginning of each block.
       
   558 		if (!IsAdded())
       
   559 			{
       
   560 			CActiveScheduler::Add(const_cast<CTextBuffer*>(this));
       
   561 			}
       
   562 		aStatus = KRequestPending;
       
   563 		iWriteStatus = &aStatus;
       
   564 		iAsyncBlockIndex = 0;
       
   565 		iAsyncWritePos = 0;
       
   566 		iAsyncWriteStartPos = aPosition;
       
   567 		iAsyncWriteLength = aLength;
       
   568 		iConsoleWriteHandle = aWriteHandle;
       
   569 		AsyncWriteNextBlock();
       
   570 		}
       
   571 	else
       
   572 		{
       
   573 		aWriteHandle.Write(Descriptor().Mid(aPosition, aLength), aStatus);
       
   574 		}
       
   575 	}
       
   576 
       
   577 CTextBuffer::CTextBuffer()
       
   578 	: CActive(CActive::EPriorityStandard), iPtr(NULL, 0)
       
   579 	{
       
   580 	}
       
   581 
       
   582 void CTextBuffer::ConstructL(TInt aExpandSize)
       
   583 	{
       
   584 	iBuf = CBufFlat::NewL(aExpandSize);
       
   585 	iScratchBuf = HBufC::NewL(aExpandSize);
       
   586 	}
       
   587 
       
   588 void CTextBuffer::NextBlock(TInt& aBlockIndex, const TDesC*& aText, TUint& aAttributes, ConsoleAttributes::TColor& aForegroundColor, ConsoleAttributes::TColor& aBackgroundColor) const
       
   589 	{
       
   590 	if (iAttributes.Count() > 0)
       
   591 		{
       
   592 		if (aBlockIndex < iAttributes.Count())
       
   593 			{
       
   594 			const TAttributes& thisAttribute = iAttributes[aBlockIndex];
       
   595 			aAttributes = thisAttribute.iAttributes.iAttributes;
       
   596 			aForegroundColor = thisAttribute.iAttributes.iForegroundColor;
       
   597 			aBackgroundColor = thisAttribute.iAttributes.iBackgroundColor;
       
   598 			TInt length;
       
   599 			if (aBlockIndex < (iAttributes.Count() - 1))
       
   600 				{
       
   601 				length = iAttributes[aBlockIndex + 1].iPosition - thisAttribute.iPosition;
       
   602 				}
       
   603 			else
       
   604 				{
       
   605 				length = Length() - thisAttribute.iPosition;
       
   606 				}
       
   607 			aText = &Descriptor(thisAttribute.iPosition, length);
       
   608 			++aBlockIndex;
       
   609 			}
       
   610 		else
       
   611 			{
       
   612 			aText = NULL;
       
   613 			}
       
   614 		}
       
   615 	else
       
   616 		{
       
   617 		// There are no attributes, so block zero is the whole buffer.
       
   618 		ASSERT((aBlockIndex == 0) || (aBlockIndex == 1));
       
   619 		if (aBlockIndex == 0)
       
   620 			{
       
   621 			aAttributes = ConsoleAttributes::ENone;
       
   622 			aForegroundColor = ConsoleAttributes::EUnchanged;
       
   623 			aBackgroundColor = ConsoleAttributes::EUnchanged;
       
   624 			aText = &Descriptor(0, Length());
       
   625 			++aBlockIndex;
       
   626 			}
       
   627 		else
       
   628 			{
       
   629 			aText = NULL;
       
   630 			}
       
   631 		}
       
   632 	}
       
   633 
       
   634 void CTextBuffer::AsyncWriteNextBlock() const
       
   635 	{
       
   636 	const TDesC* block = NULL;
       
   637 	TUint attributes;
       
   638 	ConsoleAttributes::TColor foregroundColor;
       
   639 	ConsoleAttributes::TColor backgroundColor;
       
   640 	NextBlock(iAsyncBlockIndex, block, attributes, foregroundColor, backgroundColor);
       
   641 	if (block != NULL)
       
   642 		{
       
   643 		if ((iAsyncWritePos + block->Length()) > iAsyncWriteStartPos)
       
   644 			{
       
   645 			iConsoleWriteHandle.SetAttributes(attributes, foregroundColor, backgroundColor); // Ignore error - may not be supported.
       
   646 			TInt blockOffset = iAsyncWriteStartPos - iAsyncWritePos;
       
   647 			if (blockOffset < 0)
       
   648 				{
       
   649 				blockOffset = 0;
       
   650 				}
       
   651 			iAsyncWritePtr.Set(block->Mid(blockOffset, Min(iAsyncWriteLength, block->Length() - blockOffset)));
       
   652 			iAsyncWriteLength -= iAsyncWritePtr.Length();
       
   653 			iConsoleWriteHandle.Write(iAsyncWritePtr, const_cast<TRequestStatus&>(iStatus));
       
   654 			const_cast<CTextBuffer*>(this)->SetActive();
       
   655 			}
       
   656 		iAsyncWritePos += block->Length();
       
   657 		}
       
   658 	else
       
   659 		{
       
   660 		User::RequestComplete(iWriteStatus, KErrNone);
       
   661 		}
       
   662 	}
       
   663 
       
   664 void CTextBuffer::RunL()
       
   665 	{
       
   666 	if (iStatus.Int() || (iAsyncWriteLength <= 0))
       
   667 		{
       
   668 		User::RequestComplete(iWriteStatus, iStatus.Int());
       
   669 		}
       
   670 	else
       
   671 		{
       
   672 		AsyncWriteNextBlock();
       
   673 		}
       
   674 	}
       
   675 
       
   676 void CTextBuffer::DoCancel()
       
   677 	{
       
   678 	iConsoleWriteHandle.WriteCancel();
       
   679 	}
       
   680 
       
   681 CTextBuffer::TAttributes::TAttributes(TInt aPosition, TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
       
   682 	: iPosition(aPosition), iAttributes(aAttributes, aForegroundColor, aBackgroundColor)
       
   683 	{
       
   684 	}
       
   685 
       
   686 TBool CTextBuffer::TAttributes::Matches(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor) const
       
   687 	{
       
   688 	return ((aAttributes == iAttributes.iAttributes) && (aForegroundColor == iAttributes.iForegroundColor) && (aBackgroundColor == iAttributes.iBackgroundColor));
       
   689 	}
       
   690 
       
   691 
       
   692 //
       
   693 // CTextFormatter.
       
   694 //
       
   695 
       
   696 EXPORT_C CTextFormatter* CTextFormatter::NewL(TInt aAvailableWidth)
       
   697 	{
       
   698 	CTextFormatter* self = CTextFormatter::NewLC(aAvailableWidth);
       
   699 	CleanupStack::Pop(self);
       
   700 	return self;
       
   701 	}
       
   702 
       
   703 EXPORT_C CTextFormatter* CTextFormatter::NewLC(TInt aAvailableWidth)
       
   704 	{
       
   705 	CTextFormatter* self = new(ELeave) CTextFormatter(aAvailableWidth);
       
   706 	CleanupStack::PushL(self);
       
   707 	self->ConstructL();
       
   708 	return self;
       
   709 	}
       
   710 
       
   711 EXPORT_C CTextFormatter* CTextFormatter::NewL(RIoConsoleWriteHandle& aConsoleWriteHandle)
       
   712 	{
       
   713 	CTextFormatter* self = CTextFormatter::NewLC(aConsoleWriteHandle);
       
   714 	CleanupStack::Pop(self);
       
   715 	return self;
       
   716 	}
       
   717 
       
   718 EXPORT_C CTextFormatter* CTextFormatter::NewLC(RIoConsoleWriteHandle& aConsoleWriteHandle)
       
   719 	{
       
   720 	TSize size;
       
   721 	if (aConsoleWriteHandle.AttachedToConsole())
       
   722 		{
       
   723 		User::LeaveIfError(aConsoleWriteHandle.GetScreenSize(size));
       
   724 		}
       
   725 	else
       
   726 		{
       
   727 		size.iWidth = 80;
       
   728 		}
       
   729 	CTextFormatter* self = CTextFormatter::NewLC(size.iWidth);
       
   730 	self->iWriteHandle = &aConsoleWriteHandle;
       
   731 	self->iAttributesSupported = (aConsoleWriteHandle.SetAttributes(0) == KErrNone);
       
   732 	return self;
       
   733 	}
       
   734 
       
   735 EXPORT_C CTextFormatter::~CTextFormatter()
       
   736 	{
       
   737 	}
       
   738 
       
   739 CTextFormatter::CTextFormatter(TInt aAvailableWidth)
       
   740 	: iAvailableWidth(aAvailableWidth - 1)
       
   741 	{
       
   742 	}
       
   743 
       
   744 void CTextFormatter::ConstructL()
       
   745 	{
       
   746 	CTextBuffer::ConstructL(0x100);
       
   747 	}
       
   748 
       
   749 EXPORT_C void CTextFormatter::WrapL(TInt aIndent, const TDesC& aText)
       
   750 	{
       
   751 	AppendSpacesL(aIndent);
       
   752 	WrapL(aIndent, aIndent, aText);
       
   753 	}
       
   754 
       
   755 EXPORT_C void CTextFormatter::WrapL(TInt aStartPosition, TInt aIndent, const TDesC& aText)
       
   756 	{
       
   757 	TUint originalAttributes = ConsoleAttributes::ENone;
       
   758 	ConsoleAttributes::TColor foregroundColor = ConsoleAttributes::EUnchanged;
       
   759 	ConsoleAttributes::TColor backgroundColor = ConsoleAttributes::EUnchanged;
       
   760 	if (iAttributesSupported)
       
   761 		{
       
   762 		GetCurrentAttributes(originalAttributes, foregroundColor, backgroundColor);
       
   763 		}
       
   764 
       
   765 	CTextBuffer* buffer = CTextBuffer::NewLC(0x100);
       
   766 	DecodeInteriorPodSequencesL(aText, *buffer);
       
   767 	TLex lex(buffer->Descriptor());
       
   768 	TInt linePos = aStartPosition;
       
   769 	while (!lex.Eos())
       
   770 		{
       
   771 		lex.Mark();
       
   772 		lex.SkipSpace();
       
   773 		TPtrC whiteSpace(lex.MarkedToken());
       
   774 		if (whiteSpace.Length() > 0)
       
   775 			{
       
   776 			TInt newLinePos;
       
   777 			do
       
   778 				{
       
   779 				newLinePos = whiteSpace.Find(KNewLine);
       
   780 				if (newLinePos >= 0)
       
   781 					{
       
   782 					AppendSpacesL(iAvailableWidth - linePos - 1);
       
   783 					AppendL(KNewLine);
       
   784 					AppendSpacesL(aIndent);
       
   785 					linePos = aIndent;
       
   786 					whiteSpace.Set(whiteSpace.Mid(newLinePos + KNewLine().Length()));
       
   787 					}
       
   788 				}
       
   789 				while (newLinePos >= 0);
       
   790 
       
   791 			if (iAvailableWidth < whiteSpace.Length())
       
   792 				{
       
   793 				AppendSpacesL(iAvailableWidth - linePos - 1);
       
   794 				AppendL(KNewLine);
       
   795 				AppendSpacesL(aIndent);
       
   796 				linePos = aIndent;
       
   797 				}
       
   798 			else
       
   799 				{
       
   800 				AppendL(whiteSpace);
       
   801 				linePos += whiteSpace.Length();
       
   802 				}
       
   803 			}
       
   804 
       
   805 		lex.Mark();
       
   806 		lex.SkipCharacters();
       
   807 		TPtrC word(lex.MarkedToken());
       
   808 		const TInt wordLength = word.Length();
       
   809 		if (wordLength > 0)
       
   810 			{
       
   811 			if ((linePos + wordLength + KNewLine().Length()) > iAvailableWidth)
       
   812 				{
       
   813 				AppendL(KNewLine);
       
   814 				AppendSpacesL(aIndent);
       
   815 				linePos = aIndent;
       
   816 				}
       
   817 
       
   818 			if (iAttributesSupported)
       
   819 				{
       
   820 				for (TInt i = 0; i < wordLength; ++i)
       
   821 					{
       
   822 					TUint attributes;
       
   823 					buffer->GetAttributes(lex.Offset() - wordLength + i, attributes, foregroundColor, backgroundColor);
       
   824 					SetAttributesL(originalAttributes | attributes, foregroundColor, backgroundColor);
       
   825 					AppendL(word[i]);
       
   826 					}
       
   827 				}
       
   828 			else
       
   829 				{
       
   830 				AppendL(word);
       
   831 				}
       
   832 			linePos += wordLength;
       
   833 			}
       
   834 		}
       
   835 
       
   836 	CleanupStack::PopAndDestroy(buffer);
       
   837 	SetAttributesL(originalAttributes, foregroundColor, backgroundColor);
       
   838 	}
       
   839 
       
   840 EXPORT_C void CTextFormatter::TabulateL(TInt aIndent, TInt aGap, const TDesC& aText)
       
   841 	{
       
   842 	TabulateL(aIndent, aGap, aText, EWrapLastColumn);
       
   843 	}
       
   844 
       
   845 EXPORT_C void CTextFormatter::TabulateL(TInt aIndent, TInt aGap, const TDesC& aText, TTabMode aMode)
       
   846 	{
       
   847 	CTextBuffer* scratchBuffer = NULL;
       
   848 	RArray<TInt> columnWidths;
       
   849 	CleanupClosePushL(columnWidths);
       
   850 	TLex lineLexer(aText);
       
   851 
       
   852 	// Find column widths.
       
   853 	TPtrC line;
       
   854 	while (NextLine(lineLexer, line))
       
   855 		{
       
   856 		TLex columnLexer(line);
       
   857 		TInt col = 0;
       
   858 		TPtrC column;
       
   859 		while (NextColumn(columnLexer, column))
       
   860 			{
       
   861 			if (col >= columnWidths.Count())
       
   862 				{
       
   863 				User::LeaveIfError(columnWidths.Append(aGap));
       
   864 				}
       
   865 			TInt thisColumnWidth = ActualLength(column);
       
   866 			if (columnWidths[col] < (thisColumnWidth + aGap))
       
   867 				{
       
   868 				columnWidths[col] = (thisColumnWidth + aGap);
       
   869 				}
       
   870 			++col;
       
   871 			}
       
   872 		}
       
   873 
       
   874 	const TInt numCols = columnWidths.Count();
       
   875 
       
   876 	if (numCols == 0)
       
   877 		{
       
   878 		// No columns found, so just copy aText directly.
       
   879 		AppendL(aText);
       
   880 		CleanupStack::PopAndDestroy(&columnWidths);
       
   881 		return;
       
   882 		}
       
   883 
       
   884 	if (aMode == EWrapLastColumn)
       
   885 		{
       
   886 		// Find the widest of all but the last column.
       
   887 		TInt sum = aIndent;
       
   888 		for (TInt i = 0; i < (numCols - 1); ++i)
       
   889 			{
       
   890 			sum += columnWidths[i];
       
   891 			}
       
   892 		TInt remainingSpace = iAvailableWidth - sum;
       
   893 		if (remainingSpace < 0)
       
   894 			{
       
   895 			// If you hit this, it means that the text cannot be columnised because the columns preceding the last one take up more space than the overall.
       
   896 			User::Leave(KErrTooBig); // Let's go for something marginally more descriptive than KErrGeneral
       
   897 			}
       
   898 		// Assign the remaining space to the last column (which will be wrapped).
       
   899 		columnWidths[numCols - 1] = remainingSpace; 
       
   900 		}
       
   901 	else if (aMode == ETruncateLongestColumn)
       
   902 		{
       
   903 		// Find the total width of all the columns.
       
   904 		TInt sum = aIndent;
       
   905 		for (TInt i = 0; i < numCols; ++i)
       
   906 			{
       
   907 			sum += columnWidths[i];
       
   908 			}
       
   909 		TInt excess = iAvailableWidth - sum;
       
   910 		if (excess < 0)
       
   911 			{
       
   912 			// Not enough space, so steal from the widest column until there is.
       
   913 			while (excess < 0)
       
   914 				{
       
   915 				TInt widestColumn = -1;
       
   916 				TInt widestColumnWidth = 0;
       
   917 				for (TInt i = 0; i < numCols; ++i)
       
   918 					{
       
   919 					if (columnWidths[i] > widestColumnWidth)
       
   920 						{
       
   921 						widestColumnWidth = columnWidths[i];
       
   922 						widestColumn = i;
       
   923 						}
       
   924 					}
       
   925 				if (widestColumn < 0)
       
   926 					{
       
   927 					User::Leave(KErrGeneral);
       
   928 					}
       
   929 				--columnWidths[widestColumn];
       
   930 				++excess;
       
   931 				}
       
   932 			}
       
   933 		else
       
   934 			{
       
   935 			// Assign execess to the last column.
       
   936 			columnWidths[numCols - 1] += excess; 
       
   937 			}
       
   938 		}
       
   939 	else if (aMode == EIgnoreAvailableWidth)
       
   940 		{
       
   941 		// just use the column widths we've already worked out, no matter if they're too wide.
       
   942 		}
       
   943 	else
       
   944 		{
       
   945 		ASSERT(EFalse);
       
   946 		}
       
   947 
       
   948 	// Write formatted text to the buffer.
       
   949 	lineLexer = TLex(aText);
       
   950 	TInt linePos = 0;
       
   951 	while (NextLine(lineLexer, line))
       
   952 		{
       
   953 		AppendSpacesL(aIndent);
       
   954 		linePos += aIndent;
       
   955 		TLex columnLexer(line);
       
   956 		TInt col = 0;
       
   957 		TPtrC column;
       
   958 		while (NextColumn(columnLexer, column))
       
   959 			{
       
   960 			TBool isLastColumn(col == (numCols - 1));
       
   961 			const TInt columnWidth = columnWidths[col];
       
   962 			if ((aMode == ETruncateLongestColumn) || !isLastColumn)
       
   963 				{
       
   964 				if (scratchBuffer == NULL)
       
   965 					{
       
   966 					scratchBuffer = CTextBuffer::NewLC(0x100);
       
   967 					}
       
   968 				else
       
   969 					{
       
   970 					scratchBuffer->Zero();
       
   971 					}
       
   972 				DecodeInteriorPodSequencesL(column, *scratchBuffer);
       
   973 				TInt availableWidth = columnWidth;
       
   974 				if (!isLastColumn)
       
   975 					{
       
   976 					availableWidth -= aGap;
       
   977 					}
       
   978 				if (scratchBuffer->Descriptor().Length() > availableWidth)
       
   979 					{
       
   980 					scratchBuffer->Delete(availableWidth, scratchBuffer->Descriptor().Length() - availableWidth);
       
   981 					}
       
   982 				AppendL(*scratchBuffer);
       
   983 				AppendSpacesL(columnWidth - scratchBuffer->Descriptor().Length());
       
   984 				linePos += columnWidth;
       
   985 				}
       
   986 			else if (aMode == EIgnoreAvailableWidth)
       
   987 				{
       
   988 				AppendL(column);
       
   989 				if (!isLastColumn)
       
   990 					{
       
   991 					AppendSpacesL(columnWidth - column.Length());
       
   992 					}
       
   993 				linePos += columnWidth;
       
   994 				}
       
   995 			else
       
   996 				{
       
   997 				WrapL(linePos, linePos, column);
       
   998 				}
       
   999 			++col;
       
  1000 			}
       
  1001 		AppendL(KNewLine);
       
  1002 		linePos = 0;
       
  1003 		}
       
  1004 
       
  1005 	if (scratchBuffer)
       
  1006 		{
       
  1007 		CleanupStack::PopAndDestroy(scratchBuffer);
       
  1008 		}
       
  1009 	CleanupStack::PopAndDestroy(&columnWidths);
       
  1010 	}
       
  1011 
       
  1012 EXPORT_C void CTextFormatter::ColumnizeL(TInt aIndent, TInt aGap, const TDesC& aText)
       
  1013 	{
       
  1014 	// Store the tab delimited text as an array of TPtrCs.
       
  1015 	RArray<TPtrC> items;
       
  1016 	CleanupClosePushL(items);
       
  1017 	TLex lex(aText);
       
  1018 	TPtrC column;
       
  1019 	while (NextColumn(lex, column))
       
  1020 		{
       
  1021 		User::LeaveIfError(items.Append(column));
       
  1022 		}
       
  1023 	ColumnizeL(aIndent, aGap, items.Array());
       
  1024 	CleanupStack::PopAndDestroy(1, &items);
       
  1025 	}
       
  1026 
       
  1027 EXPORT_C void CTextFormatter::ColumnizeL(TInt aIndent, TInt aGap, const TArray<TPtrC>& aItems)
       
  1028 	{
       
  1029 	// Lays out tab delimited data as a set of columns that read like a news paper
       
  1030 	// (i.e. starting with the left most column, you read down to the bottom of it
       
  1031 	// and then start reading the next column from the top, etc.).
       
  1032 
       
  1033 	// Determine the smallest number of rows that allows all the data to fit
       
  1034 	// the available horizontal space. The algorithm works by iteratively increasing
       
  1035 	// the number of rows from one until a fit is found.
       
  1036 	const TInt numItems = aItems.Count();
       
  1037 	RArray<TInt> columnWidths;
       
  1038 	CleanupClosePushL(columnWidths);
       
  1039 	TInt numRows = 0;
       
  1040 	TBool fits(EFalse);
       
  1041 	while (!fits)
       
  1042 		{
       
  1043 		++numRows;
       
  1044 		columnWidths.Reset();
       
  1045 		TInt requiredWidth = aIndent;
       
  1046 		TInt col = 0;
       
  1047 		TInt i = 0;
       
  1048 		while (i < numItems)
       
  1049 			{
       
  1050 			for (TInt row = 0; row < numRows; ++row)
       
  1051 				{
       
  1052 				if (columnWidths.Count() <= col)
       
  1053 					{
       
  1054 					User::LeaveIfError(columnWidths.Append(0));
       
  1055 					}
       
  1056 				TInt thisItemWidth = ActualLength(aItems[i]);
       
  1057 				if (thisItemWidth > columnWidths[col])
       
  1058 					{
       
  1059 					columnWidths[col] = thisItemWidth;
       
  1060 					}
       
  1061 				if (++i >= numItems)
       
  1062 					{
       
  1063 					break;
       
  1064 					}
       
  1065 				}
       
  1066 			requiredWidth += columnWidths[col];
       
  1067 			if ((requiredWidth + aGap) > iAvailableWidth)
       
  1068 				{
       
  1069 				if ((requiredWidth + KNewLine().Length()) > iAvailableWidth)
       
  1070 					{
       
  1071 					if (col > 0)
       
  1072 						{
       
  1073 						// Not enough space with this number of rows, so try another row.
       
  1074 						i = 0;
       
  1075 						break;
       
  1076 						}
       
  1077 					else
       
  1078 						{
       
  1079 						// Not enough space even with just one column. Lay out as a single column anyway and accept ugly wrapping by the console.
       
  1080 						CleanupStack::PopAndDestroy(1, &columnWidths);
       
  1081 						for (TInt i = 0; i < numItems; ++i)
       
  1082 							{
       
  1083 							AppendSpacesL(aIndent);
       
  1084 							AppendL(aItems[i]);
       
  1085 							AppendL(KNewLine);
       
  1086 							}
       
  1087 						return;
       
  1088 						}
       
  1089 					}
       
  1090 				else
       
  1091 					{
       
  1092 					requiredWidth += KNewLine().Length();
       
  1093 					}
       
  1094 				}
       
  1095 			else
       
  1096 				{
       
  1097 				requiredWidth += aGap;
       
  1098 				}
       
  1099 			++col;
       
  1100 			}
       
  1101 		if (i >= numItems)
       
  1102 			{
       
  1103 			fits = ETrue;
       
  1104 			}
       
  1105 		}
       
  1106 
       
  1107 	// Layout the columns.
       
  1108 	const TInt numCols = columnWidths.Count();
       
  1109 	for (TInt row = 0; row < numRows; ++row)
       
  1110 		{
       
  1111 		AppendSpacesL(aIndent);
       
  1112 		for (TInt col = 0; col < numCols; ++col)
       
  1113 			{
       
  1114 			TInt index = (numRows * col) + row;
       
  1115 			if (index < numItems)
       
  1116 				{
       
  1117 				TPtrC item(aItems[index]);
       
  1118 				DoAppendPodL(item);
       
  1119 				TInt gap = (col == (numCols - 1)) ? 0 : aGap;
       
  1120 				AppendSpacesL((columnWidths[col] + gap) - ActualLength(item));
       
  1121 				}
       
  1122 			}
       
  1123 		AppendL(KNewLine);
       
  1124 		}
       
  1125 
       
  1126 	CleanupStack::PopAndDestroy(1, &columnWidths);
       
  1127 	}
       
  1128 
       
  1129 EXPORT_C void CTextFormatter::AppendPodL(const TDesC& aPod)
       
  1130 	{
       
  1131 	TPodFormatter podFormatter(*this);
       
  1132 	podFormatter.FormatL(aPod);
       
  1133 	}
       
  1134 
       
  1135 EXPORT_C TInt CTextFormatter::Write()
       
  1136 	{
       
  1137 	return CTextBuffer::Write(*iWriteHandle);
       
  1138 	}
       
  1139 
       
  1140 void CTextFormatter::DoAppendPodL(const TDesC& aPod)
       
  1141 	{
       
  1142 	DecodeInteriorPodSequencesL(aPod, *this);
       
  1143 	}
       
  1144 
       
  1145 void CTextFormatter::DecodeInteriorPodSequencesL(const TDesC& aPod, CTextBuffer& aBuffer) const
       
  1146 	{
       
  1147 	TPodLexer lexer(aPod);
       
  1148 	TBool eop(EFalse);
       
  1149 	TBool eos(EFalse);
       
  1150 
       
  1151 	TUint originalAttributes = ConsoleAttributes::ENone;
       
  1152 	ConsoleAttributes::TColor foregroundColor = ConsoleAttributes::EUnchanged;
       
  1153 	ConsoleAttributes::TColor backgroundColor = ConsoleAttributes::EUnchanged;
       
  1154 	if (iAttributesSupported)
       
  1155 		{
       
  1156 		aBuffer.GetCurrentAttributes(originalAttributes, foregroundColor, backgroundColor);
       
  1157 		}
       
  1158 	TUint currentAttributes = originalAttributes;
       
  1159 
       
  1160 	while (!eos)
       
  1161 		{
       
  1162 		TPtrC token;
       
  1163 		TPodLexer::TTokenType tokenType;
       
  1164 		TUint attributes;
       
  1165 		lexer.NextTokenL(token, tokenType, attributes, eop, eos);
       
  1166 
       
  1167 		switch (tokenType)
       
  1168 			{
       
  1169 			case TPodLexer::EAttributePush:
       
  1170 			case TPodLexer::EAttributePop:
       
  1171 				if (!iAttributesSupported && (attributes & TPodLexer::EBold))
       
  1172 					{
       
  1173 					aBuffer.AppendL('*');
       
  1174 					}
       
  1175 				else if (!iAttributesSupported && (attributes & TPodLexer::EItalic))
       
  1176 					{
       
  1177 					aBuffer.AppendL('\'');
       
  1178 					}
       
  1179 				else if ((!iAttributesSupported && (attributes & TPodLexer::EFileName)) || (attributes & TPodLexer::TPodLexer::ECode))
       
  1180 					{
       
  1181 					aBuffer.AppendL('"');
       
  1182 					}
       
  1183 				break;
       
  1184 			case TPodLexer::ELink:
       
  1185 				{
       
  1186 				TInt pos = token.Locate('|');
       
  1187 				if (pos >= 0)
       
  1188 					{
       
  1189 					token.Set(token.Left(pos));
       
  1190 					}
       
  1191 				}
       
  1192 				// Deliberate fall through.
       
  1193 			case TPodLexer::ETextBlock:
       
  1194 			case TPodLexer::ECodeBlock:
       
  1195 			case TPodLexer::EIndexEntry:
       
  1196 				if (iAttributesSupported)
       
  1197 					{
       
  1198 					if ((attributes == 0) || (attributes & (TPodLexer::ENull | TPodLexer::ECode)))
       
  1199 						{
       
  1200 						currentAttributes = originalAttributes;
       
  1201 						}
       
  1202 					if (attributes & (TPodLexer::EBold | TPodLexer::EItalic | TPodLexer::EFileName))
       
  1203 						{
       
  1204 						currentAttributes |= ConsoleAttributes::EBold;
       
  1205 						}
       
  1206 					aBuffer.SetAttributesL(currentAttributes);
       
  1207 					}
       
  1208 				aBuffer.AppendL(token);
       
  1209 				break;
       
  1210 			default:
       
  1211 				ASSERT(EFalse);
       
  1212 			}
       
  1213 		}
       
  1214 
       
  1215 	if (iAttributesSupported && (currentAttributes != originalAttributes))
       
  1216 		{
       
  1217 		aBuffer.SetAttributesL(originalAttributes);
       
  1218 		}
       
  1219 	}
       
  1220 
       
  1221 EXPORT_C void CTextFormatter::Zero()
       
  1222 	{
       
  1223 	CTextBuffer::Zero();
       
  1224 	}
       
  1225 
       
  1226 EXPORT_C void CTextFormatter::Reset()
       
  1227 	{
       
  1228 	CTextBuffer::Reset();
       
  1229 	}
       
  1230 
       
  1231 EXPORT_C void CTextFormatter::ResetText()
       
  1232 	{
       
  1233 	CTextBuffer::ResetText();
       
  1234 	}
       
  1235 
       
  1236 TBool CTextFormatter::NextColumn(TLex& aLex, TPtrC& aPtr) const
       
  1237 	{
       
  1238 	aLex.Mark();
       
  1239 	while (!aLex.Eos())
       
  1240 		{
       
  1241 		if (aLex.Get() == '\t')
       
  1242 			{
       
  1243 			aLex.UnGet();
       
  1244 			aPtr.Set(aLex.MarkedToken());
       
  1245 			aLex.Get();
       
  1246 			return ETrue;
       
  1247 			}
       
  1248 		}
       
  1249 	if (aLex.TokenLength() > 0)
       
  1250 		{
       
  1251 		aPtr.Set(aLex.MarkedToken());
       
  1252 		return ETrue;
       
  1253 		}
       
  1254 	return EFalse;
       
  1255 	}
       
  1256 
       
  1257 TBool CTextFormatter::NextLine(TLex& aLex, TPtrC& aPtr) const
       
  1258 	{
       
  1259 	aLex.Mark();
       
  1260 	while (!aLex.Eos())
       
  1261 		{
       
  1262 		TChar ch = aLex.Get();
       
  1263 		if (ch == '\r')
       
  1264 			{
       
  1265 			if (aLex.Get() == '\n')
       
  1266 				{
       
  1267 				aLex.UnGet();
       
  1268 				aLex.UnGet();
       
  1269 				aPtr.Set(aLex.MarkedToken());
       
  1270 				aLex.Get();
       
  1271 				aLex.Get();
       
  1272 				return ETrue;
       
  1273 				}
       
  1274 			else
       
  1275 				{
       
  1276 				aLex.UnGet();
       
  1277 				}
       
  1278 			}
       
  1279 		}
       
  1280 	if (aLex.TokenLength() > 0)
       
  1281 		{
       
  1282 		aPtr.Set(aLex.MarkedToken());
       
  1283 		return ETrue;
       
  1284 		}
       
  1285 	return EFalse;
       
  1286 	}
       
  1287 
       
  1288 TInt CTextFormatter::ActualLength(const TDesC& aPod) const
       
  1289 	{
       
  1290 	CTextBuffer* buffer = CTextBuffer::NewLC(0x100);
       
  1291 	DecodeInteriorPodSequencesL(aPod, *buffer);
       
  1292 	TInt length = buffer->Descriptor().Length();
       
  1293 	CleanupStack::PopAndDestroy(buffer);
       
  1294 	return length;
       
  1295 	}