diff -r 000000000000 -r 7f656887cf89 libraries/iosrv/server/console.cpp --- /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 +#include +#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 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 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(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; + } + }