예제 #1
0
/**
  Search an Option of a Question by its value.

  @param  Question               The Question
  @param  OptionValue            Value for Option to be searched.

  @retval Pointer                Pointer to the found Option.
  @retval NULL                   Option not found.

**/
DISPLAY_QUESTION_OPTION *
ValueToOption (
  IN FORM_DISPLAY_ENGINE_STATEMENT   *Question,
  IN EFI_HII_VALUE                   *OptionValue
  )
{
  LIST_ENTRY               *Link;
  DISPLAY_QUESTION_OPTION  *Option;
  INTN                     Result;
  EFI_HII_VALUE            Value;

  Link = GetFirstNode (&Question->OptionListHead);
  while (!IsNull (&Question->OptionListHead, Link)) {
    Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);

    ZeroMem (&Value, sizeof (EFI_HII_VALUE));
    Value.Type = Option->OptionOpCode->Type;
    CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
    
    if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
      return Option;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  return NULL;
}
/**
  Search an Option of a Question by its value.

  @param  Question               The Question
  @param  OptionValue            Value for Option to be searched.

  @retval Pointer                Pointer to the found Option.
  @retval NULL                   Option not found.

**/
QUESTION_OPTION *
ValueToOption (
  IN FORM_BROWSER_STATEMENT   *Question,
  IN EFI_HII_VALUE            *OptionValue
  )
{
  LIST_ENTRY       *Link;
  QUESTION_OPTION  *Option;
  INTN             Result;

  Link = GetFirstNode (&Question->OptionListHead);
  while (!IsNull (&Question->OptionListHead, Link)) {
    Option = QUESTION_OPTION_FROM_LINK (Link);

    if ((CompareHiiValue (&Option->Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
      return Option;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  return NULL;
}
예제 #3
0
QUESTION_OPTION *
ValueToOption (
  IN FORM_BROWSER_STATEMENT   *Question,
  IN EFI_HII_VALUE            *OptionValue
  )
/*++

Routine Description:
  Search an Option of a Question by its value.

Arguments:
  Question         - The Question
  OptionValue      - Value for Option to be searched.

Returns:
  Pointer  - Pointer to the found Option.
  NULL     - Option not found.

--*/
{
  EFI_LIST_ENTRY   *Link;
  QUESTION_OPTION  *Option;

  Link = GetFirstNode (&Question->OptionListHead);
  while (!IsNull (&Question->OptionListHead, Link)) {
    Option = QUESTION_OPTION_FROM_LINK (Link);

    if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) {
      return Option;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  return NULL;
}
예제 #4
0
/**
  Get selection for OneOf and OrderedList (Left/Right will be ignored).

  @param  Selection         Pointer to current selection.
  @param  MenuOption        Pointer to the current input menu.

  @retval EFI_SUCCESS       If Option input is processed successfully
  @retval EFI_DEVICE_ERROR  If operation fails

**/
EFI_STATUS
GetSelectionInputPopUp (
    IN  UI_MENU_SELECTION           *Selection,
    IN  UI_MENU_OPTION              *MenuOption
)
{
    EFI_STATUS              Status;
    EFI_INPUT_KEY           Key;
    UINTN                   Index;
    CHAR16                  *StringPtr;
    CHAR16                  *TempStringPtr;
    UINTN                   Index2;
    UINTN                   TopOptionIndex;
    UINTN                   HighlightOptionIndex;
    UINTN                   Start;
    UINTN                   End;
    UINTN                   Top;
    UINTN                   Bottom;
    UINTN                   PopUpMenuLines;
    UINTN                   MenuLinesInView;
    UINTN                   PopUpWidth;
    CHAR16                  Character;
    INT32                   SavedAttribute;
    BOOLEAN                 ShowDownArrow;
    BOOLEAN                 ShowUpArrow;
    UINTN                   DimensionsWidth;
    LIST_ENTRY              *Link;
    BOOLEAN                 OrderedList;
    UINT8                   *ValueArray;
    UINT8                   ValueType;
    EFI_HII_VALUE           HiiValue;
    EFI_HII_VALUE           *HiiValueArray;
    UINTN                   OptionCount;
    QUESTION_OPTION         *OneOfOption;
    QUESTION_OPTION         *CurrentOption;
    FORM_BROWSER_STATEMENT  *Question;
    INTN                    Result;

    DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;

    ValueArray        = NULL;
    ValueType         = 0;
    CurrentOption     = NULL;
    ShowDownArrow     = FALSE;
    ShowUpArrow       = FALSE;

    StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
    ASSERT (StringPtr);

    Question = MenuOption->ThisTag;
    if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
        ValueArray = Question->BufferValue;
        ValueType = Question->ValueType;
        OrderedList = TRUE;
    } else {
        OrderedList = FALSE;
    }

    //
    // Calculate Option count
    //
    if (OrderedList) {
        for (Index = 0; Index < Question->MaxContainers; Index++) {
            if (GetArrayData (ValueArray, ValueType, Index) == 0) {
                break;
            }
        }

        OptionCount = Index;
    } else {
        OptionCount = 0;
        Link = GetFirstNode (&Question->OptionListHead);
        while (!IsNull (&Question->OptionListHead, Link)) {
            OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

            OptionCount++;

            Link = GetNextNode (&Question->OptionListHead, Link);
        }
    }

    //
    // Prepare HiiValue array
    //
    HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
    ASSERT (HiiValueArray != NULL);
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < OptionCount; Index++) {
        if (OrderedList) {
            HiiValueArray[Index].Type = ValueType;
            HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
        } else {
            OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
            CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));
            Link = GetNextNode (&Question->OptionListHead, Link);
        }
    }

    //
    // Move Suppressed Option to list tail
    //
    PopUpMenuLines = 0;
    for (Index = 0; Index < OptionCount; Index++) {
        OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
        if (OneOfOption == NULL) {
            return EFI_NOT_FOUND;
        }

        RemoveEntryList (&OneOfOption->Link);

        if ((OneOfOption->SuppressExpression != NULL) &&
                EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
            //
            // This option is suppressed, insert to tail
            //
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
        } else {
            //
            // Insert to head
            //
            InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);

            PopUpMenuLines++;
        }
    }

    //
    // Get the number of one of options present and its size
    //
    PopUpWidth = 0;
    HighlightOptionIndex = 0;
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < PopUpMenuLines; Index++) {
        OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

        StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
        if (StrLen (StringPtr) > PopUpWidth) {
            PopUpWidth = StrLen (StringPtr);
        }
        FreePool (StringPtr);

        if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
            //
            // Find current selected Option for OneOf
            //
            HighlightOptionIndex = Index;
        }

        Link = GetNextNode (&Question->OptionListHead, Link);
    }

    //
    // Perform popup menu initialization.
    //
    PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;

    SavedAttribute = gST->ConOut->Mode->Attribute;
    gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);

    if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
        PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
    }

    Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
    End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
    Top    = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
    Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1;

    MenuLinesInView = Bottom - Top - 1;
    if (MenuLinesInView >= PopUpMenuLines) {
        Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
        Bottom  = Top + PopUpMenuLines + 1;
    } else {
        ShowDownArrow = TRUE;
    }

    if (HighlightOptionIndex > (MenuLinesInView - 1)) {
        TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
    } else {
        TopOptionIndex = 0;
    }

    do {
        //
        // Clear that portion of the screen
        //
        ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);

        //
        // Draw "One of" pop-up menu
        //
        Character = BOXDRAW_DOWN_RIGHT;
        PrintCharAt (Start, Top, Character);
        for (Index = Start; Index + 2 < End; Index++) {
            if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
                Character = GEOMETRICSHAPE_UP_TRIANGLE;
            } else {
                Character = BOXDRAW_HORIZONTAL;
            }

            PrintChar (Character);
        }

        Character = BOXDRAW_DOWN_LEFT;
        PrintChar (Character);
        Character = BOXDRAW_VERTICAL;
        for (Index = Top + 1; Index < Bottom; Index++) {
            PrintCharAt (Start, Index, Character);
            PrintCharAt (End - 1, Index, Character);
        }

        //
        // Move to top Option
        //
        Link = GetFirstNode (&Question->OptionListHead);
        for (Index = 0; Index < TopOptionIndex; Index++) {
            Link = GetNextNode (&Question->OptionListHead, Link);
        }

        //
        // Display the One of options
        //
        Index2 = Top + 1;
        for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
            OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
            Link = GetNextNode (&Question->OptionListHead, Link);

            StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
            ASSERT (StringPtr != NULL);
            //
            // If the string occupies multiple lines, truncate it to fit in one line,
            // and append a "..." for indication.
            //
            if (StrLen (StringPtr) > (PopUpWidth - 1)) {
                TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
                ASSERT ( TempStringPtr != NULL );
                CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
                FreePool (StringPtr);
                StringPtr = TempStringPtr;
                StrCat (StringPtr, L"...");
            }

            if (Index == HighlightOptionIndex) {
                //
                // Highlight the selected one
                //
                CurrentOption = OneOfOption;

                gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
                PrintStringAt (Start + 2, Index2, StringPtr);
                gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
            } else {
                gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
                PrintStringAt (Start + 2, Index2, StringPtr);
            }

            Index2++;
            FreePool (StringPtr);
        }

        Character = BOXDRAW_UP_RIGHT;
        PrintCharAt (Start, Bottom, Character);
        for (Index = Start; Index + 2 < End; Index++) {
            if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
                Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
            } else {
                Character = BOXDRAW_HORIZONTAL;
            }

            PrintChar (Character);
        }

        Character = BOXDRAW_UP_LEFT;
        PrintChar (Character);

        //
        // Get User selection
        //
        Key.UnicodeChar = CHAR_NULL;
        if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
            Key.ScanCode  = gDirection;
            gDirection    = 0;
            goto TheKey;
        }

        Status = WaitForKeyStroke (&Key);

