audk/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c

761 lines
20 KiB
C

/** @file
Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "Edb.h"
/**
Set the current coordinates of the cursor position.
@param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
@param Column The position to set the cursor to.
@param Row The position to set the cursor to.
@param LineLength Length of a line.
@param TotalRow Total row of a screen.
@param Str Point to the string.
@param StrPos The position of the string.
@param Len The length of the string.
**/
VOID
EFIAPI
SetCursorPosition (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
IN UINTN Column,
IN INTN Row,
IN UINTN LineLength,
IN UINTN TotalRow,
IN CHAR16 *Str,
IN UINTN StrPos,
IN UINTN Len
);
/**
Function waits for a given event to fire, or for an optional timeout to expire.
@param Event - The event to wait for
@param Timeout - An optional timeout value in 100 ns units.
@retval EFI_SUCCESS - Event fired before Timeout expired.
@retval EFI_TIME_OUT - Timout expired before Event fired..
**/
EFI_STATUS
EFIAPI
WaitForSingleEvent (
IN EFI_EVENT Event,
IN UINT64 Timeout OPTIONAL
)
{
EFI_STATUS Status;
UINTN Index;
EFI_EVENT TimerEvent;
EFI_EVENT WaitList[2];
if (Timeout != 0) {
//
// Create a timer event
//
Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
if (!EFI_ERROR (Status)) {
//
// Set the timer event
//
gBS->SetTimer (
TimerEvent,
TimerRelative,
Timeout
);
//
// Wait for the original event or the timer
//
WaitList[0] = Event;
WaitList[1] = TimerEvent;
Status = gBS->WaitForEvent (2, WaitList, &Index);
gBS->CloseEvent (TimerEvent);
//
// If the timer expired, change the return to timed out
//
if (!EFI_ERROR (Status) && Index == 1) {
Status = EFI_TIMEOUT;
}
}
} else {
//
// No timeout... just wait on the event
//
Status = gBS->WaitForEvent (1, &Event, &Index);
ASSERT (!EFI_ERROR (Status));
ASSERT (Index == 0);
}
return Status;
}
/**
Move the cursor position one character backward.
@param LineLength Length of a line. Get it by calling QueryMode
@param Column Current column of the cursor position
@param Row Current row of the cursor position
**/
VOID
EFIAPI
ConMoveCursorBackward (
IN UINTN LineLength,
IN OUT UINTN *Column,
IN OUT UINTN *Row
)
{
ASSERT (Column != NULL);
ASSERT (Row != NULL);
//
// If current column is 0, move to the last column of the previous line,
// otherwise, just decrement column.
//
if (*Column == 0) {
(*Column) = LineLength - 1;
//
// if (*Row > 0) {
//
(*Row)--;
//
// }
//
} else {
(*Column)--;
}
}
/**
Move the cursor position one character backward.
@param LineLength Length of a line. Get it by calling QueryMode
@param TotalRow Total row of a screen, get by calling QueryMode
@param Column Current column of the cursor position
@param Row Current row of the cursor position
**/
VOID
EFIAPI
ConMoveCursorForward (
IN UINTN LineLength,
IN UINTN TotalRow,
IN OUT UINTN *Column,
IN OUT UINTN *Row
)
{
ASSERT (Column != NULL);
ASSERT (Row != NULL);
//
// If current column is at line end, move to the first column of the nest
// line, otherwise, just increment column.
//
(*Column)++;
if (*Column >= LineLength) {
(*Column) = 0;
if ((*Row) < TotalRow - 1) {
(*Row)++;
}
}
}
CHAR16 mBackupSpace[EFI_DEBUG_INPUS_BUFFER_SIZE];
CHAR16 mInputBufferHistory[EFI_DEBUG_INPUS_BUFFER_SIZE];
/**
Get user input.
@param Prompt The prompt string.
@param InStr Point to the input string.
@param StrLength The max length of string user can input.
**/
VOID
EFIAPI
Input (
IN CHAR16 *Prompt OPTIONAL,
OUT CHAR16 *InStr,
IN UINTN StrLength
)
{
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
BOOLEAN Done;
UINTN Column;
UINTN Row;
UINTN StartColumn;
UINTN Update;
UINTN Delete;
UINTN Len;
UINTN StrPos;
UINTN Index;
UINTN LineLength;
UINTN TotalRow;
UINTN SkipLength;
UINTN OutputLength;
UINTN TailRow;
UINTN TailColumn;
EFI_INPUT_KEY Key;
BOOLEAN InsertMode;
BOOLEAN NeedAdjust;
UINTN SubIndex;
CHAR16 *CommandStr;
ConOut = gST->ConOut;
ConIn = gST->ConIn;
ASSERT (ConOut != NULL);
ASSERT (ConIn != NULL);
ASSERT (InStr != NULL);
if (Prompt != NULL) {
ConOut->OutputString (ConOut, Prompt);
}
//
// Read a line from the console
//
Len = 0;
StrPos = 0;
OutputLength = 0;
Update = 0;
Delete = 0;
InsertMode = TRUE;
NeedAdjust = FALSE;
//
// If buffer is not large enough to hold a CHAR16, do nothing.
//
if (StrLength < 1) {
return ;
}
//
// Get the screen setting and the current cursor location
//
StartColumn = ConOut->Mode->CursorColumn;
Column = StartColumn;
Row = ConOut->Mode->CursorRow;
ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
if (LineLength == 0) {
return ;
}
SetMem (InStr, StrLength * sizeof (CHAR16), 0);
Done = FALSE;
do {
//
// Read a key
//
WaitForSingleEvent (ConIn->WaitForKey, 0);
ConIn->ReadKeyStroke (ConIn, &Key);
switch (Key.UnicodeChar) {
case CHAR_CARRIAGE_RETURN:
//
// All done, print a newline at the end of the string
//
TailRow = Row + (Len - StrPos + Column) / LineLength;
TailColumn = (Len - StrPos + Column) % LineLength;
Done = TRUE;
break;
case CHAR_BACKSPACE:
if (StrPos != 0) {
//
// If not move back beyond string beginning, move all characters behind
// the current position one character forward
//
StrPos -= 1;
Update = StrPos;
Delete = 1;
CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
//
// Adjust the current column and row
//
ConMoveCursorBackward (LineLength, &Column, &Row);
NeedAdjust = TRUE;
}
break;
default:
if (Key.UnicodeChar >= ' ') {
//
// If we are at the buffer's end, drop the key
//
if (Len == StrLength - 1 && (InsertMode || StrPos == Len)) {
break;
}
//
// If in insert mode, move all characters behind the current position
// one character backward to make space for this character. Then store
// the character.
//
if (InsertMode) {
for (Index = Len; Index > StrPos; Index -= 1) {
InStr[Index] = InStr[Index - 1];
}
}
InStr[StrPos] = Key.UnicodeChar;
Update = StrPos;
StrPos += 1;
OutputLength = 1;
}
break;
case 0:
switch (Key.ScanCode) {
case SCAN_DELETE:
//
// Move characters behind current position one character forward
//
if (Len != 0) {
Update = StrPos;
Delete = 1;
CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
NeedAdjust = TRUE;
}
break;
case SCAN_LEFT:
//
// Adjust current cursor position
//
if (StrPos != 0) {
StrPos -= 1;
ConMoveCursorBackward (LineLength, &Column, &Row);
}
break;
case SCAN_RIGHT:
//
// Adjust current cursor position
//
if (StrPos < Len) {
StrPos += 1;
ConMoveCursorForward (LineLength, TotalRow, &Column, &Row);
}
break;
case SCAN_HOME:
//
// Move current cursor position to the beginning of the command line
//
Row -= (StrPos + StartColumn) / LineLength;
Column = StartColumn;
StrPos = 0;
break;
case SCAN_END:
//
// Move current cursor position to the end of the command line
//
TailRow = Row + (Len - StrPos + Column) / LineLength;
TailColumn = (Len - StrPos + Column) % LineLength;
Row = TailRow;
Column = TailColumn;
StrPos = Len;
break;
case SCAN_ESC:
//
// Prepare to clear the current command line
//
InStr[0] = 0;
Update = 0;
Delete = Len;
Row -= (StrPos + StartColumn) / LineLength;
Column = StartColumn;
OutputLength = 0;
NeedAdjust = TRUE;
break;
case SCAN_INSERT:
//
// Toggle the SEnvInsertMode flag
//
InsertMode = (BOOLEAN)!InsertMode;
break;
case SCAN_UP:
case SCAN_DOWN:
//
// show history
//
CopyMem (InStr, mInputBufferHistory, StrLength * sizeof(CHAR16));
StrPos = StrLen (mInputBufferHistory);
Update = 0;
Delete = 0;
OutputLength = 0;
TailRow = Row + (StrPos + StartColumn) / LineLength;
TailColumn = (StrPos + StartColumn) % LineLength;
Row = TailRow;
Column = TailColumn;
NeedAdjust = FALSE;
ConOut->SetCursorPosition (ConOut, StartColumn, Row);
for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
mBackupSpace[SubIndex] = L' ';
}
EDBPrint (mBackupSpace);
SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
ConOut->SetCursorPosition (ConOut, StartColumn, Row);
Len = StrPos;
break;
case SCAN_F1:
case SCAN_F2:
case SCAN_F3:
case SCAN_F4:
case SCAN_F5:
case SCAN_F6:
case SCAN_F7:
case SCAN_F8:
case SCAN_F9:
case SCAN_F10:
case SCAN_F11:
case SCAN_F12:
CommandStr = GetCommandNameByKey (Key);
if (CommandStr != NULL) {
StrnCpyS (InStr, StrLength, CommandStr, StrLength - 1);
return ;
}
break;
}
}
if (Done) {
break;
}
//
// If we need to update the output do so now
//
if (Update != -1) {
if (NeedAdjust) {
ConOut->SetCursorPosition (ConOut, Column, Row);
for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
mBackupSpace[SubIndex] = L' ';
}
EDBPrint (mBackupSpace);
SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
ConOut->SetCursorPosition (ConOut, Column, Row);
NeedAdjust = FALSE;
}
EDBPrint (InStr + Update);
Len = StrLen (InStr);
if (Delete != 0) {
SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
}
if (StrPos > Len) {
StrPos = Len;
}
Update = (UINTN) -1;
//
// After using print to reflect newly updates, if we're not using
// BACKSPACE and DELETE, we need to move the cursor position forward,
// so adjust row and column here.
//
if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
//
// Calulate row and column of the tail of current string
//
TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
//
// If the tail of string reaches screen end, screen rolls up, so if
// Row does not equal TailRow, Row should be decremented
//
// (if we are recalling commands using UPPER and DOWN key, and if the
// old command is too long to fit the screen, TailColumn must be 79.
//
if (TailColumn == 0 && TailRow >= TotalRow && (UINTN) Row != TailRow) {
Row--;
}
//
// Calculate the cursor position after current operation. If cursor
// reaches line end, update both row and column, otherwise, only
// column will be changed.
//
if (Column + OutputLength >= LineLength) {
SkipLength = OutputLength - (LineLength - Column);
Row += SkipLength / LineLength + 1;
if ((UINTN) Row > TotalRow - 1) {
Row = TotalRow - 1;
}
Column = SkipLength % LineLength;
} else {
Column += OutputLength;
}
}
Delete = 0;
}
//
// Set the cursor position for this key
//
SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
} while (!Done);
CopyMem (mInputBufferHistory, InStr, StrLength * sizeof(CHAR16));
//
// Return the data to the caller
//
return ;
}
/**
Set the current coordinates of the cursor position.
@param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
@param Column The position to set the cursor to.
@param Row The position to set the cursor to.
@param LineLength Length of a line.
@param TotalRow Total row of a screen.
@param Str Point to the string.
@param StrPos The position of the string.
@param Len The length of the string.
**/
VOID
EFIAPI
SetCursorPosition (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
IN UINTN Column,
IN INTN Row,
IN UINTN LineLength,
IN UINTN TotalRow,
IN CHAR16 *Str,
IN UINTN StrPos,
IN UINTN Len
)
{
CHAR16 Backup;
ASSERT (ConOut != NULL);
ASSERT (Str != NULL);
Backup = 0;
if (Row >= 0) {
ConOut->SetCursorPosition (ConOut, Column, Row);
return ;
}
if (Len - StrPos > Column * Row) {
Backup = *(Str + StrPos + Column * Row);
*(Str + StrPos + Column * Row) = 0;
}
EDBPrint (L"%s", Str + StrPos);
if (Len - StrPos > Column * Row) {
*(Str + StrPos + Column * Row) = Backup;
}
ConOut->SetCursorPosition (ConOut, 0, 0);
}
/**
SetPageBreak.
**/
BOOLEAN
EFIAPI
SetPageBreak (
VOID
)
{
EFI_INPUT_KEY Key;
CHAR16 Str[3];
BOOLEAN OmitPrint;
//
// Check
//
if (!mDebuggerPrivate.EnablePageBreak) {
return FALSE;
}
gST->ConOut->OutputString (gST->ConOut, L"Press ENTER to continue, 'q' to exit:");
OmitPrint = FALSE;
//
// Wait for user input
//
Str[0] = ' ';
Str[1] = 0;
Str[2] = 0;
for (;;) {
WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
//
// handle control keys
//
if (Key.UnicodeChar == CHAR_NULL) {
if (Key.ScanCode == SCAN_ESC) {
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
OmitPrint = TRUE;
break;
}
continue;
}
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
gST->ConOut->OutputString (gST->ConOut, L"\r\n");
break;
}
//
// Echo input
//
Str[1] = Key.UnicodeChar;
if (Str[1] == CHAR_BACKSPACE) {
continue;
}
gST->ConOut->OutputString (gST->ConOut, Str);
if ((Str[1] == L'q') || (Str[1] == L'Q')) {
OmitPrint = TRUE;
} else {
OmitPrint = FALSE;
}
Str[0] = CHAR_BACKSPACE;
}
return OmitPrint;
}
/**
Print a Unicode string to the output device.
@param Format A Null-terminated Unicode format string.
@param ... The variable argument list that contains pointers to Null-
terminated Unicode strings to be printed
**/
UINTN
EFIAPI
EDBPrint (
IN CONST CHAR16 *Format,
...
)
{
UINTN Return;
VA_LIST Marker;
CHAR16 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
VA_START (Marker, Format);
Return = UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
VA_END (Marker);
if (gST->ConOut != NULL) {
//
// To be extra safe make sure ConOut has been initialized
//
gST->ConOut->OutputString (gST->ConOut, Buffer);
}
return Return;
}
/**
Print a Unicode string to the output buffer.
@param Buffer A pointer to the output buffer for the produced Null-terminated
Unicode string.
@param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
@param Format A Null-terminated Unicode format string.
@param ... The variable argument list that contains pointers to Null-
terminated Unicode strings to be printed
**/
UINTN
EFIAPI
EDBSPrint (
OUT CHAR16 *Buffer,
IN INTN BufferSize,
IN CONST CHAR16 *Format,
...
)
{
UINTN Return;
VA_LIST Marker;
ASSERT (BufferSize > 0);
VA_START (Marker, Format);
Return = UnicodeVSPrint (Buffer, (UINTN)BufferSize, Format, Marker);
VA_END (Marker);
return Return;
}
/**
Print a Unicode string to the output buffer with specified offset..
@param Buffer A pointer to the output buffer for the produced Null-terminated
Unicode string.
@param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
@param Offset The offset of the buffer.
@param Format A Null-terminated Unicode format string.
@param ... The variable argument list that contains pointers to Null-
terminated Unicode strings to be printed
**/
UINTN
EFIAPI
EDBSPrintWithOffset (
OUT CHAR16 *Buffer,
IN INTN BufferSize,
IN UINTN Offset,
IN CONST CHAR16 *Format,
...
)
{
UINTN Return;
VA_LIST Marker;
ASSERT (BufferSize - (Offset * sizeof(CHAR16)) > 0);
VA_START (Marker, Format);
Return = UnicodeVSPrint (Buffer + Offset, (UINTN)(BufferSize - (Offset * sizeof(CHAR16))), Format, Marker);
VA_END (Marker);
return Return;
}