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

commit 35180b3ad23e5ac357b7e7c7495d29cf13f7bd74
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Wed Mar 29 02:06:35 2023 +0200
Commit:     Hermès Bélusca-Maïto <[email protected]>
CommitDate: Wed Mar 29 02:42:31 2023 +0200

    [NTOS:KDBG] Isolate terminal and input-related routines from the rest of 
KDBG. (#5188)
    
    This is done in preparation for moving all this functionality in a
    separate KDTERM "KD Terminal Driver" DLL.
    
    Additionally:
    
    - Flush the terminal input before sending ANSI escape sequences.
    
    - In KDBG pager, always use the correct reading-key function (the
      same used also for reading keys for a line of user input), and not
      the simplistic two-call KdbpGetCharSerial + KdbpTryGetCharSerial
      that would split the \r \n across calls.
    
    - Call KdbpGetCommandLineSettings() in KdbInitialize() at BootPhase 0,
      which is indirectly called by KdDebuggerInitialize0(). And fix its
      command-line parsing too.
---
 ntoskrnl/kd/kd.h         |   5 +
 ntoskrnl/kd/kdmain.c     |  36 ++++++-
 ntoskrnl/kd/kdprompt.c   |  59 +---------
 ntoskrnl/kd/kdterminal.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++
 ntoskrnl/kd/kdterminal.h |  39 ++++++-
 ntoskrnl/kdbg/kdb.c      |  24 ++---
 ntoskrnl/kdbg/kdb.h      |  24 +----
 ntoskrnl/kdbg/kdb_cli.c  | 207 ++++++++---------------------------
 ntoskrnl/ntos.cmake      |   3 +-
 9 files changed, 407 insertions(+), 266 deletions(-)

diff --git a/ntoskrnl/kd/kd.h b/ntoskrnl/kd/kd.h
index 4440b183626..0e10f0c90b0 100644
--- a/ntoskrnl/kd/kd.h
+++ b/ntoskrnl/kd/kd.h
@@ -26,6 +26,11 @@ KdIoPrintf(
     _In_ PCSTR Format,
     ...);
 
+SIZE_T
+KdIoReadLine(
+    _Out_ PCHAR Buffer,
+    _In_ SIZE_T Size);
+
 
 /* INIT ROUTINES *************************************************************/
 
diff --git a/ntoskrnl/kd/kdmain.c b/ntoskrnl/kd/kdmain.c
index aaed45432db..8120ab52e5d 100644
--- a/ntoskrnl/kd/kdmain.c
+++ b/ntoskrnl/kd/kdmain.c
@@ -9,14 +9,42 @@
 
 #include <ntoskrnl.h>
 #include "kd.h"
+#include "kdterminal.h"
 
 #define NDEBUG
 #include <debug.h>
 
 /* PUBLIC FUNCTIONS *********************************************************/
 
+static VOID
+KdpGetTerminalSettings(
+    _In_ PCSTR p1)
+{
+#define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
+
+    while (p1 && *p1)
+    {
+        /* Skip leading whitespace */
+        while (*p1 == ' ') ++p1;
+
+        if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
+        {
+            p1 += CONST_STR_LEN("KDSERIAL");
+            KdbDebugState |= KD_DEBUG_KDSERIAL;
+            KdpDebugMode.Serial = TRUE;
+        }
+        else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
+        {
+            p1 += CONST_STR_LEN("KDNOECHO");
+            KdbDebugState |= KD_DEBUG_KDNOECHO;
+        }
+
+        /* Move on to the next option */
+        p1 = strchr(p1, ' ');
+    }
+}
+
 static PCHAR
-NTAPI
 KdpGetDebugMode(
     _In_ PCHAR Currentp2)
 {
@@ -95,10 +123,8 @@ KdDebuggerInitialize0(
             /* Upcase it */
             _strupr(CommandLine);
 
-#ifdef KDBG
-            /* Get the KDBG Settings */
-            KdbpGetCommandLineSettings(CommandLine);
-#endif
+            /* Get terminal settings */
+            KdpGetTerminalSettings(CommandLine);
 
             /* Get the port */
             Port = strstr(CommandLine, "DEBUGPORT");
diff --git a/ntoskrnl/kd/kdprompt.c b/ntoskrnl/kd/kdprompt.c
index f9ac04f6d03..8c93eb413de 100644
--- a/ntoskrnl/kd/kdprompt.c
+++ b/ntoskrnl/kd/kdprompt.c
@@ -36,72 +36,23 @@ KdIoReadLine(
     PCHAR Orig = Buffer;
     ULONG ScanCode = 0;
     CHAR Key;
-    static CHAR NextKey = ANSI_NULL;
-    BOOLEAN EchoOn;
+    BOOLEAN EchoOn = !(KdbDebugState & KD_DEBUG_KDNOECHO);
     LONG CmdHistIndex = -1; // Start at end of history.
 
+    /* Flush the input buffer */
+    KdpFlushTerminalInput();
+
     /* 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;
-        }
+        Key = KdpReadTermKey(&ScanCode);
 
         /* 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);
diff --git a/ntoskrnl/kd/kdterminal.c b/ntoskrnl/kd/kdterminal.c
new file mode 100644
index 00000000000..00888230f1e
--- /dev/null
+++ b/ntoskrnl/kd/kdterminal.c
@@ -0,0 +1,276 @@
+/*
+ * 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 Management
+ * COPYRIGHT:   Copyright 2005 Gregor Anich <[email protected]>
+ *              Copyright 2022-2023 Hermès Bélusca-Maïto 
<[email protected]>
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#include "kdterminal.h"
+
+#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
+CHAR
+KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
+
+#define KdbpGetCharSerial()  KdbpTryGetCharSerial(0)
+CHAR
+KdbpTryGetCharSerial(
+    _In_ ULONG Retry);
+
+VOID
+KdbpSendCommandSerial(
+    _In_ PCSTR Command);
+
+
+/* GLOBALS *******************************************************************/
+
+/* KD Controlling Terminal */
+ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
+SIZE KdTermSize = {0,0};
+BOOLEAN KdTermConnected = FALSE;
+BOOLEAN KdTermSerial = FALSE;
+BOOLEAN KdTermReportsSize = TRUE;
+
+static CHAR KdTermNextKey = ANSI_NULL; /* 1-character input queue buffer */
+
+
+/* FUNCTIONS *****************************************************************/
+
+/**
+ * @brief   Initializes the controlling terminal.
+ *
+ * @return
+ * TRUE if the controlling terminal is serial and detected
+ * as being connected, or FALSE if not.
+ **/
+BOOLEAN
+KdpInitTerminal(VOID)
+{
+    /* Determine whether the controlling terminal is a serial terminal:
+     * serial output is enabled *and* KDSERIAL is set (i.e. user input
+     * through serial). */
+    KdTermSerial =
+#if 0
+    // Old logic where KDSERIAL also enables serial output.
+    (KdbDebugState & KD_DEBUG_KDSERIAL) ||
+    (KdpDebugMode.Serial && !KdpDebugMode.Screen);
+#else
+    // New logic where KDSERIAL does not necessarily enable serial output.
+    KdpDebugMode.Serial &&
+    ((KdbDebugState & KD_DEBUG_KDSERIAL) || !KdpDebugMode.Screen);
+#endif
+
+    /* Flush the input buffer */
+    KdpFlushTerminalInput();
+
+    if (KdTermSerial)
+    {
+        ULONG Length;
+
+        /* Enable line-wrap */
+        KdbpSendCommandSerial("\x1b[?7h");
+
+        /*
+         * Query terminal type.
+         * Historically it was done with CTRL-E ('\x05'), however nowadays
+         * terminals respond to it with an empty (or a user-configurable)
+         * string. Instead, use the VT52-compatible 'ESC Z' sequence or the
+         * VT100-compatible 'ESC[c' one.
+         */
+        KdbpSendCommandSerial("\x1b[c");
+        KeStallExecutionProcessor(100000);
+
+        Length = 0;
+        for (;;)
+        {
+            /* Verify we get an answer, but don't care about it */
+            if (KdbpTryGetCharSerial(5000) == -1)
+                break;
+            ++Length;
+        }
+
+        /* Terminal is connected (TRUE) or not connected (FALSE) */
+        KdTermConnected = (Length > 0);
+    }
+    else
+    {
+        /* Terminal is not serial, assume it's *not* connected */
+        KdTermConnected = FALSE;
+    }
+    return KdTermConnected;
+}
+
+BOOLEAN
+KdpUpdateTerminalSize(
+    _Out_ PSIZE TermSize)
+{
+    static CHAR Buffer[128];
+    CHAR c;
+    LONG NumberOfCols = -1; // Or initialize to TermSize->cx ??
+    LONG NumberOfRows = -1; // Or initialize to TermSize->cy ??
+
+    /* Retrieve the size of the controlling terminal only when it is serial */
+    if (KdTermConnected && KdTermSerial && KdTermReportsSize)
+    {
+        /* Flush the input buffer */
+        KdpFlushTerminalInput();
+
+        /* Try to query the terminal size. A reply looks like "\x1b[8;24;80t" 
*/
+        KdTermReportsSize = FALSE;
+        KdbpSendCommandSerial("\x1b[18t");
+        KeStallExecutionProcessor(100000);
+
+        c = KdbpTryGetCharSerial(5000);
+        if (c == KEY_ESC)
+        {
+            c = KdbpTryGetCharSerial(5000);
+            if (c == '[')
+            {
+                ULONG Length = 0;
+                for (;;)
+                {
+                    c = KdbpTryGetCharSerial(5000);
+                    if (c == -1)
+                        break;
+
+                    Buffer[Length++] = c;
+                    if (isalpha(c) || Length >= (sizeof(Buffer) - 1))
+                        break;
+                }
+                Buffer[Length] = ANSI_NULL;
+
+                if (Buffer[0] == '8' && Buffer[1] == ';')
+                {
+                    SIZE_T i;
+                    for (i = 2; (i < Length) && (Buffer[i] != ';'); i++);
+
+                    if (Buffer[i] == ';')
+                    {
+                        Buffer[i++] = ANSI_NULL;
+
+                        /* Number of rows is now at Buffer + 2
+                         * and number of columns at Buffer + i */
+                        NumberOfRows = strtoul(Buffer + 2, NULL, 0);
+                        NumberOfCols = strtoul(Buffer + i, NULL, 0);
+                        KdTermReportsSize = TRUE;
+                    }
+                }
+            }
+            /* Clear further characters */
+            while (KdbpTryGetCharSerial(5000) != -1);
+        }
+    }
+
+    if (NumberOfCols <= 0)
+    {
+        /* Set the number of columns to the default */
+        if (KdpDebugMode.Screen && !KdTermSerial)
+            NumberOfCols = (SCREEN_WIDTH / 8 /*BOOTCHAR_WIDTH*/);
+        else
+            NumberOfCols = 80;
+    }
+    if (NumberOfRows <= 0)
+    {
+        /* Set the number of rows to the default */
+        if (KdpDebugMode.Screen && !KdTermSerial)
+            NumberOfRows = (SCREEN_HEIGHT / (13 /*BOOTCHAR_HEIGHT*/ + 1));
+        else
+            NumberOfRows = 24;
+    }
+
+    TermSize->cx = NumberOfCols;
+    TermSize->cy = NumberOfRows;
+
+    // KdIoPrintf("Cols/Rows: %dx%d\n", TermSize->cx, TermSize->cy);
+
+    return KdTermReportsSize;
+}
+
+/**
+ * @brief   Flushes terminal input (either serial or PS/2).
+ **/
+VOID
+KdpFlushTerminalInput(VOID)
+{
+    KdTermNextKey = ANSI_NULL;
+    if (KdbDebugState & KD_DEBUG_KDSERIAL)
+    {
+        while (KdbpTryGetCharSerial(1) != -1);
+    }
+    else
+    {
+        ULONG ScanCode;
+        while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
+    }
+}
+
+/**
+ * @brief
+ * Reads one character from the terminal. This function returns
+ * a scan code even when reading is done from a serial terminal.
+ **/
+CHAR
+KdpReadTermKey(
+    _Out_ PULONG ScanCode)
+{
+    CHAR Key;
+
+    *ScanCode = 0;
+
+    if (KdbDebugState & KD_DEBUG_KDSERIAL)
+    {
+        Key = (!KdTermNextKey ? KdbpGetCharSerial() : KdTermNextKey);
+        KdTermNextKey = 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 = (!KdTermNextKey ? KdbpGetCharKeyboard(ScanCode) : KdTermNextKey);
+        KdTermNextKey = ANSI_NULL;
+    }
+
+    /* Check for return */
+    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)
+            KdTermNextKey = KdbpTryGetCharSerial(5);
+        else
+            KdTermNextKey = KdbpTryGetCharKeyboard(ScanCode, 5);
+
+        if (KdTermNextKey == '\n' || KdTermNextKey == -1) /* \n or no response 
at all */
+            KdTermNextKey = ANSI_NULL;
+    }
+
+    return Key;
+}
+
+/* EOF */
diff --git a/ntoskrnl/kd/kdterminal.h b/ntoskrnl/kd/kdterminal.h
index d5aab3fe48c..d930ff7ae98 100644
--- a/ntoskrnl/kd/kdterminal.h
+++ b/ntoskrnl/kd/kdterminal.h
@@ -21,9 +21,40 @@
 #define KEYSC_HOME      0x0047
 #define KEYSC_ARROWUP   0x0048  // == KEY_SCAN_UP
 
-SIZE_T
-KdIoReadLine(
-    _Out_ PCHAR Buffer,
-    _In_ SIZE_T Size);
+
+typedef struct _SIZE
+{
+    LONG cx;
+    LONG cy;
+} SIZE, *PSIZE;
+
+/* KD Controlling Terminal */
+
+/* These values MUST be nonzero, they're used as bit masks */
+typedef enum _KDB_OUTPUT_SETTINGS
+{
+    KD_DEBUG_KDSERIAL = 1,
+    KD_DEBUG_KDNOECHO = 2
+} KDB_OUTPUT_SETTINGS;
+
+extern ULONG KdbDebugState;
+extern SIZE KdTermSize;
+extern BOOLEAN KdTermConnected;
+extern BOOLEAN KdTermSerial;
+extern BOOLEAN KdTermReportsSize;
+
+BOOLEAN
+KdpInitTerminal(VOID);
+
+BOOLEAN
+KdpUpdateTerminalSize(
+    _Out_ PSIZE TermSize);
+
+VOID
+KdpFlushTerminalInput(VOID);
+
+CHAR
+KdpReadTermKey(
+    _Out_ PULONG ScanCode);
 
 /* EOF */
diff --git a/ntoskrnl/kdbg/kdb.c b/ntoskrnl/kdbg/kdb.c
index 1b03f692ec5..8fd5b6675d8 100644
--- a/ntoskrnl/kdbg/kdb.c
+++ b/ntoskrnl/kdbg/kdb.c
@@ -49,7 +49,6 @@ static BOOLEAN 
KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleSte
 LONG KdbLastBreakPointNr = -1;  /* Index of the breakpoint which cause KDB to 
be entered */
 ULONG KdbNumSingleSteps = 0; /* How many single steps to do */
 BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */
-ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */
 static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was 
entered because of single step */
 PEPROCESS KdbCurrentProcess = NULL;  /* The current process context in which 
KDB runs */
 PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was 
intered */
@@ -1624,33 +1623,24 @@ continue_execution:
 }
 
 VOID
-NTAPI
 KdbpGetCommandLineSettings(
-    PCHAR p1)
+    _In_ PCSTR p1)
 {
 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1)
 
