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