TheKey:
        switch (Key.UnicodeChar) {
        case '+':
            if (OrderedList) {
                if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
                    //
                    // Highlight reaches the top of the popup window, scroll one menu item.
                    //
                    TopOptionIndex--;
                    ShowDownArrow = TRUE;
                }

                if (TopOptionIndex == 0) {
                    ShowUpArrow = FALSE;
                }

                if (HighlightOptionIndex > 0) {
                    HighlightOptionIndex--;

                    ASSERT (CurrentOption != NULL);
                    SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
                }
            }
            break;

        case '-':
            //
            // If an ordered list op-code, we will allow for a popup of +/- keys
            // to create an ordered list of items
            //
            if (OrderedList) {
                if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
                        (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
                    //
                    // Highlight reaches the bottom of the popup window, scroll one menu item.
                    //
                    TopOptionIndex++;
                    ShowUpArrow = TRUE;
                }

                if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
                    ShowDownArrow = FALSE;
                }

                if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
                    HighlightOptionIndex++;

                    ASSERT (CurrentOption != NULL);
                    SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
                }
            }
            break;

        case CHAR_NULL:
            switch (Key.ScanCode) {
            case SCAN_UP:
            case SCAN_DOWN:
                if (Key.ScanCode == SCAN_UP) {
                    if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
                        //
                        // Highlight reaches the top of the popup window, scroll one menu item.
                        //
                        TopOptionIndex--;
                        ShowDownArrow = TRUE;
                    }

                    if (TopOptionIndex == 0) {
                        ShowUpArrow = FALSE;
                    }

                    if (HighlightOptionIndex > 0) {
                        HighlightOptionIndex--;
                    }
                } else {
                    if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
                            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
                        //
                        // Highlight reaches the bottom of the popup window, scroll one menu item.
                        //
                        TopOptionIndex++;
                        ShowUpArrow = TRUE;
                    }

                    if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
                        ShowDownArrow = FALSE;
                    }

                    if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
                        HighlightOptionIndex++;
                    }
                }
                break;

            case SCAN_ESC:
                gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

                //
                // Restore link list order for orderedlist
                //
                if (OrderedList) {
                    HiiValue.Type = ValueType;
                    HiiValue.Value.u64 = 0;
                    for (Index = 0; Index < Question->MaxContainers; Index++) {
                        HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
                        if (HiiValue.Value.u64 == 0) {
                            break;
                        }

                        OneOfOption = ValueToOption (Question, &HiiValue);
                        if (OneOfOption == NULL) {
                            return EFI_NOT_FOUND;
                        }

                        RemoveEntryList (&OneOfOption->Link);
                        InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
                    }
                }

                FreePool (HiiValueArray);
                return EFI_DEVICE_ERROR;

            default:
                break;
            }

            break;

        case CHAR_CARRIAGE_RETURN:
            //
            // return the current selection
            //
            if (OrderedList) {
                Index = 0;
                Link = GetFirstNode (&Question->OptionListHead);
                while (!IsNull (&Question->OptionListHead, Link)) {
                    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);

                    SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);

                    Index++;
                    if (Index > Question->MaxContainers) {
                        break;
                    }

                    Link = GetNextNode (&Question->OptionListHead, Link);
                }
            } else {
                ASSERT (CurrentOption != NULL);
                CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
            }

            gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
            FreePool (HiiValueArray);

            Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
            if (EFI_ERROR (Status)) {
                //
                // Input value is not valid, restore Question Value
                //
                GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
            } else {
                SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
                UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
            }

            return Status;

        default:
            break;
        }
    } while (TRUE);

}
예제 #5
0
/**
  Get selection for OneOf and OrderedList (Left/Right will be ignored).

  @param  MenuOption        Pointer to the current input menu.

  @retval EFI_SUCCESS       If Option input is processed successfully
  @retval EFI_DEVICE_ERROR  If operation fails

**/
EFI_STATUS
GetSelectionInputPopUp (
  IN  UI_MENU_OPTION              *MenuOption
  )
{
  EFI_STATUS              Status;
  EFI_INPUT_KEY           Key;
  UINTN                   Index;
  CHAR16                  *StringPtr;
  CHAR16                  *TempStringPtr;
  UINTN                   Index2;
  UINTN                   TopOptionIndex;
  UINTN                   HighlightOptionIndex;
  UINTN                   Start;
  UINTN                   End;
  UINTN                   Top;
  UINTN                   Bottom;
  UINTN                   PopUpMenuLines;
  UINTN                   MenuLinesInView;
  UINTN                   PopUpWidth;
  CHAR16                  Character;
  INT32                   SavedAttribute;
  BOOLEAN                 ShowDownArrow;
  BOOLEAN                 ShowUpArrow;
  UINTN                   DimensionsWidth;
  LIST_ENTRY              *Link;
  BOOLEAN                 OrderedList;
  UINT8                   *ValueArray;
  UINT8                   *ReturnValue;
  UINT8                   ValueType;
  EFI_HII_VALUE           HiiValue;
  DISPLAY_QUESTION_OPTION         *OneOfOption;
  DISPLAY_QUESTION_OPTION         *CurrentOption;
  FORM_DISPLAY_ENGINE_STATEMENT  *Question;
  INTN                    Result;
  EFI_IFR_ORDERED_LIST    *OrderList;

  DimensionsWidth   = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;

  ValueArray        = NULL;
  ValueType         = 0;
  CurrentOption     = NULL;
  ShowDownArrow     = FALSE;
  ShowUpArrow       = FALSE;

  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
  ASSERT (StringPtr);

  ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));

  Question = MenuOption->ThisTag;
  if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
    Link = GetFirstNode (&Question->OptionListHead);
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
    ValueArray = Question->CurrentValue.Buffer;
    ValueType =  OneOfOption->OptionOpCode->Type;
    OrderedList = TRUE;
    OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
  } else {
    OrderedList = FALSE;
    OrderList = NULL;
  }

  //
  // Calculate Option count
  //
  PopUpMenuLines = 0;
  if (OrderedList) {
    AdjustOptionOrder(Question, &PopUpMenuLines);
  } else {
    Link = GetFirstNode (&Question->OptionListHead);
    while (!IsNull (&Question->OptionListHead, Link)) {
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
      PopUpMenuLines++;
      Link = GetNextNode (&Question->OptionListHead, Link);
    }
  }

  //
  // Get the number of one of options present and its size
  //
  PopUpWidth = 0;
  HighlightOptionIndex = 0;
  Link = GetFirstNode (&Question->OptionListHead);
  for (Index = 0; Index < PopUpMenuLines; Index++) {
    OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);

    StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
    if (StrLen (StringPtr) > PopUpWidth) {
      PopUpWidth = StrLen (StringPtr);
    }
    FreePool (StringPtr);
    HiiValue.Type = OneOfOption->OptionOpCode->Type;
    SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
    if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
      //
      // Find current selected Option for OneOf
      //
      HighlightOptionIndex = Index;
    }

    Link = GetNextNode (&Question->OptionListHead, Link);
  }

  //
  // Perform popup menu initialization.
  //
  PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;

  SavedAttribute = gST->ConOut->Mode->Attribute;
  gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());

  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
  }

  Start  = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
  End    = Start + PopUpWidth + POPUP_FRAME_WIDTH;
  Top    = gStatementDimensions.TopRow;
  Bottom = gStatementDimensions.BottomRow - 1;

  MenuLinesInView = Bottom - Top - 1;
  if (MenuLinesInView >= PopUpMenuLines) {
    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
    Bottom  = Top + PopUpMenuLines + 1;
  } else {
    ShowDownArrow = TRUE;
  }

  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
  } else {
    TopOptionIndex = 0;
  }

  do {
    //
    // Clear that portion of the screen
    //
    ClearLines (Start, End, Top, Bottom, GetPopupColor ());

    //
    // Draw "One of" pop-up menu
    //
    Character = BOXDRAW_DOWN_RIGHT;
    PrintCharAt (Start, Top, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_UP_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    }

    Character = BOXDRAW_DOWN_LEFT;
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    Character = BOXDRAW_VERTICAL;
    for (Index = Top + 1; Index < Bottom; Index++) {
      PrintCharAt (Start, Index, Character);
      PrintCharAt (End - 1, Index, Character);
    }

    //
    // Move to top Option
    //
    Link = GetFirstNode (&Question->OptionListHead);
    for (Index = 0; Index < TopOptionIndex; Index++) {
      Link = GetNextNode (&Question->OptionListHead, Link);
    }

    //
    // Display the One of options
    //
    Index2 = Top + 1;
    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
      OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
      Link = GetNextNode (&Question->OptionListHead, Link);

      StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
      ASSERT (StringPtr != NULL);
      //
      // If the string occupies multiple lines, truncate it to fit in one line,
      // and append a "..." for indication.
      //
      if (StrLen (StringPtr) > (PopUpWidth - 1)) {
        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
        ASSERT ( TempStringPtr != NULL );
        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
        FreePool (StringPtr);
        StringPtr = TempStringPtr;
        StrCat (StringPtr, L"...");
      }

      if (Index == HighlightOptionIndex) {
          //
          // Highlight the selected one
          //
          CurrentOption = OneOfOption;

          gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
          PrintStringAt (Start + 2, Index2, StringPtr);
          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
        } else {
          gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
          PrintStringAt (Start + 2, Index2, StringPtr);
        }

      Index2++;
      FreePool (StringPtr);
    }

    Character = BOXDRAW_UP_RIGHT;
    PrintCharAt (Start, Bottom, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
      } else {
        Character = BOXDRAW_HORIZONTAL;
      }

      PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
    }

    Character = BOXDRAW_UP_LEFT;
    PrintCharAt ((UINTN)-1, (UINTN)-1, Character);

    //
    // Get User selection
    //
    Key.UnicodeChar = CHAR_NULL;
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
      Key.ScanCode  = gDirection;
      gDirection    = 0;
      goto TheKey;
    }

    Status = WaitForKeyStroke (&Key);

