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
8 * NOTE: It's something frontend-related... (--> read my mind... ;) )
11 /* INCLUDES *******************************************************************/
18 typedef struct _HISTORY_BUFFER
24 PUNICODE_STRING Entries
;
25 UNICODE_STRING ExeName
;
26 } HISTORY_BUFFER
, *PHISTORY_BUFFER
;
29 /* PRIVATE FUNCTIONS **********************************************************/
31 static PHISTORY_BUFFER
32 HistoryCurrentBuffer(PCONSOLE Console
)
34 /* TODO: use actual EXE name sent from process that called ReadConsole */
35 UNICODE_STRING ExeName
= { 14, 14, L
"cmd.exe" };
36 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
39 for (; Entry
!= &Console
->HistoryBuffers
; Entry
= Entry
->Flink
)
41 Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
42 if (RtlEqualUnicodeString(&ExeName
, &Hist
->ExeName
, FALSE
))
46 /* Couldn't find the buffer, create a new one */
47 Hist
= ConsoleAllocHeap(0, sizeof(HISTORY_BUFFER
) + ExeName
.Length
);
48 if (!Hist
) return NULL
;
49 Hist
->MaxEntries
= Console
->HistoryBufferSize
;
51 Hist
->Entries
= ConsoleAllocHeap(0, Hist
->MaxEntries
* sizeof(UNICODE_STRING
));
54 ConsoleFreeHeap(Hist
);
57 Hist
->ExeName
.Length
= Hist
->ExeName
.MaximumLength
= ExeName
.Length
;
58 Hist
->ExeName
.Buffer
= (PWCHAR
)(Hist
+ 1);
59 memcpy(Hist
->ExeName
.Buffer
, ExeName
.Buffer
, ExeName
.Length
);
60 InsertHeadList(&Console
->HistoryBuffers
, &Hist
->ListEntry
);
65 HistoryAddEntry(PCONSOLE Console
)
67 UNICODE_STRING NewEntry
;
68 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
73 NewEntry
.Length
= NewEntry
.MaximumLength
= Console
->LineSize
* sizeof(WCHAR
);
74 NewEntry
.Buffer
= Console
->LineBuffer
;
76 /* Don't add blank or duplicate entries */
77 if (NewEntry
.Length
== 0 || Hist
->MaxEntries
== 0 ||
78 (Hist
->NumEntries
> 0 &&
79 RtlEqualUnicodeString(&Hist
->Entries
[Hist
->NumEntries
- 1], &NewEntry
, FALSE
)))
84 if (Console
->HistoryNoDup
)
86 /* Check if this line has been entered before */
87 for (i
= Hist
->NumEntries
- 1; i
>= 0; i
--)
89 if (RtlEqualUnicodeString(&Hist
->Entries
[i
], &NewEntry
, FALSE
))
91 /* Just rotate the list to bring this entry to the end */
92 NewEntry
= Hist
->Entries
[i
];
93 memmove(&Hist
->Entries
[i
], &Hist
->Entries
[i
+ 1],
94 (Hist
->NumEntries
- (i
+ 1)) * sizeof(UNICODE_STRING
));
95 Hist
->Entries
[Hist
->NumEntries
- 1] = NewEntry
;
96 Hist
->Position
= Hist
->NumEntries
- 1;
102 if (Hist
->NumEntries
== Hist
->MaxEntries
)
104 /* List is full, remove oldest entry */
105 RtlFreeUnicodeString(&Hist
->Entries
[0]);
106 memmove(&Hist
->Entries
[0], &Hist
->Entries
[1],
107 --Hist
->NumEntries
* sizeof(UNICODE_STRING
));
110 if (NT_SUCCESS(RtlDuplicateUnicodeString(0, &NewEntry
, &Hist
->Entries
[Hist
->NumEntries
])))
112 Hist
->Position
= Hist
->NumEntries
- 1;
116 HistoryGetCurrentEntry(PCONSOLE Console
, PUNICODE_STRING Entry
)
118 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
120 if (!Hist
|| Hist
->NumEntries
== 0)
123 *Entry
= Hist
->Entries
[Hist
->Position
];
126 static PHISTORY_BUFFER
127 HistoryFindBuffer(PCONSOLE Console
, PUNICODE_STRING ExeName
)
129 PLIST_ENTRY Entry
= Console
->HistoryBuffers
.Flink
;
130 while (Entry
!= &Console
->HistoryBuffers
)
132 /* For the history APIs, the caller is allowed to give only part of the name */
133 PHISTORY_BUFFER Hist
= CONTAINING_RECORD(Entry
, HISTORY_BUFFER
, ListEntry
);
134 if (RtlPrefixUnicodeString(ExeName
, &Hist
->ExeName
, TRUE
))
136 Entry
= Entry
->Flink
;
142 HistoryDeleteBuffer(PHISTORY_BUFFER Hist
)
146 while (Hist
->NumEntries
!= 0)
147 RtlFreeUnicodeString(&Hist
->Entries
[--Hist
->NumEntries
]);
149 ConsoleFreeHeap(Hist
->Entries
);
150 RemoveEntryList(&Hist
->ListEntry
);
151 ConsoleFreeHeap(Hist
);
155 HistoryDeleteBuffers(PCONSOLE Console
)
157 PLIST_ENTRY CurrentEntry
;
158 PHISTORY_BUFFER HistoryBuffer
;
160 while (!IsListEmpty(&Console
->HistoryBuffers
))
162 CurrentEntry
= RemoveHeadList(&Console
->HistoryBuffers
);
163 HistoryBuffer
= CONTAINING_RECORD(CurrentEntry
, HISTORY_BUFFER
, ListEntry
);
164 HistoryDeleteBuffer(HistoryBuffer
);
169 LineInputSetPos(PCONSOLE Console
, UINT Pos
)
171 if (Pos
!= Console
->LinePos
&& Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
173 PCONSOLE_SCREEN_BUFFER Buffer
= Console
->ActiveBuffer
;
174 SHORT OldCursorX
= Buffer
->CursorPosition
.X
;
175 SHORT OldCursorY
= Buffer
->CursorPosition
.Y
;
176 INT XY
= OldCursorY
* Buffer
->ScreenBufferSize
.X
+ OldCursorX
;
178 XY
+= (Pos
- Console
->LinePos
);
181 else if (XY
>= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
)
182 XY
= Buffer
->ScreenBufferSize
.Y
* Buffer
->ScreenBufferSize
.X
- 1;
184 Buffer
->CursorPosition
.X
= XY
% Buffer
->ScreenBufferSize
.X
;
185 Buffer
->CursorPosition
.Y
= XY
/ Buffer
->ScreenBufferSize
.X
;
186 TermSetScreenInfo(Console
, Buffer
, OldCursorX
, OldCursorY
);
189 Console
->LinePos
= Pos
;
193 LineInputEdit(PCONSOLE Console
, UINT NumToDelete
, UINT NumToInsert
, WCHAR
*Insertion
)
195 PTEXTMODE_SCREEN_BUFFER ActiveBuffer
;
196 UINT Pos
= Console
->LinePos
;
197 UINT NewSize
= Console
->LineSize
- NumToDelete
+ NumToInsert
;
200 if (GetType(Console
->ActiveBuffer
) != TEXTMODE_BUFFER
) return;
201 ActiveBuffer
= (PTEXTMODE_SCREEN_BUFFER
)Console
->ActiveBuffer
;
203 /* Make sure there's always enough room for ending \r\n */
204 if (NewSize
+ 2 > Console
->LineMaxSize
)
207 memmove(&Console
->LineBuffer
[Pos
+ NumToInsert
],
208 &Console
->LineBuffer
[Pos
+ NumToDelete
],
209 (Console
->LineSize
- (Pos
+ NumToDelete
)) * sizeof(WCHAR
));
210 memcpy(&Console
->LineBuffer
[Pos
], Insertion
, NumToInsert
* sizeof(WCHAR
));
212 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
214 for (i
= Pos
; i
< NewSize
; i
++)
216 ConioWriteConsole(Console
, ActiveBuffer
, &Console
->LineBuffer
[i
], 1, TRUE
);
218 for (; i
< Console
->LineSize
; i
++)
220 ConioWriteConsole(Console
, ActiveBuffer
, L
" ", 1, TRUE
);
222 Console
->LinePos
= i
;
225 Console
->LineSize
= NewSize
;
226 LineInputSetPos(Console
, Pos
+ NumToInsert
);
230 LineInputRecallHistory(PCONSOLE Console
, INT Offset
)
232 PHISTORY_BUFFER Hist
= HistoryCurrentBuffer(Console
);
235 if (!Hist
|| Hist
->NumEntries
== 0) return;
237 Position
= Hist
->Position
+ Offset
;
238 Position
= min(max(Position
, 0), Hist
->NumEntries
- 1);
239 Hist
->Position
= Position
;
241 LineInputSetPos(Console
, 0);
242 LineInputEdit(Console
, Console
->LineSize
,
243 Hist
->Entries
[Hist
->Position
].Length
/ sizeof(WCHAR
),
244 Hist
->Entries
[Hist
->Position
].Buffer
);
248 LineInputKeyDown(PCONSOLE Console
, KEY_EVENT_RECORD
*KeyEvent
)
250 UINT Pos
= Console
->LinePos
;
251 PHISTORY_BUFFER Hist
;
252 UNICODE_STRING Entry
;
255 switch (KeyEvent
->wVirtualKeyCode
)
258 /* Clear entire line */
259 LineInputSetPos(Console
, 0);
260 LineInputEdit(Console
, Console
->LineSize
, 0, NULL
);
263 /* Move to start of line. With ctrl, erase everything left of cursor */
264 LineInputSetPos(Console
, 0);
265 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
266 LineInputEdit(Console
, Pos
, 0, NULL
);
269 /* Move to end of line. With ctrl, erase everything right of cursor */
270 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
271 LineInputEdit(Console
, Console
->LineSize
- Pos
, 0, NULL
);
273 LineInputSetPos(Console
, Console
->LineSize
);
276 /* Move left. With ctrl, move to beginning of previous word */
277 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
279 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] == L
' ') Pos
--;
280 while (Pos
> 0 && Console
->LineBuffer
[Pos
- 1] != L
' ') Pos
--;
286 LineInputSetPos(Console
, Pos
);
290 /* Move right. With ctrl, move to beginning of next word */
291 if (KeyEvent
->dwControlKeyState
& (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
))
293 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] != L
' ') Pos
++;
294 while (Pos
< Console
->LineSize
&& Console
->LineBuffer
[Pos
] == L
' ') Pos
++;
295 LineInputSetPos(Console
, Pos
);
300 /* Recall one character (but don't overwrite current line) */
301 HistoryGetCurrentEntry(Console
, &Entry
);
302 if (Pos
< Console
->LineSize
)
303 LineInputSetPos(Console
, Pos
+ 1);
304 else if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
305 LineInputEdit(Console
, 0, 1, &Entry
.Buffer
[Pos
]);
309 /* Toggle between insert and overstrike */
310 Console
->LineInsertToggle
= !Console
->LineInsertToggle
;
311 TermSetCursorInfo(Console
, Console
->ActiveBuffer
);
314 /* Remove character to right of cursor */
315 if (Pos
!= Console
->LineSize
)
316 LineInputEdit(Console
, 1, 0, NULL
);
319 /* Recall first history entry */
320 LineInputRecallHistory(Console
, -((WORD
)-1));
323 /* Recall last history entry */
324 LineInputRecallHistory(Console
, +((WORD
)-1));
328 /* Recall previous history entry. On first time, actually recall the
329 * current (usually last) entry; on subsequent times go back. */
330 LineInputRecallHistory(Console
, Console
->LineUpPressed
? -1 : 0);
331 Console
->LineUpPressed
= TRUE
;
334 /* Recall next history entry */
335 LineInputRecallHistory(Console
, +1);
338 /* Recall remainder of current history entry */
339 HistoryGetCurrentEntry(Console
, &Entry
);
340 if (Pos
* sizeof(WCHAR
) < Entry
.Length
)
342 UINT InsertSize
= (Entry
.Length
/ sizeof(WCHAR
) - Pos
);
343 UINT DeleteSize
= min(Console
->LineSize
- Pos
, InsertSize
);
344 LineInputEdit(Console
, DeleteSize
, InsertSize
, &Entry
.Buffer
[Pos
]);
348 /* Insert a ^Z character */
349 KeyEvent
->uChar
.UnicodeChar
= 26;
352 if (KeyEvent
->dwControlKeyState
& (LEFT_ALT_PRESSED
| RIGHT_ALT_PRESSED
))
353 HistoryDeleteBuffer(HistoryCurrentBuffer(Console
));
356 /* Search for history entries starting with input. */
357 Hist
= HistoryCurrentBuffer(Console
);
358 if (!Hist
|| Hist
->NumEntries
== 0) return;
360 /* Like Up/F5, on first time start from current (usually last) entry,
361 * but on subsequent times start at previous entry. */
362 if (Console
->LineUpPressed
)
363 Hist
->Position
= (Hist
->Position
? Hist
->Position
: Hist
->NumEntries
) - 1;
364 Console
->LineUpPressed
= TRUE
;
366 Entry
.Length
= Console
->LinePos
* sizeof(WCHAR
);
367 Entry
.Buffer
= Console
->LineBuffer
;
369 /* Keep going backwards, even wrapping around to the end,
370 * until we get back to starting point */
371 HistPos
= Hist
->Position
;
374 if (RtlPrefixUnicodeString(&Entry
, &Hist
->Entries
[HistPos
], FALSE
))
376 Hist
->Position
= HistPos
;
377 LineInputEdit(Console
, Console
->LineSize
- Pos
,
378 Hist
->Entries
[HistPos
].Length
/ sizeof(WCHAR
) - Pos
,
379 &Hist
->Entries
[HistPos
].Buffer
[Pos
]);
380 /* Cursor stays where it was */
381 LineInputSetPos(Console
, Pos
);
384 if (--HistPos
< 0) HistPos
+= Hist
->NumEntries
;
385 } while (HistPos
!= Hist
->Position
);
389 if (KeyEvent
->uChar
.UnicodeChar
== L
'\b' && Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
)
391 /* backspace handling - if processed input enabled then we handle it here
392 * otherwise we treat it like a normal char. */
395 LineInputSetPos(Console
, Pos
- 1);
396 LineInputEdit(Console
, 1, 0, NULL
);
399 else if (KeyEvent
->uChar
.UnicodeChar
== L
'\r')
401 HistoryAddEntry(Console
);
403 /* TODO: Expand aliases */
405 LineInputSetPos(Console
, Console
->LineSize
);
406 Console
->LineBuffer
[Console
->LineSize
++] = L
'\r';
407 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
409 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
411 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\r", 1, TRUE
);
415 /* Add \n if processed input. There should usually be room for it,
416 * but an exception to the rule exists: the buffer could have been
417 * pre-filled with LineMaxSize - 1 characters. */
418 if (Console
->InputBuffer
.Mode
& ENABLE_PROCESSED_INPUT
&&
419 Console
->LineSize
< Console
->LineMaxSize
)
421 Console
->LineBuffer
[Console
->LineSize
++] = L
'\n';
422 if (Console
->InputBuffer
.Mode
& ENABLE_ECHO_INPUT
)
424 if (GetType(Console
->ActiveBuffer
) == TEXTMODE_BUFFER
)
426 ConioWriteConsole(Console
, (PTEXTMODE_SCREEN_BUFFER
)(Console
->ActiveBuffer
), L
"\n", 1, TRUE
);
430 Console
->LineComplete
= TRUE
;
431 Console
->LinePos
= 0;
433 else if (KeyEvent
->uChar
.UnicodeChar
!= L
'\0')
435 if (KeyEvent
->uChar
.UnicodeChar
< 0x20 &&
436 Console
->LineWakeupMask
& (1 << KeyEvent
->uChar
.UnicodeChar
))
438 /* Control key client wants to handle itself (e.g. for tab completion) */
439 Console
->LineBuffer
[Console
->LineSize
++] = L
' ';
440 Console
->LineBuffer
[Console
->LinePos
] = KeyEvent
->uChar
.UnicodeChar
;
441 Console
->LineComplete
= TRUE
;
442 Console
->LinePos
= 0;
446 /* Normal character */
447 BOOL Overstrike
= !Console
->LineInsertToggle
&& (Console
->LinePos
!= Console
->LineSize
);
448 LineInputEdit(Console
, (Overstrike
? 1 : 0), 1, &KeyEvent
->uChar
.UnicodeChar
);
454 /* PUBLIC SERVER APIS *********************************************************/
456 CSR_API(SrvGetConsoleCommandHistory
)
459 PCONSOLE_GETCOMMANDHISTORY GetCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryRequest
;
461 PHISTORY_BUFFER Hist
;
462 UNICODE_STRING ExeName
;
463 PBYTE Buffer
= (PBYTE
)GetCommandHistoryRequest
->History
;
464 ULONG BufferSize
= GetCommandHistoryRequest
->HistoryLength
;
467 if ( !CsrValidateMessageBuffer(ApiMessage
,
468 (PVOID
*)&GetCommandHistoryRequest
->History
,
469 GetCommandHistoryRequest
->HistoryLength
,
471 !CsrValidateMessageBuffer(ApiMessage
,
472 (PVOID
*)&GetCommandHistoryRequest
->ExeName
,
473 GetCommandHistoryRequest
->ExeLength
,
476 return STATUS_INVALID_PARAMETER
;
479 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
480 if (!NT_SUCCESS(Status
)) return Status
;
482 // FIXME: convert to UNICODE if Unicode(2) == FALSE
483 ExeName
.Length
= ExeName
.MaximumLength
= GetCommandHistoryRequest
->ExeLength
;
484 ExeName
.Buffer
= GetCommandHistoryRequest
->ExeName
;
486 Hist
= HistoryFindBuffer(Console
, &ExeName
);
489 for (i
= 0; i
< Hist
->NumEntries
; i
++)
491 if (BufferSize
< (Hist
->Entries
[i
].Length
+ sizeof(WCHAR
)))
493 Status
= STATUS_BUFFER_OVERFLOW
;
496 // FIXME: convert to UNICODE if Unicode == FALSE
497 memcpy(Buffer
, Hist
->Entries
[i
].Buffer
, Hist
->Entries
[i
].Length
);
498 Buffer
+= Hist
->Entries
[i
].Length
;
499 *(PWCHAR
)Buffer
= L
'\0';
500 Buffer
+= sizeof(WCHAR
);
503 // WideCharToMultiByte(CP_ACP, 0,
504 // GetCommandHistoryRequest->History,
505 // GetCommandHistoryRequest->HistoryLength / sizeof(WCHAR),
513 // FIXME: convert to UNICODE if Unicode == FALSE
514 GetCommandHistoryRequest
->HistoryLength
= Buffer
- (PBYTE
)GetCommandHistoryRequest
->History
;
516 ConSrvReleaseConsole(Console
, TRUE
);
520 CSR_API(SrvGetConsoleCommandHistoryLength
)
523 PCONSOLE_GETCOMMANDHISTORYLENGTH GetCommandHistoryLengthRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.GetCommandHistoryLengthRequest
;
525 PHISTORY_BUFFER Hist
;
526 UNICODE_STRING ExeName
;
530 if (!CsrValidateMessageBuffer(ApiMessage
,
531 (PVOID
*)&GetCommandHistoryLengthRequest
->ExeName
,
532 GetCommandHistoryLengthRequest
->ExeLength
,
535 return STATUS_INVALID_PARAMETER
;
538 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
539 if (!NT_SUCCESS(Status
)) return Status
;
541 // FIXME: convert to UNICODE if Unicode(2) == FALSE
542 ExeName
.Length
= ExeName
.MaximumLength
= GetCommandHistoryLengthRequest
->ExeLength
;
543 ExeName
.Buffer
= GetCommandHistoryLengthRequest
->ExeName
;
545 Hist
= HistoryFindBuffer(Console
, &ExeName
);
548 for (i
= 0; i
< Hist
->NumEntries
; i
++)
549 Length
+= Hist
->Entries
[i
].Length
+ sizeof(WCHAR
);
551 GetCommandHistoryLengthRequest
->HistoryLength
= Length
;
554 * Quick and dirty way of getting the number of bytes of the
555 * corresponding ANSI string from the one in UNICODE.
557 if (!GetCommandHistoryLengthRequest
->Unicode
)
558 GetCommandHistoryLengthRequest
->HistoryLength
/= sizeof(WCHAR
);
560 ConSrvReleaseConsole(Console
, TRUE
);
564 CSR_API(SrvExpungeConsoleCommandHistory
)
567 PCONSOLE_EXPUNGECOMMANDHISTORY ExpungeCommandHistoryRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.ExpungeCommandHistoryRequest
;
569 PHISTORY_BUFFER Hist
;
570 UNICODE_STRING ExeName
;
572 if (!CsrValidateMessageBuffer(ApiMessage
,
573 (PVOID
*)&ExpungeCommandHistoryRequest
->ExeName
,
574 ExpungeCommandHistoryRequest
->ExeLength
,
577 return STATUS_INVALID_PARAMETER
;
580 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
581 if (!NT_SUCCESS(Status
)) return Status
;
583 // FIXME: convert to UNICODE if Unicode(2) == FALSE
584 ExeName
.Length
= ExeName
.MaximumLength
= ExpungeCommandHistoryRequest
->ExeLength
;
585 ExeName
.Buffer
= ExpungeCommandHistoryRequest
->ExeName
;
587 Hist
= HistoryFindBuffer(Console
, &ExeName
);
588 HistoryDeleteBuffer(Hist
);
590 ConSrvReleaseConsole(Console
, TRUE
);
594 CSR_API(SrvSetConsoleNumberOfCommands
)
597 PCONSOLE_SETHISTORYNUMBERCOMMANDS SetHistoryNumberCommandsRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryNumberCommandsRequest
;
599 PHISTORY_BUFFER Hist
;
600 UINT MaxEntries
= SetHistoryNumberCommandsRequest
->NumCommands
;
601 UNICODE_STRING ExeName
;
602 PUNICODE_STRING OldEntryList
, NewEntryList
;
604 if (!CsrValidateMessageBuffer(ApiMessage
,
605 (PVOID
*)&SetHistoryNumberCommandsRequest
->ExeName
,
606 SetHistoryNumberCommandsRequest
->ExeLength
,
609 return STATUS_INVALID_PARAMETER
;
612 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
613 if (!NT_SUCCESS(Status
)) return Status
;
615 // FIXME: convert to UNICODE if Unicode(2) == FALSE
616 ExeName
.Length
= ExeName
.MaximumLength
= SetHistoryNumberCommandsRequest
->ExeLength
;
617 ExeName
.Buffer
= SetHistoryNumberCommandsRequest
->ExeName
;
619 Hist
= HistoryFindBuffer(Console
, &ExeName
);
622 OldEntryList
= Hist
->Entries
;
623 NewEntryList
= ConsoleAllocHeap(0, MaxEntries
* sizeof(UNICODE_STRING
));
626 Status
= STATUS_NO_MEMORY
;
630 /* If necessary, shrink by removing oldest entries */
631 for (; Hist
->NumEntries
> MaxEntries
; Hist
->NumEntries
--)
633 RtlFreeUnicodeString(Hist
->Entries
++);
634 Hist
->Position
+= (Hist
->Position
== 0);
637 Hist
->MaxEntries
= MaxEntries
;
638 Hist
->Entries
= memcpy(NewEntryList
, Hist
->Entries
,
639 Hist
->NumEntries
* sizeof(UNICODE_STRING
));
640 ConsoleFreeHeap(OldEntryList
);
644 ConSrvReleaseConsole(Console
, TRUE
);
648 CSR_API(SrvGetConsoleHistory
)
650 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
652 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
653 if (NT_SUCCESS(Status
))
655 HistoryInfoRequest
->HistoryBufferSize
= Console
->HistoryBufferSize
;
656 HistoryInfoRequest
->NumberOfHistoryBuffers
= Console
->NumberOfHistoryBuffers
;
657 HistoryInfoRequest
->dwFlags
= Console
->HistoryNoDup
;
658 ConSrvReleaseConsole(Console
, TRUE
);
663 CSR_API(SrvSetConsoleHistory
)
665 PCONSOLE_GETSETHISTORYINFO HistoryInfoRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.HistoryInfoRequest
;
667 NTSTATUS Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
668 if (NT_SUCCESS(Status
))
670 Console
->HistoryBufferSize
= HistoryInfoRequest
->HistoryBufferSize
;
671 Console
->NumberOfHistoryBuffers
= HistoryInfoRequest
->NumberOfHistoryBuffers
;
672 Console
->HistoryNoDup
= HistoryInfoRequest
->dwFlags
& HISTORY_NO_DUP_FLAG
;
673 ConSrvReleaseConsole(Console
, TRUE
);
678 CSR_API(SrvSetConsoleCommandHistoryMode
)
681 PCONSOLE_SETHISTORYMODE SetHistoryModeRequest
= &((PCONSOLE_API_MESSAGE
)ApiMessage
)->Data
.SetHistoryModeRequest
;
684 DPRINT1("SrvSetConsoleCommandHistoryMode(Mode = %d) is not yet implemented\n",
685 SetHistoryModeRequest
->Mode
);
687 Status
= ConSrvGetConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process
), &Console
, TRUE
);
688 if (!NT_SUCCESS(Status
)) return Status
;
690 /* This API is not yet implemented */
691 Status
= STATUS_NOT_IMPLEMENTED
;
693 ConSrvReleaseConsole(Console
, TRUE
);