]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcDebugger / EdbSupportUI.c
1 /** @file
2
3 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6
7 **/
8
9 #include "Edb.h"
10
11 /**
12 Set the current coordinates of the cursor position.
13
14 @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
15 @param Column The position to set the cursor to.
16 @param Row The position to set the cursor to.
17 @param LineLength Length of a line.
18 @param TotalRow Total row of a screen.
19 @param Str Point to the string.
20 @param StrPos The position of the string.
21 @param Len The length of the string.
22
23 **/
24 VOID
25 EFIAPI
26 SetCursorPosition (
27 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
28 IN UINTN Column,
29 IN INTN Row,
30 IN UINTN LineLength,
31 IN UINTN TotalRow,
32 IN CHAR16 *Str,
33 IN UINTN StrPos,
34 IN UINTN Len
35 );
36
37 /**
38
39 Function waits for a given event to fire, or for an optional timeout to expire.
40
41 @param Event - The event to wait for
42 @param Timeout - An optional timeout value in 100 ns units.
43
44 @retval EFI_SUCCESS - Event fired before Timeout expired.
45 @retval EFI_TIME_OUT - Timout expired before Event fired..
46
47 **/
48 EFI_STATUS
49 EFIAPI
50 WaitForSingleEvent (
51 IN EFI_EVENT Event,
52 IN UINT64 Timeout OPTIONAL
53 )
54 {
55 EFI_STATUS Status;
56 UINTN Index;
57 EFI_EVENT TimerEvent;
58 EFI_EVENT WaitList[2];
59
60 if (Timeout != 0) {
61 //
62 // Create a timer event
63 //
64 Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
65 if (!EFI_ERROR (Status)) {
66 //
67 // Set the timer event
68 //
69 gBS->SetTimer (
70 TimerEvent,
71 TimerRelative,
72 Timeout
73 );
74
75 //
76 // Wait for the original event or the timer
77 //
78 WaitList[0] = Event;
79 WaitList[1] = TimerEvent;
80 Status = gBS->WaitForEvent (2, WaitList, &Index);
81 gBS->CloseEvent (TimerEvent);
82
83 //
84 // If the timer expired, change the return to timed out
85 //
86 if (!EFI_ERROR (Status) && Index == 1) {
87 Status = EFI_TIMEOUT;
88 }
89 }
90 } else {
91 //
92 // No timeout... just wait on the event
93 //
94 Status = gBS->WaitForEvent (1, &Event, &Index);
95 ASSERT (!EFI_ERROR (Status));
96 ASSERT (Index == 0);
97 }
98
99 return Status;
100 }
101
102 /**
103
104 Move the cursor position one character backward.
105
106 @param LineLength Length of a line. Get it by calling QueryMode
107 @param Column Current column of the cursor position
108 @param Row Current row of the cursor position
109
110 **/
111 VOID
112 EFIAPI
113 ConMoveCursorBackward (
114 IN UINTN LineLength,
115 IN OUT UINTN *Column,
116 IN OUT UINTN *Row
117 )
118 {
119 ASSERT (Column != NULL);
120 ASSERT (Row != NULL);
121 //
122 // If current column is 0, move to the last column of the previous line,
123 // otherwise, just decrement column.
124 //
125 if (*Column == 0) {
126 (*Column) = LineLength - 1;
127 //
128 // if (*Row > 0) {
129 //
130 (*Row)--;
131 //
132 // }
133 //
134 } else {
135 (*Column)--;
136 }
137 }
138
139 /**
140
141 Move the cursor position one character backward.
142
143 @param LineLength Length of a line. Get it by calling QueryMode
144 @param TotalRow Total row of a screen, get by calling QueryMode
145 @param Column Current column of the cursor position
146 @param Row Current row of the cursor position
147
148 **/
149 VOID
150 EFIAPI
151 ConMoveCursorForward (
152 IN UINTN LineLength,
153 IN UINTN TotalRow,
154 IN OUT UINTN *Column,
155 IN OUT UINTN *Row
156 )
157 {
158 ASSERT (Column != NULL);
159 ASSERT (Row != NULL);
160 //
161 // If current column is at line end, move to the first column of the nest
162 // line, otherwise, just increment column.
163 //
164 (*Column)++;
165 if (*Column >= LineLength) {
166 (*Column) = 0;
167 if ((*Row) < TotalRow - 1) {
168 (*Row)++;
169 }
170 }
171 }
172
173 CHAR16 mBackupSpace[EFI_DEBUG_INPUS_BUFFER_SIZE];
174 CHAR16 mInputBufferHistory[EFI_DEBUG_INPUS_BUFFER_SIZE];
175
176 /**
177
178 Get user input.
179
180 @param Prompt The prompt string.
181 @param InStr Point to the input string.
182 @param StrLength The max length of string user can input.
183
184 **/
185 VOID
186 EFIAPI
187 Input (
188 IN CHAR16 *Prompt OPTIONAL,
189 OUT CHAR16 *InStr,
190 IN UINTN StrLength
191 )
192 {
193 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
194 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
195 BOOLEAN Done;
196 UINTN Column;
197 UINTN Row;
198 UINTN StartColumn;
199 UINTN Update;
200 UINTN Delete;
201 UINTN Len;
202 UINTN StrPos;
203 UINTN Index;
204 UINTN LineLength;
205 UINTN TotalRow;
206 UINTN SkipLength;
207 UINTN OutputLength;
208 UINTN TailRow;
209 UINTN TailColumn;
210 EFI_INPUT_KEY Key;
211 BOOLEAN InsertMode;
212 BOOLEAN NeedAdjust;
213 UINTN SubIndex;
214 CHAR16 *CommandStr;
215
216 ConOut = gST->ConOut;
217 ConIn = gST->ConIn;
218
219 ASSERT (ConOut != NULL);
220 ASSERT (ConIn != NULL);
221 ASSERT (InStr != NULL);
222
223 if (Prompt != NULL) {
224 ConOut->OutputString (ConOut, Prompt);
225 }
226 //
227 // Read a line from the console
228 //
229 Len = 0;
230 StrPos = 0;
231 OutputLength = 0;
232 Update = 0;
233 Delete = 0;
234 InsertMode = TRUE;
235 NeedAdjust = FALSE;
236
237 //
238 // If buffer is not large enough to hold a CHAR16, do nothing.
239 //
240 if (StrLength < 1) {
241 return ;
242 }
243 //
244 // Get the screen setting and the current cursor location
245 //
246 StartColumn = ConOut->Mode->CursorColumn;
247 Column = StartColumn;
248 Row = ConOut->Mode->CursorRow;
249 ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
250 if (LineLength == 0) {
251 return ;
252 }
253
254 SetMem (InStr, StrLength * sizeof (CHAR16), 0);
255 Done = FALSE;
256 do {
257 //
258 // Read a key
259 //
260 WaitForSingleEvent (ConIn->WaitForKey, 0);
261 ConIn->ReadKeyStroke (ConIn, &Key);
262
263 switch (Key.UnicodeChar) {
264 case CHAR_CARRIAGE_RETURN:
265 //
266 // All done, print a newline at the end of the string
267 //
268 TailRow = Row + (Len - StrPos + Column) / LineLength;
269 TailColumn = (Len - StrPos + Column) % LineLength;
270 Done = TRUE;
271 break;
272
273 case CHAR_BACKSPACE:
274 if (StrPos != 0) {
275 //
276 // If not move back beyond string beginning, move all characters behind
277 // the current position one character forward
278 //
279 StrPos -= 1;
280 Update = StrPos;
281 Delete = 1;
282 CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
283
284 //
285 // Adjust the current column and row
286 //
287 ConMoveCursorBackward (LineLength, &Column, &Row);
288
289 NeedAdjust = TRUE;
290 }
291 break;
292
293 default:
294 if (Key.UnicodeChar >= ' ') {
295 //
296 // If we are at the buffer's end, drop the key
297 //
298 if (Len == StrLength - 1 && (InsertMode || StrPos == Len)) {
299 break;
300 }
301 //
302 // If in insert mode, move all characters behind the current position
303 // one character backward to make space for this character. Then store
304 // the character.
305 //
306 if (InsertMode) {
307 for (Index = Len; Index > StrPos; Index -= 1) {
308 InStr[Index] = InStr[Index - 1];
309 }
310 }
311
312 InStr[StrPos] = Key.UnicodeChar;
313 Update = StrPos;
314
315 StrPos += 1;
316 OutputLength = 1;
317 }
318 break;
319
320 case 0:
321 switch (Key.ScanCode) {
322 case SCAN_DELETE:
323 //
324 // Move characters behind current position one character forward
325 //
326 if (Len != 0) {
327 Update = StrPos;
328 Delete = 1;
329 CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
330
331 NeedAdjust = TRUE;
332 }
333 break;
334
335 case SCAN_LEFT:
336 //
337 // Adjust current cursor position
338 //
339 if (StrPos != 0) {
340 StrPos -= 1;
341 ConMoveCursorBackward (LineLength, &Column, &Row);
342 }
343 break;
344
345 case SCAN_RIGHT:
346 //
347 // Adjust current cursor position
348 //
349 if (StrPos < Len) {
350 StrPos += 1;
351 ConMoveCursorForward (LineLength, TotalRow, &Column, &Row);
352 }
353 break;
354
355 case SCAN_HOME:
356 //
357 // Move current cursor position to the beginning of the command line
358 //
359 Row -= (StrPos + StartColumn) / LineLength;
360 Column = StartColumn;
361 StrPos = 0;
362 break;
363
364 case SCAN_END:
365 //
366 // Move current cursor position to the end of the command line
367 //
368 TailRow = Row + (Len - StrPos + Column) / LineLength;
369 TailColumn = (Len - StrPos + Column) % LineLength;
370 Row = TailRow;
371 Column = TailColumn;
372 StrPos = Len;
373 break;
374
375 case SCAN_ESC:
376 //
377 // Prepare to clear the current command line
378 //
379 InStr[0] = 0;
380 Update = 0;
381 Delete = Len;
382 Row -= (StrPos + StartColumn) / LineLength;
383 Column = StartColumn;
384 OutputLength = 0;
385
386 NeedAdjust = TRUE;
387 break;
388
389 case SCAN_INSERT:
390 //
391 // Toggle the SEnvInsertMode flag
392 //
393 InsertMode = (BOOLEAN)!InsertMode;
394 break;
395
396 case SCAN_UP:
397 case SCAN_DOWN:
398 //
399 // show history
400 //
401 CopyMem (InStr, mInputBufferHistory, StrLength * sizeof(CHAR16));
402 StrPos = StrLen (mInputBufferHistory);
403 Update = 0;
404 Delete = 0;
405 OutputLength = 0;
406
407 TailRow = Row + (StrPos + StartColumn) / LineLength;
408 TailColumn = (StrPos + StartColumn) % LineLength;
409 Row = TailRow;
410 Column = TailColumn;
411 NeedAdjust = FALSE;
412
413 ConOut->SetCursorPosition (ConOut, StartColumn, Row);
414 for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
415 mBackupSpace[SubIndex] = L' ';
416 }
417 EDBPrint (mBackupSpace);
418 SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
419
420 ConOut->SetCursorPosition (ConOut, StartColumn, Row);
421 Len = StrPos;
422
423 break;
424
425 case SCAN_F1:
426 case SCAN_F2:
427 case SCAN_F3:
428 case SCAN_F4:
429 case SCAN_F5:
430 case SCAN_F6:
431 case SCAN_F7:
432 case SCAN_F8:
433 case SCAN_F9:
434 case SCAN_F10:
435 case SCAN_F11:
436 case SCAN_F12:
437 CommandStr = GetCommandNameByKey (Key);
438 if (CommandStr != NULL) {
439 StrnCpyS (InStr, StrLength, CommandStr, StrLength - 1);
440 return ;
441 }
442 break;
443 }
444 }
445
446 if (Done) {
447 break;
448 }
449 //
450 // If we need to update the output do so now
451 //
452 if (Update != -1) {
453 if (NeedAdjust) {
454 ConOut->SetCursorPosition (ConOut, Column, Row);
455 for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
456 mBackupSpace[SubIndex] = L' ';
457 }
458 EDBPrint (mBackupSpace);
459 SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
460 ConOut->SetCursorPosition (ConOut, Column, Row);
461 NeedAdjust = FALSE;
462 }
463 EDBPrint (InStr + Update);
464 Len = StrLen (InStr);
465
466 if (Delete != 0) {
467 SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
468 }
469
470 if (StrPos > Len) {
471 StrPos = Len;
472 }
473
474 Update = (UINTN) -1;
475
476 //
477 // After using print to reflect newly updates, if we're not using
478 // BACKSPACE and DELETE, we need to move the cursor position forward,
479 // so adjust row and column here.
480 //
481 if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
482 //
483 // Calulate row and column of the tail of current string
484 //
485 TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
486 TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
487
488 //
489 // If the tail of string reaches screen end, screen rolls up, so if
490 // Row does not equal TailRow, Row should be decremented
491 //
492 // (if we are recalling commands using UPPER and DOWN key, and if the
493 // old command is too long to fit the screen, TailColumn must be 79.
494 //
495 if (TailColumn == 0 && TailRow >= TotalRow && (UINTN) Row != TailRow) {
496 Row--;
497 }
498 //
499 // Calculate the cursor position after current operation. If cursor
500 // reaches line end, update both row and column, otherwise, only
501 // column will be changed.
502 //
503 if (Column + OutputLength >= LineLength) {
504 SkipLength = OutputLength - (LineLength - Column);
505
506 Row += SkipLength / LineLength + 1;
507 if ((UINTN) Row > TotalRow - 1) {
508 Row = TotalRow - 1;
509 }
510
511 Column = SkipLength % LineLength;
512 } else {
513 Column += OutputLength;
514 }
515 }
516
517 Delete = 0;
518 }
519 //
520 // Set the cursor position for this key
521 //
522 SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
523 } while (!Done);
524
525 CopyMem (mInputBufferHistory, InStr, StrLength * sizeof(CHAR16));
526
527 //
528 // Return the data to the caller
529 //
530 return ;
531 }
532
533 /**
534 Set the current coordinates of the cursor position.
535
536 @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
537 @param Column The position to set the cursor to.
538 @param Row The position to set the cursor to.
539 @param LineLength Length of a line.
540 @param TotalRow Total row of a screen.
541 @param Str Point to the string.
542 @param StrPos The position of the string.
543 @param Len The length of the string.
544
545 **/
546 VOID
547 EFIAPI
548 SetCursorPosition (
549 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
550 IN UINTN Column,
551 IN INTN Row,
552 IN UINTN LineLength,
553 IN UINTN TotalRow,
554 IN CHAR16 *Str,
555 IN UINTN StrPos,
556 IN UINTN Len
557 )
558 {
559 CHAR16 Backup;
560
561 ASSERT (ConOut != NULL);
562 ASSERT (Str != NULL);
563
564 Backup = 0;
565 if (Row >= 0) {
566 ConOut->SetCursorPosition (ConOut, Column, Row);
567 return ;
568 }
569
570 if (Len - StrPos > Column * Row) {
571 Backup = *(Str + StrPos + Column * Row);
572 *(Str + StrPos + Column * Row) = 0;
573 }
574
575 EDBPrint (L"%s", Str + StrPos);
576 if (Len - StrPos > Column * Row) {
577 *(Str + StrPos + Column * Row) = Backup;
578 }
579
580 ConOut->SetCursorPosition (ConOut, 0, 0);
581 }
582
583 /**
584
585 SetPageBreak.
586
587 **/
588 BOOLEAN
589 EFIAPI
590 SetPageBreak (
591 VOID
592 )
593 {
594 EFI_INPUT_KEY Key;
595 CHAR16 Str[3];
596 BOOLEAN OmitPrint;
597
598 //
599 // Check
600 //
601 if (!mDebuggerPrivate.EnablePageBreak) {
602 return FALSE;
603 }
604
605 gST->ConOut->OutputString (gST->ConOut, L"Press ENTER to continue, 'q' to exit:");
606
607 OmitPrint = FALSE;
608 //
609 // Wait for user input
610 //
611 Str[0] = ' ';
612 Str[1] = 0;
613 Str[2] = 0;
614 for (;;) {
615 WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
616 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
617
618 //
619 // handle control keys
620 //
621 if (Key.UnicodeChar == CHAR_NULL) {
622 if (Key.ScanCode == SCAN_ESC) {
623 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
624 OmitPrint = TRUE;
625 break;
626 }
627
628 continue;
629 }
630
631 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
632 gST->ConOut->OutputString (gST->ConOut, L"\r\n");
633 break;
634 }
635 //
636 // Echo input
637 //
638 Str[1] = Key.UnicodeChar;
639 if (Str[1] == CHAR_BACKSPACE) {
640 continue;
641 }
642
643 gST->ConOut->OutputString (gST->ConOut, Str);
644
645 if ((Str[1] == L'q') || (Str[1] == L'Q')) {
646 OmitPrint = TRUE;
647 } else {
648 OmitPrint = FALSE;
649 }
650
651 Str[0] = CHAR_BACKSPACE;
652 }
653
654 return OmitPrint;
655 }
656
657 /**
658 Print a Unicode string to the output device.
659
660 @param Format A Null-terminated Unicode format string.
661 @param ... The variable argument list that contains pointers to Null-
662 terminated Unicode strings to be printed
663
664 **/
665 UINTN
666 EFIAPI
667 EDBPrint (
668 IN CONST CHAR16 *Format,
669 ...
670 )
671 {
672 UINTN Return;
673 VA_LIST Marker;
674 CHAR16 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
675
676 VA_START (Marker, Format);
677 Return = UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
678 VA_END (Marker);
679
680 if (gST->ConOut != NULL) {
681 //
682 // To be extra safe make sure ConOut has been initialized
683 //
684 gST->ConOut->OutputString (gST->ConOut, Buffer);
685 }
686
687 return Return;
688 }
689
690 /**
691 Print a Unicode string to the output buffer.
692
693 @param Buffer A pointer to the output buffer for the produced Null-terminated
694 Unicode string.
695 @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
696 @param Format A Null-terminated Unicode format string.
697 @param ... The variable argument list that contains pointers to Null-
698 terminated Unicode strings to be printed
699
700 **/
701 UINTN
702 EFIAPI
703 EDBSPrint (
704 OUT CHAR16 *Buffer,
705 IN INTN BufferSize,
706 IN CONST CHAR16 *Format,
707 ...
708 )
709 {
710 UINTN Return;
711 VA_LIST Marker;
712
713 ASSERT (BufferSize > 0);
714
715 VA_START (Marker, Format);
716 Return = UnicodeVSPrint (Buffer, (UINTN)BufferSize, Format, Marker);
717 VA_END (Marker);
718
719 return Return;
720 }
721
722 /**
723 Print a Unicode string to the output buffer with specified offset..
724
725 @param Buffer A pointer to the output buffer for the produced Null-terminated
726 Unicode string.
727 @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
728 @param Offset The offset of the buffer.
729 @param Format A Null-terminated Unicode format string.
730 @param ... The variable argument list that contains pointers to Null-
731 terminated Unicode strings to be printed
732
733 **/
734 UINTN
735 EFIAPI
736 EDBSPrintWithOffset (
737 OUT CHAR16 *Buffer,
738 IN INTN BufferSize,
739 IN UINTN Offset,
740 IN CONST CHAR16 *Format,
741 ...
742 )
743 {
744 UINTN Return;
745 VA_LIST Marker;
746
747 ASSERT (BufferSize - (Offset * sizeof(CHAR16)) > 0);
748
749 VA_START (Marker, Format);
750 Return = UnicodeVSPrint (Buffer + Offset, (UINTN)(BufferSize - (Offset * sizeof(CHAR16))), Format, Marker);
751 VA_END (Marker);
752
753 return Return;
754 }