Reactos
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
18extern PCSTR
19KdbGetHistoryEntry(
20 _Inout_ PLONG NextIndex,
21 _In_ BOOLEAN Next);
22#else
23PCSTR
24KdbGetHistoryEntry(
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 **/
50SIZE_T
51KdIoReadLine(
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 */