/** 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; }
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; }
/** 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); }
/** 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); }
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; }