2 * regexpl - Console Registry Explorer
4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 // Console.cpp: implementation of the CConsole class.
24 //////////////////////////////////////////////////////////////////////
30 #define MORE_STRING _T("-- Press space to view more. Press q or Ctrl+break to cancel.--")
31 #define MORE_EMPTY_STRING _T(" ")
34 TCHAR * _tcsnchr(const TCHAR *string, TCHAR ch, int count)
38 if (*string == 0) return NULL;
39 if (*string == ch) return const_cast <char *>(string);
46 //////////////////////////////////////////////////////////////////////
47 // Construction/Destruction
48 //////////////////////////////////////////////////////////////////////
52 m_hStdIn
= INVALID_HANDLE_VALUE
;
53 m_hStdOut
= INVALID_HANDLE_VALUE
;
54 m_blnInsetMode
= TRUE
; // Insert
55 // m_blnInsetMode = FALSE; // Overwrite
56 m_dwInsertModeCursorHeight
= 15;
57 m_dwOverwriteModeCursorHeight
= 100;
62 m_pfReplaceCompletionCallback
= NULL
;
65 m_dwOldOutputMode
= 0;
66 m_blnOldInputModeSaved
= FALSE
;
67 m_blnOldOutputModeSaved
= FALSE
;
75 delete[] m_pchBuffer1
;
77 delete[] m_pchBuffer2
;
79 if (m_blnOldInputModeSaved
)
80 SetConsoleMode(m_hStdIn
,m_dwOldInputMode
);
81 if (m_blnOldOutputModeSaved
)
82 SetConsoleMode(m_hStdOut
,m_dwOldOutputMode
);
84 if (m_hStdIn
!= INVALID_HANDLE_VALUE
)
85 VERIFY(CloseHandle(m_hStdIn
));
86 if (m_hStdOut
!= INVALID_HANDLE_VALUE
)
87 VERIFY(CloseHandle(m_hStdOut
));
90 BOOL
CConsole::Write(const TCHAR
*p
, DWORD dwChars
)
92 if (m_hStdOut
== INVALID_HANDLE_VALUE
)
94 if (m_hStdIn
== INVALID_HANDLE_VALUE
)
101 DWORD dwCharsToWrite
= (dwChars
)?dwChars
:_tcslen(p
);
102 DWORD dwCharsWrittenAdd
= 0;
104 while (dwCharsToWrite
&& (!m_blnDisableWrite
))
106 switch(p
[dwCharsWrittenAdd
])
109 m_CursorPosition
.Y
++;
110 m_CursorPosition
.X
= 0;
119 if (!Write(_T(" "))) return FALSE
;
121 while ((m_CursorPosition
.X
% TAB_WIDTH
) && (!m_blnDisableWrite
));
127 if (!WriteChar(p
[dwCharsWrittenAdd
])) return FALSE
;
128 m_CursorPosition
.X
++;
131 if (m_CursorPosition
.X
== m_BufferSize
.X
)
133 m_CursorPosition
.Y
++;
134 m_CursorPosition
.X
= 0;
136 if (m_CursorPosition
.Y
== m_BufferSize
.Y
)
138 ASSERT(m_CursorPosition
.X
== 0);
141 Src
.Right
= (SHORT
)(m_BufferSize
.X
-1);
143 Src
.Bottom
= (SHORT
)(m_BufferSize
.Y
-1);
146 ci
.Char
.UnicodeChar
= L
' ';
148 ci
.Char
.AsciiChar
= ' ';
154 if (!ScrollConsoleScreenBuffer(m_hStdOut
,&Src
,NULL
,Dest
,&ci
)) return FALSE
;
155 m_CursorPosition
.Y
--;
158 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
159 VERIFY(WriteChar(_T(' ')));
160 if ((m_blnMoreMode
)&&(m_CursorPosition
.X
== 0))
163 if (m_Lines
>= m_BufferSize
.Y
-1)
165 ASSERT(m_Lines
== m_BufferSize
.Y
-1);
167 VERIFY(WriteString(MORE_STRING
,m_CursorPosition
));
168 VERIFY(FlushInputBuffer());
170 CONSOLE_CURSOR_INFO cci
;
171 cci
.bVisible
= FALSE
;
173 VERIFY(SetConsoleCursorInfo(m_hStdOut
,&cci
));
175 INPUT_RECORD InputRecord
;
176 DWORD dwRecordsReaded
;
177 while ((ret
= ReadConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsReaded
)) != FALSE
)
179 ASSERT(dwRecordsReaded
== 1);
180 if (dwRecordsReaded
!= 1)
182 if (InputRecord
.EventType
!= KEY_EVENT
)
184 if (!InputRecord
.Event
.KeyEvent
.bKeyDown
)
187 if ((InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_CANCEL
)||
188 (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== _T('Q')))
190 VERIFY(GenerateConsoleCtrlEvent(CTRL_C_EVENT
,0));
194 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
;
196 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
;
203 VERIFY(WriteString(MORE_EMPTY_STRING
,m_CursorPosition
));
204 m_CursorPosition
.X
= 0;
207 cci
.dwSize
= m_blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
208 VERIFY(SetConsoleCursorInfo(m_hStdOut
,&cci
));
217 unsigned int CConsole::GetTabWidth()
222 BOOL
CConsole::SetTitle(const TCHAR
*p
)
224 return SetConsoleTitle(p
);
227 BOOL
CConsole::SetTextAttribute(WORD wAttributes
)
229 m_wAttributes
= wAttributes
;
233 BOOL CConsole::SetInputMode(DWORD dwMode)
235 return SetConsoleMode(m_hStdIn,dwMode);
238 BOOL CConsole::SetOutputMode(DWORD dwMode)
240 return SetConsoleMode(m_hStdOut,dwMode);
243 BOOL
CConsole::FlushInputBuffer()
245 if (m_hStdIn
== INVALID_HANDLE_VALUE
) return FALSE
;
246 return FlushConsoleInputBuffer(m_hStdIn
);
249 BOOL
CConsole::ReadLine()
251 if (m_hStdIn
== INVALID_HANDLE_VALUE
) return FALSE
;
252 if (m_hStdOut
== INVALID_HANDLE_VALUE
) return FALSE
;
253 if (m_dwBufferSize
== 0)
258 if (m_pchBuffer
== NULL
)
263 if (m_pchBuffer1
== NULL
)
268 if (!FlushConsoleInputBuffer(m_hStdIn
)) return FALSE
;
270 COORD FristCharCursorPosition
= m_CursorPosition
;
271 #define X_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT(((FristCharCursorPosition.X + ofs)%m_BufferSize.X))
272 #define Y_CURSOR_POSITION_FROM_OFFSET(ofs) USHORT((FristCharCursorPosition.Y + (FristCharCursorPosition.X + ofs)/m_BufferSize.X))
273 //#define OFFSET_FROM_CURSOR_POSITION(pos) ((pos.Y-FristCharCursorPosition.Y)*m_BufferSize.X+pos.X-FristCharCursorPosition.X)
275 DWORD dwRecordsReaded
;
276 DWORD dwCurrentCharOffset
= 0;
277 DWORD dwLastCharOffset
= 0;
280 BOOL blnCompletionMode
= FALSE
;
281 // unsigned __int64 nCompletionIndex = 0;
282 unsigned long long nCompletionIndex
= 0;
283 DWORD dwCompletionOffset
= 0;
284 DWORD dwCompletionStringSize
= 0;
285 COORD CompletionPosition
= FristCharCursorPosition
;
288 BOOL blnOldMoreMode
= m_blnMoreMode
;
289 m_blnMoreMode
= FALSE
;
291 DWORD dwHistoryIndex
= 0;
293 INPUT_RECORD InputRecord
;
294 while ((ret
= ReadConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsReaded
)) != FALSE
)
296 ASSERT(dwRecordsReaded
== 1);
297 if (dwRecordsReaded
!= 1) return FALSE
;
298 if (InputRecord
.EventType
!= KEY_EVENT
) continue;
299 if (!InputRecord
.Event
.KeyEvent
.bKeyDown
) continue;
301 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
;
303 TCHAR ch
= InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
;
308 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
309 FristCharCursorPosition
.Y
= SHORT(FristCharCursorPosition
.Y
- m_LinesScrolled
);
310 if (m_LinesScrolled
> CompletionPosition
.Y
) return FALSE
;
311 CompletionPosition
.Y
= SHORT(CompletionPosition
.Y
- m_LinesScrolled
);
315 // sprintf(Buf,"wVirtualKeyCode = %u\nchar = %u\n\n",InputRecord.Event.KeyEvent.wVirtualKeyCode,ch);
316 // OutputDebugString(Buf);
319 if ((ch
== 0x16)&&(InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== 'V'))
328 if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_INSERT
)
330 if (!(InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
))
332 VERIFY(SetInsertMode(!m_blnInsetMode
));
336 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
339 if (!IsClipboardFormatAvailable(
347 if (!OpenClipboard(NULL
))
350 const TCHAR
*pch
= NULL
;
352 HANDLE hglb
= GetClipboardData(
361 LPTSTR lptstr
= (LPTSTR
)GlobalLock(hglb
);
364 _tcsncpy(m_pchBuffer1
,lptstr
,m_dwBufferSize
);
365 m_pchBuffer1
[m_dwBufferSize
-1] = 0;
372 if (pch
== NULL
) continue;
378 if (dwLastCharOffset
>= m_dwBufferSize
-1)
380 ASSERT(dwLastCharOffset
== m_dwBufferSize
-1);
385 //if (m_blnInsetMode)
386 ch1
= m_pchBuffer
[dwCurrentCharOffset
];
387 m_pchBuffer
[dwCurrentCharOffset
] = *pch
;
388 if ((m_blnInsetMode
)||(dwCurrentCharOffset
== dwLastCharOffset
)) dwLastCharOffset
++;
389 dwCurrentCharOffset
++;
390 if (!Write(pch
,1)) return FALSE
;
393 COORD Cursor
= m_CursorPosition
;
394 DWORD ofs
= dwCurrentCharOffset
;
396 while(ofs
<= dwLastCharOffset
)
398 ch
= m_pchBuffer
[ofs
];
399 m_pchBuffer
[ofs
] = ch1
;
404 if (dwCurrentCharOffset
< dwLastCharOffset
)
406 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
410 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
411 Cursor
.Y
= SHORT(Cursor
.Y
- m_LinesScrolled
);
413 // Update cursor position
414 m_CursorPosition
= Cursor
;
415 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
425 if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_LEFT
)
427 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
428 if (dwCurrentCharOffset
)
430 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
432 TCHAR
*pchWordBegin
= m_pchBuffer
+dwCurrentCharOffset
-1;
434 while (pchWordBegin
> m_pchBuffer
)
436 if (!_istspace(*pchWordBegin
)) break;
440 while (pchWordBegin
> m_pchBuffer
)
442 if (_istspace(*(pchWordBegin
-1))) break;
446 ASSERT(pchWordBegin
>= m_pchBuffer
);
447 dwCurrentCharOffset
= pchWordBegin
- m_pchBuffer
;
449 ASSERT(dwCurrentCharOffset
< dwLastCharOffset
);
451 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
452 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
453 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
457 dwCurrentCharOffset
--;
458 if (m_CursorPosition
.X
)
460 m_CursorPosition
.X
--;
464 m_CursorPosition
.X
= SHORT(m_BufferSize
.X
-1);
465 ASSERT(m_CursorPosition
.Y
);
466 m_CursorPosition
.Y
--;
468 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
472 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_RIGHT
)
474 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
475 if (dwCurrentCharOffset
< dwLastCharOffset
)
477 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
479 TCHAR
*pchWordBegin
= m_pchBuffer
+dwCurrentCharOffset
;
481 while ((DWORD
)(pchWordBegin
- m_pchBuffer
) < dwLastCharOffset
)
483 if (_istspace(*pchWordBegin
)) break;
487 while ((DWORD
)(pchWordBegin
- m_pchBuffer
) < dwLastCharOffset
)
489 if (!_istspace(*pchWordBegin
)) break;
493 dwCurrentCharOffset
= pchWordBegin
- m_pchBuffer
;
494 ASSERT(dwCurrentCharOffset
<= dwLastCharOffset
);
495 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
496 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCurrentCharOffset
);
497 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
501 dwCurrentCharOffset
++;
502 m_CursorPosition
.X
++;
503 if (m_CursorPosition
.X
== m_BufferSize
.X
)
505 m_CursorPosition
.Y
++;
506 m_CursorPosition
.X
= 0;
508 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
512 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_HOME
)
514 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
515 dwCurrentCharOffset
= 0;
516 m_CursorPosition
= FristCharCursorPosition
;
517 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
519 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_END
)
521 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
522 dwCurrentCharOffset
= dwLastCharOffset
;
523 m_CursorPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset
);
524 m_CursorPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwLastCharOffset
);
525 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
527 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_UP
)
529 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
531 const TCHAR
*pchHistoryLine
= m_History
.GetHistoryLine(dwHistoryIndex
-1);
534 if (dwLastCharOffset
)
536 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
537 m_CursorPosition
= FristCharCursorPosition
;
538 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
539 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
540 dwCurrentCharOffset
= dwLastCharOffset
= 0;
541 m_CursorPosition
= FristCharCursorPosition
;
542 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
544 dwCurrentCharOffset
= dwLastCharOffset
= _tcslen(pchHistoryLine
);
545 if (dwLastCharOffset
>= m_dwBufferSize
)
550 _tcscpy(m_pchBuffer
,pchHistoryLine
);
551 if (!Write(m_pchBuffer
)) return FALSE
;
558 else if (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DOWN
)
560 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
564 const TCHAR
*pchHistoryLine
= m_History
.GetHistoryLine(dwHistoryIndex
-1);
565 if (dwLastCharOffset
)
567 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
568 m_CursorPosition
= FristCharCursorPosition
;
569 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
570 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
571 dwCurrentCharOffset
= dwLastCharOffset
= 0;
572 m_CursorPosition
= FristCharCursorPosition
;
573 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
577 dwCurrentCharOffset
= dwLastCharOffset
= _tcslen(pchHistoryLine
);
578 if (dwLastCharOffset
>= m_dwBufferSize
)
583 _tcscpy(m_pchBuffer
,pchHistoryLine
);
584 if (!Write(m_pchBuffer
)) return FALSE
;
588 else if ((InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_DELETE
)&&
591 // Move the characters if any...
592 ASSERT(dwLastCharOffset
);
593 DWORD dwCharOffset
= dwCurrentCharOffset
;
594 if (dwCharOffset
< dwLastCharOffset
)
596 while(dwCharOffset
< dwLastCharOffset
)
598 m_pchBuffer
[dwCharOffset
] = m_pchBuffer
[dwCharOffset
+1];
602 m_pchBuffer
[dwLastCharOffset
-1] = _T(' ');
604 // Save cursor position
605 COORD Cursor
= m_CursorPosition
;
607 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
611 // Update cursor position
612 m_CursorPosition
= Cursor
;
613 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
617 // else if ((InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_PAUSE)&&
618 // (InputRecord.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)))
620 // if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0)) return FALSE;
623 else if ((ch
== 27) && dwLastCharOffset
&&
624 (InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
== VK_ESCAPE
))
626 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
627 _tcsnset(m_pchBuffer
,_T(' '),dwLastCharOffset
);
628 m_CursorPosition
= FristCharCursorPosition
;
629 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
630 VERIFY(Write(m_pchBuffer
,dwLastCharOffset
));
631 dwCurrentCharOffset
= dwLastCharOffset
= 0;
632 m_CursorPosition
= FristCharCursorPosition
;
633 VERIFY(SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
));
635 else if (ch
== _T('\r'))
637 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
= FristCharCursorPosition
)) return FALSE
;
638 ASSERT(dwLastCharOffset
<= m_dwBufferSize
);
639 m_pchBuffer
[dwLastCharOffset
] = 0; // terminate string in buffer
640 ret
= Write(m_pchBuffer
);
641 m_History
.AddHistoryLine(m_pchBuffer
);
642 static TCHAR strLF
[] = _T("\n");
646 else if (ch
== _T('\b'))
648 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
649 if ((dwCurrentCharOffset
) && ((m_CursorPosition
.X
!= 0) || (m_CursorPosition
.Y
!= 0)))
651 // Calculate new cursor position
652 COORD NewCursorPosition
;
653 if (m_CursorPosition
.X
)
655 NewCursorPosition
.X
= SHORT(m_CursorPosition
.X
-1);
656 NewCursorPosition
.Y
= m_CursorPosition
.Y
;
660 ASSERT(m_BufferSize
.X
);
661 NewCursorPosition
.X
= SHORT(m_BufferSize
.X
-1);
662 ASSERT(m_CursorPosition
.Y
);
663 NewCursorPosition
.Y
= SHORT(m_CursorPosition
.Y
-1);
666 // Move the characters if any...
667 ASSERT(dwLastCharOffset
);
668 DWORD dwCharOffset
= dwCurrentCharOffset
-1;
669 while(dwCharOffset
< dwLastCharOffset
-1)
671 m_pchBuffer
[dwCharOffset
] = m_pchBuffer
[dwCharOffset
+1];
675 m_pchBuffer
[dwLastCharOffset
-1] = _T(' ');
677 dwCurrentCharOffset
--;
678 m_CursorPosition
= NewCursorPosition
;
679 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
681 // Update cursor position
682 m_CursorPosition
= NewCursorPosition
;
683 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
688 else if (ch
== _T('\t'))
691 if (!blnCompletionMode
) // If tab was pressed after non-tab. We enter in completion mode.
693 // Initialize completion index
694 if (InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
) // If shift was pressed
695 nCompletionIndex
= (unsigned long long) -1; // Last completion
697 nCompletionIndex
= 0; // First completion
699 // Find completion offset. It points at char after first non-quoted whitespace.
700 dwCompletionOffset
= dwCurrentCharOffset
;
701 BOOL blnQuotedParameter
= FALSE
;
702 while(dwCompletionOffset
)
704 dwCompletionOffset
--;
705 if (m_pchBuffer
[dwCompletionOffset
] == _T('\"'))
707 blnQuotedParameter
= !blnQuotedParameter
;
709 else if (!blnQuotedParameter
&& _istspace(m_pchBuffer
[dwCompletionOffset
]))
710 { // Found ! We are not inside quored parameter and we are on whitespace.
711 dwCompletionOffset
++; // dwCompletionOffset must point at char AFTER first non-quoted whitespace.
716 ASSERT(dwCompletionOffset
<= dwCurrentCharOffset
);
718 // Save not changing part (context) of completion in m_pchBuffer1
719 _tcsncpy(m_pchBuffer1
,m_pchBuffer
,dwCompletionOffset
);
720 m_pchBuffer1
[dwCompletionOffset
] = 0;
722 // Size of changing part
723 dwCompletionStringSize
= dwCurrentCharOffset
-dwCompletionOffset
;
725 // Save intial changing part of completion in m_pchBuffer2
726 if (dwCompletionStringSize
)
727 _tcsncpy(m_pchBuffer2
,m_pchBuffer
+dwCompletionOffset
,dwCompletionStringSize
);
728 m_pchBuffer2
[dwCompletionStringSize
] = 0;
730 // Calculate cursor position of point between changing and not changing ports
731 CompletionPosition
.X
= X_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset
);
732 CompletionPosition
.Y
= Y_CURSOR_POSITION_FROM_OFFSET(dwCompletionOffset
);
733 } // if first time tab
735 const TCHAR
*pchCompletion
= NULL
;
738 BOOL blnForward
= !(InputRecord
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
);
740 if (m_pfReplaceCompletionCallback
) // If we are using replace completion callback
741 pchCompletion
= m_pfReplaceCompletionCallback(nCompletionIndex
,
742 blnCompletionMode
?&blnForward
:NULL
, // If this is first time we call the completion callback, do not change completion index
743 m_pchBuffer1
,m_pchBuffer2
);
745 if (pchCompletion
) // If completion found
747 // Set cursor position to compeltion position
748 m_CursorPosition
= CompletionPosition
;
749 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
))
752 // Calculate buffer free space
753 ASSERT(m_dwBufferSize
> dwCompletionOffset
);
754 DWORD dwFree
= m_dwBufferSize
- dwCompletionOffset
- 1;
756 // Save old completion string size
757 DWORD dwOldCompletionStringSize
= dwCompletionStringSize
;
759 // Write completion string to buffer
760 dwCompletionStringSize
= _tcslen(pchCompletion
);
762 // If there is not enough space in buffer, so we truncate the completion
763 if (dwCompletionStringSize
> dwFree
)
764 dwCompletionStringSize
= dwFree
;
766 if (dwCompletionStringSize
)
768 // Copy competion into main buffer
769 _tcsncpy(m_pchBuffer
+dwCompletionOffset
,pchCompletion
,dwCompletionStringSize
);
771 // Write completion string to console
772 if (!Write(m_pchBuffer
+dwCompletionOffset
,dwCompletionStringSize
))
776 dwCurrentCharOffset
= dwLastCharOffset
= dwCompletionOffset
+ dwCompletionStringSize
;
778 ASSERT(dwLastCharOffset
< m_dwBufferSize
);
781 // Erase rest from previous completion string, if the new completion is shorter than old
782 if (dwOldCompletionStringSize
> dwCompletionStringSize
)
784 _tcsnset(m_pchBuffer
+dwCompletionOffset
+dwCompletionStringSize
,_T(' '),
785 dwOldCompletionStringSize
- dwCompletionStringSize
);
787 // Save cursor position
788 COORD pos
= m_CursorPosition
;
790 if (!Write(m_pchBuffer
+dwCompletionOffset
+dwCompletionStringSize
,
791 dwOldCompletionStringSize
- dwCompletionStringSize
))
794 // Set cursor position
795 m_CursorPosition
= pos
;
796 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
))
799 } // If completion found
801 // Ok, we are in completion mode
802 blnCompletionMode
= TRUE
;
804 else if (_istprint(ch
))
806 if (blnCompletionMode
) blnCompletionMode
= FALSE
;
807 if (dwLastCharOffset
>= m_dwBufferSize
-1)
809 ASSERT(dwLastCharOffset
== m_dwBufferSize
-1);
814 //if (m_blnInsetMode)
815 ch1
= m_pchBuffer
[dwCurrentCharOffset
];
816 m_pchBuffer
[dwCurrentCharOffset
] = ch
;
817 if ((m_blnInsetMode
)||(dwCurrentCharOffset
== dwLastCharOffset
)) dwLastCharOffset
++;
818 dwCurrentCharOffset
++;
819 if (!Write(&ch
,1)) return FALSE
;
822 COORD Cursor
= m_CursorPosition
;
823 DWORD ofs
= dwCurrentCharOffset
;
825 while(ofs
<= dwLastCharOffset
)
827 ch
= m_pchBuffer
[ofs
];
828 m_pchBuffer
[ofs
] = ch1
;
833 if (dwCurrentCharOffset
< dwLastCharOffset
)
835 if (!Write(m_pchBuffer
+dwCurrentCharOffset
,dwLastCharOffset
-dwCurrentCharOffset
)) return FALSE
;
839 if (m_LinesScrolled
> FristCharCursorPosition
.Y
) return FALSE
;
840 Cursor
.Y
= SHORT(Cursor
.Y
- m_LinesScrolled
);
842 // Update cursor position
843 m_CursorPosition
= Cursor
;
844 if (!SetConsoleCursorPosition(m_hStdOut
,m_CursorPosition
)) return FALSE
;
848 ASSERT(InputRecord
.Event
.KeyEvent
.wRepeatCount
);
849 if (!InputRecord
.Event
.KeyEvent
.wRepeatCount
) return FALSE
;
850 if (--InputRecord
.Event
.KeyEvent
.wRepeatCount
) goto KeyRepeat
;
852 m_blnMoreMode
= blnOldMoreMode
;
856 BOOL
CConsole::GetTextAttribute(WORD
& rwAttributes
)
858 rwAttributes
= m_wAttributes
;
863 // dwBufferSize - size in chars of the input line buffer
867 // pointer to the input buffer
868 TCHAR
* CConsole::Init(DWORD dwBufferSize
, DWORD dwMaxHistoryLines
)
870 if (m_hStdIn
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdIn
));
871 if (m_hStdOut
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdOut
));
873 m_hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
875 if (m_hStdIn
== INVALID_HANDLE_VALUE
)
877 // _ftprintf(stderr,_T("GetStdHandle(STD_INPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
881 m_hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
883 if (m_hStdOut
== INVALID_HANDLE_VALUE
)
885 // _ftprintf(stderr,_T("GetStdHandle(STD_OUTPUT_HANDLE) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
889 CONSOLE_SCREEN_BUFFER_INFO info
;
890 if (!GetConsoleScreenBufferInfo(m_hStdOut
,&info
))
892 // _ftprintf(stderr,_T("GetConsoleScreenBufferInfo(m_hStdOut,&info) failed. GetLastError return 0x%X\n"),(unsigned)GetLastError());
893 if (GetLastError() == 6) // redirected output
894 _ftprintf(stderr
,_T("Redirection is not supported.\n"));
898 m_wAttributes
= info
.wAttributes
;
900 if (!m_blnOldInputModeSaved
)
902 if (!GetConsoleMode(m_hStdIn
,&m_dwOldInputMode
))
904 if (GetLastError() == 6) // redirected input
905 _ftprintf(stderr
,_T("Redirection is not supported.\n"));
906 // _ftprintf(stderr,_T("GetConsoleMode(0x%X,&m_dwOldINputMode) failed. GetLastError() returns 0x%X\n"),(int)m_hStdIn,GetLastError());
910 m_blnOldInputModeSaved
= TRUE
;
913 // _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) ...\n"),(int)m_hStdOut);
914 if (!m_blnOldOutputModeSaved
)
916 if (!GetConsoleMode(m_hStdOut
,&m_dwOldOutputMode
))
918 // _ftprintf(stderr,_T("Calling GetConsoleMode(0x%X,&m_dwOldOutputMode) done.\n"),(int)m_hStdOut);
919 m_blnOldOutputModeSaved
= TRUE
;
922 // _ftprintf(stderr,_T("Calling SetConsoleMode(0x%X,0) ...\n"),(int)m_hStdIn);
923 if (!SetConsoleMode(m_hStdIn
,0))
925 if (!SetConsoleMode(m_hStdOut
,0))
928 m_CursorPosition
= info
.dwCursorPosition
;
929 m_BufferSize
= info
.dwSize
;
931 CONSOLE_CURSOR_INFO cci
;
933 cci
.dwSize
= m_blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
935 if (!SetConsoleCursorInfo(m_hStdOut
,&cci
)) goto Abort
;
937 m_dwBufferSize
= dwBufferSize
;
939 if (m_pchBuffer
) delete m_pchBuffer
;
942 if (m_pchBuffer1
) delete m_pchBuffer1
;
945 if (m_pchBuffer2
) delete m_pchBuffer2
;
948 m_pchBuffer
= new (std::nothrow
) TCHAR
[dwBufferSize
];
949 if (!m_pchBuffer
) goto Abort
;
950 m_pchBuffer
[dwBufferSize
-1] = 0;
952 m_pchBuffer1
= new (std::nothrow
) TCHAR
[dwBufferSize
];
953 if (!m_pchBuffer1
) goto Abort
;
954 m_pchBuffer1
[dwBufferSize
-1] = 0;
956 m_pchBuffer2
= new (std::nothrow
) TCHAR
[dwBufferSize
];
957 if (!m_pchBuffer2
) goto Abort
;
958 m_pchBuffer2
[dwBufferSize
-1] = 0;
960 if (dwMaxHistoryLines
)
962 if (!m_History
.Init(dwBufferSize
,dwMaxHistoryLines
)) goto Abort
;
968 if (m_hStdIn
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdIn
));
969 m_hStdIn
= INVALID_HANDLE_VALUE
;
971 if (m_hStdOut
!= INVALID_HANDLE_VALUE
) VERIFY(CloseHandle(m_hStdOut
));
972 m_hStdOut
= INVALID_HANDLE_VALUE
;
974 if (m_pchBuffer
) delete[] m_pchBuffer
;
977 if (m_pchBuffer1
) delete[] m_pchBuffer1
;
980 if (m_pchBuffer2
) delete[] m_pchBuffer2
;
988 BOOL
CConsole::WriteChar(TCHAR ch
)
991 ci
.Attributes
= m_wAttributes
;
993 ci
.Char
.UnicodeChar
= ch
;
995 ci
.Char
.AsciiChar
= ch
;
997 static COORD BufferSize
= {1,1};
998 static COORD BufferCoord
= {0,0};
1000 Dest
.Bottom
= Dest
.Top
= m_CursorPosition
.Y
;
1001 Dest
.Left
= Dest
.Right
= m_CursorPosition
.X
;
1002 return WriteConsoleOutput(m_hStdOut
,&ci
,BufferSize
,BufferCoord
,&Dest
);
1005 void CConsole::BeginScrollingOperation()
1010 BOOL
CConsole::WriteString(const TCHAR
*pchString
, COORD Position
)
1012 CHAR_INFO ciBuffer
[256];
1013 int nSize
= _tcslen(pchString
);
1014 if ((nSize
> 256)||(nSize
<= 0))
1021 BufferSize
.X
= (SHORT
)nSize
;
1023 static COORD BufferCoord
= {0,0};
1025 Dest
.Bottom
= Dest
.Top
= Position
.Y
;
1026 Dest
.Right
= SHORT((Dest
.Left
= Position
.X
) + nSize
- 1);
1030 ciBuffer
[nSize
].Attributes
= m_wAttributes
;
1032 ciBuffer
[nSize
].Char
.UnicodeChar
= pchString
[nSize
];
1034 ciBuffer
[nSize
].Char
.AsciiChar
= pchString
[nSize
];
1038 return WriteConsoleOutput(m_hStdOut
,ciBuffer
,BufferSize
,BufferCoord
,&Dest
);
1041 BOOL
CConsole::SetInsertMode(BOOL blnInsetMode
)
1043 if (m_hStdOut
== INVALID_HANDLE_VALUE
) return FALSE
;
1045 CONSOLE_CURSOR_INFO cci
;
1046 cci
.bVisible
= TRUE
;
1047 cci
.dwSize
= blnInsetMode
?m_dwInsertModeCursorHeight
:m_dwOverwriteModeCursorHeight
;
1049 BOOL ret
= SetConsoleCursorInfo(m_hStdOut
,&cci
);
1050 if (ret
) m_blnInsetMode
= blnInsetMode
;
1056 void CConsole::SetReplaceCompletionCallback(ReplaceCompletionCallback pfCallback
)
1058 m_pfReplaceCompletionCallback
= pfCallback
;
1062 void CConsole::DisableWrite()
1064 m_blnDisableWrite
= TRUE
;
1065 INPUT_RECORD InputRecord
;
1066 DWORD dwRecordsWriten
;
1067 InputRecord
.EventType
= KEY_EVENT
;
1068 InputRecord
.Event
.KeyEvent
.bKeyDown
= TRUE
;
1070 InputRecord
.Event
.KeyEvent
.uChar
.UnicodeChar
= L
' ';
1072 InputRecord
.Event
.KeyEvent
.uChar
.AsciiChar
= ' ';
1074 BOOL ret
= WriteConsoleInput(m_hStdIn
,&InputRecord
,1,&dwRecordsWriten
);
1078 void CConsole::EnableWrite()
1080 m_blnDisableWrite
= FALSE
;