libraries/iosrv/client/pod_formatter.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 45 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// pod_formatter.cpp
// 
// Copyright (c) 2009 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
// 
// Initial Contributors:
// Accenture - Initial contribution
//

#include "pod_formatter.h"

const TInt KGap = 2;

_LIT(KPartialCommandStart, "\r\n=");
_LIT(KCommandStart, "\r\n\r\n=");
_LIT(KBlankLine, "\r\n\r\n");
_LIT(KNewLine, "\r\n");

using namespace IoUtils;


TPodFormatter::TPodFormatter(CTextFormatter& aFormatter)
	: iFormatter(aFormatter)
	{
	}

void TPodFormatter::FormatL(const TDesC& aPod)
	{
	iPodLex = aPod;
	while (!iPodLex.Eos())
		{
		TPtrC command(NextCommand());
		if (command == _L("pod"))
			{
			SkipToNextBlankLine();
			}
		else if ((command == _L("head1")) || (command == _L("head2")))
			{
			iPodLex.SkipSpaceAndMark();
			SkipToLineEnd();
			iFormatter.SetAttributesL(ConsoleAttributes::EBold | ConsoleAttributes::EUnderscore);
			iFormatter.WrapL(0, iPodLex.MarkedToken());
			iFormatter.SetAttributesL(ConsoleAttributes::ENone);
			iFormatter.AppendL(KBlankLine);
			}
		else if (command == _L("cut"))
			{
			SkipToNextBlankLine();
			break;
			}
		else if (command == _L("begin"))
			{
			TPtrC nextCommand;
			do
				{
				nextCommand.Set(NextCommand());
				}
				while ((nextCommand.Length() > 0) && (nextCommand != _L("end")));

			SkipToNextBlankLine();
			}
		else if (command == _L("for"))
			{
			SkipToNextBlankLine();
			}
		else if (command == _L("over"))
			{
			iPodLex.SkipSpace();
			TUint indent;
			User::LeaveIfError(iPodLex.Val(indent));
			OverL(indent);
			}

		FormatToNextCommandL();
		}
	}

void TPodFormatter::OverL(TInt aIndent)
	{
	CTextBuffer* buffer = CTextBuffer::NewLC(0x100);

	while (!iPodLex.Eos())
		{
		FormatToNextCommandL(aIndent);

		TPtrC command(NextCommand());
		if (command == _L("item"))
			{
			iPodLex.SkipSpaceAndMark();
			SkipToLineEnd();
			buffer->AppendL(iPodLex.MarkedToken());
			iPodLex.SkipSpace();
			//buffer->AppendL('\t');
			//buffer->AppendL(TextToNextCommand());
			// Need to split the text up putting a tab in front of every paragraph of text, in case the item description is multi-paragraph.
			// If we don't, the next paragraph will end up in column one which will break the column formatter.
			// If there's a neater way of doing this, someone feel free! -TomS
			TPtrC text(TextToNextCommand());
			while(text.Length())
				{
				TInt nextNewLine = text.Find(KNewLine);
				if (nextNewLine == KErrNotFound) nextNewLine = text.Length();
				TPtrC line(text.Left(nextNewLine+KNewLine().Length()));
				buffer->AppendL('\t');
				buffer->AppendL(line);
				text.Set(text.Mid(line.Length()));
				}
			buffer->AppendL(KNewLine);
			}
		else if (command == _L("back"))
			{
			break;
			}
		else if (command == _L("over"))
			{
			if (buffer->Descriptor().Length() > 0)
				{
				iFormatter.TabulateL(aIndent, KGap, buffer->Descriptor(), EWrapLastColumn);
				iFormatter.AppendL(KNewLine);
				buffer->Zero();
				}
			iPodLex.SkipSpace();
			TUint indent;
			User::LeaveIfError(iPodLex.Val(indent));
			OverL(indent + aIndent);
			}
		}

	if (buffer->Descriptor().Length() > 0)
		{
		iFormatter.TabulateL(aIndent, KGap, buffer->Descriptor(), EWrapLastColumn);
		iFormatter.AppendL(KNewLine);
		}

	CleanupStack::PopAndDestroy(buffer);
	}

