--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/iosrv/server/console.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,1394 @@
+// console.cpp
+//
+// Copyright (c) 2006 - 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 <e32cons.h>
+#include <e32uid.h>
+#include "server.h"
+#include "console.h"
+#include "log.h"
+
+
+#ifdef IOSRV_LOGGING
+#define CONSOLE_NAME TName consoleName(Name())
+#define READER_NAME(x) TName readerName((x).IorName())
+#define WRITER_NAME(x) TName writerName((x).IowName())
+#else
+#define CONSOLE_NAME
+#define READER_NAME(x)
+#define WRITER_NAME(x)
+#endif
+
+const TInt KConsoleThreadMinHeapSize = 0x1000;
+const TInt KConsoleThreadMaxHeapSize = 0x1000000;
+
+CIoConsole* CIoConsole::NewLC(const TDesC& aImplementation, const TDesC& aTitle, const TSize& aSize, const TIoConfig& aConfig, CIoConsole* aUnderlying, TUint aOptions)
+ {
+ CIoConsole* self = new(ELeave) CIoConsole(aConfig);
+ CleanupClosePushL(*self);
+ self->ConstructL(aImplementation, aTitle, aSize, aUnderlying, aOptions);
+ return self;
+ }
+
+CIoConsole::~CIoConsole()
+ {
+ // if the sub-thread is servicing a request of ours now, we have to kill it. Otherwise, we might hang
+ // when we try and cancel the request AO, if (for example) it's servicing a long-standing Create request.
+ if (iRequestAo && (iRequestAo->IsActive()) && (iServerThread.Handle()!=KNullHandle))
+ {
+ iServerThread.Kill(KErrCancel);
+ iThreadServer.Close(); // this won't be closed by the sub-thread, as we just killed it.
+ }
+ delete iThreadWatcher;
+ delete iRequestAo;
+ iRequestQueue.Close();
+ delete iImplementation;
+ delete iReader;
+ iConsole.Close();
+ delete iCreationTitle ;
+ iServerThread.Close();
+ }
+
+const TDesC& CIoConsole::Implementation() const
+ {
+ return *iImplementation;
+ }
+
+TBool CIoConsole::IsType(RIoHandle::TType aType) const
+ {
+ return ((aType == RIoHandle::EEndPoint) || (aType == RIoHandle::EConsole));
+ }
+
+void CIoConsole::HandleReaderDetached(MIoReader& aReader)
+ {
+ HandleReadWriterDetached(aReader);
+ }
+
+void CIoConsole::HandleWriterDetached(MIoWriter& aWriter)
+ {
+ HandleReadWriterDetached(aWriter);
+ }
+
+template <class T> void CIoConsole::HandleReadWriterDetached(T& aReadWriter)
+ {
+ // Remove pending requests originated from this reader / writer.
+ for (TInt i = (iRequestQueue.Count() - 1); i >= 0; --i)
+ {
+ TConsoleRequest* request = iRequestQueue[i];
+ if (request->OriginatedFrom(aReadWriter))
+ {
+ delete request;
+ iRequestQueue.Remove(i);
+ }
+ }
+
+ // If this reader / writer originated the request that's currently being process, abort it.
+ if (iRequestAo->CurrentRequest() && iRequestAo->CurrentRequest()->OriginatedFrom(aReadWriter))
+ {
+ iRequestAo->Abort();
+ }
+ }
+
+void CIoConsole::IorepReadL(MIoReader&)
+ {
+ if (!iReader->IsActive())
+ {
+ iReader->QueueRead();
+ }
+ }
+
+void CIoConsole::IorepReadKeyL(MIoReader& aReader)
+ {
+ IorepReadL(aReader);
+ }
+
+void CIoConsole::IorepSetConsoleModeL(RIoReadWriteHandle::TMode aMode, MIoReader& aReader)
+ {
+ NewRequest(new(ELeave)TConsoleSetModeRequest(aReader, *this, aMode));
+ }
+
+void CIoConsole::IowepWriteL(MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleWriteRequest(aWriter));
+ }
+
+void CIoConsole::IowepWriteCancel(MIoWriter&)
+ {
+ }
+
+void CIoConsole::IowepCursorPosL(MIoWriter& aWriter) const
+ {
+ NewRequest(new(ELeave)TConsoleCursorPosRequest(aWriter));
+ }
+
+void CIoConsole::IowepSetCursorPosAbsL(const TPoint& aPoint, MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleSetCursorPosAbsRequest(aWriter, aPoint));
+ }
+
+void CIoConsole::IowepSetCursorPosRelL(const TPoint& aPoint, MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleSetCursorPosRelRequest(aWriter, aPoint));
+ }
+
+void CIoConsole::IowepSetCursorHeightL(TInt aPercentage, MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleSetCursorHeightRequest(aWriter, aPercentage));
+ }
+
+void CIoConsole::IowepSetTitleL(MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleSetTitleRequest(aWriter));
+ }
+
+void CIoConsole::IowepClearScreenL(MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleClearScreenRequest(aWriter));
+ }
+
+void CIoConsole::IowepClearToEndOfLineL(MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleClearToEndOfLineRequest(aWriter));
+ }
+
+void CIoConsole::IowepSetAttributesL(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor, MIoWriter& aWriter)
+ {
+ NewRequest(new(ELeave)TConsoleSetAttributesRequest(aWriter, aAttributes, aForegroundColor, aBackgroundColor));
+ }
+
+void CIoConsole::IowepScreenSizeL(MIoWriter& aWriter) const
+ {
+ NewRequest(new(ELeave)TConsoleScreenSizeRequest(aWriter, iConfig));
+ }
+
+CIoConsole::CIoConsole(const TIoConfig& aConfig)
+ : iConfig(aConfig), iDetectedSize(-1, -1)
+ {
+ }
+
+void CIoConsole::ConstructL(const TDesC& aImplementation, const TDesC& aTitle, const TSize& aSize, CIoConsole* aUnderlying, TUint aOptions)
+ {
+ LOG(CIoLog::Printf(_L("Console 0x%08x created"), this));
+ iCreationTitle = aTitle.AllocL();
+ iCreationSize = aSize;
+
+ iRequestAo = new(ELeave)CConsoleRequest(*this);
+
+ if (aImplementation.Length())
+ {
+ iImplementation = aImplementation.AllocL();
+ }
+ else
+ {
+ iImplementation = iConfig.ConsoleImplementation().AllocL();
+ }
+
+ User::LeaveIfError(iConsole.Connect(CIoConsoleProxyServerNewL, iImplementation, *iImplementation, KDefaultStackSize, KConsoleThreadMinHeapSize, KConsoleThreadMaxHeapSize, iThreadServer, iServerThread));
+ iThreadWatcher = new(ELeave)CServerDeathWatcher(iThreadServer, iServerThread);
+ if (aOptions & RIoConsole::ELazyCreate)
+ {
+ User::LeaveIfError(iConsole.SetLazyConstruct());
+ }
+ if (iConfig.ConsoleSizeDetect())
+ {
+ User::LeaveIfError(iConsole.SetConsoleSizeDetect());
+ }
+ if (aUnderlying)
+ {
+ User::LeaveIfError(aUnderlying->Open());
+ CleanupClosePushL(*aUnderlying);
+ NewRequest(new(ELeave)TConsoleSetUnderlyingRequest(*aUnderlying));
+ CleanupStack::Pop();
+ }
+ NewRequest(new(ELeave)TConsoleCreateRequest(*this));
+
+ iReader = CConsoleReader::NewL(*this);
+ }
+
+void CIoConsole::CreateComplete(TInt aError)
+ {
+ iCreateStatus = aError;
+ }
+
+void CIoConsole::NewRequest(TConsoleRequest* aRequest) const
+ {
+ ASSERT(aRequest);
+ TInt err = iRequestQueue.Append(aRequest);
+ if (err!=KErrNone)
+ {
+ aRequest->CompleteD(err);
+ return;
+ }
+
+ CheckQueue();
+ }
+
+void CIoConsole::CheckQueue() const
+ {
+ if (iCreateStatus != KErrNone)
+ {
+ while (iRequestQueue.Count())
+ {
+ TConsoleRequest* req = iRequestQueue[0];
+ iRequestQueue.Remove(0);
+ req->CompleteD(iCreateStatus);
+ }
+ return;
+ }
+ if ((!iRequestAo->IsActive()) && (iRequestQueue.Count()))
+ {
+ iRequestAo->Service(iRequestQueue[0]);
+ iRequestQueue.Remove(0);
+ }
+ }
+
+void CIoConsole::ConsoleDied()
+ {
+ iCreateStatus = KErrGeneral;
+
+ iReader = CConsoleReader::NewL(*this);
+ }
+
+void CIoConsole::ReadComplete(TInt aError)
+ {
+ MIoReader* foregroundReader = AttachedReader(0);
+ if (foregroundReader)
+ {
+ foregroundReader->IorReadKeyComplete(aError, 0, 0);
+ }
+ }
+
+void CIoConsole::ReadComplete(TUint aKeyCode, TUint aModifiers)
+ {
+ TInt index = 0;
+ MIoReader* foregroundReader = AttachedReader(index++);
+ MIoReader* reader = foregroundReader;
+ TBool keyHandled(EFalse);
+ while (reader)
+ {
+ if (reader->IorIsKeyCaptured(aKeyCode, aModifiers))
+ {
+ if (reader->IorReadPending())
+ {
+ TPtrC keyCodePtr((TUint16*)&aKeyCode, 1);
+ reader->IorReadBuf().Append(keyCodePtr);
+ reader->IorDataBuffered(1);
+ }
+ else
+ {
+ reader->IorReadKeyComplete(KErrNone, aKeyCode, aModifiers);
+ }
+ keyHandled = ETrue;
+ break;
+ }
+ reader = AttachedReader(index++);;
+ }
+
+ // Key not captured, so send to foreground (i.e. the first) reader.
+ if (!keyHandled && foregroundReader)
+ {
+ foregroundReader->IorReadKeyComplete(KErrNone, aKeyCode, aModifiers);
+ }
+
+ QueueReaderIfRequired();
+ }
+
+void CIoConsole::QueueReaderIfRequired()
+ {
+ TBool pendingReader(EFalse);
+ TInt index = 0;
+ MIoReader* reader = AttachedReader(index++);
+ while (reader)
+ {
+ if (reader->IorReadPending() || reader->IorReadKeyPending())
+ {
+ pendingReader = ETrue;
+ break;
+ }
+ reader = AttachedReader(index++);
+ }
+
+ if (pendingReader && !iReader->IsActive())
+ {
+ iReader->QueueRead();
+ }
+ else if (!pendingReader && iReader->IsActive())
+ {
+ iReader->Cancel();
+ }
+ }
+
+CIoConsole::CConsoleReader* CIoConsole::CConsoleReader::NewL(CIoConsole& aConsole)
+ {
+ return new(ELeave) CConsoleReader(aConsole);
+ }
+
+CIoConsole::CConsoleReader::~CConsoleReader()
+ {
+ Cancel();
+ }
+
+void CIoConsole::CConsoleReader::QueueRead()
+ {
+ iConsole.iConsole.Read(iKeyCodePckg, iKeyModifiersPckg, iStatus);
+ SetActive();
+ }
+
+CIoConsole::CConsoleReader::CConsoleReader(CIoConsole& aConsole)
+ : CActive(CActive::EPriorityStandard), iConsole(aConsole)
+ , iKeyCodePckg(iKeyCode), iKeyModifiersPckg(iKeyModifiers)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CIoConsole::CConsoleReader::RunL()
+ {
+ TInt err = iStatus.Int();
+ if (err==KErrServerTerminated)
+ {
+ iConsole.ConsoleDied();
+ err = KErrGeneral;
+ }
+ if (err)
+ {
+ iConsole.ReadComplete(err);
+ }
+ else
+ {
+ iConsole.ReadComplete(iKeyCode, iKeyModifiers);
+ }
+ }
+
+void CIoConsole::CConsoleReader::DoCancel()
+ {
+ iConsole.iConsole.ReadCancel();
+ }
+
+//______________________________________________________________________________
+// TConsoleRequest
+void CIoConsole::TConsoleRequest::PrepareL()
+ {
+ }
+
+TBool CIoConsole::TConsoleRequest::OriginatedFrom(MIoReader&) const
+ {
+ return EFalse;
+ }
+
+TBool CIoConsole::TConsoleRequest::OriginatedFrom(MIoWriter&) const
+ {
+ return EFalse;
+ }
+
+//______________________________________________________________________________
+// TConsoleWriterRequest
+CIoConsole::TConsoleWriterRequest::TConsoleWriterRequest(MIoWriter& aWriter)
+ : iWriter(aWriter)
+ {
+ }
+
+TBool CIoConsole::TConsoleWriterRequest::OriginatedFrom(MIoWriter& aWriter) const
+ {
+ return (&iWriter == &aWriter);
+ }
+
+//______________________________________________________________________________
+// TConsoleReaderRequest
+CIoConsole::TConsoleReaderRequest::TConsoleReaderRequest(MIoReader& aReader)
+ : iReader(aReader)
+ {
+ }
+
+TBool CIoConsole::TConsoleReaderRequest::OriginatedFrom(MIoReader& aReader) const
+ {
+ return (&iReader == &aReader);
+ }
+
+//______________________________________________________________________________
+// TConsoleCreateRequest
+CIoConsole::TConsoleCreateRequest::TConsoleCreateRequest(CIoConsole& aOwner)
+ : iOwner(aOwner)
+ {
+ }
+
+void CIoConsole::TConsoleCreateRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.Create(*iOwner.iCreationTitle, iOwner.iCreationSize, aStatus);
+ }
+
+void CIoConsole::TConsoleCreateRequest::CompleteD(TInt aError)
+ {
+ iOwner.CreateComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleWriteRequest
+CIoConsole::TConsoleWriteRequest::TConsoleWriteRequest(MIoWriter& aWriter)
+ : TConsoleWriterRequest(aWriter), iBuf(NULL)
+ {
+ }
+
+void CIoConsole::TConsoleWriteRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ if (iWriter.IowIsStdErr())
+ {
+ aProxy.WriteStdErr(*iBuf, aStatus);
+ }
+ else
+ {
+ aProxy.Write(*iBuf, aStatus);
+ }
+ }
+
+void CIoConsole::TConsoleWriteRequest::PrepareL()
+ {
+ const TInt length = iWriter.IowWriteLength();
+ if (iBuf == NULL)
+ {
+ iBuf = HBufC::NewL(length);
+ }
+ else if (iBuf->Des().MaxLength() < length)
+ {
+ iBuf = iBuf->ReAllocL(length);
+ }
+
+ TPtr bufPtr(iBuf->Des());
+ bufPtr.Zero();
+ iWriter.IowWrite(bufPtr);
+
+ if (iWriter.IorwMode() == RIoReadWriteHandle::EText)
+ {
+ // Fix line endings (change LF to CRLF).
+ RArray<TInt> indicies(5);
+ CleanupClosePushL(indicies);
+ _LIT(KCarriageReturn, "\r");
+ for (TInt i = 0; i < length; ++i)
+ {
+ if ((*iBuf)[i] == '\n')
+ {
+ if ((i == 0) || ((*iBuf)[i - 1] != '\r'))
+ {
+ User::LeaveIfError(indicies.Append(i));
+ }
+ }
+ }
+ const TInt count = indicies.Count();
+ if (count > 0)
+ {
+ if (bufPtr.MaxLength() < (length + count))
+ {
+ iBuf = iBuf->ReAllocL(length + count);
+ bufPtr.Set(iBuf->Des());
+ }
+ for (TInt i = (count - 1); i >= 0; --i)
+ {
+ bufPtr.Insert(indicies[i], KCarriageReturn);
+ }
+ }
+ CleanupStack::PopAndDestroy(&indicies);
+ }
+
+ }
+
+void CIoConsole::TConsoleWriteRequest::CompleteD(TInt aError)
+ {
+ delete iBuf;
+ iWriter.IowComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleCursorPosRequest
+CIoConsole::TConsoleCursorPosRequest::TConsoleCursorPosRequest(MIoWriter& aWriter)
+ : TConsoleWriterRequest(aWriter), iPosPckg(iPos)
+ {
+ }
+
+void CIoConsole::TConsoleCursorPosRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.CursorPos(iPosPckg, aStatus);
+ }
+
+void CIoConsole::TConsoleCursorPosRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowCursorPos(aError, iPos);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetCursorPosAbsRequest
+CIoConsole::TConsoleSetCursorPosAbsRequest::TConsoleSetCursorPosAbsRequest(MIoWriter& aWriter, const TPoint& aPoint)
+ : TConsoleWriterRequest(aWriter), iPoint(aPoint)
+ {
+ }
+
+void CIoConsole::TConsoleSetCursorPosAbsRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetCursorPosAbs(iPoint, aStatus);
+ }
+
+void CIoConsole::TConsoleSetCursorPosAbsRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowSetCursorPosAbsComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetCursorPosRelRequest
+CIoConsole::TConsoleSetCursorPosRelRequest::TConsoleSetCursorPosRelRequest(MIoWriter& aWriter, const TPoint& aPoint)
+ : TConsoleWriterRequest(aWriter), iPoint(aPoint)
+ {
+ }
+
+void CIoConsole::TConsoleSetCursorPosRelRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetCursorPosRel(iPoint, aStatus);
+ }
+
+void CIoConsole::TConsoleSetCursorPosRelRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowSetCursorPosRelComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetCursorHeightRequest
+CIoConsole::TConsoleSetCursorHeightRequest::TConsoleSetCursorHeightRequest(MIoWriter& aWriter, TInt aHeight)
+ : TConsoleWriterRequest(aWriter), iHeight(aHeight)
+ {
+ }
+
+void CIoConsole::TConsoleSetCursorHeightRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetCursorHeight(iHeight, aStatus);
+ }
+
+void CIoConsole::TConsoleSetCursorHeightRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowSetCursorHeightComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetTitleRequest
+CIoConsole::TConsoleSetTitleRequest::TConsoleSetTitleRequest(MIoWriter& aWriter)
+ : TConsoleWriterRequest(aWriter)
+ {
+ }
+
+void CIoConsole::TConsoleSetTitleRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetTitle(*iTitle, aStatus);
+ }
+
+void CIoConsole::TConsoleSetTitleRequest::PrepareL()
+ {
+ iTitle = iWriter.IowTitleLC();
+ CleanupStack::Pop(iTitle);
+ }
+
+void CIoConsole::TConsoleSetTitleRequest::CompleteD(TInt aError)
+ {
+ delete iTitle;
+ iWriter.IowSetTitleComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleClearScreenRequest
+CIoConsole::TConsoleClearScreenRequest::TConsoleClearScreenRequest(MIoWriter& aWriter)
+ : TConsoleWriterRequest(aWriter)
+ {
+ }
+
+void CIoConsole::TConsoleClearScreenRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.ClearScreen(aStatus);
+ }
+
+void CIoConsole::TConsoleClearScreenRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowClearScreenComplete(aError);
+ delete this;
+ }
+
+
+
+
+//______________________________________________________________________________
+// TConsoleClearToEndOfLineRequest
+CIoConsole::TConsoleClearToEndOfLineRequest::TConsoleClearToEndOfLineRequest(MIoWriter& aWriter)
+ : TConsoleWriterRequest(aWriter)
+ {
+ }
+
+void CIoConsole::TConsoleClearToEndOfLineRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.ClearToEndOfLine(aStatus);
+ }
+
+void CIoConsole::TConsoleClearToEndOfLineRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowClearToEndOfLineComplete(aError);
+ delete this;
+ }
+
+
+
+
+//______________________________________________________________________________
+// TConsoleScreenSizeRequest
+CIoConsole::TConsoleScreenSizeRequest::TConsoleScreenSizeRequest(MIoWriter& aWriter, const TIoConfig& aConfig)
+ : TConsoleWriterRequest(aWriter), iConfig(aConfig), iSizeBuf(iSize)
+ {
+ }
+
+void CIoConsole::TConsoleScreenSizeRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.GetScreenSize(iSizeBuf, aStatus);
+ }
+
+void CIoConsole::TConsoleScreenSizeRequest::CompleteD(TInt aError)
+ {
+ if (aError==KErrNone)
+ {
+ iSize.iWidth += iConfig.ConsoleSizeAdjustment().iWidth;
+ iSize.iHeight += iConfig.ConsoleSizeAdjustment().iHeight;
+ }
+ iWriter.IowScreenSize(aError, iSize);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetAttributesRequest
+CIoConsole::TConsoleSetAttributesRequest::TConsoleSetAttributesRequest(MIoWriter& aWriter, TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor)
+ : TConsoleWriterRequest(aWriter), iAttributes(aAttributes), iForegroundColor(aForegroundColor), iBackgroundColor(aBackgroundColor)
+ {
+ }
+
+void CIoConsole::TConsoleSetAttributesRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetAttributes(iAttributes, iForegroundColor, iBackgroundColor, aStatus);
+ }
+
+void CIoConsole::TConsoleSetAttributesRequest::CompleteD(TInt aError)
+ {
+ iWriter.IowSetAttributesComplete(aError);
+ delete this;
+ }
+
+
+//______________________________________________________________________________
+// TConsoleSetUnderlyingRequest
+CIoConsole::TConsoleSetUnderlyingRequest::TConsoleSetUnderlyingRequest(CIoConsole& aUnderlyingConsole)
+ : iConsole(aUnderlyingConsole)
+ {
+ }
+
+void CIoConsole::TConsoleSetUnderlyingRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ aProxy.SetUnderlyingConsole(iSession, aStatus);
+ }
+
+void CIoConsole::TConsoleSetUnderlyingRequest::PrepareL()
+ {
+ if (iConsole.iThreadServer.Handle())
+ {
+ User::LeaveIfError(iSession.Connect(iConsole.iThreadServer));
+ }
+ else
+ {
+ User::Leave(KErrBadHandle);
+ }
+ }
+
+void CIoConsole::TConsoleSetUnderlyingRequest::CompleteD(TInt)
+ {
+ iSession.Close();
+ iConsole.Close();
+ delete this;
+ }
+
+//______________________________________________________________________________
+// TConsoleSetModeRequest
+CIoConsole::TConsoleSetModeRequest::TConsoleSetModeRequest(MIoReader& aReader,CIoConsole& aConsole, RIoReadWriteHandle::TMode aMode)
+ : TConsoleReaderRequest(aReader), iConsole(aConsole), iMode(aMode)
+ {
+ }
+
+void CIoConsole::TConsoleSetModeRequest::Request(RIoConsoleProxy aProxy, TRequestStatus& aStatus)
+ {
+ iConsole.iReader->Cancel();
+ aProxy.SetConsoleMode(iMode, aStatus);
+ }
+
+void CIoConsole::TConsoleSetModeRequest::CompleteD(TInt aError)
+ {
+ iConsole.QueueReaderIfRequired();
+ iReader.IorSetConsoleModeComplete(aError);
+ delete this;
+ }
+
+//______________________________________________________________________________
+// CConsoleRequest
+CIoConsole::CConsoleRequest::CConsoleRequest(CIoConsole& aConsole)
+ : CActive(EPriorityStandard), iConsole(aConsole)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void CIoConsole::CConsoleRequest::Service(TConsoleRequest* aRequest)
+ {
+ ASSERT(!IsActive());
+ ASSERT(!iCurrentRequest);
+ TRAPD(err, aRequest->PrepareL());
+ if (err!=KErrNone)
+ {
+ Complete(aRequest, err);
+ return;
+ }
+ aRequest->Request(iConsole.iConsole, iStatus);
+ SetActive();
+ iCurrentRequest = aRequest;
+ }
+
+void CIoConsole::CConsoleRequest::Complete(TConsoleRequest* aRequest, TInt aError)
+ {
+ if (aError == KErrServerTerminated)
+ {
+ // console has panicked.
+ iConsole.ConsoleDied();
+ // don't want to send KErrServerTerminated up to our (iosrv) clients, as it will
+ // make them think the iosrv has died.
+ aError = KErrGeneral;
+ }
+ if (aRequest)
+ {
+ aRequest->CompleteD(aError);
+ }
+ iConsole.CheckQueue();
+ }
+
+
+CIoConsole::CConsoleRequest::~CConsoleRequest()
+ {
+ Cancel();
+ }
+
+void CIoConsole::CConsoleRequest::RunL()
+ {
+ TConsoleRequest* req = iCurrentRequest;
+ iCurrentRequest = NULL;
+ Complete(req, iStatus.Int());
+ }
+
+void CIoConsole::CConsoleRequest::DoCancel()
+ {
+ // request are handled synchronously on the server side, no cancelling is possible.
+ }
+
+const CIoConsole::TConsoleRequest* CIoConsole::CConsoleRequest::CurrentRequest() const
+ {
+ return iCurrentRequest;
+ }
+
+void CIoConsole::CConsoleRequest::Abort()
+ {
+ // We can't cancel a pending request (because they are handled synchronously on the server side),
+ // so instead we delete and NULL the associated request object. This active object will then
+ // continue to wait for the server to complete the request (as normal), but will take no further
+ // action. This is used when the originating MIoReader or MIoWriter object has been detached from
+ // the console and no longer exists.
+ ASSERT(IsActive());
+ ASSERT(iCurrentRequest);
+ delete iCurrentRequest;
+ iCurrentRequest = NULL;
+ }
+
+
+//______________________________________________________________________________
+// CServerDeathWatcher
+CIoConsole::CServerDeathWatcher::CServerDeathWatcher(RServer2& aServer, RThread& aThread)
+ : CActive(CActive::EPriorityStandard), iServer(aServer), iThread(aThread)
+ {
+ CActiveScheduler::Add(this);
+ aThread.Logon(iStatus);
+ SetActive();
+ }
+
+CIoConsole::CServerDeathWatcher::~CServerDeathWatcher()
+ {
+ Cancel();
+ }
+
+void CIoConsole::CServerDeathWatcher::RunL()
+ {
+ }
+
+void CIoConsole::CServerDeathWatcher::DoCancel()
+ {
+ iThread.LogonCancel(iStatus);
+ }
+
+//______________________________________________________________________________
+// RIoConsoleProxy
+TInt RIoConsoleProxy::SetConsoleSizeDetect()
+ {
+ return SendReceive(ESetConsoleSizeDetect);
+ }
+
+TInt RIoConsoleProxy::SetLazyConstruct()
+ {
+ return SendReceive(ESetLazyConstruct);
+ }
+
+void RIoConsoleProxy::SetConsoleMode(RIoReadWriteHandle::TMode aMode, TRequestStatus& aStatus)
+ {
+ SendReceive(ESetConsoleMode, TIpcArgs(aMode), aStatus);
+ }
+
+void RIoConsoleProxy::SetUnderlyingConsole(const RIoConsoleProxy& aUnderlyingSession, TRequestStatus& aStatus)
+ {
+ SendReceive(ESetUnderlyingConsole, TIpcArgs(aUnderlyingSession), aStatus);
+ }
+
+TInt RIoConsoleProxy::OpenExisting()
+ {
+ return SendReceive(EOpenExistingConsole);
+ }
+
+void RIoConsoleProxy::WriteStdErr(const TDesC& aDescriptor, TRequestStatus& aStatus)
+ {
+ SendReceive(EWriteStdErr, TIpcArgs(&aDescriptor), aStatus);
+ }
+
+//______________________________________________________________________________
+// CIoConsoleProxyServer
+CConsoleProxyServer* CIoConsoleProxyServerNewL(TAny* aParams)
+ {
+ const TDesC* dllName = (const TDesC*)aParams;
+ RLibrary lib;
+
+ User::LeaveIfError(lib.Load(*dllName));
+ CleanupClosePushL(lib);
+ if ((lib.Type()[1] == KSharedLibraryUid) && (lib.Type()[2] == KConsoleDllUid))
+ {
+ TConsoleCreateFunction entry = (TConsoleCreateFunction)lib.Lookup(1);
+ if (!entry) User::Leave(KErrNotSupported);
+ CleanupStack::Pop(&lib);
+ return CIoConsoleProxyServer::NewL(entry, lib);
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ return NULL; // ASSERT(Happy(compiler))
+ }
+ }
+
+CIoConsoleProxyServer* CIoConsoleProxyServer::NewL(TConsoleCreateFunction aConsoleCreate, RLibrary& aConsoleLibrary)
+ {
+ CIoConsoleProxyServer* self = new CIoConsoleProxyServer(aConsoleCreate, aConsoleLibrary);
+ if (!self)
+ {
+ aConsoleLibrary.Close();
+ User::Leave(KErrNoMemory);
+ }
+ CleanupStack::PushL(self);
+ self->ConstructL(KNullDesC);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CIoConsoleProxyServer::CIoConsoleProxyServer(TConsoleCreateFunction aConsoleCreate, const RLibrary& aConsoleLibrary)
+ : CConsoleProxyServer(aConsoleCreate, CActive::EPriorityStandard)
+ , iConsoleLibrary(aConsoleLibrary)
+ {
+ }
+
+CSession2* CIoConsoleProxyServer::NewSessionL(const TVersion&,const RMessage2&) const
+ {
+ return new(ELeave)CIoConsoleProxySession(iConsoleCreate);
+ }
+
+CIoConsoleProxyServer::~CIoConsoleProxyServer()
+ {
+ iConsoleLibrary.Close();
+ }
+
+MProxiedConsole* CIoConsoleProxyServer::TheConsole() const
+ {
+ return iTheConsole;
+ }
+
+void CIoConsoleProxyServer::SetTheConsole(MProxiedConsole* aConsole)
+ {
+ ASSERT(!iTheConsole);
+ iTheConsole = aConsole;
+ }
+
+//______________________________________________________________________________
+TSize DetectConsoleSize(CConsoleBase* aConsole)
+ {
+ TSize detectedSize;
+ aConsole->SetCursorHeight(0);
+ aConsole->ScreenSize(); // This used to be assigned to a variable, which was never used, but I'm not sure if calling ScreenSize() has side-effects so I'm leaving the call in
+ aConsole->SetCursorPosAbs(TPoint(0, 0));
+ _LIT(KSpace, " ");
+ for (TInt x = 0; ; ++x)
+ {
+ aConsole->Write(KSpace);
+ if (aConsole->CursorPos().iX == 0)
+ {
+ detectedSize.iWidth = x + 1;
+ break;
+ }
+ }
+ aConsole->SetCursorPosAbs(TPoint(0, 0));
+ TInt prevYPos = 0;
+ _LIT(KNewLine, "\r\n");
+ for (TInt y = 0; ; ++y)
+ {
+ aConsole->Write(KNewLine);
+ if (aConsole->CursorPos().iY == prevYPos)
+ {
+ detectedSize.iHeight = y;
+ break;
+ }
+ else
+ {
+ prevYPos = y;
+ }
+ }
+ aConsole->ClearScreen();
+ aConsole->SetCursorHeight(20);
+ return detectedSize;
+ }
+
+//______________________________________________________________________________
+// CIoConsoleProxySession
+CIoConsoleProxySession::CIoConsoleProxySession(TConsoleCreateFunction aConsoleCreate)
+ : CConsoleProxySession(aConsoleCreate), iFlags(ESupportsStdErr)
+ {
+ // Assume ESupportsStdErr until proven otherwise
+ }
+
+CIoConsoleProxySession::~CIoConsoleProxySession()
+ {
+ delete iUnderlyingConsole;
+ }
+
+void CIoConsoleProxySession::ServiceL(const RMessage2& aMessage)
+ {
+ switch (aMessage.Function())
+ {
+ case RIoConsoleProxy::ESetConsoleSizeDetect:
+ if (iConsole) User::Leave(KErrNotReady); // too late!
+ SetFlag(EAutoDetectSize, ETrue);
+ aMessage.Complete(KErrNone);
+ return;
+ case RIoConsoleProxy::ESetLazyConstruct:
+ if (iConsole) User::Leave(KErrNotReady); // too late!
+ SetFlag(ELazy, ETrue);
+ aMessage.Complete(KErrNone);
+ return;
+ case RIoConsoleProxy::ESetConsoleMode:
+ SetModeL(aMessage);
+ return;
+ case RIoConsoleProxy::ESetUnderlyingConsole:
+ SetUnderlyingConsoleL(aMessage);
+ return;
+ case RIoConsoleProxy::EOpenExistingConsole:
+ OpenExistingL(aMessage);
+ return;
+ case RConsoleProxy::EGetScreenSize:
+ if (GetFlag(EAutoDetectSize) && !GetFlag(ELazy))
+ {
+ DetectSizeL(aMessage);
+ return;
+ }
+ break;
+ case RIoConsoleProxy::EWriteStdErr:
+ {
+ RBuf buf;
+ CleanupClosePushL(buf);
+ buf.CreateL(aMessage.GetDesLengthL(0));
+ aMessage.ReadL(0, buf);
+ if (iFlags & ESupportsStdErr)
+ {
+ TInt err = ConsoleStdErr::Write(iConsole->Console(), buf);
+ if (err != KErrNone)
+ {
+ // Clearly it doesn't support it, clear the flag so we fall back to normal write and don't bother trying again
+ iFlags &= ~ESupportsStdErr;
+ }
+ }
+
+ if (!(iFlags & ESupportsStdErr))
+ {
+ iConsole->Console()->Write(buf);
+ }
+ CleanupStack::PopAndDestroy(&buf);
+ aMessage.Complete(KErrNone);
+ return;
+ }
+ default:
+ break;
+ }
+
+ CConsoleProxySession::ServiceL(aMessage);
+ }
+
+MProxiedConsole* CIoConsoleProxySession::InstantiateConsoleL()
+ {
+ if (Server()->TheConsole()!=NULL)
+ {
+ // make sure that only 1 console is ever created in this server
+ User::Leave(KErrAlreadyExists);
+ }
+ MProxiedConsole* cons;
+ if (GetFlag(ELazy))
+ {
+ CLazyConsole* lazy = new(ELeave)CLazyConsole(iConsoleCreate, GetFlag(EAutoDetectSize));
+ CleanupStack::PushL(lazy);
+ cons = MProxiedConsole::DefaultL(lazy);
+ CleanupStack::Pop();
+ }
+ else
+ {
+ cons = CConsoleProxySession::InstantiateConsoleL();
+ }
+
+ Server()->SetTheConsole(cons);
+
+ if (iUnderlyingConsole)
+ {
+ TInt err = UnderlyingConsole::Set(cons->Console(), iUnderlyingConsole);
+ // if this succeeds, ownership of the underlying console has been taken
+ // if it didn't, we should delete it as it's not needed.
+ if (err!=KErrNone)
+ {
+ delete iUnderlyingConsole;
+ }
+ iUnderlyingConsole = NULL;
+ }
+
+ return cons;
+ }
+
+void CIoConsoleProxySession::ConsoleCreatedL(MProxiedConsole* aConsole)
+ {
+ if (GetFlag(EAutoDetectSize) && !(GetFlag(ELazy)))
+ {
+ iDetectedSize = DetectConsoleSize(aConsole->Console());
+ }
+ }
+
+void CIoConsoleProxySession::DetectSizeL(const RMessage2& aMessage)
+ {
+ if (!iConsole) User::Leave(KErrNotReady);
+
+ aMessage.WriteL(0, TPckg<TSize>(iDetectedSize));
+ aMessage.Complete(KErrNone);
+ }
+
+void CIoConsoleProxySession::SetModeL(const RMessage2& aMessage)
+ {
+ if (!iConsole) User::Leave(KErrNotReady);
+ RIoReadWriteHandle::TMode mode = (RIoReadWriteHandle::TMode)aMessage.Int0();
+ TInt err = ConsoleMode::Set(iConsole->Console(), (mode == RIoReadWriteHandle::EBinary) ? ConsoleMode::EBinary : ConsoleMode::EText);
+ aMessage.Complete(err);
+ }
+
+void CIoConsoleProxySession::SetUnderlyingConsoleL(const RMessage2& aMessage)
+ {
+ if (iUnderlyingConsole) User::Leave(KErrAlreadyExists);
+
+ RIoConsoleProxy underlyingSession;
+ RThread client;
+ aMessage.ClientL(client, EOwnerThread);
+ CleanupClosePushL(client);
+
+ underlyingSession.SetHandle(aMessage.Int0());
+ User::LeaveIfError(underlyingSession.Duplicate(client, EOwnerThread));
+
+ CleanupClosePushL(underlyingSession);
+ User::LeaveIfError(underlyingSession.OpenExisting());
+
+ CConsoleProxy* underlying = CWriteOnlyConsoleProxy::NewL(underlyingSession);
+
+ CleanupStack::PopAndDestroy(2, &client); // we can close underlyingSession as it's been duplicated by CConsoleProxy::NewL
+
+ if (iConsole && iConsole->Console())
+ {
+ CleanupStack::PushL(underlying);
+ User::LeaveIfError(UnderlyingConsole::Set(iConsole->Console(), underlying));
+ // ownership of underlying now taken.
+ CleanupStack::Pop();
+ }
+ else
+ {
+ // save it for when the console is instantiated
+ iUnderlyingConsole = underlying;
+ }
+
+ aMessage.Complete(KErrNone);
+ }
+
+void CIoConsoleProxySession::OpenExistingL(const RMessage2& aMessage)
+ {
+ if (Server()->TheConsole()==NULL) User::Leave(KErrNotReady); // no console to connect to
+
+ iConsole = Server()->TheConsole();
+ iConsole->Open();
+ aMessage.Complete(KErrNone);
+ }
+
+TBool CIoConsoleProxySession::GetFlag(TFlag aFlag)
+ {
+ return iFlags & aFlag ? (TBool)ETrue : EFalse;
+ }
+
+void CIoConsoleProxySession::SetFlag(TFlag aFlag, TBool aSet)
+ {
+ if (aSet)
+ {
+ iFlags |= aFlag;
+ }
+ else
+ {
+ iFlags &= (~(TUint)aFlag);
+ }
+ }
+
+
+//______________________________________________________________________________
+// CWriteOnlyConsoleProxy
+CConsoleProxy* CWriteOnlyConsoleProxy::NewL(const RConsoleProxy& aProxySession)
+ {
+ CWriteOnlyConsoleProxy* self = new(ELeave)CWriteOnlyConsoleProxy();
+ CleanupStack::PushL(self);
+ self->ConstructL(aProxySession);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CWriteOnlyConsoleProxy::CWriteOnlyConsoleProxy()
+ {
+ }
+
+void CWriteOnlyConsoleProxy::Read(TRequestStatus&)
+ {
+ User::Panic(KIoServerName, EPanicCannotReadFromUnderlyingConsole);
+ }
+
+void CWriteOnlyConsoleProxy::ReadCancel()
+ {
+ }
+
+TKeyCode CWriteOnlyConsoleProxy::KeyCode() const
+ {
+ return EKeyNull;
+ }
+
+
+TUint CWriteOnlyConsoleProxy::KeyModifiers() const
+ {
+ return 0;
+ }
+
+//______________________________________________________________________________
+// CLazyConsole
+CLazyConsole::CLazyConsole(TConsoleCreateFunction aConsoleCreate, TBool aAutoDetectSize)
+ : iConsoleCreate(aConsoleCreate), iSizeAutoDetect(aAutoDetectSize)
+ {
+ }
+
+CLazyConsole::~CLazyConsole()
+ {
+ iTitle.Close();
+ delete iConsole;
+ }
+
+TInt CLazyConsole::Create(const TDesC &aTitle,TSize aSize)
+ {
+ iSize = aSize;
+ return iTitle.Create(aTitle);
+ }
+
+TInt CLazyConsole::CheckCreated() const
+ {
+ if (iCreateError) return iCreateError;
+ if (iConsole) return KErrNone;
+
+ TRAP(iCreateError, iConsole = iConsoleCreate());
+ if ((iCreateError==KErrNone) && (!iConsole))
+ {
+ iCreateError = KErrNoMemory;
+ }
+ if (iCreateError == KErrNone)
+ {
+ TName procName = RProcess().Name(); // econseik sets the process name to the console title...
+ iCreateError = iConsole->Create(iTitle, iSize);
+ User::RenameProcess(procName.Left(procName.Locate('['))); // ...so restore it just in case
+ }
+ if ((iCreateError == KErrNone) && iSizeAutoDetect)
+ {
+ iDetectedSize = DetectConsoleSize(iConsole);
+ }
+ if (iCreateError != KErrNone)
+ {
+ delete iConsole;
+ iConsole = NULL;
+ }
+ return iCreateError;
+ }
+
+void CLazyConsole::Read(TRequestStatus &aStatus)
+ {
+ TInt err = CheckCreated();
+ if (err)
+ {
+ TRequestStatus* stat = &aStatus;
+ User::RequestComplete(stat, err);
+ return;
+ }
+ iConsole->Read(aStatus);
+ }
+
+void CLazyConsole::ReadCancel()
+ {
+ if (iConsole)
+ {
+ iConsole->ReadCancel();
+ }
+ }
+
+void CLazyConsole::Write(const TDesC &aDes)
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ iConsole->Write(aDes);
+ }
+ }
+
+TPoint CLazyConsole::CursorPos() const
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->CursorPos();
+ }
+ return TPoint(0,0);
+ }
+
+void CLazyConsole::SetCursorPosAbs(const TPoint &aPoint)
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->SetCursorPosAbs(aPoint);
+ }
+ }
+
+void CLazyConsole::SetCursorPosRel(const TPoint &aPoint)
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->SetCursorPosRel(aPoint);
+ }
+ }
+
+void CLazyConsole::SetCursorHeight(TInt aPercentage)
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->SetCursorHeight(aPercentage);
+ }
+ }
+
+void CLazyConsole::SetTitle(const TDesC &aTitle)
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->SetTitle(aTitle);
+ }
+ }
+
+void CLazyConsole::ClearScreen()
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->ClearScreen();
+ }
+ }
+
+void CLazyConsole::ClearToEndOfLine()
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->ClearToEndOfLine();
+ }
+ }
+
+TSize CLazyConsole::ScreenSize() const
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ if (iSizeAutoDetect)
+ {
+ return iDetectedSize;
+ }
+ else
+ {
+ return iConsole->ScreenSize();
+ }
+ }
+ else
+ {
+ return TSize(0,0);
+ }
+ }
+
+TKeyCode CLazyConsole::KeyCode() const
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->KeyCode();
+ }
+ return EKeyNull;
+ }
+
+TUint CLazyConsole::KeyModifiers() const
+ {
+ if (CheckCreated() == KErrNone)
+ {
+ return iConsole->KeyModifiers();
+ }
+ return 0;
+ }
+
+TInt CLazyConsole::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
+ {
+ if (aExtensionId == LazyConsole::KLazyConsoleExtension)
+ {
+ TBool* constructed = (TBool*)a1;
+ *constructed = (iConsole != NULL);
+ return KErrNone;
+ }
+ else
+ {
+ TInt err = CheckCreated();
+ if (err == KErrNone)
+ {
+ return ((CLazyConsole*)iConsole)->Extension_(aExtensionId, a0, a1);
+ }
+ return err;
+ }
+ }