xref: /reactos/ntoskrnl/kd/kdprompt.c (revision cf4bb8fc)
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