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