libraries/iosrv/server/persistentconsole.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
child 100 706c7a69e448
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// persistentconsole.cpp
// 
// Copyright (c) 2008 - 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 "persistentconsole.h"
#include <e32hashtab.h>


static void CleanupNullPointer(TAny* aPtrPtr)
	{
	*((TAny**)aPtrPtr) = NULL;
	}
	
static void CleanupNullPointerPushL(TAny** aPtr)
	{
	CleanupStack::PushL(TCleanupItem(CleanupNullPointer, aPtr));
	}
	
_LIT(KProxySuffix, "_proxy");

//______________________________________________________________________________
//						CIoPersistentConsole
CIoPersistentConsole* CIoPersistentConsole::NewLC(const TDesC& aName, const TDesC& aTitle, CIoServer& aServer, const RMsg& aMessage)
	{
	CIoPersistentConsole* self = new(ELeave)CIoPersistentConsole(aServer);
	CleanupClosePushL(*self);
	self->ConstructL(aName, aTitle, aMessage);
	return self;
	}
	
TBool CIoPersistentConsole::CanConnectReaderL(const MIoReadEndPoint& aReader) const
	{
	// check that the candidate end point will not result in a circular connection of
	// persistent consoles if it's connected to this one.
	
	RHashSet<TInt> chained; // addresses of CIoPersistentConsole's in any chain
	CleanupClosePushL(chained);
	chained.InsertL((TInt)this);
	const MIoReadEndPoint* nextReader = &aReader;
	while (nextReader && nextReader->IoepIsType(RIoHandle::EPersistentConsole))
		{
		const CIoPersistentConsole* next = (const CIoPersistentConsole*)nextReader;
		if (chained.Find((TInt)next))
			{
			CleanupStack::PopAndDestroy();
			return EFalse;
			}
		chained.InsertL((TInt)next);
		nextReader = next->TransientReader();
		}
	CleanupStack::PopAndDestroy();
	return ETrue;	
	}
	
void CIoPersistentConsole::AttachTransientReaderL(MIoReadEndPoint& aReader, CIoSession* aDetachOnClose)
	{
	if (!CanConnectReaderL(aReader)) User::Leave(KErrCouldNotConnect);	
		
	if (iTransientReadEndPoint)
		{
		User::Leave(KErrInUse);
		}
		
	
	iTransientReadEndPoint = &aReader;
	CleanupNullPointerPushL((TAny**)&iTransientReadEndPoint);
	
	TInt fgProxyPos = ReaderProxyIndex(AttachedReader());
	if (fgProxyPos != KErrNotFound)
		{
		iTransientReadEndPoint->IorepAttachL(*iReaderProxies[fgProxyPos], RIoEndPoint::EForeground);
		}
	
	TInt i = 0;
	TRAPD(err, 
		for (i=0; i<iReaderProxies.Count(); ++i)
			{
			if (i != fgProxyPos)
				{
				iTransientReadEndPoint->IorepAttachL(*iReaderProxies[i], RIoEndPoint::EBackground);
				}
			}
		);
		
	if (err)
		{
		// deatch the readers the we successfully attached before failure
		for (TInt j=0; j<i; ++j)
			{
			iTransientReadEndPoint->IorepDetach(*iReaderProxies[j]);
			}
		// also make sure that the foreground reader is deatched
		if (fgProxyPos >= i)
			{
			iTransientReadEndPoint->IorepDetach(*iReaderProxies[fgProxyPos]);
			}
		User::Leave(err);
		}
	CleanupStack::Pop();
	
	iReadEndPointDetachOnClose = aDetachOnClose;
		
	// now foreward any outstanding read requests
	for (TInt i=0; i<iReaderProxies.Count(); ++i)
		{
		iReaderProxies[i]->TransientReaderAttached(*iTransientReadEndPoint);
		}
		
	MIoReader* fg = AttachedReader();
	if (fg)
		{
		fg->IorReaderChange(RIoReadHandle::EGainedForeground | RIoReadHandle::EConsoleSizeChanged);
		}
	}
	
void CIoPersistentConsole::DetachTransientReader()
	{
	if (!iTransientReadEndPoint)
		{
		return;
		}
	MIoReadEndPoint* detaching = iTransientReadEndPoint;
	iTransientReadEndPoint = NULL;

	TInt fgReaderPos = ReaderProxyIndex(AttachedReader());
	for (TInt i=0; i<iReaderProxies.Count(); ++i)
		{
		if (i!=fgReaderPos)
			{
			detaching->IorepDetach(*iReaderProxies[i]);
			}
		}
	if (fgReaderPos!=KErrNotFound)
		{
		detaching->IorepDetach(*iReaderProxies[fgReaderPos]);
		}
	iReadEndPointDetachOnClose = NULL;

	SendReadDetachNotifications();
	}
	