TheKey:
    switch (Key.UnicodeChar) {
    case '+':
      if (OrderedList) {
        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
          //
          // Highlight reaches the top of the popup window, scroll one menu item.
          //
          TopOptionIndex--;
          ShowDownArrow = TRUE;
        }

        if (TopOptionIndex == 0) {
          ShowUpArrow = FALSE;
        }

        if (HighlightOptionIndex > 0) {
          HighlightOptionIndex--;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
        }
      }
      break;

    case '-':
      //
      // If an ordered list op-code, we will allow for a popup of +/- keys
      // to create an ordered list of items
      //
      if (OrderedList) {
        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
          //
          // Highlight reaches the bottom of the popup window, scroll one menu item.
          //
          TopOptionIndex++;
          ShowUpArrow = TRUE;
        }

        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
          ShowDownArrow = FALSE;
        }

        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
          HighlightOptionIndex++;

          ASSERT (CurrentOption != NULL);
          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
        }
      }
      break;

    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_UP:
      case SCAN_DOWN:
        if (Key.ScanCode == SCAN_UP) {
          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
            //
            // Highlight reaches the top of the popup window, scroll one menu item.
            //
            TopOptionIndex--;
            ShowDownArrow = TRUE;
          }

          if (TopOptionIndex == 0) {
            ShowUpArrow = FALSE;
          }

          if (HighlightOptionIndex > 0) {
            HighlightOptionIndex--;
          }
        } else {
          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
            //
            // Highlight reaches the bottom of the popup window, scroll one menu item.
            //
            TopOptionIndex++;
            ShowUpArrow = TRUE;
          }

          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
            ShowDownArrow = FALSE;
          }

          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
            HighlightOptionIndex++;
          }
        }
        break;

      case SCAN_ESC:
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

        //
        // Restore link list order for orderedlist
        //
        if (OrderedList) {
          HiiValue.Type = ValueType;
          HiiValue.Value.u64 = 0;
          for (Index = 0; Index < OrderList->MaxContainers; Index++) {
            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
            if (HiiValue.Value.u64 == 0) {
              break;
            }

            OneOfOption = ValueToOption (Question, &HiiValue);
            if (OneOfOption == NULL) {
              return EFI_NOT_FOUND;
            }

            RemoveEntryList (&OneOfOption->Link);
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
          }
        }

        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

    case CHAR_CARRIAGE_RETURN:
      //
      // return the current selection
      //
      if (OrderedList) {
        ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
        ASSERT (ReturnValue != NULL);
        Index = 0;
        Link = GetFirstNode (&Question->OptionListHead);
        while (!IsNull (&Question->OptionListHead, Link)) {
          OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
          Link = GetNextNode (&Question->OptionListHead, Link);

          SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);

          Index++;
          if (Index > OrderList->MaxContainers) {
            break;
          }
        }
        if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
          FreePool (ReturnValue);
          return EFI_DEVICE_ERROR;
        } else {
          gUserInput->InputValue.Buffer = ReturnValue;
          gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
          Status = EFI_SUCCESS;
        }
      } else {
        ASSERT (CurrentOption != NULL);
        gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
        if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
          return EFI_DEVICE_ERROR;
        } else {
          SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
          Status = EFI_SUCCESS;
        }
      }

      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);

      return EFI_SUCCESS;
      
    default:
      break;
    }
  } while (TRUE);

}
예제 #6
0
파일: Expression.c 프로젝트: Kohrara/edk
EFI_STATUS
EvaluateExpression (
  IN FORM_BROWSER_FORMSET  *FormSet,
  IN FORM_BROWSER_FORM     *Form,
  IN OUT FORM_EXPRESSION   *Expression
  )
