[CONSRV]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Fri, 29 Aug 2014 19:45:45 +0000 (19:45 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Fri, 29 Aug 2014 19:45:45 +0000 (19:45 +0000)
Commit my work that I've done during my trip from Albi back to Paris (part 1/2):
- QuickEdit and InsertMode are input modes that are related to CONSRV terminal(s), therefore remove them from CONDRV that needs to be agnostic about terminal specificities.
- Separate history helper functions from the line discipline functions to different files.

svn path=/branches/condrv_restructure/; revision=63978

win32ss/user/winsrv/consrv.cmake
win32ss/user/winsrv/consrv/alias.c
win32ss/user/winsrv/consrv/condrv/console.c
win32ss/user/winsrv/consrv/console.c
win32ss/user/winsrv/consrv/history.c [new file with mode: 0644]
win32ss/user/winsrv/consrv/history.h [new file with mode: 0644]
win32ss/user/winsrv/consrv/include/conio.h
win32ss/user/winsrv/consrv/include/conio_winsrv.h
win32ss/user/winsrv/consrv/lineinput.c
win32ss/user/winsrv/consrv/lineinput.h

index 63b6f57..073a4db 100644 (file)
@@ -11,6 +11,7 @@ list(APPEND CONSRV_SOURCE
     consrv/console.c
     consrv/frontendctl.c
     consrv/handle.c
+    consrv/history.c
     consrv/init.c
     consrv/lineinput.c
     consrv/settings.c
index a288f97..6c67ee8 100644 (file)
 
 typedef struct _ALIAS_ENTRY
 {
+    struct _ALIAS_ENTRY* Next;
     UNICODE_STRING Source;
     UNICODE_STRING Target;
-    struct _ALIAS_ENTRY* Next;
 } ALIAS_ENTRY, *PALIAS_ENTRY;
 
 typedef struct _ALIAS_HEADER
 {
+    struct _ALIAS_HEADER* Next;
     UNICODE_STRING ExeName;
     PALIAS_ENTRY   Data;
-    struct _ALIAS_HEADER* Next;
 } ALIAS_HEADER, *PALIAS_HEADER;
 
 
index 4f60730..6f229c4 100644 (file)
@@ -257,13 +257,6 @@ ConDrvInitConsole(OUT PCONSOLE* NewConsole,
     Console->InputBuffer.Mode = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
                                 ENABLE_ECHO_INPUT      | ENABLE_MOUSE_INPUT;
 
-    Console->InsertMode = ConsoleInfo->InsertMode;
-    Console->LineBuffer = NULL;
-    Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
-    Console->LineComplete = Console->LineUpPressed = FALSE;
-    Console->LineInsertToggle = Console->InsertMode;
-    // LineWakeupMask
-
     /* Set-up the code page */
     Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
 
@@ -518,17 +511,7 @@ ConDrvGetConsoleMode(IN PCONSOLE Console,
     if (INPUT_BUFFER == Object->Type)
     {
         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
-
         *ConsoleMode = InputBuffer->Mode;
-
-        if (Console->QuickEdit || Console->InsertMode)
-        {
-            // Windows does this, even if it's not documented on MSDN
-            *ConsoleMode |= ENABLE_EXTENDED_FLAGS;
-
-            if (Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
-            if (Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
-        }
     }
     else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
     {
@@ -548,8 +531,6 @@ ConDrvSetConsoleMode(IN PCONSOLE Console,
                      IN PCONSOLE_IO_OBJECT Object,
                      IN ULONG ConsoleMode)
 {
-#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS   | \
-                                      ENABLE_INSERT_MODE      | ENABLE_QUICK_EDIT_MODE )
 #define CONSOLE_VALID_INPUT_MODES   ( ENABLE_PROCESSED_INPUT  | ENABLE_LINE_INPUT   | \
                                       ENABLE_ECHO_INPUT       | ENABLE_WINDOW_INPUT | \
                                       ENABLE_MOUSE_INPUT )
@@ -567,45 +548,21 @@ ConDrvSetConsoleMode(IN PCONSOLE Console,
     {
         PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object;
 
-        DPRINT("SetConsoleMode(Input, %d)\n", ConsoleMode);
-
-        /*
-         * 1. Only the presence of valid mode flags is allowed.
-         */
-        if (ConsoleMode & ~(CONSOLE_VALID_INPUT_MODES | CONSOLE_VALID_CONTROL_MODES))
+        /* Only the presence of valid mode flags is allowed */
+        if (ConsoleMode & ~CONSOLE_VALID_INPUT_MODES)
         {
             Status = STATUS_INVALID_PARAMETER;
-            goto Quit;
         }
-
-        /*
-         * 2. If we use control mode flags without ENABLE_EXTENDED_FLAGS,
-         *    then consider the flags invalid.
-         *
-        if ( (ConsoleMode & CONSOLE_VALID_CONTROL_MODES) &&
-             (ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0 )
-        {
-            Status = STATUS_INVALID_PARAMETER;
-            goto Quit;
-        }
-        */
-
-        /*
-         * 3. Now we can continue.
-         */
-        if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
+        else
         {
-            Console->QuickEdit  = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
-            Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
+            InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
         }
-        InputBuffer->Mode = (ConsoleMode & CONSOLE_VALID_INPUT_MODES);
     }
     else if (TEXTMODE_BUFFER == Object->Type || GRAPHICS_BUFFER == Object->Type)
     {
         PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object;
 
-        DPRINT("SetConsoleMode(Output, %d)\n", ConsoleMode);
-
+        /* Only the presence of valid mode flags is allowed */
         if (ConsoleMode & ~CONSOLE_VALID_OUTPUT_MODES)
         {
             Status = STATUS_INVALID_PARAMETER;
@@ -620,7 +577,6 @@ ConDrvSetConsoleMode(IN PCONSOLE Console,
         Status = STATUS_INVALID_HANDLE;
     }
 
-Quit:
     return Status;
 }
 
index a5d7c65..e0a6455 100644 (file)
@@ -15,6 +15,7 @@
 #include <ndk/psfuncs.h>
 
 #include <alias.h>
+#include <history.h>
 #include "procinit.h"
 
 #define NDEBUG
@@ -427,7 +428,14 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
     Console->NumberOfHistoryBuffers = ConsoleInfo.NumberOfHistoryBuffers;
     Console->HistoryNoDup           = ConsoleInfo.HistoryNoDup;
 
-    Console->QuickEdit = ConsoleInfo.QuickEdit;
+    /* Initialize the Input Line Discipline */
+    Console->LineBuffer = NULL;
+    Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
+    Console->LineComplete = Console->LineUpPressed = FALSE;
+    // LineWakeupMask
+    Console->LineInsertToggle =
+    Console->InsertMode = ConsoleInfo.InsertMode;
+    Console->QuickEdit  = ConsoleInfo.QuickEdit;
 
     /* Colour table */
     memcpy(Console->Colors, ConsoleInfo.Colors, sizeof(ConsoleInfo.Colors));
@@ -755,13 +763,34 @@ CSR_API(SrvGetConsoleMode)
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
     PCONSOLE_IO_OBJECT Object;
 
+    PULONG ConsoleMode = &ConsoleModeRequest->Mode;
+
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                              ConsoleModeRequest->Handle,
                              &Object, NULL, GENERIC_READ, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
+    /* Get the standard console modes */
     Status = ConDrvGetConsoleMode(Object->Console, Object,
-                                  &ConsoleModeRequest->Mode);
+                                  ConsoleMode);
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * If getting the console modes succeeds, then retrieve
+         * the extended CONSRV-specific input modes.
+         */
+        if (INPUT_BUFFER == Object->Type)
+        {
+            if (Object->Console->InsertMode || Object->Console->QuickEdit)
+            {
+                /* Windows does this, even if it is not documented on MSDN */
+                *ConsoleMode |= ENABLE_EXTENDED_FLAGS;
+
+                if (Object->Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
+                if (Object->Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
+            }
+        }
+    }
 
     ConSrvReleaseObject(Object, TRUE);
     return Status;
@@ -773,17 +802,52 @@ ConDrvSetConsoleMode(IN PCONSOLE Console,
                      IN ULONG ConsoleMode);
 CSR_API(SrvSetConsoleMode)
 {
+#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
+                                      ENABLE_INSERT_MODE    | ENABLE_QUICK_EDIT_MODE )
+
     NTSTATUS Status;
     PCONSOLE_GETSETCONSOLEMODE ConsoleModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ConsoleModeRequest;
     PCONSOLE_IO_OBJECT Object;
 
+    ULONG ConsoleMode = ConsoleModeRequest->Mode;
+
     Status = ConSrvGetObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
                              ConsoleModeRequest->Handle,
                              &Object, NULL, GENERIC_WRITE, TRUE, 0);
     if (!NT_SUCCESS(Status)) return Status;
 
+    /* Set the standard console modes (without the CONSRV-specific input modes) */
+    ConsoleMode &= ~CONSOLE_VALID_CONTROL_MODES; // Remove CONSRV-specific input modes.
     Status = ConDrvSetConsoleMode(Object->Console, Object,
-                                  ConsoleModeRequest->Mode);
+                                  ConsoleMode);
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * If setting the console modes succeeds, then set
+         * the extended CONSRV-specific input modes.
+         */
+        if (INPUT_BUFFER == Object->Type)
+        {
+            ConsoleMode = ConsoleModeRequest->Mode;
+
+            if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
+            {
+                /*
+                 * If we use control mode flags without ENABLE_EXTENDED_FLAGS,
+                 * then consider the flags invalid.
+                 */
+                if ((ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0)
+                {
+                    Status = STATUS_INVALID_PARAMETER;
+                }
+                else
+                {
+                    Object->Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
+                    Object->Console->QuickEdit  = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
+                }
+            }
+        }
+    }
 
     ConSrvReleaseObject(Object, TRUE);
     return Status;
diff --git a/win32ss/user/winsrv/consrv/history.c b/win32ss/user/winsrv/consrv/history.c
new file mode 100644 (file)
index 0000000..06df881
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Console Server DLL
+ * FILE:            win32ss/user/winsrv/consrv/history.c
+ * PURPOSE:         Console line input functions
+ * PROGRAMMERS:     Jeffrey Morlan
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "consrv.h"
+
+#define NDEBUG
+#include <debug.h>
+
+typedef struct _HISTORY_BUFFER
+{
+    LIST_ENTRY ListEntry;
+    ULONG Position;
+    ULONG MaxEntries;
+    ULONG NumEntries;
+    UNICODE_STRING  ExeName;
+    PUNICODE_STRING Entries;
+} HISTORY_BUFFER, *PHISTORY_BUFFER;
+
+
+BOOLEAN
+ConvertInputAnsiToUnicode(PCONSOLE Console,
+                          PVOID    Source,
+                          USHORT   SourceLength,
+                          // BOOLEAN  IsUnicode,
+                          PWCHAR*  Target,
+                          PUSHORT  TargetLength);
+BOOLEAN
+ConvertInputUnicodeToAnsi(PCONSOLE Console,
+                          PVOID    Source,
+                          USHORT   SourceLength,
+                          // BOOLEAN  IsAnsi,
+                          PCHAR/* * */   Target,
+                          /*P*/USHORT  TargetLength);
+
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+static PHISTORY_BUFFER
+HistoryCurrentBuffer(PCONSRV_CONSOLE Console,
+                     PUNICODE_STRING ExeName)
+{
+    PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
+    PHISTORY_BUFFER Hist;
+
+    for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
+    {
+        Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
+        if (RtlEqualUnicodeString(ExeName, &Hist->ExeName, FALSE))
+            return Hist;
+    }
+
+    /* Couldn't find the buffer, create a new one */
+    Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName->Length);
+    if (!Hist) return NULL;
+    Hist->MaxEntries = Console->HistoryBufferSize;
+    Hist->NumEntries = 0;
+    Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING));
+    if (!Hist->Entries)
+    {
+        ConsoleFreeHeap(Hist);
+        return NULL;
+    }
+    Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName->Length;
+    Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
+    memcpy(Hist->ExeName.Buffer, ExeName->Buffer, ExeName->Length);
+    InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
+    return Hist;
+}
+
+static PHISTORY_BUFFER
+HistoryFindBuffer(PCONSRV_CONSOLE Console,
+                  PVOID    ExeName,
+                  USHORT   ExeLength,
+                  BOOLEAN  UnicodeExe)
+{
+    UNICODE_STRING ExeNameU;
+
+    PLIST_ENTRY Entry;
+    PHISTORY_BUFFER Hist = NULL;
+
+    if (ExeName == NULL) return NULL;
+
+    if (UnicodeExe)
+    {
+        ExeNameU.Buffer = ExeName;
+        /* Length is in bytes */
+        ExeNameU.MaximumLength = ExeLength;
+    }
+    else
+    {
+        if (!ConvertInputAnsiToUnicode(Console,
+                                       ExeName, ExeLength,
+                                       &ExeNameU.Buffer, &ExeNameU.MaximumLength))
+        {
+            return NULL;
+        }
+    }
+    ExeNameU.Length = ExeNameU.MaximumLength;
+
+    Entry = Console->HistoryBuffers.Flink;
+    while (Entry != &Console->HistoryBuffers)
+    {
+        Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
+
+        /* For the history APIs, the caller is allowed to give only part of the name */
+        if (RtlPrefixUnicodeString(&ExeNameU, &Hist->ExeName, TRUE))
+        {
+            if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
+            return Hist;
+        }
+
+        Entry = Entry->Flink;
+    }
+
+    if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
+    return NULL;
+}
+
+static VOID
+HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
+{
+    if (!Hist) return;
+
+    while (Hist->NumEntries != 0)
+        RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
+
+    ConsoleFreeHeap(Hist->Entries);
+    RemoveEntryList(&Hist->ListEntry);
+    ConsoleFreeHeap(Hist);
+}
+
+VOID
+HistoryAddEntry(PCONSRV_CONSOLE Console,
+                PUNICODE_STRING ExeName,
+                PUNICODE_STRING Entry)
+{
+    // UNICODE_STRING NewEntry;
+    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
+
+    if (!Hist) return;
+
+    // NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
+    // NewEntry.Buffer = Console->LineBuffer;
+
+    /* Don't add blank or duplicate entries */
+    if (Entry->Length == 0 || Hist->MaxEntries == 0 ||
+        (Hist->NumEntries > 0 &&
+         RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], Entry, FALSE)))
+    {
+        return;
+    }
+
+    if (Console->HistoryNoDup)
+    {
+        INT i;
+
+        /* Check if this line has been entered before */
+        for (i = Hist->NumEntries - 1; i >= 0; i--)
+        {
+            if (RtlEqualUnicodeString(&Hist->Entries[i], Entry, FALSE))
+            {
+                UNICODE_STRING NewEntry;
+
+                /* Just rotate the list to bring this entry to the end */
+                NewEntry = Hist->Entries[i];
+                memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
+                        (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
+                Hist->Entries[Hist->NumEntries - 1] = NewEntry;
+                Hist->Position = Hist->NumEntries - 1;
+                return;
+            }
+        }
+    }
+
+    if (Hist->NumEntries == Hist->MaxEntries)
+    {
+        /* List is full, remove oldest entry */
+        RtlFreeUnicodeString(&Hist->Entries[0]);
+        memmove(&Hist->Entries[0], &Hist->Entries[1],
+                --Hist->NumEntries * sizeof(UNICODE_STRING));
+    }
+
+    if (NT_SUCCESS(RtlDuplicateUnicodeString(0, Entry, &Hist->Entries[Hist->NumEntries])))
+        Hist->NumEntries++;
+    Hist->Position = Hist->NumEntries - 1;
+}
+
+VOID
+HistoryGetCurrentEntry(PCONSRV_CONSOLE Console,
+                       PUNICODE_STRING ExeName,
+                       PUNICODE_STRING Entry)
+{
+    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
+
+    if (!Hist || Hist->NumEntries == 0)
+        Entry->Length = 0;
+    else
+        *Entry = Hist->Entries[Hist->Position];
+}
+
+BOOL
+HistoryRecallHistory(PCONSRV_CONSOLE Console,
+                     PUNICODE_STRING ExeName,
+                     INT Offset,
+                     PUNICODE_STRING Entry)
+{
+    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
+    ULONG Position = 0;
+
+    if (!Hist || Hist->NumEntries == 0) return FALSE;
+
+    Position = Hist->Position + Offset;
+    Position = min(max(Position, 0), Hist->NumEntries - 1);
+    Hist->Position = Position;
+
+    *Entry = Hist->Entries[Hist->Position];
+    return TRUE;
+}
+
+BOOL
+HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console,
+                         PUNICODE_STRING ExeName,
+                         PUNICODE_STRING Prefix,
+                         PUNICODE_STRING Entry)
+{
+    INT HistPos;
+
+    /* Search for history entries starting with input. */
+    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
+    if (!Hist || Hist->NumEntries == 0) return FALSE;
+
+    /*
+     * Like Up/F5, on first time start from current (usually last) entry,
+     * but on subsequent times start at previous entry.
+     */
+    if (Console->LineUpPressed)
+        Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
+    Console->LineUpPressed = TRUE;
+
+    // Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
+    // Entry.Buffer = Console->LineBuffer;
+
+    /*
+     * Keep going backwards, even wrapping around to the end,
+     * until we get back to starting point.
+     */
+    HistPos = Hist->Position;
+    do
+    {
+        if (RtlPrefixUnicodeString(Prefix, &Hist->Entries[HistPos], FALSE))
+        {
+            Hist->Position = HistPos;
+            *Entry = Hist->Entries[HistPos];
+            return TRUE;
+        }
+        if (--HistPos < 0) HistPos += Hist->NumEntries;
+    } while (HistPos != Hist->Position);
+
+    return FALSE;
+}
+
+VOID
+HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console,
+                           PVOID ExeName)
+{
+    HistoryDeleteBuffer(HistoryCurrentBuffer(Console, ExeName));
+}
+
+VOID
+HistoryDeleteBuffers(PCONSRV_CONSOLE Console)
+{
+    PLIST_ENTRY CurrentEntry;
+    PHISTORY_BUFFER HistoryBuffer;
+
+    while (!IsListEmpty(&Console->HistoryBuffers))
+    {
+        CurrentEntry = RemoveHeadList(&Console->HistoryBuffers);
+        HistoryBuffer = CONTAINING_RECORD(CurrentEntry, HISTORY_BUFFER, ListEntry);
+        HistoryDeleteBuffer(HistoryBuffer);
+    }
+}
+
+
+/* PUBLIC SERVER APIS *********************************************************/
+
+CSR_API(SrvGetConsoleCommandHistory)
+{
+    NTSTATUS Status;
+    PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryRequest;
+    PCONSRV_CONSOLE Console;
+    ULONG BytesWritten = 0;
+    PHISTORY_BUFFER Hist;
+
+    DPRINT1("SrvGetConsoleCommandHistory entered\n");
+
+    if ( !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&GetCommandHistoryRequest->History,
+                                   GetCommandHistoryRequest->HistoryLength,
+                                   sizeof(BYTE))                    ||
+         !CsrValidateMessageBuffer(ApiMessage,
+                                   (PVOID*)&GetCommandHistoryRequest->ExeName,
+                                   GetCommandHistoryRequest->ExeLength,
+                                   sizeof(BYTE)) )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    Hist = HistoryFindBuffer(Console,
+                             GetCommandHistoryRequest->ExeName,
+                             GetCommandHistoryRequest->ExeLength,
+                             GetCommandHistoryRequest->Unicode2);
+    if (Hist)
+    {
+        ULONG i;
+
+        LPSTR  TargetBufferA;
+        LPWSTR TargetBufferW;
+        ULONG BufferSize = GetCommandHistoryRequest->HistoryLength;
+
+        ULONG Offset = 0;
+        ULONG SourceLength;
+
+        if (GetCommandHistoryRequest->Unicode)
+        {
+            TargetBufferW = GetCommandHistoryRequest->History;
+            BufferSize /= sizeof(WCHAR);
+        }
+        else
+        {
+            TargetBufferA = GetCommandHistoryRequest->History;
+        }
+
+        for (i = 0; i < Hist->NumEntries; i++)
+        {
+            SourceLength = Hist->Entries[i].Length / sizeof(WCHAR);
+            if (Offset + SourceLength + 1 > BufferSize)
+            {
+                Status = STATUS_BUFFER_OVERFLOW;
+                break;
+            }
+
+            if (GetCommandHistoryRequest->Unicode)
+            {
+                RtlCopyMemory(&TargetBufferW[Offset], Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR));
+                Offset += SourceLength;
+                TargetBufferW[Offset++] = L'\0';
+            }
+            else
+            {
+                ConvertInputUnicodeToAnsi(Console,
+                                          Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR),
+                                          &TargetBufferA[Offset], SourceLength);
+                Offset += SourceLength;
+                TargetBufferA[Offset++] = '\0';
+            }
+        }
+
+        if (GetCommandHistoryRequest->Unicode)
+            BytesWritten = Offset * sizeof(WCHAR);
+        else
+            BytesWritten = Offset;
+    }
+
+    // GetCommandHistoryRequest->HistoryLength = TargetBuffer - (PBYTE)GetCommandHistoryRequest->History;
+    GetCommandHistoryRequest->HistoryLength = BytesWritten;
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+CSR_API(SrvGetConsoleCommandHistoryLength)
+{
+    NTSTATUS Status;
+    PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryLengthRequest;
+    PCONSRV_CONSOLE Console;
+    PHISTORY_BUFFER Hist;
+    ULONG Length = 0;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&GetCommandHistoryLengthRequest->ExeName,
+                                  GetCommandHistoryLengthRequest->ExeLength,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    Hist = HistoryFindBuffer(Console,
+                             GetCommandHistoryLengthRequest->ExeName,
+                             GetCommandHistoryLengthRequest->ExeLength,
+                             GetCommandHistoryLengthRequest->Unicode2);
+    if (Hist)
+    {
+        ULONG i;
+        for (i = 0; i < Hist->NumEntries; i++)
+            Length += Hist->Entries[i].Length + sizeof(WCHAR); // Each entry is returned NULL-terminated
+    }
+    /*
+     * Quick and dirty way of getting the number of bytes of the
+     * corresponding ANSI string from the one in UNICODE.
+     */
+    if (!GetCommandHistoryLengthRequest->Unicode)
+        Length /= sizeof(WCHAR);
+
+    GetCommandHistoryLengthRequest->HistoryLength = Length;
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+CSR_API(SrvExpungeConsoleCommandHistory)
+{
+    NTSTATUS Status;
+    PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ExpungeCommandHistoryRequest;
+    PCONSRV_CONSOLE Console;
+    PHISTORY_BUFFER Hist;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&ExpungeCommandHistoryRequest->ExeName,
+                                  ExpungeCommandHistoryRequest->ExeLength,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    Hist = HistoryFindBuffer(Console,
+                             ExpungeCommandHistoryRequest->ExeName,
+                             ExpungeCommandHistoryRequest->ExeLength,
+                             ExpungeCommandHistoryRequest->Unicode2);
+    HistoryDeleteBuffer(Hist);
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+CSR_API(SrvSetConsoleNumberOfCommands)
+{
+    NTSTATUS Status;
+    PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryNumberCommandsRequest;
+    PCONSRV_CONSOLE Console;
+    PHISTORY_BUFFER Hist;
+
+    if (!CsrValidateMessageBuffer(ApiMessage,
+                                  (PVOID*)&SetHistoryNumberCommandsRequest->ExeName,
+                                  SetHistoryNumberCommandsRequest->ExeLength,
+                                  sizeof(BYTE)))
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    Hist = HistoryFindBuffer(Console,
+                             SetHistoryNumberCommandsRequest->ExeName,
+                             SetHistoryNumberCommandsRequest->ExeLength,
+                             SetHistoryNumberCommandsRequest->Unicode2);
+    if (Hist)
+    {
+        ULONG MaxEntries = SetHistoryNumberCommandsRequest->NumCommands;
+        PUNICODE_STRING OldEntryList = Hist->Entries;
+        PUNICODE_STRING NewEntryList = ConsoleAllocHeap(0, MaxEntries * sizeof(UNICODE_STRING));
+        if (!NewEntryList)
+        {
+            Status = STATUS_NO_MEMORY;
+        }
+        else
+        {
+            /* If necessary, shrink by removing oldest entries */
+            for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
+            {
+                RtlFreeUnicodeString(Hist->Entries++);
+                Hist->Position += (Hist->Position == 0);
+            }
+
+            Hist->MaxEntries = MaxEntries;
+            Hist->Entries = memcpy(NewEntryList, Hist->Entries,
+                                   Hist->NumEntries * sizeof(UNICODE_STRING));
+            ConsoleFreeHeap(OldEntryList);
+        }
+    }
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+CSR_API(SrvGetConsoleHistory)
+{
+#if 0 // Vista+
+    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
+    PCONSRV_CONSOLE Console;
+    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        HistoryInfoRequest->HistoryBufferSize      = Console->HistoryBufferSize;
+        HistoryInfoRequest->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
+        HistoryInfoRequest->dwFlags                = Console->HistoryNoDup;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+#else
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+CSR_API(SrvSetConsoleHistory)
+{
+#if 0 // Vista+
+    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
+    PCONSRV_CONSOLE Console;
+    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        Console->HistoryBufferSize      = HistoryInfoRequest->HistoryBufferSize;
+        Console->NumberOfHistoryBuffers = HistoryInfoRequest->NumberOfHistoryBuffers;
+        Console->HistoryNoDup           = HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG;
+        ConSrvReleaseConsole(Console, TRUE);
+    }
+    return Status;
+#else
+    DPRINT1("%s not yet implemented\n", __FUNCTION__);
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+CSR_API(SrvSetConsoleCommandHistoryMode)
+{
+    NTSTATUS Status;
+    PCONSOLE_SETHISTORYMODE SetHistoryModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryModeRequest;
+    PCONSRV_CONSOLE Console;
+
+    DPRINT1("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
+            SetHistoryModeRequest->Mode);
+
+    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* This API is not yet implemented */
+    Status = STATUS_NOT_IMPLEMENTED;
+
+    ConSrvReleaseConsole(Console, TRUE);
+    return Status;
+}
+
+/* EOF */
diff --git a/win32ss/user/winsrv/consrv/history.h b/win32ss/user/winsrv/consrv/history.h
new file mode 100644 (file)
index 0000000..1b3833f
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Console Server DLL
+ * FILE:            win32ss/user/winsrv/consrv/history.h
+ * PURPOSE:         Console line input functions
+ * PROGRAMMERS:     Jeffrey Morlan
+ */
+
+#pragma once
+
+VOID HistoryDeleteBuffers(PCONSRV_CONSOLE Console);
index fc9d4eb..e9c1fb7 100644 (file)
@@ -279,24 +279,12 @@ typedef struct _CONSOLE
     ULONG ConsoleID;                        /* The ID of the console */
     LIST_ENTRY ListEntry;                   /* Entry in the list of consoles */
 
-/**************************** Input buffer and data ***************************/
+    HANDLE UnpauseEvent;                    /* When != NULL, event for pausing the console */
+
+/******************************** Input buffer ********************************/
     CONSOLE_INPUT_BUFFER InputBuffer;       /* Input buffer of the console */
     UINT InputCodePage;
 
-    /** Put those things in CONSOLE_INPUT_BUFFER in PWINSRV_CONSOLE ?? **/
-    PWCHAR  LineBuffer;                     /* Current line being input, in line buffered mode */
-    ULONG   LineMaxSize;                    /* Maximum size of line in characters (including CR+LF) */
-    ULONG   LineSize;                       /* Current size of line */
-    ULONG   LinePos;                        /* Current position within line */
-    BOOLEAN LineComplete;                   /* User pressed enter, ready to send back to client */
-    BOOLEAN LineUpPressed;
-    BOOLEAN LineInsertToggle;               /* Replace character over cursor instead of inserting */
-    ULONG   LineWakeupMask;                 /* Bitmap of which control characters will end line input */
-
-    /** In PWINSRV_CONSOLE ?? **/
-    BOOLEAN InsertMode;
-    /*************************************************/
-
 /******************************* Screen buffers *******************************/
     LIST_ENTRY BufferList;                  /* List of all screen buffers for this console */
     PCONSOLE_SCREEN_BUFFER ActiveBuffer;    /* Pointer to currently active screen buffer */
@@ -306,8 +294,6 @@ typedef struct _CONSOLE
     UNICODE_STRING OriginalTitle;           /* Original title of console, the one defined when the console leader is launched; it never changes. Always NULL-terminated */
     UNICODE_STRING Title;                   /* Title of console. Always NULL-terminated */
 
-    HANDLE UnpauseEvent;                    /* When != NULL, event for pausing the console */
-
     COORD   ConsoleSize;                    /* The current size of the console, for text-mode only */
     BOOLEAN FixedSize;                      /* TRUE if the console is of fixed size */
 
index d7be50e..a3e8285 100644 (file)
@@ -131,8 +131,6 @@ typedef struct _WINSRV_CONSOLE
     PCONSOLE_PROCESS_DATA NotifiedLastCloseProcess; /* Pointer to the unique process that needs to be notified when the console leader process is killed */
     BOOLEAN NotifyLastClose;        /* TRUE if the console should send a control event when the console leader process is killed */
 
-    BOOLEAN QuickEdit;
-
 /******************************* Pausing support ******************************/
     BYTE PauseFlags;
     LIST_ENTRY  ReadWaitQueue;      /* List head for the queue of unique input buffer read wait blocks */
@@ -145,6 +143,19 @@ typedef struct _WINSRV_CONSOLE
     ULONG NumberOfHistoryBuffers;           /* Maximum number of history buffers allowed */
     BOOLEAN HistoryNoDup;                   /* Remove old duplicate history entries */
 
+/**************************** Input Line Discipline ***************************/
+    PWCHAR  LineBuffer;                     /* Current line being input, in line buffered mode */
+    ULONG   LineMaxSize;                    /* Maximum size of line in characters (including CR+LF) */
+    ULONG   LineSize;                       /* Current size of line */
+    ULONG   LinePos;                        /* Current position within line */
+    BOOLEAN LineComplete;                   /* User pressed enter, ready to send back to client */
+    BOOLEAN LineUpPressed;
+    BOOLEAN LineInsertToggle;               /* Replace character over cursor instead of inserting */
+    ULONG   LineWakeupMask;                 /* Bitmap of which control characters will end line input */
+
+    BOOLEAN InsertMode;
+    BOOLEAN QuickEdit;
+
 /************************ Virtual DOS Machine support *************************/
     COORD   VDMBufferSize;             /* Real size of the VDM buffer, in units of ??? */
     HANDLE  VDMBufferSection;          /* Handle to the memory shared section for the VDM buffer */
index e60ff4c..e9fe3ce 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-typedef struct _HISTORY_BUFFER
-{
-    LIST_ENTRY ListEntry;
-    UINT Position;
-    UINT MaxEntries;
-    UINT NumEntries;
-    UNICODE_STRING ExeName;
-    PUNICODE_STRING Entries;
-} HISTORY_BUFFER, *PHISTORY_BUFFER;
-
 
 BOOLEAN
 ConvertInputAnsiToUnicode(PCONSOLE Console,
@@ -40,183 +30,35 @@ ConvertInputUnicodeToAnsi(PCONSOLE Console,
                           /*P*/USHORT  TargetLength);
 
 
-/* PRIVATE FUNCTIONS **********************************************************/
-
-static PHISTORY_BUFFER
-HistoryCurrentBuffer(PCONSRV_CONSOLE Console,
-                     PUNICODE_STRING ExeName)
-{
-    PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
-    PHISTORY_BUFFER Hist;
-
-    for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
-    {
-        Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
-        if (RtlEqualUnicodeString(ExeName, &Hist->ExeName, FALSE))
-            return Hist;
-    }
-
-    /* Couldn't find the buffer, create a new one */
-    Hist = ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER) + ExeName->Length);
-    if (!Hist) return NULL;
-    Hist->MaxEntries = Console->HistoryBufferSize;
-    Hist->NumEntries = 0;
-    Hist->Entries = ConsoleAllocHeap(0, Hist->MaxEntries * sizeof(UNICODE_STRING));
-    if (!Hist->Entries)
-    {
-        ConsoleFreeHeap(Hist);
-        return NULL;
-    }
-    Hist->ExeName.Length = Hist->ExeName.MaximumLength = ExeName->Length;
-    Hist->ExeName.Buffer = (PWCHAR)(Hist + 1);
-    memcpy(Hist->ExeName.Buffer, ExeName->Buffer, ExeName->Length);
-    InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
-    return Hist;
-}
-
-static VOID
+VOID
 HistoryAddEntry(PCONSRV_CONSOLE Console,
-                PUNICODE_STRING ExeName)
-{
-    UNICODE_STRING NewEntry;
-    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
-    INT i;
-
-    if (!Hist) return;
-
-    NewEntry.Length = NewEntry.MaximumLength = Console->LineSize * sizeof(WCHAR);
-    NewEntry.Buffer = Console->LineBuffer;
-
-    /* Don't add blank or duplicate entries */
-    if (NewEntry.Length == 0 || Hist->MaxEntries == 0 ||
-        (Hist->NumEntries > 0 &&
-         RtlEqualUnicodeString(&Hist->Entries[Hist->NumEntries - 1], &NewEntry, FALSE)))
-    {
-        return;
-    }
-
-    if (Console->HistoryNoDup)
-    {
-        /* Check if this line has been entered before */
-        for (i = Hist->NumEntries - 1; i >= 0; i--)
-        {
-            if (RtlEqualUnicodeString(&Hist->Entries[i], &NewEntry, FALSE))
-            {
-                /* Just rotate the list to bring this entry to the end */
-                NewEntry = Hist->Entries[i];
-                memmove(&Hist->Entries[i], &Hist->Entries[i + 1],
-                        (Hist->NumEntries - (i + 1)) * sizeof(UNICODE_STRING));
-                Hist->Entries[Hist->NumEntries - 1] = NewEntry;
-                Hist->Position = Hist->NumEntries - 1;
-                return;
-            }
-        }
-    }
-
-    if (Hist->NumEntries == Hist->MaxEntries)
-    {
-        /* List is full, remove oldest entry */
-        RtlFreeUnicodeString(&Hist->Entries[0]);
-        memmove(&Hist->Entries[0], &Hist->Entries[1],
-                --Hist->NumEntries * sizeof(UNICODE_STRING));
-    }
-
-    if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry, &Hist->Entries[Hist->NumEntries])))
-        Hist->NumEntries++;
-    Hist->Position = Hist->NumEntries - 1;
-}
-
-static VOID
+                PUNICODE_STRING ExeName,
+                PUNICODE_STRING Entry);
+BOOL
+HistoryRecallHistory(PCONSRV_CONSOLE Console,
+                     PUNICODE_STRING ExeName,
+                     INT Offset,
+                     PUNICODE_STRING Entry);
+VOID
 HistoryGetCurrentEntry(PCONSRV_CONSOLE Console,
                        PUNICODE_STRING ExeName,
-                       PUNICODE_STRING Entry)
-{
-    PHISTORY_BUFFER Hist = HistoryCurrentBuffer(Console, ExeName);
-
-    if (!Hist || Hist->NumEntries == 0)
-        Entry->Length = 0;
-    else
-        *Entry = Hist->Entries[Hist->Position];
-}
-
-static PHISTORY_BUFFER
-HistoryFindBuffer(PCONSRV_CONSOLE Console,
-                  PVOID    ExeName,
-                  USHORT   ExeLength,
-                  BOOLEAN  UnicodeExe)
-{
-    UNICODE_STRING ExeNameU;
-
-    PLIST_ENTRY Entry;
-    PHISTORY_BUFFER Hist = NULL;
-
-    if (ExeName == NULL) return NULL;
-
-    if (UnicodeExe)
-    {
-        ExeNameU.Buffer = ExeName;
-        /* Length is in bytes */
-        ExeNameU.MaximumLength = ExeLength;
-    }
-    else
-    {
-        if (!ConvertInputAnsiToUnicode(Console,
-                                       ExeName, ExeLength,
-                                       &ExeNameU.Buffer, &ExeNameU.MaximumLength))
-        {
-            return NULL;
-        }
-    }
-    ExeNameU.Length = ExeNameU.MaximumLength;
-
-    Entry = Console->HistoryBuffers.Flink;
-    while (Entry != &Console->HistoryBuffers)
-    {
-        Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
-
-        /* For the history APIs, the caller is allowed to give only part of the name */
-        if (RtlPrefixUnicodeString(&ExeNameU, &Hist->ExeName, TRUE))
-        {
-            if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
-            return Hist;
-        }
-
-        Entry = Entry->Flink;
-    }
-
-    if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
-    return NULL;
-}
-
-static VOID
-HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
-{
-    if (!Hist) return;
-
-    while (Hist->NumEntries != 0)
-        RtlFreeUnicodeString(&Hist->Entries[--Hist->NumEntries]);
+                       PUNICODE_STRING Entry);
+VOID
+HistoryDeleteCurrentBuffer(PCONSRV_CONSOLE Console,
+                           PVOID ExeName);
+BOOL
+HistoryFindEntryByPrefix(PCONSRV_CONSOLE Console,
+                         PUNICODE_STRING ExeName,
+                         PUNICODE_STRING Prefix,
+                         PUNICODE_STRING Entry);
 
