1 /* 2 * PROJECT: ReactOS KDBG Kernel Debugger Terminal Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Terminal line-editing (Prompt) interface 5 * COPYRIGHT: Copyright 2001-2004 David Welch <welch@cwcom.net> 6 * Copyright 2004-2005 Gregor Anich <blight@blight.eu.org> 7 * Copyright 2022-2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org> 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #include "kd.h" 14 #include "kdterminal.h" 15 16 /* In kdb.h only when KDBG defined */ 17 #ifdef KDBG 18 extern PCSTR 19 KdbGetHistoryEntry( 20 _Inout_ PLONG NextIndex, 21 _In_ BOOLEAN Next); 22 #else 23 PCSTR 24 KdbGetHistoryEntry( 25 _Inout_ PLONG NextIndex, 26 _In_ BOOLEAN Next) 27 { 28 /* Dummy function */ 29 return NULL; 30 } 31 #endif 32 33 34 /* FUNCTIONS *****************************************************************/ 35 36 /** 37 * @brief Reads a line of user input from the terminal. 38 * 39 * @param[out] Buffer 40 * Buffer where to store the input. Trailing newlines are removed. 41 * 42 * @param[in] Size 43 * Size of @p Buffer. 44 * 45 * @return 46 * Returns the number of characters stored, not counting the NULL terminator. 47 * 48 * @note Accepts only \n newlines, \r is ignored. 49 **/ 50 SIZE_T 51 KdIoReadLine( 52 _Out_ PCHAR Buffer, 53 _In_ SIZE_T Size) 54 { 55 PCHAR Orig = Buffer; 56 ULONG ScanCode = 0; 57 CHAR Key; 58 BOOLEAN EchoOn = !(KdbDebugState & KD_DEBUG_KDNOECHO); 59 LONG CmdHistIndex = -1; // Start at end of history. 60 61 /* Flush the input buffer */ 62 KdpFlushTerminalInput(); 63 64 /* Bail out if the buffer is zero-sized */ 65 if (Size == 0) 66 return 0; 67 68 for (;;) 69 { 70 Key = KdpReadTermKey(&ScanCode); 71 72 /* Check for return or newline */ 73 if ((Key == '\r') || (Key == '\n')) 74 { 75 *Buffer = ANSI_NULL; 76 KdIoPuts("\n"); 77 return (SIZE_T)(Buffer - Orig); 78 } 79 else if (Key == KEY_BS || Key == KEY_DEL) 80 { 81 /* Erase the last character */ 82 if (Buffer > Orig) 83 { 84 Buffer--; 85 *Buffer = ANSI_NULL; 86 87 if (EchoOn) 88 KdIoPrintf("%c %c", KEY_BS, KEY_BS); 89 else 90 KdIoPrintf(" %c", KEY_BS); 91 } 92 } 93 else if (ScanCode == KEY_SCAN_UP || ScanCode == KEY_SCAN_DOWN) 94 { 95 PCSTR CmdHistory = KdbGetHistoryEntry(&CmdHistIndex, 96 (ScanCode == KEY_SCAN_DOWN)); 97 if (CmdHistory) 98 { 99 SIZE_T i; 100 101 /* Erase the whole line */ 102 while (Buffer > Orig) 103 { 104 Buffer--; 105 *Buffer = ANSI_NULL; 106 107 if (EchoOn) 108 KdIoPrintf("%c %c", KEY_BS, KEY_BS); 109 else 110 KdIoPrintf(" %c", KEY_BS); 111 } 112 113 /* Copy and display the history entry */ 114 i = min(strlen(CmdHistory), Size - 1); 115 memcpy(Orig, CmdHistory, i); 116 Orig[i] = ANSI_NULL; 117 Buffer = Orig + i; 118 KdIoPuts(Orig); 119 } 120 } 121 else 122 { 123 /* Do not accept characters anymore if the buffer is full */ 124 if ((SIZE_T)(Buffer - Orig) >= (Size - 1)) 125 continue; 126 127 if (EchoOn) 128 KdIoPrintf("%c", Key); 129 130 *Buffer = Key; 131 Buffer++; 132 } 133 } 134 } 135 136 /* EOF */ 137