[CONSRV] Support history resizing from console settings and from SetConsoleHistoryInfo() server implementation.

In addition, honour the maximum number of history buffers allowed when
creating new ones.

Some implementation information has been obtained from
https://github.com/microsoft/terminal
(under MIT License).
This commit is contained in:
Hermès Bélusca-Maïto 2020-02-29 17:35:57 +01:00
parent 7a7212f984
commit 19596768cb
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
7 changed files with 174 additions and 82 deletions

View file

@ -697,9 +697,10 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
/* Initialize the alias and history buffers */
Console->Aliases = NULL;
InitializeListHead(&Console->HistoryBuffers);
Console->HistoryBufferSize = ConsoleInfo->HistoryBufferSize;
Console->NumberOfHistoryBuffers = ConsoleInfo->NumberOfHistoryBuffers;
Console->HistoryNoDup = ConsoleInfo->HistoryNoDup;
Console->NumberOfHistoryBuffers = 0;
Console->MaxNumberOfHistoryBuffers = ConsoleInfo->NumberOfHistoryBuffers;
Console->HistoryBufferSize = ConsoleInfo->HistoryBufferSize;
Console->HistoryNoDup = ConsoleInfo->HistoryNoDup;
/* Initialize the Input Line Discipline */
Console->LineBuffer = NULL;

View file