-    ConsoleFreeHeap(Hist->Entries);
-    RemoveEntryList(&Hist->ListEntry);
-    ConsoleFreeHeap(Hist);
-}
 
-VOID
-HistoryDeleteBuffers(PCONSRV_CONSOLE Console)
-{
-    PLIST_ENTRY CurrentEntry;
-    PHISTORY_BUFFER HistoryBuffer;
 
-    while (!IsListEmpty(&Console->HistoryBuffers))
-    {
-        CurrentEntry = RemoveHeadList(&Console->HistoryBuffers);
-        HistoryBuffer = CONTAINING_RECORD(CurrentEntry, HISTORY_BUFFER, ListEntry);
-        HistoryDeleteBuffer(HistoryBuffer);
-    }
-}
+/* PRIVATE FUNCTIONS **********************************************************/
 
 static VOID
-LineInputSetPos(PCONSRV_CONSOLE Console, UINT Pos)
+LineInputSetPos(PCONSRV_CONSOLE Console,
+                UINT Pos)
 {
     if (Pos != Console->LinePos && Console->InputBuffer.Mode & ENABLE_ECHO_INPUT)
     {
@@ -240,7 +82,10 @@ LineInputSetPos(PCONSRV_CONSOLE Console, UINT Pos)
 }
 
 static VOID
-LineInputEdit(PCONSRV_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, PWCHAR Insertion)
+LineInputEdit(PCONSRV_CONSOLE Console,
+              UINT NumToDelete,
+              UINT NumToInsert,
+              PWCHAR Insertion)
 {
     PTEXTMODE_SCREEN_BUFFER ActiveBuffer;
     UINT Pos = Console->LinePos;
@@ -276,6 +121,7 @@ LineInputEdit(PCONSRV_CONSOLE Console, UINT NumToDelete, UINT NumToInsert, PWCHA
     LineInputSetPos(Console, Pos + NumToInsert);
 }
 
+#if 0
 static VOID
 LineInputRecallHistory(PCONSRV_CONSOLE Console,
                        PUNICODE_STRING ExeName,
@@ -295,6 +141,22 @@ LineInputRecallHistory(PCONSRV_CONSOLE Console,
                   Hist->Entries[Hist->Position].Length / sizeof(WCHAR),
                   Hist->Entries[Hist->Position].Buffer);
 }
+#else
+static VOID
+LineInputRecallHistory(PCONSRV_CONSOLE Console,
+                       PUNICODE_STRING ExeName,
+                       INT Offset)
+{
+    UNICODE_STRING Entry;
+
+    if (!HistoryRecallHistory(Console, ExeName, Offset, &Entry)) return;
+
+    LineInputSetPos(Console, 0);
+    LineInputEdit(Console, Console->LineSize,
+                  Entry.Length / sizeof(WCHAR),
+                  Entry.Buffer);
+}
+#endif
 
 VOID
 LineInputKeyDown(PCONSRV_CONSOLE Console,
@@ -302,9 +164,12 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
                  KEY_EVENT_RECORD *KeyEvent)
 {
     UINT Pos = Console->LinePos;
-    PHISTORY_BUFFER Hist;
     UNICODE_STRING Entry;
-    INT HistPos;
+    // INT HistPos;
+
+    /*
+     * First, deal with control keys...
+     */
 
     switch (KeyEvent->wVirtualKeyCode)
     {
@@ -314,20 +179,20 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
         LineInputEdit(Console, Console->LineSize, 0, NULL);
         return;
     case VK_HOME:
-        /* Move to start of line. With ctrl, erase everything left of cursor */
+        /* Move to start of line. With CTRL, erase everything left of cursor */
         LineInputSetPos(Console, 0);
         if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
             LineInputEdit(Console, Pos, 0, NULL);
         return;
     case VK_END:
-        /* Move to end of line. With ctrl, erase everything right of cursor */
+        /* Move to end of line. With CTRL, erase everything right of cursor */
         if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
             LineInputEdit(Console, Console->LineSize - Pos, 0, NULL);
         else
             LineInputSetPos(Console, Console->LineSize);
         return;
     case VK_LEFT:
-        /* Move left. With ctrl, move to beginning of previous word */
+        /* Move left. With CTRL, move to beginning of previous word */
         if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
         {
             while (Pos > 0 && Console->LineBuffer[Pos - 1] == L' ') Pos--;
@@ -341,13 +206,12 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
         return;
     case VK_RIGHT:
     case VK_F1:
-        /* Move right. With ctrl, move to beginning of next word */
+        /* Move right. With CTRL, move to beginning of next word */
         if (KeyEvent->dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
         {
             while (Pos < Console->LineSize && Console->LineBuffer[Pos] != L' ') Pos++;
             while (Pos < Console->LineSize && Console->LineBuffer[Pos] == L' ') Pos++;
             LineInputSetPos(Console, Pos);
-            return;
         }
         else
         {
@@ -379,8 +243,10 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
         return;
     case VK_UP:
     case VK_F5:
-        /* Recall previous history entry. On first time, actually recall the
-         * current (usually last) entry; on subsequent times go back. */
+        /*
+         * Recall previous history entry. On first time, actually recall the
+         * current (usually last) entry; on subsequent times go back.
+         */
         LineInputRecallHistory(Console, ExeName, Console->LineUpPressed ? -1 : 0);
         Console->LineUpPressed = TRUE;
         return;
@@ -404,24 +270,47 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
         break;
     case VK_F7:
         if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
-            HistoryDeleteBuffer(HistoryCurrentBuffer(Console, ExeName));
+            HistoryDeleteCurrentBuffer(Console, ExeName);
         return;
     case VK_F8:
+
+    {
+        UNICODE_STRING EntryFound;
+
+        Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
+        Entry.Buffer = Console->LineBuffer;
+
+        if (HistoryFindEntryByPrefix(Console, ExeName, &Entry, &EntryFound))
+        {
+            LineInputEdit(Console, Console->LineSize - Pos,
+                          EntryFound.Length / sizeof(WCHAR) - Pos,
+                          &EntryFound.Buffer[Pos]);
+            /* Cursor stays where it was */
+            LineInputSetPos(Console, Pos);
+        }
+    }
+#if 0
+        PHISTORY_BUFFER Hist;
+
         /* Search for history entries starting with input. */
         Hist = HistoryCurrentBuffer(Console, ExeName);
         if (!Hist || Hist->NumEntries == 0) return;
 
-        /* Like Up/F5, on first time start from current (usually last) entry,
-         * but on subsequent times start at previous entry. */
+        /*
+         * Like Up/F5, on first time start from current (usually last) entry,
+         * but on subsequent times start at previous entry.
+         */
         if (Console->LineUpPressed)
             Hist->Position = (Hist->Position ? Hist->Position : Hist->NumEntries) - 1;
         Console->LineUpPressed = TRUE;
 
-        Entry.Length = Console->LinePos * sizeof(WCHAR);
+        Entry.Length = Console->LinePos * sizeof(WCHAR); // == Pos * sizeof(WCHAR)
         Entry.Buffer = Console->LineBuffer;
 
-        /* Keep going backwards, even wrapping around to the end,
-         * until we get back to starting point */
+        /*
+         * Keep going backwards, even wrapping around to the end,
+         * until we get back to starting point.
+         */
         HistPos = Hist->Position;
         do
         {
@@ -437,9 +326,16 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
             }
             if (--HistPos < 0) HistPos += Hist->NumEntries;
         } while (HistPos != Hist->Position);
+#endif
+
         return;
     }
 
+
+    /*
+     * OK, we can continue...
+     */
+
     if (KeyEvent->uChar.UnicodeChar == L'\b' && Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT)
     {
         /* backspace handling - if processed input enabled then we handle it here
@@ -452,9 +348,12 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
     }
     else if (KeyEvent->uChar.UnicodeChar == L'\r')
     {
-        HistoryAddEntry(Console, ExeName);
+        Entry.Length = Entry.MaximumLength = Console->LineSize * sizeof(WCHAR);
+        Entry.Buffer = Console->LineBuffer;
+        HistoryAddEntry(Console, ExeName, &Entry);
 
         /* TODO: Expand aliases */
+        DPRINT1("TODO: Expand aliases\n");
 
         LineInputSetPos(Console, Console->LineSize);
         Console->LineBuffer[Console->LineSize++] = L'\r';
@@ -466,9 +365,11 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
             }
         }
 
-        /* Add \n if processed input. There should usually be room for it,
+        /*
+         * Add \n if processed input. There should usually be room for it,
          * but an exception to the rule exists: the buffer could have been 
-         * pre-filled with LineMaxSize - 1 characters. */
+         * pre-filled with LineMaxSize - 1 characters.
+         */
         if (Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
             Console->LineSize < Console->LineMaxSize)
         {
@@ -507,272 +408,4 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
 
 /* PUBLIC SERVER APIS *********************************************************/
 
-CSR_API(SrvGetConsoleCommandHistory)
-{
-    NTSTATUS Status;
-    PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryRequest;
-    PCONSRV_CONSOLE Console;
-    ULONG BytesWritten = 0;
-    PHISTORY_BUFFER Hist;
-
-    DPRINT1("SrvGetConsoleCommandHistory entered\n");
-
-    if ( !CsrValidateMessageBuffer(ApiMessage,
-                                   (PVOID*)&GetCommandHistoryRequest->History,
-                                   GetCommandHistoryRequest->HistoryLength,
-                                   sizeof(BYTE))                    ||
-         !CsrValidateMessageBuffer(ApiMessage,
-                                   (PVOID*)&GetCommandHistoryRequest->ExeName,
-                                   GetCommandHistoryRequest->ExeLength,
-                                   sizeof(BYTE)) )
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    Hist = HistoryFindBuffer(Console,
-                             GetCommandHistoryRequest->ExeName,
-                             GetCommandHistoryRequest->ExeLength,
-                             GetCommandHistoryRequest->Unicode2);
-    if (Hist)
-    {
-        UINT i;
-
-        LPSTR  TargetBufferA;
-        LPWSTR TargetBufferW;
-        ULONG BufferSize = GetCommandHistoryRequest->HistoryLength;
-
-        UINT Offset = 0;
-        UINT SourceLength;
-
-        if (GetCommandHistoryRequest->Unicode)
-        {
-            TargetBufferW = GetCommandHistoryRequest->History;
-            BufferSize /= sizeof(WCHAR);
-        }
-        else
-        {
-            TargetBufferA = GetCommandHistoryRequest->History;
-        }
-
-        for (i = 0; i < Hist->NumEntries; i++)
-        {
-            SourceLength = Hist->Entries[i].Length / sizeof(WCHAR);
-            if (Offset + SourceLength + 1 > BufferSize)
-            {
-                Status = STATUS_BUFFER_OVERFLOW;
-                break;
-            }
-
-            if (GetCommandHistoryRequest->Unicode)
-            {
-                RtlCopyMemory(&TargetBufferW[Offset], Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR));
-                Offset += SourceLength;
-                TargetBufferW[Offset++] = L'\0';
-            }
-            else
-            {
-                ConvertInputUnicodeToAnsi(Console,
-                                          Hist->Entries[i].Buffer, SourceLength * sizeof(WCHAR),
-                                          &TargetBufferA[Offset], SourceLength);
-                Offset += SourceLength;
-                TargetBufferA[Offset++] = '\0';
-            }
-        }
-
-        if (GetCommandHistoryRequest->Unicode)
-            BytesWritten = Offset * sizeof(WCHAR);
-        else
-            BytesWritten = Offset;
-    }
-
-    // GetCommandHistoryRequest->HistoryLength = TargetBuffer - (PBYTE)GetCommandHistoryRequest->History;
-    GetCommandHistoryRequest->HistoryLength = BytesWritten;
-
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
-
-CSR_API(SrvGetConsoleCommandHistoryLength)
-{
-    NTSTATUS Status;
-    PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.GetCommandHistoryLengthRequest;
-    PCONSRV_CONSOLE Console;
-    PHISTORY_BUFFER Hist;
-    ULONG Length = 0;
-    UINT  i;
-
-    if (!CsrValidateMessageBuffer(ApiMessage,
-                                  (PVOID*)&GetCommandHistoryLengthRequest->ExeName,
-                                  GetCommandHistoryLengthRequest->ExeLength,
-                                  sizeof(BYTE)))
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    Hist = HistoryFindBuffer(Console,
-                             GetCommandHistoryLengthRequest->ExeName,
-                             GetCommandHistoryLengthRequest->ExeLength,
-                             GetCommandHistoryLengthRequest->Unicode2);
-    if (Hist)
-    {
-        for (i = 0; i < Hist->NumEntries; i++)
-            Length += Hist->Entries[i].Length + sizeof(WCHAR); // Each entry is returned NULL-terminated
-    }
-    /*
-     * Quick and dirty way of getting the number of bytes of the
-     * corresponding ANSI string from the one in UNICODE.
-     */
-    if (!GetCommandHistoryLengthRequest->Unicode)
-        Length /= sizeof(WCHAR);
-
-    GetCommandHistoryLengthRequest->HistoryLength = Length;
-
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
-
-CSR_API(SrvExpungeConsoleCommandHistory)
-{
-    NTSTATUS Status;
-    PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.ExpungeCommandHistoryRequest;
-    PCONSRV_CONSOLE Console;
-    PHISTORY_BUFFER Hist;
-
-    if (!CsrValidateMessageBuffer(ApiMessage,
-                                  (PVOID*)&ExpungeCommandHistoryRequest->ExeName,
-                                  ExpungeCommandHistoryRequest->ExeLength,
-                                  sizeof(BYTE)))
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    Hist = HistoryFindBuffer(Console,
-                             ExpungeCommandHistoryRequest->ExeName,
-                             ExpungeCommandHistoryRequest->ExeLength,
-                             ExpungeCommandHistoryRequest->Unicode2);
-    HistoryDeleteBuffer(Hist);
-
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
-
-CSR_API(SrvSetConsoleNumberOfCommands)
-{
-    NTSTATUS Status;
-    PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryNumberCommandsRequest;
-    PCONSRV_CONSOLE Console;
-    PHISTORY_BUFFER Hist;
-
-    if (!CsrValidateMessageBuffer(ApiMessage,
-                                  (PVOID*)&SetHistoryNumberCommandsRequest->ExeName,
-                                  SetHistoryNumberCommandsRequest->ExeLength,
-                                  sizeof(BYTE)))
-    {
-        return STATUS_INVALID_PARAMETER;
-    }
-
-    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    Hist = HistoryFindBuffer(Console,
-                             SetHistoryNumberCommandsRequest->ExeName,
-                             SetHistoryNumberCommandsRequest->ExeLength,
-                             SetHistoryNumberCommandsRequest->Unicode2);
-    if (Hist)
-    {
-        UINT MaxEntries = SetHistoryNumberCommandsRequest->NumCommands;
-        PUNICODE_STRING OldEntryList = Hist->Entries;
-        PUNICODE_STRING NewEntryList = ConsoleAllocHeap(0, MaxEntries * sizeof(UNICODE_STRING));
-        if (!NewEntryList)
-        {
-            Status = STATUS_NO_MEMORY;
-        }
-        else
-        {
-            /* If necessary, shrink by removing oldest entries */
-            for (; Hist->NumEntries > MaxEntries; Hist->NumEntries--)
-            {
-                RtlFreeUnicodeString(Hist->Entries++);
-                Hist->Position += (Hist->Position == 0);
-            }
-
-            Hist->MaxEntries = MaxEntries;
-            Hist->Entries = memcpy(NewEntryList, Hist->Entries,
-                                   Hist->NumEntries * sizeof(UNICODE_STRING));
-            ConsoleFreeHeap(OldEntryList);
-        }
-    }
-
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
-
-CSR_API(SrvGetConsoleHistory)
-{
-#if 0 // Vista+
-    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
-    PCONSRV_CONSOLE Console;
-    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (NT_SUCCESS(Status))
-    {
-        HistoryInfoRequest->HistoryBufferSize      = Console->HistoryBufferSize;
-        HistoryInfoRequest->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
-        HistoryInfoRequest->dwFlags                = Console->HistoryNoDup;
-        ConSrvReleaseConsole(Console, TRUE);
-    }
-    return Status;
-#else
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
-#endif
-}
-
-CSR_API(SrvSetConsoleHistory)
-{
-#if 0 // Vista+
-    PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.HistoryInfoRequest;
-    PCONSRV_CONSOLE Console;
-    NTSTATUS Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (NT_SUCCESS(Status))
-    {
-        Console->HistoryBufferSize      = HistoryInfoRequest->HistoryBufferSize;
-        Console->NumberOfHistoryBuffers = HistoryInfoRequest->NumberOfHistoryBuffers;
-        Console->HistoryNoDup           = HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG;
-        ConSrvReleaseConsole(Console, TRUE);
-    }
-    return Status;
-#else
-    DPRINT1("%s not yet implemented\n", __FUNCTION__);
-    return STATUS_NOT_IMPLEMENTED;
-#endif
-}
-
-CSR_API(SrvSetConsoleCommandHistoryMode)
-{
-    NTSTATUS Status;
-    PCONSOLE_SETHISTORYMODE SetHistoryModeRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.SetHistoryModeRequest;
-    PCONSRV_CONSOLE Console;
-
-    DPRINT1("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
-            SetHistoryModeRequest->Mode);
-
-    Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process), &Console, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
-
-    /* This API is not yet implemented */
-    Status = STATUS_NOT_IMPLEMENTED;
-
-    ConSrvReleaseConsole(Console, TRUE);
-    return Status;
-}
-
 /* EOF */
index 55511a0..c26a33a 100644 (file)
@@ -1,15 +1,13 @@
 /*
  * LICENSE:         GPL - See COPYING in the top level directory
  * PROJECT:         ReactOS Console Server DLL
- * FILE:            win32ss/user/winsrv/consrv/lineinput.c
+ * FILE:            win32ss/user/winsrv/consrv/lineinput.h
  * PURPOSE:         Console line input functions
  * PROGRAMMERS:     Jeffrey Morlan
  */
 
 #pragma once
 
-VOID HistoryDeleteBuffers(PCONSRV_CONSOLE Console);
-
 VOID
 LineInputKeyDown(PCONSRV_CONSOLE Console,
                  PUNICODE_STRING ExeName,