void TPodFormatter::FormatToNextCommandL(TInt aIndent)
	{
	FOREVER
		{
		TPtrC paragraph(NextParagraph());
		if (paragraph.Length() > 0)
			{
			if (TChar(paragraph[0]).IsSpace())
				{
				iFormatter.AppendL(paragraph);
				}
			else
				{
				iFormatter.WrapL(aIndent, paragraph);
				}
			iFormatter.AppendL(KNewLine);
			}
		else
			{
			break;
			}
		}
	}

TPtrC TPodFormatter::NextCommand()
	{
	TPtrC command;
	if (SkipToNextCommand() == KErrNone)
		{
		iPodLex.Mark();
		iPodLex.SkipCharacters();
		command.Set(iPodLex.MarkedToken());
		}
	return command;
	}

TPtrC TPodFormatter::NextParagraph()
	{
	// Consume leading new line characters.
	while (iPodLex.Remainder().Find(KNewLine) == 0)
		{
		if (AtCommandStart())
			{
			return TPtrC();
			}
		iPodLex.Inc(KNewLine().Length());
		}
	
	iPodLex.Mark();

	if (iPodLex.Peek().IsSpace())
		{
		// This line has leading white space - treat everything up to the next blank line as a single paragraph.
		if (SkipToNextBlankLine() != KErrNone)
			{
			SkipToLineEnd();
			}
		}
	else if (SkipToNextLine() != KErrNone)
		{
		SkipToLineEnd();
		}

	return iPodLex.MarkedToken();
	}

TPtrC TPodFormatter::TextToNextCommand()
	{
	TInt initialOffset = iPodLex.Offset();
	iPodLex.Mark();

	if (SkipToNextCommand() == KErrNone)
		{
		if (iPodLex.Offset() >= KCommandStart().Length())
			{
			iPodLex.Inc(-(KCommandStart().Length()));
			}
		else
			{
			iPodLex.Inc(-(iPodLex.Remainder().Length()));
			}
		}
	else
		{
		iPodLex.Inc(iPodLex.Remainder().Length());
		}

	if (initialOffset < iPodLex.Offset())
		{
		return iPodLex.MarkedToken();
		}
	else
		{
		return TPtrC(NULL, 0);
		}
	}

void TPodFormatter::SkipToLineEnd()
	{
	if (SkipTo(KNewLine) != KErrNone)
		{
		iPodLex.Inc(iPodLex.Remainder().Length());
		}
	}

TInt TPodFormatter::SkipToNextLine()
	{
	TInt ret = SkipTo(KNewLine);
	if (ret == KErrNone)
		{
		iPodLex.Inc(KNewLine().Length());
		}
	return ret;
	}

TInt TPodFormatter::SkipToNextCommand()
	{
	if (iPodLex.Remainder().Find(KPartialCommandStart) == 0)
		{
		if (iPodLex.Offset() == 0)
			{
			iPodLex.Inc(KPartialCommandStart().Length());
			return KErrNone;
			}
		else
			{
			iPodLex.Inc(-2);
			if (iPodLex.Remainder().Find(KCommandStart) == 0)
				{
				iPodLex.Inc(KCommandStart().Length());
				return KErrNone;
				}
			else
				{
				iPodLex.Inc(2);
				}
			}
		}

	TInt ret = SkipTo(KCommandStart);
	if (ret == KErrNone)
		{
		iPodLex.Inc(KCommandStart().Length());
		}
	return ret;
	}

TInt TPodFormatter::SkipToNextBlankLine()
	{
	TInt ret = SkipTo(KBlankLine);
	if (ret == KErrNone)
		{
		iPodLex.Inc(2);
		}
	return ret;
	}

TInt TPodFormatter::SkipTo(const TDesC& aDes)
	{
	TInt ret = iPodLex.Remainder().Find(aDes);
	if (ret >= 0)
		{
		iPodLex.Inc(ret);
		return KErrNone;
		}
	return KErrNotFound;
	}

TBool TPodFormatter::AtCommandStart()
	{
	return ((iPodLex.Remainder().Find(KCommandStart) == 0) || (iPodLex.Remainder().Find(KPartialCommandStart) == 0));
	}