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(PCONSOLE Console
)
48 /* TODO: use actual EXE name sent from process that called ReadConsole */
49 UNICODE_STRING ExeName
= { 14, 14, L
"cmd.exe" };
50 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
53 for (; Entry
!= &Console
->HistoryBuffers
; Entry
= Entry
->Flink
)
55 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
56 if (RtlEqualUnicodeString(&ExeName
, &Hist
->ExeName
, FALSE
))
60 /* Couldn't find the buffer, create a new one */
61 Hist
= ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER
) + ExeName
.Length
);
62 if (!Hist
) return NULL
;
63 Hist
->MaxEntries
= Console
->HistoryBufferSize
;
65 Hist
->Entries
= ConsoleAllocHeap(0, Hist
->MaxEntries
* sizeof(UNICODE_STRING
));
68 ConsoleFreeHeap(Hist
);
71 Hist
->ExeName
.Length
= Hist
->ExeName
.MaximumLength
= ExeName
.Length
;
72 Hist
->ExeName
.Buffer
= (PWCHAR
)(Hist
+ 1);
73 memcpy(Hist
->ExeName
.Buffer
, ExeName
.Buffer
, ExeName
.Length
);
74 InsertHeadList(&Console
->HistoryBuffers
, &Hist
->ListEntry
);
79 HistoryAddEntry(PCONSOLE Console
)
81 UNICODE_STRING NewEntry
;
82 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
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(PCONSOLE Console
, PUNICODE_STRING Entry
)
132 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
134 if (!Hist
|| Hist
->NumEntries
== 0)
137 *Entry
= Hist
->Entries
[Hist
->Position
];
140 static PHISTORY_BUFFER
141 HistoryFindBuffer(PCONSOLE Console
,
146 UNICODE_STRING ExeNameU
;
149 PHISTORY_BUFFER Hist
= NULL
;
151 if (ExeName
== NULL
) return NULL
;
155 ExeNameU
.Buffer
= ExeName
;
156 /* Length is in bytes */
157 ExeNameU
.MaximumLength
= ExeLength
;
161 if (!ConvertInputAnsiToUnicode(Console
,
163 &ExeNameU
.Buffer
, &ExeNameU
.MaximumLength
))
168 ExeNameU
.Length
= ExeNameU
.MaximumLength
;
170 Entry
= Console
->HistoryBuffers
.Flink
;
171 while (Entry
!= &Console
->HistoryBuffers
)
173 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
175 /* For the history APIs, the caller is allowed to give only part of the name */
176 if (RtlPrefixUnicodeString(&ExeNameU
, &Hist
->ExeName
, TRUE
))
178 if (!UnicodeExe
) ConsoleFreeHeap(ExeNameU
.Buffer
);
182 Entry
= Entry
->Flink
;
185 if (!UnicodeExe
) ConsoleFreeHeap(ExeNameU
.Buffer
);
190 HistoryDeleteBuffer(PHISTORY_BUFFER Hist
)
194 while (Hist
->NumEntries
!= 0)
195 RtlFreeUnicodeString(&Hist
->Entries
[--Hist
->NumEntries
]);
197 ConsoleFreeHeap(Hist
->Entries
);
198 RemoveEntryList(&Hist
->ListEntry
);
199 ConsoleFreeHeap(Hist
);
203 HistoryDeleteBuffers(PCONSOLE Console
)
205 PLIST_ENTRY CurrentEntry
;
206 PHISTORY_BUFFER HistoryBuffer
;
208 while (!IsListEmpty(&Console
->HistoryBuffers
))
210 CurrentEntry
= RemoveHeadList(&Console
->HistoryBuffers
);
211 HistoryBuffer
= CONTAINING_RECORD(CurrentEntry
, HISTORY_BUFFER
, ListEntry
);
212 HistoryDeleteBuffer(HistoryBuffer
);
217 LineInputSetPos(PCONSOLE Console
, UINT Pos
)
219 if (Pos
!= Console
->LinePos
&& Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
221 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
222 SHORT OldCursorX
= Buffer
->CursorPosition
.X
;
223 SHORT OldCursorY
= Buffer
->CursorPosition
.Y
;
224 INT XY
= OldCursorY
* Buffer
->ScreenBufferSize
.X
+ OldCursorX
;
226 XY
+= (Pos
- Console
->LinePos
);
229 else if (XY
>= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
)
230 XY
= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
- 1;
232 Buffer
->CursorPosition
.X
= XY
% Buffer
->ScreenBufferSize
.X
;
233 Buffer
->CursorPosition
.Y
= XY
/ Buffer
->ScreenBufferSize
.X
;
234 TermSetScreenInfo(Console
, Buffer
, OldCursorX
, OldCursorY
);
237 Console
->LinePos
= Pos
;
241 LineInputEdit(PCONSOLE Console
, UINT NumToDelete
, UINT NumToInsert
, PWCHAR Insertion
)
243 PTEXTMODE_SCREEN_BUFFER ActiveBuffer
;
244 UINT Pos
= Console
->LinePos
;
245 UINT NewSize
= Console
->LineSize
- NumToDelete
+ NumToInsert
;
248 if (GetType(Console
->ActiveBuffer
) != TEXTMODE_BUFFER
) return;
249 ActiveBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Console
->ActiveBuffer
;
251 /* Make sure there's always enough room for ending \r\n */
252 if (NewSize
+ 2 > Console
->LineMaxSize
)
255 memmove(&Console
->LineBuffer
[Pos
+ NumToInsert
],
256 &Console
->LineBuffer
[Pos
+ NumToDelete
],
257 (Console
->LineSize
- (Pos
+ NumToDelete
)) * sizeof(WCHAR
));
258 memcpy(&Console
->LineBuffer
[Pos
], Insertion
, NumToInsert
* sizeof(WCHAR
));
260 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
262 for (i
= Pos
; i
< NewSize
; i
++)
264 ConioWriteConsole(Console
, ActiveBuffer
, &Console
->LineBuffer
[i
], 1, TRUE
);
266 for (; i
< Console
->LineSize
; i
++)
268 ConioWriteConsole(Console
, ActiveBuffer
, L
" ", 1, TRUE
);
270 Console
->LinePos
= i
;
273 Console
->LineSize
= NewSize
;
274 LineInputSetPos(Console
, Pos
+ NumToInsert
);
278 LineInputRecallHistory(PCONSOLE Console
, INT Offset
)
280 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
283 if (!Hist
|| Hist
->NumEntries
== 0) return;
285 Position
= Hist
->Position
+ Offset
;
286 Position
= min(max(Position
, 0), Hist
->NumEntries
- 1);
287 Hist
->Position
= Position
;
289 LineInputSetPos(Console
, 0);
290 LineInputEdit(Console
, Console
->LineSize
,
291 Hist
->Entries
[Hist
->Position
].Length
/ sizeof(WCHAR
),
292 Hist
->Entries
[Hist
->Position
].Buffer
);
296 LineInputKeyDown(PCONSOLE Console
, KEY_EVENT_RECORD
*KeyEvent
)
298 UINT Pos
= Console
->LinePos
;
299 PHISTORY_BUFFER Hist
;
300 UNICODE_STRING Entry
;
303 switch (KeyEvent
->wVirtualKeyCode
)
306 /* Clear entire line */
307 LineInputSetPos(Console
, 0);
308 LineInputEdit(Console
, Console
->LineSize
, 0, NULL
);
311 /* Move to start of line. With ctrl, erase everything left of cursor */
312 LineInputSetPos(Console
, 0);
313 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
314 LineInputEdit(Console
, Pos
, 0, NULL
);
317 /* Move to end of line. With ctrl, erase everything right of cursor */
318 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
319 LineInputEdit(Console
, Console
->LineSize
- Pos
, 0, NULL
);
321 LineInputSetPos(Console
, Console
->LineSize
);
324 /* Move left. With ctrl, move to beginning of previous word */
325 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
327 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] == L
' ') Pos
--;
328 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] != L
' ') Pos
--;
334 LineInputSetPos(Console
, Pos
);
338 /* Move right. With ctrl, move to beginning of next word */
339 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
341 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] != L
' ') Pos
++;
342 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] == L
' ') Pos
++;
343 LineInputSetPos(Console
, Pos
);
348 /* Recall one character (but don't overwrite current line) */
349 HistoryGetCurrentEntry(Console
, &Entry
);
350 if (Pos
< Console
->LineSize
)
351 LineInputSetPos(Console
, Pos
+ 1);
352 else if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
353 LineInputEdit(Console
, 0, 1, &Entry
.Buffer
[Pos
]);
357 /* Toggle between insert and overstrike */
358 Console
->LineInsertToggle
= !Console
->LineInsertToggle
;
359 TermSetCursorInfo(Console
, Console
->ActiveBuffer
);
362 /* Remove character to right of cursor */
363 if (Pos
!= Console
->LineSize
)
364 LineInputEdit(Console
, 1, 0, NULL
);
367 /* Recall first history entry */
368 LineInputRecallHistory(Console
, -((WORD
)-1));
371 /* Recall last history entry */
372 LineInputRecallHistory(Console
, +((WORD
)-1));
376 /* Recall previous history entry. On first time, actually recall the
377 * current (usually last) entry; on subsequent times go back. */
378 LineInputRecallHistory(Console
, Console
->LineUpPressed
? -1 : 0);
379 Console
->LineUpPressed
= TRUE
;
382 /* Recall next history entry */
383 LineInputRecallHistory(Console
, +1);
386 /* Recall remainder of current history entry */
387 HistoryGetCurrentEntry(Console
, &Entry
);
388 if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
390 UINT InsertSize
= (Entry
.Length
/ sizeof(WCHAR
) - Pos
);
391 UINT DeleteSize
= min(Console
->LineSize
- Pos
, InsertSize
);
392 LineInputEdit(Console
, DeleteSize
, InsertSize
, &Entry
.Buffer
[Pos
]);
396 /* Insert a ^Z character */
397 KeyEvent
->uChar
.UnicodeChar
= 26;
400 if (KeyEvent
->dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
401 HistoryDeleteBuffer(HistoryCurrentBuffer(Console
));
404 /* Search for history entries starting with input. */
405 Hist
= HistoryCurrentBuffer(Console
);
406 if (!Hist
|| Hist
->NumEntries
== 0) return;
408 /* Like Up/F5, on first time start from current (usually last) entry,
409 * but on subsequent times start at previous entry. */
410 if (Console
->LineUpPressed
)
411 Hist
->Position
= (Hist
->Position
? Hist
->Position
: Hist
->NumEntries
) - 1;
412 Console
->LineUpPressed
= TRUE
;
414 Entry
.Length
= Console
->LinePos
* sizeof(WCHAR
);
415 Entry
.Buffer
= Console
->LineBuffer
;
417 /* Keep going backwards, even wrapping around to the end,
418 * until we get back to starting point */
419 HistPos
= Hist
->Position
;
422 if (RtlPrefixUnicodeString(&Entry
, &Hist
->Entries
[HistPos
], FALSE
))
424 Hist
->Position
= HistPos
;
425 LineInputEdit(Console
, Console
->LineSize
- Pos
,
426 Hist
->Entries
[HistPos
].Length
/ sizeof(WCHAR
) - Pos
,
427 &Hist
->Entries
[HistPos
].Buffer
[Pos
]);
428 /* Cursor stays where it was */
429 LineInputSetPos(Console
, Pos
);
432 if (--HistPos
< 0) HistPos
+= Hist
->NumEntries
;
433 } while (HistPos
!= Hist
->Position
);
437 if (KeyEvent
->uChar
.UnicodeChar
== L
'\b' && Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
)
439 /* backspace handling - if processed input enabled then we handle it here
440 * otherwise we treat it like a normal char. */
443 LineInputSetPos(Console
, Pos
- 1);
444 LineInputEdit(Console
, 1, 0, NULL
);
447 else if (KeyEvent
->uChar
.UnicodeChar
== L
'\r')
449 HistoryAddEntry(Console
);
451 /* TODO: Expand aliases */
453 LineInputSetPos(Console
, Console
->LineSize
);
454 Console
->LineBuffer
[Console
->LineSize
++] = L
'\r';
455 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
457 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
459 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\r", 1, TRUE
);
463 /* Add \n if processed input. There should usually be room for it,
464 * but an exception to the rule exists: the buffer could have been
465 * pre-filled with LineMaxSize - 1 characters. */
466 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
467 Console
->LineSize
< Console
->LineMaxSize
)
469 Console
->LineBuffer
[Console
->LineSize
++] = L
'\n';
470 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
472 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
474 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\n", 1, TRUE
);
478 Console
->LineComplete
= TRUE
;
479 Console
->LinePos
= 0;
481 else if (KeyEvent
->uChar
.UnicodeChar
!= L
'\0')
483 if (KeyEvent
->uChar
.UnicodeChar
< 0x20 &&
484 Console
->LineWakeupMask
& (1 << KeyEvent
->uChar
.UnicodeChar
))
486 /* Control key client wants to handle itself (e.g. for tab completion) */
487 Console
->LineBuffer
[Console
->LineSize
++] = L
' ';
488 Console
->LineBuffer
[Console
->LinePos
] = KeyEvent
->uChar
.UnicodeChar
;
489 Console
->LineComplete
= TRUE
;
490 Console
->LinePos
= 0;
494 /* Normal character */
495 BOOL Overstrike
= !Console
->LineInsertToggle
&& (Console
->LinePos
!= Console
->LineSize
);
496 LineInputEdit(Console
, (Overstrike
? 1 : 0), 1, &KeyEvent
->uChar
.UnicodeChar
);
502 /* PUBLIC SERVER APIS *********************************************************/
504 CSR_API(SrvGetConsoleCommandHistory
)
507 PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryRequest
;
509 ULONG BytesWritten
= 0;
510 PHISTORY_BUFFER Hist
;
512 DPRINT1("SrvGetConsoleCommandHistory entered\n");
514 if ( !CsrValidateMessageBuffer(ApiMessage
,
515 (PVOID
*)&GetCommandHistoryRequest
->History
,
516 GetCommandHistoryRequest
->HistoryLength
,
518 !CsrValidateMessageBuffer(ApiMessage
,
519 (PVOID
*)&GetCommandHistoryRequest
->ExeName
,
520 GetCommandHistoryRequest
->ExeLength
,
523 return STATUS_INVALID_PARAMETER
;
526 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
527 if (!NT_SUCCESS(Status
)) return Status
;
529 Hist
= HistoryFindBuffer(Console
,
530 GetCommandHistoryRequest
->ExeName
,
531 GetCommandHistoryRequest
->ExeLength
,
532 GetCommandHistoryRequest
->Unicode2
);
538 LPWSTR TargetBufferW
;
539 ULONG BufferSize
= GetCommandHistoryRequest
->HistoryLength
;
544 if (GetCommandHistoryRequest
->Unicode
)
546 TargetBufferW
= GetCommandHistoryRequest
->History
;
547 BufferSize
/= sizeof(WCHAR
);
551 TargetBufferA
= GetCommandHistoryRequest
->History
;
554 for (i
= 0; i
< Hist
->NumEntries
; i
++)
556 SourceLength
= Hist
->Entries
[i
].Length
/ sizeof(WCHAR
);
557 if (Offset
+ SourceLength
+ 1 > BufferSize
)
559 Status
= STATUS_BUFFER_OVERFLOW
;
563 if (GetCommandHistoryRequest
->Unicode
)
565 RtlCopyMemory(&TargetBufferW
[Offset
], Hist
->Entries
[i
].Buffer
, SourceLength
* sizeof(WCHAR
));
566 Offset
+= SourceLength
;
567 TargetBufferW
[Offset
++] = L
'\0';
571 ConvertInputUnicodeToAnsi(Console
,
572 Hist
->Entries
[i
].Buffer
, SourceLength
* sizeof(WCHAR
),
573 &TargetBufferA
[Offset
], SourceLength
);
574 Offset
+= SourceLength
;
575 TargetBufferA
[Offset
++] = '\0';
579 if (GetCommandHistoryRequest
->Unicode
)
580 BytesWritten
= Offset
* sizeof(WCHAR
);
582 BytesWritten
= Offset
;
585 // GetCommandHistoryRequest->HistoryLength = TargetBuffer - (PBYTE)GetCommandHistoryRequest->History;
586 GetCommandHistoryRequest
->HistoryLength
= BytesWritten
;
588 ConSrvReleaseConsole(Console
, TRUE
);
592 CSR_API(SrvGetConsoleCommandHistoryLength
)
595 PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryLengthRequest
;
597 PHISTORY_BUFFER Hist
;
601 if (!CsrValidateMessageBuffer(ApiMessage
,
602 (PVOID
*)&GetCommandHistoryLengthRequest
->ExeName
,
603 GetCommandHistoryLengthRequest
->ExeLength
,
606 return STATUS_INVALID_PARAMETER
;
609 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
610 if (!NT_SUCCESS(Status
)) return Status
;
612 Hist
= HistoryFindBuffer(Console
,
613 GetCommandHistoryLengthRequest
->ExeName
,
614 GetCommandHistoryLengthRequest
->ExeLength
,
615 GetCommandHistoryLengthRequest
->Unicode2
);
618 for (i
= 0; i
< Hist
->NumEntries
; i
++)
619 Length
+= Hist
->Entries
[i
].Length
+ sizeof(WCHAR
); // Each entry is returned NULL-terminated
622 * Quick and dirty way of getting the number of bytes of the
623 * corresponding ANSI string from the one in UNICODE.
625 if (!GetCommandHistoryLengthRequest
->Unicode
)
626 Length
/= sizeof(WCHAR
);
628 GetCommandHistoryLengthRequest
->HistoryLength
= Length
;
630 ConSrvReleaseConsole(Console
, TRUE
);
634 CSR_API(SrvExpungeConsoleCommandHistory
)
637 PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ExpungeCommandHistoryRequest
;
639 PHISTORY_BUFFER Hist
;
641 if (!CsrValidateMessageBuffer(ApiMessage
,
642 (PVOID
*)&ExpungeCommandHistoryRequest
->ExeName
,
643 ExpungeCommandHistoryRequest
->ExeLength
,
646 return STATUS_INVALID_PARAMETER
;
649 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
650 if (!NT_SUCCESS(Status
)) return Status
;
652 Hist
= HistoryFindBuffer(Console
,
653 ExpungeCommandHistoryRequest
->ExeName
,
654 ExpungeCommandHistoryRequest
->ExeLength
,
655 ExpungeCommandHistoryRequest
->Unicode2
);
656 HistoryDeleteBuffer(Hist
);
658 ConSrvReleaseConsole(Console
, TRUE
);
662 CSR_API(SrvSetConsoleNumberOfCommands
)
665 PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryNumberCommandsRequest
;
667 PHISTORY_BUFFER Hist
;
669 if (!CsrValidateMessageBuffer(ApiMessage
,
670 (PVOID
*)&SetHistoryNumberCommandsRequest
->ExeName
,
671 SetHistoryNumberCommandsRequest
->ExeLength
,
674 return STATUS_INVALID_PARAMETER
;
677 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
678 if (!NT_SUCCESS(Status
)) return Status
;
680 Hist
= HistoryFindBuffer(Console
,
681 SetHistoryNumberCommandsRequest
->ExeName
,
682 SetHistoryNumberCommandsRequest
->ExeLength
,
683 SetHistoryNumberCommandsRequest
->Unicode2
);
686 UINT MaxEntries
= SetHistoryNumberCommandsRequest
->NumCommands
;
687 PUNICODE_STRING OldEntryList
= Hist
->Entries
;
688 PUNICODE_STRING NewEntryList
= ConsoleAllocHeap(0, MaxEntries
* sizeof(UNICODE_STRING
));
691 Status
= STATUS_NO_MEMORY
;
695 /* If necessary, shrink by removing oldest entries */
696 for (; Hist
->NumEntries
> MaxEntries
; Hist
->NumEntries
--)
698 RtlFreeUnicodeString(Hist
->Entries
++);
699 Hist
->Position
+= (Hist
->Position
== 0);
702 Hist
->MaxEntries
= MaxEntries
;
703 Hist
->Entries
= memcpy(NewEntryList
, Hist
->Entries
,
704 Hist
->NumEntries
* sizeof(UNICODE_STRING
));
705 ConsoleFreeHeap(OldEntryList
);
709 ConSrvReleaseConsole(Console
, TRUE
);
713 CSR_API(SrvGetConsoleHistory
)
716 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
718 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
719 if (NT_SUCCESS(Status
))
721 HistoryInfoRequest
->HistoryBufferSize
= Console
->HistoryBufferSize
;
722 HistoryInfoRequest
->NumberOfHistoryBuffers
= Console
->NumberOfHistoryBuffers
;
723 HistoryInfoRequest
->dwFlags
= Console
->HistoryNoDup
;
724 ConSrvReleaseConsole(Console
, TRUE
);
728 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
729 return STATUS_NOT_IMPLEMENTED
;
733 CSR_API(SrvSetConsoleHistory
)
736 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
738 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
739 if (NT_SUCCESS(Status
))
741 Console
->HistoryBufferSize
= HistoryInfoRequest
->HistoryBufferSize
;
742 Console
->NumberOfHistoryBuffers
= HistoryInfoRequest
->NumberOfHistoryBuffers
;
743 Console
->HistoryNoDup
= HistoryInfoRequest
->dwFlags
& HISTORY_NO_DUP_FLAG
;
744 ConSrvReleaseConsole(Console
, TRUE
);
748 DPRINT1("%s not yet implemented\n", __FUNCTION__
);
749 return STATUS_NOT_IMPLEMENTED
;
753 CSR_API(SrvSetConsoleCommandHistoryMode
)
756 PCONSOLE_SETHISTORYMODE SetHistoryModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryModeRequest
;
759 DPRINT1("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
760 SetHistoryModeRequest
->Mode
);
762 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
763 if (!NT_SUCCESS(Status
)) return Status
;
765 /* This API is not yet implemented */
766 Status
= STATUS_NOT_IMPLEMENTED
;
768 ConSrvReleaseConsole(Console
, TRUE
);