2 * LICENSE: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/lineinput.c
5 * PURPOSE: Console line input functions
6 * PROGRAMMERS: Jeffrey Morlan
9 /* INCLUDES *******************************************************************/
16 typedef struct _HISTORY_BUFFER
22 UNICODE_STRING ExeName
;
23 PUNICODE_STRING Entries
;
24 } HISTORY_BUFFER
, *PHISTORY_BUFFER
;
28 ConvertInputAnsiToUnicode(PCONSOLE Console
,
33 PUSHORT TargetLength
);
35 ConvertInputUnicodeToAnsi(PCONSOLE Console
,
40 /*P*/USHORT TargetLength
);
43 /* PRIVATE FUNCTIONS **********************************************************/
45 static PHISTORY_BUFFER
46 HistoryCurrentBuffer(PCONSRV_CONSOLE Console
,
47 PUNICODE_STRING ExeName
)
49 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
52 for (; Entry
!= &Console
->HistoryBuffers
; Entry
= Entry
->Flink
)
54 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
55 if (RtlEqualUnicodeString(ExeName
, &Hist
->ExeName
, FALSE
))
59 /* Couldn't find the buffer, create a new one */
60 Hist
= ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER
) + ExeName
->Length
);
61 if (!Hist
) return NULL
;
62 Hist
->MaxEntries
= Console
->HistoryBufferSize
;
64 Hist
->Entries
= ConsoleAllocHeap(0, Hist
->MaxEntries
* sizeof(UNICODE_STRING
));
67 ConsoleFreeHeap(Hist
);
70 Hist
->ExeName
.Length
= Hist
->ExeName
.MaximumLength
= ExeName
->Length
;
71 Hist
->ExeName
.Buffer
= (PWCHAR
)(Hist
+ 1);
72 memcpy(Hist
->ExeName
.Buffer
, ExeName
->Buffer
, ExeName
->Length
);
73 InsertHeadList(&Console
->HistoryBuffers
, &Hist
->ListEntry
);
78 HistoryAddEntry(PCONSRV_CONSOLE Console
,
79 PUNICODE_STRING ExeName
)
81 UNICODE_STRING NewEntry
;
82 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
, ExeName
);
87 NewEntry
.Length
= NewEntry
.MaximumLength
= Console
->LineSize
* sizeof(WCHAR
);
88 NewEntry
.Buffer
= Console
->LineBuffer
;
90 /* Don't add blank or duplicate entries */
91 if (NewEntry
.Length
== 0 || Hist
->MaxEntries
== 0 ||
92 (Hist
->NumEntries
> 0 &&
93 RtlEqualUnicodeString(&Hist
->Entries
[Hist
->NumEntries
- 1], &NewEntry
, FALSE
)))
98 if (Console
->HistoryNoDup
)
100 /* Check if this line has been entered before */
101 for (i
= Hist
->NumEntries
- 1; i
>= 0; i
--)
103 if (RtlEqualUnicodeString(&Hist
->Entries
[i
], &NewEntry
, FALSE
))
105 /* Just rotate the list to bring this entry to the end */
106 NewEntry
= Hist
->Entries
[i
];
107 memmove(&Hist
->Entries
[i
], &Hist
->Entries
[i
+ 1],
108 (Hist
->NumEntries
- (i
+ 1)) * sizeof(UNICODE_STRING
));
109 Hist
->Entries
[Hist
->NumEntries
- 1] = NewEntry
;
110 Hist
->Position
= Hist
->NumEntries
- 1;
116 if (Hist
->NumEntries
== Hist
->MaxEntries
)
118 /* List is full, remove oldest entry */
119 RtlFreeUnicodeString(&Hist
->Entries
[0]);
120 memmove(&Hist
->Entries
[0], &Hist
->Entries
[1],
121 --Hist
->NumEntries
* sizeof(UNICODE_STRING
));
124 if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry
, &Hist
->Entries
[Hist
->NumEntries
])))
126 Hist
->Position
= Hist
->NumEntries
- 1;
130 HistoryGetCurrentEntry(PCONSRV_CONSOLE Console
,
131 PUNICODE_STRING ExeName
,
132 PUNICODE_STRING Entry
)
134 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
, ExeName
);
136 if (!Hist
|| Hist
->NumEntries
== 0)
139 *Entry
= Hist
->Entries
[Hist
->Position
];
142 static PHISTORY_BUFFER
143 HistoryFindBuffer(PCONSRV_CONSOLE Console
,
148 UNICODE_STRING ExeNameU
;
151 PHISTORY_BUFFER Hist
= NULL
;
153 if (ExeName
== NULL
) return NULL
;
157 ExeNameU
.Buffer
= ExeName
;
158 /* Length is in bytes */
159 ExeNameU
.MaximumLength
= ExeLength
;
163 if (!ConvertInputAnsiToUnicode(Console
,
165 &ExeNameU
.Buffer
, &ExeNameU
.MaximumLength
))
170 ExeNameU
.Length
= ExeNameU
.MaximumLength
;
172 Entry
= Console
->HistoryBuffers
.Flink
;
173 while (Entry
!= &Console
->HistoryBuffers
)
175 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
177 /* For the history APIs, the caller is allowed to give only part of the name */
178 if (RtlPrefixUnicodeString(&ExeNameU
, &Hist
->ExeName
, TRUE
))
180 if (!UnicodeExe
) ConsoleFreeHeap(ExeNameU
.Buffer
);
184 Entry
= Entry
->Flink
;
187 if (!UnicodeExe
) ConsoleFreeHeap(ExeNameU
.Buffer
);
192 HistoryDeleteBuffer(PHISTORY_BUFFER Hist
)
196 while (Hist
->NumEntries
!= 0)
197 RtlFreeUnicodeString(&Hist
->Entries
[--Hist
->NumEntries
]);
199 ConsoleFreeHeap(Hist
->Entries
);
200 RemoveEntryList(&Hist
->ListEntry
);
201 ConsoleFreeHeap(Hist
);
205 HistoryDeleteBuffers(PCONSRV_CONSOLE Console
)
207 PLIST_ENTRY CurrentEntry
;
208 PHISTORY_BUFFER HistoryBuffer
;
210 while (!IsListEmpty(&Console
->HistoryBuffers
))
212 CurrentEntry
= RemoveHeadList(&Console
->HistoryBuffers
);
213 HistoryBuffer
= CONTAINING_RECORD(CurrentEntry
, HISTORY_BUFFER
, ListEntry
);
214 HistoryDeleteBuffer(HistoryBuffer
);
219 LineInputSetPos(PCONSRV_CONSOLE Console
, UINT Pos
)
221 if (Pos
!= Console
->LinePos
&& Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
223 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
224 SHORT OldCursorX
= Buffer
->CursorPosition
.X
;
225 SHORT OldCursorY
= Buffer
->CursorPosition
.Y
;
226 INT XY
= OldCursorY
* Buffer
->ScreenBufferSize
.X
+ OldCursorX
;
228 XY
+= (Pos
- Console
->LinePos
);
231 else if (XY
>= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
)
232 XY
= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
- 1;
234 Buffer
->CursorPosition
.X
= XY
% Buffer
->ScreenBufferSize
.X
;
235 Buffer
->CursorPosition
.Y
= XY
/ Buffer
->ScreenBufferSize
.X
;
236 TermSetScreenInfo(Console
, Buffer
, OldCursorX
, OldCursorY
);
239 Console
->LinePos
= Pos
;
243 LineInputEdit(PCONSRV_CONSOLE Console
, UINT NumToDelete
, UINT NumToInsert
, PWCHAR Insertion
)
245 PTEXTMODE_SCREEN_BUFFER ActiveBuffer
;
246 UINT Pos
= Console
->LinePos
;
247 UINT NewSize
= Console
->LineSize
- NumToDelete
+ NumToInsert
;
250 if (GetType(Console
->ActiveBuffer
) != TEXTMODE_BUFFER
) return;
251 ActiveBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Console
->ActiveBuffer
;
253 /* Make sure there's always enough room for ending \r\n */
254 if (NewSize
+ 2 > Console
->LineMaxSize
)
257 memmove(&Console
->LineBuffer
[Pos
+ NumToInsert
],
258 &Console
->LineBuffer
[Pos
+ NumToDelete
],
259 (Console
->LineSize
- (Pos
+ NumToDelete
)) * sizeof(WCHAR
));
260 memcpy(&Console
->LineBuffer
[Pos
], Insertion
, NumToInsert
* sizeof(WCHAR
));
262 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
264 for (i
= Pos
; i
< NewSize
; i
++)
266 ConioWriteConsole(Console
, ActiveBuffer
, &Console
->LineBuffer
[i
], 1, TRUE
);
268 for (; i
< Console
->LineSize
; i
++)
270 ConioWriteConsole(Console
, ActiveBuffer
, L
" ", 1, TRUE
);
272 Console
->LinePos
= i
;
275 Console
->LineSize
= NewSize
;
276 LineInputSetPos(Console
, Pos
+ NumToInsert
);
280 LineInputRecallHistory(PCONSRV_CONSOLE Console
,
281 PUNICODE_STRING ExeName
,
284 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
, ExeName
);
287 if (!Hist
|| Hist
->NumEntries
== 0) return;
289 Position
= Hist
->Position
+ Offset
;
290 Position
= min(max(Position
, 0), Hist
->NumEntries
- 1);
291 Hist
->Position
= Position
;
293 LineInputSetPos(Console
, 0);
294 LineInputEdit(Console
, Console
->LineSize
,
295 Hist
->Entries
[Hist
->Position
].Length
/ sizeof(WCHAR
),
296 Hist
->Entries
[Hist
->Position
].Buffer
);
300 LineInputKeyDown(PCONSRV_CONSOLE Console
,
301 PUNICODE_STRING ExeName
,
302 KEY_EVENT_RECORD
*KeyEvent
)
304 UINT Pos
= Console
->LinePos
;
305 PHISTORY_BUFFER Hist
;
306 UNICODE_STRING Entry
;
309 switch (KeyEvent
->wVirtualKeyCode
)
312 /* Clear entire line */
313 LineInputSetPos(Console
, 0);
314 LineInputEdit(Console
, Console
->LineSize
, 0, NULL
);
317 /* Move to start of line. With ctrl, erase everything left of cursor */
318 LineInputSetPos(Console
, 0);
319 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
320 LineInputEdit(Console
, Pos
, 0, NULL
);
323 /* Move to end of line. With ctrl, erase everything right of cursor */
324 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
325 LineInputEdit(Console
, Console
->LineSize
- Pos
, 0, NULL
);
327 LineInputSetPos(Console
, Console
->LineSize
);
330 /* Move left. With ctrl, move to beginning of previous word */
331 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
333 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] == L
' ') Pos
--;
334 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] != L
' ') Pos
--;
340 LineInputSetPos(Console
, Pos
);
344 /* Move right. With ctrl, move to beginning of next word */
345 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
347 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] != L
' ') Pos
++;
348 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] == L
' ') Pos
++;
349 LineInputSetPos(Console
, Pos
);
354 /* Recall one character (but don't overwrite current line) */
355 HistoryGetCurrentEntry(Console
, ExeName
, &Entry
);
356 if (Pos
< Console
->LineSize
)
357 LineInputSetPos(Console
, Pos
+ 1);
358 else if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
359 LineInputEdit(Console
, 0, 1, &Entry
.Buffer
[Pos
]);
363 /* Toggle between insert and overstrike */
364 Console
->LineInsertToggle
= !Console
->LineInsertToggle
;
365 TermSetCursorInfo(Console
, Console
->ActiveBuffer
);
368 /* Remove character to right of cursor */
369 if (Pos
!= Console
->LineSize
)
370 LineInputEdit(Console
, 1, 0, NULL
);
373 /* Recall first history entry */
374 LineInputRecallHistory(Console
, ExeName
, -((WORD
)-1));
377 /* Recall last history entry */
378 LineInputRecallHistory(Console
, ExeName
, +((WORD
)-1));
382 /* Recall previous history entry. On first time, actually recall the
383 * current (usually last) entry; on subsequent times go back. */
384 LineInputRecallHistory(Console
, ExeName
, Console
->LineUpPressed
? -1 : 0);
385 Console
->LineUpPressed
= TRUE
;
388 /* Recall next history entry */
389 LineInputRecallHistory(Console
, ExeName
, +1);
392 /* Recall remainder of current history entry */
393 HistoryGetCurrentEntry(Console
, ExeName
, &Entry
);
394 if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
396 UINT InsertSize
= (Entry
.Length
/ sizeof(WCHAR
) - Pos
);
397 UINT DeleteSize
= min(Console
->LineSize
- Pos
, InsertSize
);
398 LineInputEdit(Console
, DeleteSize
, InsertSize
, &Entry
.Buffer
[Pos
]);
402 /* Insert a ^Z character */
403 KeyEvent
->uChar
.UnicodeChar
= 26;
406 if (KeyEvent
->dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
407 HistoryDeleteBuffer(HistoryCurrentBuffer(Console
, ExeName
));
410 /* Search for history entries starting with input. */
411 Hist
= HistoryCurrentBuffer(Console
, ExeName
);
412 if (!Hist
|| Hist
->NumEntries
== 0) return;
414 /* Like Up/F5, on first time start from current (usually last) entry,
415 * but on subsequent times start at previous entry. */
416 if (Console
->LineUpPressed
)
417 Hist
->Position
= (Hist
->Position
? Hist
->Position
: Hist
->NumEntries
) - 1;
418 Console
->LineUpPressed
= TRUE
;
420 Entry
.Length
= Console
->LinePos
* sizeof(WCHAR
);
421 Entry
.Buffer
= Console
->LineBuffer
;
423 /* Keep going backwards, even wrapping around to the end,
424 * until we get back to starting point */
425 HistPos
= Hist
->Position
;
428 if (RtlPrefixUnicodeString(&Entry
, &Hist
->Entries
[HistPos
], FALSE
))
430 Hist
->Position
= HistPos
;
431 LineInputEdit(Console
, Console
->LineSize
- Pos
,
432 Hist
->Entries
[HistPos
].Length
/ sizeof(WCHAR
) - Pos
,
433 &Hist
->Entries
[HistPos
].Buffer
[Pos
]);
434 /* Cursor stays where it was */
435 LineInputSetPos(Console
, Pos
);
438 if (--HistPos
< 0) HistPos
+= Hist
->NumEntries
;
439 } while (HistPos
!= Hist
->Position
);
443 if (KeyEvent
->uChar
.UnicodeChar
== L
'\b' && Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
)
445 /* backspace handling - if processed input enabled then we handle it here
446 * otherwise we treat it like a normal char. */
449 LineInputSetPos(Console
, Pos
- 1);
450 LineInputEdit(Console
, 1, 0, NULL
);
453 else if (KeyEvent
->uChar
.UnicodeChar
== L
'\r')
455 HistoryAddEntry(Console
, ExeName
);
457 /* TODO: Expand aliases */
459 LineInputSetPos(Console
, Console
->LineSize
);
460 Console
->LineBuffer
[Console
->LineSize
++] = L
'\r';
461 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
463 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
465 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\r", 1, TRUE
);
469 /* Add \n if processed input. There should usually be room for it,
470 * but an exception to the rule exists: the buffer could have been
471 * pre-filled with LineMaxSize - 1 characters. */
472 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
473 Console
->LineSize
< Console
->LineMaxSize
)
475 Console
->LineBuffer
[Console
->LineSize
++] = L
'\n';
476 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
478 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
480 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\n", 1, TRUE
);
484 Console
->LineComplete
= TRUE
;
485 Console
->LinePos
= 0;
487 else if (KeyEvent
->uChar
.UnicodeChar
!= L
'\0')
489 if (KeyEvent
->uChar
.UnicodeChar
< 0x20 &&
490 Console
->LineWakeupMask
& (1 << KeyEvent
->uChar
.UnicodeChar
))
492 /* Control key client wants to handle itself (e.g. for tab completion) */
493 Console
->LineBuffer
[Console
->LineSize
++] = L
' ';
494 Console
->LineBuffer
[Console
->LinePos
] = KeyEvent
->uChar
.UnicodeChar
;
495 Console
->LineComplete
= TRUE
;
496 Console
->LinePos
= 0;
500 /* Normal character */
501 BOOL Overstrike
= !Console
->LineInsertToggle
&& (Console
->LinePos
!= Console
->LineSize
);
502 LineInputEdit(Console
, (Overstrike
? 1 : 0), 1, &KeyEvent
->uChar
.UnicodeChar
);
508 /* PUBLIC SERVER APIS *********************************************************/
510 CSR_API(SrvGetConsoleCommandHistory
)
513 PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryRequest
;
514 PCONSRV_CONSOLE Console
;
515 ULONG BytesWritten
= 0;
516 PHISTORY_BUFFER Hist
;
518 DPRINT1("SrvGetConsoleCommandHistory entered\n");
520 if ( !CsrValidateMessageBuffer(ApiMessage
,
521 (PVOID
*)&GetCommandHistoryRequest
->History
,
522 GetCommandHistoryRequest
->HistoryLength
,
524 !CsrValidateMessageBuffer(ApiMessage
,
525 (PVOID
*)&GetCommandHistoryRequest
->ExeName
,
526 GetCommandHistoryRequest
->ExeLength
,
529 return STATUS_INVALID_PARAMETER
;
532 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
533 if (!NT_SUCCESS(Status
)) return Status
;
535 Hist
= HistoryFindBuffer(Console
,
536 GetCommandHistoryRequest
->ExeName
,
537 GetCommandHistoryRequest
->ExeLength
,
538 GetCommandHistoryRequest
->Unicode2
);
544 LPWSTR TargetBufferW
;
545 ULONG BufferSize
= GetCommandHistoryRequest
->HistoryLength
;
550 if (GetCommandHistoryRequest
->Unicode
)
552 TargetBufferW
= GetCommandHistoryRequest
->History
;
553 BufferSize
/= sizeof(WCHAR
);
557 TargetBufferA
= GetCommandHistoryRequest
->History
;
560 for (i
= 0; i
< Hist
->NumEntries
; i
++)
562 SourceLength
= Hist
->Entries
[i
].Length
/ sizeof(WCHAR
);
563 if (Offset
+ SourceLength
+ 1 > BufferSize
)
565 Status
= STATUS_BUFFER_OVERFLOW
;
569 if (GetCommandHistoryRequest
->Unicode
)
571 RtlCopyMemory(&TargetBufferW
[Offset
], Hist
->Entries
[i
].Buffer
, SourceLength
* sizeof(WCHAR
));
572 Offset
+= SourceLength
;
573 TargetBufferW
[Offset
++] = L
'\0';
577 ConvertInputUnicodeToAnsi(Console
,
578 Hist
->Entries
[i
].Buffer
, SourceLength
* sizeof(WCHAR
),
579 &TargetBufferA
[Offset
], SourceLength
);
580 Offset
+= SourceLength
;
581 TargetBufferA
[Offset
++] = '\0';
585 if (GetCommandHistoryRequest
->Unicode
)
586 BytesWritten
= Offset
* sizeof(WCHAR
);
588 BytesWritten
= Offset
;
591 // GetCommandHistoryRequest->HistoryLength = TargetBuffer - (PBYTE)GetCommandHistoryRequest->History;
592 GetCommandHistoryRequest
->HistoryLength
= BytesWritten
;
594 ConSrvReleaseConsole(Console
, TRUE
);
598 CSR_API(SrvGetConsoleCommandHistoryLength
)
601 PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryLengthRequest
;
602 PCONSRV_CONSOLE Console
;
603 PHISTORY_BUFFER Hist
;
607 if (!CsrValidateMessageBuffer(ApiMessage
,
608 (PVOID
*)&GetCommandHistoryLengthRequest
->ExeName
,
609 GetCommandHistoryLengthRequest
->ExeLength
,
612 return STATUS_INVALID_PARAMETER
;
615 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
616 if (!NT_SUCCESS(Status
)) return Status
;
618 Hist
= HistoryFindBuffer(Console
,
619 GetCommandHistoryLengthRequest
->ExeName
,
620 GetCommandHistoryLengthRequest
->ExeLength
,
621 GetCommandHistoryLengthRequest
->Unicode2
);
624 for (i
= 0; i
< Hist
->NumEntries
; i
++)
625 Length
+= Hist
->Entries
[i
].Length
+ sizeof(WCHAR
); // Each entry is returned NULL-terminated
628 * Quick and dirty way of getting the number of bytes of the
629 * corresponding ANSI string from the one in UNICODE.
631 if (!GetCommandHistoryLengthRequest
->Unicode
)
632 Length
/= sizeof(WCHAR
);
634 GetCommandHistoryLengthRequest
->HistoryLength
= Length
;
636 ConSrvReleaseConsole(Console
, TRUE
);
640 CSR_API(SrvExpungeConsoleCommandHistory
)
643 PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ExpungeCommandHistoryRequest
;
644 PCONSRV_CONSOLE Console
;
645 PHISTORY_BUFFER Hist
;
647 if (!CsrValidateMessageBuffer(ApiMessage
,
648 (PVOID
*)&ExpungeCommandHistoryRequest
->ExeName
,
649 ExpungeCommandHistoryRequest
->ExeLength
,
652 return STATUS_INVALID_PARAMETER
;
655 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
656 if (!NT_SUCCESS(Status
)) return Status
;
658 Hist
= HistoryFindBuffer(Console
,
659 ExpungeCommandHistoryRequest
->ExeName
,
660 ExpungeCommandHistoryRequest
->ExeLength
,
661 ExpungeCommandHistoryRequest
->Unicode2
);
662 HistoryDeleteBuffer(Hist
);
664 ConSrvReleaseConsole(Console
, TRUE
);
668 CSR_API(SrvSetConsoleNumberOfCommands
)
671 PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryNumberCommandsRequest
;
672 PCONSRV_CONSOLE Console
;
673 PHISTORY_BUFFER Hist
;
675 if (!CsrValidateMessageBuffer(ApiMessage
,
676 (PVOID
*)&SetHistoryNumberCommandsRequest
->ExeName
,
677 SetHistoryNumberCommandsRequest
->ExeLength
,
680 return STATUS_INVALID_PARAMETER
;
683 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
684 if (!NT_SUCCESS(Status
)) return Status
;
686 Hist
= HistoryFindBuffer(Console
,
687 SetHistoryNumberCommandsRequest
->ExeName
,
688 SetHistoryNumberCommandsRequest
->ExeLength
,
689 SetHistoryNumberCommandsRequest
->Unicode2
);
692 UINT MaxEntries
= SetHistoryNumberCommandsRequest
->NumCommands
;
693 PUNICODE_STRING OldEntryList
= Hist
->Entries
;
694 PUNICODE_STRING NewEntryList
= ConsoleAllocHeap(0, MaxEntries
* sizeof(UNICODE_STRING
));
697 Status
= STATUS_NO_MEMORY
;
701 /* If necessary, shrink by removing oldest entries */
702 for (; Hist
->NumEntries
> MaxEntries
; Hist
->NumEntries
--)
704 RtlFreeUnicodeString(Hist
->Entries
++);
705 Hist
->Position
+= (Hist
->Position
== 0);
708 Hist
->MaxEntries
= MaxEntries
;
709 Hist
->Entries
= memcpy(NewEntryList
, Hist
->Entries
,
710 Hist
->NumEntries
* sizeof(UNICODE_STRING
));
711 ConsoleFreeHeap(OldEntryList
);
715 ConSrvReleaseConsole(Console
, TRUE
);
719 CSR_API(SrvGetConsoleHistory
)
722 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
723 PCONSRV_CONSOLE Console
;
724 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
725 if (NT_SUCCESS(Status
))
727 HistoryInfoRequest
->HistoryBufferSize
= Console
->HistoryBufferSize
;
728 HistoryInfoRequest
->NumberOfHistoryBuffers
= Console
->NumberOfHistoryBuffers
;
729 HistoryInfoRequest
->dwFlags
= Console
->HistoryNoDup
;
730 ConSrvReleaseConsole(Console
, TRUE
);
734 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
735 return STATUS_NOT_IMPLEMENTED
;
739 CSR_API(SrvSetConsoleHistory
)
742 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
743 PCONSRV_CONSOLE Console
;
744 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
745 if (NT_SUCCESS(Status
))
747 Console
->HistoryBufferSize
= HistoryInfoRequest
->HistoryBufferSize
;
748 Console
->NumberOfHistoryBuffers
= HistoryInfoRequest
->NumberOfHistoryBuffers
;
749 Console
->HistoryNoDup
= HistoryInfoRequest
->dwFlags
& HISTORY_NO_DUP_FLAG
;
750 ConSrvReleaseConsole(Console
, TRUE
);
754 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
755 return STATUS_NOT_IMPLEMENTED
;
759 CSR_API(SrvSetConsoleCommandHistoryMode
)
762 PCONSOLE_SETHISTORYMODE SetHistoryModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryModeRequest
;
763 PCONSRV_CONSOLE Console
;
765 DPRINT1("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
766 SetHistoryModeRequest
->Mode
);
768 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
769 if (!NT_SUCCESS(Status
)) return Status
;
771 /* This API is not yet implemented */
772 Status
= STATUS_NOT_IMPLEMENTED
;
774 ConSrvReleaseConsole(Console
, TRUE
);