const MIoReadEndPoint* CIoPersistentConsole::TransientReader() const
	{
	return iTransientReadEndPoint;
	}	

TBool CIoPersistentConsole::CanConnectWriterL(const MIoWriteEndPoint& aWriter) const
	{
	// check that the candidate end point will not result in a circular connection of
	// persistent consoles if it's connected to this one.
	
	RHashSet<TInt> chained; // addresses of CIoPersistentConsole's in any chain
	CleanupClosePushL(chained);
	chained.InsertL((TInt)this);
	const MIoWriteEndPoint* nextWriter = &aWriter;
	while (nextWriter && nextWriter->IoepIsType(RIoHandle::EPersistentConsole))
		{
		const CIoPersistentConsole* next = (const CIoPersistentConsole*)nextWriter;
		if (chained.Find((TInt)next))
			{
			CleanupStack::PopAndDestroy();
			return EFalse;
			}
		chained.InsertL((TInt)next);
		nextWriter = next->TransientWriter();
		}
	CleanupStack::PopAndDestroy();
	return ETrue;	
	}
	
void CIoPersistentConsole::AttachTransientWriterL(MIoWriteEndPoint& aWriter, CIoSession* aDetachOnClose)
	{
	if (!CanConnectWriterL(aWriter)) User::Leave(KErrCouldNotConnect);	
	
	if (iTransientWriteEndPoint)
		{
		User::Leave(KErrInUse);
		}
	iTransientWriteEndPoint = &aWriter;
	CleanupNullPointerPushL((TAny**)&iTransientWriteEndPoint);
	
	TInt i = 0;
	TRAPD(err, 
		for (i=0; i<iWriterProxies.Count(); ++i)
			{
			iTransientWriteEndPoint->IowepAttachL(*iWriterProxies[i]);
			}
		);
	if (err)
		{
		// deatch the writers the we successfully attached before failure
		for (TInt j=0; j<i; ++j)
			{
			iWriterProxies[j]->TransientWriterDetach(*iTransientWriteEndPoint);
			}
		User::Leave(err);
		}
	CleanupStack::Pop();
	
	iWriteEndPointDetachOnClose = aDetachOnClose;
	
	TRAP_IGNORE(iTransientWriteEndPoint->IowepSetTitleL(iTitleSetter));
	
	for (TInt i=0; i<iWriterProxies.Count(); ++i)
		{
		iWriterProxies[i]->TransientWriterAttached(*iTransientWriteEndPoint);
		}		
	}
	
void CIoPersistentConsole::DetachTransientWriter()
	{
	if (!iTransientWriteEndPoint)
		{
		return;
		}
	MIoWriteEndPoint* detaching = iTransientWriteEndPoint;
	iTransientWriteEndPoint = NULL;
	for (TInt i=0; i<iWriterProxies.Count(); ++i)
		{
		iWriterProxies[i]->TransientWriterDetach(*detaching);
		}
	iWriteEndPointDetachOnClose = NULL;
	
	SendWriteDetachNotifications();
	}
	
const MIoWriteEndPoint* CIoPersistentConsole::TransientWriter() const
	{
	return iTransientWriteEndPoint;
	}
	
MIoWriteEndPoint* CIoPersistentConsole::TransientWriter()
	{
	return iTransientWriteEndPoint;
	}
	
void CIoPersistentConsole::NotifyReadDetachL(const RMsg& aMessage)
	{
	if ((iReaderProxies.Count()==0) || !iTransientReadEndPoint)
		{
		Complete(aMessage, KErrNone);
		}
	else
		{
		iReadDetachNotifications.AppendL(aMessage);
		}
	}
	
void CIoPersistentConsole::CancelNotifyReadDetach(TRequestStatus* aClientStatus)
	{
	for (TInt i=0; i<iReadDetachNotifications.Count(); ++i)
		{
		if (iReadDetachNotifications[i].ClientStatus() == aClientStatus)
			{
			Complete(iReadDetachNotifications[i], KErrCancel);
			iReadDetachNotifications.Remove(i);
			return;
			}
		}
	}
	
void CIoPersistentConsole::NotifyWriteDetachL(const RMsg& aMessage)
	{
	if ((iWriterProxies.Count()==0) || !iTransientWriteEndPoint)
		{
		Complete(aMessage, KErrNone);
		}
	else
		{
		iWriteDetachNotifications.AppendL(aMessage);
		}
	}
	