-    while (p1 && (p1 = strchr(p1, ' ')))
+    while (p1 && *p1)
     {
-        /* Skip other spaces */
+        /* Skip leading whitespace */
         while (*p1 == ' ') ++p1;
 
-        if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL")))
-        {
-            p1 += CONST_STR_LEN("KDSERIAL");
-            KdbDebugState |= KD_DEBUG_KDSERIAL;
-            KdpDebugMode.Serial = TRUE;
-        }
-        else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO")))
-        {
-            p1 += CONST_STR_LEN("KDNOECHO");
-            KdbDebugState |= KD_DEBUG_KDNOECHO;
-        }
-        else if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
+        if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE")))
         {
             p1 += CONST_STR_LEN("FIRSTCHANCE");
             KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways);
         }
+
+        /* Move on to the next option */
+        p1 = strchr(p1, ' ');
     }
 }
 
diff --git a/ntoskrnl/kdbg/kdb.h b/ntoskrnl/kdbg/kdb.h
index 26c79577030..4e2c04e7e3c 100644
--- a/ntoskrnl/kdbg/kdb.h
+++ b/ntoskrnl/kdbg/kdb.h
@@ -51,12 +51,6 @@ typedef enum _KDB_ENTER_CONDITION
    KdbEnterFromUmode
 } KDB_ENTER_CONDITION;
 
