--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/consoles/rcons/server/win32/TextBuffer.cpp Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,467 @@
+// TextBuffer.cpp
+//
+// Copyright (c) 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 "Misc.h"
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include "TextBuffer.h"
+
+const int KTabSize = 4;
+
+
+CTextBuffer* CTextBuffer::New(int aWidth, int aHeight, int aMaxNumOverflowLines)
+ {
+ std::auto_ptr<CTextBuffer> self(new(EThrow) CTextBuffer(aWidth, aHeight, aMaxNumOverflowLines));
+ self->Construct();
+ return self.release();
+ }
+
+CTextBuffer::~CTextBuffer()
+ {
+ delete iBuffer;
+ }
+
+void CTextBuffer::SetObserver(MTextBufferObserver* aObserver)
+ {
+ iObserver = aObserver;
+ }
+
+int StringLength(LPCTSTR aStart, LPCTSTR aEnd)
+ {
+ return (aEnd - aStart) + 1;
+ }
+
+void CTextBuffer::Write(LPCTSTR aString, int aLength)
+ {
+ LPCTSTR startBlock = aString;
+ LPCTSTR ptr = aString;
+ LPCTSTR end = aString + aLength - 1;
+ int numCharsToLineEnd = NumCharsToLineEnd();
+ while (ptr <= end)
+ {
+ if (!IsOrdinaryChar(*ptr))
+ {
+ // Not an ordinary character, so write the block we've gathered so far.
+ if (StringLength(startBlock, ptr - 1) > 0)
+ {
+ WriteBlock(startBlock, StringLength(startBlock, ptr - 1));
+ }
+ // Write the special character.
+ WriteSpecialChar(*ptr);
+ // Setup variables for the next block.
+ startBlock = ptr + 1;
+ numCharsToLineEnd = NumCharsToLineEnd();
+ }
+ else if (StringLength(startBlock, ptr) == numCharsToLineEnd)
+ {
+ // Reached line end, so write the block we've gathered so far.
+ ASSERT(numCharsToLineEnd > 0);
+ WriteBlock(startBlock, numCharsToLineEnd);
+ // Setup variables for the next block.
+ startBlock = ptr + 1;
+ numCharsToLineEnd = NumCharsToLineEnd();
+ }
+ else if (ptr == end)
+ {
+ // Reached end of buffer.
+ if (StringLength(startBlock, ptr) > 0)
+ {
+ WriteBlock(startBlock, StringLength(startBlock, ptr));
+ }
+ }
+ ++ptr;
+ }
+ }
+
+void CTextBuffer::GetCursorPos(int& aX, int& aY) const
+ {
+ aX = iCursorPosX;
+ aY = iCursorPosY;
+ }
+
+void CTextBuffer::SetAbsCursorPos(int aX, int aY)
+ {
+ MoveCursor(aX, aY);
+ }
+
+void CTextBuffer::SetRelCursorPos(int aX, int aY)
+ {
+ MoveCursor(iCursorPosX + aX, iCursorPosY + aY);
+ }
+
+void CTextBuffer::GetSize(int& aWidth, int& aHeight) const
+ {
+ aWidth = iWidth;
+ aHeight = iHeight;
+ }
+
+int CTextBuffer::NumOverflowLines() const
+ {
+ return iNumOverflowLines;
+ }
+
+void CTextBuffer::Clear()
+ {
+ ClearBuffer();
+ MoveCursor(0, 0);
+ }
+
+void CTextBuffer::ClearToEndOfLine()
+ {
+ const PTCHAR start = CursorPtr();
+ PTCHAR ptr = start;
+ const PTCHAR end = LineEndPtr();
+
+ while (ptr <= end)
+ {
+ *ptr++ = TCHAR(' ');
+ }
+
+ if (iObserver)
+ {
+ iObserver->HandleTextBufferChange(iCursorPosX, iCursorPosY, start, StringLength(start, end));
+ }
+ }
+
+CTextBuffer::CTextBuffer(int aWidth, int aHeight, int aMaxNumOverflowLines)
+ : iObserver(NULL), iBuffer(NULL), iWidth(aWidth), iHeight(aHeight), iMaxNumOverflowLines(aMaxNumOverflowLines), iNumOverflowLines(0), iCursorPosX(0), iCursorPosY(0), iCaptureFile(0)
+ {
+ }
+
+void CTextBuffer::Construct()
+ {
+ iBuffer = new(EThrow) TCHAR[iWidth * (iHeight + iMaxNumOverflowLines)];
+ ClearBuffer();
+ }
+
+void CTextBuffer::MoveCursor(int aNewX, int aNewY)
+ {
+ ASSERT((aNewX >= 0) && (aNewY >= 0));
+ if ((aNewX >= 0) && (aNewY >= 0))
+ {
+ if (aNewX < iWidth)
+ {
+ iCursorPosX = aNewX;
+ }
+ if (aNewY < iHeight)
+ {
+ iCursorPosY = aNewY;
+ }
+ if (iObserver)
+ {
+ iObserver->HandleTextBufferCursorChange();
+ }
+ }
+ }
+
+PTCHAR CTextBuffer::CursorPtr() const
+ {
+ return iBuffer + (((iMaxNumOverflowLines + iCursorPosY) * iWidth) + iCursorPosX);
+ }
+
+PTCHAR CTextBuffer::LineEndPtr() const
+ {
+ return iBuffer + (((iMaxNumOverflowLines + iCursorPosY) * iWidth) + (iWidth - 1));
+ }
+
+PTCHAR CTextBuffer::BufEndPtr() const
+ {
+ return iBuffer + (iWidth * (iHeight + iMaxNumOverflowLines));
+ }
+
+void CTextBuffer::WriteSpecialChar(TCHAR aChar)
+ {
+ switch(aChar)
+ {
+ case 0x00: // Null.
+ break;
+ case 0x07: // Bell.
+ break;
+ case 0x08: // Backspace.
+ case 0x7f: // Delete.
+ BackSpace();
+ break;
+ case 0x09:
+ HorizontalTab();
+ break;
+ case 0x0a:
+ LineFeed();
+ break;
+ case 0x0b: // Vertical tab.
+ break;
+ case 0x0c:
+ FormFeed();
+ break;
+ case 0x0d:
+ CarriageReturn();
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+ }
+
+void CTextBuffer::WriteBlock(LPCTSTR aString, int aLength)
+ {
+ PTCHAR cursorPtr = CursorPtr();
+ PTCHAR ptr = cursorPtr;
+ for (int i = 0; i < aLength; ++i)
+ {
+ *ptr++ = aString[i];
+ }
+ if (iObserver)
+ {
+ iObserver->HandleTextBufferChange(iCursorPosX, iCursorPosY, cursorPtr, aLength);
+ }
+ if ((iCursorPosX + aLength) == iWidth)
+ {
+ MoveCursor(iWidth - 1, iCursorPosY);
+ CursorRight();
+ }
+ else
+ {
+ MoveCursor(iCursorPosX + aLength, iCursorPosY);
+ }
+ }
+
+bool CTextBuffer::IsOrdinaryChar(TCHAR aChar) const
+ {
+ switch(aChar)
+ {
+ case 0x00: // Null.
+ case 0x07: // Bell.
+ case 0x08: // Backspace.
+ case 0x7f: // Delete.
+ case 0x09: // Tab.
+ case 0x0a: // Line feed.
+ case 0x0b: // Vertical tab.
+ case 0x0c: // Form feed.
+ case 0x0d: // Carriage return.
+ return FALSE;
+ default:
+ return TRUE;
+ }
+ }
+
+int CTextBuffer::NumCharsToLineEnd() const
+ {
+ return iWidth - iCursorPosX;
+ }
+
+void CTextBuffer::ClearBuffer()
+ {
+ PTCHAR bufPtr = iBuffer;
+ PTCHAR end = BufEndPtr();
+ while (bufPtr < end )
+ {
+ *bufPtr++ = TCHAR(' ');
+ }
+ iNumOverflowLines = 0;
+ if (iObserver)
+ {
+ iObserver->HandleTextBufferCleared();
+ }
+ }
+
+LPCTSTR CTextBuffer::GetLine(int aPos) const
+ {
+ ASSERT(aPos >= -iNumOverflowLines);
+ ASSERT(aPos < iHeight);
+ return iBuffer + ((iMaxNumOverflowLines + aPos) * iWidth);
+ }
+
+void CTextBuffer::CaptureToFile(LPCTSTR aFileName)
+ {
+ ASSERT(iCaptureFile == 0);
+ iCaptureFile = _wopen(aFileName, _O_CREAT | _O_WRONLY | _O_BINARY, _S_IWRITE);
+ if (iCaptureFile == -1)
+ {
+ iCaptureFile = 0;
+ throw KExceptionFailedToCreateCaptureFile;
+ }
+ WriteOverflowLinesToCaptureFile();
+ }
+
+void CTextBuffer::StopCaptureToFile()
+ {
+ if (iCaptureFile)
+ {
+ WriteBufferToCaptureFile();
+ _close(iCaptureFile);
+ iCaptureFile = 0;
+ }
+ }
+
+bool CTextBuffer::IsCapturingToFile() const
+ {
+ return !(iCaptureFile == 0);
+ }
+
+void CTextBuffer::CursorLeft()
+ {
+ if (iCursorPosX > 0)
+ {
+ // Not yet reached beginning of line.
+ MoveCursor(iCursorPosX - 1, iCursorPosY);
+ }
+ else if (iCursorPosY > 0)
+ {
+ // Reached beginning of line, so jump to end of line above.
+ MoveCursor(iWidth - 1, iCursorPosY - 1);
+ }
+ else
+ {
+ // Reached the top left corner of the console - do nothing.
+ }
+ }
+
+void CTextBuffer::CursorRight()
+ {
+ if (iCursorPosX < (iWidth - 1))
+ {
+ // Not yet reached the end of the line.
+ MoveCursor(iCursorPosX + 1, iCursorPosY);
+ }
+ else if (iCursorPosY < (iHeight - 1))
+ {
+ // Reached the end of the line and there's space below - jump to the beginning of the line below.
+ MoveCursor(0, iCursorPosY + 1);
+ }
+ else
+ {
+ // Reached the end of the line and there's no space below - scroll up a line and jump to the beginning of the newly exposed line.
+ ScrollUp();
+ MoveCursor(0, iCursorPosY);
+ }
+ }
+
+void CTextBuffer::FormFeed()
+ {
+ Clear();
+ }
+
+void CTextBuffer::LineFeed()
+ {
+ if (iCursorPosY < (iHeight - 1))
+ {
+ MoveCursor(0, iCursorPosY + 1);
+ }
+ else
+ {
+ ScrollUp();
+ MoveCursor(0, iCursorPosY);
+ }
+ }
+
+void CTextBuffer::CarriageReturn()
+ {
+ MoveCursor(0, iCursorPosY);
+ }
+
+void CTextBuffer::BackSpace()
+ {
+ if (!((iCursorPosX == 0) && (iCursorPosY == 0)))
+ {
+ CursorLeft();
+ WriteBlock(TEXT(" "), 1);
+ CursorLeft();
+ }
+ }
+
+void CTextBuffer::HorizontalTab()
+ {
+ MoveCursor(iCursorPosX - (iCursorPosX % KTabSize) + KTabSize, iCursorPosY);
+ if (iCursorPosX > (iWidth - 1))
+ {
+ CarriageReturn();
+ LineFeed();
+ }
+ }
+
+void CTextBuffer::ScrollUp()
+ {
+ WriteLineToCaptureFile(GetLine(0));
+ PTCHAR dst = iBuffer;
+ PTCHAR end = BufEndPtr();
+ PTCHAR src = dst + iWidth;
+ while (src < end)
+ {
+ *dst++ = *src++;
+ }
+ while (dst < end)
+ {
+ *dst++ = TCHAR(' ');
+ }
+ if (iNumOverflowLines < iMaxNumOverflowLines)
+ {
+ ++iNumOverflowLines;
+ }
+ if (iObserver)
+ {
+ iObserver->HandleTextBufferScroll();
+ }
+ }
+
+void CTextBuffer::WriteLineToCaptureFile(LPCTSTR aLinePtr)
+ {
+ if (iCaptureFile)
+ {
+ LPCTSTR lineEnd = aLinePtr + iWidth - 1;
+ while ((*lineEnd == TCHAR(' ')) && (lineEnd > aLinePtr))
+ {
+ --lineEnd;
+ }
+ if (lineEnd == aLinePtr)
+ {
+ if (_write(iCaptureFile, "\r\n", 2) != 2)
+ {
+ _close(iCaptureFile);
+ iCaptureFile = 0;
+ throw KExceptionFailedToWriteToCaptureFile;
+ }
+ }
+ else
+ {
+ const int lineLength = (lineEnd - aLinePtr) + 3;
+ std::auto_ptr<char> narrowBuf(new(EThrow) char[lineLength]);
+ char* narrowBufPtr = narrowBuf.get();
+ while (aLinePtr <= lineEnd)
+ {
+ *narrowBufPtr++ = (char)*aLinePtr++;
+ }
+ *narrowBufPtr++ = '\r';
+ *narrowBufPtr = '\n';
+ if (_write(iCaptureFile, narrowBuf.get(), lineLength) != lineLength)
+ {
+ _close(iCaptureFile);
+ iCaptureFile = 0;
+ throw KExceptionFailedToWriteToCaptureFile;
+ }
+
+ }
+ }
+ }
+
+void CTextBuffer::WriteOverflowLinesToCaptureFile()
+ {
+ for (int i = -iNumOverflowLines; i < 0; ++i)
+ {
+ WriteLineToCaptureFile(GetLine(i));
+ }
+ }
+
+void CTextBuffer::WriteBufferToCaptureFile()
+ {
+ for (int i = 0; i < iHeight; ++i)
+ {
+ WriteLineToCaptureFile(GetLine(i));
+ }
+ }