/*++

Routine Description:

  Evaluate the result of a HII expression

Arguments:

  FormSet    - FormSet associated with this expression.
  Form       - Form associated with this expression.
  Expression - Expression to be evaluated.

Returns:

  EFI_SUCCESS           - The expression evaluated successfuly
  EFI_NOT_FOUND         - The Question which referenced by a QuestionId could not be found.
  EFI_OUT_OF_RESOURCES  - There is not enough system memory to grow the stack.
  EFI_ACCESS_DENIED     - The pop operation underflowed the stack
  EFI_INVALID_PARAMETER - Syntax error with the Expression

--*/
{
  EFI_STATUS              Status;
  EFI_LIST_ENTRY          *Link;
  EXPRESSION_OPCODE       *OpCode;
  FORM_BROWSER_STATEMENT  *Question;
  FORM_BROWSER_STATEMENT  *Question2;
  UINT16                  Index;
  EFI_HII_VALUE           Data1;
  EFI_HII_VALUE           Data2;
  EFI_HII_VALUE           Data3;
  FORM_EXPRESSION         *RuleExpression;
  EFI_HII_VALUE           *Value;
  INTN                    Result;
  CHAR16                  *StrPtr;

  //
  // Always reset the stack before evaluating an Expression
  //
  ResetExpressionStack ();

  Expression->Result.Type = EFI_IFR_TYPE_OTHER;

  Link = GetFirstNode (&Expression->OpCodeListHead);
  while (!IsNull (&Expression->OpCodeListHead, Link)) {
    OpCode = EXPRESSION_OPCODE_FROM_LINK (Link);

    Link = GetNextNode (&Expression->OpCodeListHead, Link);

    EfiZeroMem (&Data1, sizeof (EFI_HII_VALUE));
    EfiZeroMem (&Data2, sizeof (EFI_HII_VALUE));
    EfiZeroMem (&Data3, sizeof (EFI_HII_VALUE));

    Value = &Data3;
    Value->Type = EFI_IFR_TYPE_BOOLEAN;
    Status = EFI_SUCCESS;

    switch (OpCode->Operand) {
    //
    // Built-in functions
    //
    case EFI_IFR_EQ_ID_VAL_OP:
      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
      if (Question == NULL) {
        return EFI_NOT_FOUND;
      }

      Result = CompareHiiValue (&Question->HiiValue, &OpCode->Value, NULL);
      if (Result == EFI_INVALID_PARAMETER) {
        return EFI_INVALID_PARAMETER;
      }
      Value->Value.b = (Result == 0) ? TRUE : FALSE;
      break;

    case EFI_IFR_EQ_ID_ID_OP:
      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
      if (Question == NULL) {
        return EFI_NOT_FOUND;
      }

      Question2 = IdToQuestion (FormSet, Form, OpCode->QuestionId2);
      if (Question2 == NULL) {
        return EFI_NOT_FOUND;
      }

      Result = CompareHiiValue (&Question->HiiValue, &Question2->HiiValue, FormSet->HiiHandle);
      if (Result == EFI_INVALID_PARAMETER) {
        return EFI_INVALID_PARAMETER;
      }
      Value->Value.b = (Result == 0) ? TRUE : FALSE;
      break;

    case EFI_IFR_EQ_ID_LIST_OP:
      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
      if (Question == NULL) {
        return EFI_NOT_FOUND;
      }

      Value->Value.b = FALSE;
      for (Index =0; Index < OpCode->ListLength; Index++) {
        if (Question->HiiValue.Value.u16 == OpCode->ValueList[Index]) {
          Value->Value.b = TRUE;
          break;
        }
      }
      break;

    case EFI_IFR_DUP_OP:
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      Status = PushExpression (Value);
      break;

    case EFI_IFR_QUESTION_REF1_OP:
    case EFI_IFR_THIS_OP:
      Question = IdToQuestion (FormSet, Form, OpCode->QuestionId);
      if (Question == NULL) {
        return EFI_NOT_FOUND;
      }

      Value = &Question->HiiValue;
      break;

    case EFI_IFR_QUESTION_REF3_OP:
      if (OpCode->DevicePath == 0) {
        //
        // EFI_IFR_QUESTION_REF3
        // Pop an expression from the expression stack
        //
        Status = PopExpression (Value);
        if (EFI_ERROR (Status)) {
          return Status;
        }

        //
        // Validate the expression value
        //
        if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
          return EFI_NOT_FOUND;
        }

        Question = IdToQuestion (FormSet, Form, Value->Value.u16);
        if (Question == NULL) {
          return EFI_NOT_FOUND;
        }

        //
        // push the questions' value on to the expression stack
        //
        Value = &Question->HiiValue;
      } else {
        //
        // BUGBUG: push 0 for EFI_IFR_QUESTION_REF3_2 and EFI_IFR_QUESTION_REF3_3,
        // since it is impractical to evaluate the value of a Question in another
        // Hii Package list.
        //
        EfiZeroMem (Value, sizeof (EFI_HII_VALUE));
      }
      break;

    case EFI_IFR_RULE_REF_OP:
      //
      // Find expression for this rule
      //
      RuleExpression = RuleIdToExpression (Form, OpCode->RuleId);
      if (RuleExpression == NULL) {
        return EFI_NOT_FOUND;
      }

      //
      // Evaluate this rule expression
      //
      Status = EvaluateExpression (FormSet, Form, RuleExpression);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      Value = &RuleExpression->Result;
      break;

    case EFI_IFR_STRING_REF1_OP:
      Value->Type = EFI_IFR_TYPE_STRING;
      Value->Value.string = OpCode->Value.Value.string;
      break;

    //
    // Constant
    //
    case EFI_IFR_TRUE_OP:
    case EFI_IFR_FALSE_OP:
    case EFI_IFR_ONE_OP:
    case EFI_IFR_ONES_OP:
    case EFI_IFR_UINT8_OP:
    case EFI_IFR_UINT16_OP:
    case EFI_IFR_UINT32_OP:
    case EFI_IFR_UINT64_OP:
    case EFI_IFR_UNDEFINED_OP:
    case EFI_IFR_VERSION_OP:
    case EFI_IFR_ZERO_OP:
      Value = &OpCode->Value;
      break;

    //
    // unary-op
    //
    case EFI_IFR_LENGTH_OP:
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Value->Type != EFI_IFR_TYPE_STRING) {
        return EFI_INVALID_PARAMETER;
      }

      StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
      if (StrPtr == NULL) {
        return EFI_INVALID_PARAMETER;
      }

      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
      Value->Value.u64 = EfiStrLen (StrPtr);
      gBS->FreePool (StrPtr);
      break;

    case EFI_IFR_NOT_OP:
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Value->Type != EFI_IFR_TYPE_BOOLEAN) {
        return EFI_INVALID_PARAMETER;
      }
      Value->Value.b = !Value->Value.b;
      break;

    case EFI_IFR_QUESTION_REF2_OP:
      //
      // Pop an expression from the expression stack
      //
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      //
      // Validate the expression value
      //
      if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
        return EFI_NOT_FOUND;
      }

      Question = IdToQuestion (FormSet, Form, Value->Value.u16);
      if (Question == NULL) {
        return EFI_NOT_FOUND;
      }

      Value = &Question->HiiValue;
      break;

    case EFI_IFR_STRING_REF2_OP:
      //
      // Pop an expression from the expression stack
      //
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      //
      // Validate the expression value
      //
      if ((Value->Type > EFI_IFR_TYPE_NUM_SIZE_64) || (Value->Value.u64 > 0xffff)) {
        return EFI_NOT_FOUND;
      }

      Value->Type = EFI_IFR_TYPE_STRING;
      StrPtr = GetToken (Value->Value.u16, FormSet->HiiHandle);
      if (StrPtr == NULL) {
        //
        // If String not exit, push an empty string
        //
        Value->Value.string = NewString (gEmptyString, FormSet->HiiHandle);
      } else {
        Index = (UINT16) Value->Value.u64;
        Value->Value.string = Index;
        gBS->FreePool (StrPtr);
      }
      break;

    case EFI_IFR_TO_BOOLEAN_OP:
      //
      // Pop an expression from the expression stack
      //
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      //
      // Convert an expression to a Boolean
      //
      if (Value->Type <= EFI_IFR_TYPE_DATE) {
        //
        // When converting from an unsigned integer, zero will be converted to
        // FALSE and any other value will be converted to TRUE.
        //
        Value->Value.b = (Value->Value.u64) ? TRUE : FALSE;

        Value->Type = EFI_IFR_TYPE_BOOLEAN;
      } else if (Value->Type == EFI_IFR_TYPE_STRING) {
        //
        // When converting from a string, if case-insensitive compare
        // with "true" is True, then push True. If a case-insensitive compare
        // with "false" is True, then push False.
        //
        StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
        if (StrPtr == NULL) {
          return EFI_INVALID_PARAMETER;
        }

        if ((EfiStrCmp (StrPtr, L"true") == 0) || (EfiStrCmp (StrPtr, L"false") == 0)){
          Value->Value.b = TRUE;
        } else {
          Value->Value.b = FALSE;
        }
        gBS->FreePool (StrPtr);
        Value->Type = EFI_IFR_TYPE_BOOLEAN;
      }
      break;

    case EFI_IFR_TO_STRING_OP:
      Status = IfrToString (FormSet, OpCode->Format, Value);
      break;

    case EFI_IFR_TO_UINT_OP:
      Status = IfrToUint (FormSet, Value);
      break;

    case EFI_IFR_TO_LOWER_OP:
    case EFI_IFR_TO_UPPER_OP:
      Status = InitializeUnicodeCollationProtocol ();
      if (EFI_ERROR (Status)) {
        return Status;
      }

      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      if (Value->Type != EFI_IFR_TYPE_STRING) {
        return EFI_UNSUPPORTED;
      }

      StrPtr = GetToken (Value->Value.string, FormSet->HiiHandle);
      if (StrPtr == NULL) {
        return EFI_NOT_FOUND;
      }

      if (OpCode->Operand == EFI_IFR_TO_LOWER_OP) {
        mUnicodeCollation->StrLwr (mUnicodeCollation, StrPtr);
      } else {
        mUnicodeCollation->StrUpr (mUnicodeCollation, StrPtr);
      }
      Value->Value.string = NewString (StrPtr, FormSet->HiiHandle);
      gBS->FreePool (StrPtr);
      break;

    case EFI_IFR_BITWISE_NOT_OP:
      //
      // Pop an expression from the expression stack
      //
      Status = PopExpression (Value);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Value->Type > EFI_IFR_TYPE_DATE) {
        return EFI_INVALID_PARAMETER;
      }

      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;
      Value->Value.u64 = ~Value->Value.u64;
      break;

    //
    // binary-op
    //
    case EFI_IFR_ADD_OP:
    case EFI_IFR_SUBTRACT_OP:
    case EFI_IFR_MULTIPLY_OP:
    case EFI_IFR_DIVIDE_OP:
    case EFI_IFR_MODULO_OP:
    case EFI_IFR_BITWISE_AND_OP:
    case EFI_IFR_BITWISE_OR_OP:
    case EFI_IFR_SHIFT_LEFT_OP:
    case EFI_IFR_SHIFT_RIGHT_OP:
      //
      // Pop an expression from the expression stack
      //
      Status = PopExpression (&Data2);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data2.Type > EFI_IFR_TYPE_DATE) {
        return EFI_INVALID_PARAMETER;
      }

      //
      // Pop another expression from the expression stack
      //
      Status = PopExpression (&Data1);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data1.Type > EFI_IFR_TYPE_DATE) {
        return EFI_INVALID_PARAMETER;
      }

      Value->Type = EFI_IFR_TYPE_NUM_SIZE_64;

      switch (OpCode->Operand) {
        case EFI_IFR_ADD_OP:
          Value->Value.u64 = Data1.Value.u64 + Data2.Value.u64;
          break;

        case EFI_IFR_SUBTRACT_OP:
          Value->Value.u64 = Data1.Value.u64 - Data2.Value.u64;
          break;

        case EFI_IFR_MULTIPLY_OP:
          Value->Value.u64 = MultU64x32 (Data1.Value.u64, (UINTN) Data2.Value.u64);
          break;

        case EFI_IFR_DIVIDE_OP:
          Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINTN) Data2.Value.u64, NULL);
          break;

        case EFI_IFR_MODULO_OP:
          DivU64x32 (Data1.Value.u64, (UINTN) Data2.Value.u64, (UINTN *) &Value->Value.u64);
          break;

        case EFI_IFR_BITWISE_AND_OP:
          Value->Value.u64 = Data1.Value.u64 & Data2.Value.u64;
          break;

        case EFI_IFR_BITWISE_OR_OP:
          Value->Value.u64 = Data1.Value.u64 | Data2.Value.u64;
          break;

        case EFI_IFR_SHIFT_LEFT_OP:
          Value->Value.u64 = LShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
          break;

        case EFI_IFR_SHIFT_RIGHT_OP:
          Value->Value.u64 = RShiftU64 (Data1.Value.u64, (UINTN) Data2.Value.u64);
          break;

        default:
          break;
      }
      break;

    case EFI_IFR_AND_OP:
    case EFI_IFR_OR_OP:
      //
      // Two Boolean operator
      //
      Status = PopExpression (&Data2);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data2.Type != EFI_IFR_TYPE_BOOLEAN) {
        return EFI_INVALID_PARAMETER;
      }

      //
      // Pop another expression from the expression stack
      //
      Status = PopExpression (&Data1);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
        return EFI_INVALID_PARAMETER;
      }

      if (OpCode->Operand == EFI_IFR_AND_OP) {
        Value->Value.b = Data1.Value.b && Data2.Value.b;
      } else {
        Value->Value.b = Data1.Value.b || Data2.Value.b;
      }
      break;

    case EFI_IFR_EQUAL_OP:
    case EFI_IFR_NOT_EQUAL_OP:
    case EFI_IFR_GREATER_EQUAL_OP:
    case EFI_IFR_GREATER_THAN_OP:
    case EFI_IFR_LESS_EQUAL_OP:
    case EFI_IFR_LESS_THAN_OP:
      //
      // Compare two integer, string, boolean or date/time
      //
      Status = PopExpression (&Data2);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data2.Type > EFI_IFR_TYPE_BOOLEAN && Data2.Type != EFI_IFR_TYPE_STRING) {
        return EFI_INVALID_PARAMETER;
      }

      //
      // Pop another expression from the expression stack
      //
      Status = PopExpression (&Data1);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      Result = CompareHiiValue (&Data1, &Data2, FormSet->HiiHandle);
      if (Result == EFI_INVALID_PARAMETER) {
        return EFI_INVALID_PARAMETER;
      }

      switch (OpCode->Operand) {
      case EFI_IFR_EQUAL_OP:
        Value->Value.b = (Result == 0) ? TRUE : FALSE;
        break;

      case EFI_IFR_NOT_EQUAL_OP:
        Value->Value.b = (Result != 0) ? TRUE : FALSE;
        break;

      case EFI_IFR_GREATER_EQUAL_OP:
        Value->Value.b = (Result >= 0) ? TRUE : FALSE;
        break;

      case EFI_IFR_GREATER_THAN_OP:
        Value->Value.b = (Result > 0) ? TRUE : FALSE;
        break;

      case EFI_IFR_LESS_EQUAL_OP:
        Value->Value.b = (Result <= 0) ? TRUE : FALSE;
        break;

      case EFI_IFR_LESS_THAN_OP:
        Value->Value.b = (Result < 0) ? TRUE : FALSE;
        break;

      default:
        break;
      }
      break;

    case EFI_IFR_MATCH_OP:
      Status = IfrMatch (FormSet, Value);
      break;

    case EFI_IFR_CATENATE_OP:
      Status = IfrCatenate (FormSet, Value);
      break;

    //
    // ternary-op
    //
    case EFI_IFR_CONDITIONAL_OP:
      //
      // Pop third expression from the expression stack
      //
      Status = PopExpression (&Data3);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      //
      // Pop second expression from the expression stack
      //
      Status = PopExpression (&Data2);
      if (EFI_ERROR (Status)) {
        return Status;
      }

      //
      // Pop first expression from the expression stack
      //
      Status = PopExpression (&Data1);
      if (EFI_ERROR (Status)) {
        return Status;
      }
      if (Data1.Type != EFI_IFR_TYPE_BOOLEAN) {
        return EFI_INVALID_PARAMETER;
      }

      if (Data1.Value.b) {
        Value = &Data3;
      } else {
        Value = &Data2;
      }
      break;

    case EFI_IFR_FIND_OP:
      Status = IfrFind (FormSet, OpCode->Format, Value);
      break;

    case EFI_IFR_MID_OP:
      Status = IfrMid (FormSet, Value);
      break;

    case EFI_IFR_TOKEN_OP:
      Status = IfrToken (FormSet, Value);
      break;

    case EFI_IFR_SPAN_OP:
      Status = IfrSpan (FormSet, OpCode->Flags, Value);
      break;

    default:
      break;
    }
    if (EFI_ERROR (Status)) {
      return Status;
    }

    Status = PushExpression (Value);
    if (EFI_ERROR (Status)) {
      return Status;
    }
  }

  //
  // Pop the final result from expression stack
  //
  Value = &Data1;
  Status = PopExpression (Value);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  //
  // After evaluating an expression, there should be only one value left on the expression stack
  //
  if (PopExpression (Value) != EFI_ACCESS_DENIED) {
    return EFI_INVALID_PARAMETER;
  }

  EfiCopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE));

  return EFI_SUCCESS;
}