text: /** @file
    Implements inputbar interface functions.
  
    Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include "EditInputBar.h"
  #include "UefiShellDebug1CommandsLib.h"
  
  CHAR16  *mPrompt;        // Input bar mPrompt string.
  CHAR16  *mReturnString;  // The returned string.
  UINTN   StringSize;      // Size of mReturnString space size.
  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *mTextInEx;
  
  /**
    Initialize the input bar.
  
    @param[in] TextInEx  Pointer to SimpleTextInEx instance in System Table.
  **/
  VOID
  InputBarInit (
    IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInEx
    )
  {
    mPrompt       = NULL;
    mReturnString = NULL;
    StringSize    = 0;
    mTextInEx     = TextInEx;
  }
  
  /**
    Cleanup function for input bar.
  **/
  VOID
  InputBarCleanup (
    VOID
    )
  {
    //
    // free input bar's prompt and input string
    //
    SHELL_FREE_NON_NULL (mPrompt);
    SHELL_FREE_NON_NULL (mReturnString);
    mPrompt       = NULL;
    mReturnString = NULL;
  }
  
  /**
    Display the prompt.
    Do the requesting of input.
  
    @param[in]  LastColumn   The last printable column.
    @param[in]  LastRow      The last printable row.
  **/
  VOID
  InputBarPrintInput (
    IN UINTN LastColumn,
    IN UINTN LastRow
    )
  {
    UINTN   Limit;
    UINTN   Size;
    CHAR16  *Buffer;
    UINTN   Index;
    UINTN   mPromptLen;
  
    mPromptLen = StrLen (mPrompt);
    Limit     = LastColumn - mPromptLen - 1;
    Size      = StrLen (mReturnString);
  
    //
    // check whether the mPrompt length and input length will
    // exceed limit
    //
    if (Size <= Limit) {
      Buffer = mReturnString;
    } else {
      Buffer = mReturnString + Size - Limit;
    }
  
    gST->ConOut->EnableCursor (gST->ConOut, FALSE);
  
    ShellPrintEx (((INT32)mPromptLen), ((INT32)LastRow) - 1, L"%s", Buffer);
    Size = StrLen (Buffer);
  
    //
    // print " " after mPrompt
    //
    for (Index = Size; Index < Limit; Index++) {
      ShellPrintEx ((INT32)(mPromptLen + Size), ((INT32)LastRow) - 1, L" ");
    }
  
    gST->ConOut->EnableCursor (gST->ConOut, TRUE);
    gST->ConOut->SetCursorPosition (gST->ConOut, Size + mPromptLen, LastRow - 1);
  }
  
  typedef struct {
    UINT32  Foreground : 4;
    UINT32  Background : 3;
  } INPUT_BAR_COLOR_ATTRIBUTES;
  
  typedef union {
    INPUT_BAR_COLOR_ATTRIBUTES  Colors;
    UINTN                       Data;
  } INPUT_BAR_COLOR_UNION;
  
  
  /**
    The refresh function for InputBar, it will wait for user input
  
    @param[in] LastRow            The last printable row.
    @param[in] LastColumn         The last printable column.
  
    @retval EFI_SUCCESS           The operation was successful.
  **/
  EFI_STATUS
  InputBarRefresh (
    UINTN LastRow,
    UINTN LastColumn
    )
  {
    INPUT_BAR_COLOR_UNION   Orig;
    INPUT_BAR_COLOR_UNION   New;
    EFI_KEY_DATA            KeyData;
    UINTN                   Size;
    EFI_STATUS              Status;
    BOOLEAN                 NoDisplay;
    UINTN                   EventIndex;
    UINTN                   CursorRow;
    UINTN                   CursorCol;
  
    //
    // variable initialization
    //
    Size    = 0;
    Status  = EFI_SUCCESS;
  
    //
    // back up the old screen attributes
    //
    CursorCol             = gST->ConOut->Mode->CursorColumn;
    CursorRow             = gST->ConOut->Mode->CursorRow;
    Orig.Data             = gST->ConOut->Mode->Attribute;
    New.Data              = 0;
    New.Colors.Foreground = Orig.Colors.Background & 0xF;
    New.Colors.Background = Orig.Colors.Foreground & 0x7;
  
    gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F);
  
    //
    // clear input bar
    //
    EditorClearLine (LastRow , LastColumn, LastRow);
  
    gST->ConOut->SetCursorPosition (gST->ConOut, 0, LastRow - 1);
    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_EDIT_LIBINPUTBAR_MAININPUTBAR), gShellDebug1HiiHandle, mPrompt);
  
    //
    // this is a selection mPrompt, cursor will stay in edit area
    // actually this is for search , search/replace
    //
    if (StrStr (mPrompt, L"Yes/No")) {
      NoDisplay = TRUE;
      gST->ConOut->SetCursorPosition (gST->ConOut, CursorCol, CursorRow);
      gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
    } else {
      NoDisplay = FALSE;
    }
    //
    // wait for user input
    //
    for (;;) {
      Status = gBS->WaitForEvent (1, &mTextInEx->WaitForKeyEx, &EventIndex);
      if (EFI_ERROR (Status) || (EventIndex != 0)) {
        continue;
      }
      Status = mTextInEx->ReadKeyStrokeEx (mTextInEx, &KeyData);
      if (EFI_ERROR (Status)) {
        continue;
      }
      if (((KeyData.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) &&
          (KeyData.KeyState.KeyShiftState != EFI_SHIFT_STATE_VALID)) {
        //
        // Shift key pressed.
        //
        continue;
      }
      //
      // pressed ESC
      //
      if (KeyData.Key.ScanCode == SCAN_ESC) {
        Size    = 0;
        Status  = EFI_NOT_READY;
        break;
      }
      //
      // return pressed
      //
      if (KeyData.Key.UnicodeChar == CHAR_LINEFEED || KeyData.Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
        break;
      } else if (KeyData.Key.UnicodeChar == CHAR_BACKSPACE) {
        //
        // backspace
        //
        if (Size > 0) {
          Size--;
          mReturnString[Size] = CHAR_NULL;
          if (!NoDisplay) {
  
            InputBarPrintInput (LastColumn, LastRow);
  
          }
        }
      } else if (KeyData.Key.UnicodeChar <= 127 && KeyData.Key.UnicodeChar >= 32) {
        //
        // VALID ASCII char pressed
        //
        mReturnString[Size] = KeyData.Key.UnicodeChar;
  
        //
        // should be less than specified length
        //
        if (Size >= StringSize) {
          continue;
        }
  
        Size++;
  
        mReturnString[Size] = CHAR_NULL;
  
        if (!NoDisplay) {
  
          InputBarPrintInput (LastColumn, LastRow);
  
        } else {
          //
          // if just choose yes/no
          //
          break;
        }
  
      }
    }
  
    mReturnString[Size] = CHAR_NULL;
  
  
    //
    // restore screen attributes
    //
    gST->ConOut->SetCursorPosition (gST->ConOut, CursorCol, CursorRow);
    gST->ConOut->SetAttribute (gST->ConOut, Orig.Data);
  
    return Status;
  }
  
  /**
    SetPrompt and wait for input.
  
    @param[in] Str                The prompt string.
  
    @retval EFI_SUCCESS           The operation was successful.
    @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
  **/
  EFI_STATUS
  InputBarSetPrompt (
    IN CONST CHAR16 *Str
    )
  {
    //
    // FREE the old mPrompt string
    //
    SHELL_FREE_NON_NULL (mPrompt);
  
    mPrompt = CatSPrint (NULL, L"%s ", Str);
    if (mPrompt == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  
    return EFI_SUCCESS;
  }
  
  /**
    Set the size of the string in characters.
  
    @param[in] Size               The max number of characters to accept.
  
    @retval EFI_SUCCESS           The operation was successful.
    @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
  **/
  EFI_STATUS
  InputBarSetStringSize (
    UINTN   Size
    )
  {
    //
    // free the old ReturnStirng
    //
    SHELL_FREE_NON_NULL (mReturnString);
  
    StringSize = Size;
    mReturnString = AllocateZeroPool ((StringSize + 1) * sizeof(mReturnString[0]));
    if (mReturnString == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
  
    return EFI_SUCCESS;
  }
  
  /**
    Function to retrieve the input from the user.
  
    @retval NULL                  No input has been received.
    @return The string that was input.
  **/
  CONST CHAR16*
  InputBarGetString (
    VOID
    )
  {
    return (mReturnString);
  }
  