https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f3dd7133823a2985966059e52630e08ef4849cf5

commit f3dd7133823a2985966059e52630e08ef4849cf5
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Mon Mar 20 17:49:15 2023 +0100
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Tue Mar 28 16:14:40 2023 +0200

    [NTOS:KD:KDBG] Isolate the read-line (prompt) functionality in a separate 
file.
    
    Rename KdbpReadCommand as KdIoReadLine. Extract the last-command
    repetition functionality out of KdIoReadLine and put it where it
    belongs: only in the KDBG command main loop KdbpCliMainLoop.
---
 ntoskrnl/kd/kdio.c       |   5 +-
 ntoskrnl/kd/kdmain.c     |   1 +
 ntoskrnl/kd/kdprompt.c   | 166 +++++++++++++++++++++++++++++++++++++
 ntoskrnl/kd/kdserial.c   |   2 +
 ntoskrnl/kd/kdterminal.h |  29 +++++++
 ntoskrnl/kdbg/kdb.h      |   5 --
 ntoskrnl/kdbg/kdb_cli.c  | 209 ++++++-----------------------------------------
 ntoskrnl/ntos.cmake      |   1 +
 8 files changed, 226 insertions(+), 192 deletions(-)

diff --git a/ntoskrnl/kd/kdio.c b/ntoskrnl/kd/kdio.c
index f9e7b38abe1..a196b905113 100644
--- a/ntoskrnl/kd/kdio.c
+++ b/ntoskrnl/kd/kdio.c
@@ -12,6 +12,7 @@
 #include <ntoskrnl.h>
 #include <reactos/buildno.h>
 #include "kd.h"
+#include "kdterminal.h"
 
 #define NDEBUG
 #include <debug.h>