-/* These values MUST be nonzero.  They're used as bit masks. */
-typedef enum _KDB_OUTPUT_SETTINGS
-{
-   KD_DEBUG_KDSERIAL = 1,
-   KD_DEBUG_KDNOECHO = 2
-} KDB_OUTPUT_SETTINGS;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -187,7 +181,6 @@ extern LONG KdbLastBreakPointNr;
 extern ULONG KdbNumSingleSteps;
 extern BOOLEAN KdbSingleStepOver;
 extern PKDB_KTRAP_FRAME KdbCurrentTrapFrame;
-extern ULONG KdbDebugState;
 
 LONG
 KdbpGetNextBreakPointNr(
@@ -252,8 +245,8 @@ KdbpAttachToProcess(
    PVOID ProcessId);
 
 VOID
-NTAPI
-KdbpGetCommandLineSettings(PCHAR p1);
+KdbpGetCommandLineSettings(
+    _In_ PCSTR p1);
 
 KD_CONTINUE_TYPE
 KdbEnterDebuggerException(IN PEXCEPTION_RECORD64 ExceptionRecord,
@@ -289,19 +282,6 @@ KdbpSafeWriteMemory(OUT PVOID Dest,
                     IN PVOID Src,
                     IN ULONG Bytes);
 
-#define KdbpGetCharKeyboard(ScanCode) KdbpTryGetCharKeyboard((ScanCode), 0)
-CHAR
-KdbpTryGetCharKeyboard(PULONG ScanCode, ULONG Retry);
-
-#define KdbpGetCharSerial()  KdbpTryGetCharSerial(0)
-CHAR
-KdbpTryGetCharSerial(
-    _In_ ULONG Retry);
-
-VOID
-KdbpSendCommandSerial(
-    _In_ PCSTR Command);
-
 VOID
 KbdDisableMouse(VOID);
 
diff --git a/ntoskrnl/kdbg/kdb_cli.c b/ntoskrnl/kdbg/kdb_cli.c
index f909fecdfc7..f889bd850a7 100644
--- a/ntoskrnl/kdbg/kdb_cli.c
+++ b/ntoskrnl/kdbg/kdb_cli.c
@@ -131,8 +131,6 @@ static ULONG KdbNumberOfRowsPrinted = 0;
 static ULONG KdbNumberOfColsPrinted = 0;
 static BOOLEAN KdbOutputAborted = FALSE;
 static BOOLEAN KdbRepeatLastCommand = FALSE;
-static LONG KdbNumberOfRowsTerminal = -1;
-static LONG KdbNumberOfColsTerminal = -1;
 
 PCHAR KdbInitFileBuffer = NULL; /* Buffer where KDBinit file is loaded into 
during initialization */
 BOOLEAN KdbpBugCheckRequested = FALSE;
@@ -2786,26 +2784,35 @@ memrchr(const void *s, int c, size_t n)
     return NULL;
 }
 
-/*!\brief Calculate pointer position for N lines upper of current position.
+/**
+ * @brief   Calculate pointer position for N lines above the current position.
  *
- * \param Buffer     Characters buffer to operate on.
- * \param BufLength  Buffer size.
+ * Calculate pointer position for N lines above the current displaying
+ * position within the given buffer. Used by KdbpPager().
  *
- * \note Calculate pointer position for N lines upper of current displaying
- *       position within the given buffer.
+ * @param[in]   Buffer
+ * Character buffer to operate on.
  *
- * Used by KdbpPager().
- * Now N lines count is hardcoded to KdbNumberOfRowsTerminal.
- */
+ * @param[in]   BufLength
+ * Size of the buffer.
+ *
+ * @param[in]   pCurPos
+ * Current position within the buffer.
+ *
+ * @return  Beginning of the previous page of text.
+ *
+ * @note    N lines count is hardcoded to the terminal's number of rows.
+ **/
 static PCHAR
 CountOnePageUp(
     _In_ PCCH Buffer,
     _In_ ULONG BufLength,
-    _In_ PCCH pCurPos)
+    _In_ PCCH pCurPos,
+    _In_ const SIZE* TermSize)
 {
     PCCH p;
     // p0 is initial guess of Page Start
-    ULONG p0len = KdbNumberOfRowsTerminal * KdbNumberOfColsTerminal;
+    ULONG p0len = TermSize->cx * TermSize->cy;
     PCCH p0 = pCurPos - p0len;
     PCCH prev_p = p0, p1;
     ULONG j;
@@ -2817,7 +2824,7 @@ CountOnePageUp(
     p = memrchr(p0, '\n', p0len);
     if (!p)
         p = p0;
-    for (j = KdbNumberOfRowsTerminal; j--; )
+    for (j = TermSize->cy; j--; )
     {
         int linesCnt;
         p1 = memrchr(p0, '\n', p-p0);
@@ -2830,7 +2837,7 @@ CountOnePageUp(
                 p = p0;
             break;
         }
-        linesCnt = (KdbNumberOfColsTerminal+prev_p-p-2) / 
KdbNumberOfColsTerminal;
+        linesCnt = (TermSize->cx+prev_p-p-2) / TermSize->cx;
         if (linesCnt > 1)
             j -= linesCnt-1;
     }
@@ -2874,27 +2881,23 @@ KdpFilterEscapes(
  *       Maximum length of buffer is limited only by memory size.
  *       Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold 
the debugger lock.
  *
- * Note: BufLength should be greater then (KdbNumberOfRowsTerminal * 
KdbNumberOfColsTerminal).
+ * Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
  */
-VOID
+static VOID
 KdbpPagerInternal(
     _In_ PCHAR Buffer,
     _In_ ULONG BufLength,
     _In_ BOOLEAN DoPage)
 {
-    static CHAR InBuffer[128];
     static BOOLEAN TerminalInitialized = FALSE;
-    static BOOLEAN TerminalConnected = FALSE;
-    static BOOLEAN TerminalReportsSize = TRUE;
     CHAR c;
     ULONG ScanCode;
     PCHAR p;
-    ULONG Length;
     SIZE_T i;
     LONG RowsPrintedByTerminal;
 
     if (BufLength == 0)
-      return;
+        return;
 
     /* Check if the user has aborted output of the current command */
     if (KdbOutputAborted)
@@ -2904,117 +2907,13 @@ KdbpPagerInternal(
     if (!TerminalInitialized)
     {
         TerminalInitialized = TRUE;
-
-        /* Enable line-wrap */
-        KdbpSendCommandSerial("\x1b[?7h");
-
-        /*
-         * Query terminal type.
-         * Historically it was done with CTRL-E ('\x05'), however nowadays
-         * terminals respond to it with an empty (or a user-configurable)
-         * string. Instead, use the VT52-compatible 'ESC Z' sequence or the
-         * VT100-compatible 'ESC[c' one.
-         */
-        KdbpSendCommandSerial("\x1b[c");
-        KeStallExecutionProcessor(100000);
-
-        Length = 0;
-        for (;;)
-        {
-            /* Verify we get an answer, but don't care about it */
-            c = KdbpTryGetCharSerial(5000);
-            if (c == -1)
-                break;
-            ++Length;
-        }
-        if (Length > 0)
-            TerminalConnected = TRUE;
+        KdpInitTerminal();
     }
 
-    /* Get number of rows and columns in terminal */
-    if ((KdbNumberOfRowsTerminal < 0) || (KdbNumberOfColsTerminal < 0) ||
-        /* Refresh terminal size each time when number of rows printed is 0 */
-        (KdbNumberOfRowsPrinted) == 0)
+    /* Refresh terminal size each time when number of rows printed is 0 */
+    if (KdbNumberOfRowsPrinted == 0)
     {
-        /* Retrieve the size of the serial terminal only when it is the
-         * controlling terminal: serial output is enabled *and* KDSERIAL
-         * is set (i.e. user input through serial). */
-        BOOLEAN SerialTerminal =
-#if 0
-        // Old logic where KDSERIAL also enables serial output.
-        (KdbDebugState & KD_DEBUG_KDSERIAL) ||
-        (KdpDebugMode.Serial && !KdpDebugMode.Screen);
-#else
-        // New logic where KDSERIAL does not necessarily enable serial output.
-        KdpDebugMode.Serial &&
-        ((KdbDebugState & KD_DEBUG_KDSERIAL) || !KdpDebugMode.Screen);
-#endif
-
-        if (SerialTerminal && TerminalConnected && TerminalReportsSize)
-        {
-            /* Try to query number of rows from terminal. A reply looks like 
"\x1b[8;24;80t" */
-            TerminalReportsSize = FALSE;
-            KdbpSendCommandSerial("\x1b[18t");
-            KeStallExecutionProcessor(100000);
-
-            c = KdbpTryGetCharSerial(5000);
-            if (c == KEY_ESC)
-            {
-                c = KdbpTryGetCharSerial(5000);
-                if (c == '[')
-                {
-                    Length = 0;
-                    for (;;)
-                    {
-                        c = KdbpTryGetCharSerial(5000);
-                        if (c == -1)
-                            break;
-
-                        InBuffer[Length++] = c;
-                        if (isalpha(c) || Length >= (sizeof(InBuffer) - 1))
-                            break;
-                    }
-                    InBuffer[Length] = '\0';
-
-                    if (InBuffer[0] == '8' && InBuffer[1] == ';')
-                    {
-                        for (i = 2; (i < Length) && (InBuffer[i] != ';'); i++);
-
-                        if (InBuffer[i] == ';')
-                        {
-                            InBuffer[i++] = '\0';
-
-                            /* Number of rows is now at Buffer + 2 and number 
of cols at Buffer + i */
-                            KdbNumberOfRowsTerminal = strtoul(InBuffer + 2, 
NULL, 0);
-                            KdbNumberOfColsTerminal = strtoul(InBuffer + i, 
NULL, 0);
-                            TerminalReportsSize = TRUE;
-                        }
-                    }
-                }
-                /* Clear further characters */
-                while ((c = KdbpTryGetCharSerial(5000)) != -1);
-            }
-        }
-
-        if (KdbNumberOfRowsTerminal <= 0)
-        {
-            /* Set number of rows to the default */
-            if (KdpDebugMode.Screen && !SerialTerminal)
-                KdbNumberOfRowsTerminal = (SCREEN_HEIGHT / (13 
/*BOOTCHAR_HEIGHT*/ + 1));
-            else
-                KdbNumberOfRowsTerminal = 24;
-        }
-        if (KdbNumberOfColsTerminal <= 0)
-        {
-            /* Set number of cols to the default */
-            if (KdpDebugMode.Screen && !SerialTerminal)
-                KdbNumberOfColsTerminal = (SCREEN_WIDTH / 8 
/*BOOTCHAR_WIDTH*/);
-            else
-                KdbNumberOfColsTerminal = 80;
-        }
-
-        // KdpDprintf("Cols/Rows: %dx%d\n",
-                   // KdbNumberOfColsTerminal, KdbNumberOfRowsTerminal);
+        KdpUpdateTerminalSize(&KdTermSize);
     }
 
     /* Loop through the strings */
@@ -3041,7 +2940,7 @@ KdbpPagerInternal(
         /* Calculate the number of lines which will be printed in
          * the terminal when outputting the current line. */
         if (i > 0)
-            RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / 
KdbNumberOfColsTerminal;
+            RowsPrintedByTerminal = (i + KdbNumberOfColsPrinted - 1) / 
KdTermSize.cx;
         else
             RowsPrintedByTerminal = 0;
 
@@ -3051,9 +2950,10 @@ KdbpPagerInternal(
         //KdpDprintf("!%d!%d!%d!%d!", KdbNumberOfRowsPrinted, 
KdbNumberOfColsPrinted, i, RowsPrintedByTerminal);
 
         /* Display a prompt if we printed one screen full of text */
-        if (KdbNumberOfRowsTerminal > 0 &&
-            (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= 
KdbNumberOfRowsTerminal)
+        if (KdTermSize.cy > 0 &&
+            (LONG)(KdbNumberOfRowsPrinted + RowsPrintedByTerminal) >= 
KdTermSize.cy)
         {
+            /* Disable the repetition of previous command with long many-page 
output */
             KdbRepeatLastCommand = FALSE;
 
             if (KdbNumberOfColsPrinted > 0)
@@ -3069,21 +2969,7 @@ KdbpPagerInternal(
             }
             RowsPrintedByTerminal++;
 
-            if (KdbDebugState & KD_DEBUG_KDSERIAL)
-                c = KdbpGetCharSerial();
-            else
-                c = KdbpGetCharKeyboard(&ScanCode);
-
-            if (c == '\r')
-            {
-                /* Try to read '\n' which might follow '\r' - if \n is not 
received here
-                 * it will be interpreted as "return" when the next command 
should be read.
-                 */
-                if (KdbDebugState & KD_DEBUG_KDSERIAL)
-                    c = KdbpTryGetCharSerial(5);
-                else
-                    c = KdbpTryGetCharKeyboard(&ScanCode, 5);
-            }
+            c = KdpReadTermKey(&ScanCode);
 
             if (DoPage)
             {
@@ -3106,13 +2992,13 @@ KdbpPagerInternal(
                 if (ScanCode == KEYSC_END || c == 'e')
                 {
                     PCHAR pBufEnd = Buffer + BufLength;
-                    p = CountOnePageUp(Buffer, BufLength, pBufEnd);
+                    p = CountOnePageUp(Buffer, BufLength, pBufEnd, 
&KdTermSize);
                     i = strcspn(p, "\n");
                 }
                 else if (ScanCode == KEYSC_PAGEUP  ||
                          ScanCode == KEYSC_ARROWUP || c == 'u')
                 {
-                    p = CountOnePageUp(Buffer, BufLength, p);
+                    p = CountOnePageUp(Buffer, BufLength, p, &KdTermSize);
                     i = strcspn(p, "\n");
                 }
                 else if (ScanCode == KEYSC_HOME || c == 'h')
@@ -3139,11 +3025,10 @@ KdbpPagerInternal(
 
         /* Remove escape sequences from the line if there is no terminal 
connected */
         // FIXME: Dangerous operation since we modify the source string!!
-        if (!TerminalConnected)
+        if (!KdTermConnected)
             KdpFilterEscapes(p);
 
         /* Print the current line */
-        // KdpDprintf(p);
         KdpDprintf("%s", p);
 
         /* Restore not null char with saved */
@@ -3178,7 +3063,7 @@ KdbpPagerInternal(
  *       Maximum length of buffer is limited only by memory size.
  *       Uses KdpDprintf internally (NOT DbgPrint!). Callers must already hold 
the debugger lock.
  *
- * Note: BufLength should be greater then (KdbNumberOfRowsTerminal * 
KdbNumberOfColsTerminal).
+ * Note: BufLength should be greater than (KdTermSize.cx * KdTermSize.cy).
  */
 VOID
 KdbpPager(
@@ -3408,17 +3293,6 @@ KdbpCliMainLoop(
         KdbpPrint("\n");
     }
 
-    /* Flush the input buffer */
-    if (KdbDebugState & KD_DEBUG_KDSERIAL)
-    {
-        while (KdbpTryGetCharSerial(1) != -1);
-    }
-    else
-    {
-        ULONG ScanCode;
-        while (KdbpTryGetCharKeyboard(&ScanCode, 1) != -1);
-    }
-
     /* Main loop */
     do
     {
@@ -3687,6 +3561,13 @@ KdbInitialize(
         /* Write out the functions that we support for now */
         DispatchTable->KdpPrintRoutine = KdbDebugPrint;
 
+        /* Check if we have a command line */
+        if (KeLoaderBlock && KeLoaderBlock->LoadOptions)
+        {
+            /* Get the KDBG Settings */
+            KdbpGetCommandLineSettings(KeLoaderBlock->LoadOptions);
+        }
+
         /* Register for BootPhase 1 initialization and as a Provider */
         DispatchTable->KdpInitRoutine = KdbInitialize;
         InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake
index 8df4eacccc3..8f3b6c8abbf 100644
--- a/ntoskrnl/ntos.cmake
+++ b/ntoskrnl/ntos.cmake
@@ -415,7 +415,8 @@ if(NOT _WINKD_)
         ${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)
+        ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdserial.c
+        ${REACTOS_SOURCE_DIR}/ntoskrnl/kd/kdterminal.c)
 
 else()
     add_definitions(-D_WINKD_)

Reply via email to