void CIoPersistentConsole::CancelNotifyWriteDetach(TRequestStatus* aClientStatus)
	{
	for (TInt i=0; i<iWriteDetachNotifications.Count(); ++i)
		{
		if (iWriteDetachNotifications[i].ClientStatus() == aClientStatus)
			{
			Complete(iWriteDetachNotifications[i], KErrCancel);
			iWriteDetachNotifications.Remove(i);
			return;
			}
		}
	}
	
TName CIoPersistentConsole::TransientReaderName()
	{
	if (iTransientReadEndPoint)
		{
		return iTransientReadEndPoint->IoepName();
		}
	else
		{
		return KNullDesC();
		}
	}
	
TName CIoPersistentConsole::TransientWriterName()
	{
	if (iTransientWriteEndPoint)
		{
		return iTransientWriteEndPoint->IoepName();
		}
	else
		{
		return KNullDesC();
		}
	}
	
TThreadId CIoPersistentConsole::Creator()
	{
	return iCreator.Id();
	}
	
TName CIoPersistentConsole::Name() const
	{
	return iName;
	}

TBool CIoPersistentConsole::IsType(RIoHandle::TType aType) const
	{
	if (aType == RIoHandle::EPersistentConsole)
		{
		return ETrue;
		}
	else
		{
		return CIoConsole::IsType(aType);
		}
	}
	
void CIoPersistentConsole::SessionClosed(const CIoSession& aSession)
	{
	if (&aSession == iReadEndPointDetachOnClose)
		{
		DetachTransientReader();
		}
	if (&aSession == iWriteEndPointDetachOnClose)
		{
		DetachTransientWriter();
		}
	}
	
void CIoPersistentConsole::ClosedBy(const CIoSession& aSession)
	{
	SessionClosed(aSession);
	}
	
void CIoPersistentConsole::SendReadDetachNotifications()
	{
	for (TInt i=0; i<iReadDetachNotifications.Count(); ++i)
		{
		Complete(iReadDetachNotifications[i], KErrNone);
		}
	iReadDetachNotifications.Reset();
	}
	
void CIoPersistentConsole::SendWriteDetachNotifications()
	{
	for (TInt i=0; i<iWriteDetachNotifications.Count(); ++i)
		{
		Complete(iWriteDetachNotifications[i], KErrNone);
		}
	iWriteDetachNotifications.Reset();
	}

//______________________________________________________________________________
//		MIoReadEndPoint implementation - to handle reads from persistent side
TInt CIoPersistentConsole::HandleReaderAttached(MIoReader& aReader)
	{
	TIoReaderProxy* proxy = new TIoReaderProxy(aReader, *this);
	TInt err = proxy ? KErrNone : KErrNoMemory;
	if (err==KErrNone)
		{
		err = iReaderProxies.Append(proxy);
		}
	
	if ((err == KErrNone) && iTransientReadEndPoint)
		{
		TRAP(err, iTransientReadEndPoint->IorepAttachL(*proxy, RIoEndPoint::EBackground));
		}

	if (err != KErrNone)
		{
		TInt pos = ReaderProxyIndex(proxy);
		if (pos!=KErrNotFound)
			{
			iReaderProxies.Remove(pos);
			}
		delete proxy;
		}		
	return err;
	}
	
void CIoPersistentConsole::HandleReaderDetached(MIoReader& aReader)
	{
	TInt pos = ReaderProxyIndex(&aReader);
	if (pos!=KErrNotFound)
		{
		if (iTransientReadEndPoint)
			{
			iTransientReadEndPoint->IorepDetach(*iReaderProxies[pos]);
			}
		delete iReaderProxies[pos];
		iReaderProxies.Remove(pos);
		
		if (iReaderProxies.Count()==0)
			{
			SendReadDetachNotifications();
			}
		}
	}
	
void CIoPersistentConsole::HandleForegroundReaderChanged()
	{
	if (iTransientReadEndPoint)
		{
		CIoEndPoint::HandleForegroundReaderChanged();
		}
	else
		{
		ForegroundReaderChanged();
		}
	}
	
void CIoPersistentConsole::ForegroundReaderChanged()
	{
	MIoReader* fgReader = AttachedReader();
	if (iTransientReadEndPoint && fgReader)
		{
		TInt fgPos = ReaderProxyIndex(fgReader);
		ASSERT(fgPos != KErrNotFound);
		TRAPD(err, iTransientReadEndPoint->IorepSetForegroundReaderL(*iReaderProxies[fgPos]));
		__ASSERT_ALWAYS(err == KErrNone, User::Invariant());
		// this would only fail if this endpoints list of readers differs from the transient
		// endpoints list; the two should always be kept in sync.
		}
	}
	