@@ -779,8 +780,8 @@ KdReceivePacket(
      * in which case the string is simply truncated without NULL-termination.
      */
     ResponseString.Length =
-        (USHORT)KdbpReadCommand(ResponseString.Buffer,
-                                ResponseString.MaximumLength);
+        (USHORT)KdIoReadLine(ResponseString.Buffer,
+                             ResponseString.MaximumLength);
 
     if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
         KbdEnableMouse();
diff --git a/ntoskrnl/kd/kdmain.c b/ntoskrnl/kd/kdmain.c
index de341bad204..aaed45432db 100644
--- a/ntoskrnl/kd/kdmain.c
+++ b/ntoskrnl/kd/kdmain.c
@@ -9,6 +9,7 @@
 
 #include <ntoskrnl.h>
 #include "kd.h"
+
 #define NDEBUG
 #include <debug.h>
 
diff --git a/ntoskrnl/kd/kdprompt.c b/ntoskrnl/kd/kdprompt.c
new file mode 100644
index 00000000000..f9ac04f6d03
--- /dev/null
+++ b/ntoskrnl/kd/kdprompt.c
@@ -0,0 +1,166 @@
+/*
+ * PROJECT:     ReactOS KDBG Kernel Debugger Terminal Driver
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     Terminal line-editing (Prompt) interface
+ * COPYRIGHT:   Copyright 2001-2004 David Welch <[email protected]>
+ *              Copyright 2004-2005 Gregor Anich <[email protected]>
+ *              Copyright 2022-2023 Hermès Bélusca-Maïto 
<[email protected]>
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#include "kdterminal.h"
+
+/* FUNCTIONS *****************************************************************/
+
+/**
+ * @brief   Reads a line of user input from the terminal.
+ *
+ * @param[out]  Buffer
+ * Buffer where to store the input. Trailing newlines are removed.
+ *
+ * @param[in]   Size
+ * Size of @p Buffer.
+ *
+ * @return
+ * Returns the number of characters stored, not counting the NULL terminator.
+ *
+ * @note Accepts only \n newlines, \r is ignored.
+ **/
+SIZE_T
+KdIoReadLine(
+    _Out_ PCHAR Buffer,
+    _In_ SIZE_T Size)
+{
+    PCHAR Orig = Buffer;
+    ULONG ScanCode = 0;
+    CHAR Key;
+    static CHAR NextKey = ANSI_NULL;
+    BOOLEAN EchoOn;
+    LONG CmdHistIndex = -1; // Start at end of history.
+
+    /* Bail out if the buffer is zero-sized */
+    if (Size == 0)
+        return 0;
+
+    EchoOn = ((KdbDebugState & KD_DEBUG_KDNOECHO) == 0);
+
+    for (;;)
+    {
+        ScanCode = 0;
+        if (KdbDebugState & KD_DEBUG_KDSERIAL)
+        {
+            Key = (!NextKey ? KdbpGetCharSerial() : NextKey);
+            NextKey = ANSI_NULL;
+            if (Key == KEY_ESC) /* ESC */
+            {
+                Key = KdbpGetCharSerial();
+                if (Key == '[')
+                {
+                    Key = KdbpGetCharSerial();
+
+                    switch (Key)
+                    {
+                        case 'A':
+                            ScanCode = KEY_SCAN_UP;
+                            break;
+                        case 'B':
+                            ScanCode = KEY_SCAN_DOWN;
+                            break;
+                        case 'C':
+                            break;
+                        case 'D':
+                            break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            Key = (!NextKey ? KdbpGetCharKeyboard(&ScanCode) : NextKey);
+            NextKey = ANSI_NULL;
+        }
+
+        /* Check for return or newline */
+        if ((Key == '\r') || (Key == '\n'))
+        {
+            if (Key == '\r')
+            {
+                /*
+                 * We might need to discard the next '\n' which most clients
+                 * should send after \r. Wait a bit to make sure we receive it.
+                 */
+                KeStallExecutionProcessor(100000);
+
+                if (KdbDebugState & KD_DEBUG_KDSERIAL)
+                    NextKey = KdbpTryGetCharSerial(5);
+                else
+                    NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5);
+
+                if (NextKey == '\n' || NextKey == -1) /* \n or no response at 
all */
+                    NextKey = ANSI_NULL;
+            }
+
+            *Buffer = ANSI_NULL;
+            KdIoPuts("\n");
+            return (SIZE_T)(Buffer - Orig);
+        }
+        else if (Key == KEY_BS || Key == KEY_DEL)
+        {
+            /* Erase the last character */
+            if (Buffer > Orig)
+            {
+                Buffer--;
+                *Buffer = ANSI_NULL;
+
+                if (EchoOn)
+                    KdIoPrintf("%c %c", KEY_BS, KEY_BS);
+                else
+                    KdIoPrintf(" %c", KEY_BS);
+            }
+        }
+        else if (ScanCode == KEY_SCAN_UP || ScanCode == KEY_SCAN_DOWN)
+        {
+            PCSTR CmdHistory = KdbGetHistoryEntry(&CmdHistIndex,
+                                                  (ScanCode == KEY_SCAN_DOWN));
+            if (CmdHistory)
+            {
+                SIZE_T i;
+
+                /* Erase the whole line */
+                while (Buffer > Orig)
+                {
+                    Buffer--;
+                    *Buffer = ANSI_NULL;
+
+                    if (EchoOn)
+                        KdIoPrintf("%c %c", KEY_BS, KEY_BS);
+                    else
+                        KdIoPrintf(" %c", KEY_BS);
+                }
+
+                /* Copy and display the history entry */
+                i = min(strlen(CmdHistory), Size - 1);
+                memcpy(Orig, CmdHistory, i);
+                Orig[i] = ANSI_NULL;
+                Buffer = Orig + i;
+                KdIoPuts(Orig);
+            }
+        }
+        else
+        {
+            /* Do not accept characters anymore if the buffer is full */
+            if ((SIZE_T)(Buffer - Orig) >= (Size - 1))
+                continue;
+
+            if (EchoOn)
+                KdIoPrintf("%c", Key);
+
+            *Buffer = Key;
+            Buffer++;
+        }
+    }
+}
+
+/* EOF */
diff --git a/ntoskrnl/kd/kdserial.c b/ntoskrnl/kd/kdserial.c
index d36b7abe559..d854d92aca2 100644
--- a/ntoskrnl/kd/kdserial.c
+++ b/ntoskrnl/kd/kdserial.c
@@ -34,3 +34,5 @@ KdbpTryGetCharSerial(
 
     return Result;
 }
+
+/* EOF */
diff --git a/ntoskrnl/kd/kdterminal.h b/ntoskrnl/kd/kdterminal.h
new file mode 100644
index 00000000000..d5aab3fe48c
--- /dev/null
+++ b/ntoskrnl/kd/kdterminal.h
@@ -0,0 +1,29 @@
+/*
+ * PROJECT:     ReactOS KDBG Kernel Debugger Terminal Driver
+ * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE:     KD Terminal Driver public header
+ * COPYRIGHT:   Copyright 2023 Hermès Bélusca-Maïto 
<[email protected]>
+ */
+
+#pragma once
+
+#define KEY_BS          8
+#define KEY_ESC         27
+#define KEY_DEL         127
+
+#define KEY_SCAN_UP     72
+#define KEY_SCAN_DOWN   80
+
+/* Scan codes of keyboard keys */
+#define KEYSC_END       0x004f
+#define KEYSC_PAGEUP    0x0049
+#define KEYSC_PAGEDOWN  0x0051
+#define KEYSC_HOME      0x0047
+#define KEYSC_ARROWUP   0x0048  // == KEY_SCAN_UP
+
+SIZE_T
+KdIoReadLine(
+    _Out_ PCHAR Buffer,
+    _In_ SIZE_T Size);
+
+/* EOF */
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h
index bf8a47e5ec1..26c79577030 100644
--- a/ntoskrnl/kdbg/kdb.h
+++ b/ntoskrnl/kdbg/kdb.h
@@ -113,11 +113,6 @@ KdbGetHistoryEntry(
     _Inout_ PLONG NextIndex,
     _In_ BOOLEAN Next);
 
-SIZE_T
-KdbpReadCommand(
-    _Out_ PCHAR Buffer,
-    _In_ SIZE_T Size);
-
 VOID
 KdbpPager(
     _In_ PCHAR Buffer,
diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c
index ad28412fd91..f909fecdfc7 100644
--- a/ntoskrnl/kdbg/kdb_cli.c
+++ b/ntoskrnl/kdbg/kdb_cli.c
@@ -29,26 +29,13 @@
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
+#include "../kd/kdterminal.h"
 
 #define NDEBUG
 #include <debug.h>
 
 /* DEFINES *******************************************************************/
 
-#define KEY_BS          8
-#define KEY_ESC         27
-#define KEY_DEL         127
-
-#define KEY_SCAN_UP     72
-#define KEY_SCAN_DOWN   80
-
-/* Scan codes of keyboard keys: */
-#define KEYSC_END       0x004f
-#define KEYSC_PAGEUP    0x0049
-#define KEYSC_PAGEDOWN  0x0051
-#define KEYSC_HOME      0x0047
-#define KEYSC_ARROWUP   0x0048
-
 #define KDB_ENTER_CONDITION_TO_STRING(cond)                               \
                    ((cond) == KdbDoNotEnter ? "never" :                   \
                    ((cond) == KdbEnterAlways ? "always" :                 \
@@ -3253,172 +3240,6 @@ KdbpPrintUnicodeString(
 }
 
 
-/**
- * @brief   Reads a line of user input from the terminal.
- *
- * @param[out]  Buffer
- * Buffer where to store the input. Trailing newlines are removed.
- *
- * @param[in]   Size
- * Size of \a Buffer.
- *
- * @return
- * Returns the number of characters stored, not counting the NULL terminator.
- *
- * @note Accepts only \n newlines, \r is ignored.
- **/
-SIZE_T
-KdbpReadCommand(
-    _Out_ PCHAR Buffer,
-    _In_ SIZE_T Size)
-{
-    PCHAR Orig = Buffer;
-    ULONG ScanCode = 0;
-    CHAR Key;
-    BOOLEAN EchoOn;
-    static CHAR LastCommand[1024];
-    static CHAR NextKey = '\0';
-    LONG CmdHistIndex = -1; // Start at end of history.
-
-    /* Bail out if the buffer is zero-sized */
-    if (Size == 0)
-        return 0;
-
-    EchoOn = ((KdbDebugState & KD_DEBUG_KDNOECHO) == 0);
-
-    for (;;)
-    {
-        if (KdbDebugState & KD_DEBUG_KDSERIAL)
-        {
-            Key = (NextKey == '\0') ? KdbpGetCharSerial() : NextKey;
-            NextKey = '\0';
-            ScanCode = 0;
-            if (Key == KEY_ESC) /* ESC */
-            {
-                Key = KdbpGetCharSerial();
-                if (Key == '[')
-                {
-                    Key = KdbpGetCharSerial();
-
-                    switch (Key)
-                    {
-                        case 'A':
-                            ScanCode = KEY_SCAN_UP;
-                            break;
-                        case 'B':
-                            ScanCode = KEY_SCAN_DOWN;
-                            break;
-                        case 'C':
-                            break;
-                        case 'D':
-                            break;
-                    }
-                }
-            }
-        }
-        else
-        {
-            ScanCode = 0;
-            Key = (NextKey == '\0') ? KdbpGetCharKeyboard(&ScanCode) : NextKey;
-            NextKey = '\0';
-        }
-
-        /* Check for return or newline */
-        if ((Key == '\r') || (Key == '\n'))
-        {
-            if (Key == '\r')
-            {
-                /*
-                 * We might need to discard the next '\n' which most clients
-                 * should send after \r. Wait a bit to make sure we receive it.
-                 */
-                KeStallExecutionProcessor(100000);
-
-                if (KdbDebugState & KD_DEBUG_KDSERIAL)
-                    NextKey = KdbpTryGetCharSerial(5);
-                else
-                    NextKey = KdbpTryGetCharKeyboard(&ScanCode, 5);
-
-                if (NextKey == '\n' || NextKey == -1) /* \n or no response at 
all */
-                    NextKey = '\0';
-            }
-
-            KdpDprintf("\n");
-
-            /*
-             * Repeat the last command if the user presses enter. Reduces the
-             * risk of RSI when single-stepping.
-             */
-            if (Buffer != Orig)
-            {
-                KdbRepeatLastCommand = TRUE;
-                *Buffer = '\0';
-                RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Orig);
-            }
-            else if (KdbRepeatLastCommand)
-                RtlStringCbCopyA(Buffer, Size, LastCommand);
-            else
-                *Buffer = '\0';
-
-            return (SIZE_T)(Buffer - Orig);
-        }
-        else if (Key == KEY_BS || Key == KEY_DEL)
-        {
-            /* Erase the last character */
-            if (Buffer > Orig)
-            {
-                Buffer--;
-                *Buffer = '\0';
-
-                if (EchoOn)
-                    KdpDprintf("%c %c", KEY_BS, KEY_BS);
-                else
-                    KdpDprintf(" %c", KEY_BS);
-            }
-        }
-        else if (ScanCode == KEY_SCAN_UP || ScanCode == KEY_SCAN_DOWN)
-        {
-            PCSTR CmdHistory = KdbGetHistoryEntry(&CmdHistIndex,
-                                                  (ScanCode == KEY_SCAN_DOWN));
-            if (CmdHistory)
-            {
-                SIZE_T i;
-
-                /* Erase the whole line */
-                while (Buffer > Orig)
-                {
-                    Buffer--;
-                    *Buffer = '\0';
-
-                    if (EchoOn)
-                        KdpDprintf("%c %c", KEY_BS, KEY_BS);
-                    else
-                        KdpDprintf(" %c", KEY_BS);
-                }
-
-                i = min(strlen(CmdHistory), Size - 1);
-                memcpy(Orig, CmdHistory, i);
-                Orig[i] = '\0';
-                Buffer = Orig + i;
-                KdpDprintf("%s", Orig);
-            }
-        }
-        else
-        {
-            /* Don't accept any key if the buffer is full */
-            if ((SIZE_T)(Buffer - Orig) >= (Size - 1))
-                continue;
-
-            if (EchoOn)
-                KdpDprintf("%c", Key);
-
-            *Buffer = Key;
-            Buffer++;
-        }
-    }
-}
-
-
 BOOLEAN
 NTAPI
 KdbRegisterCliCallback(
@@ -3567,8 +3388,10 @@ VOID
 KdbpCliMainLoop(
     IN BOOLEAN EnteredOnSingleStep)
 {
-    static CHAR Command[1024];
     BOOLEAN Continue;
+    SIZE_T CmdLen;
+    static CHAR Command[1024];
+    static CHAR LastCommand[1024] = "";
 
     if (EnteredOnSingleStep)
     {
@@ -3603,11 +3426,27 @@ KdbpCliMainLoop(
         KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;
 
         /* Print the prompt */
-        KdbpPrint(KdbPromptString.Buffer);
+        KdpDprintf(KdbPromptString.Buffer);
+
+        /*
+         * Read a command. Repeat the last one if the user pressed Enter.
+         * This reduces the risk of RSI when single-stepping!
+         */
+        CmdLen = KdIoReadLine(Command, sizeof(Command));
+        if (CmdLen > 0) // i.e. (*Command != ANSI_NULL)
+        {
+            /* Save this new last command */
+            KdbRepeatLastCommand = TRUE;
+            RtlStringCbCopyA(LastCommand, sizeof(LastCommand), Command);
 
-        /* Read a command and remember it */
-        KdbpReadCommand(Command, sizeof(Command));
-        KdbpCommandHistoryAppend(Command);
+            /* Remember it */
+            KdbpCommandHistoryAppend(Command);
+        }
+        else if (KdbRepeatLastCommand)
+        {
+            /* The user directly pressed Enter */
+            RtlStringCbCopyA(Command, sizeof(Command), LastCommand);
+        }
 
         /* Reset the number of rows/cols printed and output aborted state */
         KdbNumberOfRowsPrinted = KdbNumberOfColsPrinted = 0;
diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake
index 648de8faf6b..8df4eacccc3 100644
--- a/ntoskrnl/ntos.cmake
+++ b/ntoskrnl/ntos.cmake
@@ -413,6 +413,7 @@ if(NOT _WINKD_)
     list(APPEND SOURCE
         ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdio.c
         ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdmain.c
+        ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdprompt.c
         ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdps2kbd.c
         ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c)
 

Reply via email to