|
1 // TextBuffer.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 #include "Misc.h" |
|
13 #include <fcntl.h> |
|
14 #include <io.h> |
|
15 #include <sys/stat.h> |
|
16 #include "TextBuffer.h" |
|
17 |
|
18 const int KTabSize = 4; |
|
19 |
|
20 |
|
21 CTextBuffer* CTextBuffer::New(int aWidth, int aHeight, int aMaxNumOverflowLines) |
|
22 { |
|
23 std::auto_ptr<CTextBuffer> self(new(EThrow) CTextBuffer(aWidth, aHeight, aMaxNumOverflowLines)); |
|
24 self->Construct(); |
|
25 return self.release(); |
|
26 } |
|
27 |
|
28 CTextBuffer::~CTextBuffer() |
|
29 { |
|
30 delete iBuffer; |
|
31 } |
|
32 |
|
33 void CTextBuffer::SetObserver(MTextBufferObserver* aObserver) |
|
34 { |
|
35 iObserver = aObserver; |
|
36 } |
|
37 |
|
38 int StringLength(LPCTSTR aStart, LPCTSTR aEnd) |
|
39 { |
|
40 return (aEnd - aStart) + 1; |
|
41 } |
|
42 |
|
43 void CTextBuffer::Write(LPCTSTR aString, int aLength) |
|
44 { |
|
45 LPCTSTR startBlock = aString; |
|
46 LPCTSTR ptr = aString; |
|
47 LPCTSTR end = aString + aLength - 1; |
|
48 int numCharsToLineEnd = NumCharsToLineEnd(); |
|
49 while (ptr <= end) |
|
50 { |
|
51 if (!IsOrdinaryChar(*ptr)) |
|
52 { |
|
53 // Not an ordinary character, so write the block we've gathered so far. |
|
54 if (StringLength(startBlock, ptr - 1) > 0) |
|
55 { |
|
56 WriteBlock(startBlock, StringLength(startBlock, ptr - 1)); |
|
57 } |
|
58 // Write the special character. |
|
59 WriteSpecialChar(*ptr); |
|
60 // Setup variables for the next block. |
|
61 startBlock = ptr + 1; |
|
62 numCharsToLineEnd = NumCharsToLineEnd(); |
|
63 } |
|
64 else if (StringLength(startBlock, ptr) == numCharsToLineEnd) |
|
65 { |
|
66 // Reached line end, so write the block we've gathered so far. |
|
67 ASSERT(numCharsToLineEnd > 0); |
|
68 WriteBlock(startBlock, numCharsToLineEnd); |
|
69 // Setup variables for the next block. |
|
70 startBlock = ptr + 1; |
|
71 numCharsToLineEnd = NumCharsToLineEnd(); |
|
72 } |
|
73 else if (ptr == end) |
|
74 { |
|
75 // Reached end of buffer. |
|
76 if (StringLength(startBlock, ptr) > 0) |
|
77 { |
|
78 WriteBlock(startBlock, StringLength(startBlock, ptr)); |
|
79 } |
|
80 } |
|
81 ++ptr; |
|
82 } |
|
83 } |
|
84 |
|
85 void CTextBuffer::GetCursorPos(int& aX, int& aY) const |
|
86 { |
|
87 aX = iCursorPosX; |
|
88 aY = iCursorPosY; |
|
89 } |
|
90 |
|
91 void CTextBuffer::SetAbsCursorPos(int aX, int aY) |
|
92 { |
|
93 MoveCursor(aX, aY); |
|
94 } |
|
95 |
|
96 void CTextBuffer::SetRelCursorPos(int aX, int aY) |
|
97 { |
|
98 MoveCursor(iCursorPosX + aX, iCursorPosY + aY); |
|
99 } |
|
100 |
|
101 void CTextBuffer::GetSize(int& aWidth, int& aHeight) const |
|
102 { |
|
103 aWidth = iWidth; |
|
104 aHeight = iHeight; |
|
105 } |
|
106 |
|
107 int CTextBuffer::NumOverflowLines() const |
|
108 { |
|
109 return iNumOverflowLines; |
|
110 } |
|
111 |
|
112 void CTextBuffer::Clear() |
|
113 { |
|
114 ClearBuffer(); |
|
115 MoveCursor(0, 0); |
|
116 } |
|
117 |
|
118 void CTextBuffer::ClearToEndOfLine() |
|
119 { |
|
120 const PTCHAR start = CursorPtr(); |
|
121 PTCHAR ptr = start; |
|
122 const PTCHAR end = LineEndPtr(); |
|
123 |
|
124 while (ptr <= end) |
|
125 { |
|
126 *ptr++ = TCHAR(' '); |
|
127 } |
|
128 |
|
129 if (iObserver) |
|
130 { |
|
131 iObserver->HandleTextBufferChange(iCursorPosX, iCursorPosY, start, StringLength(start, end)); |
|
132 } |
|
133 } |
|
134 |
|
135 CTextBuffer::CTextBuffer(int aWidth, int aHeight, int aMaxNumOverflowLines) |
|
136 : iObserver(NULL), iBuffer(NULL), iWidth(aWidth), iHeight(aHeight), iMaxNumOverflowLines(aMaxNumOverflowLines), iNumOverflowLines(0), iCursorPosX(0), iCursorPosY(0), iCaptureFile(0) |
|
137 { |
|
138 } |
|
139 |
|
140 void CTextBuffer::Construct() |
|
141 { |
|
142 iBuffer = new(EThrow) TCHAR[iWidth * (iHeight + iMaxNumOverflowLines)]; |
|
143 ClearBuffer(); |
|
144 } |
|
145 |
|
146 void CTextBuffer::MoveCursor(int aNewX, int aNewY) |
|
147 { |
|
148 ASSERT((aNewX >= 0) && (aNewY >= 0)); |
|
149 if ((aNewX >= 0) && (aNewY >= 0)) |
|
150 { |
|
151 if (aNewX < iWidth) |
|
152 { |
|
153 iCursorPosX = aNewX; |
|
154 } |
|
155 if (aNewY < iHeight) |
|
156 { |
|
157 iCursorPosY = aNewY; |
|
158 } |
|
159 if (iObserver) |
|
160 { |
|
161 iObserver->HandleTextBufferCursorChange(); |
|
162 } |
|
163 } |
|
164 } |
|
165 |
|
166 PTCHAR CTextBuffer::CursorPtr() const |
|
167 { |
|
168 return iBuffer + (((iMaxNumOverflowLines + iCursorPosY) * iWidth) + iCursorPosX); |
|
169 } |
|
170 |
|
171 PTCHAR CTextBuffer::LineEndPtr() const |
|
172 { |
|
173 return iBuffer + (((iMaxNumOverflowLines + iCursorPosY) * iWidth) + (iWidth - 1)); |
|
174 } |
|
175 |
|
176 PTCHAR CTextBuffer::BufEndPtr() const |
|
177 { |
|
178 return iBuffer + (iWidth * (iHeight + iMaxNumOverflowLines)); |
|
179 } |
|
180 |
|
181 void CTextBuffer::WriteSpecialChar(TCHAR aChar) |
|
182 { |
|
183 switch(aChar) |
|
184 { |
|
185 case 0x00: // Null. |
|
186 break; |
|
187 case 0x07: // Bell. |
|
188 break; |
|
189 case 0x08: // Backspace. |
|
190 case 0x7f: // Delete. |
|
191 BackSpace(); |
|
192 break; |
|
193 case 0x09: |
|
194 HorizontalTab(); |
|
195 break; |
|
196 case 0x0a: |
|
197 LineFeed(); |
|
198 break; |
|
199 case 0x0b: // Vertical tab. |
|
200 break; |
|
201 case 0x0c: |
|
202 FormFeed(); |
|
203 break; |
|
204 case 0x0d: |
|
205 CarriageReturn(); |
|
206 break; |
|
207 default: |
|
208 ASSERT(FALSE); |
|
209 } |
|
210 } |
|
211 |
|
212 void CTextBuffer::WriteBlock(LPCTSTR aString, int aLength) |
|
213 { |
|
214 PTCHAR cursorPtr = CursorPtr(); |
|
215 PTCHAR ptr = cursorPtr; |
|
216 for (int i = 0; i < aLength; ++i) |
|
217 { |
|
218 *ptr++ = aString[i]; |
|
219 } |
|
220 if (iObserver) |
|
221 { |
|
222 iObserver->HandleTextBufferChange(iCursorPosX, iCursorPosY, cursorPtr, aLength); |
|
223 } |
|
224 if ((iCursorPosX + aLength) == iWidth) |
|
225 { |
|
226 MoveCursor(iWidth - 1, iCursorPosY); |
|
227 CursorRight(); |
|
228 } |
|
229 else |
|
230 { |
|
231 MoveCursor(iCursorPosX + aLength, iCursorPosY); |
|
232 } |
|
233 } |
|
234 |
|
235 bool CTextBuffer::IsOrdinaryChar(TCHAR aChar) const |
|
236 { |
|
237 switch(aChar) |
|
238 { |
|
239 case 0x00: // Null. |
|
240 case 0x07: // Bell. |
|
241 case 0x08: // Backspace. |
|
242 case 0x7f: // Delete. |
|
243 case 0x09: // Tab. |
|
244 case 0x0a: // Line feed. |
|
245 case 0x0b: // Vertical tab. |
|
246 case 0x0c: // Form feed. |
|
247 case 0x0d: // Carriage return. |
|
248 return FALSE; |
|
249 default: |
|
250 return TRUE; |
|
251 } |
|
252 } |
|
253 |
|
254 int CTextBuffer::NumCharsToLineEnd() const |
|
255 { |
|
256 return iWidth - iCursorPosX; |
|
257 } |
|
258 |
|
259 void CTextBuffer::ClearBuffer() |
|
260 { |
|
261 PTCHAR bufPtr = iBuffer; |
|
262 PTCHAR end = BufEndPtr(); |
|
263 while (bufPtr < end ) |
|
264 { |
|
265 *bufPtr++ = TCHAR(' '); |
|
266 } |
|
267 iNumOverflowLines = 0; |
|
268 if (iObserver) |
|
269 { |
|
270 iObserver->HandleTextBufferCleared(); |
|
271 } |
|
272 } |
|
273 |
|
274 LPCTSTR CTextBuffer::GetLine(int aPos) const |
|
275 { |
|
276 ASSERT(aPos >= -iNumOverflowLines); |
|
277 ASSERT(aPos < iHeight); |
|
278 return iBuffer + ((iMaxNumOverflowLines + aPos) * iWidth); |
|
279 } |
|
280 |
|
281 void CTextBuffer::CaptureToFile(LPCTSTR aFileName) |
|
282 { |
|
283 ASSERT(iCaptureFile == 0); |
|
284 iCaptureFile = _wopen(aFileName, _O_CREAT | _O_WRONLY | _O_BINARY, _S_IWRITE); |
|
285 if (iCaptureFile == -1) |
|
286 { |
|
287 iCaptureFile = 0; |
|
288 throw KExceptionFailedToCreateCaptureFile; |
|
289 } |
|
290 WriteOverflowLinesToCaptureFile(); |
|
291 } |
|
292 |
|
293 void CTextBuffer::StopCaptureToFile() |
|
294 { |
|
295 if (iCaptureFile) |
|
296 { |
|
297 WriteBufferToCaptureFile(); |
|
298 _close(iCaptureFile); |
|
299 iCaptureFile = 0; |
|
300 } |
|
301 } |
|
302 |
|
303 bool CTextBuffer::IsCapturingToFile() const |
|
304 { |
|
305 return !(iCaptureFile == 0); |
|
306 } |
|
307 |
|
308 void CTextBuffer::CursorLeft() |
|
309 { |
|
310 if (iCursorPosX > 0) |
|
311 { |
|
312 // Not yet reached beginning of line. |
|
313 MoveCursor(iCursorPosX - 1, iCursorPosY); |
|
314 } |
|
315 else if (iCursorPosY > 0) |
|
316 { |
|
317 // Reached beginning of line, so jump to end of line above. |
|
318 MoveCursor(iWidth - 1, iCursorPosY - 1); |
|
319 } |
|
320 else |
|
321 { |
|
322 // Reached the top left corner of the console - do nothing. |
|
323 } |
|
324 } |
|
325 |
|
326 void CTextBuffer::CursorRight() |
|
327 { |
|
328 if (iCursorPosX < (iWidth - 1)) |
|
329 { |
|
330 // Not yet reached the end of the line. |
|
331 MoveCursor(iCursorPosX + 1, iCursorPosY); |
|
332 } |
|
333 else if (iCursorPosY < (iHeight - 1)) |
|
334 { |
|
335 // Reached the end of the line and there's space below - jump to the beginning of the line below. |
|
336 MoveCursor(0, iCursorPosY + 1); |
|
337 } |
|
338 else |
|
339 { |
|
340 // 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. |
|
341 ScrollUp(); |
|
342 MoveCursor(0, iCursorPosY); |
|
343 } |
|
344 } |
|
345 |
|
346 void CTextBuffer::FormFeed() |
|
347 { |
|
348 Clear(); |
|
349 } |
|
350 |
|
351 void CTextBuffer::LineFeed() |
|
352 { |
|
353 if (iCursorPosY < (iHeight - 1)) |
|
354 { |
|
355 MoveCursor(0, iCursorPosY + 1); |
|
356 } |
|
357 else |
|
358 { |
|
359 ScrollUp(); |
|
360 MoveCursor(0, iCursorPosY); |
|
361 } |
|
362 } |
|
363 |
|
364 void CTextBuffer::CarriageReturn() |
|
365 { |
|
366 MoveCursor(0, iCursorPosY); |
|
367 } |
|
368 |
|
369 void CTextBuffer::BackSpace() |
|
370 { |
|
371 if (!((iCursorPosX == 0) && (iCursorPosY == 0))) |
|
372 { |
|
373 CursorLeft(); |
|
374 WriteBlock(TEXT(" "), 1); |
|
375 CursorLeft(); |
|
376 } |
|
377 } |
|
378 |
|
379 void CTextBuffer::HorizontalTab() |
|
380 { |
|
381 MoveCursor(iCursorPosX - (iCursorPosX % KTabSize) + KTabSize, iCursorPosY); |
|
382 if (iCursorPosX > (iWidth - 1)) |
|
383 { |
|
384 CarriageReturn(); |
|
385 LineFeed(); |
|
386 } |
|
387 } |
|
388 |
|
389 void CTextBuffer::ScrollUp() |
|
390 { |
|
391 WriteLineToCaptureFile(GetLine(0)); |
|
392 PTCHAR dst = iBuffer; |
|
393 PTCHAR end = BufEndPtr(); |
|
394 PTCHAR src = dst + iWidth; |
|
395 while (src < end) |
|
396 { |
|
397 *dst++ = *src++; |
|
398 } |
|
399 while (dst < end) |
|
400 { |
|
401 *dst++ = TCHAR(' '); |
|
402 } |
|
403 if (iNumOverflowLines < iMaxNumOverflowLines) |
|
404 { |
|
405 ++iNumOverflowLines; |
|
406 } |
|
407 if (iObserver) |
|
408 { |
|
409 iObserver->HandleTextBufferScroll(); |
|
410 } |
|
411 } |
|
412 |
|
413 void CTextBuffer::WriteLineToCaptureFile(LPCTSTR aLinePtr) |
|
414 { |
|
415 if (iCaptureFile) |
|
416 { |
|
417 LPCTSTR lineEnd = aLinePtr + iWidth - 1; |
|
418 while ((*lineEnd == TCHAR(' ')) && (lineEnd > aLinePtr)) |
|
419 { |
|
420 --lineEnd; |
|
421 } |
|
422 if (lineEnd == aLinePtr) |
|
423 { |
|
424 if (_write(iCaptureFile, "\r\n", 2) != 2) |
|
425 { |
|
426 _close(iCaptureFile); |
|
427 iCaptureFile = 0; |
|
428 throw KExceptionFailedToWriteToCaptureFile; |
|
429 } |
|
430 } |
|
431 else |
|
432 { |
|
433 const int lineLength = (lineEnd - aLinePtr) + 3; |
|
434 std::auto_ptr<char> narrowBuf(new(EThrow) char[lineLength]); |
|
435 char* narrowBufPtr = narrowBuf.get(); |
|
436 while (aLinePtr <= lineEnd) |
|
437 { |
|
438 *narrowBufPtr++ = (char)*aLinePtr++; |
|
439 } |
|
440 *narrowBufPtr++ = '\r'; |
|
441 *narrowBufPtr = '\n'; |
|
442 if (_write(iCaptureFile, narrowBuf.get(), lineLength) != lineLength) |
|
443 { |
|
444 _close(iCaptureFile); |
|
445 iCaptureFile = 0; |
|
446 throw KExceptionFailedToWriteToCaptureFile; |
|
447 } |
|
448 |
|
449 } |
|
450 } |
|
451 } |
|
452 |
|
453 void CTextBuffer::WriteOverflowLinesToCaptureFile() |
|
454 { |
|
455 for (int i = -iNumOverflowLines; i < 0; ++i) |
|
456 { |
|
457 WriteLineToCaptureFile(GetLine(i)); |
|
458 } |
|
459 } |
|
460 |
|
461 void CTextBuffer::WriteBufferToCaptureFile() |
|
462 { |
|
463 for (int i = 0; i < iHeight; ++i) |
|
464 { |
|
465 WriteLineToCaptureFile(GetLine(i)); |
|
466 } |
|
467 } |