@ -132,11 +132,11 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
pSharedInfo->hWnd = GuiData->hWindow;
/* Console information */
pSharedInfo->HistoryBufferSize = Console->HistoryBufferSize;
pSharedInfo->NumberOfHistoryBuffers = Console->NumberOfHistoryBuffers;
pSharedInfo->HistoryNoDup = Console->HistoryNoDup;
pSharedInfo->QuickEdit = Console->QuickEdit;
pSharedInfo->InsertMode = Console->InsertMode;
pSharedInfo->NumberOfHistoryBuffers = Console->MaxNumberOfHistoryBuffers;
pSharedInfo->HistoryBufferSize = Console->HistoryBufferSize;
pSharedInfo->HistoryNoDup = Console->HistoryNoDup;
/// pSharedInfo->InputBufferSize = 0;
pSharedInfo->ScreenBufferSize = ActiveBuffer->ScreenBufferSize;
pSharedInfo->WindowSize = ActiveBuffer->ViewSize;
@ -154,7 +154,7 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData,
// FIXME: Gather defaults from the registry ?
pSharedInfo->ScreenAttributes = DEFAULT_SCREEN_ATTRIB;
pSharedInfo->PopupAttributes = DEFAULT_POPUP_ATTRIB ;
pSharedInfo->PopupAttributes = DEFAULT_POPUP_ATTRIB;
}
/* We display the output code page only */
@ -315,12 +315,6 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
/* Retrieve terminal informations */
/* Console information */
#if 0 // FIXME: Things not set
ConInfo.HistoryBufferSize = pConInfo->HistoryBufferSize;
ConInfo.NumberOfHistoryBuffers = pConInfo->NumberOfHistoryBuffers;
ConInfo.HistoryNoDup = !!pConInfo->HistoryNoDup;
ConInfo.CodePage = pConInfo->CodePage; // Done in ConSrvApplyUserSettings
#endif
/*
* Apply the settings

View file

@ -44,35 +44,52 @@ ConvertInputUnicodeToAnsi(PCONSRV_CONSOLE Console,
/* PRIVATE FUNCTIONS **********************************************************/
static PHISTORY_BUFFER
HistoryCurrentBuffer(PCONSRV_CONSOLE Console,
PUNICODE_STRING ExeName)
HistoryCurrentBuffer(
IN PCONSRV_CONSOLE Console,
IN PUNICODE_STRING ExeName)
{
PLIST_ENTRY Entry = Console->HistoryBuffers.Flink;
PLIST_ENTRY Entry;
PHISTORY_BUFFER Hist;
for (; Entry != &Console->HistoryBuffers; Entry = Entry->Flink)
for (Entry = Console->HistoryBuffers.Flink;
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)
/* Could not find the buffer, create a new one */
if (Console->NumberOfHistoryBuffers < Console->MaxNumberOfHistoryBuffers)
{
ConsoleFreeHeap(Hist);
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);
RtlCopyMemory(Hist->ExeName.Buffer, ExeName->Buffer, ExeName->Length);
InsertHeadList(&Console->HistoryBuffers, &Hist->ListEntry);
Console->NumberOfHistoryBuffers++;
return Hist;
}
else
{
// FIXME: TODO !!!!!!!
// Reuse an older history buffer, if possible with the same Exe name,
// otherwise take the oldest one and reset its contents.
// And move the history buffer back to the head of the list.
UNIMPLEMENTED;
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
@ -105,8 +122,9 @@ HistoryFindBuffer(PCONSRV_CONSOLE Console,
}
ExeNameU.Length = ExeNameU.MaximumLength;
Entry = Console->HistoryBuffers.Flink;
while (Entry != &Console->HistoryBuffers)
for (Entry = Console->HistoryBuffers.Flink;
Entry != &Console->HistoryBuffers;
Entry = Entry->Flink)
{
Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
@ -116,8 +134,6 @@ HistoryFindBuffer(PCONSRV_CONSOLE Console,
if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
return Hist;
}
Entry = Entry->Flink;
}
if (!UnicodeExe) ConsoleFreeHeap(ExeNameU.Buffer);
@ -137,6 +153,34 @@ HistoryDeleteBuffer(PHISTORY_BUFFER Hist)
ConsoleFreeHeap(Hist);
}
static NTSTATUS
HistoryResizeBuffer(
IN PHISTORY_BUFFER Hist,
IN ULONG NumCommands)
{
PUNICODE_STRING OldEntryList = Hist->Entries;
PUNICODE_STRING NewEntryList;
NewEntryList = ConsoleAllocHeap(0, NumCommands * sizeof(UNICODE_STRING));
if (!NewEntryList)
return STATUS_NO_MEMORY;
/* If necessary, shrink by removing oldest entries */
for (; Hist->NumEntries > NumCommands; Hist->NumEntries--)
{
RtlFreeUnicodeString(Hist->Entries++);
Hist->Position += (Hist->Position == 0);
}
Hist->MaxEntries = NumCommands;
RtlCopyMemory(NewEntryList, Hist->Entries,
Hist->NumEntries * sizeof(UNICODE_STRING));
Hist->Entries = NewEntryList;
ConsoleFreeHeap(OldEntryList);
return STATUS_SUCCESS;
}
VOID
HistoryAddEntry(PCONSRV_CONSOLE Console,
PUNICODE_STRING ExeName,
@ -171,8 +215,8 @@ HistoryAddEntry(PCONSRV_CONSOLE Console,
/* 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));
RtlMoveMemory(&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;
@ -184,8 +228,8 @@ HistoryAddEntry(PCONSRV_CONSOLE Console,
{
/* List is full, remove oldest entry */
RtlFreeUnicodeString(&Hist->Entries[0]);
memmove(&Hist->Entries[0], &Hist->Entries[1],
--Hist->NumEntries * sizeof(UNICODE_STRING));
RtlMoveMemory(&Hist->Entries[0], &Hist->Entries[1],
--Hist->NumEntries * sizeof(UNICODE_STRING));
}
if (NT_SUCCESS(RtlDuplicateUnicodeString(0, Entry, &Hist->Entries[Hist->NumEntries])))
@ -323,6 +367,58 @@ HistoryDeleteBuffers(PCONSRV_CONSOLE Console)
}
}
VOID
HistoryReshapeAllBuffers(
IN PCONSRV_CONSOLE Console,
IN ULONG HistoryBufferSize,
IN ULONG MaxNumberOfHistoryBuffers,
IN BOOLEAN HistoryNoDup)
{
PLIST_ENTRY Entry;
PHISTORY_BUFFER Hist;
NTSTATUS Status;
// ASSERT(Console->NumberOfHistoryBuffers <= Console->MaxNumberOfHistoryBuffers);
if (MaxNumberOfHistoryBuffers < Console->NumberOfHistoryBuffers)
{
/*
* Trim the history buffers list and reduce it up to MaxNumberOfHistoryBuffers.
* We loop the history buffers list backwards so as to trim the oldest
* buffers first.
*/
while (!IsListEmpty(&Console->HistoryBuffers) &&
(Console->NumberOfHistoryBuffers > MaxNumberOfHistoryBuffers))
{
Entry = RemoveTailList(&Console->HistoryBuffers);
Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
HistoryDeleteBuffer(Hist);
Console->NumberOfHistoryBuffers--;
}
ASSERT(Console->NumberOfHistoryBuffers == MaxNumberOfHistoryBuffers);
ASSERT(((Console->NumberOfHistoryBuffers == 0) && IsListEmpty(&Console->HistoryBuffers)) ||
((Console->NumberOfHistoryBuffers > 0) && !IsListEmpty(&Console->HistoryBuffers)));
}
Console->MaxNumberOfHistoryBuffers = MaxNumberOfHistoryBuffers;
/* Resize each history buffer */
for (Entry = Console->HistoryBuffers.Flink;
Entry != &Console->HistoryBuffers;
Entry = Entry->Flink)
{
Hist = CONTAINING_RECORD(Entry, HISTORY_BUFFER, ListEntry);
Status = HistoryResizeBuffer(Hist, HistoryBufferSize);
if (!NT_SUCCESS(Status))
{
DPRINT1("HistoryResizeBuffer(0x%p, %lu) failed, Status 0x%08lx\n",
Hist, HistoryBufferSize, Status);
}
}
Console->HistoryBufferSize = HistoryBufferSize;
/* No duplicates */
Console->HistoryNoDup = !!HistoryNoDup;
}
/* PUBLIC SERVER APIS *********************************************************/
@ -516,27 +612,7 @@ CSR_API(SrvSetConsoleNumberOfCommands)
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);
}
Status = HistoryResizeBuffer(Hist, SetHistoryNumberCommandsRequest->NumCommands);
}
ConSrvReleaseConsole(Console, TRUE);
@ -546,18 +622,20 @@ CSR_API(SrvSetConsoleNumberOfCommands)
/* API_NUMBER: ConsolepGetHistory */
CSR_API(SrvGetConsoleHistory)
{
#if 0 // Vista+
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
NTSTATUS Status;
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 ? HISTORY_NO_DUP_FLAG : 0);
ConSrvReleaseConsole(Console, TRUE);
}
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
&Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
HistoryInfoRequest->HistoryBufferSize = Console->HistoryBufferSize;
HistoryInfoRequest->NumberOfHistoryBuffers = Console->MaxNumberOfHistoryBuffers;
HistoryInfoRequest->dwFlags = (Console->HistoryNoDup ? HISTORY_NO_DUP_FLAG : 0);
ConSrvReleaseConsole(Console, TRUE);
return Status;
#else
DPRINT1("%s not yet implemented\n", __FUNCTION__);
@ -568,19 +646,22 @@ CSR_API(SrvGetConsoleHistory)
/* API_NUMBER: ConsolepSetHistory */
CSR_API(SrvSetConsoleHistory)
{
#if 0 // Vista+
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
NTSTATUS Status;
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;
Status = ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
&Console, TRUE);
if (!NT_SUCCESS(Status)) return Status;
HistoryReshapeAllBuffers(Console,
HistoryInfoRequest->HistoryBufferSize,
HistoryInfoRequest->NumberOfHistoryBuffers,
!!(HistoryInfoRequest->dwFlags & HISTORY_NO_DUP_FLAG));
ConSrvReleaseConsole(Console, TRUE);
return STATUS_SUCCESS;
#else
DPRINT1("%s not yet implemented\n", __FUNCTION__);
return STATUS_NOT_IMPLEMENTED;