TInt CIoPersistentConsole::ReaderProxyIndex(MIoReader* aReader) const
	{
	for (TInt i=0; i<iReaderProxies.Count(); ++i)
		{
		if (&iReaderProxies[i]->ClientReader() == aReader)
			{
			return i;
			}
		}
	return KErrNotFound;
	}

void CIoPersistentConsole::IorepReadL(MIoReader& aReader)
	{
	TInt pos = ReaderProxyIndex(&aReader);
	ASSERT(pos!=KErrNotFound);
	iReaderProxies[pos]->ReadL(iTransientReadEndPoint);
	}

void CIoPersistentConsole::IorepReadKeyL(MIoReader& aReader)
	{
	TInt pos = ReaderProxyIndex(&aReader);
	ASSERT(pos!=KErrNotFound);
	iReaderProxies[pos]->ReadKeyL(iTransientReadEndPoint);
	}

void CIoPersistentConsole::IorepSetConsoleModeL(RIoReadWriteHandle::TMode aMode, MIoReader& aReader)
	{
	iPersistentConsoleMode = aMode;
	GetReaderProxy(&aReader).SetConsoleModeL(iTransientReadEndPoint, aMode);
	}

//______________________________________________________________________________
//		MIoWriteEndPoint implementation - to handles writes from persistent side
TInt CIoPersistentConsole::HandleWriterAttached(MIoWriter& aWriter)
	{
	// call from CIoEndPoint
	TIoWriterProxy* proxy = new TIoWriterProxy(aWriter, *this);
	TInt err = proxy ? KErrNone : KErrNoMemory;
	if (err==KErrNone)
		{
		err = iWriterProxies.Append(proxy);
		}
	
	if ((err == KErrNone) && iTransientWriteEndPoint)
		{
		TRAP(err, iTransientWriteEndPoint->IowepAttachL(*proxy));
		}

	if (err != KErrNone)
		{
		TInt pos = WriterProxyIndex(proxy);
		if (pos!=KErrNotFound)
			{
			iWriterProxies.Remove(pos);
			}
		delete proxy;
		}		
	return err;
	}
	
void CIoPersistentConsole::HandleWriterDetached(MIoWriter& aWriter)
	{
	TInt pos = WriterProxyIndex(&aWriter);
	if (pos!=KErrNotFound)
		{
		if (iTransientWriteEndPoint)
			{
			iWriterProxies[pos]->TransientWriterDetach(*iTransientWriteEndPoint);
			}
		delete iWriterProxies[pos];
		iWriterProxies.Remove(pos);
		
		if (iWriterProxies.Count()==0)
			{
			SendWriteDetachNotifications();
			}
		}
		
	}
	
TInt CIoPersistentConsole::WriterProxyIndex(MIoWriter* aWriter) const
	{
	for (TInt i=0; i<iWriterProxies.Count(); ++i)
		{
		if (&iWriterProxies[i]->ClientWriter() == aWriter)
			{
			return i;
			}
		}
	return KErrNotFound;
	}
	
CIoPersistentConsole::TIoWriterProxy& CIoPersistentConsole::GetWriterProxy(MIoWriter* aWriter) const
	{
	TInt pos = WriterProxyIndex(aWriter);
	ASSERT(pos!=KErrNotFound);
	return *iWriterProxies[pos];
	}
	
CIoPersistentConsole::TIoReaderProxy& CIoPersistentConsole::GetReaderProxy(MIoReader* aWriter) const
	{
	TInt pos = ReaderProxyIndex(aWriter);
	ASSERT(pos!=KErrNotFound);
	return *iReaderProxies[pos];
	}

void CIoPersistentConsole::IowepWriteL(MIoWriter& aWriter)
	{
	TInt pos = WriterProxyIndex(&aWriter);
	ASSERT(pos!=KErrNotFound);
	iWriterProxies[pos]->WriteL(iTransientWriteEndPoint);

	// move the proxy to the end of the array so that we service the writes 
	// in the correct order when we get a write end point, or when the end
	// point goes away and comes back
	TIoWriterProxy* proxy(iWriterProxies[pos]);
	iWriterProxies.Remove(pos);
	iWriterProxies.Append(proxy);
	}
	