View file

@ -9,3 +9,10 @@
#pragma once
VOID HistoryDeleteBuffers(PCONSRV_CONSOLE Console);
VOID
HistoryReshapeAllBuffers(
IN PCONSRV_CONSOLE Console,
IN ULONG HistoryBufferSize,
IN ULONG MaxNumberOfHistoryBuffers,
IN BOOLEAN HistoryNoDup);

View file

@ -159,8 +159,9 @@ typedef struct _WINSRV_CONSOLE
/**************************** Aliases and Histories ***************************/
struct _ALIAS_HEADER *Aliases;
LIST_ENTRY HistoryBuffers;
ULONG NumberOfHistoryBuffers; /* Number of history buffers */
ULONG MaxNumberOfHistoryBuffers; /* Maximum number of history buffers allowed */
ULONG HistoryBufferSize; /* Size for newly created history buffers */
ULONG NumberOfHistoryBuffers; /* Maximum number of history buffers allowed */
BOOLEAN HistoryNoDup; /* Remove old duplicate history entries */
/**************************** Input Line Discipline ***************************/

View file

@ -323,7 +323,9 @@ LineInputKeyDown(PCONSRV_CONSOLE Console,
case VK_F7:
{
if (KeyEvent->dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
{
HistoryDeleteCurrentBuffer(Console, ExeName);
}
else
{
if (Popup) DestroyPopupWindow(Popup);

View file

@ -10,6 +10,7 @@
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "history.h"
#include "../concfg/font.h"
#define NDEBUG
@ -40,10 +41,15 @@ ConSrvApplyUserSettings(IN PCONSOLE Console,
/*
* Apply terminal-edition settings:
* - QuickEdit and Insert modes,
* - history settings.
* - History settings.
*/
Console->QuickEdit = !!ConsoleInfo->QuickEdit;
Console->InsertMode = !!ConsoleInfo->InsertMode;
/// Console->InputBufferSize = 0;
HistoryReshapeAllBuffers(Console,
ConsoleInfo->HistoryBufferSize,
ConsoleInfo->NumberOfHistoryBuffers,
ConsoleInfo->HistoryNoDup);
/* Copy the new console palette */
// FIXME: Possible buffer overflow if s_colors is bigger than ConsoleInfo->ColorTable.