void CIoPersistentConsole::IowepWriteCancel(MIoWriter& aWriter)
	{
	TInt pos = WriterProxyIndex(&aWriter);
	ASSERT(pos!=KErrNotFound);
	iWriterProxies[pos]->WriteCancel(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepCursorPosL(MIoWriter& aWriter) const
	{
	GetWriterProxy(&aWriter).GetCursorPosL(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepSetCursorPosAbsL(const TPoint& aPoint, MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).SetCursorPosAbsL(aPoint, iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepSetCursorPosRelL(const TPoint& aPoint, MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).SetCursorPosRelL(aPoint, iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepSetCursorHeightL(TInt aPercentage, MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).SetCursorHeightL(aPercentage, iTransientWriteEndPoint);
	// TODO cache cursor height
	}

void CIoPersistentConsole::IowepSetTitleL(MIoWriter& aWriter)
	{
	delete iTitle;
	iTitle = NULL;
	TRAP_IGNORE(iTitle = aWriter.IowTitleLC(); CleanupStack::Pop(iTitle)); // not much we can do if this fails
	GetWriterProxy(&aWriter).SetTitleL(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepClearScreenL(MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).ClearScreenL(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepClearToEndOfLineL(MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).ClearToEndOfLineL(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepScreenSizeL(MIoWriter& aWriter) const
	{
	GetWriterProxy(&aWriter).GetScreenSizeL(iTransientWriteEndPoint);
	}

void CIoPersistentConsole::IowepSetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor, MIoWriter& aWriter)
	{
	GetWriterProxy(&aWriter).SetAttributesL(aAttributes, aForegroundColor, aBackgroundColor, iTransientWriteEndPoint);
	}
	
CIoPersistentConsole::CIoPersistentConsole(CIoServer& aServer)
	: CIoConsole(aServer.Config()), iServer(aServer), iTitleSetter(iTitle)
	{
	}
	
CIoPersistentConsole::~CIoPersistentConsole()
	{
	iServer.PersistentConsoleRemove(iName, *this);
	SendReadDetachNotifications();
	iReadDetachNotifications.Close();
	SendWriteDetachNotifications();
	iWriteDetachNotifications.Close();
	
	delete iTitle;
	iWriterProxies.ResetAndDestroy();
	iReaderProxies.ResetAndDestroy();
	
	iCreator.Close();
	}

_LIT(KPersistentConsoleImplementation, "<persistent console>");

void CIoPersistentConsole::ConstructL(const TDesC& aName, const TDesC& aTitle, const RMsg& aMessage)
	{
	LOG(CIoLog::Printf(_L("Persistent console %S @ 0x%08x created"), &aName, this));
	iName = aName.Left(KMaxName);
	iServer.PersistentConsoleAddL(iName, *this);
	iImplementation = KPersistentConsoleImplementation().AllocL();
	iTitle = aTitle.AllocL();
	aMessage.ClientL(iCreator);
	}

//______________________________________________________________________________
//							TIoWriterProxy
// MIoWriter proxy to service write requests from the transient side
CIoPersistentConsole::TIoWriterProxy::TIoWriterProxy(MIoWriter& aWriter, CIoPersistentConsole& aOwner)
	: iWriter(aWriter)
	, iOwner(aOwner)
	, iFlags(0)
	{
	}
	
TBool CIoPersistentConsole::TIoWriterProxy::GetFlag(TFlags aFlag)
	{
	return iFlags & aFlag;
	}
	
void CIoPersistentConsole::TIoWriterProxy::SetFlag(TFlags aFlag)
	{
	iFlags |= aFlag;
	}
	
void CIoPersistentConsole::TIoWriterProxy::ClearFlag(TFlags aFlag)
	{
	iFlags &= (~aFlag);
	}
	
#define TRAP_OR(x, y) {TRAPD(err, x); if (err!=KErrNone) {y;} }
	
	
void CIoPersistentConsole::TIoWriterProxy::TransientWriterAttached(MIoWriteEndPoint& aEndPoint)
	{
	if (GetFlag(EWritePending))
		{
		TRAP_OR(aEndPoint.IowepWriteL(*this), IowComplete(err));
		}
	if (GetFlag(EGetCursorPosPending))
		{
		TRAP_OR(aEndPoint.IowepCursorPosL(*this), IowCursorPos(err, TPoint(0,0)));
		}
	if (GetFlag(ESetCursorPosAbsPending))
		{
		TRAP_OR(aEndPoint.IowepSetCursorPosAbsL(iSetCursPosAbsPoint, *this), IowSetCursorPosAbsComplete(err));
		}
	if (GetFlag(ESetCursorPosRelPending))
		{
		TRAP_OR(aEndPoint.IowepSetCursorPosRelL(iSetCursPosRelPoint, *this), IowSetCursorPosRelComplete(err));
		}
	if (GetFlag(ESetCursorHeightPending))
		{
		TRAP_OR(aEndPoint.IowepSetCursorHeightL(iSetCursorHeight, *this), IowSetCursorHeightComplete(err));
		}
	if (GetFlag(ESetTitlePending))
		{
		TRAP_OR(aEndPoint.IowepSetTitleL(*this), IowSetTitleComplete(err));
		}
	if (GetFlag(EClearScreenPending))
		{
		TRAP_OR(aEndPoint.IowepClearScreenL(*this), IowClearScreenComplete(err));
		}
	if (GetFlag(EClearToEndOfLinePending))
		{
		TRAP_OR(aEndPoint.IowepClearToEndOfLineL(*this), IowClearToEndOfLineComplete(err));
		}
	if (GetFlag(EGetScreenSizePending))
		{
		TRAP_OR(aEndPoint.IowepScreenSizeL(*this), IowScreenSize(err, TSize(0,0)));
		}
	if (GetFlag(ESetAttributesPending))
		{
		TRAP_OR(aEndPoint.IowepSetAttributesL(iAttributes, iForegroundColor, iBackgroundColor, *this), IowSetAttributesComplete(err));
		}
	}
	
void CIoPersistentConsole::TIoWriterProxy::TransientWriterDetach(MIoWriteEndPoint& aEndPoint)
	{
	if (GetFlag(EDetaching)) return;
	if (GetFlag(EWritePending))
		{
		aEndPoint.IowepWriteCancel(*this);
		// leave the write pending so it is serviced when we get a new transient end point
		}
	aEndPoint.IowepDetach(*this);
	}
	
void CIoPersistentConsole::TIoWriterProxy::WriteL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(EWritePending);
	if (aEndPoint)
		{
		TRAPD(err, aEndPoint->IowepWriteL(*this));
		if (err)
			{
			ClearFlag(EWritePending);
			User::Leave(err);
			}
		}
	}
	
void CIoPersistentConsole::TIoWriterProxy::WriteCancel(MIoWriteEndPoint* aEndPoint)
	{
	if (aEndPoint)
		{
		aEndPoint->IowepWriteCancel(*this);
		}
	ClearFlag(EWritePending);
	}

	
MIoWriter& CIoPersistentConsole::TIoWriterProxy::ClientWriter() const
	{
	return iWriter;
	}
	
void CIoPersistentConsole::TIoWriterProxy::GetCursorPosL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(EGetCursorPosPending);
	if (aEndPoint)
		{
		aEndPoint->IowepCursorPosL(*this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::SetCursorPosAbsL(const TPoint& aPos, MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(ESetCursorPosAbsPending);
	iSetCursPosAbsPoint = aPos;
	if (aEndPoint)
		{
		aEndPoint->IowepSetCursorPosAbsL(iSetCursPosAbsPoint, *this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::SetCursorPosRelL(const TPoint& aPos, MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(ESetCursorPosRelPending);
	iSetCursPosRelPoint = aPos;
	if (aEndPoint)
		{
		aEndPoint->IowepSetCursorPosRelL(iSetCursPosRelPoint, *this);
		}
	}
	
void CIoPersistentConsole::TIoWriterProxy::SetCursorHeightL(TInt aPercentage, MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(ESetCursorHeightPending);
	iSetCursorHeight = aPercentage;
	if (aEndPoint)
		{
		aEndPoint->IowepSetCursorHeightL(iSetCursorHeight, *this);
		}
	}
	
void CIoPersistentConsole::TIoWriterProxy::SetTitleL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(ESetTitlePending);
	if (aEndPoint)
		{
		aEndPoint->IowepSetTitleL(*this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::ClearScreenL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(EClearScreenPending);
	if (aEndPoint)
		{
		aEndPoint->IowepClearScreenL(*this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::ClearToEndOfLineL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(EClearToEndOfLinePending);
	if (aEndPoint)
		{
		aEndPoint->IowepClearToEndOfLineL(*this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::GetScreenSizeL(MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(EGetScreenSizePending);
	if (aEndPoint)
		{
		aEndPoint->IowepScreenSizeL(*this);
		}
	}

void CIoPersistentConsole::TIoWriterProxy::SetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor, MIoWriteEndPoint* aEndPoint)
	{
	SetFlag(ESetAttributesPending);
	iAttributes = aAttributes;
	iForegroundColor = aForegroundColor;
	iBackgroundColor = aBackgroundColor;
	if (aEndPoint)
		{
		aEndPoint->IowepSetAttributesL(iAttributes, iForegroundColor, iBackgroundColor, *this);
		}
	}

TInt CIoPersistentConsole::TIoWriterProxy::IowWriteLength() const
	{
	return iWriter.IowWriteLength();
	}

TInt CIoPersistentConsole::TIoWriterProxy::IowWrite(TDes& aBuf)
	{
	return iWriter.IowWrite(aBuf);
	}

void CIoPersistentConsole::TIoWriterProxy::IowComplete(TInt aError)
	{
	if (aError == KErrNone)
		{
		iWriter.IowComplete(KErrNone);
		ClearFlag(EWritePending);
		}
	else
		{
		SetFlag(EDetaching);
		iOwner.DetachTransientWriter();
		ClearFlag(EDetaching);
		}
	}

TName CIoPersistentConsole::TIoWriterProxy::IowName()
	{
	TName name(iWriter.IowName());
	if (name.Length() + KProxySuffix().Length() > name.MaxLength())
		{
		name.SetLength(name.MaxLength() - KProxySuffix().Length());
		}
	name.Append(KProxySuffix);
	return name;
	}

RIoReadWriteHandle::TMode CIoPersistentConsole::TIoWriterProxy::IorwMode() const
	{
	return iWriter.IorwMode();
	}
	
void CIoPersistentConsole::TIoWriterProxy::IowCursorPos(TInt aError, TPoint aPos)
	{
	ClearFlag(EGetCursorPosPending);
	iWriter.IowCursorPos(aError, aPos);
	}

void CIoPersistentConsole::TIoWriterProxy::IowSetCursorPosAbsComplete(TInt aError)
	{
	ClearFlag(ESetCursorPosAbsPending);
	iWriter.IowSetCursorPosAbsComplete(aError);
	}

void CIoPersistentConsole::TIoWriterProxy::IowSetCursorPosRelComplete(TInt aError)
	{
	ClearFlag(ESetCursorPosRelPending);
	iWriter.IowSetCursorPosRelComplete(aError);
	}
	
void CIoPersistentConsole::TIoWriterProxy::IowSetCursorHeightComplete(TInt aError)
	{
	ClearFlag(ESetCursorHeightPending);
	iWriter.IowSetCursorHeightComplete(aError);
	}
	
void CIoPersistentConsole::TIoWriterProxy::IowSetTitleComplete(TInt aError)
	{
	ClearFlag(ESetTitlePending);
	iWriter.IowSetTitleComplete(aError);
	}

void CIoPersistentConsole::TIoWriterProxy::IowClearScreenComplete(TInt aError)
	{
	ClearFlag(EClearScreenPending);
	iWriter.IowClearScreenComplete(aError);
	}

void CIoPersistentConsole::TIoWriterProxy::IowClearToEndOfLineComplete(TInt aError)
	{
	ClearFlag(EClearToEndOfLinePending);
	iWriter.IowClearToEndOfLineComplete(aError);
	}

void CIoPersistentConsole::TIoWriterProxy::IowScreenSize(TInt aError, TSize aSize)
	{
	ClearFlag(EGetScreenSizePending);
	iWriter.IowScreenSize(aError, aSize);
	}

void CIoPersistentConsole::TIoWriterProxy::IowSetAttributesComplete(TInt aError)
	{
	ClearFlag(ESetAttributesPending);
	iWriter.IowSetAttributesComplete(aError);
	}
	
HBufC* CIoPersistentConsole::TIoWriterProxy::IowTitleLC()
	{
	return iWriter.IowTitleLC();
	}

//______________________________________________________________________________
//							TIoReaderProxy
//	MIoReader proxy - to service read requests from transient side
CIoPersistentConsole::TIoReaderProxy::TIoReaderProxy(MIoReader& aReader, CIoPersistentConsole& aOwner)
	: iReader(aReader), iOwner(aOwner), iDetaching(EFalse), iSetConsoleModePending(EFalse)
	{
	}
	
void CIoPersistentConsole::TIoReaderProxy::TransientReaderAttached(MIoReadEndPoint& aReader)
	{
	if (iReader.IorReadPending())
		{
		TRAPD(err, aReader.IorepReadL(*this));
		if (err)
			{
			IorReadComplete(err);
			}
		}
	if (iReader.IorReadKeyPending())
		{
		TRAPD(err, aReader.IorepReadKeyL(*this));
		if (err)
			{
			IorReadKeyComplete(err, EKeyNull, 0);
			}
		}
	if (iSetConsoleModePending)
		{
		TRAP_OR(aReader.IorepSetConsoleModeL(iSetConsoleMode, *this), IorSetConsoleModeComplete(err));
		}
	}
	
void CIoPersistentConsole::TIoReaderProxy::ReadL(MIoReadEndPoint* aEndPoint)
	{
	if (aEndPoint)
		{
		aEndPoint->IorepReadL(*this);
		}
	}
	
void CIoPersistentConsole::TIoReaderProxy::ReadKeyL(MIoReadEndPoint* aEndPoint)
	{
	if (aEndPoint)
		{
		aEndPoint->IorepReadKeyL(*this);
		}
	}
	
void CIoPersistentConsole::TIoReaderProxy::SetConsoleModeL(MIoReadEndPoint* aEndPoint, RIoReadWriteHandle::TMode aMode)
	{
	iSetConsoleModePending = ETrue;
	iSetConsoleMode = aMode;
	if (aEndPoint)
		{
		CleanupNullPointerPushL((TAny**)&iSetConsoleModePending);
		aEndPoint->IorepSetConsoleModeL(iSetConsoleMode, *this);
		CleanupStack::Pop();
		}
	}
	
MIoReader& CIoPersistentConsole::TIoReaderProxy::ClientReader() const
	{
	return iReader;
	}

RIoReadWriteHandle::TMode CIoPersistentConsole::TIoReaderProxy::IorwMode() const
	{
	return iReader.IorwMode();
	}

TBool CIoPersistentConsole::TIoReaderProxy::IorReadPending() const
	{
	return iReader.IorReadPending();
	}

TBool CIoPersistentConsole::TIoReaderProxy::IorReadKeyPending() const
	{
	return iReader.IorReadKeyPending();
	}


TDes& CIoPersistentConsole::TIoReaderProxy::IorReadBuf()
	{
	return iReader.IorReadBuf();
	}

void CIoPersistentConsole::TIoReaderProxy::IorDataBuffered(TInt aLength)
	{
	iReader.IorDataBuffered(aLength);
	}

TBool CIoPersistentConsole::TIoReaderProxy::IorDataIsBuffered() const
	{
	return iReader.IorDataIsBuffered();
	}


TBool CIoPersistentConsole::TIoReaderProxy::IorIsKeyCaptured(TUint aKeyCode, TUint aModifiers)
	{
	return iReader.IorIsKeyCaptured(aKeyCode, aModifiers);
	}

void CIoPersistentConsole::TIoReaderProxy::IorReadComplete(TInt /*aError*/)
	{
	// indicates that the read end point will be providing no more data
	// so detatch it
	iDetaching = ETrue;
	iOwner.DetachTransientReader();
	iDetaching = EFalse;
	}

void CIoPersistentConsole::TIoReaderProxy::IorReadKeyComplete(TInt aError, TUint aKeyCode, TUint aModifiers)
	{
	if (aError == KErrEof)
		{
		// indicates that the read end point will be providing no more data
		// so detatch it
		iOwner.DetachTransientReader();
		}
	else
		{
		iReader.IorReadKeyComplete(aError, aKeyCode, aModifiers);
		}
	}

TName CIoPersistentConsole::TIoReaderProxy::IorName()
	{
	TName name(iReader.IorName());
	if (name.Length() + KProxySuffix().Length() > name.MaxLength())
		{
		name.SetLength(name.MaxLength() - KProxySuffix().Length());
		}
	name.Append(KProxySuffix);
	return name;
	}

void CIoPersistentConsole::TIoReaderProxy::IorReaderChange(TUint aChange)
	{
	iReader.IorReaderChange(aChange);
	}

void CIoPersistentConsole::TIoReaderProxy::IorSetConsoleModeComplete(TInt aError)
	{
	iSetConsoleModePending = EFalse;
	iReader.IorSetConsoleModeComplete(aError);
	}

//______________________________________________________________________________
//						TConsoleTitleSetter
TConsoleTitleSetter::TConsoleTitleSetter(HBufC*& aTitle)
	: iTitle(aTitle)
	{
	}

TInt TConsoleTitleSetter::IowWriteLength() const
	{
	ASSERT(0);
	return 0;
	}

TInt TConsoleTitleSetter::IowWrite(TDes&)
	{
	ASSERT(0);
	return 0;
	}

void TConsoleTitleSetter::IowComplete(TInt)
	{
	ASSERT(0);
	}

TName TConsoleTitleSetter::IowName()
	{
	ASSERT(0);
	return TName();
	}

RIoReadWriteHandle::TMode TConsoleTitleSetter::IorwMode() const
	{
	ASSERT(0);
	return RIoReadWriteHandle::EText;
	}

void TConsoleTitleSetter::IowCursorPos(TInt, TPoint)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowSetCursorPosAbsComplete(TInt)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowSetCursorPosRelComplete(TInt)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowSetCursorHeightComplete(TInt)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowSetTitleComplete(TInt)
	{
	}

void TConsoleTitleSetter::IowClearScreenComplete(TInt)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowClearToEndOfLineComplete(TInt)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowScreenSize(TInt, TSize)
	{
	ASSERT(0);
	}

void TConsoleTitleSetter::IowSetAttributesComplete(TInt)
	{
	ASSERT(0);
	}

HBufC* TConsoleTitleSetter::IowTitleLC()
	{
	return iTitle->AllocLC();
	}