diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h index 1b355ec5b6..94c3368c3a 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Colors.h @@ -1,4 +1,5 @@ /** @file +MACRO definitions for color used in Setup Browser. Copyright (c) 2004, Intel Corporation All rights reserved. This program and the accompanying materials @@ -9,20 +10,12 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - Colors.h - -Abstract: - - -Revision History - - **/ +// +// Unicode collation protocol in -#ifndef _COLORS_H -#define _COLORS_H +#ifndef _COLORS_H_ +#define _COLORS_H_ // // Screen Color Settings diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c index a074b92a27..25d4e0a678 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Expression.c @@ -1,1938 +1,1925 @@ -/** @file - -Copyright (c) 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Expression.c - -Abstract: - - Expression evaluation. - - -**/ - -#include "Ui.h" -#include "Setup.h" - -// -// Global stack used to evaluate boolean expresions -// -EFI_HII_VALUE *mOpCodeScopeStack = NULL; -EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; -EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; - -EFI_HII_VALUE *mExpressionEvaluationStack = NULL; -EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL; -EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL; - -// -// Unicode collation protocol interface -// -EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; - - -/** - Grow size of the stack - - @param Stack On input: old stack; On output: new stack - @param StackPtr On input: old stack pointer; On output: new stack - pointer - @param StackPtr On input: old stack end; On output: new stack end - - @retval EFI_SUCCESS Grow stack success. - @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. - -**/ -STATIC -EFI_STATUS -GrowStack ( - IN OUT EFI_HII_VALUE **Stack, - IN OUT EFI_HII_VALUE **StackPtr, - IN OUT EFI_HII_VALUE **StackEnd - ) -{ - UINTN Size; - EFI_HII_VALUE *NewStack; - - Size = EXPRESSION_STACK_SIZE_INCREMENT; - if (*StackPtr != NULL) { - Size = Size + (*StackEnd - *Stack); - } - - NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE)); - if (NewStack == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - if (*StackPtr != NULL) { - // - // Copy from Old Stack to the New Stack - // - CopyMem ( - NewStack, - *Stack, - (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE) - ); - - // - // Free The Old Stack - // - gBS->FreePool (*Stack); - } - - // - // Make the Stack pointer point to the old data in the new stack - // - *StackPtr = NewStack + (*StackPtr - *Stack); - *Stack = NewStack; - *StackEnd = NewStack + Size; - - return EFI_SUCCESS; -} - - -/** - Push an element onto the Boolean Stack - - @param Stack On input: old stack; On output: new stack - @param StackPtr On input: old stack pointer; On output: new stack - pointer - @param StackPtr On input: old stack end; On output: new stack end - @param Data Data to push. - - @retval EFI_SUCCESS Push stack success. - -**/ -EFI_STATUS -PushStack ( - IN OUT EFI_HII_VALUE **Stack, - IN OUT EFI_HII_VALUE **StackPtr, - IN OUT EFI_HII_VALUE **StackEnd, - IN EFI_HII_VALUE *Data - ) -{ - EFI_STATUS Status; - - // - // Check for a stack overflow condition - // - if (*StackPtr >= *StackEnd) { - // - // Grow the stack - // - Status = GrowStack (Stack, StackPtr, StackEnd); - if (EFI_ERROR (Status)) { - return Status; - } - } - - // - // Push the item onto the stack - // - CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); - *StackPtr = *StackPtr + 1; - - return EFI_SUCCESS; -} - - -/** - Pop an element from the stack. - - @param Stack On input: old stack; On output: new stack - @param StackPtr On input: old stack pointer; On output: new stack - pointer - @param StackPtr On input: old stack end; On output: new stack end - @param Data Data to pop. - - @retval EFI_SUCCESS The value was popped onto the stack. - @retval EFI_ACCESS_DENIED The pop operation underflowed the stack - -**/ -EFI_STATUS -PopStack ( - IN OUT EFI_HII_VALUE **Stack, - IN OUT EFI_HII_VALUE **StackPtr, - IN OUT EFI_HII_VALUE **StackEnd, - OUT EFI_HII_VALUE *Data - ) -{ - // - // Check for a stack underflow condition - // - if (*StackPtr == *Stack) { - return EFI_ACCESS_DENIED; - } - - // - // Pop the item off the stack - // - *StackPtr = *StackPtr - 1; - CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); - return EFI_SUCCESS; -} - - -/** - Reset stack pointer to begin of the stack. - - None. - - @return None. - -**/ -VOID -ResetScopeStack ( - VOID - ) -{ - mOpCodeScopeStackPointer = mOpCodeScopeStack; -} - - -/** - Push an Operand onto the Stack - - @param Operand Operand to push. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - -**/ -EFI_STATUS -PushScope ( - IN UINT8 Operand - ) -{ - EFI_HII_VALUE Data; - - Data.Type = EFI_IFR_TYPE_NUM_SIZE_8; - Data.Value.u8 = Operand; - - return PushStack ( - &mOpCodeScopeStack, - &mOpCodeScopeStackPointer, - &mOpCodeScopeStackEnd, - &Data - ); -} - - -/** - Pop an Operand from the Stack - - @param Operand Operand to pop. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - -**/ -EFI_STATUS -PopScope ( - OUT UINT8 *Operand - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Data; - - Status = PopStack ( - &mOpCodeScopeStack, - &mOpCodeScopeStackPointer, - &mOpCodeScopeStackEnd, - &Data - ); - - *Operand = Data.Value.u8; - - return Status; -} - - -/** - Reset stack pointer to begin of the stack. - - None. - - @return None. - -**/ -VOID -ResetExpressionStack ( - VOID - ) -{ - mExpressionEvaluationStackPointer = mExpressionEvaluationStack; -} - - -/** - Push an Expression value onto the Stack - - @param Value Expression value to push. - - @retval EFI_SUCCESS The value was pushed onto the stack. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - -**/ -EFI_STATUS -PushExpression ( - IN EFI_HII_VALUE *Value - ) -{ - return PushStack ( - &mExpressionEvaluationStack, - &mExpressionEvaluationStackPointer, - &mExpressionEvaluationStackEnd, - Value - ); -} - - -/** - Pop an Expression value from the stack. - - @param Value Expression value to pop. - - @retval EFI_SUCCESS The value was popped onto the stack. - @retval EFI_ACCESS_DENIED The pop operation underflowed the stack - -**/ -EFI_STATUS -PopExpression ( - OUT EFI_HII_VALUE *Value - ) -{ - return PopStack ( - &mExpressionEvaluationStack, - &mExpressionEvaluationStackPointer, - &mExpressionEvaluationStackEnd, - Value - ); -} - - -/** - Get Form given its FormId. - - @param FormSet The formset which contains this form. - @param FormId Id of this form. - - @retval Pointer The form. - @retval NULL Specified Form is not found in the formset. - -**/ -FORM_BROWSER_FORM * -IdToForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT16 FormId -) -{ - LIST_ENTRY *Link; - FORM_BROWSER_FORM *Form; - - Link = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, Link)) { - Form = FORM_BROWSER_FORM_FROM_LINK (Link); - - if (Form->FormId == FormId) { - return Form; - } - - Link = GetNextNode (&FormSet->FormListHead, Link); - } - - return NULL; -} - - -/** - Search a Question in Form scope using its QuestionId. - - @param Form The form which contains this Question. - @param QuestionId Id of this Question. - - @retval Pointer The Question. - @retval NULL Specified Question not found in the form. - -**/ -FORM_BROWSER_STATEMENT * -IdToQuestion2 ( - IN FORM_BROWSER_FORM *Form, - IN UINT16 QuestionId - ) -{ - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Question; - - if (QuestionId == 0) { - // - // The value of zero is reserved - // - return NULL; - } - - Link = GetFirstNode (&Form->StatementListHead); - while (!IsNull (&Form->StatementListHead, Link)) { - Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - - if (Question->QuestionId == QuestionId) { - return Question; - } - - Link = GetNextNode (&Form->StatementListHead, Link); - } - - return NULL; -} - - -/** - Search a Question in Formset scope using its QuestionId. - - @param FormSet The formset which contains this form. - @param Form The form which contains this Question. - @param QuestionId Id of this Question. - - @retval Pointer The Question. - @retval NULL Specified Question not found in the form. - -**/ -FORM_BROWSER_STATEMENT * -IdToQuestion ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN UINT16 QuestionId - ) -{ - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Question; - - // - // Search in the form scope first - // - Question = IdToQuestion2 (Form, QuestionId); - if (Question != NULL) { - return Question; - } - - // - // Search in the formset scope - // - Link = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, Link)) { - Form = FORM_BROWSER_FORM_FROM_LINK (Link); - - Question = IdToQuestion2 (Form, QuestionId); - if (Question != NULL) { - return Question; - } - - Link = GetNextNode (&FormSet->FormListHead, Link); - } - - return NULL; -} - - -/** - Get Expression given its RuleId. - - @param Form The form which contains this Expression. - @param RuleId Id of this Expression. - - @retval Pointer The Expression. - @retval NULL Specified Expression not found in the form. - -**/ -FORM_EXPRESSION * -RuleIdToExpression ( - IN FORM_BROWSER_FORM *Form, - IN UINT8 RuleId - ) -{ - LIST_ENTRY *Link; - FORM_EXPRESSION *Expression; - - Link = GetFirstNode (&Form->ExpressionListHead); - while (!IsNull (&Form->ExpressionListHead, Link)) { - Expression = FORM_EXPRESSION_FROM_LINK (Link); - - if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) { - return Expression; - } - - Link = GetNextNode (&Form->ExpressionListHead, Link); - } - - return NULL; -} - - -/** - Locate the Unicode Collation Protocol interface for later use. - - None. - - @retval EFI_SUCCESS Protocol interface initialize success. - @retval Other Protocol interface initialize failed. - -**/ -EFI_STATUS -InitializeUnicodeCollationProtocol ( - VOID - ) -{ - EFI_STATUS Status; - - if (mUnicodeCollation != NULL) { - return EFI_SUCCESS; - } - - // - // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol - // instances first and then select one which support English language. - // Current implementation just pick the first instance. - // - Status = gBS->LocateProtocol ( - &gEfiUnicodeCollation2ProtocolGuid, - NULL, - (VOID **) &mUnicodeCollation - ); - return Status; -} - -VOID -IfrStrToUpper ( - CHAR16 *String - ) -{ - while (*String != 0) { - if ((*String >= 'a') && (*String <= 'z')) { - *String = (UINT16) ((*String) & ((UINT16) ~0x20)); - } - String++; - } -} - - -/** - Evaluate opcode EFI_IFR_TO_STRING. - - @param FormSet Formset which contains this opcode. - @param Format String format in EFI_IFR_TO_STRING. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrToString ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT8 Format, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String; - CHAR16 *PrintFormat; - CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; - UINTN BufferSize; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - - switch (Value.Type) { - case EFI_IFR_TYPE_NUM_SIZE_8: - case EFI_IFR_TYPE_NUM_SIZE_16: - case EFI_IFR_TYPE_NUM_SIZE_32: - case EFI_IFR_TYPE_NUM_SIZE_64: - BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); - switch (Format) { - case EFI_IFR_STRING_UNSIGNED_DEC: - case EFI_IFR_STRING_SIGNED_DEC: - PrintFormat = L"%ld"; - break; - - case EFI_IFR_STRING_LOWERCASE_HEX: - PrintFormat = L"%lx"; - break; - - case EFI_IFR_STRING_UPPERCASE_HEX: - PrintFormat = L"%lX"; - break; - - default: - return EFI_UNSUPPORTED; - } - UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); - String = Buffer; - break; - - case EFI_IFR_TYPE_STRING: - CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); - return EFI_SUCCESS; - - case EFI_IFR_TYPE_BOOLEAN: - String = (Value.Value.b) ? L"True" : L"False"; - break; - - default: - return EFI_UNSUPPORTED; - } - - Result->Type = EFI_IFR_TYPE_STRING; - Result->Value.string = NewString (String, FormSet->HiiHandle); - return EFI_SUCCESS; -} - - -/** - Evaluate opcode EFI_IFR_TO_UINT. - - @param FormSet Formset which contains this opcode. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrToUint ( - IN FORM_BROWSER_FORMSET *FormSet, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String; - CHAR16 *StringPtr; - UINTN BufferSize; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - - if (Value.Type >= EFI_IFR_TYPE_OTHER) { - return EFI_UNSUPPORTED; - } - - Status = EFI_SUCCESS; - if (Value.Type == EFI_IFR_TYPE_STRING) { - String = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String == NULL) { - return EFI_NOT_FOUND; - } - - IfrStrToUpper (String); - StringPtr = StrStr (String, L"0X"); - if (StringPtr != NULL) { - // - // Hex string - // - BufferSize = sizeof (UINT64); - Status = HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL); - } else { - // - // BUGBUG: Need handle decimal string - // - } - gBS->FreePool (String); - } else { - CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); - } - - Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; - return Status; -} - - -/** - Evaluate opcode EFI_IFR_CATENATE. - - @param FormSet Formset which contains this opcode. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrCatenate ( - IN FORM_BROWSER_FORMSET *FormSet, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - UINTN Index; - CHAR16 *StringPtr; - UINTN Size; - - // - // String[0] - The second string - // String[1] - The first string - // - String[0] = NULL; - String[1] = NULL; - StringPtr = NULL; - Status = EFI_SUCCESS; - - for (Index = 0; Index < 2; Index++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - goto Done; - } - - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String== NULL) { - Status = EFI_NOT_FOUND; - goto Done; - } - } - - Size = StrSize (String[0]); - StringPtr= AllocatePool (StrSize (String[1]) + Size); - ASSERT (StringPtr != NULL); - StrCpy (StringPtr, String[1]); - StrCat (StringPtr, String[0]); - - Result->Type = EFI_IFR_TYPE_STRING; - Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); - -Done: - SafeFreePool (String[0]); - SafeFreePool (String[1]); - SafeFreePool (StringPtr); - - return Status; -} - - -/** - Evaluate opcode EFI_IFR_MATCH. - - @param FormSet Formset which contains this opcode. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrMatch ( - IN FORM_BROWSER_FORMSET *FormSet, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - UINTN Index; - - // - // String[0] - The string to search - // String[1] - pattern - // - String[0] = NULL; - String[1] = NULL; - Status = EFI_SUCCESS; - for (Index = 0; Index < 2; Index++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - goto Done; - } - - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String== NULL) { - Status = EFI_NOT_FOUND; - goto Done; - } - } - - Result->Type = EFI_IFR_TYPE_BOOLEAN; - Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); - -Done: - SafeFreePool (String[0]); - SafeFreePool (String[1]); - - return Status; -} - - -/** - Evaluate opcode EFI_IFR_FIND. - - @param FormSet Formset which contains this opcode. - @param Format Case sensitive or insensitive. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrFind ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT8 Format, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - UINTN Base; - CHAR16 *StringPtr; - UINTN Index; - - if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { - return EFI_UNSUPPORTED; - } - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; - } - Base = (UINTN) Value.Value.u64; - - // - // String[0] - sub-string - // String[1] - The string to search - // - String[0] = NULL; - String[1] = NULL; - for (Index = 0; Index < 2; Index++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - goto Done; - } - - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String== NULL) { - Status = EFI_NOT_FOUND; - goto Done; - } - - if (Format == EFI_IFR_FF_CASE_INSENSITIVE) { - // - // Case insensitive, convert both string to upper case - // - IfrStrToUpper (String[Index]); - } - } - - Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; - if (Base >= StrLen (String[1])) { - Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL; - } else { - StringPtr = StrStr (String[1] + Base, String[0]); - Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]); - } - -Done: - SafeFreePool (String[0]); - SafeFreePool (String[1]); - - return Status; -} - - -/** - Evaluate opcode EFI_IFR_MID. - - @param FormSet Formset which contains this opcode. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrMid ( - IN FORM_BROWSER_FORMSET *FormSet, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String; - UINTN Base; - UINTN Length; - CHAR16 *SubString; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; - } - Length = (UINTN) Value.Value.u64; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; - } - Base = (UINTN) Value.Value.u64; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type != EFI_IFR_TYPE_STRING) { - return EFI_UNSUPPORTED; - } - String = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String == NULL) { - return EFI_NOT_FOUND; - } - - if (Length == 0 || Base >= StrLen (String)) { - SubString = gEmptyString; - } else { - SubString = String + Base; - if ((Base + Length) < StrLen (String)) { - SubString[Length] = L'\0'; - } - } - - Result->Type = EFI_IFR_TYPE_STRING; - Result->Value.string = NewString (SubString, FormSet->HiiHandle); - - gBS->FreePool (String); - - return Status; -} - - -/** - Evaluate opcode EFI_IFR_TOKEN. - - @param FormSet Formset which contains this opcode. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrToken ( - IN FORM_BROWSER_FORMSET *FormSet, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - UINTN Count; - CHAR16 *Delimiter; - CHAR16 *SubString; - CHAR16 *StringPtr; - UINTN Index; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; - } - Count = (UINTN) Value.Value.u64; - - // - // String[0] - Delimiter - // String[1] - The string to search - // - String[0] = NULL; - String[1] = NULL; - for (Index = 0; Index < 2; Index++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - goto Done; - } - - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String== NULL) { - Status = EFI_NOT_FOUND; - goto Done; - } - } - - Delimiter = String[0]; - SubString = String[1]; - while (Count > 0) { - SubString = StrStr (SubString, Delimiter); - if (SubString != NULL) { - // - // Skip over the delimiter - // - SubString = SubString + StrLen (Delimiter); - } else { - break; - } - Count--; - } - - if (SubString == NULL) { - // - // nth delimited sub-string not found, push an empty string - // - SubString = gEmptyString; - } else { - // - // Put a NULL terminator for nth delimited sub-string - // - StringPtr = StrStr (SubString, Delimiter); - if (StringPtr != NULL) { - *StringPtr = L'\0'; - } - } - - Result->Type = EFI_IFR_TYPE_STRING; - Result->Value.string = NewString (SubString, FormSet->HiiHandle); - -Done: - SafeFreePool (String[0]); - SafeFreePool (String[1]); - - return Status; -} - - -/** - Evaluate opcode EFI_IFR_SPAN. - - @param FormSet Formset which contains this opcode. - @param Flags FIRST_MATCHING or FIRST_NON_MATCHING. - @param Result Evaluation result for this opcode. - - @retval EFI_SUCCESS Opcode evaluation success. - @retval Other Opcode evaluation failed. - -**/ -EFI_STATUS -IfrSpan ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT8 Flags, - OUT EFI_HII_VALUE *Result - ) -{ - EFI_STATUS Status; - EFI_HII_VALUE Value; - CHAR16 *String[2]; - CHAR16 *Charset; - UINTN Base; - UINTN Index; - CHAR16 *StringPtr; - BOOLEAN Found; - - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - return Status; - } - if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { - return EFI_UNSUPPORTED; - } - Base = (UINTN) Value.Value.u64; - - // - // String[0] - Charset - // String[1] - The string to search - // - String[0] = NULL; - String[1] = NULL; - for (Index = 0; Index < 2; Index++) { - Status = PopExpression (&Value); - if (EFI_ERROR (Status)) { - goto Done; - } - - if (Value.Type != EFI_IFR_TYPE_STRING) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); - if (String== NULL) { - Status = EFI_NOT_FOUND; - goto Done; - } - } - - if (Base >= StrLen (String[1])) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - Found = FALSE; - StringPtr = String[1] + Base; - Charset = String[0]; - while (*StringPtr != 0 && !Found) { - Index = 0; - while (Charset[Index] != 0) { - if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) { - if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) { - Found = TRUE; - break; - } - } else { - if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) { - Found = TRUE; - break; - } - } - // - // Skip characters pair representing low-end of a range and high-end of a range - // - Index += 2; - } - - if (!Found) { - StringPtr++; - } - } - - Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; - Result->Value.u64 = StringPtr - String[1]; - -Done: - SafeFreePool (String[0]); - SafeFreePool (String[1]); - - return Status; -} - - -/** - Zero extend integer/boolean/date/time to UINT64 for comparing. - - @param Value HII Value to be converted. - - @return None. - -**/ -VOID -ExtendValueToU64 ( - IN EFI_HII_VALUE *Value - ) -{ - UINT64 Temp; - - Temp = 0; - switch (Value->Type) { - case EFI_IFR_TYPE_NUM_SIZE_8: - Temp = Value->Value.u8; - break; - - case EFI_IFR_TYPE_NUM_SIZE_16: - Temp = Value->Value.u16; - break; - - case EFI_IFR_TYPE_NUM_SIZE_32: - Temp = Value->Value.u32; - break; - - case EFI_IFR_TYPE_BOOLEAN: - Temp = Value->Value.b; - break; - - case EFI_IFR_TYPE_TIME: - Temp = Value->Value.u32 & 0xffffff; - break; - - case EFI_IFR_TYPE_DATE: - Temp = Value->Value.u32; - break; - - default: - return; - } - - Value->Value.u64 = Temp; -} - - -/** - Compare two Hii value. - - @param Value1 Expression value to compare on left-hand - @param Value2 Expression value to compare on right-hand - @param HiiHandle Only required for string compare - - @retval EFI_INVALID_PARAMETER Could not perform comparation on two values - @retval 0 Two operators equeal - @retval 0 Value1 is greater than Value2 - @retval 0 Value1 is less than Value2 - -**/ -INTN -CompareHiiValue ( - IN EFI_HII_VALUE *Value1, - IN EFI_HII_VALUE *Value2, - IN EFI_HII_HANDLE HiiHandle OPTIONAL - ) -{ - INTN Result; - INT64 Temp64; - CHAR16 *Str1; - CHAR16 *Str2; - - if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) { - return EFI_INVALID_PARAMETER; - } - - if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) { - if (Value1->Type != Value2->Type) { - // - // Both Operator should be type of String - // - return EFI_INVALID_PARAMETER; - } - - if (Value1->Value.string == 0 || Value2->Value.string == 0) { - // - // StringId 0 is reserved - // - return EFI_INVALID_PARAMETER; - } - - if (Value1->Value.string == Value2->Value.string) { - return 0; - } - - Str1 = GetToken (Value1->Value.string, HiiHandle); - if (Str1 == NULL) { - // - // String not found - // - return EFI_INVALID_PARAMETER; - } - - Str2 = GetToken (Value2->Value.string, HiiHandle); - if (Str2 == NULL) { - gBS->FreePool (Str1); - return EFI_INVALID_PARAMETER; - } - - Result = StrCmp (Str1, Str2); - - gBS->FreePool (Str1); - gBS->FreePool (Str2); - - return Result; - } - - // - // Take remain types(integer, boolean, date/time) as integer - // - Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); - if (Temp64 > 0) { - Result = 1; - } else if (Temp64 < 0) { - Result = -1; - } else { - Result = 0; - } - - return Result; -} - - -/** - Evaluate the result of a HII expression - - @param FormSet FormSet associated with this expression. - @param Form Form associated with this expression. - @param Expression Expression to be evaluated. - - @retval EFI_SUCCESS The expression evaluated successfuly - @retval EFI_NOT_FOUND The Question which referenced by a QuestionId - could not be found. - @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the - stack. - @retval EFI_ACCESS_DENIED The pop operation underflowed the stack - @retval EFI_INVALID_PARAMETER Syntax error with the Expression - -**/ -EFI_STATUS -EvaluateExpression ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_EXPRESSION *Expression - ) -{ - EFI_STATUS Status; - 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; - UINT32 TempValue; - - // - // 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); - - ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); - ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); - ZeroMem (&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 = (BOOLEAN) ((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 = (BOOLEAN) ((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. - // - ZeroMem (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 = StrLen (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 = (BOOLEAN) (!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 = (BOOLEAN) ((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 ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (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, (UINT32) Data2.Value.u64); - break; - - case EFI_IFR_DIVIDE_OP: - Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); - break; - - case EFI_IFR_MODULO_OP: - DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue); - Value->Value.u64 = TempValue; - 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 = (BOOLEAN) (Data1.Value.b && Data2.Value.b); - } else { - Value->Value.b = (BOOLEAN) (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 = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); - break; - - case EFI_IFR_NOT_EQUAL_OP: - Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); - break; - - case EFI_IFR_GREATER_EQUAL_OP: - Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE); - break; - - case EFI_IFR_GREATER_THAN_OP: - Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE); - break; - - case EFI_IFR_LESS_EQUAL_OP: - Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE); - break; - - case EFI_IFR_LESS_THAN_OP: - Value->Value.b = (BOOLEAN) ((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; - } - - CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); - - return EFI_SUCCESS; -} +/** @file +Utility functions for expression evaluation. + +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ui.h" +#include "Setup.h" + +// +// Global stack used to evaluate boolean expresions +// +EFI_HII_VALUE *mOpCodeScopeStack = NULL; +EFI_HII_VALUE *mOpCodeScopeStackEnd = NULL; +EFI_HII_VALUE *mOpCodeScopeStackPointer = NULL; + +EFI_HII_VALUE *mExpressionEvaluationStack = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackEnd = NULL; +EFI_HII_VALUE *mExpressionEvaluationStackPointer = NULL; + +// +// Unicode collation protocol interface +// +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + + +/** + Grow size of the stack. + + This is an internal function. + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackEnd On input: old stack end; On output: new stack end + + @retval EFI_SUCCESS Grow stack success. + @retval EFI_OUT_OF_RESOURCES No enough memory for stack space. + +**/ +EFI_STATUS +GrowStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd + ) +{ + UINTN Size; + EFI_HII_VALUE *NewStack; + + Size = EXPRESSION_STACK_SIZE_INCREMENT; + if (*StackPtr != NULL) { + Size = Size + (*StackEnd - *Stack); + } + + NewStack = AllocatePool (Size * sizeof (EFI_HII_VALUE)); + if (NewStack == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (*StackPtr != NULL) { + // + // Copy from Old Stack to the New Stack + // + CopyMem ( + NewStack, + *Stack, + (*StackEnd - *Stack) * sizeof (EFI_HII_VALUE) + ); + + // + // Free The Old Stack + // + gBS->FreePool (*Stack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + *StackPtr = NewStack + (*StackPtr - *Stack); + *Stack = NewStack; + *StackEnd = NewStack + Size; + + return EFI_SUCCESS; +} + + +/** + Push an element onto the Boolean Stack. + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackEnd On input: old stack end; On output: new stack end + @param Data Data to push. + + @retval EFI_SUCCESS Push stack success. + +**/ +EFI_STATUS +PushStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + IN EFI_HII_VALUE *Data + ) +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (*StackPtr >= *StackEnd) { + // + // Grow the stack + // + Status = GrowStack (Stack, StackPtr, StackEnd); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + CopyMem (*StackPtr, Data, sizeof (EFI_HII_VALUE)); + *StackPtr = *StackPtr + 1; + + return EFI_SUCCESS; +} + + +/** + Pop an element from the stack. + + @param Stack On input: old stack; On output: new stack + @param StackPtr On input: old stack pointer; On output: new stack + pointer + @param StackEnd On input: old stack end; On output: new stack end + @param Data Data to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopStack ( + IN OUT EFI_HII_VALUE **Stack, + IN OUT EFI_HII_VALUE **StackPtr, + IN OUT EFI_HII_VALUE **StackEnd, + OUT EFI_HII_VALUE *Data + ) +{ + // + // Check for a stack underflow condition + // + if (*StackPtr == *Stack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + *StackPtr = *StackPtr - 1; + CopyMem (Data, *StackPtr, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; +} + + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetScopeStack ( + VOID + ) +{ + mOpCodeScopeStackPointer = mOpCodeScopeStack; +} + + +/** + Push an Operand onto the Stack + + @param Operand Operand to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +{ + EFI_HII_VALUE Data; + + Data.Type = EFI_IFR_TYPE_NUM_SIZE_8; + Data.Value.u8 = Operand; + + return PushStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); +} + + +/** + Pop an Operand from the Stack + + @param Operand Operand to pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Data; + + Status = PopStack ( + &mOpCodeScopeStack, + &mOpCodeScopeStackPointer, + &mOpCodeScopeStackEnd, + &Data + ); + + *Operand = Data.Value.u8; + + return Status; +} + + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetExpressionStack ( + VOID + ) +{ + mExpressionEvaluationStackPointer = mExpressionEvaluationStack; +} + + +/** + Push an Expression value onto the Stack + + @param Value Expression value to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushExpression ( + IN EFI_HII_VALUE *Value + ) +{ + return PushStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Pop an Expression value from the stack. + + @param Value Expression value to pop. + + @retval EFI_SUCCESS The value was popped onto the stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + +**/ +EFI_STATUS +PopExpression ( + OUT EFI_HII_VALUE *Value + ) +{ + return PopStack ( + &mExpressionEvaluationStack, + &mExpressionEvaluationStackPointer, + &mExpressionEvaluationStackEnd, + Value + ); +} + + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId +) +{ + LIST_ENTRY *Link; + FORM_BROWSER_FORM *Form; + + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + if (Form->FormId == FormId) { + return Form; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Form scope using its QuestionId. + + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion2 ( + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + if (QuestionId == 0) { + // + // The value of zero is reserved + // + return NULL; + } + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Question->QuestionId == QuestionId) { + return Question; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return NULL; +} + + +/** + Search a Question in Formset scope using its QuestionId. + + @param FormSet The formset which contains this form. + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +{ + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + // + // Search in the form scope first + // + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + // + // Search in the formset scope + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Question = IdToQuestion2 (Form, QuestionId); + if (Question != NULL) { + return Question; + } + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + return NULL; +} + + +/** + Get Expression given its RuleId. + + @param Form The form which contains this Expression. + @param RuleId Id of this Expression. + + @retval Pointer The Expression. + @retval NULL Specified Expression not found in the form. + +**/ +FORM_EXPRESSION * +RuleIdToExpression ( + IN FORM_BROWSER_FORM *Form, + IN UINT8 RuleId + ) +{ + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + if (Expression->Type == EFI_HII_EXPRESSION_RULE && Expression->RuleId == RuleId) { + return Expression; + } + + Link = GetNextNode (&Form->ExpressionListHead, Link); + } + + return NULL; +} + + +/** + Locate the Unicode Collation Protocol interface for later use. + + @retval EFI_SUCCESS Protocol interface initialize success. + @retval Other Protocol interface initialize failed. + +**/ +EFI_STATUS +InitializeUnicodeCollationProtocol ( + VOID + ) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + return Status; +} + +/** + Convert the input Unicode character to upper. + + @param String Th Unicode character to be converted. + +**/ +VOID +IfrStrToUpper ( + CHAR16 *String + ) +{ + while (*String != 0) { + if ((*String >= 'a') && (*String <= 'z')) { + *String = (UINT16) ((*String) & ((UINT16) ~0x20)); + } + String++; + } +} + + +/** + Evaluate opcode EFI_IFR_TO_STRING. + + @param FormSet Formset which contains this opcode. + @param Format String format in EFI_IFR_TO_STRING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToString ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *PrintFormat; + CHAR16 Buffer[MAXIMUM_VALUE_CHARACTERS]; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + switch (Value.Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + case EFI_IFR_TYPE_NUM_SIZE_16: + case EFI_IFR_TYPE_NUM_SIZE_32: + case EFI_IFR_TYPE_NUM_SIZE_64: + BufferSize = MAXIMUM_VALUE_CHARACTERS * sizeof (CHAR16); + switch (Format) { + case EFI_IFR_STRING_UNSIGNED_DEC: + case EFI_IFR_STRING_SIGNED_DEC: + PrintFormat = L"%ld"; + break; + + case EFI_IFR_STRING_LOWERCASE_HEX: + PrintFormat = L"%lx"; + break; + + case EFI_IFR_STRING_UPPERCASE_HEX: + PrintFormat = L"%lX"; + break; + + default: + return EFI_UNSUPPORTED; + } + UnicodeSPrint (Buffer, BufferSize, PrintFormat, Value.Value.u64); + String = Buffer; + break; + + case EFI_IFR_TYPE_STRING: + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + return EFI_SUCCESS; + + case EFI_IFR_TYPE_BOOLEAN: + String = (Value.Value.b) ? L"True" : L"False"; + break; + + default: + return EFI_UNSUPPORTED; + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (String, FormSet->HiiHandle); + return EFI_SUCCESS; +} + + +/** + Evaluate opcode EFI_IFR_TO_UINT. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToUint ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + CHAR16 *StringPtr; + UINTN BufferSize; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Value.Type >= EFI_IFR_TYPE_OTHER) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + if (Value.Type == EFI_IFR_TYPE_STRING) { + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + IfrStrToUpper (String); + StringPtr = StrStr (String, L"0X"); + if (StringPtr != NULL) { + // + // Hex string + // + BufferSize = sizeof (UINT64); + Status = HexStringToBuf ((UINT8 *) &Result->Value.u64, &BufferSize, StringPtr + 2, NULL); + } else { + // + // BUGBUG: Need handle decimal string + // + } + gBS->FreePool (String); + } else { + CopyMem (Result, &Value, sizeof (EFI_HII_VALUE)); + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + return Status; +} + + +/** + Evaluate opcode EFI_IFR_CATENATE. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrCatenate ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + CHAR16 *StringPtr; + UINTN Size; + + // + // String[0] - The second string + // String[1] - The first string + // + String[0] = NULL; + String[1] = NULL; + StringPtr = NULL; + Status = EFI_SUCCESS; + + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Size = StrSize (String[0]); + StringPtr= AllocatePool (StrSize (String[1]) + Size); + ASSERT (StringPtr != NULL); + StrCpy (StringPtr, String[1]); + StrCat (StringPtr, String[0]); + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (StringPtr, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + SafeFreePool (StringPtr); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MATCH. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMatch ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Index; + + // + // String[0] - The string to search + // String[1] - pattern + // + String[0] = NULL; + String[1] = NULL; + Status = EFI_SUCCESS; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Result->Type = EFI_IFR_TYPE_BOOLEAN; + Result->Value.b = mUnicodeCollation->MetaiMatch (mUnicodeCollation, String[0], String[1]); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_FIND. + + @param FormSet Formset which contains this opcode. + @param Format Case sensitive or insensitive. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrFind ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Format, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Base; + CHAR16 *StringPtr; + UINTN Index; + + if (Format > EFI_IFR_FF_CASE_INSENSITIVE) { + return EFI_UNSUPPORTED; + } + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - sub-string + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + + if (Format == EFI_IFR_FF_CASE_INSENSITIVE) { + // + // Case insensitive, convert both string to upper case + // + IfrStrToUpper (String[Index]); + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + if (Base >= StrLen (String[1])) { + Result->Value.u64 = 0xFFFFFFFFFFFFFFFFULL; + } else { + StringPtr = StrStr (String[1] + Base, String[0]); + Result->Value.u64 = (StringPtr == NULL) ? 0xFFFFFFFFFFFFFFFFULL : (StringPtr - String[1]); + } + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_MID. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrMid ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String; + UINTN Base; + UINTN Length; + CHAR16 *SubString; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Length = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type != EFI_IFR_TYPE_STRING) { + return EFI_UNSUPPORTED; + } + String = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String == NULL) { + return EFI_NOT_FOUND; + } + + if (Length == 0 || Base >= StrLen (String)) { + SubString = gEmptyString; + } else { + SubString = String + Base; + if ((Base + Length) < StrLen (String)) { + SubString[Length] = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + + gBS->FreePool (String); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_TOKEN. + + @param FormSet Formset which contains this opcode. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrToken ( + IN FORM_BROWSER_FORMSET *FormSet, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + UINTN Count; + CHAR16 *Delimiter; + CHAR16 *SubString; + CHAR16 *StringPtr; + UINTN Index; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Count = (UINTN) Value.Value.u64; + + // + // String[0] - Delimiter + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + Delimiter = String[0]; + SubString = String[1]; + while (Count > 0) { + SubString = StrStr (SubString, Delimiter); + if (SubString != NULL) { + // + // Skip over the delimiter + // + SubString = SubString + StrLen (Delimiter); + } else { + break; + } + Count--; + } + + if (SubString == NULL) { + // + // nth delimited sub-string not found, push an empty string + // + SubString = gEmptyString; + } else { + // + // Put a NULL terminator for nth delimited sub-string + // + StringPtr = StrStr (SubString, Delimiter); + if (StringPtr != NULL) { + *StringPtr = L'\0'; + } + } + + Result->Type = EFI_IFR_TYPE_STRING; + Result->Value.string = NewString (SubString, FormSet->HiiHandle); + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Evaluate opcode EFI_IFR_SPAN. + + @param FormSet Formset which contains this opcode. + @param Flags FIRST_MATCHING or FIRST_NON_MATCHING. + @param Result Evaluation result for this opcode. + + @retval EFI_SUCCESS Opcode evaluation success. + @retval Other Opcode evaluation failed. + +**/ +EFI_STATUS +IfrSpan ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT8 Flags, + OUT EFI_HII_VALUE *Result + ) +{ + EFI_STATUS Status; + EFI_HII_VALUE Value; + CHAR16 *String[2]; + CHAR16 *Charset; + UINTN Base; + UINTN Index; + CHAR16 *StringPtr; + BOOLEAN Found; + + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + return Status; + } + if (Value.Type > EFI_IFR_TYPE_NUM_SIZE_64) { + return EFI_UNSUPPORTED; + } + Base = (UINTN) Value.Value.u64; + + // + // String[0] - Charset + // String[1] - The string to search + // + String[0] = NULL; + String[1] = NULL; + for (Index = 0; Index < 2; Index++) { + Status = PopExpression (&Value); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (Value.Type != EFI_IFR_TYPE_STRING) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + String[Index] = GetToken (Value.Value.string, FormSet->HiiHandle); + if (String== NULL) { + Status = EFI_NOT_FOUND; + goto Done; + } + } + + if (Base >= StrLen (String[1])) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Found = FALSE; + StringPtr = String[1] + Base; + Charset = String[0]; + while (*StringPtr != 0 && !Found) { + Index = 0; + while (Charset[Index] != 0) { + if (*StringPtr >= Charset[Index] && *StringPtr <= Charset[Index + 1]) { + if (Flags == EFI_IFR_FLAGS_FIRST_MATCHING) { + Found = TRUE; + break; + } + } else { + if (Flags == EFI_IFR_FLAGS_FIRST_NON_MATCHING) { + Found = TRUE; + break; + } + } + // + // Skip characters pair representing low-end of a range and high-end of a range + // + Index += 2; + } + + if (!Found) { + StringPtr++; + } + } + + Result->Type = EFI_IFR_TYPE_NUM_SIZE_64; + Result->Value.u64 = StringPtr - String[1]; + +Done: + SafeFreePool (String[0]); + SafeFreePool (String[1]); + + return Status; +} + + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +{ + UINT64 Temp; + + Temp = 0; + switch (Value->Type) { + case EFI_IFR_TYPE_NUM_SIZE_8: + Temp = Value->Value.u8; + break; + + case EFI_IFR_TYPE_NUM_SIZE_16: + Temp = Value->Value.u16; + break; + + case EFI_IFR_TYPE_NUM_SIZE_32: + Temp = Value->Value.u32; + break; + + case EFI_IFR_TYPE_BOOLEAN: + Temp = Value->Value.b; + break; + + case EFI_IFR_TYPE_TIME: + Temp = Value->Value.u32 & 0xffffff; + break; + + case EFI_IFR_TYPE_DATE: + Temp = Value->Value.u32; + break; + + default: + return; + } + + Value->Value.u64 = Temp; +} + + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param HiiHandle Only required for string compare. + + @retval EFI_INVALID_PARAMETER Could not perform comparation on two values. + @retval 0 Two operators equeal. + @return Positive value if Value1 is greater than Value2. + @retval Negative value if Value1 is less than Value2. + +**/ +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +{ + INTN Result; + INT64 Temp64; + CHAR16 *Str1; + CHAR16 *Str2; + + if (Value1->Type >= EFI_IFR_TYPE_OTHER || Value2->Type >= EFI_IFR_TYPE_OTHER ) { + return EFI_INVALID_PARAMETER; + } + + if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) { + if (Value1->Type != Value2->Type) { + // + // Both Operator should be type of String + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == 0 || Value2->Value.string == 0) { + // + // StringId 0 is reserved + // + return EFI_INVALID_PARAMETER; + } + + if (Value1->Value.string == Value2->Value.string) { + return 0; + } + + Str1 = GetToken (Value1->Value.string, HiiHandle); + if (Str1 == NULL) { + // + // String not found + // + return EFI_INVALID_PARAMETER; + } + + Str2 = GetToken (Value2->Value.string, HiiHandle); + if (Str2 == NULL) { + gBS->FreePool (Str1); + return EFI_INVALID_PARAMETER; + } + + Result = StrCmp (Str1, Str2); + + gBS->FreePool (Str1); + gBS->FreePool (Str2); + + return Result; + } + + // + // Take remain types(integer, boolean, date/time) as integer + // + Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64); + if (Temp64 > 0) { + Result = 1; + } else if (Temp64 < 0) { + Result = -1; + } else { + Result = 0; + } + + return Result; +} + + +/** + Evaluate the result of a HII expression + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +{ + EFI_STATUS Status; + 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; + UINT32 TempValue; + + // + // 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); + + ZeroMem (&Data1, sizeof (EFI_HII_VALUE)); + ZeroMem (&Data2, sizeof (EFI_HII_VALUE)); + ZeroMem (&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 = (BOOLEAN) ((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 = (BOOLEAN) ((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. + // + ZeroMem (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 = StrLen (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 = (BOOLEAN) (!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 = (BOOLEAN) ((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 ((StrCmp (StrPtr, L"true") == 0) || (StrCmp (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, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_DIVIDE_OP: + Value->Value.u64 = DivU64x32 (Data1.Value.u64, (UINT32) Data2.Value.u64); + break; + + case EFI_IFR_MODULO_OP: + DivU64x32Remainder (Data1.Value.u64, (UINT32) Data2.Value.u64, &TempValue); + Value->Value.u64 = TempValue; + 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 = (BOOLEAN) (Data1.Value.b && Data2.Value.b); + } else { + Value->Value.b = (BOOLEAN) (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 = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_NOT_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result == 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result >= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_GREATER_THAN_OP: + Value->Value.b = (BOOLEAN) ((Result > 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_EQUAL_OP: + Value->Value.b = (BOOLEAN) ((Result <= 0) ? TRUE : FALSE); + break; + + case EFI_IFR_LESS_THAN_OP: + Value->Value.b = (BOOLEAN) ((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; + } + + CopyMem (&Expression->Result, Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c index 9108acb473..7e5f6684ce 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/IfrParse.c @@ -1,4 +1,6 @@ /** @file +Parser for IFR binary encoding. + Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -8,15 +10,6 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - IfrParse.c - -Abstract: - - Parser for IFR binary encoding. - - **/ #include "Setup.h" @@ -337,7 +330,7 @@ InitializeRequestElement ( StrLen = UnicodeSPrint (RequestElement, 30 * sizeof (CHAR16), L"&%s", Question->VariableName); } - if ((Question->Operand == EFI_IFR_PASSWORD_OP) && (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { + if ((Question->Operand == EFI_IFR_PASSWORD_OP) && ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK)) { // // Password with CALLBACK flag is stored in encoded format, // so don't need to append it to @@ -371,12 +364,10 @@ InitializeRequestElement ( /** - Free resources of a Expression + Free resources of a Expression. @param FormSet Pointer of the Expression - @return None. - **/ VOID DestroyExpression ( @@ -402,12 +393,10 @@ DestroyExpression ( /** - Free resources of a storage + Free resources of a storage. @param Storage Pointer of the storage - @return None. - **/ VOID DestroyStorage ( @@ -444,12 +433,10 @@ DestroyStorage ( /** - Free resources of a Statement + Free resources of a Statement. @param Statement Pointer of the Statement - @return None. - **/ VOID DestroyStatement ( @@ -511,11 +498,9 @@ DestroyStatement ( /** - Free resources of a Form + Free resources of a Form. - @param Form Pointer of the Form - - @return None. + @param Form Pointer of the Form. **/ VOID @@ -557,12 +542,10 @@ DestroyForm ( /** - Free resources allocated for a FormSet + Free resources allocated for a FormSet. @param FormSet Pointer of the FormSet - @return None. - **/ VOID DestroyFormSet ( @@ -657,8 +640,6 @@ IsExpressionOpCode ( @param NumberOfStatement Number of Statemens(Questions) @param NumberOfExpression Number of Expression OpCodes - @return None. - **/ VOID CountOpCodes ( @@ -791,7 +772,7 @@ ParseOpCodes ( // // If scope bit set, push onto scope stack // - if (Scope) { + if (Scope != 0) { PushScope (Operand); } @@ -1091,7 +1072,7 @@ ParseOpCodes ( CurrentStatement = CreateStatement (OpCodeData, FormSet, CurrentForm); CurrentStatement->Flags = ((EFI_IFR_SUBTITLE *) OpCodeData)->Flags; - if (Scope) { + if (Scope != 0) { mInScopeSubtitle = TRUE; } break; @@ -1187,7 +1168,7 @@ ParseOpCodes ( InitializeRequestElement (FormSet, CurrentStatement); - if ((Operand == EFI_IFR_ONE_OF_OP) && Scope) { + if ((Operand == EFI_IFR_ONE_OF_OP) && Scope != 0) { SuppressForOption = TRUE; } break; @@ -1208,7 +1189,7 @@ ParseOpCodes ( CurrentStatement->HiiValue.Type = EFI_IFR_TYPE_OTHER; CurrentStatement->BufferValue = AllocateZeroPool (CurrentStatement->StorageWidth); - if (Scope) { + if (Scope != 0) { SuppressForOption = TRUE; } break; @@ -1320,7 +1301,7 @@ ParseOpCodes ( // InsertTailList (&CurrentStatement->DefaultListHead, &CurrentDefault->Link); - if (Scope) { + if (Scope != 0) { InScopeDefault = TRUE; } break; diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c index cc580b81c7..b958f4fdc7 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c @@ -1,1146 +1,1144 @@ -/** @file - -Copyright (c) 2004 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - InputHandler.c - -Abstract: - - Implementation for handling user input from the User Interface - -Revision History - - -**/ - -#include "Ui.h" -#include "Setup.h" - - -/** - Get string or password input from user. - - @param MenuOption Pointer to the current input menu. - @param Prompt The prompt string shown on popup window. - @param StringPtr Destination for use input string. - - @retval EFI_SUCCESS If string input is read successfully - @retval EFI_DEVICE_ERROR If operation fails - -**/ -EFI_STATUS -ReadString ( - IN UI_MENU_OPTION *MenuOption, - IN CHAR16 *Prompt, - OUT CHAR16 *StringPtr - ) -{ - EFI_STATUS Status; - EFI_INPUT_KEY Key; - CHAR16 NullCharacter; - UINTN ScreenSize; - CHAR16 Space[2]; - CHAR16 KeyPad[2]; - CHAR16 *TempString; - CHAR16 *BufferedString; - UINTN Index; - UINTN Count; - UINTN Start; - UINTN Top; - UINTN DimensionsWidth; - UINTN DimensionsHeight; - BOOLEAN CursorVisible; - UINTN Minimum; - UINTN Maximum; - FORM_BROWSER_STATEMENT *Question; - BOOLEAN IsPassword; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; - - NullCharacter = CHAR_NULL; - ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); - Space[0] = L' '; - Space[1] = CHAR_NULL; - - Question = MenuOption->ThisTag; - Minimum = (UINTN) Question->Minimum; - Maximum = (UINTN) Question->Maximum; - - if (Question->Operand == EFI_IFR_PASSWORD_OP) { - IsPassword = TRUE; - } else { - IsPassword = FALSE; - } - - TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16)); - ASSERT (TempString); - - if (ScreenSize < (Maximum + 1)) { - ScreenSize = Maximum + 1; - } - - if ((ScreenSize + 2) > DimensionsWidth) { - ScreenSize = DimensionsWidth - 2; - } - - BufferedString = AllocateZeroPool (ScreenSize * 2); - ASSERT (BufferedString); - - Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; - Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; - - // - // Display prompt for string - // - CreatePopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); - - CursorVisible = gST->ConOut->Mode->CursorVisible; - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - - do { - Status = WaitForKeyStroke (&Key); - ASSERT_EFI_ERROR (Status); - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); - switch (Key.UnicodeChar) { - case CHAR_NULL: - switch (Key.ScanCode) { - case SCAN_LEFT: - break; - - case SCAN_RIGHT: - break; - - case SCAN_ESC: - gBS->FreePool (TempString); - gBS->FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); - return EFI_DEVICE_ERROR; - - default: - break; - } - - break; - - case CHAR_CARRIAGE_RETURN: - if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) { - - gBS->FreePool (TempString); - gBS->FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); - return EFI_SUCCESS; - } else { - // - // Simply create a popup to tell the user that they had typed in too few characters. - // To save code space, we can then treat this as an error and return back to the menu. - // - do { - CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - - gBS->FreePool (TempString); - gBS->FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); - return EFI_DEVICE_ERROR; - } - - break; - - case CHAR_BACKSPACE: - if (StringPtr[0] != CHAR_NULL) { - for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { - TempString[Index] = StringPtr[Index]; - } - // - // Effectively truncate string by 1 character - // - TempString[Index - 1] = CHAR_NULL; - StrCpy (StringPtr, TempString); - } - - default: - // - // If it is the beginning of the string, don't worry about checking maximum limits - // - if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - StrnCpy (StringPtr, &Key.UnicodeChar, 1); - StrnCpy (TempString, &Key.UnicodeChar, 1); - } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - KeyPad[0] = Key.UnicodeChar; - KeyPad[1] = CHAR_NULL; - StrCat (StringPtr, KeyPad); - StrCat (TempString, KeyPad); - } - - // - // If the width of the input string is now larger than the screen, we nee to - // adjust the index to start printing portions of the string - // - SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); - PrintStringAt (Start + 1, Top + 3, BufferedString); - - if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { - Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; - } else { - Index = 0; - } - - if (IsPassword) { - gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); - } - - for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { - BufferedString[Count] = StringPtr[Index]; - - if (IsPassword) { - PrintChar (L'*'); - } - } - - if (!IsPassword) { - PrintStringAt (Start + 1, Top + 3, BufferedString); - } - break; - } - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); - } while (TRUE); - -} - - -/** - This routine reads a numeric value from the user input. - - @param Selection Pointer to current selection. - @param MenuOption Pointer to the current input menu. - - @retval EFI_SUCCESS If numerical input is read successfully - @retval EFI_DEVICE_ERROR If operation fails - -**/ -EFI_STATUS -GetNumericInput ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ) -{ - EFI_STATUS Status; - UINTN Column; - UINTN Row; - CHAR16 InputText[23]; - CHAR16 FormattedNumber[22]; - UINT64 PreviousNumber[20]; - UINTN Count; - UINTN Loop; - BOOLEAN ManualInput; - BOOLEAN HexInput; - BOOLEAN DateOrTime; - UINTN InputWidth; - UINT64 EditValue; - UINT64 Step; - UINT64 Minimum; - UINT64 Maximum; - UINTN EraseLen; - UINT8 Digital; - EFI_INPUT_KEY Key; - EFI_HII_VALUE *QuestionValue; - FORM_BROWSER_FORM *Form; - FORM_BROWSER_FORMSET *FormSet; - FORM_BROWSER_STATEMENT *Question; - - Column = MenuOption->OptCol; - Row = MenuOption->Row; - PreviousNumber[0] = 0; - Count = 0; - InputWidth = 0; - Digital = 0; - - FormSet = Selection->FormSet; - Form = Selection->Form; - Question = MenuOption->ThisTag; - QuestionValue = &Question->HiiValue; - Step = Question->Step; - Minimum = Question->Minimum; - Maximum = Question->Maximum; - - if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { - DateOrTime = TRUE; - } else { - DateOrTime = FALSE; - } - - // - // Prepare Value to be edit - // - EraseLen = 0; - EditValue = 0; - if (Question->Operand == EFI_IFR_DATE_OP) { - Step = 1; - Minimum = 1; - - switch (MenuOption->Sequence) { - case 0: - Maximum = 12; - EraseLen = 4; - EditValue = QuestionValue->Value.date.Month; - break; - - case 1: - Maximum = 31; - EraseLen = 3; - EditValue = QuestionValue->Value.date.Day; - break; - - case 2: - Maximum = 0xffff; - EraseLen = 5; - EditValue = QuestionValue->Value.date.Year; - break; - - default: - break; - } - } else if (Question->Operand == EFI_IFR_TIME_OP) { - Step = 1; - Minimum = 0; - - switch (MenuOption->Sequence) { - case 0: - Maximum = 23; - EraseLen = 4; - EditValue = QuestionValue->Value.time.Hour; - break; - - case 1: - Maximum = 59; - EraseLen = 3; - EditValue = QuestionValue->Value.time.Minute; - break; - - case 2: - Maximum = 59; - EraseLen = 3; - EditValue = QuestionValue->Value.time.Second; - break; - - default: - break; - } - } else { - // - // Numeric - // - EraseLen = gOptionBlockWidth; - EditValue = QuestionValue->Value.u64; - if (Maximum == 0) { - Maximum = (UINT64) -1; - } - } - - if (Step == 0) { - ManualInput = TRUE; - } else { - ManualInput = FALSE; - } - - if ((Question->Operand == EFI_IFR_NUMERIC_OP) && - ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { - HexInput = TRUE; - } else { - HexInput = FALSE; - } - - if (ManualInput) { - if (HexInput) { - InputWidth = Question->StorageWidth * 2; - } else { - switch (Question->StorageWidth) { - case 1: - InputWidth = 3; - break; - - case 2: - InputWidth = 5; - break; - - case 4: - InputWidth = 10; - break; - - case 8: - InputWidth = 20; - break; - - default: - InputWidth = 0; - break; - } - } - - InputText[0] = LEFT_NUMERIC_DELIMITER; - SetUnicodeMem (InputText + 1, InputWidth, L' '); - InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; - InputText[InputWidth + 2] = L'\0'; - - PrintAt (Column, Row, InputText); - Column++; - } - - // - // First time we enter this handler, we need to check to see if - // we were passed an increment or decrement directive - // - do { - Key.UnicodeChar = CHAR_NULL; - if (gDirection != 0) { - Key.ScanCode = gDirection; - gDirection = 0; - goto TheKey2; - } - - Status = WaitForKeyStroke (&Key); - -TheKey2: - switch (Key.UnicodeChar) { - - case '+': - case '-': - if (Key.UnicodeChar == '+') { - Key.ScanCode = SCAN_RIGHT; - } else { - Key.ScanCode = SCAN_LEFT; - } - Key.UnicodeChar = CHAR_NULL; - goto TheKey2; - - case CHAR_NULL: - switch (Key.ScanCode) { - case SCAN_LEFT: - case SCAN_RIGHT: - if (DateOrTime) { - // - // By setting this value, we will return back to the caller. - // We need to do this since an auto-refresh will destroy the adjustment - // based on what the real-time-clock is showing. So we always commit - // upon changing the value. - // - gDirection = SCAN_DOWN; - } - - if (!ManualInput) { - if (Key.ScanCode == SCAN_LEFT) { - if (EditValue > Step) { - EditValue = EditValue - Step; - } else { - EditValue = Minimum; - } - } else if (Key.ScanCode == SCAN_RIGHT) { - EditValue = EditValue + Step; - if (EditValue > Maximum) { - EditValue = Maximum; - } - } - - ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); - if (Question->Operand == EFI_IFR_DATE_OP) { - if (MenuOption->Sequence == 2) { - // - // Year - // - UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", EditValue); - } else { - // - // Month/Day - // - UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); - } - - if (MenuOption->Sequence == 0) { - FormattedNumber[EraseLen - 2] = DATE_SEPARATOR; - } else if (MenuOption->Sequence == 1) { - FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; - } - } else if (Question->Operand == EFI_IFR_TIME_OP) { - UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); - - if (MenuOption->Sequence == 0) { - FormattedNumber[EraseLen - 2] = TIME_SEPARATOR; - } else if (MenuOption->Sequence == 1) { - FormattedNumber[EraseLen - 1] = TIME_SEPARATOR; - } - } else { - QuestionValue->Value.u64 = EditValue; - PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); - } - - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - for (Loop = 0; Loop < EraseLen; Loop++) { - PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); - } - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); - - if (MenuOption->Sequence == 0) { - PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); - Column = MenuOption->OptCol + 1; - } - - PrintStringAt (Column, Row, FormattedNumber); - - if (!DateOrTime || MenuOption->Sequence == 2) { - PrintChar (RIGHT_NUMERIC_DELIMITER); - } - } - break; - - case SCAN_UP: - case SCAN_DOWN: - goto EnterCarriageReturn; - - case SCAN_ESC: - return EFI_DEVICE_ERROR; - - default: - break; - } - - break; - -EnterCarriageReturn: - - case CHAR_CARRIAGE_RETURN: - // - // Store Edit value back to Question - // - if (Question->Operand == EFI_IFR_DATE_OP) { - switch (MenuOption->Sequence) { - case 0: - QuestionValue->Value.date.Month = (UINT8) EditValue; - break; - - case 1: - QuestionValue->Value.date.Day = (UINT8) EditValue; - break; - - case 2: - QuestionValue->Value.date.Year = (UINT16) EditValue; - break; - - default: - break; - } - } else if (Question->Operand == EFI_IFR_TIME_OP) { - switch (MenuOption->Sequence) { - case 0: - QuestionValue->Value.time.Hour = (UINT8) EditValue; - break; - - case 1: - QuestionValue->Value.time.Minute = (UINT8) EditValue; - break; - - case 2: - QuestionValue->Value.time.Second = (UINT8) EditValue; - break; - - default: - break; - } - } else { - // - // Numeric - // - QuestionValue->Value.u64 = EditValue; - } - - // - // Check to see if the Value is something reasonable against consistency limitations. - // If not, let's kick the error specified. - // - Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); - if (EFI_ERROR (Status)) { - // - // Input value is not valid, restore Question Value - // - GetQuestionValue (FormSet, Form, Question, TRUE); - } else { - SetQuestionValue (FormSet, Form, Question, TRUE); - if (!DateOrTime || (Question->Storage != NULL)) { - // - // NV flag is unnecessary for RTC type of Date/Time - // - UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } - } - - return Status; - break; - - case CHAR_BACKSPACE: - if (ManualInput) { - if (Count == 0) { - break; - } - // - // Remove a character - // - EditValue = PreviousNumber[Count - 1]; - UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); - Count--; - Column--; - PrintAt (Column, Row, L" "); - } - break; - - default: - if (ManualInput) { - if (HexInput) { - if (!IsHexDigit (&Digital, Key.UnicodeChar)) { - UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); - break; - } - } else { - if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { - UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); - break; - } - } - - // - // If Count exceed input width, there is no way more is valid - // - if (Count >= InputWidth) { - break; - } - // - // Someone typed something valid! - // - if (Count != 0) { - if (HexInput) { - EditValue = LShiftU64 (EditValue, 4) + Digital; - } else { - EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0'); - } - } else { - if (HexInput) { - EditValue = Digital; - } else { - EditValue = Key.UnicodeChar - L'0'; - } - } - - if (EditValue > Maximum) { - UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); - EditValue = PreviousNumber[Count]; - break; - } else { - UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); - } - - Count++; - PreviousNumber[Count] = EditValue; - - PrintCharAt (Column, Row, Key.UnicodeChar); - Column++; - } - break; - } - } while (TRUE); - -} - - -/** - 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; - EFI_HII_VALUE HiiValue; - EFI_HII_VALUE *HiiValueArray; - UINTN OptionCount; - QUESTION_OPTION *OneOfOption; - QUESTION_OPTION *CurrentOption; - FORM_BROWSER_STATEMENT *Question; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - - ValueArray = NULL; - 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; - OrderedList = TRUE; - } else { - OrderedList = FALSE; - } - - // - // Calculate Option count - // - if (OrderedList) { - for (Index = 0; Index < Question->MaxContainers; Index++) { - if (ValueArray[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 = EFI_IFR_TYPE_NUM_SIZE_8; - HiiValueArray[Index].Value.u8 = ValueArray[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) && - (OneOfOption->SuppressExpression->Result.Value.b)) { - // - // 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); - } - gBS->FreePool (StringPtr); - - if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 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 - FOOTER_HEIGHT - 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); - // - // 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))); - gBS->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++; - gBS->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--; - - 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++; - - 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 = EFI_IFR_TYPE_NUM_SIZE_8; - HiiValue.Value.u64 = 0; - for (Index = 0; Index < Question->MaxContainers; Index++) { - HiiValue.Value.u8 = ValueArray[Index]; - if (HiiValue.Value.u8) { - break; - } - - OneOfOption = ValueToOption (Question, &HiiValue); - if (OneOfOption == NULL) { - return EFI_NOT_FOUND; - } - - RemoveEntryList (&OneOfOption->Link); - InsertTailList (&Question->OptionListHead, &OneOfOption->Link); - } - } - - gBS->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); - - Question->BufferValue[Index] = OneOfOption->Value.Value.u8; - - Index++; - if (Index > Question->MaxContainers) { - break; - } - - Link = GetNextNode (&Question->OptionListHead, Link); - } - } else { - CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE)); - } - - gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); - gBS->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 (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); - } - - return Status; - - default: - break; - } - } while (TRUE); - -} - -EFI_STATUS -WaitForKeyStroke ( - OUT EFI_INPUT_KEY *Key - ) -{ - EFI_STATUS Status; - - do { - UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0); - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); - } while (EFI_ERROR(Status)); - - return Status; -} +/** @file +Implementation for handling user input from the User Interfaces. + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ui.h" +#include "Setup.h" + + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR16 NullCharacter; + UINTN ScreenSize; + CHAR16 Space[2]; + CHAR16 KeyPad[2]; + CHAR16 *TempString; + CHAR16 *BufferedString; + UINTN Index; + UINTN Count; + UINTN Start; + UINTN Top; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + BOOLEAN CursorVisible; + UINTN Minimum; + UINTN Maximum; + FORM_BROWSER_STATEMENT *Question; + BOOLEAN IsPassword; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + NullCharacter = CHAR_NULL; + ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16); + Space[0] = L' '; + Space[1] = CHAR_NULL; + + Question = MenuOption->ThisTag; + Minimum = (UINTN) Question->Minimum; + Maximum = (UINTN) Question->Maximum; + + if (Question->Operand == EFI_IFR_PASSWORD_OP) { + IsPassword = TRUE; + } else { + IsPassword = FALSE; + } + + TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16)); + ASSERT (TempString); + + if (ScreenSize < (Maximum + 1)) { + ScreenSize = Maximum + 1; + } + + if ((ScreenSize + 2) > DimensionsWidth) { + ScreenSize = DimensionsWidth - 2; + } + + BufferedString = AllocateZeroPool (ScreenSize * 2); + ASSERT (BufferedString); + + Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1; + + // + // Display prompt for string + // + CreatePopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + + CursorVisible = gST->ConOut->Mode->CursorVisible; + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + do { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)); + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + break; + + case SCAN_RIGHT: + break; + + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) { + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_SUCCESS; + } else { + // + // Simply create a popup to tell the user that they had typed in too few characters. + // To save code space, we can then treat this as an error and return back to the menu. + // + do { + CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, CursorVisible); + return EFI_DEVICE_ERROR; + } + + break; + + case CHAR_BACKSPACE: + if (StringPtr[0] != CHAR_NULL) { + for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringPtr[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringPtr, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringPtr, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringPtr, KeyPad); + StrCat (TempString, KeyPad); + } + + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, ScreenSize - 1, L' '); + PrintStringAt (Start + 1, Top + 3, BufferedString); + + if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + if (IsPassword) { + gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3); + } + + for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) { + BufferedString[Count] = StringPtr[Index]; + + if (IsPassword) { + PrintChar (L'*'); + } + } + + if (!IsPassword) { + PrintStringAt (Start + 1, Top + 3, BufferedString); + } + break; + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3); + } while (TRUE); + +} + + +/** + This routine reads a numeric value from the user input. + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +{ + EFI_STATUS Status; + UINTN Column; + UINTN Row; + CHAR16 InputText[23]; + CHAR16 FormattedNumber[22]; + UINT64 PreviousNumber[20]; + UINTN Count; + UINTN Loop; + BOOLEAN ManualInput; + BOOLEAN HexInput; + BOOLEAN DateOrTime; + UINTN InputWidth; + UINT64 EditValue; + UINT64 Step; + UINT64 Minimum; + UINT64 Maximum; + UINTN EraseLen; + UINT8 Digital; + EFI_INPUT_KEY Key; + EFI_HII_VALUE *QuestionValue; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_STATEMENT *Question; + + Column = MenuOption->OptCol; + Row = MenuOption->Row; + PreviousNumber[0] = 0; + Count = 0; + InputWidth = 0; + Digital = 0; + + FormSet = Selection->FormSet; + Form = Selection->Form; + Question = MenuOption->ThisTag; + QuestionValue = &Question->HiiValue; + Step = Question->Step; + Minimum = Question->Minimum; + Maximum = Question->Maximum; + + if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) { + DateOrTime = TRUE; + } else { + DateOrTime = FALSE; + } + + // + // Prepare Value to be edit + // + EraseLen = 0; + EditValue = 0; + if (Question->Operand == EFI_IFR_DATE_OP) { + Step = 1; + Minimum = 1; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 12; + EraseLen = 4; + EditValue = QuestionValue->Value.date.Month; + break; + + case 1: + Maximum = 31; + EraseLen = 3; + EditValue = QuestionValue->Value.date.Day; + break; + + case 2: + Maximum = 0xffff; + EraseLen = 5; + EditValue = QuestionValue->Value.date.Year; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + Step = 1; + Minimum = 0; + + switch (MenuOption->Sequence) { + case 0: + Maximum = 23; + EraseLen = 4; + EditValue = QuestionValue->Value.time.Hour; + break; + + case 1: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Minute; + break; + + case 2: + Maximum = 59; + EraseLen = 3; + EditValue = QuestionValue->Value.time.Second; + break; + + default: + break; + } + } else { + // + // Numeric + // + EraseLen = gOptionBlockWidth; + EditValue = QuestionValue->Value.u64; + if (Maximum == 0) { + Maximum = (UINT64) -1; + } + } + + if (Step == 0) { + ManualInput = TRUE; + } else { + ManualInput = FALSE; + } + + if ((Question->Operand == EFI_IFR_NUMERIC_OP) && + ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) { + HexInput = TRUE; + } else { + HexInput = FALSE; + } + + if (ManualInput) { + if (HexInput) { + InputWidth = Question->StorageWidth * 2; + } else { + switch (Question->StorageWidth) { + case 1: + InputWidth = 3; + break; + + case 2: + InputWidth = 5; + break; + + case 4: + InputWidth = 10; + break; + + case 8: + InputWidth = 20; + break; + + default: + InputWidth = 0; + break; + } + } + + InputText[0] = LEFT_NUMERIC_DELIMITER; + SetUnicodeMem (InputText + 1, InputWidth, L' '); + InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER; + InputText[InputWidth + 2] = L'\0'; + + PrintAt (Column, Row, InputText); + Column++; + } + + // + // First time we enter this handler, we need to check to see if + // we were passed an increment or decrement directive + // + do { + Key.UnicodeChar = CHAR_NULL; + if (gDirection != 0) { + Key.ScanCode = gDirection; + gDirection = 0; + goto TheKey2; + } + + Status = WaitForKeyStroke (&Key); + +TheKey2: + switch (Key.UnicodeChar) { + + case '+': + case '-': + if (Key.UnicodeChar == '+') { + Key.ScanCode = SCAN_RIGHT; + } else { + Key.ScanCode = SCAN_LEFT; + } + Key.UnicodeChar = CHAR_NULL; + goto TheKey2; + + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_LEFT: + case SCAN_RIGHT: + if (DateOrTime) { + // + // By setting this value, we will return back to the caller. + // We need to do this since an auto-refresh will destroy the adjustment + // based on what the real-time-clock is showing. So we always commit + // upon changing the value. + // + gDirection = SCAN_DOWN; + } + + if (!ManualInput) { + if (Key.ScanCode == SCAN_LEFT) { + if (EditValue > Step) { + EditValue = EditValue - Step; + } else { + EditValue = Minimum; + } + } else if (Key.ScanCode == SCAN_RIGHT) { + EditValue = EditValue + Step; + if (EditValue > Maximum) { + EditValue = Maximum; + } + } + + ZeroMem (FormattedNumber, 21 * sizeof (CHAR16)); + if (Question->Operand == EFI_IFR_DATE_OP) { + if (MenuOption->Sequence == 2) { + // + // Year + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", EditValue); + } else { + // + // Month/Day + // + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + } + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = DATE_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = DATE_SEPARATOR; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", EditValue); + + if (MenuOption->Sequence == 0) { + FormattedNumber[EraseLen - 2] = TIME_SEPARATOR; + } else if (MenuOption->Sequence == 1) { + FormattedNumber[EraseLen - 1] = TIME_SEPARATOR; + } + } else { + QuestionValue->Value.u64 = EditValue; + PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16)); + } + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + for (Loop = 0; Loop < EraseLen; Loop++) { + PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" "); + } + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + + if (MenuOption->Sequence == 0) { + PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER); + Column = MenuOption->OptCol + 1; + } + + PrintStringAt (Column, Row, FormattedNumber); + + if (!DateOrTime || MenuOption->Sequence == 2) { + PrintChar (RIGHT_NUMERIC_DELIMITER); + } + } + break; + + case SCAN_UP: + case SCAN_DOWN: + goto EnterCarriageReturn; + + case SCAN_ESC: + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + +EnterCarriageReturn: + + case CHAR_CARRIAGE_RETURN: + // + // Store Edit value back to Question + // + if (Question->Operand == EFI_IFR_DATE_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.date.Month = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.date.Day = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.date.Year = (UINT16) EditValue; + break; + + default: + break; + } + } else if (Question->Operand == EFI_IFR_TIME_OP) { + switch (MenuOption->Sequence) { + case 0: + QuestionValue->Value.time.Hour = (UINT8) EditValue; + break; + + case 1: + QuestionValue->Value.time.Minute = (UINT8) EditValue; + break; + + case 2: + QuestionValue->Value.time.Second = (UINT8) EditValue; + break; + + default: + break; + } + } else { + // + // Numeric + // + QuestionValue->Value.u64 = EditValue; + } + + // + // Check to see if the Value is something reasonable against consistency limitations. + // If not, let's kick the error specified. + // + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF); + if (EFI_ERROR (Status)) { + // + // Input value is not valid, restore Question Value + // + GetQuestionValue (FormSet, Form, Question, TRUE); + } else { + SetQuestionValue (FormSet, Form, Question, TRUE); + if (!DateOrTime || (Question->Storage != NULL)) { + // + // NV flag is unnecessary for RTC type of Date/Time + // + UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + } + + return Status; + break; + + case CHAR_BACKSPACE: + if (ManualInput) { + if (Count == 0) { + break; + } + // + // Remove a character + // + EditValue = PreviousNumber[Count - 1]; + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + Count--; + Column--; + PrintAt (Column, Row, L" "); + } + break; + + default: + if (ManualInput) { + if (HexInput) { + if (!IsHexDigit (&Digital, Key.UnicodeChar)) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } else { + if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + break; + } + } + + // + // If Count exceed input width, there is no way more is valid + // + if (Count >= InputWidth) { + break; + } + // + // Someone typed something valid! + // + if (Count != 0) { + if (HexInput) { + EditValue = LShiftU64 (EditValue, 4) + Digital; + } else { + EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0'); + } + } else { + if (HexInput) { + EditValue = Digital; + } else { + EditValue = Key.UnicodeChar - L'0'; + } + } + + if (EditValue > Maximum) { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE); + EditValue = PreviousNumber[Count]; + break; + } else { + UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE); + } + + Count++; + PreviousNumber[Count] = EditValue; + + PrintCharAt (Column, Row, Key.UnicodeChar); + Column++; + } + break; + } + } while (TRUE); + +} + + +/** + 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; + EFI_HII_VALUE HiiValue; + EFI_HII_VALUE *HiiValueArray; + UINTN OptionCount; + QUESTION_OPTION *OneOfOption; + QUESTION_OPTION *CurrentOption; + FORM_BROWSER_STATEMENT *Question; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + + ValueArray = NULL; + 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; + OrderedList = TRUE; + } else { + OrderedList = FALSE; + } + + // + // Calculate Option count + // + if (OrderedList) { + for (Index = 0; Index < Question->MaxContainers; Index++) { + if (ValueArray[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 = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValueArray[Index].Value.u8 = ValueArray[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) && + (OneOfOption->SuppressExpression->Result.Value.b)) { + // + // 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); + } + gBS->FreePool (StringPtr); + + if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 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 - FOOTER_HEIGHT - 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); + // + // 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))); + gBS->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++; + gBS->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--; + + 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++; + + 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 = EFI_IFR_TYPE_NUM_SIZE_8; + HiiValue.Value.u64 = 0; + for (Index = 0; Index < Question->MaxContainers; Index++) { + HiiValue.Value.u8 = ValueArray[Index]; + if (HiiValue.Value.u8) { + break; + } + + OneOfOption = ValueToOption (Question, &HiiValue); + if (OneOfOption == NULL) { + return EFI_NOT_FOUND; + } + + RemoveEntryList (&OneOfOption->Link); + InsertTailList (&Question->OptionListHead, &OneOfOption->Link); + } + } + + gBS->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); + + Question->BufferValue[Index] = OneOfOption->Value.Value.u8; + + Index++; + if (Index > Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } else { + CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE)); + } + + gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute); + gBS->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 (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE); + } + + return Status; + + default: + break; + } + } while (TRUE); + +} + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +{ + EFI_STATUS Status; + + do { + UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0); + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key); + } while (EFI_ERROR(Status)); + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c index 631f6413b8..47f99f5b8d 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Presentation.c @@ -1,928 +1,1005 @@ -/** @file -Copyright (c) 2004 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - Presentation.c - -Abstract: - - Some presentation routines. - - -**/ - -#include "Setup.h" -#include "Ui.h" - -BOOLEAN mHiiPackageListUpdated; -UI_MENU_SELECTION *gCurrentSelection; - - -/** - Clear retangle with specified text attribute. - - @param LeftColumn Left column of retangle. - @param RightColumn Right column of retangle. - @param TopRow Start row of retangle. - @param BottomRow End row of retangle. - @param TextAttribute The character foreground and background. - - @return None. - -**/ -VOID -ClearLines ( - UINTN LeftColumn, - UINTN RightColumn, - UINTN TopRow, - UINTN BottomRow, - UINTN TextAttribute - ) -{ - CHAR16 *Buffer; - UINTN Row; - - // - // For now, allocate an arbitrarily long buffer - // - Buffer = AllocateZeroPool (0x10000); - ASSERT (Buffer != NULL); - - // - // Set foreground and background as defined - // - gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); - - // - // Much faster to buffer the long string instead of print it a character at a time - // - SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); - - // - // Clear the desired area with the appropriate foreground/background - // - for (Row = TopRow; Row <= BottomRow; Row++) { - PrintStringAt (LeftColumn, Row, Buffer); - } - - gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); - - gBS->FreePool (Buffer); - return ; -} - -VOID -NewStrCat ( - CHAR16 *Destination, - CHAR16 *Source - ) -{ - UINTN Length; - - for (Length = 0; Destination[Length] != 0; Length++) - ; - - // - // We now have the length of the original string - // We can safely assume for now that we are concatenating a narrow value to this string. - // For instance, the string is "XYZ" and cat'ing ">" - // If this assumption changes, we need to make this routine a bit more complex - // - Destination[Length] = NARROW_CHAR; - Length++; - - StrCpy (Destination + Length, Source); -} - -UINTN -GetStringWidth ( - CHAR16 *String - ) -{ - UINTN Index; - UINTN Count; - UINTN IncrementValue; - - Index = 0; - Count = 0; - IncrementValue = 1; - - do { - // - // Advance to the null-terminator or to the first width directive - // - for (; - (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); - Index++, Count = Count + IncrementValue - ) - ; - - // - // We hit the null-terminator, we now have a count - // - if (String[Index] == 0) { - break; - } - // - // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed - // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) - // - if (String[Index] == NARROW_CHAR) { - // - // Skip to the next character - // - Index++; - IncrementValue = 1; - } else { - // - // Skip to the next character - // - Index++; - IncrementValue = 2; - } - } while (String[Index] != 0); - - // - // Increment by one to include the null-terminator in the size - // - Count++; - - return Count * sizeof (CHAR16); -} - -VOID -DisplayPageFrame ( - VOID - ) -{ - UINTN Index; - UINT8 Line; - UINT8 Alignment; - CHAR16 Character; - CHAR16 *Buffer; - CHAR16 *StrFrontPageBanner; - UINTN Row; - EFI_SCREEN_DESCRIPTOR LocalScreen; - - ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); - gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); - ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - // - // For now, allocate an arbitrarily long buffer - // - Buffer = AllocateZeroPool (0x10000); - ASSERT (Buffer != NULL); - - Character = BOXDRAW_HORIZONTAL; - - for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { - Buffer[Index] = Character; - } - - if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { - // - // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); - // - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.TopRow, - FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, - BANNER_TEXT | BANNER_BACKGROUND - ); - // - // for (Line = 0; Line < BANNER_HEIGHT; Line++) { - // - for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { - // - // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { - // - for (Alignment = (UINT8) LocalScreen.LeftColumn; - Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; - Alignment++ - ) { - if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) { - StrFrontPageBanner = GetToken ( - BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn], - FrontPageHandle - ); - } else { - continue; - } - - switch (Alignment - LocalScreen.LeftColumn) { - case 0: - // - // Handle left column - // - PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner); - break; - - case 1: - // - // Handle center column - // - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, - Line, - StrFrontPageBanner - ); - break; - - case 2: - // - // Handle right column - // - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, - Line, - StrFrontPageBanner - ); - break; - } - - gBS->FreePool (StrFrontPageBanner); - } - } - } - - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, - LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, - KEYHELP_TEXT | KEYHELP_BACKGROUND - ); - - if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - LocalScreen.TopRow, - LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, - TITLE_TEXT | TITLE_BACKGROUND - ); - // - // Print Top border line - // +------------------------------------------------------------------------------+ - // ? ? - // +------------------------------------------------------------------------------+ - // - Character = BOXDRAW_DOWN_RIGHT; - - PrintChar (Character); - PrintString (Buffer); - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - - Character = BOXDRAW_VERTICAL; - for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { - PrintCharAt (LocalScreen.LeftColumn, Row, Character); - PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); - } - - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); - PrintString (Buffer); - - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); - - if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { - // - // Print Bottom border line - // +------------------------------------------------------------------------------+ - // ? ? - // +------------------------------------------------------------------------------+ - // - Character = BOXDRAW_DOWN_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); - - PrintString (Buffer); - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - Character = BOXDRAW_VERTICAL; - for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; - Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; - Row++ - ) { - PrintCharAt (LocalScreen.LeftColumn, Row, Character); - PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); - } - - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); - - PrintString (Buffer); - - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); - } - } - - gBS->FreePool (Buffer); - -} - - -/** - Evaluate all expressions in a Form. - - @param FormSet FormSet this Form belongs to. - @param Form The Form. - - @retval EFI_SUCCESS The expression evaluated successfuly - -**/ -EFI_STATUS -EvaluateFormExpressions ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - FORM_EXPRESSION *Expression; - - Link = GetFirstNode (&Form->ExpressionListHead); - while (!IsNull (&Form->ExpressionListHead, Link)) { - Expression = FORM_EXPRESSION_FROM_LINK (Link); - Link = GetNextNode (&Form->ExpressionListHead, Link); - - if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || - Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { - // - // Postpone Form validation to Question editing or Form submiting - // - continue; - } - - Status = EvaluateExpression (FormSet, Form, Expression); - if (EFI_ERROR (Status)) { - return Status; - } - } - - return EFI_SUCCESS; -} - -/* -+------------------------------------------------------------------------------+ -?F2=Previous Page Setup Page ? -+------------------------------------------------------------------------------+ - - - - - - - - - - - - - - - - - -+------------------------------------------------------------------------------+ -?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? -| ^"=Move Highlight Toggles Checkbox Esc=Discard Changes | -+------------------------------------------------------------------------------+ -*/ -EFI_STATUS -DisplayForm ( - IN OUT UI_MENU_SELECTION *Selection - ) -{ - CHAR16 *StringPtr; - UINT16 MenuItemCount; - EFI_HII_HANDLE Handle; - BOOLEAN Suppress; - EFI_SCREEN_DESCRIPTOR LocalScreen; - UINT16 Width; - UINTN ArrayEntry; - CHAR16 *OutputString; - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Statement; - UINT16 NumberOfLines; - EFI_STATUS Status; - - Handle = Selection->Handle; - MenuItemCount = 0; - ArrayEntry = 0; - OutputString = NULL; - - UiInitMenu (); - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - StringPtr = GetToken (Selection->FormSet->FormSetTitle, Handle); - - if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { - gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); - PrintStringAt ( - (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, - LocalScreen.TopRow + 1, - StringPtr - ); - } - - if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { - gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - // - // Display the infrastructure strings - // - if (!IsListEmpty (&gMenuList)) { - PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString); - } - - PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString); - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, - LocalScreen.BottomRow - 4, - gFunctionNineString - ); - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, - LocalScreen.BottomRow - 4, - gFunctionTenString - ); - PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - PrintStringAt ( - LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, - LocalScreen.BottomRow - 3, - gEscapeString - ); - } - // - // Remove Buffer allocated for StringPtr after it has been used. - // - gBS->FreePool (StringPtr); - - // - // Evaluate all the Expressions in this Form - // - Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form); - if (EFI_ERROR (Status)) { - return Status; - } - - Link = GetFirstNode (&Selection->Form->StatementListHead); - while (!IsNull (&Selection->Form->StatementListHead, Link)) { - Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - - if (Statement->SuppressExpression != NULL) { - Suppress = Statement->SuppressExpression->Result.Value.b; - } else { - Suppress = FALSE; - } - - if (!Suppress) { - StringPtr = GetToken (Statement->Prompt, Handle); - - Width = GetWidth (Statement, Handle); - - NumberOfLines = 1; - ArrayEntry = 0; - for (; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) { - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&StringPtr[ArrayEntry])) { - NumberOfLines++; - } - - gBS->FreePool (OutputString); - } - - // - // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do - // it in UiFreeMenu. - // - UiAddMenuOption (StringPtr, Selection->Handle, Statement, NumberOfLines, MenuItemCount); - MenuItemCount++; - } - - Link = GetNextNode (&Selection->Form->StatementListHead, Link); - } - - Status = UiDisplayMenu (Selection); - - UiFreeMenu (); - - return Status; -} - -VOID -InitializeBrowserStrings ( - VOID - ) -{ - gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle); - gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle); - gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); - gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); - gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); - gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); - gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); - gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); - gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); - gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); - gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); - gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle); - gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle); - gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); - gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); - gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); - gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); - gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); - gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); - gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); - gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); - gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); - gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); - gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); - gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); - gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); - gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); - return ; -} - -VOID -FreeBrowserStrings ( - VOID - ) -{ - SafeFreePool (gFunctionOneString); - SafeFreePool (gFunctionTwoString); - SafeFreePool (gFunctionNineString); - SafeFreePool (gFunctionTenString); - SafeFreePool (gEnterString); - SafeFreePool (gEnterCommitString); - SafeFreePool (gEscapeString); - SafeFreePool (gMoveHighlight); - SafeFreePool (gMakeSelection); - SafeFreePool (gDecNumericInput); - SafeFreePool (gHexNumericInput); - SafeFreePool (gToggleCheckBox); - SafeFreePool (gPromptForData); - SafeFreePool (gPromptForPassword); - SafeFreePool (gPromptForNewPassword); - SafeFreePool (gConfirmPassword); - SafeFreePool (gPassowordInvalid); - SafeFreePool (gConfirmError); - SafeFreePool (gPressEnter); - SafeFreePool (gEmptyString); - SafeFreePool (gAreYouSure); - SafeFreePool (gYesResponse); - SafeFreePool (gNoResponse); - SafeFreePool (gMiniString); - SafeFreePool (gPlusString); - SafeFreePool (gMinusString); - SafeFreePool (gAdjustNumber); - return ; -} - - -/** - Update key's help imformation - - @param MenuOption The Menu option - @param Selected Whether or not a tag be selected - - @return None - -**/ -VOID -UpdateKeyHelp ( - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected - ) -{ - UINTN SecCol; - UINTN ThdCol; - UINTN LeftColumnOfHelp; - UINTN RightColumnOfHelp; - UINTN TopRowOfHelp; - UINTN BottomRowOfHelp; - UINTN StartColumnOfHelp; - EFI_SCREEN_DESCRIPTOR LocalScreen; - FORM_BROWSER_STATEMENT *Statement; - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; - ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; - - StartColumnOfHelp = LocalScreen.LeftColumn + 2; - LeftColumnOfHelp = LocalScreen.LeftColumn + 1; - RightColumnOfHelp = LocalScreen.RightColumn - 2; - TopRowOfHelp = LocalScreen.BottomRow - 4; - BottomRowOfHelp = LocalScreen.BottomRow - 3; - - if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) { - return ; - } - - gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - Statement = MenuOption->ThisTag; - switch (Statement->Operand) { - case EFI_IFR_ORDERED_LIST_OP: - case EFI_IFR_ONE_OF_OP: - case EFI_IFR_NUMERIC_OP: - case EFI_IFR_TIME_OP: - case EFI_IFR_DATE_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - if (!Selected) { - if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - - if ((Statement->Operand == EFI_IFR_DATE_OP) || - (Statement->Operand == EFI_IFR_TIME_OP) || - (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { - PrintAt ( - StartColumnOfHelp, - BottomRowOfHelp, - L"%c%c%c%c%s", - ARROW_UP, - ARROW_DOWN, - ARROW_RIGHT, - ARROW_LEFT, - gMoveHighlight - ); - PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber); - } else { - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); - } - } else { - PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); - - // - // If it is a selected numeric with manual input, display different message - // - if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) { - PrintStringAt ( - SecCol, - TopRowOfHelp, - (Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput - ); - } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) { - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - } - - if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); - PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); - } - - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - break; - - case EFI_IFR_CHECKBOX_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); - break; - - case EFI_IFR_REF_OP: - case EFI_IFR_PASSWORD_OP: - case EFI_IFR_STRING_OP: - case EFI_IFR_TEXT_OP: - case EFI_IFR_ACTION_OP: - case EFI_IFR_RESET_BUTTON_OP: - ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); - - if (!Selected) { - if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { - PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); - PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); - PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - - PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); - if (Statement->Operand != EFI_IFR_TEXT_OP) { - PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); - } - } else { - if (Statement->Operand != EFI_IFR_REF_OP) { - PrintStringAt ( - (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, - BottomRowOfHelp, - gEnterCommitString - ); - PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); - } - } - break; - - default: - break; - } -} - -EFI_STATUS -FormUpdateNotify ( - IN UINT8 PackageType, - IN CONST EFI_GUID *PackageGuid, - IN CONST EFI_HII_PACKAGE_HEADER *Package, - IN EFI_HII_HANDLE Handle, - IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType - ) -{ - mHiiPackageListUpdated = TRUE; - - return EFI_SUCCESS; -} - -EFI_STATUS -SetupBrowser ( - IN OUT UI_MENU_SELECTION *Selection - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - EFI_BROWSER_ACTION_REQUEST ActionRequest; - EFI_HANDLE NotifyHandle; - EFI_HII_VALUE *HiiValue; - FORM_BROWSER_STATEMENT *Statement; - EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - - gMenuRefreshHead = NULL; - gResetRequired = FALSE; - gNvUpdateRequired = FALSE; - - UiInitMenuList (); - - // - // Register notify for Form package update - // - Status = mHiiDatabase->RegisterPackageNotify ( - mHiiDatabase, - EFI_HII_PACKAGE_FORM, - NULL, - FormUpdateNotify, - EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, - &NotifyHandle - ); - if (EFI_ERROR (Status)) { - return Status; - } - - do { - // - // Displays the Header and Footer borders - // - DisplayPageFrame (); - - // - // Initialize Selection->Form - // - if (Selection->FormId == 0) { - // - // Zero FormId indicates display the first Form in a FormSet - // - Link = GetFirstNode (&Selection->FormSet->FormListHead); - - Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); - Selection->FormId = Selection->Form->FormId; - } else { - Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); - } - - // - // Load Questions' Value for display - // - Status = LoadFormConfig (Selection->FormSet, Selection->Form); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Display form - // - Status = DisplayForm (Selection); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Check Selected Statement (if press ESC, Selection->Statement will be NULL) - // - Statement = Selection->Statement; - if (Statement != NULL) { - if (Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) { - gResetRequired = TRUE; - } - - // - // Reset FormPackage update flag - // - mHiiPackageListUpdated = FALSE; - - if (Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK && Statement->Operand != EFI_IFR_PASSWORD_OP) { - ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; - - HiiValue = &Statement->HiiValue; - if (HiiValue->Type == EFI_IFR_TYPE_STRING) { - // - // Create String in HII database for Configuration Driver to retrieve - // - HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle); - } - - ConfigAccess = Selection->FormSet->ConfigAccess; - if (ConfigAccess == NULL) { - return EFI_UNSUPPORTED; - } - Status = ConfigAccess->Callback ( - ConfigAccess, - EFI_BROWSER_ACTION_CHANGING, - Statement->QuestionId, - HiiValue->Type, - &HiiValue->Value, - &ActionRequest - ); - - if (HiiValue->Type == EFI_IFR_TYPE_STRING) { - // - // Clean the String in HII Database - // - DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle); - } - - if (!EFI_ERROR (Status)) { - switch (ActionRequest) { - case EFI_BROWSER_ACTION_REQUEST_RESET: - gResetRequired = TRUE; - break; - - case EFI_BROWSER_ACTION_REQUEST_SUBMIT: - SubmitForm (Selection->FormSet, Selection->Form); - break; - - case EFI_BROWSER_ACTION_REQUEST_EXIT: - Selection->Action = UI_ACTION_EXIT; - gNvUpdateRequired = FALSE; - break; - - default: - break; - } - } - } - - // - // Check whether Form Package has been updated during Callback - // - if (mHiiPackageListUpdated && (Selection->Action == UI_ACTION_REFRESH_FORM)) { - // - // Force to reparse IFR binary of target Formset - // - Selection->Action = UI_ACTION_REFRESH_FORMSET; - } - } - } while (Selection->Action == UI_ACTION_REFRESH_FORM); - - // - // Unregister notify for Form package update - // - Status = mHiiDatabase->UnregisterPackageNotify ( - mHiiDatabase, - NotifyHandle - ); - return Status; -} +/** @file +Utility functions for UI presentation. + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Setup.h" +#include "Ui.h" + +BOOLEAN mHiiPackageListUpdated; +UI_MENU_SELECTION *gCurrentSelection; + + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + +**/ +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +{ + CHAR16 *Buffer; + UINTN Row; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + // + // Set foreground and background as defined + // + gST->ConOut->SetAttribute (gST->ConOut, TextAttribute); + + // + // Much faster to buffer the long string instead of print it a character at a time + // + SetUnicodeMem (Buffer, RightColumn - LeftColumn, L' '); + + // + // Clear the desired area with the appropriate foreground/background + // + for (Row = TopRow; Row <= BottomRow; Row++) { + PrintStringAt (LeftColumn, Row, Buffer); + } + + gST->ConOut->SetCursorPosition (gST->ConOut, LeftColumn, TopRow); + + gBS->FreePool (Buffer); + return ; +} + +/** + Concatenate a narrow string to another string. + + @param Destination The destination string. + @param Source The source string. The string to be concatenated. + to the end of Destination. + +**/ +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +{ + UINTN Length; + + for (Length = 0; Destination[Length] != 0; Length++) + ; + + // + // We now have the length of the original string + // We can safely assume for now that we are concatenating a narrow value to this string. + // For instance, the string is "XYZ" and cat'ing ">" + // If this assumption changes, we need to make this routine a bit more complex + // + Destination[Length] = NARROW_CHAR; + Length++; + + StrCpy (Destination + Length, Source); +} + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetStringWidth ( + CHAR16 *String + ) +{ + UINTN Index; + UINTN Count; + UINTN IncrementValue; + + Index = 0; + Count = 0; + IncrementValue = 1; + + do { + // + // Advance to the null-terminator or to the first width directive + // + for (; + (String[Index] != NARROW_CHAR) && (String[Index] != WIDE_CHAR) && (String[Index] != 0); + Index++, Count = Count + IncrementValue + ) + ; + + // + // We hit the null-terminator, we now have a count + // + if (String[Index] == 0) { + break; + } + // + // We encountered a narrow directive - strip it from the size calculation since it doesn't get printed + // and also set the flag that determines what we increment by.(if narrow, increment by 1, if wide increment by 2) + // + if (String[Index] == NARROW_CHAR) { + // + // Skip to the next character + // + Index++; + IncrementValue = 1; + } else { + // + // Skip to the next character + // + Index++; + IncrementValue = 2; + } + } while (String[Index] != 0); + + // + // Increment by one to include the null-terminator in the size + // + Count++; + + return Count * sizeof (CHAR16); +} + +/** + This function displays the page frame. + +**/ +VOID +DisplayPageFrame ( + VOID + ) +{ + UINTN Index; + UINT8 Line; + UINT8 Alignment; + CHAR16 Character; + CHAR16 *Buffer; + CHAR16 *StrFrontPageBanner; + UINTN Row; + EFI_SCREEN_DESCRIPTOR LocalScreen; + + ZeroMem (&LocalScreen, sizeof (EFI_SCREEN_DESCRIPTOR)); + gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &LocalScreen.RightColumn, &LocalScreen.BottomRow); + ClearLines (0, LocalScreen.RightColumn, 0, LocalScreen.BottomRow, KEYHELP_BACKGROUND); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + ASSERT (Buffer != NULL); + + Character = BOXDRAW_HORIZONTAL; + + for (Index = 0; Index + 2 < (LocalScreen.RightColumn - LocalScreen.LeftColumn); Index++) { + Buffer[Index] = Character; + } + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // ClearLines(0, LocalScreen.RightColumn, 0, BANNER_HEIGHT-1, BANNER_TEXT | BANNER_BACKGROUND); + // + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + FRONT_PAGE_HEADER_HEIGHT - 1 + LocalScreen.TopRow, + BANNER_TEXT | BANNER_BACKGROUND + ); + // + // for (Line = 0; Line < BANNER_HEIGHT; Line++) { + // + for (Line = (UINT8) LocalScreen.TopRow; Line < BANNER_HEIGHT + (UINT8) LocalScreen.TopRow; Line++) { + // + // for (Alignment = 0; Alignment < BANNER_COLUMNS; Alignment++) { + // + for (Alignment = (UINT8) LocalScreen.LeftColumn; + Alignment < BANNER_COLUMNS + (UINT8) LocalScreen.LeftColumn; + Alignment++ + ) { + if (BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn] != 0x0000) { + StrFrontPageBanner = GetToken ( + BannerData->Banner[Line - (UINT8) LocalScreen.TopRow][Alignment - (UINT8) LocalScreen.LeftColumn], + FrontPageHandle + ); + } else { + continue; + } + + switch (Alignment - LocalScreen.LeftColumn) { + case 0: + // + // Handle left column + // + PrintStringAt (LocalScreen.LeftColumn, Line, StrFrontPageBanner); + break; + + case 1: + // + // Handle center column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + Line, + StrFrontPageBanner + ); + break; + + case 2: + // + // Handle right column + // + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + Line, + StrFrontPageBanner + ); + break; + } + + gBS->FreePool (StrFrontPageBanner); + } + } + } + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, + LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, + KEYHELP_TEXT | KEYHELP_BACKGROUND + ); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + LocalScreen.TopRow, + LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, + TITLE_TEXT | TITLE_BACKGROUND + ); + // + // Print Top border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + + PrintChar (Character); + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.TopRow + 1; Row <= LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 2; Row++) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT - 1, Character); + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + // + // Print Bottom border line + // +------------------------------------------------------------------------------+ + // ? ? + // +------------------------------------------------------------------------------+ + // + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT, Character); + + PrintString (Buffer); + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Row = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT + 1; + Row <= LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 2; + Row++ + ) { + PrintCharAt (LocalScreen.LeftColumn, Row, Character); + PrintCharAt (LocalScreen.RightColumn - 1, Row, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (LocalScreen.LeftColumn, LocalScreen.BottomRow - STATUS_BAR_HEIGHT - 1, Character); + + PrintString (Buffer); + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); + } + } + + gBS->FreePool (Buffer); + +} + + +/** + Evaluate all expressions in a Form. + + @param FormSet FormSet this Form belongs to. + @param Form The Form. + + @retval EFI_SUCCESS The expression evaluated successfuly + +**/ +EFI_STATUS +EvaluateFormExpressions ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_EXPRESSION *Expression; + + Link = GetFirstNode (&Form->ExpressionListHead); + while (!IsNull (&Form->ExpressionListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + Link = GetNextNode (&Form->ExpressionListHead, Link); + + if (Expression->Type == EFI_HII_EXPRESSION_INCONSISTENT_IF || + Expression->Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + // + // Postpone Form validation to Question editing or Form submiting + // + continue; + } + + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/* ++------------------------------------------------------------------------------+ +?F2=Previous Page Setup Page ? ++------------------------------------------------------------------------------+ + + + + + + + + + + + + + + + + + ++------------------------------------------------------------------------------+ +?F1=Scroll Help F9=Reset to Defaults F10=Save and Exit ? +| ^"=Move Highlight Toggles Checkbox Esc=Discard Changes | ++------------------------------------------------------------------------------+ +*/ + +/** + + + Display form and wait for user to select one menu option, then return it. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +DisplayForm ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + CHAR16 *StringPtr; + UINT16 MenuItemCount; + EFI_HII_HANDLE Handle; + BOOLEAN Suppress; + EFI_SCREEN_DESCRIPTOR LocalScreen; + UINT16 Width; + UINTN ArrayEntry; + CHAR16 *OutputString; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Statement; + UINT16 NumberOfLines; + EFI_STATUS Status; + + Handle = Selection->Handle; + MenuItemCount = 0; + ArrayEntry = 0; + OutputString = NULL; + + UiInitMenu (); + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + StringPtr = GetToken (Selection->FormSet->FormSetTitle, Handle); + + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, TITLE_TEXT | TITLE_BACKGROUND); + PrintStringAt ( + (LocalScreen.RightColumn + LocalScreen.LeftColumn - GetStringWidth (StringPtr) / 2) / 2, + LocalScreen.TopRow + 1, + StringPtr + ); + } + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + // + // Display the infrastructure strings + // + if (!IsListEmpty (&gMenuList)) { + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.TopRow + 1, gFunctionTwoString); + } + + PrintStringAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 4, gFunctionOneString); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 4, + gFunctionNineString + ); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3, + LocalScreen.BottomRow - 4, + gFunctionTenString + ); + PrintAt (LocalScreen.LeftColumn + 2, LocalScreen.BottomRow - 3, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt ( + LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3, + LocalScreen.BottomRow - 3, + gEscapeString + ); + } + // + // Remove Buffer allocated for StringPtr after it has been used. + // + gBS->FreePool (StringPtr); + + // + // Evaluate all the Expressions in this Form + // + Status = EvaluateFormExpressions (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetFirstNode (&Selection->Form->StatementListHead); + while (!IsNull (&Selection->Form->StatementListHead, Link)) { + Statement = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + if (Statement->SuppressExpression != NULL) { + Suppress = Statement->SuppressExpression->Result.Value.b; + } else { + Suppress = FALSE; + } + + if (!Suppress) { + StringPtr = GetToken (Statement->Prompt, Handle); + + Width = GetWidth (Statement, Handle); + + NumberOfLines = 1; + ArrayEntry = 0; + for (; GetLineByWidth (StringPtr, Width, &ArrayEntry, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[ArrayEntry])) { + NumberOfLines++; + } + + gBS->FreePool (OutputString); + } + + // + // We are NOT!! removing this StringPtr buffer via FreePool since it is being used in the menuoptions, we will do + // it in UiFreeMenu. + // + UiAddMenuOption (StringPtr, Selection->Handle, Statement, NumberOfLines, MenuItemCount); + MenuItemCount++; + } + + Link = GetNextNode (&Selection->Form->StatementListHead, Link); + } + + Status = UiDisplayMenu (Selection); + + UiFreeMenu (); + + return Status; +} + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeBrowserStrings ( + VOID + ) +{ + gFunctionOneString = GetToken (STRING_TOKEN (FUNCTION_ONE_STRING), gHiiHandle); + gFunctionTwoString = GetToken (STRING_TOKEN (FUNCTION_TWO_STRING), gHiiHandle); + gFunctionNineString = GetToken (STRING_TOKEN (FUNCTION_NINE_STRING), gHiiHandle); + gFunctionTenString = GetToken (STRING_TOKEN (FUNCTION_TEN_STRING), gHiiHandle); + gEnterString = GetToken (STRING_TOKEN (ENTER_STRING), gHiiHandle); + gEnterCommitString = GetToken (STRING_TOKEN (ENTER_COMMIT_STRING), gHiiHandle); + gEscapeString = GetToken (STRING_TOKEN (ESCAPE_STRING), gHiiHandle); + gSaveFailed = GetToken (STRING_TOKEN (SAVE_FAILED), gHiiHandle); + gMoveHighlight = GetToken (STRING_TOKEN (MOVE_HIGHLIGHT), gHiiHandle); + gMakeSelection = GetToken (STRING_TOKEN (MAKE_SELECTION), gHiiHandle); + gDecNumericInput = GetToken (STRING_TOKEN (DEC_NUMERIC_INPUT), gHiiHandle); + gHexNumericInput = GetToken (STRING_TOKEN (HEX_NUMERIC_INPUT), gHiiHandle); + gToggleCheckBox = GetToken (STRING_TOKEN (TOGGLE_CHECK_BOX), gHiiHandle); + gPromptForData = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle); + gPromptForPassword = GetToken (STRING_TOKEN (PROMPT_FOR_PASSWORD), gHiiHandle); + gPromptForNewPassword = GetToken (STRING_TOKEN (PROMPT_FOR_NEW_PASSWORD), gHiiHandle); + gConfirmPassword = GetToken (STRING_TOKEN (CONFIRM_PASSWORD), gHiiHandle); + gConfirmError = GetToken (STRING_TOKEN (CONFIRM_ERROR), gHiiHandle); + gPassowordInvalid = GetToken (STRING_TOKEN (PASSWORD_INVALID), gHiiHandle); + gPressEnter = GetToken (STRING_TOKEN (PRESS_ENTER), gHiiHandle); + gEmptyString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + gAreYouSure = GetToken (STRING_TOKEN (ARE_YOU_SURE), gHiiHandle); + gYesResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_YES), gHiiHandle); + gNoResponse = GetToken (STRING_TOKEN (ARE_YOU_SURE_NO), gHiiHandle); + gMiniString = GetToken (STRING_TOKEN (MINI_STRING), gHiiHandle); + gPlusString = GetToken (STRING_TOKEN (PLUS_STRING), gHiiHandle); + gMinusString = GetToken (STRING_TOKEN (MINUS_STRING), gHiiHandle); + gAdjustNumber = GetToken (STRING_TOKEN (ADJUST_NUMBER), gHiiHandle); + return ; +} + +/** + Free up the resource allocated for all strings required + by Setup Browser. + +**/ +VOID +FreeBrowserStrings ( + VOID + ) +{ + SafeFreePool (gFunctionOneString); + SafeFreePool (gFunctionTwoString); + SafeFreePool (gFunctionNineString); + SafeFreePool (gFunctionTenString); + SafeFreePool (gEnterString); + SafeFreePool (gEnterCommitString); + SafeFreePool (gEscapeString); + SafeFreePool (gMoveHighlight); + SafeFreePool (gMakeSelection); + SafeFreePool (gDecNumericInput); + SafeFreePool (gHexNumericInput); + SafeFreePool (gToggleCheckBox); + SafeFreePool (gPromptForData); + SafeFreePool (gPromptForPassword); + SafeFreePool (gPromptForNewPassword); + SafeFreePool (gConfirmPassword); + SafeFreePool (gPassowordInvalid); + SafeFreePool (gConfirmError); + SafeFreePool (gPressEnter); + SafeFreePool (gEmptyString); + SafeFreePool (gAreYouSure); + SafeFreePool (gYesResponse); + SafeFreePool (gNoResponse); + SafeFreePool (gMiniString); + SafeFreePool (gPlusString); + SafeFreePool (gMinusString); + SafeFreePool (gAdjustNumber); + return ; +} + + +/** + Update key's help imformation. + + @param MenuOption The Menu option + @param Selected Whether or not a tag be selected + +**/ +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +{ + UINTN SecCol; + UINTN ThdCol; + UINTN LeftColumnOfHelp; + UINTN RightColumnOfHelp; + UINTN TopRowOfHelp; + UINTN BottomRowOfHelp; + UINTN StartColumnOfHelp; + EFI_SCREEN_DESCRIPTOR LocalScreen; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + SecCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) / 3; + ThdCol = LocalScreen.LeftColumn + (LocalScreen.RightColumn - LocalScreen.LeftColumn) * 2 / 3; + + StartColumnOfHelp = LocalScreen.LeftColumn + 2; + LeftColumnOfHelp = LocalScreen.LeftColumn + 1; + RightColumnOfHelp = LocalScreen.RightColumn - 2; + TopRowOfHelp = LocalScreen.BottomRow - 4; + BottomRowOfHelp = LocalScreen.BottomRow - 3; + + if (gClassOfVfr == EFI_GENERAL_APPLICATION_SUBCLASS) { + return ; + } + + gST->ConOut->SetAttribute (gST->ConOut, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + Statement = MenuOption->ThisTag; + switch (Statement->Operand) { + case EFI_IFR_ORDERED_LIST_OP: + case EFI_IFR_ONE_OF_OP: + case EFI_IFR_NUMERIC_OP: + case EFI_IFR_TIME_OP: + case EFI_IFR_DATE_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + if ((Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + PrintAt ( + StartColumnOfHelp, + BottomRowOfHelp, + L"%c%c%c%c%s", + ARROW_UP, + ARROW_DOWN, + ARROW_RIGHT, + ARROW_LEFT, + gMoveHighlight + ); + PrintStringAt (SecCol, BottomRowOfHelp, gAdjustNumber); + } else { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterCommitString); + + // + // If it is a selected numeric with manual input, display different message + // + if ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step == 0)) { + PrintStringAt ( + SecCol, + TopRowOfHelp, + ((Statement->Flags & EFI_IFR_DISPLAY_UINT_HEX) == EFI_IFR_DISPLAY_UINT_HEX) ? gHexNumericInput : gDecNumericInput + ); + } else if (Statement->Operand != EFI_IFR_ORDERED_LIST_OP) { + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + } + + if (Statement->Operand == EFI_IFR_ORDERED_LIST_OP) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gPlusString); + PrintStringAt (ThdCol, TopRowOfHelp, gMinusString); + } + + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + break; + + case EFI_IFR_CHECKBOX_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + PrintStringAt (SecCol, BottomRowOfHelp, gToggleCheckBox); + break; + + case EFI_IFR_REF_OP: + case EFI_IFR_PASSWORD_OP: + case EFI_IFR_STRING_OP: + case EFI_IFR_TEXT_OP: + case EFI_IFR_ACTION_OP: + case EFI_IFR_RESET_BUTTON_OP: + ClearLines (LeftColumnOfHelp, RightColumnOfHelp, TopRowOfHelp, BottomRowOfHelp, KEYHELP_TEXT | KEYHELP_BACKGROUND); + + if (!Selected) { + if (gClassOfVfr == EFI_SETUP_APPLICATION_SUBCLASS) { + PrintStringAt (StartColumnOfHelp, TopRowOfHelp, gFunctionOneString); + PrintStringAt (SecCol, TopRowOfHelp, gFunctionNineString); + PrintStringAt (ThdCol, TopRowOfHelp, gFunctionTenString); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + + PrintAt (StartColumnOfHelp, BottomRowOfHelp, L"%c%c%s", ARROW_UP, ARROW_DOWN, gMoveHighlight); + if (Statement->Operand != EFI_IFR_TEXT_OP) { + PrintStringAt (SecCol, BottomRowOfHelp, gEnterString); + } + } else { + if (Statement->Operand != EFI_IFR_REF_OP) { + PrintStringAt ( + (LocalScreen.RightColumn - GetStringWidth (gEnterCommitString) / 2) / 2, + BottomRowOfHelp, + gEnterCommitString + ); + PrintStringAt (ThdCol, BottomRowOfHelp, gEscapeString); + } + } + break; + + default: + break; + } +} + +/** + Functions which are registered to receive notification of + database events have this prototype. The actual event is encoded + in NotifyType. The following table describes how PackageType, + PackageGuid, Handle, and Package are used for each of the + notification types. + + @param PackageType Package type of the notification. + + @param PackageGuid If PackageType is + EFI_HII_PACKAGE_TYPE_GUID, then this is + the pointer to the GUID from the Guid + field of EFI_HII_PACKAGE_GUID_HEADER. + Otherwise, it must be NULL. + + @param Package Points to the package referred to by the + notification Handle The handle of the package + list which contains the specified package. + + @param Handle The HII handle. + + @param NotifyType The type of change concerning the + database. See + EFI_HII_DATABASE_NOTIFY_TYPE. + +**/ +EFI_STATUS +FormUpdateNotify ( + IN UINT8 PackageType, + IN CONST EFI_GUID *PackageGuid, + IN CONST EFI_HII_PACKAGE_HEADER *Package, + IN EFI_HII_HANDLE Handle, + IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType + ) +{ + mHiiPackageListUpdated = TRUE; + + return EFI_SUCCESS; +} + +/** + The worker function that send the displays to the screen. On output, + the selection made by user is returned. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @retval EFI_SUCCESS The page is displayed successfully. + @return Other value if the page failed to be diplayed. + +**/ +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_BROWSER_ACTION_REQUEST ActionRequest; + EFI_HANDLE NotifyHandle; + EFI_HII_VALUE *HiiValue; + FORM_BROWSER_STATEMENT *Statement; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + gMenuRefreshHead = NULL; + gResetRequired = FALSE; + gNvUpdateRequired = FALSE; + + UiInitMenuList (); + + // + // Register notify for Form package update + // + Status = mHiiDatabase->RegisterPackageNotify ( + mHiiDatabase, + EFI_HII_PACKAGE_FORM, + NULL, + FormUpdateNotify, + EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, + &NotifyHandle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + // + // Displays the Header and Footer borders + // + DisplayPageFrame (); + + // + // Initialize Selection->Form + // + if (Selection->FormId == 0) { + // + // Zero FormId indicates display the first Form in a FormSet + // + Link = GetFirstNode (&Selection->FormSet->FormListHead); + + Selection->Form = FORM_BROWSER_FORM_FROM_LINK (Link); + Selection->FormId = Selection->Form->FormId; + } else { + Selection->Form = IdToForm (Selection->FormSet, Selection->FormId); + } + + // + // Load Questions' Value for display + // + Status = LoadFormConfig (Selection->FormSet, Selection->Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Display form + // + Status = DisplayForm (Selection); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check Selected Statement (if press ESC, Selection->Statement will be NULL) + // + Statement = Selection->Statement; + if (Statement != NULL) { + if ((Statement->QuestionFlags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED) { + gResetRequired = TRUE; + } + + // + // Reset FormPackage update flag + // + mHiiPackageListUpdated = FALSE; + + if (((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) == EFI_IFR_FLAG_CALLBACK) && (Statement->Operand != EFI_IFR_PASSWORD_OP)) { + ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + + HiiValue = &Statement->HiiValue; + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Create String in HII database for Configuration Driver to retrieve + // + HiiValue->Value.string = NewString ((CHAR16 *) Statement->BufferValue, Selection->FormSet->HiiHandle); + } + + ConfigAccess = Selection->FormSet->ConfigAccess; + if (ConfigAccess == NULL) { + return EFI_UNSUPPORTED; + } + Status = ConfigAccess->Callback ( + ConfigAccess, + EFI_BROWSER_ACTION_CHANGING, + Statement->QuestionId, + HiiValue->Type, + &HiiValue->Value, + &ActionRequest + ); + + if (HiiValue->Type == EFI_IFR_TYPE_STRING) { + // + // Clean the String in HII Database + // + DeleteString (HiiValue->Value.string, Selection->FormSet->HiiHandle); + } + + if (!EFI_ERROR (Status)) { + switch (ActionRequest) { + case EFI_BROWSER_ACTION_REQUEST_RESET: + gResetRequired = TRUE; + break; + + case EFI_BROWSER_ACTION_REQUEST_SUBMIT: + SubmitForm (Selection->FormSet, Selection->Form); + break; + + case EFI_BROWSER_ACTION_REQUEST_EXIT: + Selection->Action = UI_ACTION_EXIT; + gNvUpdateRequired = FALSE; + break; + + default: + break; + } + } + } + + // + // Check whether Form Package has been updated during Callback + // + if (mHiiPackageListUpdated && (Selection->Action == UI_ACTION_REFRESH_FORM)) { + // + // Force to reparse IFR binary of target Formset + // + Selection->Action = UI_ACTION_REFRESH_FORMSET; + } + } + } while (Selection->Action == UI_ACTION_REFRESH_FORM); + + // + // Unregister notify for Form package update + // + Status = mHiiDatabase->UnregisterPackageNotify ( + mHiiDatabase, + NotifyHandle + ); + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c index 235ee45d2d..d8b42f8973 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Print.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.c @@ -1,326 +1,349 @@ -/** @file - -Copyright (c) 2004 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Print.c - -Abstract: - - Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very - simple implemenation of SPrint() and Print() to support debug. - - You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a - time. This makes the implementation very simple. - - VSPrint, Print, SPrint format specification has the follwoing form - - %type - - type: - 'S','s' - argument is an Unicode string - 'c' - argument is an ascii character - '%' - Print a % - - -**/ - -#include "Setup.h" - -UINTN -ValueToString ( - IN OUT CHAR16 *Buffer, - IN BOOLEAN Flags, - IN INT64 Value - ); - -UINTN -PrintInternal ( - IN UINTN Column, - IN UINTN Row, - IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, - IN CHAR16 *fmt, - IN VA_LIST args - ) -// -// Display string worker for: Print, PrintAt, IPrint, IPrintAt -// -{ - CHAR16 *Buffer; - CHAR16 *BackupBuffer; - UINTN Index; - UINTN PreviousIndex; - - // - // For now, allocate an arbitrarily long buffer - // - Buffer = AllocateZeroPool (0x10000); - BackupBuffer = AllocateZeroPool (0x10000); - ASSERT (Buffer); - ASSERT (BackupBuffer); - - if (Column != (UINTN) -1) { - Out->SetCursorPosition (Out, Column, Row); - } - - UnicodeVSPrint (Buffer, 0x10000, fmt, args); - - Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; - - Out->SetAttribute (Out, Out->Mode->Attribute); - - Index = 0; - PreviousIndex = 0; - - do { - for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { - BackupBuffer[Index] = Buffer[Index]; - } - - if (Buffer[Index] == 0) { - break; - } - // - // Null-terminate the temporary string - // - BackupBuffer[Index] = 0; - - // - // Print this out, we are about to switch widths - // - Out->OutputString (Out, &BackupBuffer[PreviousIndex]); - - // - // Preserve the current index + 1, since this is where we will start printing from next - // - PreviousIndex = Index + 1; - - // - // We are at a narrow or wide character directive. Set attributes and strip it and print it - // - if (Buffer[Index] == NARROW_CHAR) { - // - // Preserve bits 0 - 6 and zero out the rest - // - Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; - Out->SetAttribute (Out, Out->Mode->Attribute); - } else { - // - // Must be wide, set bit 7 ON - // - Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; - Out->SetAttribute (Out, Out->Mode->Attribute); - } - - Index++; - - } while (Buffer[Index] != 0); - - // - // We hit the end of the string - print it - // - Out->OutputString (Out, &BackupBuffer[PreviousIndex]); - - gBS->FreePool (Buffer); - gBS->FreePool (BackupBuffer); - return EFI_SUCCESS; -} - - -/** - Prints a formatted unicode string to the default console - - @param fmt Format string - - @return Length of string printed to the console - -**/ -UINTN -ConsolePrint ( - IN CHAR16 *fmt, - ... - ) -{ - VA_LIST args; - - VA_START (args, fmt); - return PrintInternal ((UINTN) -1, (UINTN) -1, gST->ConOut, fmt, args); -} - - -/** - Prints a unicode string to the default console, - using L"%s" format. - - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintString ( - CHAR16 *String - ) -{ - return ConsolePrint (L"%s", String); -} - - -/** - Prints a chracter to the default console, - using L"%c" format. - - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintChar ( - CHAR16 Character - ) -{ - return ConsolePrint (L"%c", Character); -} - - -/** - Prints a formatted unicode string to the default console, at - the supplied cursor position - - @param Row The cursor position to print the string at - @param fmt Format string - - @return Length of string printed to the console - -**/ -UINTN -PrintAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *fmt, - ... - ) -{ - VA_LIST args; - - VA_START (args, fmt); - return PrintInternal (Column, Row, gST->ConOut, fmt, args); -} - - -/** - Prints a unicode string to the default console, at - the supplied cursor position, using L"%s" format. - - @param Row The cursor position to print the string at - @param String String pointer. - - @return Length of string printed to the console - -**/ -UINTN -PrintStringAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 *String - ) -{ - return PrintAt (Column, Row, L"%s", String); -} - - -/** - Prints a chracter to the default console, at - the supplied cursor position, using L"%c" format. - - @param Row The cursor position to print the string at - @param Character Character to print. - - @return Length of string printed to the console. - -**/ -UINTN -PrintCharAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 Character - ) -{ - return PrintAt (Column, Row, L"%c", Character); -} - - -/** - VSPrint worker function that prints a Value as a decimal number in Buffer - - @param Buffer Location to place ascii decimal number string of Value. - @param Value Decimal value to convert to a string in Buffer. - @param Flags Flags to use in printing decimal string, see file header for - details. - - @return Number of characters printed. - -**/ -UINTN -ValueToString ( - IN OUT CHAR16 *Buffer, - IN BOOLEAN Flags, - IN INT64 Value - ) -{ - CHAR16 TempBuffer[30]; - CHAR16 *TempStr; - CHAR16 *BufferPtr; - UINTN Count; - UINTN NumberCount; - UINT32 Remainder; - BOOLEAN Negative; - - Negative = FALSE; - TempStr = TempBuffer; - BufferPtr = Buffer; - Count = 0; - NumberCount = 0; - - if (Value < 0) { - Negative = TRUE; - Value = -Value; - } - - do { - Value = (INT64) DivU64x32Remainder ((UINT64) Value, 10, &Remainder); - *(TempStr++) = (CHAR16) (Remainder + '0'); - Count++; - NumberCount++; - if ((Flags & COMMA_TYPE) == COMMA_TYPE) { - if (NumberCount % 3 == 0 && Value != 0) { - *(TempStr++) = ','; - Count++; - } - } - } while (Value != 0); - - if (Negative) { - *(BufferPtr++) = '-'; - Count++; - } - - // - // Reverse temp string into Buffer. - // - while (TempStr != TempBuffer) { - *(BufferPtr++) = *(--TempStr); - } - - *BufferPtr = 0; - return Count; -} +/** @file +Basic Ascii AvSPrintf() function named VSPrint(). VSPrint() enables very +simple implemenation of SPrint() and Print() to support debug. + +You can not Print more than EFI_DRIVER_LIB_MAX_PRINT_BUFFER characters at a +time. This makes the implementation very simple. + +VSPrint, Print, SPrint format specification has the follwoing form + +%type + +type: + 'S','s' - argument is an Unicode string + 'c' - argument is an ascii character + '%' - Print a % + + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Setup.h" + +/** + VSPrint worker function that prints a Value as a decimal number in Buffer. + + @param Buffer Location to place ascii decimal number string of Value. + @param Flags Flags to use in printing decimal string, see file header for + details. + @param Value Decimal value to convert to a string in Buffer. + + @return Number of characters printed. + +**/ +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ); + +/** + The internal function prints to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL + protocol instance. + + @param Column The position of the output string. + @param Row The position of the output string. + @param Out The EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance. + @param Fmt The format string. + @param Args The additional argument for the variables in the format string. + + @return Number of Unicode character printed. + +**/ +UINTN +PrintInternal ( + IN UINTN Column, + IN UINTN Row, + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Out, + IN CHAR16 *Fmt, + IN VA_LIST Args + ) +{ + CHAR16 *Buffer; + CHAR16 *BackupBuffer; + UINTN Index; + UINTN PreviousIndex; + UINTN Count; + + // + // For now, allocate an arbitrarily long buffer + // + Buffer = AllocateZeroPool (0x10000); + BackupBuffer = AllocateZeroPool (0x10000); + ASSERT (Buffer); + ASSERT (BackupBuffer); + + if (Column != (UINTN) -1) { + Out->SetCursorPosition (Out, Column, Row); + } + + UnicodeVSPrint (Buffer, 0x10000, Fmt, Args); + + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + + Out->SetAttribute (Out, Out->Mode->Attribute); + + Index = 0; + PreviousIndex = 0; + Count = 0; + + do { + for (; (Buffer[Index] != NARROW_CHAR) && (Buffer[Index] != WIDE_CHAR) && (Buffer[Index] != 0); Index++) { + BackupBuffer[Index] = Buffer[Index]; + } + + if (Buffer[Index] == 0) { + break; + } + // + // Null-terminate the temporary string + // + BackupBuffer[Index] = 0; + + // + // Print this out, we are about to switch widths + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + Count += StrLen (&BackupBuffer[PreviousIndex]); + + // + // Preserve the current index + 1, since this is where we will start printing from next + // + PreviousIndex = Index + 1; + + // + // We are at a narrow or wide character directive. Set attributes and strip it and print it + // + if (Buffer[Index] == NARROW_CHAR) { + // + // Preserve bits 0 - 6 and zero out the rest + // + Out->Mode->Attribute = Out->Mode->Attribute & 0x7f; + Out->SetAttribute (Out, Out->Mode->Attribute); + } else { + // + // Must be wide, set bit 7 ON + // + Out->Mode->Attribute = Out->Mode->Attribute | EFI_WIDE_ATTRIBUTE; + Out->SetAttribute (Out, Out->Mode->Attribute); + } + + Index++; + + } while (Buffer[Index] != 0); + + // + // We hit the end of the string - print it + // + Out->OutputString (Out, &BackupBuffer[PreviousIndex]); + Count += StrLen (&BackupBuffer[PreviousIndex]); + + gBS->FreePool (Buffer); + gBS->FreePool (BackupBuffer); + return Count; +} + + +/** + Prints a formatted unicode string to the default console. + + @param Fmt Format string + @param ... Variable argument list for format string. + + @return Length of string printed to the console. + +**/ +UINTN +ConsolePrint ( + IN CHAR16 *Fmt, + IN ... + ) +{ + VA_LIST Args; + + VA_START (Args, Fmt); + return PrintInternal ((UINTN) -1, (UINTN) -1, gST->ConOut, Fmt, Args); +} + + +/** + Prints a unicode string to the default console, + using L"%s" format. + + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintString ( + IN CHAR16 *String + ) +{ + return ConsolePrint (L"%s", String); +} + + +/** + Prints a chracter to the default console, + using L"%c" format. + + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintChar ( + CHAR16 Character + ) +{ + return ConsolePrint (L"%c", Character); +} + + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Fmt Format string. + @param ... Variable argument list for format string. + + @return Length of string printed to the console + +**/ +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *Fmt, + ... + ) +{ + VA_LIST Args; + + VA_START (Args, Fmt); + return PrintInternal (Column, Row, gST->ConOut, Fmt, Args); +} + + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 *String + ) +{ + return PrintAt (Column, Row, L"%s", String); +} + + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +{ + return PrintAt (Column, Row, L"%c", Character); +} + + +/** + VSPrint worker function that prints a Value as a decimal number in Buffer. + + @param Buffer Location to place ascii decimal number string of Value. + @param Flags Flags to use in printing decimal string, see file header for + details. + @param Value Decimal value to convert to a string in Buffer. + + @return Number of characters printed. + +**/ +UINTN +ValueToString ( + IN OUT CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ) +{ + CHAR16 TempBuffer[30]; + CHAR16 *TempStr; + CHAR16 *BufferPtr; + UINTN Count; + UINTN NumberCount; + UINT32 Remainder; + BOOLEAN Negative; + + Negative = FALSE; + TempStr = TempBuffer; + BufferPtr = Buffer; + Count = 0; + NumberCount = 0; + + if (Value < 0) { + Negative = TRUE; + Value = -Value; + } + + do { + Value = (INT64) DivU64x32Remainder ((UINT64) Value, 10, &Remainder); + *(TempStr++) = (CHAR16) (Remainder + '0'); + Count++; + NumberCount++; + if ((Flags & COMMA_TYPE) == COMMA_TYPE) { + if (NumberCount % 3 == 0 && Value != 0) { + *(TempStr++) = ','; + Count++; + } + } + } while (Value != 0); + + if (Negative) { + *(BufferPtr++) = '-'; + Count++; + } + + // + // Reverse temp string into Buffer. + // + while (TempStr != TempBuffer) { + *(BufferPtr++) = *(--TempStr); + } + + *BufferPtr = 0; + return Count; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Print.h b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h index c473a26cfa..b75e0ffbc5 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Print.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Print.h @@ -1,4 +1,5 @@ /** @file +Micro definitions data for Print.c Copyright (c) 2004, Intel Corporation All rights reserved. This program and the accompanying materials @@ -9,15 +10,6 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - Print.h - -Abstract: - - Private data for Print.c - - **/ #ifndef _PRINT_H_ diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c index ac9eeda777..3e2cd180f6 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c @@ -1,4 +1,6 @@ /** @file +Implementation for handling the User Interface option processing. + Copyright (c) 2004 - 2007, Intel Corporation All rights reserved. This program and the accompanying materials @@ -9,17 +11,6 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - ProcessOptions.c - -Abstract: - - Implementation for handling the User Interface option processing. - -Revision History - - **/ #include "Ui.h" @@ -113,7 +104,7 @@ ValueToOption ( /** Print Question Value according to it's storage width and display attributes. - @param Event The event to wait for + @param Question The Question to be printed. @param FormattedNumber Buffer for output string. @param BufferSize The FormattedNumber buffer size in bytes. @@ -265,10 +256,6 @@ PasswordCallback ( /** Display error message for invalid password. - None. - - @return None. - **/ VOID PasswordInvalid ( @@ -624,7 +611,7 @@ ProcessOptions ( // // For interactive passwords, old password is validated by callback // - if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { // // Use a NULL password to test whether old password is required // @@ -707,7 +694,7 @@ ProcessOptions ( // // Reset state machine for interactive password // - if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } @@ -725,7 +712,7 @@ ProcessOptions ( // // Reset state machine for interactive password // - if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } @@ -741,7 +728,7 @@ ProcessOptions ( // // Two password match, send it to Configuration Driver // - if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, StringPtr); } else { CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16)); @@ -751,7 +738,7 @@ ProcessOptions ( // // Reset state machine for interactive password // - if (Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) { + if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { PasswordCallback (Selection, MenuOption, NULL); } @@ -781,11 +768,8 @@ ProcessOptions ( FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. @param StringPtr The entire help string. - @param MenuOption The MenuOption for this Question. + @param FormattedString The oupput formatted string. @param RowCount TRUE: if Question is selected. - @param OptionString Pointer of the Option String to be displayed. - - @return None. **/ VOID diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c index ff857750ef..40c2544bdd 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.c @@ -1,2312 +1,2302 @@ -/** @file -Copyright (c) 2007 - 2008, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Setup.c - -Abstract: - - Entry and initialization module for the browser. - - -**/ - -#include "Setup.h" -#include "Ui.h" - - -SETUP_DRIVER_PRIVATE_DATA mPrivateData = { - SETUP_DRIVER_SIGNATURE, - NULL, - { - SendForm, - BrowserCallback - }, - { - UnicodeVSPrint - } -}; - -EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; -EFI_HII_STRING_PROTOCOL *mHiiString; -EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; - -BANNER_DATA *BannerData; -EFI_HII_HANDLE FrontPageHandle; -UINTN gClassOfVfr; -UINTN gFunctionKeySetting; -BOOLEAN gResetRequired; -BOOLEAN gNvUpdateRequired; -EFI_HII_HANDLE gHiiHandle; -BOOLEAN gFirstIn; -UINT16 gDirection; -EFI_SCREEN_DESCRIPTOR gScreenDimensions; -BOOLEAN gUpArrow; -BOOLEAN gDownArrow; - -// -// Browser Global Strings -// -CHAR16 *gFunctionOneString; -CHAR16 *gFunctionTwoString; -CHAR16 *gFunctionNineString; -CHAR16 *gFunctionTenString; -CHAR16 *gEnterString; -CHAR16 *gEnterCommitString; -CHAR16 *gEscapeString; -CHAR16 *gSaveFailed; -CHAR16 *gMoveHighlight; -CHAR16 *gMakeSelection; -CHAR16 *gDecNumericInput; -CHAR16 *gHexNumericInput; -CHAR16 *gToggleCheckBox; -CHAR16 *gPromptForData; -CHAR16 *gPromptForPassword; -CHAR16 *gPromptForNewPassword; -CHAR16 *gConfirmPassword; -CHAR16 *gConfirmError; -CHAR16 *gPassowordInvalid; -CHAR16 *gPressEnter; -CHAR16 *gEmptyString; -CHAR16 *gAreYouSure; -CHAR16 *gYesResponse; -CHAR16 *gNoResponse; -CHAR16 *gMiniString; -CHAR16 *gPlusString; -CHAR16 *gMinusString; -CHAR16 *gAdjustNumber; - -CHAR16 gPromptBlockWidth; -CHAR16 gOptionBlockWidth; -CHAR16 gHelpBlockWidth; - -EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; -EFI_GUID gSetupBrowserGuid = { - 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32} -}; - -FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { - // - // Boot Manager - // - { - { - 0x847bc3fe, - 0xb974, - 0x446d, - { - 0x94, - 0x49, - 0x5a, - 0xd5, - 0x41, - 0x2e, - 0x99, - 0x3b - } - }, - NONE_FUNCTION_KEY_SETTING - }, - // - // Device Manager - // - { - { - 0x3ebfa8e6, - 0x511d, - 0x4b5b, - { - 0xa9, - 0x5f, - 0xfb, - 0x38, - 0x26, - 0xf, - 0x1c, - 0x27 - } - }, - NONE_FUNCTION_KEY_SETTING - }, - // - // BMM FormSet. - // - { - { - 0x642237c7, - 0x35d4, - 0x472d, - { - 0x83, - 0x65, - 0x12, - 0xe0, - 0xcc, - 0xf2, - 0x7a, - 0x22 - } - }, - NONE_FUNCTION_KEY_SETTING - }, - // - // BMM File Explorer FormSet. - // - { - { - 0x1f2d63e1, - 0xfebd, - 0x4dc7, - { - 0x9c, - 0xc5, - 0xba, - 0x2b, - 0x1c, - 0xef, - 0x9c, - 0x5b - } - }, - NONE_FUNCTION_KEY_SETTING - }, -}; - -EFI_STATUS -EFIAPI -SendForm ( - IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, - IN EFI_HII_HANDLE *Handles, - IN UINTN HandleCount, - IN EFI_GUID *FormSetGuid, OPTIONAL - IN UINT16 FormId, OPTIONAL - IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL - OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL - ) -/*++ - -Routine Description: - This is the routine which an external caller uses to direct the browser - where to obtain it's information. - -Arguments: - This - The Form Browser protocol instanse. - Handles - A pointer to an array of Handles. If HandleCount > 1 we - display a list of the formsets for the handles specified. - HandleCount - The number of Handles specified in Handle. - FormSetGuid - This field points to the EFI_GUID which must match the Guid - field in the EFI_IFR_FORM_SET op-code for the specified - forms-based package. If FormSetGuid is NULL, then this - function will display the first found forms package. - FormId - This field specifies which EFI_IFR_FORM to render as the first - displayable page. If this field has a value of 0x0000, then - the forms browser will render the specified forms in their encoded order. - ScreenDimenions - This allows the browser to be called so that it occupies a - portion of the physical screen instead of dynamically determining the screen dimensions. - ActionRequest - Points to the action recommended by the form. - -Returns: - EFI_SUCCESS - The function completed successfully. - EFI_INVALID_PARAMETER - One of the parameters has an invalid value. - EFI_NOT_FOUND - No valid forms could be found to display. - ---*/ -{ - EFI_STATUS Status; - UI_MENU_SELECTION *Selection; - UINTN Index; - FORM_BROWSER_FORMSET *FormSet; - - Status = EFI_SUCCESS; - ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - // - // Seed the dimensions in the global - // - gST->ConOut->QueryMode ( - gST->ConOut, - gST->ConOut->Mode->Mode, - &gScreenDimensions.RightColumn, - &gScreenDimensions.BottomRow - ); - - if (ScreenDimensions != NULL) { - // - // Check local dimension vs. global dimension. - // - if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || - (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) - ) { - return EFI_INVALID_PARAMETER; - } else { - // - // Local dimension validation. - // - if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && - (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && - ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && - ( - (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + - SCROLL_ARROW_HEIGHT * - 2 + - FRONT_PAGE_HEADER_HEIGHT + - FOOTER_HEIGHT + - 1 - ) - ) { - CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - } else { - return EFI_INVALID_PARAMETER; - } - } - } - - gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); - gHelpBlockWidth = gOptionBlockWidth; - gPromptBlockWidth = gOptionBlockWidth; - - // - // Initialize the strings for the browser, upon exit of the browser, the strings will be freed - // - InitializeBrowserStrings (); - - gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; - gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; - - // - // Ensure we are in Text mode - // - if (gFirstIn) { - gFirstIn = FALSE; - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - DisableQuietBoot (); - } - - for (Index = 0; Index < HandleCount; Index++) { - Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); - ASSERT (Selection != NULL); - - Selection->Handle = Handles[Index]; - if (FormSetGuid != NULL) { - CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); - Selection->FormId = FormId; - } - - do { - FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); - ASSERT (FormSet != NULL); - - // - // Initialize internal data structures of FormSet - // - Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); - if (EFI_ERROR (Status)) { - DestroyFormSet (FormSet); - break; - } - Selection->FormSet = FormSet; - - // - // Initialize current settings of Questions in this FormSet - // - Status = InitializeCurrentSetting (FormSet); - if (EFI_ERROR (Status)) { - DestroyFormSet (FormSet); - break; - } - - // - // Display this formset - // - gCurrentSelection = Selection; - - Status = SetupBrowser (Selection); - - gCurrentSelection = NULL; - DestroyFormSet (FormSet); - - if (EFI_ERROR (Status)) { - break; - } - - } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); - - gBS->FreePool (Selection); - } - - if (ActionRequest != NULL) { - *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; - if (gResetRequired) { - *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; - } - } - - FreeBrowserStrings (); - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->ClearScreen (gST->ConOut); - - return Status; -} - - -/** - This function is called by a callback handler to retrieve uncommitted state - data from the browser. - - @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL - instance. - @param ResultsDataSize A pointer to the size of the buffer associated - with ResultsData. - @param ResultsData A string returned from an IFR browser or - equivalent. The results string will have no - routing information in them. - @param RetrieveData A BOOLEAN field which allows an agent to retrieve - (if RetrieveData = TRUE) data from the uncommitted - browser state information or set (if RetrieveData - = FALSE) data in the uncommitted browser state - information. - @param VariableGuid An optional field to indicate the target variable - GUID name to use. - @param VariableName An optional field to indicate the target - human-readable variable name. - - @retval EFI_SUCCESS The results have been distributed or are awaiting - distribution. - @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to - contain the results data. - -**/ -EFI_STATUS -EFIAPI -BrowserCallback ( - IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, - IN OUT UINTN *ResultsDataSize, - IN OUT EFI_STRING ResultsData, - IN BOOLEAN RetrieveData, - IN CONST EFI_GUID *VariableGuid, OPTIONAL - IN CONST CHAR16 *VariableName OPTIONAL - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - FORMSET_STORAGE *Storage; - FORM_BROWSER_FORMSET *FormSet; - BOOLEAN Found; - CHAR16 *ConfigResp; - CHAR16 *StrPtr; - UINTN BufferSize; - UINTN TmpSize; - - if (ResultsDataSize == NULL || ResultsData == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (gCurrentSelection == NULL) { - return EFI_NOT_READY; - } - - Storage = NULL; - ConfigResp = NULL; - FormSet = gCurrentSelection->FormSet; - - // - // Find target storage - // - Link = GetFirstNode (&FormSet->StorageListHead); - if (IsNull (&FormSet->StorageListHead, Link)) { - return EFI_UNSUPPORTED; - } - - if (VariableGuid != NULL) { - // - // Try to find target storage - // - Found = FALSE; - while (!IsNull (&FormSet->StorageListHead, Link)) { - Storage = FORMSET_STORAGE_FROM_LINK (Link); - Link = GetNextNode (&FormSet->StorageListHead, Link); - - if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { - if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { - // - // Buffer storage require both GUID and Name - // - if (VariableName == NULL) { - return EFI_NOT_FOUND; - } - - if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { - continue; - } - } - Found = TRUE; - break; - } - } - - if (!Found) { - return EFI_NOT_FOUND; - } - } else { - // - // GUID/Name is not specified, take the first storage in FormSet - // - Storage = FORMSET_STORAGE_FROM_LINK (Link); - } - - if (RetrieveData) { - // - // Skip if there is no RequestElement - // - if (Storage->ElementCount == 0) { - return EFI_SUCCESS; - } - - // - // Generate - // - Status = StorageToConfigResp (Storage, &ConfigResp); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Skip and '&' to point to - // - StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; - - BufferSize = StrSize (StrPtr); - if (*ResultsDataSize < BufferSize) { - *ResultsDataSize = BufferSize; - - gBS->FreePool (ConfigResp); - return EFI_BUFFER_TOO_SMALL; - } - - *ResultsDataSize = BufferSize; - CopyMem (ResultsData, StrPtr, BufferSize); - - gBS->FreePool (ConfigResp); - } else { - // - // Prepare - // - TmpSize = StrLen (ResultsData); - BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); - ConfigResp = AllocateZeroPool (BufferSize); - ASSERT (ConfigResp != NULL); - - StrCpy (ConfigResp, Storage->ConfigHdr); - StrCat (ConfigResp, L"&"); - StrCat (ConfigResp, ResultsData); - - // - // Update Browser uncommited data - // - Status = ConfigRespToStorage (Storage, ConfigResp); - if (EFI_ERROR (Status)) { - return Status; - } - } - - return EFI_SUCCESS; -} - - -/** - Initialize Setup - - @param entry EFI_IMAGE_ENTRY_POINT) - - @retval EFI_SUCCESS Setup loaded. - @retval other Setup Error - -**/ -EFI_STATUS -EFIAPI -InitializeSetup ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - EFI_HANDLE HiiDriverHandle; - EFI_HII_PACKAGE_LIST_HEADER *PackageList; - - // - // Locate required Hii relative protocols - // - Status = gBS->LocateProtocol ( - &gEfiHiiDatabaseProtocolGuid, - NULL, - (VOID **) &mHiiDatabase - ); - ASSERT_EFI_ERROR (Status); - - Status = gBS->LocateProtocol ( - &gEfiHiiStringProtocolGuid, - NULL, - (VOID **) &mHiiString - ); - ASSERT_EFI_ERROR (Status); - - Status = gBS->LocateProtocol ( - &gEfiHiiConfigRoutingProtocolGuid, - NULL, - (VOID **) &mHiiConfigRouting - ); - ASSERT_EFI_ERROR (Status); - - // - // Publish our HII data - // - Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle); - ASSERT_EFI_ERROR (Status); - - PackageList = HiiLibPreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings); - ASSERT (PackageList != NULL); - Status = mHiiDatabase->NewPackageList ( - mHiiDatabase, - PackageList, - HiiDriverHandle, - &gHiiHandle - ); - ASSERT_EFI_ERROR (Status); - - // - // Initialize Driver private data - // - gFirstIn = TRUE; - BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); - ASSERT (BannerData != NULL); - - // - // Install FormBrowser2 protocol - // - mPrivateData.Handle = NULL; - Status = gBS->InstallProtocolInterface ( - &mPrivateData.Handle, - &gEfiFormBrowser2ProtocolGuid, - EFI_NATIVE_INTERFACE, - &mPrivateData.FormBrowser2 - ); - ASSERT_EFI_ERROR (Status); - - // - // Install Print protocol - // - Status = gBS->InstallProtocolInterface ( - &mPrivateData.Handle, - &gEfiPrintProtocolGuid, - EFI_NATIVE_INTERFACE, - &mPrivateData.Print - ); - - return Status; -} - - -/** - Create a new string in HII Package List. - - @param String The String to be added - @param HiiHandle The package list in the HII database to insert the - specified string. - - @return The output string. - -**/ -EFI_STRING_ID -NewString ( - IN CHAR16 *String, - IN EFI_HII_HANDLE HiiHandle - ) -{ - EFI_STRING_ID StringId; - EFI_STATUS Status; - - StringId = 0; - Status = HiiLibNewString (HiiHandle, &StringId, String); - ASSERT_EFI_ERROR (Status); - - return StringId; -} - - -/** - Delete a string from HII Package List. - - @param StringId Id of the string in HII database. - @param HiiHandle The HII package list handle. - - @retval EFI_SUCCESS The string was deleted successfully. - -**/ -EFI_STATUS -DeleteString ( - IN EFI_STRING_ID StringId, - IN EFI_HII_HANDLE HiiHandle - ) -{ - CHAR16 NullChar; - - NullChar = CHAR_NULL; - return HiiLibSetString (HiiHandle, StringId, &NullChar); -} - - -/** - Get the string based on the StringId and HII Package List Handle. - - @param Token The String's ID. - @param HiiHandle The package list in the HII database to search for - the specified string. - - @return The output string. - -**/ -CHAR16 * -GetToken ( - IN EFI_STRING_ID Token, - IN EFI_HII_HANDLE HiiHandle - ) -{ - EFI_STATUS Status; - CHAR16 *String; - UINTN BufferLength; - - // - // Set default string size assumption at no more than 256 bytes - // - BufferLength = 0x100; - String = AllocateZeroPool (BufferLength); - ASSERT (String != NULL); - - Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength); - - if (Status == EFI_BUFFER_TOO_SMALL) { - gBS->FreePool (String); - String = AllocateZeroPool (BufferLength); - ASSERT (String != NULL); - - Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength); - } - ASSERT_EFI_ERROR (Status); - - return String; -} - - -/** - Allocate new memory and then copy the Unicode string Source to Destination. - - @param Dest Location to copy string - @param Src String to copy - - @return NONE - -**/ -VOID -NewStringCpy ( - IN OUT CHAR16 **Dest, - IN CHAR16 *Src - ) -{ - SafeFreePool (*Dest); - *Dest = AllocateCopyPool (StrSize (Src), Src); - ASSERT (*Dest != NULL); -} - - -/** - Allocate new memory and concatinate Source on the end of Destination. - - @param Dest String to added to the end of. - @param Src String to concatinate. - - @return NONE - -**/ -VOID -NewStringCat ( - IN OUT CHAR16 **Dest, - IN CHAR16 *Src - ) -{ - CHAR16 *NewString; - UINTN TmpSize; - - if (*Dest == NULL) { - NewStringCpy (Dest, Src); - return; - } - - TmpSize = StrSize (*Dest); - NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1); - ASSERT (NewString != NULL); - - StrCpy (NewString, *Dest); - StrCat (NewString, Src); - - gBS->FreePool (*Dest); - *Dest = NewString; -} - - -/** - Synchronize Storage's Edit copy to Shadow copy. - - @param Storage The Storage to be synchronized. - - @return NONE - -**/ -VOID -SynchronizeStorage ( - IN FORMSET_STORAGE *Storage - ) -{ - LIST_ENTRY *Link; - NAME_VALUE_NODE *Node; - - switch (Storage->Type) { - case EFI_HII_VARSTORE_BUFFER: - CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); - break; - - case EFI_HII_VARSTORE_NAME_VALUE: - Link = GetFirstNode (&Storage->NameValueListHead); - while (!IsNull (&Storage->NameValueListHead, Link)) { - Node = NAME_VALUE_NODE_FROM_LINK (Link); - - NewStringCpy (&Node->Value, Node->EditValue); - - Link = GetNextNode (&Storage->NameValueListHead, Link); - } - break; - - case EFI_HII_VARSTORE_EFI_VARIABLE: - default: - break; - } -} - - -/** - Get Value for given Name from a NameValue Storage. - - @param Storage The NameValue Storage. - @param Name The Name. - @param Value The retured Value. - - @retval EFI_SUCCESS Value found for given Name. - @retval EFI_NOT_FOUND No such Name found in NameValue storage. - -**/ -EFI_STATUS -GetValueByName ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 *Name, - IN OUT CHAR16 **Value - ) -{ - LIST_ENTRY *Link; - NAME_VALUE_NODE *Node; - - *Value = NULL; - - Link = GetFirstNode (&Storage->NameValueListHead); - while (!IsNull (&Storage->NameValueListHead, Link)) { - Node = NAME_VALUE_NODE_FROM_LINK (Link); - - if (StrCmp (Name, Node->Name) == 0) { - NewStringCpy (Value, Node->EditValue); - return EFI_SUCCESS; - } - - Link = GetNextNode (&Storage->NameValueListHead, Link); - } - - return EFI_NOT_FOUND; -} - - -/** - Set Value of given Name in a NameValue Storage. - - @param Storage The NameValue Storage. - @param Name The Name. - @param Value The Value to set. - - @retval EFI_SUCCESS Value found for given Name. - @retval EFI_NOT_FOUND No such Name found in NameValue storage. - -**/ -EFI_STATUS -SetValueByName ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 *Name, - IN CHAR16 *Value - ) -{ - LIST_ENTRY *Link; - NAME_VALUE_NODE *Node; - - Link = GetFirstNode (&Storage->NameValueListHead); - while (!IsNull (&Storage->NameValueListHead, Link)) { - Node = NAME_VALUE_NODE_FROM_LINK (Link); - - if (StrCmp (Name, Node->Name) == 0) { - SafeFreePool (Node->EditValue); - Node->EditValue = AllocateCopyPool (StrSize (Value), Value); - ASSERT (Node->EditValue != NULL); - return EFI_SUCCESS; - } - - Link = GetNextNode (&Storage->NameValueListHead, Link); - } - - return EFI_NOT_FOUND; -} - - -/** - Convert setting of Buffer Storage or NameValue Storage to . - - @param Storage The Storage to be conveted. - @param ConfigResp The returned . - - @retval EFI_SUCCESS Convert success. - @retval EFI_INVALID_PARAMETER Incorrect storage type. - -**/ -EFI_STATUS -StorageToConfigResp ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 **ConfigResp - ) -{ - EFI_STATUS Status; - EFI_STRING Progress; - LIST_ENTRY *Link; - NAME_VALUE_NODE *Node; - - Status = EFI_SUCCESS; - - switch (Storage->Type) { - case EFI_HII_VARSTORE_BUFFER: - Status = mHiiConfigRouting->BlockToConfig ( - mHiiConfigRouting, - Storage->ConfigRequest, - Storage->EditBuffer, - Storage->Size, - ConfigResp, - &Progress - ); - break; - - case EFI_HII_VARSTORE_NAME_VALUE: - *ConfigResp = NULL; - NewStringCat (ConfigResp, Storage->ConfigHdr); - - Link = GetFirstNode (&Storage->NameValueListHead); - while (!IsNull (&Storage->NameValueListHead, Link)) { - Node = NAME_VALUE_NODE_FROM_LINK (Link); - - NewStringCat (ConfigResp, L"&"); - NewStringCat (ConfigResp, Node->Name); - NewStringCat (ConfigResp, L"="); - NewStringCat (ConfigResp, Node->EditValue); - - Link = GetNextNode (&Storage->NameValueListHead, Link); - } - break; - - case EFI_HII_VARSTORE_EFI_VARIABLE: - default: - Status = EFI_INVALID_PARAMETER; - break; - } - - return Status; -} - - -/** - Convert to settings in Buffer Storage or NameValue Storage. - - @param Storage The Storage to receive the settings. - @param ConfigResp The to be converted. - - @retval EFI_SUCCESS Convert success. - @retval EFI_INVALID_PARAMETER Incorrect storage type. - -**/ -EFI_STATUS -ConfigRespToStorage ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 *ConfigResp - ) -{ - EFI_STATUS Status; - EFI_STRING Progress; - UINTN BufferSize; - CHAR16 *StrPtr; - CHAR16 *Name; - CHAR16 *Value; - - Status = EFI_SUCCESS; - - switch (Storage->Type) { - case EFI_HII_VARSTORE_BUFFER: - BufferSize = Storage->Size; - Status = mHiiConfigRouting->ConfigToBlock ( - mHiiConfigRouting, - ConfigResp, - Storage->EditBuffer, - &BufferSize, - &Progress - ); - break; - - case EFI_HII_VARSTORE_NAME_VALUE: - StrPtr = StrStr (ConfigResp, L"&"); - while (StrPtr != NULL) { - // - // Skip '&' - // - StrPtr = StrPtr + 1; - Name = StrPtr; - StrPtr = StrStr (StrPtr, L"="); - if (StrPtr == NULL) { - break; - } - *StrPtr = 0; - - // - // Skip '=' - // - StrPtr = StrPtr + 1; - Value = StrPtr; - StrPtr = StrStr (StrPtr, L"&"); - if (StrPtr != NULL) { - *StrPtr = 0; - } - SetValueByName (Storage, Name, Value); - } - break; - - case EFI_HII_VARSTORE_EFI_VARIABLE: - default: - Status = EFI_INVALID_PARAMETER; - break; - } - - return Status; -} - - -/** - Get Question's current Value. - - @param FormSet FormSet data structure. - @param Form Form data structure. - @param Question Question to be initialized. - @param Cached TRUE: get from Edit copy FALSE: get from original - Storage - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -GetQuestionValue ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_BROWSER_STATEMENT *Question, - IN BOOLEAN Cached - ) -{ - EFI_STATUS Status; - BOOLEAN Enabled; - BOOLEAN Pending; - UINT8 *Dst; - UINTN StorageWidth; - EFI_TIME EfiTime; - FORMSET_STORAGE *Storage; - EFI_IFR_TYPE_VALUE *QuestionValue; - CHAR16 *ConfigRequest; - CHAR16 *Progress; - CHAR16 *Result; - CHAR16 *Value; - UINTN Length; - BOOLEAN IsBufferStorage; - BOOLEAN IsString; - - Status = EFI_SUCCESS; - - // - // Statement don't have storage, skip them - // - if (Question->QuestionId == 0) { - return Status; - } - - // - // Question value is provided by an Expression, evaluate it - // - if (Question->ValueExpression != NULL) { - Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); - if (!EFI_ERROR (Status)) { - CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE)); - } - return Status; - } - - // - // Question value is provided by RTC - // - Storage = Question->Storage; - QuestionValue = &Question->HiiValue.Value; - if (Storage == NULL) { - // - // It's a Question without storage, or RTC date/time - // - if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { - // - // Date and time define the same Flags bit - // - switch (Question->Flags & EFI_QF_DATE_STORAGE) { - case QF_DATE_STORAGE_TIME: - Status = gRT->GetTime (&EfiTime, NULL); - break; - - case QF_DATE_STORAGE_WAKEUP: - Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); - break; - - case QF_DATE_STORAGE_NORMAL: - default: - // - // For date/time without storage - // - return EFI_SUCCESS; - } - - if (EFI_ERROR (Status)) { - return Status; - } - - if (Question->Operand == EFI_IFR_DATE_OP) { - QuestionValue->date.Year = EfiTime.Year; - QuestionValue->date.Month = EfiTime.Month; - QuestionValue->date.Day = EfiTime.Day; - } else { - QuestionValue->time.Hour = EfiTime.Hour; - QuestionValue->time.Minute = EfiTime.Minute; - QuestionValue->time.Second = EfiTime.Second; - } - } - - return EFI_SUCCESS; - } - - // - // Question value is provided by EFI variable - // - StorageWidth = Question->StorageWidth; - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - if (Question->BufferValue != NULL) { - Dst = Question->BufferValue; - } else { - Dst = (UINT8 *) QuestionValue; - } - - Status = gRT->GetVariable ( - Question->VariableName, - &Storage->Guid, - NULL, - &StorageWidth, - Dst - ); - // - // Always return success, even this EFI variable doesn't exist - // - return EFI_SUCCESS; - } - - // - // Question Value is provided by Buffer Storage or NameValue Storage - // - if (Question->BufferValue != NULL) { - // - // This Question is password or orderedlist - // - Dst = Question->BufferValue; - } else { - // - // Other type of Questions - // - Dst = (UINT8 *) &Question->HiiValue.Value; - } - - IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); - IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); - if (Cached) { - if (IsBufferStorage) { - // - // Copy from storage Edit buffer - // - CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); - } else { - Status = GetValueByName (Storage, Question->VariableName, &Value); - if (EFI_ERROR (Status)) { - return Status; - } - - if (IsString) { - // - // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" - // - Length = StorageWidth + sizeof (CHAR16); - Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value); - } else { - Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL); - } - - gBS->FreePool (Value); - } - } else { - // - // Request current settings from Configuration Driver - // - if (FormSet->ConfigAccess == NULL) { - return EFI_NOT_FOUND; - } - - // - // ::= + || - // + "&" + - // - if (IsBufferStorage) { - Length = StrLen (Storage->ConfigHdr); - Length += StrLen (Question->BlockName); - } else { - Length = StrLen (Storage->ConfigHdr); - Length += StrLen (Question->VariableName) + 1; - } - ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); - ASSERT (ConfigRequest != NULL); - - StrCpy (ConfigRequest, Storage->ConfigHdr); - if (IsBufferStorage) { - StrCat (ConfigRequest, Question->BlockName); - } else { - StrCat (ConfigRequest, L"&"); - StrCat (ConfigRequest, Question->VariableName); - } - - Status = FormSet->ConfigAccess->ExtractConfig ( - FormSet->ConfigAccess, - ConfigRequest, - &Progress, - &Result - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Skip - // - Value = Result + Length; - if (IsBufferStorage) { - // - // Skip "&VALUE" - // - Value = Value + 6; - } - if (*Value != '=') { - gBS->FreePool (Result); - return EFI_NOT_FOUND; - } - // - // Skip '=', point to value - // - Value = Value + 1; - if (!IsBufferStorage && IsString) { - // - // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" - // - Length = StorageWidth + sizeof (CHAR16); - Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value); - } else { - Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL); - if (EFI_ERROR (Status)) { - gBS->FreePool (Result); - return Status; - } - } - - // - // Synchronize Edit Buffer - // - if (IsBufferStorage) { - CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); - } else { - SetValueByName (Storage, Question->VariableName, Value); - } - gBS->FreePool (Result); - } - - return Status; -} - - -/** - Save Question Value to edit copy(cached) or Storage(uncached). - - @param FormSet FormSet data structure. - @param Form Form data structure. - @param Question Pointer to the Question. - @param Cached TRUE: set to Edit copy FALSE: set to original - Storage - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -SetQuestionValue ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_BROWSER_STATEMENT *Question, - IN BOOLEAN Cached - ) -{ - EFI_STATUS Status; - BOOLEAN Enabled; - BOOLEAN Pending; - UINT8 *Src; - EFI_TIME EfiTime; - UINTN BufferLen; - UINTN StorageWidth; - FORMSET_STORAGE *Storage; - EFI_IFR_TYPE_VALUE *QuestionValue; - CHAR16 *ConfigResp; - CHAR16 *Progress; - CHAR16 *Value; - UINTN Length; - BOOLEAN IsBufferStorage; - BOOLEAN IsString; - - Status = EFI_SUCCESS; - - // - // Statement don't have storage, skip them - // - if (Question->QuestionId == 0) { - return Status; - } - - // - // If Question value is provided by an Expression, then it is read only - // - if (Question->ValueExpression != NULL) { - return Status; - } - - // - // Question value is provided by RTC - // - Storage = Question->Storage; - QuestionValue = &Question->HiiValue.Value; - if (Storage == NULL) { - // - // It's a Question without storage, or RTC date/time - // - if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { - // - // Date and time define the same Flags bit - // - switch (Question->Flags & EFI_QF_DATE_STORAGE) { - case QF_DATE_STORAGE_TIME: - Status = gRT->GetTime (&EfiTime, NULL); - break; - - case QF_DATE_STORAGE_WAKEUP: - Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); - break; - - case QF_DATE_STORAGE_NORMAL: - default: - // - // For date/time without storage - // - return EFI_SUCCESS; - } - - if (EFI_ERROR (Status)) { - return Status; - } - - if (Question->Operand == EFI_IFR_DATE_OP) { - EfiTime.Year = QuestionValue->date.Year; - EfiTime.Month = QuestionValue->date.Month; - EfiTime.Day = QuestionValue->date.Day; - } else { - EfiTime.Hour = QuestionValue->time.Hour; - EfiTime.Minute = QuestionValue->time.Minute; - EfiTime.Second = QuestionValue->time.Second; - } - - if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { - Status = gRT->SetTime (&EfiTime); - } else { - Status = gRT->SetWakeupTime (TRUE, &EfiTime); - } - } - - return Status; - } - - // - // Question value is provided by EFI variable - // - StorageWidth = Question->StorageWidth; - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - if (Question->BufferValue != NULL) { - Src = Question->BufferValue; - } else { - Src = (UINT8 *) QuestionValue; - } - - Status = gRT->SetVariable ( - Question->VariableName, - &Storage->Guid, - Storage->Attributes, - StorageWidth, - Src - ); - return Status; - } - - // - // Question Value is provided by Buffer Storage or NameValue Storage - // - if (Question->BufferValue != NULL) { - Src = Question->BufferValue; - } else { - Src = (UINT8 *) &Question->HiiValue.Value; - } - - IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); - IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); - if (IsBufferStorage) { - // - // Copy to storage edit buffer - // - CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); - } else { - if (IsString) { - // - // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" - // - Value = NULL; - BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); - Value = AllocateZeroPool (BufferLen); - ASSERT (Value != NULL); - Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src); - ASSERT_EFI_ERROR (Status); - } else { - BufferLen = StorageWidth * 2 + 1; - Value = AllocateZeroPool (BufferLen * sizeof (CHAR16)); - ASSERT (Value != NULL); - BufToHexString (Value, &BufferLen, Src, StorageWidth); - ToLower (Value); - } - - Status = SetValueByName (Storage, Question->VariableName, Value); - gBS->FreePool (Value); - } - - if (!Cached) { - // - // ::= + + "&VALUE=" + "StorageWidth * 2" || - // + "&" + + "=" + "" - // - if (IsBufferStorage) { - Length = StrLen (Question->BlockName) + 7; - } else { - Length = StrLen (Question->VariableName) + 2; - } - if (!IsBufferStorage && IsString) { - Length += (StrLen ((CHAR16 *) Src) * 4); - } else { - Length += (StorageWidth * 2); - } - ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16)); - ASSERT (ConfigResp != NULL); - - StrCpy (ConfigResp, Storage->ConfigHdr); - if (IsBufferStorage) { - StrCat (ConfigResp, Question->BlockName); - StrCat (ConfigResp, L"&VALUE="); - } else { - StrCat (ConfigResp, L"&"); - StrCat (ConfigResp, Question->VariableName); - StrCat (ConfigResp, L"="); - } - - Value = ConfigResp + StrLen (ConfigResp); - if (!IsBufferStorage && IsString) { - // - // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" - // - BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); - Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src); - ASSERT_EFI_ERROR (Status); - } else { - BufferLen = StorageWidth * 2 + 1; - BufToHexString (Value, &BufferLen, Src, StorageWidth); - ToLower (Value); - } - - // - // Submit Question Value to Configuration Driver - // - if (FormSet->ConfigAccess != NULL) { - Status = FormSet->ConfigAccess->RouteConfig ( - FormSet->ConfigAccess, - ConfigResp, - &Progress - ); - if (EFI_ERROR (Status)) { - gBS->FreePool (ConfigResp); - return Status; - } - } - gBS->FreePool (ConfigResp); - - // - // Synchronize shadow Buffer - // - SynchronizeStorage (Storage); - } - - return Status; -} - - -/** - Perform inconsistent check for a Form. - - @param FormSet FormSet data structure. - @param Form Form data structure. - @param Question The Question to be validated. - @param Type Validation type: InConsistent or NoSubmit - - @retval EFI_SUCCESS Form validation pass. - @retval other Form validation failed. - -**/ -EFI_STATUS -ValidateQuestion ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Question, - IN UINTN Type - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - LIST_ENTRY *ListHead; - EFI_STRING PopUp; - EFI_INPUT_KEY Key; - FORM_EXPRESSION *Expression; - - if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { - ListHead = &Question->InconsistentListHead; - } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { - ListHead = &Question->NoSubmitListHead; - } else { - return EFI_UNSUPPORTED; - } - - Link = GetFirstNode (ListHead); - while (!IsNull (ListHead, Link)) { - Expression = FORM_EXPRESSION_FROM_LINK (Link); - - // - // Evaluate the expression - // - Status = EvaluateExpression (FormSet, Form, Expression); - if (EFI_ERROR (Status)) { - return Status; - } - - if (Expression->Result.Value.b) { - // - // Condition meet, show up error message - // - if (Expression->Error != 0) { - PopUp = GetToken (Expression->Error, FormSet->HiiHandle); - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - gBS->FreePool (PopUp); - } - - return EFI_NOT_READY; - } - - Link = GetNextNode (ListHead, Link); - } - - return EFI_SUCCESS; -} - - -/** - Perform NoSubmit check for a Form. - - @param FormSet FormSet data structure. - @param Form Form data structure. - - @retval EFI_SUCCESS Form validation pass. - @retval other Form validation failed. - -**/ -EFI_STATUS -NoSubmitCheck ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Question; - - Link = GetFirstNode (&Form->StatementListHead); - while (!IsNull (&Form->StatementListHead, Link)) { - Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - - Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); - if (EFI_ERROR (Status)) { - return Status; - } - - Link = GetNextNode (&Form->StatementListHead, Link); - } - - return EFI_SUCCESS; -} - - -/** - Submit a Form. - - @param FormSet FormSet data structure. - @param Form Form data structure. - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -SubmitForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - EFI_STRING ConfigResp; - EFI_STRING Progress; - FORMSET_STORAGE *Storage; - - // - // Validate the Form by NoSubmit check - // - Status = NoSubmitCheck (FormSet, Form); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Submit Buffer storage or Name/Value storage - // - Link = GetFirstNode (&FormSet->StorageListHead); - while (!IsNull (&FormSet->StorageListHead, Link)) { - Storage = FORMSET_STORAGE_FROM_LINK (Link); - Link = GetNextNode (&FormSet->StorageListHead, Link); - - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - continue; - } - - // - // Skip if there is no RequestElement - // - if (Storage->ElementCount == 0) { - continue; - } - - // - // Prepare - // - Status = StorageToConfigResp (Storage, &ConfigResp); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Send to Configuration Driver - // - if (FormSet->ConfigAccess != NULL) { - Status = FormSet->ConfigAccess->RouteConfig ( - FormSet->ConfigAccess, - ConfigResp, - &Progress - ); - if (EFI_ERROR (Status)) { - gBS->FreePool (ConfigResp); - return Status; - } - } - gBS->FreePool (ConfigResp); - - // - // Config success, update storage shadow Buffer - // - SynchronizeStorage (Storage); - } - - gNvUpdateRequired = FALSE; - - return EFI_SUCCESS; -} - - -/** - Reset Question to its default value. - - @param FormSet FormSet data structure. - @param DefaultId The Class of the default. - - @retval EFI_SUCCESS Question is reset to default value. - -**/ -EFI_STATUS -GetQuestionDefault ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Question, - IN UINT16 DefaultId - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - QUESTION_DEFAULT *Default; - QUESTION_OPTION *Option; - EFI_HII_VALUE *HiiValue; - UINT8 Index; - - Status = EFI_SUCCESS; - - // - // Statement don't have storage, skip them - // - if (Question->QuestionId == 0) { - return Status; - } - - // - // There are three ways to specify default value for a Question: - // 1, use nested EFI_IFR_DEFAULT (highest priority) - // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) - // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) - // - HiiValue = &Question->HiiValue; - - // - // EFI_IFR_DEFAULT has highest priority - // - if (!IsListEmpty (&Question->DefaultListHead)) { - Link = GetFirstNode (&Question->DefaultListHead); - while (!IsNull (&Question->DefaultListHead, Link)) { - Default = QUESTION_DEFAULT_FROM_LINK (Link); - - if (Default->DefaultId == DefaultId) { - if (Default->ValueExpression != NULL) { - // - // Default is provided by an Expression, evaluate it - // - Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); - if (EFI_ERROR (Status)) { - return Status; - } - - CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE)); - } else { - // - // Default value is embedded in EFI_IFR_DEFAULT - // - CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); - } - - return EFI_SUCCESS; - } - - Link = GetNextNode (&Question->DefaultListHead, Link); - } - } - - // - // EFI_ONE_OF_OPTION - // - if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { - if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { - // - // OneOfOption could only provide Standard and Manufacturing default - // - Link = GetFirstNode (&Question->OptionListHead); - while (!IsNull (&Question->OptionListHead, Link)) { - Option = QUESTION_OPTION_FROM_LINK (Link); - - if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Option->Flags & EFI_IFR_OPTION_DEFAULT)) || - ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG)) - ) { - CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); - - return EFI_SUCCESS; - } - - Link = GetNextNode (&Question->OptionListHead, Link); - } - } - } - - // - // EFI_IFR_CHECKBOX - lowest priority - // - if (Question->Operand == EFI_IFR_CHECKBOX_OP) { - if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { - // - // Checkbox could only provide Standard and Manufacturing default - // - if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT)) || - ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && (Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG)) - ) { - HiiValue->Value.b = TRUE; - } else { - HiiValue->Value.b = FALSE; - } - - return EFI_SUCCESS; - } - } - - // - // For Questions without default - // - switch (Question->Operand) { - case EFI_IFR_NUMERIC_OP: - // - // Take minimal value as numeric's default value - // - HiiValue->Value.u64 = Question->Minimum; - break; - - case EFI_IFR_ONE_OF_OP: - // - // Take first oneof option as oneof's default value - // - Link = GetFirstNode (&Question->OptionListHead); - if (!IsNull (&Question->OptionListHead, Link)) { - Option = QUESTION_OPTION_FROM_LINK (Link); - CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); - } - break; - - case EFI_IFR_ORDERED_LIST_OP: - // - // Take option sequence in IFR as ordered list's default value - // - Index = 0; - Link = GetFirstNode (&Question->OptionListHead); - while (!IsNull (&Question->OptionListHead, Link)) { - Option = QUESTION_OPTION_FROM_LINK (Link); - - Question->BufferValue[Index] = Option->Value.Value.u8; - - Index++; - if (Index >= Question->MaxContainers) { - break; - } - - Link = GetNextNode (&Question->OptionListHead, Link); - } - break; - - default: - Status = EFI_NOT_FOUND; - break; - } - - return Status; -} - - -/** - Reset Questions in a Form to their default value. - - @param FormSet FormSet data structure. - @param Form The Form which to be reset. - @param DefaultId The Class of the default. - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -ExtractFormDefault ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN UINT16 DefaultId - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Question; - - Link = GetFirstNode (&Form->StatementListHead); - while (!IsNull (&Form->StatementListHead, Link)) { - Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - Link = GetNextNode (&Form->StatementListHead, Link); - - // - // Reset Question to its default value - // - Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); - if (EFI_ERROR (Status)) { - continue; - } - - // - // Synchronize Buffer storage's Edit buffer - // - if ((Question->Storage != NULL) && - (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { - SetQuestionValue (FormSet, Form, Question, TRUE); - } - } - - return EFI_SUCCESS; -} - - -/** - Initialize Question's Edit copy from Storage. - - @param FormSet FormSet data structure. - @param Form Form data structure. - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -LoadFormConfig ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -{ - EFI_STATUS Status; - LIST_ENTRY *Link; - FORM_BROWSER_STATEMENT *Question; - - Link = GetFirstNode (&Form->StatementListHead); - while (!IsNull (&Form->StatementListHead, Link)) { - Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); - - // - // Initialize local copy of Value for each Question - // - Status = GetQuestionValue (FormSet, Form, Question, TRUE); - if (EFI_ERROR (Status)) { - return Status; - } - - Link = GetNextNode (&Form->StatementListHead, Link); - } - - return EFI_SUCCESS; -} - - -/** - Fill storage's edit copy with settings requested from Configuration Driver. - - @param FormSet FormSet data structure. - @param Storage Buffer Storage. - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -LoadStorage ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORMSET_STORAGE *Storage - ) -{ - EFI_STATUS Status; - EFI_STRING Progress; - EFI_STRING Result; - CHAR16 *StrPtr; - - if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { - return EFI_SUCCESS; - } - - if (FormSet->ConfigAccess == NULL) { - return EFI_NOT_FOUND; - } - - if (Storage->ElementCount == 0) { - // - // Skip if there is no RequestElement - // - return EFI_SUCCESS; - } - - // - // Request current settings from Configuration Driver - // - Status = FormSet->ConfigAccess->ExtractConfig ( - FormSet->ConfigAccess, - Storage->ConfigRequest, - &Progress, - &Result - ); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Convert Result from to - // - StrPtr = StrStr (Result, L"ALTCFG"); - if (StrPtr != NULL) { - *StrPtr = L'\0'; - } - - Status = ConfigRespToStorage (Storage, Result); - gBS->FreePool (Result); - return Status; -} - - -/** - Get current setting of Questions. - - @param FormSet FormSet data structure. - - @retval EFI_SUCCESS The function completed successfully. - -**/ -EFI_STATUS -InitializeCurrentSetting ( - IN OUT FORM_BROWSER_FORMSET *FormSet - ) -{ - LIST_ENTRY *Link; - FORMSET_STORAGE *Storage; - FORM_BROWSER_FORM *Form; - EFI_STATUS Status; - - // - // Extract default from IFR binary - // - Link = GetFirstNode (&FormSet->FormListHead); - while (!IsNull (&FormSet->FormListHead, Link)) { - Form = FORM_BROWSER_FORM_FROM_LINK (Link); - - Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD); - - Link = GetNextNode (&FormSet->FormListHead, Link); - } - - // - // Request current settings from Configuration Driver - // - Link = GetFirstNode (&FormSet->StorageListHead); - while (!IsNull (&FormSet->StorageListHead, Link)) { - Storage = FORMSET_STORAGE_FROM_LINK (Link); - - Status = LoadStorage (FormSet, Storage); - - // - // Now Edit Buffer is filled with default values(lower priority) and current - // settings(higher priority), sychronize it to shadow Buffer - // - if (!EFI_ERROR (Status)) { - SynchronizeStorage (Storage); - } - - Link = GetNextNode (&FormSet->StorageListHead, Link); - } - - return EFI_SUCCESS; -} - - -/** - Fetch the Ifr binary data of a FormSet. - - @param Handle PackageList Handle - @param FormSetGuid GUID of a formset. If not specified (NULL or zero - GUID), take the first FormSet found in package - list. - @param BinaryLength The length of the FormSet IFR binary. - @param BinaryData The buffer designed to receive the FormSet. - - @retval EFI_SUCCESS Buffer filled with the requested FormSet. - BufferLength was updated. - @retval EFI_INVALID_PARAMETER The handle is unknown. - @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot - be found with the requested FormId. - -**/ -EFI_STATUS -GetIfrBinaryData ( - IN EFI_HII_HANDLE Handle, - IN OUT EFI_GUID *FormSetGuid, - OUT UINTN *BinaryLength, - OUT UINT8 **BinaryData - ) -{ - EFI_STATUS Status; - EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; - UINTN BufferSize; - UINT8 *Package; - UINT8 *OpCodeData; - UINT32 Offset; - UINT32 Offset2; - BOOLEAN ReturnDefault; - UINT32 PackageListLength; - EFI_HII_PACKAGE_HEADER PackageHeader; - - OpCodeData = NULL; - Package = NULL; - ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));; - - // - // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list - // - if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { - ReturnDefault = TRUE; - } else { - ReturnDefault = FALSE; - } - - // - // Get HII PackageList - // - BufferSize = 0; - HiiPackageList = NULL; - Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); - if (Status == EFI_BUFFER_TOO_SMALL) { - HiiPackageList = AllocatePool (BufferSize); - ASSERT (HiiPackageList != NULL); - - Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); - } - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Get Form package from this HII package List - // - Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); - Offset2 = 0; - CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); - - while (Offset < PackageListLength) { - Package = ((UINT8 *) HiiPackageList) + Offset; - CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); - - if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) { - // - // Search FormSet in this Form Package - // - Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); - while (Offset2 < PackageHeader.Length) { - OpCodeData = Package + Offset2; - - if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { - // - // Check whether return default FormSet - // - if (ReturnDefault) { - break; - } - - // - // FormSet GUID is specified, check it - // - if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { - break; - } - } - - Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; - } - - if (Offset2 < PackageHeader.Length) { - // - // Target formset found - // - break; - } - } - - Offset += PackageHeader.Length; - } - - if (Offset >= PackageListLength) { - // - // Form package not found in this Package List - // - gBS->FreePool (HiiPackageList); - return EFI_NOT_FOUND; - } - - if (ReturnDefault && FormSetGuid != NULL) { - // - // Return the default FormSet GUID - // - CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); - } - - // - // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes - // in this FormSet; So, here just simply copy the data from start of a FormSet to the end - // of the Form Package. - // - *BinaryLength = PackageHeader.Length - Offset2; - *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); - - gBS->FreePool (HiiPackageList); - - if (*BinaryData == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - return EFI_SUCCESS; -} - - -/** - Initialize the internal data structure of a FormSet. - - @param Handle PackageList Handle - @param FormSetGuid GUID of a formset. If not specified (NULL or zero - GUID), take the first FormSet found in package - list. - @param FormSet FormSet data structure. - - @retval EFI_SUCCESS The function completed successfully. - @retval EFI_NOT_FOUND The specified FormSet could not be found. - -**/ -EFI_STATUS -InitializeFormSet ( - IN EFI_HII_HANDLE Handle, - IN OUT EFI_GUID *FormSetGuid, - OUT FORM_BROWSER_FORMSET *FormSet - ) -{ - EFI_STATUS Status; - EFI_HANDLE DriverHandle; - UINT16 Index; - - Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); - if (EFI_ERROR (Status)) { - return Status; - } - - FormSet->HiiHandle = Handle; - CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); - - // - // Retrieve ConfigAccess Protocol associated with this HiiPackageList - // - Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); - if (EFI_ERROR (Status)) { - return Status; - } - FormSet->DriverHandle = DriverHandle; - Status = gBS->HandleProtocol ( - DriverHandle, - &gEfiHiiConfigAccessProtocolGuid, - (VOID **) &FormSet->ConfigAccess - ); - if (EFI_ERROR (Status)) { - // - // Configuration Driver don't attach ConfigAccess protocol to its HII package - // list, then there will be no configuration action required - // - FormSet->ConfigAccess = NULL; - } - - // - // Parse the IFR binary OpCodes - // - Status = ParseOpCodes (FormSet); - if (EFI_ERROR (Status)) { - return Status; - } - - gClassOfVfr = FormSet->SubClass; - if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { - FrontPageHandle = FormSet->HiiHandle; - } - - // - // Match GUID to find out the function key setting. If match fail, use the default setting. - // - for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { - if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { - // - // Update the function key setting. - // - gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; - // - // Function key prompt can not be displayed if the function key has been disabled. - // - if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { - gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } - - if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { - gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } - - if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { - gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } - - if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { - gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); - } - } - } - - return Status; -} +/** @file +Entry and initialization module for the browser. + +Copyright (c) 2007 - 2008, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Setup.h" +#include "Ui.h" + + +SETUP_DRIVER_PRIVATE_DATA mPrivateData = { + SETUP_DRIVER_SIGNATURE, + NULL, + { + SendForm, + BrowserCallback + }, + { + UnicodeVSPrint + } +}; + +EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +EFI_HII_STRING_PROTOCOL *mHiiString; +EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +BANNER_DATA *BannerData; +EFI_HII_HANDLE FrontPageHandle; +UINTN gClassOfVfr; +UINTN gFunctionKeySetting; +BOOLEAN gResetRequired; +BOOLEAN gNvUpdateRequired; +EFI_HII_HANDLE gHiiHandle; +BOOLEAN gFirstIn; +UINT16 gDirection; +EFI_SCREEN_DESCRIPTOR gScreenDimensions; +BOOLEAN gUpArrow; +BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +CHAR16 *gFunctionOneString; +CHAR16 *gFunctionTwoString; +CHAR16 *gFunctionNineString; +CHAR16 *gFunctionTenString; +CHAR16 *gEnterString; +CHAR16 *gEnterCommitString; +CHAR16 *gEscapeString; +CHAR16 *gSaveFailed; +CHAR16 *gMoveHighlight; +CHAR16 *gMakeSelection; +CHAR16 *gDecNumericInput; +CHAR16 *gHexNumericInput; +CHAR16 *gToggleCheckBox; +CHAR16 *gPromptForData; +CHAR16 *gPromptForPassword; +CHAR16 *gPromptForNewPassword; +CHAR16 *gConfirmPassword; +CHAR16 *gConfirmError; +CHAR16 *gPassowordInvalid; +CHAR16 *gPressEnter; +CHAR16 *gEmptyString; +CHAR16 *gAreYouSure; +CHAR16 *gYesResponse; +CHAR16 *gNoResponse; +CHAR16 *gMiniString; +CHAR16 *gPlusString; +CHAR16 *gMinusString; +CHAR16 *gAdjustNumber; + +CHAR16 gPromptBlockWidth; +CHAR16 gOptionBlockWidth; +CHAR16 gHelpBlockWidth; + +EFI_GUID gZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; +EFI_GUID gSetupBrowserGuid = { + 0xab368524, 0xb60c, 0x495b, {0xa0, 0x9, 0x12, 0xe8, 0x5b, 0x1a, 0xea, 0x32} +}; + +FUNCTIION_KEY_SETTING gFunctionKeySettingTable[] = { + // + // Boot Manager + // + { + { + 0x847bc3fe, + 0xb974, + 0x446d, + { + 0x94, + 0x49, + 0x5a, + 0xd5, + 0x41, + 0x2e, + 0x99, + 0x3b + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // Device Manager + // + { + { + 0x3ebfa8e6, + 0x511d, + 0x4b5b, + { + 0xa9, + 0x5f, + 0xfb, + 0x38, + 0x26, + 0xf, + 0x1c, + 0x27 + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM FormSet. + // + { + { + 0x642237c7, + 0x35d4, + 0x472d, + { + 0x83, + 0x65, + 0x12, + 0xe0, + 0xcc, + 0xf2, + 0x7a, + 0x22 + } + }, + NONE_FUNCTION_KEY_SETTING + }, + // + // BMM File Explorer FormSet. + // + { + { + 0x1f2d63e1, + 0xfebd, + 0x4dc7, + { + 0x9c, + 0xc5, + 0xba, + 0x2b, + 0x1c, + 0xef, + 0x9c, + 0x5b + } + }, + NONE_FUNCTION_KEY_SETTING + }, +}; + +/** + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + + + @param This The Form Browser protocol instanse. + @param Handles A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + @param HandleCount The number of Handles specified in Handle. + @param FormSetGuid This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + @param FormId This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in + characters. + @param ActionRequest Points to the action recommended by the form. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND No valid forms could be found to display. + +**/ +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +{ + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + UINTN Index; + FORM_BROWSER_FORMSET *FormSet; + + Status = EFI_SUCCESS; + ZeroMem (&gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + // + // Seed the dimensions in the global + // + gST->ConOut->QueryMode ( + gST->ConOut, + gST->ConOut->Mode->Mode, + &gScreenDimensions.RightColumn, + &gScreenDimensions.BottomRow + ); + + if (ScreenDimensions != NULL) { + // + // Check local dimension vs. global dimension. + // + if ((gScreenDimensions.RightColumn < ScreenDimensions->RightColumn) || + (gScreenDimensions.BottomRow < ScreenDimensions->BottomRow) + ) { + return EFI_INVALID_PARAMETER; + } else { + // + // Local dimension validation. + // + if ((ScreenDimensions->RightColumn > ScreenDimensions->LeftColumn) && + (ScreenDimensions->BottomRow > ScreenDimensions->TopRow) && + ((ScreenDimensions->RightColumn - ScreenDimensions->LeftColumn) > 2) && + ( + (ScreenDimensions->BottomRow - ScreenDimensions->TopRow) > STATUS_BAR_HEIGHT + + SCROLL_ARROW_HEIGHT * + 2 + + FRONT_PAGE_HEADER_HEIGHT + + FOOTER_HEIGHT + + 1 + ) + ) { + CopyMem (&gScreenDimensions, (VOID *) ScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + } else { + return EFI_INVALID_PARAMETER; + } + } + } + + gOptionBlockWidth = (CHAR16) ((gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn) / 3); + gHelpBlockWidth = gOptionBlockWidth; + gPromptBlockWidth = gOptionBlockWidth; + + // + // Initialize the strings for the browser, upon exit of the browser, the strings will be freed + // + InitializeBrowserStrings (); + + gFunctionKeySetting = DEFAULT_FUNCTION_KEY_SETTING; + gClassOfVfr = EFI_SETUP_APPLICATION_SUBCLASS; + + // + // Ensure we are in Text mode + // + if (gFirstIn) { + gFirstIn = FALSE; + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + DisableQuietBoot (); + } + + for (Index = 0; Index < HandleCount; Index++) { + Selection = AllocateZeroPool (sizeof (UI_MENU_SELECTION)); + ASSERT (Selection != NULL); + + Selection->Handle = Handles[Index]; + if (FormSetGuid != NULL) { + CopyMem (&Selection->FormSetGuid, FormSetGuid, sizeof (EFI_GUID)); + Selection->FormId = FormId; + } + + do { + FormSet = AllocateZeroPool (sizeof (FORM_BROWSER_FORMSET)); + ASSERT (FormSet != NULL); + + // + // Initialize internal data structures of FormSet + // + Status = InitializeFormSet (Selection->Handle, &Selection->FormSetGuid, FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + Selection->FormSet = FormSet; + + // + // Initialize current settings of Questions in this FormSet + // + Status = InitializeCurrentSetting (FormSet); + if (EFI_ERROR (Status)) { + DestroyFormSet (FormSet); + break; + } + + // + // Display this formset + // + gCurrentSelection = Selection; + + Status = SetupBrowser (Selection); + + gCurrentSelection = NULL; + DestroyFormSet (FormSet); + + if (EFI_ERROR (Status)) { + break; + } + + } while (Selection->Action == UI_ACTION_REFRESH_FORMSET); + + gBS->FreePool (Selection); + } + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + if (gResetRequired) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; + } + } + + FreeBrowserStrings (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->ClearScreen (gST->ConOut); + + return Status; +} + + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORMSET *FormSet; + BOOLEAN Found; + CHAR16 *ConfigResp; + CHAR16 *StrPtr; + UINTN BufferSize; + UINTN TmpSize; + + if (ResultsDataSize == NULL || ResultsData == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (gCurrentSelection == NULL) { + return EFI_NOT_READY; + } + + Storage = NULL; + ConfigResp = NULL; + FormSet = gCurrentSelection->FormSet; + + // + // Find target storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + if (IsNull (&FormSet->StorageListHead, Link)) { + return EFI_UNSUPPORTED; + } + + if (VariableGuid != NULL) { + // + // Try to find target storage + // + Found = FALSE; + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (CompareGuid (&Storage->Guid, (EFI_GUID *) VariableGuid)) { + if (Storage->Type == EFI_HII_VARSTORE_BUFFER) { + // + // Buffer storage require both GUID and Name + // + if (VariableName == NULL) { + return EFI_NOT_FOUND; + } + + if (StrCmp (Storage->Name, (CHAR16 *) VariableName) != 0) { + continue; + } + } + Found = TRUE; + break; + } + } + + if (!Found) { + return EFI_NOT_FOUND; + } + } else { + // + // GUID/Name is not specified, take the first storage in FormSet + // + Storage = FORMSET_STORAGE_FROM_LINK (Link); + } + + if (RetrieveData) { + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + return EFI_SUCCESS; + } + + // + // Generate + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip and '&' to point to + // + StrPtr = ConfigResp + StrLen (Storage->ConfigHdr) + 1; + + BufferSize = StrSize (StrPtr); + if (*ResultsDataSize < BufferSize) { + *ResultsDataSize = BufferSize; + + gBS->FreePool (ConfigResp); + return EFI_BUFFER_TOO_SMALL; + } + + *ResultsDataSize = BufferSize; + CopyMem (ResultsData, StrPtr, BufferSize); + + gBS->FreePool (ConfigResp); + } else { + // + // Prepare + // + TmpSize = StrLen (ResultsData); + BufferSize = (TmpSize + StrLen (Storage->ConfigHdr) + 2) * sizeof (CHAR16); + ConfigResp = AllocateZeroPool (BufferSize); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, ResultsData); + + // + // Update Browser uncommited data + // + Status = ConfigRespToStorage (Storage, ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Setup Browser driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS The Setup Browser module is initialized correctly.. + @return Other value if failed to initialize the Setup Browser module. + +**/ +EFI_STATUS +EFIAPI +InitializeSetup ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE HiiDriverHandle; + EFI_HII_PACKAGE_LIST_HEADER *PackageList; + + // + // Locate required Hii relative protocols + // + Status = gBS->LocateProtocol ( + &gEfiHiiDatabaseProtocolGuid, + NULL, + (VOID **) &mHiiDatabase + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiStringProtocolGuid, + NULL, + (VOID **) &mHiiString + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &mHiiConfigRouting + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + Status = HiiLibCreateHiiDriverHandle (&HiiDriverHandle); + ASSERT_EFI_ERROR (Status); + + PackageList = HiiLibPreparePackageList (1, &gSetupBrowserGuid, SetupBrowserStrings); + ASSERT (PackageList != NULL); + Status = mHiiDatabase->NewPackageList ( + mHiiDatabase, + PackageList, + HiiDriverHandle, + &gHiiHandle + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize Driver private data + // + gFirstIn = TRUE; + BannerData = AllocateZeroPool (sizeof (BANNER_DATA)); + ASSERT (BannerData != NULL); + + // + // Install FormBrowser2 protocol + // + mPrivateData.Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiFormBrowser2ProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.FormBrowser2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Print protocol + // + Status = gBS->InstallProtocolInterface ( + &mPrivateData.Handle, + &gEfiPrintProtocolGuid, + EFI_NATIVE_INTERFACE, + &mPrivateData.Print + ); + + return Status; +} + + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STRING_ID StringId; + EFI_STATUS Status; + + StringId = 0; + Status = HiiLibNewString (HiiHandle, &StringId, String); + ASSERT_EFI_ERROR (Status); + + return StringId; +} + + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +{ + CHAR16 NullChar; + + NullChar = CHAR_NULL; + return HiiLibSetString (HiiHandle, StringId, &NullChar); +} + + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +{ + EFI_STATUS Status; + CHAR16 *String; + UINTN BufferLength; + + // + // Set default string size assumption at no more than 256 bytes + // + BufferLength = 0x100; + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength); + + if (Status == EFI_BUFFER_TOO_SMALL) { + gBS->FreePool (String); + String = AllocateZeroPool (BufferLength); + ASSERT (String != NULL); + + Status = HiiLibGetString (HiiHandle, Token, String, &BufferLength); + } + ASSERT_EFI_ERROR (Status); + + return String; +} + + +/** + Allocate new memory and then copy the Unicode string Source to Destination. + + @param Dest Location to copy string + @param Src String to copy + +**/ +VOID +NewStringCpy ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + SafeFreePool (*Dest); + *Dest = AllocateCopyPool (StrSize (Src), Src); + ASSERT (*Dest != NULL); +} + + +/** + Allocate new memory and concatinate Source on the end of Destination. + + @param Dest String to added to the end of. + @param Src String to concatinate. + +**/ +VOID +NewStringCat ( + IN OUT CHAR16 **Dest, + IN CHAR16 *Src + ) +{ + CHAR16 *NewString; + UINTN TmpSize; + + if (*Dest == NULL) { + NewStringCpy (Dest, Src); + return; + } + + TmpSize = StrSize (*Dest); + NewString = AllocateZeroPool (TmpSize + StrSize (Src) - 1); + ASSERT (NewString != NULL); + + StrCpy (NewString, *Dest); + StrCat (NewString, Src); + + gBS->FreePool (*Dest); + *Dest = NewString; +} + + +/** + Synchronize Storage's Edit copy to Shadow copy. + + @param Storage The Storage to be synchronized. + +**/ +VOID +SynchronizeStorage ( + IN FORMSET_STORAGE *Storage + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + CopyMem (Storage->Buffer, Storage->EditBuffer, Storage->Size); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCpy (&Node->Value, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + break; + } +} + + +/** + Get Value for given Name from a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The retured Value. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +GetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN OUT CHAR16 **Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + *Value = NULL; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + NewStringCpy (Value, Node->EditValue); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Set Value of given Name in a NameValue Storage. + + @param Storage The NameValue Storage. + @param Name The Name. + @param Value The Value to set. + + @retval EFI_SUCCESS Value found for given Name. + @retval EFI_NOT_FOUND No such Name found in NameValue storage. + +**/ +EFI_STATUS +SetValueByName ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *Name, + IN CHAR16 *Value + ) +{ + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + if (StrCmp (Name, Node->Name) == 0) { + SafeFreePool (Node->EditValue); + Node->EditValue = AllocateCopyPool (StrSize (Value), Value); + ASSERT (Node->EditValue != NULL); + return EFI_SUCCESS; + } + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + + return EFI_NOT_FOUND; +} + + +/** + Convert setting of Buffer Storage or NameValue Storage to . + + @param Storage The Storage to be conveted. + @param ConfigResp The returned . + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + LIST_ENTRY *Link; + NAME_VALUE_NODE *Node; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + Status = mHiiConfigRouting->BlockToConfig ( + mHiiConfigRouting, + Storage->ConfigRequest, + Storage->EditBuffer, + Storage->Size, + ConfigResp, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + *ConfigResp = NULL; + NewStringCat (ConfigResp, Storage->ConfigHdr); + + Link = GetFirstNode (&Storage->NameValueListHead); + while (!IsNull (&Storage->NameValueListHead, Link)) { + Node = NAME_VALUE_NODE_FROM_LINK (Link); + + NewStringCat (ConfigResp, L"&"); + NewStringCat (ConfigResp, Node->Name); + NewStringCat (ConfigResp, L"="); + NewStringCat (ConfigResp, Node->EditValue); + + Link = GetNextNode (&Storage->NameValueListHead, Link); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Convert to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + UINTN BufferSize; + CHAR16 *StrPtr; + CHAR16 *Name; + CHAR16 *Value; + + Status = EFI_SUCCESS; + + switch (Storage->Type) { + case EFI_HII_VARSTORE_BUFFER: + BufferSize = Storage->Size; + Status = mHiiConfigRouting->ConfigToBlock ( + mHiiConfigRouting, + ConfigResp, + Storage->EditBuffer, + &BufferSize, + &Progress + ); + break; + + case EFI_HII_VARSTORE_NAME_VALUE: + StrPtr = StrStr (ConfigResp, L"&"); + while (StrPtr != NULL) { + // + // Skip '&' + // + StrPtr = StrPtr + 1; + Name = StrPtr; + StrPtr = StrStr (StrPtr, L"="); + if (StrPtr == NULL) { + break; + } + *StrPtr = 0; + + // + // Skip '=' + // + StrPtr = StrPtr + 1; + Value = StrPtr; + StrPtr = StrStr (StrPtr, L"&"); + if (StrPtr != NULL) { + *StrPtr = 0; + } + SetValueByName (Storage, Name, Value); + } + break; + + case EFI_HII_VARSTORE_EFI_VARIABLE: + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param Cached TRUE: get from Edit copy FALSE: get from original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Dst; + UINTN StorageWidth; + EFI_TIME EfiTime; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigRequest; + CHAR16 *Progress; + CHAR16 *Result; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // Question value is provided by an Expression, evaluate it + // + if (Question->ValueExpression != NULL) { + Status = EvaluateExpression (FormSet, Form, Question->ValueExpression); + if (!EFI_ERROR (Status)) { + CopyMem (&Question->HiiValue, &Question->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + QuestionValue->date.Year = EfiTime.Year; + QuestionValue->date.Month = EfiTime.Month; + QuestionValue->date.Day = EfiTime.Day; + } else { + QuestionValue->time.Hour = EfiTime.Hour; + QuestionValue->time.Minute = EfiTime.Minute; + QuestionValue->time.Second = EfiTime.Second; + } + } + + return EFI_SUCCESS; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Dst = Question->BufferValue; + } else { + Dst = (UINT8 *) QuestionValue; + } + + Status = gRT->GetVariable ( + Question->VariableName, + &Storage->Guid, + NULL, + &StorageWidth, + Dst + ); + // + // Always return success, even this EFI variable doesn't exist + // + return EFI_SUCCESS; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + // + // This Question is password or orderedlist + // + Dst = Question->BufferValue; + } else { + // + // Other type of Questions + // + Dst = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (Cached) { + if (IsBufferStorage) { + // + // Copy from storage Edit buffer + // + CopyMem (Dst, Storage->EditBuffer + Question->VarStoreInfo.VarOffset, StorageWidth); + } else { + Status = GetValueByName (Storage, Question->VariableName, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsString) { + // + // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" + // + Length = StorageWidth + sizeof (CHAR16); + Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value); + } else { + Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL); + } + + gBS->FreePool (Value); + } + } else { + // + // Request current settings from Configuration Driver + // + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + // + // ::= + || + // + "&" + + // + if (IsBufferStorage) { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->BlockName); + } else { + Length = StrLen (Storage->ConfigHdr); + Length += StrLen (Question->VariableName) + 1; + } + ConfigRequest = AllocateZeroPool ((Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigRequest != NULL); + + StrCpy (ConfigRequest, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigRequest, Question->BlockName); + } else { + StrCat (ConfigRequest, L"&"); + StrCat (ConfigRequest, Question->VariableName); + } + + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Skip + // + Value = Result + Length; + if (IsBufferStorage) { + // + // Skip "&VALUE" + // + Value = Value + 6; + } + if (*Value != '=') { + gBS->FreePool (Result); + return EFI_NOT_FOUND; + } + // + // Skip '=', point to value + // + Value = Value + 1; + if (!IsBufferStorage && IsString) { + // + // Convert Config String to Unicode String, e.g "0041004200430044" => "ABCD" + // + Length = StorageWidth + sizeof (CHAR16); + Status = ConfigStringToUnicode ((CHAR16 *) Dst, &Length, Value); + } else { + Status = HexStringToBuf (Dst, &StorageWidth, Value, NULL); + if (EFI_ERROR (Status)) { + gBS->FreePool (Result); + return Status; + } + } + + // + // Synchronize Edit Buffer + // + if (IsBufferStorage) { + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Dst, StorageWidth); + } else { + SetValueByName (Storage, Question->VariableName, Value); + } + gBS->FreePool (Result); + } + + return Status; +} + + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param Cached TRUE: set to Edit copy FALSE: set to original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +{ + EFI_STATUS Status; + BOOLEAN Enabled; + BOOLEAN Pending; + UINT8 *Src; + EFI_TIME EfiTime; + UINTN BufferLen; + UINTN StorageWidth; + FORMSET_STORAGE *Storage; + EFI_IFR_TYPE_VALUE *QuestionValue; + CHAR16 *ConfigResp; + CHAR16 *Progress; + CHAR16 *Value; + UINTN Length; + BOOLEAN IsBufferStorage; + BOOLEAN IsString; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // If Question value is provided by an Expression, then it is read only + // + if (Question->ValueExpression != NULL) { + return Status; + } + + // + // Question value is provided by RTC + // + Storage = Question->Storage; + QuestionValue = &Question->HiiValue.Value; + if (Storage == NULL) { + // + // It's a Question without storage, or RTC date/time + // + if (Question->Operand == EFI_IFR_DATE_OP || Question->Operand == EFI_IFR_TIME_OP) { + // + // Date and time define the same Flags bit + // + switch (Question->Flags & EFI_QF_DATE_STORAGE) { + case QF_DATE_STORAGE_TIME: + Status = gRT->GetTime (&EfiTime, NULL); + break; + + case QF_DATE_STORAGE_WAKEUP: + Status = gRT->GetWakeupTime (&Enabled, &Pending, &EfiTime); + break; + + case QF_DATE_STORAGE_NORMAL: + default: + // + // For date/time without storage + // + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Question->Operand == EFI_IFR_DATE_OP) { + EfiTime.Year = QuestionValue->date.Year; + EfiTime.Month = QuestionValue->date.Month; + EfiTime.Day = QuestionValue->date.Day; + } else { + EfiTime.Hour = QuestionValue->time.Hour; + EfiTime.Minute = QuestionValue->time.Minute; + EfiTime.Second = QuestionValue->time.Second; + } + + if ((Question->Flags & EFI_QF_DATE_STORAGE) == QF_DATE_STORAGE_TIME) { + Status = gRT->SetTime (&EfiTime); + } else { + Status = gRT->SetWakeupTime (TRUE, &EfiTime); + } + } + + return Status; + } + + // + // Question value is provided by EFI variable + // + StorageWidth = Question->StorageWidth; + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) QuestionValue; + } + + Status = gRT->SetVariable ( + Question->VariableName, + &Storage->Guid, + Storage->Attributes, + StorageWidth, + Src + ); + return Status; + } + + // + // Question Value is provided by Buffer Storage or NameValue Storage + // + if (Question->BufferValue != NULL) { + Src = Question->BufferValue; + } else { + Src = (UINT8 *) &Question->HiiValue.Value; + } + + IsBufferStorage = (BOOLEAN) ((Storage->Type == EFI_HII_VARSTORE_BUFFER) ? TRUE : FALSE); + IsString = (BOOLEAN) ((Question->HiiValue.Type == EFI_IFR_TYPE_STRING) ? TRUE : FALSE); + if (IsBufferStorage) { + // + // Copy to storage edit buffer + // + CopyMem (Storage->EditBuffer + Question->VarStoreInfo.VarOffset, Src, StorageWidth); + } else { + if (IsString) { + // + // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" + // + Value = NULL; + BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); + Value = AllocateZeroPool (BufferLen); + ASSERT (Value != NULL); + Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src); + ASSERT_EFI_ERROR (Status); + } else { + BufferLen = StorageWidth * 2 + 1; + Value = AllocateZeroPool (BufferLen * sizeof (CHAR16)); + ASSERT (Value != NULL); + BufToHexString (Value, &BufferLen, Src, StorageWidth); + ToLower (Value); + } + + Status = SetValueByName (Storage, Question->VariableName, Value); + gBS->FreePool (Value); + } + + if (!Cached) { + // + // ::= + + "&VALUE=" + "StorageWidth * 2" || + // + "&" + + "=" + "" + // + if (IsBufferStorage) { + Length = StrLen (Question->BlockName) + 7; + } else { + Length = StrLen (Question->VariableName) + 2; + } + if (!IsBufferStorage && IsString) { + Length += (StrLen ((CHAR16 *) Src) * 4); + } else { + Length += (StorageWidth * 2); + } + ConfigResp = AllocateZeroPool ((StrLen (Storage->ConfigHdr) + Length + 1) * sizeof (CHAR16)); + ASSERT (ConfigResp != NULL); + + StrCpy (ConfigResp, Storage->ConfigHdr); + if (IsBufferStorage) { + StrCat (ConfigResp, Question->BlockName); + StrCat (ConfigResp, L"&VALUE="); + } else { + StrCat (ConfigResp, L"&"); + StrCat (ConfigResp, Question->VariableName); + StrCat (ConfigResp, L"="); + } + + Value = ConfigResp + StrLen (ConfigResp); + if (!IsBufferStorage && IsString) { + // + // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044" + // + BufferLen = ((StrLen ((CHAR16 *) Src) * 4) + 1) * sizeof (CHAR16); + Status = UnicodeToConfigString (Value, &BufferLen, (CHAR16 *) Src); + ASSERT_EFI_ERROR (Status); + } else { + BufferLen = StorageWidth * 2 + 1; + BufToHexString (Value, &BufferLen, Src, StorageWidth); + ToLower (Value); + } + + // + // Submit Question Value to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Synchronize shadow Buffer + // + SynchronizeStorage (Storage); + } + + return Status; +} + + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + LIST_ENTRY *ListHead; + EFI_STRING PopUp; + EFI_INPUT_KEY Key; + FORM_EXPRESSION *Expression; + + if (Type == EFI_HII_EXPRESSION_INCONSISTENT_IF) { + ListHead = &Question->InconsistentListHead; + } else if (Type == EFI_HII_EXPRESSION_NO_SUBMIT_IF) { + ListHead = &Question->NoSubmitListHead; + } else { + return EFI_UNSUPPORTED; + } + + Link = GetFirstNode (ListHead); + while (!IsNull (ListHead, Link)) { + Expression = FORM_EXPRESSION_FROM_LINK (Link); + + // + // Evaluate the expression + // + Status = EvaluateExpression (FormSet, Form, Expression); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Expression->Result.Value.b) { + // + // Condition meet, show up error message + // + if (Expression->Error != 0) { + PopUp = GetToken (Expression->Error, FormSet->HiiHandle); + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, PopUp, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gBS->FreePool (PopUp); + } + + return EFI_NOT_READY; + } + + Link = GetNextNode (ListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Perform NoSubmit check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +NoSubmitCheck ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_NO_SUBMIT_IF); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Submit a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + EFI_STRING ConfigResp; + EFI_STRING Progress; + FORMSET_STORAGE *Storage; + + // + // Validate the Form by NoSubmit check + // + Status = NoSubmitCheck (FormSet, Form); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Submit Buffer storage or Name/Value storage + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + Link = GetNextNode (&FormSet->StorageListHead, Link); + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + continue; + } + + // + // Skip if there is no RequestElement + // + if (Storage->ElementCount == 0) { + continue; + } + + // + // Prepare + // + Status = StorageToConfigResp (Storage, &ConfigResp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Send to Configuration Driver + // + if (FormSet->ConfigAccess != NULL) { + Status = FormSet->ConfigAccess->RouteConfig ( + FormSet->ConfigAccess, + ConfigResp, + &Progress + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (ConfigResp); + return Status; + } + } + gBS->FreePool (ConfigResp); + + // + // Config success, update storage shadow Buffer + // + SynchronizeStorage (Storage); + } + + gNvUpdateRequired = FALSE; + + return EFI_SUCCESS; +} + + +/** + Reset Question to its default value. + + @param FormSet The form set. + @param Form The form. + @param Question The question. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + QUESTION_DEFAULT *Default; + QUESTION_OPTION *Option; + EFI_HII_VALUE *HiiValue; + UINT8 Index; + + Status = EFI_SUCCESS; + + // + // Statement don't have storage, skip them + // + if (Question->QuestionId == 0) { + return Status; + } + + // + // There are three ways to specify default value for a Question: + // 1, use nested EFI_IFR_DEFAULT (highest priority) + // 2, set flags of EFI_ONE_OF_OPTION (provide Standard and Manufacturing default) + // 3, set flags of EFI_IFR_CHECKBOX (provide Standard and Manufacturing default) (lowest priority) + // + HiiValue = &Question->HiiValue; + + // + // EFI_IFR_DEFAULT has highest priority + // + if (!IsListEmpty (&Question->DefaultListHead)) { + Link = GetFirstNode (&Question->DefaultListHead); + while (!IsNull (&Question->DefaultListHead, Link)) { + Default = QUESTION_DEFAULT_FROM_LINK (Link); + + if (Default->DefaultId == DefaultId) { + if (Default->ValueExpression != NULL) { + // + // Default is provided by an Expression, evaluate it + // + Status = EvaluateExpression (FormSet, Form, Default->ValueExpression); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (HiiValue, &Default->ValueExpression->Result, sizeof (EFI_HII_VALUE)); + } else { + // + // Default value is embedded in EFI_IFR_DEFAULT + // + CopyMem (HiiValue, &Default->Value, sizeof (EFI_HII_VALUE)); + } + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->DefaultListHead, Link); + } + } + + // + // EFI_ONE_OF_OPTION + // + if ((Question->Operand == EFI_IFR_ONE_OF_OP) && !IsListEmpty (&Question->OptionListHead)) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // OneOfOption could only provide Standard and Manufacturing default + // + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT) != 0)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Option->Flags & EFI_IFR_OPTION_DEFAULT_MFG) != 0)) + ) { + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + + return EFI_SUCCESS; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + } + } + + // + // EFI_IFR_CHECKBOX - lowest priority + // + if (Question->Operand == EFI_IFR_CHECKBOX_OP) { + if (DefaultId <= EFI_HII_DEFAULT_CLASS_MANUFACTURING) { + // + // Checkbox could only provide Standard and Manufacturing default + // + if (((DefaultId == EFI_HII_DEFAULT_CLASS_STANDARD) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT) != 0)) || + ((DefaultId == EFI_HII_DEFAULT_CLASS_MANUFACTURING) && ((Question->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) != 0)) + ) { + HiiValue->Value.b = TRUE; + } else { + HiiValue->Value.b = FALSE; + } + + return EFI_SUCCESS; + } + } + + // + // For Questions without default + // + switch (Question->Operand) { + case EFI_IFR_NUMERIC_OP: + // + // Take minimal value as numeric's default value + // + HiiValue->Value.u64 = Question->Minimum; + break; + + case EFI_IFR_ONE_OF_OP: + // + // Take first oneof option as oneof's default value + // + Link = GetFirstNode (&Question->OptionListHead); + if (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + CopyMem (HiiValue, &Option->Value, sizeof (EFI_HII_VALUE)); + } + break; + + case EFI_IFR_ORDERED_LIST_OP: + // + // Take option sequence in IFR as ordered list's default value + // + Index = 0; + Link = GetFirstNode (&Question->OptionListHead); + while (!IsNull (&Question->OptionListHead, Link)) { + Option = QUESTION_OPTION_FROM_LINK (Link); + + Question->BufferValue[Index] = Option->Value.Value.u8; + + Index++; + if (Index >= Question->MaxContainers) { + break; + } + + Link = GetNextNode (&Question->OptionListHead, Link); + } + break; + + default: + Status = EFI_NOT_FOUND; + break; + } + + return Status; +} + + +/** + Reset Questions in a Form to their default value. + + @param FormSet FormSet data structure. + @param Form The Form which to be reset. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + Link = GetNextNode (&Form->StatementListHead, Link); + + // + // Reset Question to its default value + // + Status = GetQuestionDefault (FormSet, Form, Question, DefaultId); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Synchronize Buffer storage's Edit buffer + // + if ((Question->Storage != NULL) && + (Question->Storage->Type != EFI_HII_VARSTORE_EFI_VARIABLE)) { + SetQuestionValue (FormSet, Form, Question, TRUE); + } + } + + return EFI_SUCCESS; +} + + +/** + Initialize Question's Edit copy from Storage. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +{ + EFI_STATUS Status; + LIST_ENTRY *Link; + FORM_BROWSER_STATEMENT *Question; + + Link = GetFirstNode (&Form->StatementListHead); + while (!IsNull (&Form->StatementListHead, Link)) { + Question = FORM_BROWSER_STATEMENT_FROM_LINK (Link); + + // + // Initialize local copy of Value for each Question + // + Status = GetQuestionValue (FormSet, Form, Question, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + Link = GetNextNode (&Form->StatementListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +{ + EFI_STATUS Status; + EFI_STRING Progress; + EFI_STRING Result; + CHAR16 *StrPtr; + + if (Storage->Type == EFI_HII_VARSTORE_EFI_VARIABLE) { + return EFI_SUCCESS; + } + + if (FormSet->ConfigAccess == NULL) { + return EFI_NOT_FOUND; + } + + if (Storage->ElementCount == 0) { + // + // Skip if there is no RequestElement + // + return EFI_SUCCESS; + } + + // + // Request current settings from Configuration Driver + // + Status = FormSet->ConfigAccess->ExtractConfig ( + FormSet->ConfigAccess, + Storage->ConfigRequest, + &Progress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert Result from to + // + StrPtr = StrStr (Result, L"ALTCFG"); + if (StrPtr != NULL) { + *StrPtr = L'\0'; + } + + Status = ConfigRespToStorage (Storage, Result); + gBS->FreePool (Result); + return Status; +} + + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + LIST_ENTRY *Link; + FORMSET_STORAGE *Storage; + FORM_BROWSER_FORM *Form; + EFI_STATUS Status; + + // + // Extract default from IFR binary + // + Link = GetFirstNode (&FormSet->FormListHead); + while (!IsNull (&FormSet->FormListHead, Link)) { + Form = FORM_BROWSER_FORM_FROM_LINK (Link); + + Status = ExtractFormDefault (FormSet, Form, EFI_HII_DEFAULT_CLASS_STANDARD); + + Link = GetNextNode (&FormSet->FormListHead, Link); + } + + // + // Request current settings from Configuration Driver + // + Link = GetFirstNode (&FormSet->StorageListHead); + while (!IsNull (&FormSet->StorageListHead, Link)) { + Storage = FORMSET_STORAGE_FROM_LINK (Link); + + Status = LoadStorage (FormSet, Storage); + + // + // Now Edit Buffer is filled with default values(lower priority) and current + // settings(higher priority), sychronize it to shadow Buffer + // + if (!EFI_ERROR (Status)) { + SynchronizeStorage (Storage); + } + + Link = GetNextNode (&FormSet->StorageListHead, Link); + } + + return EFI_SUCCESS; +} + + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +{ + EFI_STATUS Status; + EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList; + UINTN BufferSize; + UINT8 *Package; + UINT8 *OpCodeData; + UINT32 Offset; + UINT32 Offset2; + BOOLEAN ReturnDefault; + UINT32 PackageListLength; + EFI_HII_PACKAGE_HEADER PackageHeader; + + OpCodeData = NULL; + Package = NULL; + ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));; + + // + // if FormSetGuid is NULL or zero GUID, return first FormSet in the package list + // + if (FormSetGuid == NULL || CompareGuid (FormSetGuid, &gZeroGuid)) { + ReturnDefault = TRUE; + } else { + ReturnDefault = FALSE; + } + + // + // Get HII PackageList + // + BufferSize = 0; + HiiPackageList = NULL; + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + if (Status == EFI_BUFFER_TOO_SMALL) { + HiiPackageList = AllocatePool (BufferSize); + ASSERT (HiiPackageList != NULL); + + Status = mHiiDatabase->ExportPackageLists (mHiiDatabase, Handle, &BufferSize, HiiPackageList); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Form package from this HII package List + // + Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER); + Offset2 = 0; + CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32)); + + while (Offset < PackageListLength) { + Package = ((UINT8 *) HiiPackageList) + Offset; + CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER)); + + if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) { + // + // Search FormSet in this Form Package + // + Offset2 = sizeof (EFI_HII_PACKAGE_HEADER); + while (Offset2 < PackageHeader.Length) { + OpCodeData = Package + Offset2; + + if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) { + // + // Check whether return default FormSet + // + if (ReturnDefault) { + break; + } + + // + // FormSet GUID is specified, check it + // + if (CompareGuid (FormSetGuid, (EFI_GUID *)(OpCodeData + sizeof (EFI_IFR_OP_HEADER)))) { + break; + } + } + + Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length; + } + + if (Offset2 < PackageHeader.Length) { + // + // Target formset found + // + break; + } + } + + Offset += PackageHeader.Length; + } + + if (Offset >= PackageListLength) { + // + // Form package not found in this Package List + // + gBS->FreePool (HiiPackageList); + return EFI_NOT_FOUND; + } + + if (ReturnDefault && FormSetGuid != NULL) { + // + // Return the default FormSet GUID + // + CopyMem (FormSetGuid, &((EFI_IFR_FORM_SET *) OpCodeData)->Guid, sizeof (EFI_GUID)); + } + + // + // To determine the length of a whole FormSet IFR binary, one have to parse all the Opcodes + // in this FormSet; So, here just simply copy the data from start of a FormSet to the end + // of the Form Package. + // + *BinaryLength = PackageHeader.Length - Offset2; + *BinaryData = AllocateCopyPool (*BinaryLength, OpCodeData); + + gBS->FreePool (HiiPackageList); + + if (*BinaryData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + UINT16 Index; + + Status = GetIfrBinaryData (Handle, FormSetGuid, &FormSet->IfrBinaryLength, &FormSet->IfrBinaryData); + if (EFI_ERROR (Status)) { + return Status; + } + + FormSet->HiiHandle = Handle; + CopyMem (&FormSet->Guid, FormSetGuid, sizeof (EFI_GUID)); + + // + // Retrieve ConfigAccess Protocol associated with this HiiPackageList + // + Status = mHiiDatabase->GetPackageListHandle (mHiiDatabase, Handle, &DriverHandle); + if (EFI_ERROR (Status)) { + return Status; + } + FormSet->DriverHandle = DriverHandle; + Status = gBS->HandleProtocol ( + DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + (VOID **) &FormSet->ConfigAccess + ); + if (EFI_ERROR (Status)) { + // + // Configuration Driver don't attach ConfigAccess protocol to its HII package + // list, then there will be no configuration action required + // + FormSet->ConfigAccess = NULL; + } + + // + // Parse the IFR binary OpCodes + // + Status = ParseOpCodes (FormSet); + if (EFI_ERROR (Status)) { + return Status; + } + + gClassOfVfr = FormSet->SubClass; + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + FrontPageHandle = FormSet->HiiHandle; + } + + // + // Match GUID to find out the function key setting. If match fail, use the default setting. + // + for (Index = 0; Index < sizeof (gFunctionKeySettingTable) / sizeof (FUNCTIION_KEY_SETTING); Index++) { + if (CompareGuid (&FormSet->Guid, &(gFunctionKeySettingTable[Index].FormSetGuid))) { + // + // Update the function key setting. + // + gFunctionKeySetting = gFunctionKeySettingTable[Index].KeySetting; + // + // Function key prompt can not be displayed if the function key has been disabled. + // + if ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE) { + gFunctionOneString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO) { + gFunctionTwoString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE) { + gFunctionNineString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + + if ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN) { + gFunctionTenString = GetToken (STRING_TOKEN (EMPTY_STRING), gHiiHandle); + } + } + } + + return Status; +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h index 80a9d299a3..2a4eb9e80e 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Setup.h @@ -1,747 +1,1071 @@ -/** @file - -Copyright (c) 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Setup.h - -Abstract: - - -Revision History - - -**/ - -#ifndef _SETUP_H -#define _SETUP_H - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Colors.h" - -// -// This is the generated header file which includes whatever needs to be exported (strings + IFR) -// - -extern UINT8 SetupBrowserStrings[]; - -// -// Screen definitions -// -#define BANNER_HEIGHT 6 -#define BANNER_COLUMNS 3 - -#define FRONT_PAGE_HEADER_HEIGHT 6 -#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 -#define LEFT_SKIPPED_COLUMNS 4 -#define FOOTER_HEIGHT 4 -#define STATUS_BAR_HEIGHT 1 -#define SCROLL_ARROW_HEIGHT 1 -#define POPUP_PAD_SPACE_COUNT 5 -#define POPUP_FRAME_WIDTH 2 - -// -// Definition for function key setting -// -#define NONE_FUNCTION_KEY_SETTING 0 -#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_ONE | FUNCTION_TWO | FUNCTION_NINE | FUNCTION_TEN) - -#define FUNCTION_ONE (1 << 0) -#define FUNCTION_TWO (1 << 1) -#define FUNCTION_NINE (1 << 2) -#define FUNCTION_TEN (1 << 3) - -typedef struct { - EFI_GUID FormSetGuid; - UINTN KeySetting; -} FUNCTIION_KEY_SETTING; - -// -// Character definitions -// -#define CHAR_SPACE 0x0020 -#define UPPER_LOWER_CASE_OFFSET 0x20 - -// -// Time definitions -// -#define ONE_SECOND 10000000 - -// -// Display definitions -// -#define LEFT_HYPER_DELIMITER L'<' -#define RIGHT_HYPER_DELIMITER L'>' - -#define LEFT_ONEOF_DELIMITER L'<' -#define RIGHT_ONEOF_DELIMITER L'>' - -#define LEFT_NUMERIC_DELIMITER L'[' -#define RIGHT_NUMERIC_DELIMITER L']' - -#define LEFT_CHECKBOX_DELIMITER L'[' -#define RIGHT_CHECKBOX_DELIMITER L']' - -#define CHECK_ON L'X' -#define CHECK_OFF L' ' - -#define TIME_SEPARATOR L':' -#define DATE_SEPARATOR L'/' - -#define YES_ANSWER L'Y' -#define NO_ANSWER L'N' - -// -// This is the Input Error Message -// -#define INPUT_ERROR 1 - -// -// This is the NV RAM update required Message -// -#define NV_UPDATE_REQUIRED 2 - -// -// Refresh the Status Bar with flags -// -#define REFRESH_STATUS_BAR 0xff - -// -// Incremental string lenght of ConfigRequest -// -#define CONFIG_REQUEST_STRING_INCREMENTAL 1024 - -// -// HII value compare result -// -#define HII_VALUE_UNDEFINED 0 -#define HII_VALUE_EQUAL 1 -#define HII_VALUE_LESS_THAN 2 -#define HII_VALUE_GREATER_THAN 3 - -// -// Incremental size of stack for expression -// -#define EXPRESSION_STACK_SIZE_INCREMENT 0x100 - - -#define EFI_SPECIFICATION_ERRATA_VERSION 0 - -#define EFI_IFR_SPECIFICATION_VERSION \ - ((((EFI_SPECIFICATION_VERSION) >> 8) & 0xff00) | \ - (((EFI_SPECIFICATION_VERSION) & 0xf) << 4) | \ - ((EFI_SPECIFICATION_ERRATA_VERSION) & 0xf)) - -#define SETUP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('F', 'B', 'D', 'V') -typedef struct { - UINT32 Signature; - - EFI_HANDLE Handle; - - // - // Produced protocol - // - EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; - EFI_PRINT_PROTOCOL Print; - -} SETUP_DRIVER_PRIVATE_DATA; - -typedef struct { - EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; -} BANNER_DATA; - -// -// IFR relative definition -// -#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 -#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 -#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 -#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 -#define EFI_HII_EXPRESSION_DISABLE_IF 4 -#define EFI_HII_EXPRESSION_VALUE 5 -#define EFI_HII_EXPRESSION_RULE 6 - -#define EFI_HII_VARSTORE_BUFFER 0 -#define EFI_HII_VARSTORE_NAME_VALUE 1 -#define EFI_HII_VARSTORE_EFI_VARIABLE 2 - -#define FORM_INCONSISTENT_VALIDATION 0 -#define FORM_NO_SUBMIT_VALIDATION 1 - -typedef struct { - UINT8 Type; - EFI_IFR_TYPE_VALUE Value; -} EFI_HII_VALUE; - -#define NAME_VALUE_NODE_SIGNATURE EFI_SIGNATURE_32 ('N', 'V', 'S', 'T') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - CHAR16 *Name; - CHAR16 *Value; - CHAR16 *EditValue; -} NAME_VALUE_NODE; - -#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE) - -#define FORMSET_STORAGE_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'G') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT8 Type; // Storage type - - UINT16 VarStoreId; - EFI_GUID Guid; - - CHAR16 *Name; // For EFI_IFR_VARSTORE - UINT16 Size; - UINT8 *Buffer; - UINT8 *EditBuffer; // Edit copy for Buffer Storage - - LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE - - UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute - - CHAR16 *ConfigHdr; // - CHAR16 *ConfigRequest; // = + - UINTN ElementCount; // Number of in the - UINTN SpareStrLen; // Spare length of ConfigRequest string buffer -} FORMSET_STORAGE; - -#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) - -#define EXPRESSION_OPCODE_SIGNATURE EFI_SIGNATURE_32 ('E', 'X', 'O', 'P') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT8 Operand; - - UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND - UINT8 Flags; // For EFI_IFR_SPAN - UINT8 RuleId; // For EFI_IFR_RULE_REF - - EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1 - - EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_LIST, EFI_IFR_QUESTION_REF1 - EFI_QUESTION_ID QuestionId2; - - UINT16 ListLength; // For EFI_IFR_EQ_ID_LIST - UINT16 *ValueList; - - EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3 - EFI_GUID Guid; -} EXPRESSION_OPCODE; - -#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE) - -#define FORM_EXPRESSION_SIGNATURE EFI_SIGNATURE_32 ('F', 'E', 'X', 'P') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT8 Type; // Type for this expression - - UINT8 RuleId; // For EFI_IFR_RULE only - EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only - - EFI_HII_VALUE Result; // Expression evaluation result - - LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE) -} FORM_EXPRESSION; - -#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE) - -#define QUESTION_DEFAULT_SIGNATURE EFI_SIGNATURE_32 ('Q', 'D', 'F', 'T') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT16 DefaultId; - EFI_HII_VALUE Value; // Default value - - FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE -} QUESTION_DEFAULT; - -#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE) - -#define QUESTION_OPTION_SIGNATURE EFI_SIGNATURE_32 ('Q', 'O', 'P', 'T') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - EFI_STRING_ID Text; - UINT8 Flags; - EFI_HII_VALUE Value; - EFI_IMAGE_ID ImageId; - - FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf -} QUESTION_OPTION; - -#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE) - -#define FORM_BROWSER_STATEMENT_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'A') -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT8 Operand; // The operand (first byte) of this Statement or Question - - // - // Statement Header - // - EFI_STRING_ID Prompt; - EFI_STRING_ID Help; - EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT - - // - // Question Header - // - EFI_QUESTION_ID QuestionId; // The value of zero is reserved - EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage - FORMSET_STORAGE *Storage; - union { - EFI_STRING_ID VarName; - UINT16 VarOffset; - } VarStoreInfo; - UINT16 StorageWidth; - UINT8 QuestionFlags; - CHAR16 *VariableName; // Name/Value or EFI Variable name - CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..." - - EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof - UINT8 *BufferValue; // Edit copy for string, password, orderedlist - - // - // OpCode specific members - // - UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF, - // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER - UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST - - UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number - EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed - - UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value - UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length - UINT64 Step; - - EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON - EFI_FORM_ID RefFormId; // for EFI_IFR_REF - EFI_QUESTION_ID RefQuestionId; // for EFI_IFR_REF2 - EFI_GUID RefFormSetId; // for EFI_IFR_REF3 - EFI_STRING_ID RefDevicePath; // for EFI_IFR_REF4 - - // - // Get from IFR parsing - // - FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly - LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values - LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) - - EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE - UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh - BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE - - LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION) - LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION) - FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf - FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf - -} FORM_BROWSER_STATEMENT; - -#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE) - -#define FORM_BROWSER_FORM_SIGNATURE EFI_SIGNATURE_32 ('F', 'F', 'R', 'M') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT16 FormId; - EFI_STRING_ID FormTitle; - - EFI_IMAGE_ID ImageId; - - LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) - LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) -} FORM_BROWSER_FORM; - -#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE) - -#define FORMSET_DEFAULTSTORE_SIGNATURE EFI_SIGNATURE_32 ('F', 'D', 'F', 'S') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - UINT16 DefaultId; - EFI_STRING_ID DefaultName; -} FORMSET_DEFAULTSTORE; - -#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) - -typedef struct { - EFI_HII_HANDLE HiiHandle; - EFI_HANDLE DriverHandle; - EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - - UINTN IfrBinaryLength; - UINT8 *IfrBinaryData; - - EFI_GUID Guid; - EFI_STRING_ID FormSetTitle; - EFI_STRING_ID Help; - UINT16 Class; - UINT16 SubClass; - EFI_IMAGE_ID ImageId; - - FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions - EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode - - LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) - LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) - LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) -} FORM_BROWSER_FORMSET; - - -extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; -extern EFI_HII_STRING_PROTOCOL *mHiiString; -extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; - -extern BANNER_DATA *BannerData; -extern EFI_HII_HANDLE FrontPageHandle; -extern UINTN gClassOfVfr; -extern UINTN gFunctionKeySetting; -extern BOOLEAN gResetRequired; -extern BOOLEAN gNvUpdateRequired; -extern EFI_HII_HANDLE gHiiHandle; -extern BOOLEAN gFirstIn; -extern UINT16 gDirection; -extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; -extern BOOLEAN gUpArrow; -extern BOOLEAN gDownArrow; - -// -// Browser Global Strings -// -extern CHAR16 *gFunctionOneString; -extern CHAR16 *gFunctionTwoString; -extern CHAR16 *gFunctionNineString; -extern CHAR16 *gFunctionTenString; -extern CHAR16 *gEnterString; -extern CHAR16 *gEnterCommitString; -extern CHAR16 *gEscapeString; -extern CHAR16 *gSaveFailed; -extern CHAR16 *gMoveHighlight; -extern CHAR16 *gMakeSelection; -extern CHAR16 *gDecNumericInput; -extern CHAR16 *gHexNumericInput; -extern CHAR16 *gToggleCheckBox; -extern CHAR16 *gPromptForData; -extern CHAR16 *gPromptForPassword; -extern CHAR16 *gPromptForNewPassword; -extern CHAR16 *gConfirmPassword; -extern CHAR16 *gConfirmError; -extern CHAR16 *gPassowordInvalid; -extern CHAR16 *gPressEnter; -extern CHAR16 *gEmptyString; -extern CHAR16 *gAreYouSure; -extern CHAR16 *gYesResponse; -extern CHAR16 *gNoResponse; -extern CHAR16 *gMiniString; -extern CHAR16 *gPlusString; -extern CHAR16 *gMinusString; -extern CHAR16 *gAdjustNumber; - -extern CHAR16 gPromptBlockWidth; -extern CHAR16 gOptionBlockWidth; -extern CHAR16 gHelpBlockWidth; - -extern EFI_GUID gZeroGuid; -extern EFI_GUID gTianoHiiIfrGuid; - -// -// Global Procedure Defines -// -VOID -InitializeBrowserStrings ( - VOID - ) -; - -UINTN -_Print ( - IN CHAR16 *fmt, - ... - ) -; - -UINTN -PrintString ( - CHAR16 *String - ) -; - -UINTN -PrintChar ( - CHAR16 Character - ) -; - -UINTN -PrintAt ( - IN UINTN Column, - IN UINTN Row, - IN CHAR16 *fmt, - ... - ) -; - -UINTN -PrintStringAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 *String - ) -; - -UINTN -PrintCharAt ( - IN UINTN Column, - IN UINTN Row, - CHAR16 Character - ) -; - -EFI_STATUS -ParseOpCodes ( - IN FORM_BROWSER_FORMSET *FormSet - ) -; - -VOID -DestroyFormSet ( - IN OUT FORM_BROWSER_FORMSET *FormSet - ) -; - -VOID -DisplayPageFrame ( - VOID - ) -; - -EFI_STRING_ID -NewString ( - IN CHAR16 *String, - IN EFI_HII_HANDLE HiiHandle - ) -; - -EFI_STATUS -DeleteString ( - IN EFI_STRING_ID StringId, - IN EFI_HII_HANDLE HiiHandle - ) -; -CHAR16 * -GetToken ( - IN EFI_STRING_ID Token, - IN EFI_HII_HANDLE HiiHandle - ) -; - -VOID -CreateSharedPopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - IN CHAR16 **ArrayOfStrings - ) -; - -EFI_STATUS -CreateDialog ( - IN UINTN NumberOfLines, - IN BOOLEAN HotKey, - IN UINTN MaximumStringSize, - OUT CHAR16 *StringBuffer, - OUT EFI_INPUT_KEY *KeyValue, - IN CHAR16 *String, - ... - ) -; - -EFI_STATUS -GetQuestionValue ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_BROWSER_STATEMENT *Question, - IN BOOLEAN Cached - ) -; - -EFI_STATUS -SetQuestionValue ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_BROWSER_STATEMENT *Question, - IN BOOLEAN Cached - ) -; - -EFI_STATUS -ValidateQuestion ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Question, - IN UINTN Type - ) -; - -EFI_STATUS -SubmitForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -; - -EFI_STATUS -GetQuestionDefault ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN FORM_BROWSER_STATEMENT *Question, - IN UINT16 DefaultId - ) -; - -EFI_STATUS -InitializeCurrentSetting ( - IN OUT FORM_BROWSER_FORMSET *FormSet - ) -; - -EFI_STATUS -InitializeFormSet ( - IN EFI_HII_HANDLE Handle, - IN OUT EFI_GUID *FormSetGuid, - OUT FORM_BROWSER_FORMSET *FormSet - ) -; - -EFI_STATUS -ExtractFormDefault ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN UINT16 DefaultId - ) -; - -EFI_STATUS -LoadFormConfig ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form - ) -; - -EFI_STATUS -StorageToConfigResp ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 **ConfigResp - ) -; - -EFI_STATUS -ConfigRespToStorage ( - IN FORMSET_STORAGE *Storage, - IN CHAR16 *ConfigResp - ) -; - -EFI_STATUS -LoadStorage ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORMSET_STORAGE *Storage - ) -; - -EFI_STATUS -GetIfrBinaryData ( - IN EFI_HII_HANDLE Handle, - IN OUT EFI_GUID *FormSetGuid, - OUT UINTN *BinaryLength, - OUT UINT8 **BinaryData - ) -; - -EFI_STATUS -EFIAPI -SendForm ( - IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, - IN EFI_HII_HANDLE *Handles, - IN UINTN HandleCount, - IN EFI_GUID *FormSetGuid, OPTIONAL - IN UINT16 FormId, OPTIONAL - IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL - OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL - ) -; - -EFI_STATUS -EFIAPI -BrowserCallback ( - IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, - IN OUT UINTN *ResultsDataSize, - IN OUT EFI_STRING ResultsData, - IN BOOLEAN RetrieveData, - IN CONST EFI_GUID *VariableGuid, OPTIONAL - IN CONST CHAR16 *VariableName OPTIONAL - ) -; - -#endif +/** @file +Private MACRO, structure and function definitions for Setup Browser module. + +Copyright (c) 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#ifndef _SETUP_H_ +#define _SETUP_H_ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Colors.h" + +// +// This is the generated header file which includes whatever needs to be exported (strings + IFR) +// + +extern UINT8 SetupBrowserStrings[]; + +// +// Screen definitions +// +#define BANNER_HEIGHT 6 +#define BANNER_COLUMNS 3 + +#define FRONT_PAGE_HEADER_HEIGHT 6 +#define NONE_FRONT_PAGE_HEADER_HEIGHT 3 +#define LEFT_SKIPPED_COLUMNS 4 +#define FOOTER_HEIGHT 4 +#define STATUS_BAR_HEIGHT 1 +#define SCROLL_ARROW_HEIGHT 1 +#define POPUP_PAD_SPACE_COUNT 5 +#define POPUP_FRAME_WIDTH 2 + +// +// Definition for function key setting +// +#define NONE_FUNCTION_KEY_SETTING 0 +#define DEFAULT_FUNCTION_KEY_SETTING (FUNCTION_ONE | FUNCTION_TWO | FUNCTION_NINE | FUNCTION_TEN) + +#define FUNCTION_ONE (1 << 0) +#define FUNCTION_TWO (1 << 1) +#define FUNCTION_NINE (1 << 2) +#define FUNCTION_TEN (1 << 3) + +typedef struct { + EFI_GUID FormSetGuid; + UINTN KeySetting; +} FUNCTIION_KEY_SETTING; + +// +// Character definitions +// +#define CHAR_SPACE 0x0020 +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// Time definitions +// +#define ONE_SECOND 10000000 + +// +// Display definitions +// +#define LEFT_HYPER_DELIMITER L'<' +#define RIGHT_HYPER_DELIMITER L'>' + +#define LEFT_ONEOF_DELIMITER L'<' +#define RIGHT_ONEOF_DELIMITER L'>' + +#define LEFT_NUMERIC_DELIMITER L'[' +#define RIGHT_NUMERIC_DELIMITER L']' + +#define LEFT_CHECKBOX_DELIMITER L'[' +#define RIGHT_CHECKBOX_DELIMITER L']' + +#define CHECK_ON L'X' +#define CHECK_OFF L' ' + +#define TIME_SEPARATOR L':' +#define DATE_SEPARATOR L'/' + +#define YES_ANSWER L'Y' +#define NO_ANSWER L'N' + +// +// This is the Input Error Message +// +#define INPUT_ERROR 1 + +// +// This is the NV RAM update required Message +// +#define NV_UPDATE_REQUIRED 2 + +// +// Refresh the Status Bar with flags +// +#define REFRESH_STATUS_BAR 0xff + +// +// Incremental string lenght of ConfigRequest +// +#define CONFIG_REQUEST_STRING_INCREMENTAL 1024 + +// +// HII value compare result +// +#define HII_VALUE_UNDEFINED 0 +#define HII_VALUE_EQUAL 1 +#define HII_VALUE_LESS_THAN 2 +#define HII_VALUE_GREATER_THAN 3 + +// +// Incremental size of stack for expression +// +#define EXPRESSION_STACK_SIZE_INCREMENT 0x100 + + +#define EFI_SPECIFICATION_ERRATA_VERSION 0 + +#define EFI_IFR_SPECIFICATION_VERSION \ + ((((EFI_SPECIFICATION_VERSION) >> 8) & 0xff00) | \ + (((EFI_SPECIFICATION_VERSION) & 0xf) << 4) | \ + ((EFI_SPECIFICATION_ERRATA_VERSION) & 0xf)) + +#define SETUP_DRIVER_SIGNATURE EFI_SIGNATURE_32 ('F', 'B', 'D', 'V') +typedef struct { + UINT32 Signature; + + EFI_HANDLE Handle; + + // + // Produced protocol + // + EFI_FORM_BROWSER2_PROTOCOL FormBrowser2; + EFI_PRINT_PROTOCOL Print; + +} SETUP_DRIVER_PRIVATE_DATA; + +typedef struct { + EFI_STRING_ID Banner[BANNER_HEIGHT][BANNER_COLUMNS]; +} BANNER_DATA; + +// +// IFR relative definition +// +#define EFI_HII_EXPRESSION_INCONSISTENT_IF 0 +#define EFI_HII_EXPRESSION_NO_SUBMIT_IF 1 +#define EFI_HII_EXPRESSION_GRAY_OUT_IF 2 +#define EFI_HII_EXPRESSION_SUPPRESS_IF 3 +#define EFI_HII_EXPRESSION_DISABLE_IF 4 +#define EFI_HII_EXPRESSION_VALUE 5 +#define EFI_HII_EXPRESSION_RULE 6 + +#define EFI_HII_VARSTORE_BUFFER 0 +#define EFI_HII_VARSTORE_NAME_VALUE 1 +#define EFI_HII_VARSTORE_EFI_VARIABLE 2 + +#define FORM_INCONSISTENT_VALIDATION 0 +#define FORM_NO_SUBMIT_VALIDATION 1 + +typedef struct { + UINT8 Type; + EFI_IFR_TYPE_VALUE Value; +} EFI_HII_VALUE; + +#define NAME_VALUE_NODE_SIGNATURE EFI_SIGNATURE_32 ('N', 'V', 'S', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + CHAR16 *Name; + CHAR16 *Value; + CHAR16 *EditValue; +} NAME_VALUE_NODE; + +#define NAME_VALUE_NODE_FROM_LINK(a) CR (a, NAME_VALUE_NODE, Link, NAME_VALUE_NODE_SIGNATURE) + +#define FORMSET_STORAGE_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'G') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Storage type + + UINT16 VarStoreId; + EFI_GUID Guid; + + CHAR16 *Name; // For EFI_IFR_VARSTORE + UINT16 Size; + UINT8 *Buffer; + UINT8 *EditBuffer; // Edit copy for Buffer Storage + + LIST_ENTRY NameValueListHead; // List of NAME_VALUE_NODE + + UINT32 Attributes; // For EFI_IFR_VARSTORE_EFI: EFI Variable attribute + + CHAR16 *ConfigHdr; // + CHAR16 *ConfigRequest; // = + + UINTN ElementCount; // Number of in the + UINTN SpareStrLen; // Spare length of ConfigRequest string buffer +} FORMSET_STORAGE; + +#define FORMSET_STORAGE_FROM_LINK(a) CR (a, FORMSET_STORAGE, Link, FORMSET_STORAGE_SIGNATURE) + +#define EXPRESSION_OPCODE_SIGNATURE EFI_SIGNATURE_32 ('E', 'X', 'O', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; + + UINT8 Format; // For EFI_IFR_TO_STRING, EFI_IFR_FIND + UINT8 Flags; // For EFI_IFR_SPAN + UINT8 RuleId; // For EFI_IFR_RULE_REF + + EFI_HII_VALUE Value; // For EFI_IFR_EQ_ID_VAL, EFI_IFR_UINT64, EFI_IFR_UINT32, EFI_IFR_UINT16, EFI_IFR_UINT8, EFI_IFR_STRING_REF1 + + EFI_QUESTION_ID QuestionId; // For EFI_IFR_EQ_ID_ID, EFI_IFR_EQ_ID_LIST, EFI_IFR_QUESTION_REF1 + EFI_QUESTION_ID QuestionId2; + + UINT16 ListLength; // For EFI_IFR_EQ_ID_LIST + UINT16 *ValueList; + + EFI_STRING_ID DevicePath; // For EFI_IFR_QUESTION_REF3_2, EFI_IFR_QUESTION_REF3_3 + EFI_GUID Guid; +} EXPRESSION_OPCODE; + +#define EXPRESSION_OPCODE_FROM_LINK(a) CR (a, EXPRESSION_OPCODE, Link, EXPRESSION_OPCODE_SIGNATURE) + +#define FORM_EXPRESSION_SIGNATURE EFI_SIGNATURE_32 ('F', 'E', 'X', 'P') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Type; // Type for this expression + + UINT8 RuleId; // For EFI_IFR_RULE only + EFI_STRING_ID Error; // For EFI_IFR_NO_SUBMIT_IF, EFI_IFR_INCONSISTENT_IF only + + EFI_HII_VALUE Result; // Expression evaluation result + + LIST_ENTRY OpCodeListHead; // OpCodes consist of this expression (EXPRESSION_OPCODE) +} FORM_EXPRESSION; + +#define FORM_EXPRESSION_FROM_LINK(a) CR (a, FORM_EXPRESSION, Link, FORM_EXPRESSION_SIGNATURE) + +#define QUESTION_DEFAULT_SIGNATURE EFI_SIGNATURE_32 ('Q', 'D', 'F', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_HII_VALUE Value; // Default value + + FORM_EXPRESSION *ValueExpression; // Not-NULL indicates default value is provided by EFI_IFR_VALUE +} QUESTION_DEFAULT; + +#define QUESTION_DEFAULT_FROM_LINK(a) CR (a, QUESTION_DEFAULT, Link, QUESTION_DEFAULT_SIGNATURE) + +#define QUESTION_OPTION_SIGNATURE EFI_SIGNATURE_32 ('Q', 'O', 'P', 'T') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_STRING_ID Text; + UINT8 Flags; + EFI_HII_VALUE Value; + EFI_IMAGE_ID ImageId; + + FORM_EXPRESSION *SuppressExpression; // Non-NULL indicates nested inside of SuppressIf +} QUESTION_OPTION; + +#define QUESTION_OPTION_FROM_LINK(a) CR (a, QUESTION_OPTION, Link, QUESTION_OPTION_SIGNATURE) + +#define FORM_BROWSER_STATEMENT_SIGNATURE EFI_SIGNATURE_32 ('F', 'S', 'T', 'A') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT8 Operand; // The operand (first byte) of this Statement or Question + + // + // Statement Header + // + EFI_STRING_ID Prompt; + EFI_STRING_ID Help; + EFI_STRING_ID TextTwo; // For EFI_IFR_TEXT + + // + // Question Header + // + EFI_QUESTION_ID QuestionId; // The value of zero is reserved + EFI_VARSTORE_ID VarStoreId; // A value of zero indicates no variable storage + FORMSET_STORAGE *Storage; + union { + EFI_STRING_ID VarName; + UINT16 VarOffset; + } VarStoreInfo; + UINT16 StorageWidth; + UINT8 QuestionFlags; + CHAR16 *VariableName; // Name/Value or EFI Variable name + CHAR16 *BlockName; // Buffer storage block name: "OFFSET=...WIDTH=..." + + EFI_HII_VALUE HiiValue; // Edit copy for checkbox, numberic, oneof + UINT8 *BufferValue; // Edit copy for string, password, orderedlist + + // + // OpCode specific members + // + UINT8 Flags; // for EFI_IFR_CHECKBOX, EFI_IFR_DATE, EFI_IFR_NUMERIC, EFI_IFR_ONE_OF, + // EFI_IFR_ORDERED_LIST, EFI_IFR_STRING,EFI_IFR_SUBTITLE,EFI_IFR_TIME, EFI_IFR_BANNER + UINT8 MaxContainers; // for EFI_IFR_ORDERED_LIST + + UINT16 BannerLineNumber; // for EFI_IFR_BANNER, 1-based line number + EFI_STRING_ID QuestionConfig; // for EFI_IFR_ACTION, if 0 then no configuration string will be processed + + UINT64 Minimum; // for EFI_IFR_ONE_OF/EFI_IFR_NUMERIC, it's Min/Max value + UINT64 Maximum; // for EFI_IFR_STRING/EFI_IFR_PASSWORD, it's Min/Max length + UINT64 Step; + + EFI_DEFAULT_ID DefaultId; // for EFI_IFR_RESET_BUTTON + EFI_FORM_ID RefFormId; // for EFI_IFR_REF + EFI_QUESTION_ID RefQuestionId; // for EFI_IFR_REF2 + EFI_GUID RefFormSetId; // for EFI_IFR_REF3 + EFI_STRING_ID RefDevicePath; // for EFI_IFR_REF4 + + // + // Get from IFR parsing + // + FORM_EXPRESSION *ValueExpression; // nested EFI_IFR_VALUE, provide Question value and indicate Question is ReadOnly + LIST_ENTRY DefaultListHead; // nested EFI_IFR_DEFAULT list (QUESTION_DEFAULT), provide default values + LIST_ENTRY OptionListHead; // nested EFI_IFR_ONE_OF_OPTION list (QUESTION_OPTION) + + EFI_IMAGE_ID ImageId; // nested EFI_IFR_IMAGE + UINT8 RefreshInterval; // nested EFI_IFR_REFRESH, refresh interval(in seconds) for Question value, 0 means no refresh + BOOLEAN InSubtitle; // nesting inside of EFI_IFR_SUBTITLE + + LIST_ENTRY InconsistentListHead;// nested inconsistent expression list (FORM_EXPRESSION) + LIST_ENTRY NoSubmitListHead; // nested nosubmit expression list (FORM_EXPRESSION) + FORM_EXPRESSION *GrayOutExpression; // nesting inside of GrayOutIf + FORM_EXPRESSION *SuppressExpression; // nesting inside of SuppressIf + +} FORM_BROWSER_STATEMENT; + +#define FORM_BROWSER_STATEMENT_FROM_LINK(a) CR (a, FORM_BROWSER_STATEMENT, Link, FORM_BROWSER_STATEMENT_SIGNATURE) + +#define FORM_BROWSER_FORM_SIGNATURE EFI_SIGNATURE_32 ('F', 'F', 'R', 'M') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 FormId; + EFI_STRING_ID FormTitle; + + EFI_IMAGE_ID ImageId; + + LIST_ENTRY ExpressionListHead; // List of Expressions (FORM_EXPRESSION) + LIST_ENTRY StatementListHead; // List of Statements and Questions (FORM_BROWSER_STATEMENT) +} FORM_BROWSER_FORM; + +#define FORM_BROWSER_FORM_FROM_LINK(a) CR (a, FORM_BROWSER_FORM, Link, FORM_BROWSER_FORM_SIGNATURE) + +#define FORMSET_DEFAULTSTORE_SIGNATURE EFI_SIGNATURE_32 ('F', 'D', 'F', 'S') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + UINT16 DefaultId; + EFI_STRING_ID DefaultName; +} FORMSET_DEFAULTSTORE; + +#define FORMSET_DEFAULTSTORE_FROM_LINK(a) CR (a, FORMSET_DEFAULTSTORE, Link, FORMSET_DEFAULTSTORE_SIGNATURE) + +typedef struct { + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + UINTN IfrBinaryLength; + UINT8 *IfrBinaryData; + + EFI_GUID Guid; + EFI_STRING_ID FormSetTitle; + EFI_STRING_ID Help; + UINT16 Class; + UINT16 SubClass; + EFI_IMAGE_ID ImageId; + + FORM_BROWSER_STATEMENT *StatementBuffer; // Buffer for all Statements and Questions + EXPRESSION_OPCODE *ExpressionBuffer; // Buffer for all Expression OpCode + + LIST_ENTRY StorageListHead; // Storage list (FORMSET_STORAGE) + LIST_ENTRY DefaultStoreListHead; // DefaultStore list (FORMSET_DEFAULTSTORE) + LIST_ENTRY FormListHead; // Form list (FORM_BROWSER_FORM) +} FORM_BROWSER_FORMSET; + + +extern EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; +extern EFI_HII_STRING_PROTOCOL *mHiiString; +extern EFI_HII_CONFIG_ROUTING_PROTOCOL *mHiiConfigRouting; + +extern BANNER_DATA *BannerData; +extern EFI_HII_HANDLE FrontPageHandle; +extern UINTN gClassOfVfr; +extern UINTN gFunctionKeySetting; +extern BOOLEAN gResetRequired; +extern BOOLEAN gNvUpdateRequired; +extern EFI_HII_HANDLE gHiiHandle; +extern BOOLEAN gFirstIn; +extern UINT16 gDirection; +extern EFI_SCREEN_DESCRIPTOR gScreenDimensions; +extern BOOLEAN gUpArrow; +extern BOOLEAN gDownArrow; + +// +// Browser Global Strings +// +extern CHAR16 *gFunctionOneString; +extern CHAR16 *gFunctionTwoString; +extern CHAR16 *gFunctionNineString; +extern CHAR16 *gFunctionTenString; +extern CHAR16 *gEnterString; +extern CHAR16 *gEnterCommitString; +extern CHAR16 *gEscapeString; +extern CHAR16 *gSaveFailed; +extern CHAR16 *gMoveHighlight; +extern CHAR16 *gMakeSelection; +extern CHAR16 *gDecNumericInput; +extern CHAR16 *gHexNumericInput; +extern CHAR16 *gToggleCheckBox; +extern CHAR16 *gPromptForData; +extern CHAR16 *gPromptForPassword; +extern CHAR16 *gPromptForNewPassword; +extern CHAR16 *gConfirmPassword; +extern CHAR16 *gConfirmError; +extern CHAR16 *gPassowordInvalid; +extern CHAR16 *gPressEnter; +extern CHAR16 *gEmptyString; +extern CHAR16 *gAreYouSure; +extern CHAR16 *gYesResponse; +extern CHAR16 *gNoResponse; +extern CHAR16 *gMiniString; +extern CHAR16 *gPlusString; +extern CHAR16 *gMinusString; +extern CHAR16 *gAdjustNumber; + +extern CHAR16 gPromptBlockWidth; +extern CHAR16 gOptionBlockWidth; +extern CHAR16 gHelpBlockWidth; + +extern EFI_GUID gZeroGuid; +extern EFI_GUID gTianoHiiIfrGuid; + +// +// Global Procedure Defines +// + +/** + Initialize the HII String Token to the correct values. + +**/ +VOID +InitializeBrowserStrings ( + VOID + ) +; + +/** + Prints a unicode string to the default console, + using L"%s" format. + + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintString ( + IN CHAR16 *String + ) +; + +/** + Prints a chracter to the default console, + using L"%c" format. + + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintChar ( + CHAR16 Character + ) +; + +/** + Prints a formatted unicode string to the default console, at + the supplied cursor position. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at + @param Fmt Format string + @param ... Variable argument list for formating string. + + @return Length of string printed to the console + +**/ +UINTN +PrintAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *Fmt, + ... + ) +; + +/** + Prints a unicode string to the default console, at + the supplied cursor position, using L"%s" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at + @param String String pointer. + + @return Length of string printed to the console + +**/ +UINTN +PrintStringAt ( + IN UINTN Column, + IN UINTN Row, + IN CHAR16 *String + ) +; + +/** + Prints a chracter to the default console, at + the supplied cursor position, using L"%c" format. + + @param Column The cursor position to print the string at. + @param Row The cursor position to print the string at. + @param Character Character to print. + + @return Length of string printed to the console. + +**/ +UINTN +PrintCharAt ( + IN UINTN Column, + IN UINTN Row, + CHAR16 Character + ) +; + +/** + Parse opcodes in the formset IFR binary. + + @param FormSet Pointer of the FormSet data structure. + + @retval EFI_SUCCESS Opcode parse success. + @retval Other Opcode parse fail. + +**/ +EFI_STATUS +ParseOpCodes ( + IN FORM_BROWSER_FORMSET *FormSet + ) +; + +/** + Free resources allocated for a FormSet. + + @param FormSet Pointer of the FormSet + +**/ +VOID +DestroyFormSet ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +/** + This function displays the page frame. + +**/ +VOID +DisplayPageFrame ( + VOID + ) +; + +/** + Create a new string in HII Package List. + + @param String The String to be added + @param HiiHandle The package list in the HII database to insert the + specified string. + + @return The output string. + +**/ +EFI_STRING_ID +NewString ( + IN CHAR16 *String, + IN EFI_HII_HANDLE HiiHandle + ) +; + +/** + Delete a string from HII Package List. + + @param StringId Id of the string in HII database. + @param HiiHandle The HII package list handle. + + @retval EFI_SUCCESS The string was deleted successfully. + +**/ +EFI_STATUS +DeleteString ( + IN EFI_STRING_ID StringId, + IN EFI_HII_HANDLE HiiHandle + ) +; + +/** + Get the string based on the StringId and HII Package List Handle. + + @param Token The String's ID. + @param HiiHandle The package list in the HII database to search for + the specified string. + + @return The output string. + +**/ +CHAR16 * +GetToken ( + IN EFI_STRING_ID Token, + IN EFI_HII_HANDLE HiiHandle + ) +; + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ArrayOfStrings The array of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +; + +/** + Routine used to abstract a generic dialog interface and return the selected key or string + + @param NumberOfLines The number of lines for the dialog box + @param HotKey Defines whether a single character is parsed + (TRUE) and returned in KeyValue or a string is + returned in StringBuffer. Two special characters + are considered when entering a string, a SCAN_ESC + and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates + string input and returns + @param MaximumStringSize The maximum size in bytes of a typed in string + (each character is a CHAR16) and the minimum + string returned is two bytes + @param StringBuffer The passed in pointer to the buffer which will + hold the typed in string if HotKey is FALSE + @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. + @param String Pointer to the first string in the list + @param ... A series of (quantity == NumberOfLines) text + strings which will be used to construct the dialog + box + + @retval EFI_SUCCESS Displayed dialog and received user interaction + @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. + (StringBuffer == NULL) && (HotKey == FALSE)) + @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine + +**/ +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +; + +/** + Get Question's current Value. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Question to be initialized. + @param Cached TRUE: get from Edit copy FALSE: get from original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +GetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +/** + Save Question Value to edit copy(cached) or Storage(uncached). + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question Pointer to the Question. + @param Cached TRUE: set to Edit copy FALSE: set to original + Storage + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SetQuestionValue ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_BROWSER_STATEMENT *Question, + IN BOOLEAN Cached + ) +; + +/** + Perform inconsistent check for a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + @param Question The Question to be validated. + @param Type Validation type: InConsistent or NoSubmit + + @retval EFI_SUCCESS Form validation pass. + @retval other Form validation failed. + +**/ +EFI_STATUS +ValidateQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINTN Type + ) +; + +/** + Submit a Form. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +SubmitForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +/** + Reset Question to its default value. + + @param FormSet The form set. + @param Form The form. + @param Question The question. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS Question is reset to default value. + +**/ +EFI_STATUS +GetQuestionDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN FORM_BROWSER_STATEMENT *Question, + IN UINT16 DefaultId + ) +; + +/** + Get current setting of Questions. + + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +InitializeCurrentSetting ( + IN OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +/** + Initialize the internal data structure of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param FormSet FormSet data structure. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The specified FormSet could not be found. + +**/ +EFI_STATUS +InitializeFormSet ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT FORM_BROWSER_FORMSET *FormSet + ) +; + +/** + Reset Questions in a Form to their default value. + + @param FormSet FormSet data structure. + @param Form The Form which to be reset. + @param DefaultId The Class of the default. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +ExtractFormDefault ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 DefaultId + ) +; + +/** + Initialize Question's Edit copy from Storage. + + @param FormSet FormSet data structure. + @param Form Form data structure. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadFormConfig ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form + ) +; + +/** + Convert setting of Buffer Storage or NameValue Storage to . + + @param Storage The Storage to be conveted. + @param ConfigResp The returned . + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +StorageToConfigResp ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 **ConfigResp + ) +; + +/** + Convert to settings in Buffer Storage or NameValue Storage. + + @param Storage The Storage to receive the settings. + @param ConfigResp The to be converted. + + @retval EFI_SUCCESS Convert success. + @retval EFI_INVALID_PARAMETER Incorrect storage type. + +**/ +EFI_STATUS +ConfigRespToStorage ( + IN FORMSET_STORAGE *Storage, + IN CHAR16 *ConfigResp + ) +; + +/** + Fill storage's edit copy with settings requested from Configuration Driver. + + @param FormSet FormSet data structure. + @param Storage Buffer Storage. + + @retval EFI_SUCCESS The function completed successfully. + +**/ +EFI_STATUS +LoadStorage ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORMSET_STORAGE *Storage + ) +; + +/** + Fetch the Ifr binary data of a FormSet. + + @param Handle PackageList Handle + @param FormSetGuid GUID of a formset. If not specified (NULL or zero + GUID), take the first FormSet found in package + list. + @param BinaryLength The length of the FormSet IFR binary. + @param BinaryData The buffer designed to receive the FormSet. + + @retval EFI_SUCCESS Buffer filled with the requested FormSet. + BufferLength was updated. + @retval EFI_INVALID_PARAMETER The handle is unknown. + @retval EFI_NOT_FOUND A form or FormSet on the requested handle cannot + be found with the requested FormId. + +**/ +EFI_STATUS +GetIfrBinaryData ( + IN EFI_HII_HANDLE Handle, + IN OUT EFI_GUID *FormSetGuid, + OUT UINTN *BinaryLength, + OUT UINT8 **BinaryData + ) +; + +/** + This is the routine which an external caller uses to direct the browser + where to obtain it's information. + + + @param This The Form Browser protocol instanse. + @param Handles A pointer to an array of Handles. If HandleCount > 1 we + display a list of the formsets for the handles specified. + @param HandleCount The number of Handles specified in Handle. + @param FormSetGuid This field points to the EFI_GUID which must match the Guid + field in the EFI_IFR_FORM_SET op-code for the specified + forms-based package. If FormSetGuid is NULL, then this + function will display the first found forms package. + @param FormId This field specifies which EFI_IFR_FORM to render as the first + displayable page. If this field has a value of 0x0000, then + the forms browser will render the specified forms in their encoded order. + ScreenDimenions - This allows the browser to be called so that it occupies a + portion of the physical screen instead of dynamically determining the screen dimensions. + ActionRequest - Points to the action recommended by the form. + @param ScreenDimensions Points to recommended form dimensions, including any non-content area, in + characters. + @param ActionRequest Points to the action recommended by the form. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_NOT_FOUND No valid forms could be found to display. + +**/ +EFI_STATUS +EFIAPI +SendForm ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN EFI_HII_HANDLE *Handles, + IN UINTN HandleCount, + IN EFI_GUID *FormSetGuid, OPTIONAL + IN UINT16 FormId, OPTIONAL + IN CONST EFI_SCREEN_DESCRIPTOR *ScreenDimensions, OPTIONAL + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest OPTIONAL + ) +; + +/** + This function is called by a callback handler to retrieve uncommitted state + data from the browser. + + @param This A pointer to the EFI_FORM_BROWSER2_PROTOCOL + instance. + @param ResultsDataSize A pointer to the size of the buffer associated + with ResultsData. + @param ResultsData A string returned from an IFR browser or + equivalent. The results string will have no + routing information in them. + @param RetrieveData A BOOLEAN field which allows an agent to retrieve + (if RetrieveData = TRUE) data from the uncommitted + browser state information or set (if RetrieveData + = FALSE) data in the uncommitted browser state + information. + @param VariableGuid An optional field to indicate the target variable + GUID name to use. + @param VariableName An optional field to indicate the target + human-readable variable name. + + @retval EFI_SUCCESS The results have been distributed or are awaiting + distribution. + @retval EFI_BUFFER_TOO_SMALL The ResultsDataSize specified was too small to + contain the results data. + +**/ +EFI_STATUS +EFIAPI +BrowserCallback ( + IN CONST EFI_FORM_BROWSER2_PROTOCOL *This, + IN OUT UINTN *ResultsDataSize, + IN OUT EFI_STRING ResultsData, + IN BOOLEAN RetrieveData, + IN CONST EFI_GUID *VariableGuid, OPTIONAL + IN CONST CHAR16 *VariableName OPTIONAL + ) +; + +#endif diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c index 04b9f69303..a66e946475 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.c @@ -1,2874 +1,2858 @@ -/** @file - -Copyright (c) 2004 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Ui.c - -Abstract: - - Implementation for UI. - -Revision History - - -**/ - -#include "Ui.h" -#include "Setup.h" - -LIST_ENTRY Menu; -LIST_ENTRY gMenuList; -MENU_REFRESH_ENTRY *gMenuRefreshHead; - -// -// Search table for UiDisplayMenu() -// -SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { - { - SCAN_UP, - UiUp, - }, - { - SCAN_DOWN, - UiDown, - }, - { - SCAN_PAGE_UP, - UiPageUp, - }, - { - SCAN_PAGE_DOWN, - UiPageDown, - }, - { - SCAN_ESC, - UiReset, - }, - { - SCAN_F2, - UiPrevious, - }, - { - SCAN_LEFT, - UiLeft, - }, - { - SCAN_RIGHT, - UiRight, - }, - { - SCAN_F9, - UiDefault, - }, - { - SCAN_F10, - UiSave - } -}; - -SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { - { - UiNoOperation, - CfUiNoOperation, - }, - { - UiDefault, - CfUiDefault, - }, - { - UiSelect, - CfUiSelect, - }, - { - UiUp, - CfUiUp, - }, - { - UiDown, - CfUiDown, - }, - { - UiLeft, - CfUiLeft, - }, - { - UiRight, - CfUiRight, - }, - { - UiReset, - CfUiReset, - }, - { - UiSave, - CfUiSave, - }, - { - UiPrevious, - CfUiPrevious, - }, - { - UiPageUp, - CfUiPageUp, - }, - { - UiPageDown, - CfUiPageDown - } -}; - - -/** - Set Buffer to Value for Size bytes. - - @param Buffer Memory to set. - @param Size Number of bytes to set - @param Value Value of the set operation. - - @return None - -**/ -VOID -SetUnicodeMem ( - IN VOID *Buffer, - IN UINTN Size, - IN CHAR16 Value - ) -{ - CHAR16 *Ptr; - - Ptr = Buffer; - while (Size--) { - *(Ptr++) = Value; - } -} - - -/** - Initialize Menu option list. - - None. - - @return None. - -**/ -VOID -UiInitMenu ( - VOID - ) -{ - InitializeListHead (&Menu); -} - - -/** - Initialize Menu option list. - - None. - - @return None. - -**/ -VOID -UiInitMenuList ( - VOID - ) -{ - InitializeListHead (&gMenuList); -} - - -/** - Remove a Menu in list, and return FormId/QuestionId for previous Menu. - - @param Selection Menu selection. - - @return None. - -**/ -VOID -UiRemoveMenuListEntry ( - IN OUT UI_MENU_SELECTION *Selection - ) -{ - UI_MENU_LIST *UiMenuList; - - if (!IsListEmpty (&gMenuList)) { - UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); - - Selection->FormId = UiMenuList->FormId; - Selection->QuestionId = UiMenuList->QuestionId; - RemoveEntryList (&UiMenuList->MenuLink); - gBS->FreePool (UiMenuList); - } -} - - -/** - Free Menu option linked list. - - None. - - @return None. - -**/ -VOID -UiFreeMenuList ( - VOID - ) -{ - UI_MENU_LIST *UiMenuList; - - while (!IsListEmpty (&gMenuList)) { - UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); - RemoveEntryList (&UiMenuList->MenuLink); - gBS->FreePool (UiMenuList); - } -} - - -/** - Add one menu entry to the linked lst - - @param Selection Menu selection. - - @return None. - -**/ -VOID -UiAddMenuListEntry ( - IN UI_MENU_SELECTION *Selection - ) -{ - UI_MENU_LIST *UiMenuList; - - UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); - ASSERT (UiMenuList != NULL); - - UiMenuList->Signature = UI_MENU_LIST_SIGNATURE; - UiMenuList->FormId = Selection->FormId; - UiMenuList->QuestionId = Selection->QuestionId; - - InsertHeadList (&gMenuList, &UiMenuList->MenuLink); -} - - -/** - Free Menu option linked list. - - None. - - @return None. - -**/ -VOID -UiFreeMenu ( - VOID - ) -{ - UI_MENU_OPTION *MenuOption; - - while (!IsListEmpty (&Menu)) { - MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink); - RemoveEntryList (&MenuOption->Link); - - // - // We allocated space for this description when we did a GetToken, free it here - // - if (MenuOption->Skip != 0) { - // - // For date/time, MenuOption->Description is shared by three Menu Options - // Data format : [01/02/2004] [11:22:33] - // Line number : 0 0 1 0 0 1 - // - gBS->FreePool (MenuOption->Description); - } - gBS->FreePool (MenuOption); - } -} - - -/** - Free Menu option linked list. - - None. - - @return None. - -**/ -VOID -UiFreeRefreshList ( - VOID - ) -{ - MENU_REFRESH_ENTRY *OldMenuRefreshEntry; - - while (gMenuRefreshHead != NULL) { - OldMenuRefreshEntry = gMenuRefreshHead->Next; - gBS->FreePool (gMenuRefreshHead); - gMenuRefreshHead = OldMenuRefreshEntry; - } - - gMenuRefreshHead = NULL; -} - - - -/** - Refresh screen. - - None. - - @return None. - -**/ -VOID -RefreshForm ( - VOID - ) -{ - CHAR16 *OptionString; - MENU_REFRESH_ENTRY *MenuRefreshEntry; - UINTN Index; - UINTN Loop; - EFI_STATUS Status; - UI_MENU_SELECTION *Selection; - FORM_BROWSER_STATEMENT *Question; - - OptionString = NULL; - - if (gMenuRefreshHead != NULL) { - - MenuRefreshEntry = gMenuRefreshHead; - - do { - gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); - - Selection = MenuRefreshEntry->Selection; - Question = MenuRefreshEntry->MenuOption->ThisTag; - - // - // Don't update Question being edited - // - if (Question != MenuRefreshEntry->Selection->Statement) { - - Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); - if (EFI_ERROR (Status)) { - return; - } - - ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString); - - if (OptionString != NULL) { - // - // If leading spaces on OptionString - remove the spaces - // - for (Index = 0; OptionString[Index] == L' '; Index++) - ; - - for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { - OptionString[Loop] = OptionString[Index]; - Loop++; - } - - OptionString[Loop] = CHAR_NULL; - - PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); - gBS->FreePool (OptionString); - } - } - - MenuRefreshEntry = MenuRefreshEntry->Next; - - } while (MenuRefreshEntry != NULL); - } -} - - -/** - Wait for a given event to fire, or for an optional timeout to expire. - - @param Event The event to wait for - @param Timeout An optional timeout value in 100 ns units. - @param RefreshInterval Menu refresh interval (in seconds). - - @retval EFI_SUCCESS Event fired before Timeout expired. - @retval EFI_TIME_OUT Timout expired before Event fired. - -**/ -EFI_STATUS -UiWaitForSingleEvent ( - IN EFI_EVENT Event, - IN UINT64 Timeout, OPTIONAL - IN UINT8 RefreshInterval OPTIONAL - ) -{ - EFI_STATUS Status; - UINTN Index; - EFI_EVENT TimerEvent; - EFI_EVENT WaitList[2]; - - if (Timeout) { - // - // Create a timer event - // - Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); - if (!EFI_ERROR (Status)) { - // - // Set the timer event - // - gBS->SetTimer ( - TimerEvent, - TimerRelative, - Timeout - ); - - // - // Wait for the original event or the timer - // - WaitList[0] = Event; - WaitList[1] = TimerEvent; - Status = gBS->WaitForEvent (2, WaitList, &Index); - gBS->CloseEvent (TimerEvent); - - // - // If the timer expired, change the return to timed out - // - if (!EFI_ERROR (Status) && Index == 1) { - Status = EFI_TIMEOUT; - } - } - } else { - // - // Update screen every second - // - if (RefreshInterval == 0) { - Timeout = ONE_SECOND; - } else { - Timeout = RefreshInterval * ONE_SECOND; - } - - do { - Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); - - // - // Set the timer event - // - gBS->SetTimer ( - TimerEvent, - TimerRelative, - Timeout - ); - - // - // Wait for the original event or the timer - // - WaitList[0] = Event; - WaitList[1] = TimerEvent; - Status = gBS->WaitForEvent (2, WaitList, &Index); - - // - // If the timer expired, update anything that needs a refresh and keep waiting - // - if (!EFI_ERROR (Status) && Index == 1) { - Status = EFI_TIMEOUT; - if (RefreshInterval != 0) { - RefreshForm (); - } - } - - gBS->CloseEvent (TimerEvent); - } while (Status == EFI_TIMEOUT); - } - - return Status; -} - - -/** - Add one menu option by specified description and context. - - @param String String description for this option. - @param Handle Hii handle for the package list. - @param Statement Statement of this Menu Option. - @param NumberOfLines Display lines for this Menu Option. - @param MenuItemCount The index for this Option in the Menu. - - @return None. - -**/ -VOID -UiAddMenuOption ( - IN CHAR16 *String, - IN EFI_HII_HANDLE Handle, - IN FORM_BROWSER_STATEMENT *Statement, - IN UINT16 NumberOfLines, - IN UINT16 MenuItemCount - ) -{ - UI_MENU_OPTION *MenuOption; - UINTN Index; - UINTN Count; - - Count = 1; - - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - // - // Add three MenuOptions for Date/Time - // Data format : [01/02/2004] [11:22:33] - // Line number : 0 0 1 0 0 1 - // - NumberOfLines = 0; - Count = 3; - - if (Statement->Storage == NULL) { - // - // For RTC type of date/time, set default refresh interval to be 1 second - // - if (Statement->RefreshInterval == 0) { - Statement->RefreshInterval = 1; - } - } - } - - for (Index = 0; Index < Count; Index++) { - MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); - ASSERT (MenuOption); - - MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; - MenuOption->Description = String; - MenuOption->Handle = Handle; - MenuOption->ThisTag = Statement; - MenuOption->EntryNumber = MenuItemCount; - - if (Index == 2) { - // - // Override LineNumber for the MenuOption in Date/Time sequence - // - MenuOption->Skip = 1; - } else { - MenuOption->Skip = NumberOfLines; - } - MenuOption->Sequence = Index; - - if (Statement->GrayOutExpression != NULL) { - MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b; - } - - if ((Statement->ValueExpression != NULL) || - (Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY)) { - MenuOption->ReadOnly = TRUE; - } - - InsertTailList (&Menu, &MenuOption->Link); - } -} - - -/** - Routine used to abstract a generic dialog interface and return the selected key or string - - @param NumberOfLines The number of lines for the dialog box - @param HotKey Defines whether a single character is parsed - (TRUE) and returned in KeyValue or a string is - returned in StringBuffer. Two special characters - are considered when entering a string, a SCAN_ESC - and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates - string input and returns - @param MaximumStringSize The maximum size in bytes of a typed in string - (each character is a CHAR16) and the minimum - string returned is two bytes - @param StringBuffer The passed in pointer to the buffer which will - hold the typed in string if HotKey is FALSE - @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. - @param String Pointer to the first string in the list - @param ... A series of (quantity == NumberOfLines) text - strings which will be used to construct the dialog - box - - @retval EFI_SUCCESS Displayed dialog and received user interaction - @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. - (StringBuffer == NULL) && (HotKey == FALSE)) - @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine - -**/ -EFI_STATUS -CreateDialog ( - IN UINTN NumberOfLines, - IN BOOLEAN HotKey, - IN UINTN MaximumStringSize, - OUT CHAR16 *StringBuffer, - OUT EFI_INPUT_KEY *KeyValue, - IN CHAR16 *String, - ... - ) -{ - VA_LIST Marker; - UINTN Count; - EFI_INPUT_KEY Key; - UINTN LargestString; - CHAR16 *TempString; - CHAR16 *BufferedString; - CHAR16 *StackString; - CHAR16 KeyPad[2]; - UINTN Start; - UINTN Top; - UINTN Index; - EFI_STATUS Status; - BOOLEAN SelectionComplete; - UINTN InputOffset; - UINTN CurrentAttribute; - UINTN DimensionsWidth; - UINTN DimensionsHeight; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; - - SelectionComplete = FALSE; - InputOffset = 0; - TempString = AllocateZeroPool (MaximumStringSize * 2); - BufferedString = AllocateZeroPool (MaximumStringSize * 2); - CurrentAttribute = gST->ConOut->Mode->Attribute; - - ASSERT (TempString); - ASSERT (BufferedString); - - VA_START (Marker, String); - - // - // Zero the outgoing buffer - // - ZeroMem (StringBuffer, MaximumStringSize); - - if (HotKey) { - if (KeyValue == NULL) { - return EFI_INVALID_PARAMETER; - } - } else { - if (StringBuffer == NULL) { - return EFI_INVALID_PARAMETER; - } - } - // - // Disable cursor - // - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - - LargestString = (GetStringWidth (String) / 2); - - if (*String == L' ') { - InputOffset = 1; - } - // - // Determine the largest string in the dialog box - // Notice we are starting with 1 since String is the first string - // - for (Count = 1; Count < NumberOfLines; Count++) { - StackString = VA_ARG (Marker, CHAR16 *); - - if (StackString[0] == L' ') { - InputOffset = Count + 1; - } - - if ((GetStringWidth (StackString) / 2) > LargestString) { - // - // Size of the string visually and subtract the width by one for the null-terminator - // - LargestString = (GetStringWidth (StackString) / 2); - } - } - - Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; - Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; - - Count = 0; - - // - // Display the Popup - // - CreateSharedPopUp (LargestString, NumberOfLines, &String); - - // - // Take the first key typed and report it back? - // - if (HotKey) { - Status = WaitForKeyStroke (&Key); - ASSERT_EFI_ERROR (Status); - CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); - - } else { - do { - Status = WaitForKeyStroke (&Key); - - switch (Key.UnicodeChar) { - case CHAR_NULL: - switch (Key.ScanCode) { - case SCAN_ESC: - gBS->FreePool (TempString); - gBS->FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_DEVICE_ERROR; - - default: - break; - } - - break; - - case CHAR_CARRIAGE_RETURN: - SelectionComplete = TRUE; - gBS->FreePool (TempString); - gBS->FreePool (BufferedString); - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; - break; - - case CHAR_BACKSPACE: - if (StringBuffer[0] != CHAR_NULL) { - for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { - TempString[Index] = StringBuffer[Index]; - } - // - // Effectively truncate string by 1 character - // - TempString[Index - 1] = CHAR_NULL; - StrCpy (StringBuffer, TempString); - } - - default: - // - // If it is the beginning of the string, don't worry about checking maximum limits - // - if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - StrnCpy (StringBuffer, &Key.UnicodeChar, 1); - StrnCpy (TempString, &Key.UnicodeChar, 1); - } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { - KeyPad[0] = Key.UnicodeChar; - KeyPad[1] = CHAR_NULL; - StrCat (StringBuffer, KeyPad); - StrCat (TempString, KeyPad); - } - // - // If the width of the input string is now larger than the screen, we nee to - // adjust the index to start printing portions of the string - // - SetUnicodeMem (BufferedString, LargestString, L' '); - - PrintStringAt (Start + 1, Top + InputOffset, BufferedString); - - if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { - Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; - } else { - Index = 0; - } - - for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { - BufferedString[Count] = StringBuffer[Index]; - } - - PrintStringAt (Start + 1, Top + InputOffset, BufferedString); - break; - } - } while (!SelectionComplete); - } - - gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - return EFI_SUCCESS; -} - -VOID -CreateSharedPopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - IN CHAR16 **ArrayOfStrings - ) -{ - UINTN Index; - UINTN Count; - CHAR16 Character; - UINTN Start; - UINTN End; - UINTN Top; - UINTN Bottom; - CHAR16 *String; - UINTN DimensionsWidth; - UINTN DimensionsHeight; - - DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; - DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; - - Count = 0; - - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); - - if ((RequestedWidth + 2) > DimensionsWidth) { - RequestedWidth = DimensionsWidth - 2; - } - - // - // Subtract the PopUp width from total Columns, allow for one space extra on - // each end plus a border. - // - Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1; - End = Start + RequestedWidth + 1; - - Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; - Bottom = Top + NumberOfLines + 2; - - Character = BOXDRAW_DOWN_RIGHT; - PrintCharAt (Start, Top, Character); - Character = BOXDRAW_HORIZONTAL; - for (Index = Start; Index + 2 < End; Index++) { - PrintChar (Character); - } - - Character = BOXDRAW_DOWN_LEFT; - PrintChar (Character); - Character = BOXDRAW_VERTICAL; - for (Index = Top; Index + 2 < Bottom; Index++) { - String = ArrayOfStrings[Count]; - Count++; - - // - // This will clear the background of the line - we never know who might have been - // here before us. This differs from the next clear in that it used the non-reverse - // video for normal printing. - // - if (GetStringWidth (String) / 2 > 1) { - ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); - } - - // - // Passing in a space results in the assumption that this is where typing will occur - // - if (String[0] == L' ') { - ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); - } - - // - // Passing in a NULL results in a blank space - // - if (String[0] == CHAR_NULL) { - ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); - } - - PrintStringAt ( - ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, - Index + 1, - String - ); - gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); - PrintCharAt (Start, Index + 1, Character); - PrintCharAt (End - 1, Index + 1, Character); - } - - Character = BOXDRAW_UP_RIGHT; - PrintCharAt (Start, Bottom - 1, Character); - Character = BOXDRAW_HORIZONTAL; - for (Index = Start; Index + 2 < End; Index++) { - PrintChar (Character); - } - - Character = BOXDRAW_UP_LEFT; - PrintChar (Character); -} - -VOID -CreatePopUp ( - IN UINTN RequestedWidth, - IN UINTN NumberOfLines, - IN CHAR16 *ArrayOfStrings, - ... - ) -{ - CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings); -} - - -/** - Update status bar on the bottom of menu. - - @param MessageType The type of message to be shown. - @param Flags The flags in Question header. - @param State Set or clear. - - @return None. - -**/ -VOID -UpdateStatusBar ( - IN UINTN MessageType, - IN UINT8 Flags, - IN BOOLEAN State - ) -{ - UINTN Index; - STATIC BOOLEAN InputError; - CHAR16 *NvUpdateMessage; - CHAR16 *InputErrorMessage; - - NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); - InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); - - switch (MessageType) { - case INPUT_ERROR: - if (State) { - gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); - PrintStringAt ( - gScreenDimensions.LeftColumn + gPromptBlockWidth, - gScreenDimensions.BottomRow - 1, - InputErrorMessage - ); - InputError = TRUE; - } else { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); - for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { - PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" "); - } - - InputError = FALSE; - } - break; - - case NV_UPDATE_REQUIRED: - if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { - if (State) { - gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); - PrintStringAt ( - gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, - gScreenDimensions.BottomRow - 1, - NvUpdateMessage - ); - gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); - - gNvUpdateRequired = TRUE; - } else { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); - for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { - PrintAt ( - (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), - gScreenDimensions.BottomRow - 1, - L" " - ); - } - - gNvUpdateRequired = FALSE; - } - } - break; - - case REFRESH_STATUS_BAR: - if (InputError) { - UpdateStatusBar (INPUT_ERROR, Flags, TRUE); - } - - if (gNvUpdateRequired) { - UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE); - } - break; - - default: - break; - } - - gBS->FreePool (InputErrorMessage); - gBS->FreePool (NvUpdateMessage); - return ; -} - - -/** - Get the supported width for a particular op-code - - @param Statement The FORM_BROWSER_STATEMENT structure passed in. - @param Handle The handle in the HII database being used - - @return Returns the number of CHAR16 characters that is support. - -**/ -UINT16 -GetWidth ( - IN FORM_BROWSER_STATEMENT *Statement, - IN EFI_HII_HANDLE Handle - ) -{ - CHAR16 *String; - UINTN Size; - UINT16 Width; - - Size = 0; - - // - // See if the second text parameter is really NULL - // - if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { - String = GetToken (Statement->TextTwo, Handle); - Size = StrLen (String); - gBS->FreePool (String); - } - - if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) || - (Statement->Operand == EFI_IFR_REF_OP) || - (Statement->Operand == EFI_IFR_PASSWORD_OP) || - (Statement->Operand == EFI_IFR_ACTION_OP) || - (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) || - // - // Allow a wide display if text op-code and no secondary text op-code - // - ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0)) - ) { - Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); - } else { - Width = (UINT16) gPromptBlockWidth; - } - - if (Statement->InSubtitle) { - Width -= SUBTITLE_INDENT; - } - - return Width; -} - - -/** - Will copy LineWidth amount of a string in the OutputString buffer and return the - number of CHAR16 characters that were copied into the OutputString buffer. - - @param InputString String description for this option. - @param LineWidth Width of the desired string to extract in CHAR16 - characters - @param Index Where in InputString to start the copy process - @param OutputString Buffer to copy the string into - - @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. - -**/ -UINT16 -GetLineByWidth ( - IN CHAR16 *InputString, - IN UINT16 LineWidth, - IN OUT UINTN *Index, - OUT CHAR16 **OutputString - ) -{ - static BOOLEAN Finished; - UINT16 Count; - UINT16 Count2; - - if (Finished) { - Finished = FALSE; - return (UINT16) 0; - } - - Count = LineWidth; - Count2 = 0; - - *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2)); - - // - // Ensure we have got a valid buffer - // - if (*OutputString != NULL) { - - // - //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. - //To avoid displaying this empty line in screen, just skip the two CHARs here. - // - if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { - *Index = *Index + 2; - } - - // - // Fast-forward the string and see if there is a carriage-return in the string - // - for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++) - ; - - // - // Copy the desired LineWidth of data to the output buffer. - // Also make sure that we don't copy more than the string. - // Also make sure that if there are linefeeds, we account for them. - // - if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) && - (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2)) - ) { - // - // Convert to CHAR16 value and show that we are done with this operation - // - LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2); - if (LineWidth != 0) { - Finished = TRUE; - } - } else { - if (Count2 == LineWidth) { - // - // Rewind the string from the maximum size until we see a space to break the line - // - for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--) - ; - if (LineWidth == 0) { - LineWidth = Count; - } - } else { - LineWidth = Count2; - } - } - - CopyMem (*OutputString, &InputString[*Index], LineWidth * 2); - - // - // If currently pointing to a space, increment the index to the first non-space character - // - for (; - (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN); - (*Index)++ - ) - ; - *Index = (UINT16) (*Index + LineWidth); - return LineWidth; - } else { - return (UINT16) 0; - } -} - - -/** - Update display lines for a Menu Option. - - @param MenuOption The MenuOption to be checked. - - @retval TRUE This Menu Option is selectable. - @retval FALSE This Menu Option could not be selected. - -**/ -VOID -UpdateOptionSkipLines ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN CHAR16 **OptionalString, - IN UINTN SkipValue - ) -{ - UINTN Index; - UINT16 Width; - UINTN Row; - UINTN OriginalRow; - CHAR16 *OutputString; - CHAR16 *OptionString; - - Row = 0; - OptionString = *OptionalString; - OutputString = NULL; - - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - - if (OptionString != NULL) { - Width = (UINT16) gOptionBlockWidth; - - OriginalRow = Row; - - for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index])) { - if (SkipValue == 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - } - - gBS->FreePool (OutputString); - if (SkipValue != 0) { - SkipValue--; - } - } - - Row = OriginalRow; - } - - *OptionalString = OptionString; -} - - -/** - Check whether this Menu Option could be highlighted. - - @param MenuOption The MenuOption to be checked. - - @retval TRUE This Menu Option is selectable. - @retval FALSE This Menu Option could not be selected. - -**/ -STATIC -BOOLEAN -IsSelectable ( - UI_MENU_OPTION *MenuOption - ) -{ - if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) || - MenuOption->GrayOut || MenuOption->ReadOnly) { - return FALSE; - } else { - return TRUE; - } -} - - -/** - Determine if the menu is the last menu that can be selected. - - @param Direction the scroll direction. False is down. True is up. - - @return FALSE -- the menu isn't the last menu that can be selected. - @return TRUE -- the menu is the last menu that can be selected. - -**/ -STATIC -BOOLEAN -ValueIsScroll ( - IN BOOLEAN Direction, - IN LIST_ENTRY *CurrentPos - ) -{ - LIST_ENTRY *Temp; - UI_MENU_OPTION *MenuOption; - - Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; - - if (Temp == &Menu) { - return TRUE; - } - - for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) { - MenuOption = MENU_OPTION_FROM_LINK (Temp); - if (IsSelectable (MenuOption)) { - return FALSE; - } - } - - return TRUE; -} - - -/** - Move to next selectable statement. - - @param GoUp The navigation direction. TRUE: up, FALSE: down. - @param CurrentPosition Current position. - - @return The row distance from current MenuOption to next selectable MenuOption. - -**/ -STATIC -INTN -MoveToNextStatement ( - IN BOOLEAN GoUp, - IN OUT LIST_ENTRY **CurrentPosition - ) -{ - INTN Distance; - LIST_ENTRY *Pos; - BOOLEAN HitEnd; - UI_MENU_OPTION *NextMenuOption; - - Distance = 0; - Pos = *CurrentPosition; - HitEnd = FALSE; - - while (TRUE) { - NextMenuOption = MENU_OPTION_FROM_LINK (Pos); - if (IsSelectable (NextMenuOption)) { - break; - } - if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { - HitEnd = TRUE; - break; - } - Distance += NextMenuOption->Skip; - Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); - } - - if (HitEnd) { - // - // If we hit end there is still no statement can be focused, - // we go backwards to find the statement can be focused. - // - Distance = 0; - Pos = *CurrentPosition; - - while (TRUE) { - NextMenuOption = MENU_OPTION_FROM_LINK (Pos); - if (IsSelectable (NextMenuOption)) { - break; - } - if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { - ASSERT (FALSE); - break; - } - Distance -= NextMenuOption->Skip; - Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink); - } - } - - *CurrentPosition = &NextMenuOption->Link; - return Distance; -} - - -/** - Adjust Data and Time position accordingly. - Data format : [01/02/2004] [11:22:33] - Line number : 0 0 1 0 0 1 - - @param DirectionUp the up or down direction. False is down. True is - up. - @param CurrentPosition Current position. On return: Point to the last - Option (Year or Second) if up; Point to the first - Option (Month or Hour) if down. - - @return Return line number to pad. It is possible that we stand on a zero-advance - @return data or time opcode, so pad one line when we judge if we are going to scroll outside. - -**/ -STATIC -UINTN -AdjustDateAndTimePosition ( - IN BOOLEAN DirectionUp, - IN OUT LIST_ENTRY **CurrentPosition - ) -{ - UINTN Count; - LIST_ENTRY *NewPosition; - UI_MENU_OPTION *MenuOption; - UINTN PadLineNumber; - - PadLineNumber = 0; - NewPosition = *CurrentPosition; - MenuOption = MENU_OPTION_FROM_LINK (NewPosition); - - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || - (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - // - // Calculate the distance from current position to the last Date/Time MenuOption - // - Count = 0; - while (MenuOption->Skip == 0) { - Count++; - NewPosition = NewPosition->ForwardLink; - MenuOption = MENU_OPTION_FROM_LINK (NewPosition); - PadLineNumber = 1; - } - - NewPosition = *CurrentPosition; - if (DirectionUp) { - // - // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended - // to be one that back to the previous set of MenuOptions, we need to advance to the first - // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate - // checking can be done. - // - while (Count++ < 2) { - NewPosition = NewPosition->BackLink; - } - } else { - // - // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended - // to be one that progresses to the next set of MenuOptions, we need to advance to the last - // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate - // checking can be done. - // - while (Count-- > 0) { - NewPosition = NewPosition->ForwardLink; - } - } - - *CurrentPosition = NewPosition; - } - - return PadLineNumber; -} - - -/** - Display menu and wait for user to select one menu option, then return it. - If AutoBoot is enabled, then if user doesn't select any option, - after period of time, it will automatically return the first menu option. - - - @return Return the pointer of the menu which selected, - @return otherwise return NULL. - -**/ -EFI_STATUS -UiDisplayMenu ( - IN OUT UI_MENU_SELECTION *Selection - ) -{ - INTN SkipValue; - INTN Difference; - INTN OldSkipValue; - UINTN DistanceValue; - UINTN Row; - UINTN Col; - UINTN Temp; - UINTN Temp2; - UINTN TopRow; - UINTN BottomRow; - UINTN OriginalRow; - UINTN Index; - UINT32 Count; - UINT16 Width; - CHAR16 *StringPtr; - CHAR16 *OptionString; - CHAR16 *OutputString; - CHAR16 *FormattedString; - CHAR16 YesResponse; - CHAR16 NoResponse; - BOOLEAN NewLine; - BOOLEAN Repaint; - BOOLEAN SavedValue; - EFI_STATUS Status; - EFI_INPUT_KEY Key; - LIST_ENTRY *Link; - LIST_ENTRY *NewPos; - LIST_ENTRY *TopOfScreen; - LIST_ENTRY *SavedListEntry; - UI_MENU_OPTION *MenuOption; - UI_MENU_OPTION *NextMenuOption; - UI_MENU_OPTION *SavedMenuOption; - UI_MENU_OPTION *PreviousMenuOption; - UI_CONTROL_FLAG ControlFlag; - EFI_SCREEN_DESCRIPTOR LocalScreen; - MENU_REFRESH_ENTRY *MenuRefreshEntry; - UI_SCREEN_OPERATION ScreenOperation; - UINT8 MinRefreshInterval; - UINTN BufferSize; - UINT16 DefaultId; - EFI_DEVICE_PATH_PROTOCOL *DevicePath; - FORM_BROWSER_STATEMENT *Statement; - - CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); - - Status = EFI_SUCCESS; - FormattedString = NULL; - OptionString = NULL; - ScreenOperation = UiNoOperation; - NewLine = TRUE; - MinRefreshInterval = 0; - DefaultId = 0; - - OutputString = NULL; - gUpArrow = FALSE; - gDownArrow = FALSE; - SkipValue = 0; - OldSkipValue = 0; - MenuRefreshEntry = gMenuRefreshHead; - - NextMenuOption = NULL; - PreviousMenuOption = NULL; - SavedMenuOption = NULL; - - ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); - - if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { - TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - } else { - TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; - } - - Col = LocalScreen.LeftColumn; - BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; - - Selection->TopRow = TopRow; - Selection->BottomRow = BottomRow; - Selection->PromptCol = Col; - Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; - Selection->Statement = NULL; - - TopOfScreen = Menu.ForwardLink; - Repaint = TRUE; - MenuOption = NULL; - - // - // Get user's selection - // - NewPos = Menu.ForwardLink; - - gST->ConOut->EnableCursor (gST->ConOut, FALSE); - UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE); - - ControlFlag = CfInitialization; - Selection->Action = UI_ACTION_NONE; - while (TRUE) { - switch (ControlFlag) { - case CfInitialization: - if (IsListEmpty (&Menu)) { - ControlFlag = CfReadKey; - } else { - ControlFlag = CfCheckSelection; - } - break; - - case CfCheckSelection: - if (Selection->Action != UI_ACTION_NONE) { - ControlFlag = CfExit; - } else { - ControlFlag = CfRepaint; - } - break; - - case CfRepaint: - ControlFlag = CfRefreshHighLight; - - if (Repaint) { - // - // Display menu - // - gDownArrow = FALSE; - gUpArrow = FALSE; - Row = TopRow; - - Temp = SkipValue; - Temp2 = SkipValue; - - ClearLines ( - LocalScreen.LeftColumn, - LocalScreen.RightColumn, - TopRow - SCROLL_ARROW_HEIGHT, - BottomRow + SCROLL_ARROW_HEIGHT, - FIELD_TEXT | FIELD_BACKGROUND - ); - - UiFreeRefreshList (); - MinRefreshInterval = 0; - - for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) { - MenuOption = MENU_OPTION_FROM_LINK (Link); - MenuOption->Row = Row; - MenuOption->Col = Col; - MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; - - Statement = MenuOption->ThisTag; - if (Statement->InSubtitle) { - MenuOption->Col += SUBTITLE_INDENT; - } - - if (MenuOption->GrayOut) { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); - } else { - if (Statement->Operand == EFI_IFR_SUBTITLE_OP) { - gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); - } - } - - Width = GetWidth (Statement, MenuOption->Handle); - OriginalRow = Row; - - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { - if ((Temp == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->Col, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index])) { - if (Temp == 0) { - Row++; - } - } - - gBS->FreePool (OutputString); - if (Temp != 0) { - Temp--; - } - } - - Temp = 0; - Row = OriginalRow; - - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - - if (OptionString != NULL) { - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - // - // If leading spaces on OptionString - remove the spaces - // - for (Index = 0; OptionString[Index] == L' '; Index++) { - MenuOption->OptCol++; - } - - for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { - OptionString[Count] = OptionString[Index]; - Count++; - } - - OptionString[Count] = CHAR_NULL; - } - - // - // If Question request refresh, register the op-code - // - if (Statement->RefreshInterval != 0) { - // - // Menu will be refreshed at minimal interval of all Questions - // which have refresh request - // - if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) { - MinRefreshInterval = Statement->RefreshInterval; - } - - if (gMenuRefreshHead == NULL) { - MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - ASSERT (MenuRefreshEntry != NULL); - MenuRefreshEntry->MenuOption = MenuOption; - MenuRefreshEntry->Selection = Selection; - MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; - MenuRefreshEntry->CurrentRow = MenuOption->Row; - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; - gMenuRefreshHead = MenuRefreshEntry; - } else { - // - // Advance to the last entry - // - for (MenuRefreshEntry = gMenuRefreshHead; - MenuRefreshEntry->Next != NULL; - MenuRefreshEntry = MenuRefreshEntry->Next - ) - ; - MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); - ASSERT (MenuRefreshEntry->Next != NULL); - MenuRefreshEntry = MenuRefreshEntry->Next; - MenuRefreshEntry->MenuOption = MenuOption; - MenuRefreshEntry->Selection = Selection; - MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; - MenuRefreshEntry->CurrentRow = MenuOption->Row; - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; - } - } - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = Row; - - for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { - if ((Temp2 == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->OptCol, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index])) { - if (Temp2 == 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - } - - gBS->FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - Temp2 = 0; - Row = OriginalRow; - - gBS->FreePool (OptionString); - } - // - // If this is a text op with secondary text information - // - if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { - StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle); - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = Row; - - for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) { - if ((Temp == 0) && (Row <= BottomRow)) { - PrintStringAt (MenuOption->OptCol, Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&StringPtr[Index])) { - if (Temp2 == 0) { - Row++; - // - // Since the Number of lines for this menu entry may or may not be reflected accurately - // since the prompt might be 1 lines and option might be many, and vice versa, we need to do - // some testing to ensure we are keeping this in-sync. - // - // If the difference in rows is greater than or equal to the skip value, increase the skip value - // - if ((Row - OriginalRow) >= MenuOption->Skip) { - MenuOption->Skip++; - } - } - } - - gBS->FreePool (OutputString); - if (Temp2 != 0) { - Temp2--; - } - } - - Row = OriginalRow; - gBS->FreePool (StringPtr); - } - - // - // Need to handle the bottom of the display - // - if (MenuOption->Skip > 1) { - Row += MenuOption->Skip - SkipValue; - SkipValue = 0; - } else { - Row += MenuOption->Skip; - } - - if (Row > BottomRow) { - if (!ValueIsScroll (FALSE, Link)) { - gDownArrow = TRUE; - } - - Row = BottomRow + 1; - break; - } - } - - if (!ValueIsScroll (TRUE, TopOfScreen)) { - gUpArrow = TRUE; - } - - if (gUpArrow) { - gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); - PrintAt ( - LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, - TopRow - SCROLL_ARROW_HEIGHT, - L"%c", - ARROW_UP - ); - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - } - - if (gDownArrow) { - gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); - PrintAt ( - LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, - BottomRow + SCROLL_ARROW_HEIGHT, - L"%c", - ARROW_DOWN - ); - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - } - - MenuOption = NULL; - } - break; - - case CfRefreshHighLight: - // - // MenuOption: Last menu option that need to remove hilight - // MenuOption is set to NULL in Repaint - // NewPos: Current menu option that need to hilight - // - ControlFlag = CfUpdateHelpString; - - // - // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily - // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. - // - SavedValue = Repaint; - Repaint = FALSE; - - if (Selection->QuestionId != 0) { - NewPos = Menu.ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); - - while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) { - NewPos = NewPos->ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); - } - if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) { - // - // Target Question found, find its MenuOption - // - Link = TopOfScreen; - - for (Index = TopRow; Index <= BottomRow && Link != NewPos;) { - SavedMenuOption = MENU_OPTION_FROM_LINK (Link); - Index += SavedMenuOption->Skip; - Link = Link->ForwardLink; - } - - if (Link != NewPos || Index > BottomRow) { - // - // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page - // - Link = NewPos; - for (Index = TopRow; Index <= BottomRow; ) { - Link = Link->BackLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (Link); - Index += SavedMenuOption->Skip; - } - TopOfScreen = Link->ForwardLink; - - Repaint = TRUE; - NewLine = TRUE; - ControlFlag = CfRepaint; - break; - } - } else { - // - // Target Question not found, highlight the default menu option - // - NewPos = TopOfScreen; - } - - Selection->QuestionId = 0; - } - - if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { - if (MenuOption != NULL) { - // - // Remove highlight on last Menu Option - // - gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - if (OptionString != NULL) { - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || - (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) - ) { - // - // If leading spaces on OptionString - remove the spaces - // - for (Index = 0; OptionString[Index] == L' '; Index++) - ; - - for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { - OptionString[Count] = OptionString[Index]; - Count++; - } - - OptionString[Count] = CHAR_NULL; - } - - Width = (UINT16) gOptionBlockWidth; - OriginalRow = MenuOption->Row; - - for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { - if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { - PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index])) { - MenuOption->Row++; - } - - gBS->FreePool (OutputString); - } - - MenuOption->Row = OriginalRow; - - gBS->FreePool (OptionString); - } else { - if (NewLine) { - if (MenuOption->GrayOut) { - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); - } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { - gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); - } - - OriginalRow = MenuOption->Row; - Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); - - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { - if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { - PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index])) { - MenuOption->Row++; - } - - gBS->FreePool (OutputString); - } - - MenuOption->Row = OriginalRow; - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - } - } - } - - // - // This is only possible if we entered this page and the first menu option is - // a "non-menu" item. In that case, force it UiDown - // - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - if (!IsSelectable (MenuOption)) { - ASSERT (ScreenOperation == UiNoOperation); - ScreenOperation = UiDown; - ControlFlag = CfScreenOperation; - break; - } - - // - // This is the current selected statement - // - Statement = MenuOption->ThisTag; - Selection->Statement = Statement; - - // - // Set reverse attribute - // - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); - gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); - - // - // Assuming that we have a refresh linked-list created, lets annotate the - // appropriate entry that we are highlighting with its new attribute. Just prior to this - // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh - // - if (gMenuRefreshHead != NULL) { - for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; - if (MenuRefreshEntry->MenuOption == MenuOption) { - MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT; - } - } - } - - ProcessOptions (Selection, MenuOption, FALSE, &OptionString); - if (OptionString != NULL) { - if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { - // - // If leading spaces on OptionString - remove the spaces - // - for (Index = 0; OptionString[Index] == L' '; Index++) - ; - - for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { - OptionString[Count] = OptionString[Index]; - Count++; - } - - OptionString[Count] = CHAR_NULL; - } - Width = (UINT16) gOptionBlockWidth; - - OriginalRow = MenuOption->Row; - - for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { - if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { - PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&OptionString[Index])) { - MenuOption->Row++; - } - - gBS->FreePool (OutputString); - } - - MenuOption->Row = OriginalRow; - - gBS->FreePool (OptionString); - } else { - if (NewLine) { - OriginalRow = MenuOption->Row; - - Width = GetWidth (Statement, MenuOption->Handle); - - for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { - if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { - PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); - } - // - // If there is more string to process print on the next row and increment the Skip value - // - if (StrLen (&MenuOption->Description[Index])) { - MenuOption->Row++; - } - - gBS->FreePool (OutputString); - } - - MenuOption->Row = OriginalRow; - - } - } - - if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) || - ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) || - (ScreenOperation == UiNoOperation) - ) { - UpdateKeyHelp (MenuOption, FALSE); - } - // - // Clear reverse attribute - // - gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); - } - // - // Repaint flag will be used when process CfUpdateHelpString, so restore its value - // if we didn't break halfway when process CfRefreshHighLight. - // - Repaint = SavedValue; - break; - - case CfUpdateHelpString: - ControlFlag = CfPrepareToReadKey; - - if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) { - // - // Don't print anything if it is a NULL help token - // - if (MenuOption->ThisTag->Help == 0) { - StringPtr = L"\0"; - } else { - StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); - } - - ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow); - - gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); - - for (Index = 0; Index < BottomRow - TopRow; Index++) { - // - // Pad String with spaces to simulate a clearing of the previous line - // - for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) { - StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" "); - } - - PrintStringAt ( - LocalScreen.RightColumn - gHelpBlockWidth, - Index + TopRow, - &FormattedString[Index * gHelpBlockWidth * 2] - ); - } - } - // - // Reset this flag every time we finish using it. - // - Repaint = FALSE; - NewLine = FALSE; - break; - - case CfPrepareToReadKey: - ControlFlag = CfReadKey; - ScreenOperation = UiNoOperation; - break; - - case CfReadKey: - ControlFlag = CfScreenOperation; - - // - // Wait for user's selection - // - do { - Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval); - } while (Status == EFI_TIMEOUT); - - if (Status == EFI_TIMEOUT) { - Key.UnicodeChar = CHAR_CARRIAGE_RETURN; - } else { - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - // - // if we encounter error, continue to read another key in. - // - if (EFI_ERROR (Status)) { - ControlFlag = CfReadKey; - continue; - } - } - - if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) { - // - // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset - // - break; - } - - switch (Key.UnicodeChar) { - case CHAR_CARRIAGE_RETURN: - ScreenOperation = UiSelect; - gDirection = 0; - break; - - // - // We will push the adjustment of these numeric values directly to the input handler - // NOTE: we won't handle manual input numeric - // - case '+': - case '-': - Statement = MenuOption->ThisTag; - if ((Statement->Operand == EFI_IFR_DATE_OP) - || (Statement->Operand == EFI_IFR_TIME_OP) - || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0)) - ){ - if (Key.UnicodeChar == '+') { - gDirection = SCAN_RIGHT; - } else { - gDirection = SCAN_LEFT; - } - Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); - SafeFreePool (OptionString); - } - break; - - case '^': - ScreenOperation = UiUp; - break; - - case 'V': - case 'v': - ScreenOperation = UiDown; - break; - - case ' ': - if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { - if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) { - ScreenOperation = UiSelect; - } - } - break; - - case CHAR_NULL: - if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) || - ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) || - ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || - ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) - ) { - // - // If the function key has been disabled, just ignore the key. - // - } else { - for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { - if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { - if (Key.ScanCode == SCAN_F9) { - // - // Reset to standard default - // - DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; - } - ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; - break; - } - } - } - break; - } - break; - - case CfScreenOperation: - if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) { - // - // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset - // ignore the selection and go back to reading keys. - // - if (IsListEmpty (&Menu)) { - ControlFlag = CfReadKey; - break; - } - // - // if there is nothing logical to place a cursor on, just move on to wait for a key. - // - for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { - NextMenuOption = MENU_OPTION_FROM_LINK (Link); - if (IsSelectable (NextMenuOption)) { - break; - } - } - - if (Link == &Menu) { - ControlFlag = CfPrepareToReadKey; - break; - } - } else if (ScreenOperation == UiReset) { - // - // Press ESC to exit FormSet - // - Selection->Action = UI_ACTION_EXIT; - Selection->Statement = NULL; - } - - for (Index = 0; - Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); - Index++ - ) { - if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { - ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; - break; - } - } - break; - - case CfUiPrevious: - ControlFlag = CfCheckSelection; - - if (IsListEmpty (&gMenuList)) { - Selection->Action = UI_ACTION_NONE; - if (IsListEmpty (&Menu)) { - ControlFlag = CfReadKey; - } - break; - } - - // - // Remove the Cached page entry - // - UiRemoveMenuListEntry (Selection); - - Selection->Action = UI_ACTION_REFRESH_FORM; - Selection->Statement = NULL; - break; - - case CfUiSelect: - ControlFlag = CfCheckSelection; - - Statement = MenuOption->ThisTag; - if ((Statement->Operand == EFI_IFR_TEXT_OP) || - (Statement->Operand == EFI_IFR_DATE_OP) || - (Statement->Operand == EFI_IFR_TIME_OP) || - (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { - break; - } - - // - // Keep highlight on current MenuOption - // - Selection->QuestionId = Statement->QuestionId; - - switch (Statement->Operand) { - case EFI_IFR_REF_OP: - if (Statement->RefDevicePath != 0) { - // - // Goto another Hii Package list - // - ControlFlag = CfUiReset; - Selection->Action = UI_ACTION_REFRESH_FORMSET; - - StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle); - if (StringPtr == NULL) { - // - // No device path string not found, exit - // - Selection->Action = UI_ACTION_EXIT; - Selection->Statement = NULL; - break; - } - BufferSize = StrLen (StringPtr) / 2; - DevicePath = AllocatePool (BufferSize); - - HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr); - Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath); - if (Selection->Handle == NULL) { - // - // If target Hii Handle not found, exit - // - Selection->Action = UI_ACTION_EXIT; - Selection->Statement = NULL; - break; - } - - gBS->FreePool (StringPtr); - gBS->FreePool (DevicePath); - - CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); - Selection->FormId = Statement->RefFormId; - Selection->QuestionId = Statement->RefQuestionId; - } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) { - // - // Goto another Formset, check for uncommitted data - // - ControlFlag = CfUiReset; - Selection->Action = UI_ACTION_REFRESH_FORMSET; - - CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); - Selection->FormId = Statement->RefFormId; - Selection->QuestionId = Statement->RefQuestionId; - } else if (Statement->RefFormId != 0) { - // - // Goto another form inside this formset, - // - Selection->Action = UI_ACTION_REFRESH_FORM; - - // - // Link current form so that we can always go back when someone hits the UiPrevious - // - UiAddMenuListEntry (Selection); - - Selection->FormId = Statement->RefFormId; - Selection->QuestionId = Statement->RefQuestionId; - } else if (Statement->RefQuestionId != 0) { - // - // Goto another Question - // - Selection->QuestionId = Statement->RefQuestionId; - - if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK)) { - Selection->Action = UI_ACTION_REFRESH_FORM; - } else { - Repaint = TRUE; - NewLine = TRUE; - break; - } - } - break; - - case EFI_IFR_ACTION_OP: - // - // Process the Config string - // - Status = ProcessQuestionConfig (Selection, Statement); - - if (EFI_ERROR (Status)) { - break; - } - - // - // The action button may change some Question value, so refresh the form - // - Selection->Action = UI_ACTION_REFRESH_FORM; - break; - - case EFI_IFR_RESET_BUTTON_OP: - // - // Reset Question to default value specified by DefaultId - // - ControlFlag = CfUiDefault; - DefaultId = Statement->DefaultId; - break; - - default: - // - // Editable Questions: oneof, ordered list, checkbox, numeric, string, password - // - UpdateKeyHelp (MenuOption, TRUE); - Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); - - if (EFI_ERROR (Status)) { - Repaint = TRUE; - NewLine = TRUE; - break; - } - - if (OptionString != NULL) { - PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString); - gBS->FreePool (OptionString); - } - - Selection->Action = UI_ACTION_REFRESH_FORM; - break; - } - break; - - case CfUiReset: - // - // We are going to leave current FormSet, so check uncommited data in this FormSet - // - ControlFlag = CfCheckSelection; - - if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { - // - // There is no parent menu for FrontPage - // - Selection->Action = UI_ACTION_NONE; - Selection->Statement = MenuOption->ThisTag; - break; - } - - // - // If NV flag is up, prompt user - // - if (gNvUpdateRequired) { - Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); - - YesResponse = gYesResponse[0]; - NoResponse = gNoResponse[0]; - - do { - CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString); - } while - ( - (Key.ScanCode != SCAN_ESC) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && - ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) - ); - - // - // If the user hits the YesResponse key - // - if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { - } else { - Repaint = TRUE; - NewLine = TRUE; - - Selection->Action = UI_ACTION_NONE; - break; - } - } - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - - UiFreeMenuList (); - gST->ConOut->ClearScreen (gST->ConOut); - return EFI_SUCCESS; - - case CfUiLeft: - ControlFlag = CfCheckSelection; - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - if (MenuOption->Sequence != 0) { - // - // In the middle or tail of the Date/Time op-code set, go left. - // - NewPos = NewPos->BackLink; - } - } - break; - - case CfUiRight: - ControlFlag = CfCheckSelection; - if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { - if (MenuOption->Sequence != 2) { - // - // In the middle or tail of the Date/Time op-code set, go left. - // - NewPos = NewPos->ForwardLink; - } - } - break; - - case CfUiUp: - ControlFlag = CfCheckSelection; - - SavedListEntry = TopOfScreen; - - if (NewPos->BackLink != &Menu) { - NewLine = TRUE; - // - // Adjust Date/Time position before we advance forward. - // - AdjustDateAndTimePosition (TRUE, &NewPos); - - // - // Caution that we have already rewind to the top, don't go backward in this situation. - // - if (NewPos->BackLink != &Menu) { - NewPos = NewPos->BackLink; - } - - PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); - DistanceValue = PreviousMenuOption->Skip; - - // - // Since the behavior of hitting the up arrow on a Date/Time op-code is intended - // to be one that back to the previous set of op-codes, we need to advance to the sencond - // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate - // checking can be done. - // - DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos); - - // - // Check the previous menu entry to see if it was a zero-length advance. If it was, - // don't worry about a redraw. - // - if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { - Repaint = TRUE; - TopOfScreen = NewPos; - } - - Difference = MoveToNextStatement (TRUE, &NewPos); - if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { - if (Difference > 0) { - // - // Previous focus MenuOption is above the TopOfScreen, so we need to scroll - // - TopOfScreen = NewPos; - Repaint = TRUE; - } - } - if (Difference < 0) { - // - // We want to goto previous MenuOption, but finally we go down. - // it means that we hit the begining MenuOption that can be focused - // so we simply scroll to the top - // - if (SavedListEntry != Menu.ForwardLink) { - TopOfScreen = Menu.ForwardLink; - Repaint = TRUE; - } - } - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - - UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - } else { - SavedMenuOption = MenuOption; - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - if (!IsSelectable (MenuOption)) { - // - // If we are at the end of the list and sitting on a text op, we need to more forward - // - ScreenOperation = UiDown; - ControlFlag = CfScreenOperation; - break; - } - - MenuOption = SavedMenuOption; - } - break; - - case CfUiPageUp: - ControlFlag = CfCheckSelection; - - if (NewPos->BackLink == &Menu) { - NewLine = FALSE; - Repaint = FALSE; - break; - } - - NewLine = TRUE; - Repaint = TRUE; - Link = TopOfScreen; - PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); - Index = BottomRow; - while ((Index >= TopRow) && (Link->BackLink != &Menu)) { - Index = Index - PreviousMenuOption->Skip; - Link = Link->BackLink; - PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); - } - - TopOfScreen = Link; - Difference = MoveToNextStatement (TRUE, &Link); - if (Difference > 0) { - // - // The focus MenuOption is above the TopOfScreen - // - TopOfScreen = Link; - } else if (Difference < 0) { - // - // This happens when there is no MenuOption can be focused from - // Current MenuOption to the first MenuOption - // - TopOfScreen = Menu.ForwardLink; - } - Index += Difference; - if (Index < TopRow) { - MenuOption = NULL; - } - - if (NewPos == Link) { - Repaint = FALSE; - NewLine = FALSE; - } else { - NewPos = Link; - } - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // Don't do this when we are already in the first page. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - - case CfUiPageDown: - ControlFlag = CfCheckSelection; - - if (NewPos->ForwardLink == &Menu) { - NewLine = FALSE; - Repaint = FALSE; - break; - } - - NewLine = TRUE; - Repaint = TRUE; - Link = TopOfScreen; - NextMenuOption = MENU_OPTION_FROM_LINK (Link); - Index = TopRow; - while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) { - Index = Index + NextMenuOption->Skip; - Link = Link->ForwardLink; - NextMenuOption = MENU_OPTION_FROM_LINK (Link); - } - - Index += MoveToNextStatement (FALSE, &Link); - if (Index > BottomRow) { - // - // There are more MenuOption needing scrolling - // - TopOfScreen = Link; - MenuOption = NULL; - } - if (NewPos == Link && Index <= BottomRow) { - // - // Finally we know that NewPos is the last MenuOption can be focused. - // - NewLine = FALSE; - Repaint = FALSE; - } else { - NewPos = Link; - } - - // - // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. - // Don't do this when we are already in the last page. - // - AdjustDateAndTimePosition (TRUE, &TopOfScreen); - AdjustDateAndTimePosition (TRUE, &NewPos); - break; - - case CfUiDown: - ControlFlag = CfCheckSelection; - // - // Since the behavior of hitting the down arrow on a Date/Time op-code is intended - // to be one that progresses to the next set of op-codes, we need to advance to the last - // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate - // checking can be done. The only other logic we need to introduce is that if a Date/Time - // op-code is the last entry in the menu, we need to rewind back to the first op-code of - // the Date/Time op-code. - // - SavedListEntry = NewPos; - DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos); - - if (NewPos->ForwardLink != &Menu) { - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - NewLine = TRUE; - NewPos = NewPos->ForwardLink; - NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); - - DistanceValue += NextMenuOption->Skip; - DistanceValue += MoveToNextStatement (FALSE, &NewPos); - // - // An option might be multi-line, so we need to reflect that data in the overall skip value - // - UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue); - - Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; - if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && - (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || - NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) - ) { - Temp ++; - } - - // - // If we are going to scroll, update TopOfScreen - // - if (Temp > BottomRow) { - do { - // - // Is the current top of screen a zero-advance op-code? - // If so, keep moving forward till we hit a >0 advance op-code - // - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - - // - // If bottom op-code is more than one line or top op-code is more than one line - // - if ((DistanceValue > 1) || (MenuOption->Skip > 1)) { - // - // Is the bottom op-code greater than or equal in size to the top op-code? - // - if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) { - // - // Skip the top op-code - // - TopOfScreen = TopOfScreen->ForwardLink; - Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue); - - OldSkipValue = Difference; - - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - - // - // If we have a remainder, skip that many more op-codes until we drain the remainder - // - for (; - Difference >= (INTN) SavedMenuOption->Skip; - Difference = Difference - (INTN) SavedMenuOption->Skip - ) { - // - // Since the Difference is greater than or equal to this op-code's skip value, skip it - // - TopOfScreen = TopOfScreen->ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - if (Difference < (INTN) SavedMenuOption->Skip) { - Difference = SavedMenuOption->Skip - Difference - 1; - break; - } else { - if (Difference == (INTN) SavedMenuOption->Skip) { - TopOfScreen = TopOfScreen->ForwardLink; - SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); - Difference = SavedMenuOption->Skip - Difference; - break; - } - } - } - // - // Since we will act on this op-code in the next routine, and increment the - // SkipValue, set the skips to one less than what is required. - // - SkipValue = Difference - 1; - - } else { - // - // Since we will act on this op-code in the next routine, and increment the - // SkipValue, set the skips to one less than what is required. - // - SkipValue = OldSkipValue + (Temp - BottomRow) - 1; - } - } else { - if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) { - TopOfScreen = TopOfScreen->ForwardLink; - break; - } else { - SkipValue = OldSkipValue; - } - } - // - // If the op-code at the top of the screen is more than one line, let's not skip it yet - // Let's set a skip flag to smoothly scroll the top of the screen. - // - if (SavedMenuOption->Skip > 1) { - if (SavedMenuOption == NextMenuOption) { - SkipValue = 0; - } else { - SkipValue++; - } - } else { - SkipValue = 0; - TopOfScreen = TopOfScreen->ForwardLink; - } - } while (SavedMenuOption->Skip == 0); - - Repaint = TRUE; - OldSkipValue = SkipValue; - } - - MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); - - UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - - } else { - SavedMenuOption = MenuOption; - MenuOption = MENU_OPTION_FROM_LINK (NewPos); - if (!IsSelectable (MenuOption)) { - // - // If we are at the end of the list and sitting on a text op, we need to more forward - // - ScreenOperation = UiUp; - ControlFlag = CfScreenOperation; - break; - } - - MenuOption = SavedMenuOption; - // - // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. - // - AdjustDateAndTimePosition (TRUE, &NewPos); - } - break; - - case CfUiSave: - ControlFlag = CfCheckSelection; - - // - // Submit the form - // - Status = SubmitForm (Selection->FormSet, Selection->Form); - - if (!EFI_ERROR (Status)) { - UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); - UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); - } else { - do { - CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString); - } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); - - Repaint = TRUE; - NewLine = TRUE; - } - break; - - case CfUiDefault: - ControlFlag = CfCheckSelection; - - Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId); - - if (!EFI_ERROR (Status)) { - Selection->Action = UI_ACTION_REFRESH_FORM; - - // - // Show NV update flag on status bar - // - gNvUpdateRequired = TRUE; - } - break; - - case CfUiNoOperation: - ControlFlag = CfCheckSelection; - break; - - case CfExit: - UiFreeRefreshList (); - - gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); - gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); - gST->ConOut->EnableCursor (gST->ConOut, TRUE); - gST->ConOut->OutputString (gST->ConOut, L"\n"); - - return EFI_SUCCESS; - - default: - break; - } - } -} +/** @file +Utility functions for User Interface functions. + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Ui.h" +#include "Setup.h" + +LIST_ENTRY Menu; +LIST_ENTRY gMenuList; +MENU_REFRESH_ENTRY *gMenuRefreshHead; + +// +// Search table for UiDisplayMenu() +// +SCAN_CODE_TO_SCREEN_OPERATION gScanCodeToOperation[] = { + { + SCAN_UP, + UiUp, + }, + { + SCAN_DOWN, + UiDown, + }, + { + SCAN_PAGE_UP, + UiPageUp, + }, + { + SCAN_PAGE_DOWN, + UiPageDown, + }, + { + SCAN_ESC, + UiReset, + }, + { + SCAN_F2, + UiPrevious, + }, + { + SCAN_LEFT, + UiLeft, + }, + { + SCAN_RIGHT, + UiRight, + }, + { + SCAN_F9, + UiDefault, + }, + { + SCAN_F10, + UiSave + } +}; + +SCREEN_OPERATION_T0_CONTROL_FLAG gScreenOperationToControlFlag[] = { + { + UiNoOperation, + CfUiNoOperation, + }, + { + UiDefault, + CfUiDefault, + }, + { + UiSelect, + CfUiSelect, + }, + { + UiUp, + CfUiUp, + }, + { + UiDown, + CfUiDown, + }, + { + UiLeft, + CfUiLeft, + }, + { + UiRight, + CfUiRight, + }, + { + UiReset, + CfUiReset, + }, + { + UiSave, + CfUiSave, + }, + { + UiPrevious, + CfUiPrevious, + }, + { + UiPageUp, + CfUiPageUp, + }, + { + UiPageDown, + CfUiPageDown + } +}; + + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +{ + CHAR16 *Ptr; + + Ptr = Buffer; + while ((Size--) != 0) { + *(Ptr++) = Value; + } +} + + +/** + Initialize Menu option list. + +**/ +VOID +UiInitMenu ( + VOID + ) +{ + InitializeListHead (&Menu); +} + + +/** + Initialize Menu option list. + +**/ +VOID +UiInitMenuList ( + VOID + ) +{ + InitializeListHead (&gMenuList); +} + + +/** + Remove a Menu in list, and return FormId/QuestionId for previous Menu. + + @param Selection Menu selection. + +**/ +VOID +UiRemoveMenuListEntry ( + OUT UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + if (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + + Selection->FormId = UiMenuList->FormId; + Selection->QuestionId = UiMenuList->QuestionId; + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Free Menu option linked list. + +**/ +VOID +UiFreeMenuList ( + VOID + ) +{ + UI_MENU_LIST *UiMenuList; + + while (!IsListEmpty (&gMenuList)) { + UiMenuList = CR (gMenuList.ForwardLink, UI_MENU_LIST, MenuLink, UI_MENU_LIST_SIGNATURE); + RemoveEntryList (&UiMenuList->MenuLink); + gBS->FreePool (UiMenuList); + } +} + + +/** + Add one menu entry to the linked lst + + @param Selection Menu selection. + +**/ +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +{ + UI_MENU_LIST *UiMenuList; + + UiMenuList = AllocateZeroPool (sizeof (UI_MENU_LIST)); + ASSERT (UiMenuList != NULL); + + UiMenuList->Signature = UI_MENU_LIST_SIGNATURE; + UiMenuList->FormId = Selection->FormId; + UiMenuList->QuestionId = Selection->QuestionId; + + InsertHeadList (&gMenuList, &UiMenuList->MenuLink); +} + + +/** + Free Menu option linked list. + +**/ +VOID +UiFreeMenu ( + VOID + ) +{ + UI_MENU_OPTION *MenuOption; + + while (!IsListEmpty (&Menu)) { + MenuOption = MENU_OPTION_FROM_LINK (Menu.ForwardLink); + RemoveEntryList (&MenuOption->Link); + + // + // We allocated space for this description when we did a GetToken, free it here + // + if (MenuOption->Skip != 0) { + // + // For date/time, MenuOption->Description is shared by three Menu Options + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + gBS->FreePool (MenuOption->Description); + } + gBS->FreePool (MenuOption); + } +} + + +/** + Free Menu option linked list. + +**/ +VOID +UiFreeRefreshList ( + VOID + ) +{ + MENU_REFRESH_ENTRY *OldMenuRefreshEntry; + + while (gMenuRefreshHead != NULL) { + OldMenuRefreshEntry = gMenuRefreshHead->Next; + gBS->FreePool (gMenuRefreshHead); + gMenuRefreshHead = OldMenuRefreshEntry; + } + + gMenuRefreshHead = NULL; +} + + + +/** + Refresh screen. + +**/ +VOID +RefreshForm ( + VOID + ) +{ + CHAR16 *OptionString; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UINTN Index; + UINTN Loop; + EFI_STATUS Status; + UI_MENU_SELECTION *Selection; + FORM_BROWSER_STATEMENT *Question; + + OptionString = NULL; + + if (gMenuRefreshHead != NULL) { + + MenuRefreshEntry = gMenuRefreshHead; + + do { + gST->ConOut->SetAttribute (gST->ConOut, MenuRefreshEntry->CurrentAttribute); + + Selection = MenuRefreshEntry->Selection; + Question = MenuRefreshEntry->MenuOption->ThisTag; + + // + // Don't update Question being edited + // + if (Question != MenuRefreshEntry->Selection->Statement) { + + Status = GetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE); + if (EFI_ERROR (Status)) { + return; + } + + ProcessOptions (Selection, MenuRefreshEntry->MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Loop = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Loop] = OptionString[Index]; + Loop++; + } + + OptionString[Loop] = CHAR_NULL; + + PrintStringAt (MenuRefreshEntry->CurrentColumn, MenuRefreshEntry->CurrentRow, OptionString); + gBS->FreePool (OptionString); + } + } + + MenuRefreshEntry = MenuRefreshEntry->Next; + + } while (MenuRefreshEntry != NULL); + } +} + + +/** + Wait for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + @param Timeout An optional timeout value in 100 ns units. + @param RefreshInterval Menu refresh interval (in seconds). + + @retval EFI_SUCCESS Event fired before Timeout expired. + @retval EFI_TIME_OUT Timout expired before Event fired. + +**/ +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_EVENT TimerEvent; + EFI_EVENT WaitList[2]; + + if (Timeout != 0) { + // + // Create a timer event + // + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + if (!EFI_ERROR (Status)) { + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + gBS->CloseEvent (TimerEvent); + + // + // If the timer expired, change the return to timed out + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + } + } + } else { + // + // Update screen every second + // + if (RefreshInterval == 0) { + Timeout = ONE_SECOND; + } else { + Timeout = RefreshInterval * ONE_SECOND; + } + + do { + Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent); + + // + // Set the timer event + // + gBS->SetTimer ( + TimerEvent, + TimerRelative, + Timeout + ); + + // + // Wait for the original event or the timer + // + WaitList[0] = Event; + WaitList[1] = TimerEvent; + Status = gBS->WaitForEvent (2, WaitList, &Index); + + // + // If the timer expired, update anything that needs a refresh and keep waiting + // + if (!EFI_ERROR (Status) && Index == 1) { + Status = EFI_TIMEOUT; + if (RefreshInterval != 0) { + RefreshForm (); + } + } + + gBS->CloseEvent (TimerEvent); + } while (Status == EFI_TIMEOUT); + } + + return Status; +} + + +/** + Add one menu option by specified description and context. + + @param String String description for this option. + @param Handle Hii handle for the package list. + @param Statement Statement of this Menu Option. + @param NumberOfLines Display lines for this Menu Option. + @param MenuItemCount The index for this Option in the Menu. + +**/ +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +{ + UI_MENU_OPTION *MenuOption; + UINTN Index; + UINTN Count; + + Count = 1; + + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // Add three MenuOptions for Date/Time + // Data format : [01/02/2004] [11:22:33] + // Line number : 0 0 1 0 0 1 + // + NumberOfLines = 0; + Count = 3; + + if (Statement->Storage == NULL) { + // + // For RTC type of date/time, set default refresh interval to be 1 second + // + if (Statement->RefreshInterval == 0) { + Statement->RefreshInterval = 1; + } + } + } + + for (Index = 0; Index < Count; Index++) { + MenuOption = AllocateZeroPool (sizeof (UI_MENU_OPTION)); + ASSERT (MenuOption); + + MenuOption->Signature = UI_MENU_OPTION_SIGNATURE; + MenuOption->Description = String; + MenuOption->Handle = Handle; + MenuOption->ThisTag = Statement; + MenuOption->EntryNumber = MenuItemCount; + + if (Index == 2) { + // + // Override LineNumber for the MenuOption in Date/Time sequence + // + MenuOption->Skip = 1; + } else { + MenuOption->Skip = NumberOfLines; + } + MenuOption->Sequence = Index; + + if (Statement->GrayOutExpression != NULL) { + MenuOption->GrayOut = Statement->GrayOutExpression->Result.Value.b; + } + + if ((Statement->ValueExpression != NULL) || + ((Statement->QuestionFlags & EFI_IFR_FLAG_READ_ONLY) != 0)) { + MenuOption->ReadOnly = TRUE; + } + + InsertTailList (&Menu, &MenuOption->Link); + } +} + + +/** + Routine used to abstract a generic dialog interface and return the selected key or string + + @param NumberOfLines The number of lines for the dialog box + @param HotKey Defines whether a single character is parsed + (TRUE) and returned in KeyValue or a string is + returned in StringBuffer. Two special characters + are considered when entering a string, a SCAN_ESC + and an CHAR_CARRIAGE_RETURN. SCAN_ESC terminates + string input and returns + @param MaximumStringSize The maximum size in bytes of a typed in string + (each character is a CHAR16) and the minimum + string returned is two bytes + @param StringBuffer The passed in pointer to the buffer which will + hold the typed in string if HotKey is FALSE + @param KeyValue The EFI_KEY value returned if HotKey is TRUE.. + @param String Pointer to the first string in the list + @param ... A series of (quantity == NumberOfLines) text + strings which will be used to construct the dialog + box + + @retval EFI_SUCCESS Displayed dialog and received user interaction + @retval EFI_INVALID_PARAMETER One of the parameters was invalid (e.g. + (StringBuffer == NULL) && (HotKey == FALSE)) + @retval EFI_DEVICE_ERROR User typed in an ESC character to exit the routine + +**/ +EFI_STATUS +CreateDialog ( + IN UINTN NumberOfLines, + IN BOOLEAN HotKey, + IN UINTN MaximumStringSize, + OUT CHAR16 *StringBuffer, + OUT EFI_INPUT_KEY *KeyValue, + IN CHAR16 *String, + ... + ) +{ + VA_LIST Marker; + UINTN Count; + EFI_INPUT_KEY Key; + UINTN LargestString; + CHAR16 *TempString; + CHAR16 *BufferedString; + CHAR16 *StackString; + CHAR16 KeyPad[2]; + UINTN Start; + UINTN Top; + UINTN Index; + EFI_STATUS Status; + BOOLEAN SelectionComplete; + UINTN InputOffset; + UINTN CurrentAttribute; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + SelectionComplete = FALSE; + InputOffset = 0; + TempString = AllocateZeroPool (MaximumStringSize * 2); + BufferedString = AllocateZeroPool (MaximumStringSize * 2); + CurrentAttribute = gST->ConOut->Mode->Attribute; + + ASSERT (TempString); + ASSERT (BufferedString); + + VA_START (Marker, String); + + // + // Zero the outgoing buffer + // + ZeroMem (StringBuffer, MaximumStringSize); + + if (HotKey) { + if (KeyValue == NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (StringBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + } + // + // Disable cursor + // + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + + LargestString = (GetStringWidth (String) / 2); + + if (*String == L' ') { + InputOffset = 1; + } + // + // Determine the largest string in the dialog box + // Notice we are starting with 1 since String is the first string + // + for (Count = 1; Count < NumberOfLines; Count++) { + StackString = VA_ARG (Marker, CHAR16 *); + + if (StackString[0] == L' ') { + InputOffset = Count + 1; + } + + if ((GetStringWidth (StackString) / 2) > LargestString) { + // + // Size of the string visually and subtract the width by one for the null-terminator + // + LargestString = (GetStringWidth (StackString) / 2); + } + } + + Start = (DimensionsWidth - LargestString - 2) / 2 + gScreenDimensions.LeftColumn + 1; + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + + Count = 0; + + // + // Display the Popup + // + CreateSharedPopUp (LargestString, NumberOfLines, &String); + + // + // Take the first key typed and report it back? + // + if (HotKey) { + Status = WaitForKeyStroke (&Key); + ASSERT_EFI_ERROR (Status); + CopyMem (KeyValue, &Key, sizeof (EFI_INPUT_KEY)); + + } else { + do { + Status = WaitForKeyStroke (&Key); + + switch (Key.UnicodeChar) { + case CHAR_NULL: + switch (Key.ScanCode) { + case SCAN_ESC: + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_DEVICE_ERROR; + + default: + break; + } + + break; + + case CHAR_CARRIAGE_RETURN: + SelectionComplete = TRUE; + gBS->FreePool (TempString); + gBS->FreePool (BufferedString); + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; + break; + + case CHAR_BACKSPACE: + if (StringBuffer[0] != CHAR_NULL) { + for (Index = 0; StringBuffer[Index] != CHAR_NULL; Index++) { + TempString[Index] = StringBuffer[Index]; + } + // + // Effectively truncate string by 1 character + // + TempString[Index - 1] = CHAR_NULL; + StrCpy (StringBuffer, TempString); + } + + default: + // + // If it is the beginning of the string, don't worry about checking maximum limits + // + if ((StringBuffer[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + StrnCpy (StringBuffer, &Key.UnicodeChar, 1); + StrnCpy (TempString, &Key.UnicodeChar, 1); + } else if ((GetStringWidth (StringBuffer) < MaximumStringSize) && (Key.UnicodeChar != CHAR_BACKSPACE)) { + KeyPad[0] = Key.UnicodeChar; + KeyPad[1] = CHAR_NULL; + StrCat (StringBuffer, KeyPad); + StrCat (TempString, KeyPad); + } + // + // If the width of the input string is now larger than the screen, we nee to + // adjust the index to start printing portions of the string + // + SetUnicodeMem (BufferedString, LargestString, L' '); + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + + if ((GetStringWidth (StringBuffer) / 2) > (DimensionsWidth - 2)) { + Index = (GetStringWidth (StringBuffer) / 2) - DimensionsWidth + 2; + } else { + Index = 0; + } + + for (Count = 0; Index + 1 < GetStringWidth (StringBuffer) / 2; Index++, Count++) { + BufferedString[Count] = StringBuffer[Index]; + } + + PrintStringAt (Start + 1, Top + InputOffset, BufferedString); + break; + } + } while (!SelectionComplete); + } + + gST->ConOut->SetAttribute (gST->ConOut, CurrentAttribute); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + return EFI_SUCCESS; +} + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ArrayOfStrings The array of string to be printed. + +**/ +VOID +CreateSharedPopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 **ArrayOfStrings + ) +{ + UINTN Index; + UINTN Count; + CHAR16 Character; + UINTN Start; + UINTN End; + UINTN Top; + UINTN Bottom; + CHAR16 *String; + UINTN DimensionsWidth; + UINTN DimensionsHeight; + + DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn; + DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow; + + Count = 0; + + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + + if ((RequestedWidth + 2) > DimensionsWidth) { + RequestedWidth = DimensionsWidth - 2; + } + + // + // Subtract the PopUp width from total Columns, allow for one space extra on + // each end plus a border. + // + Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gScreenDimensions.LeftColumn + 1; + End = Start + RequestedWidth + 1; + + Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gScreenDimensions.TopRow - 1; + Bottom = Top + NumberOfLines + 2; + + Character = BOXDRAW_DOWN_RIGHT; + PrintCharAt (Start, Top, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = BOXDRAW_DOWN_LEFT; + PrintChar (Character); + Character = BOXDRAW_VERTICAL; + for (Index = Top; Index + 2 < Bottom; Index++) { + String = ArrayOfStrings[Count]; + Count++; + + // + // This will clear the background of the line - we never know who might have been + // here before us. This differs from the next clear in that it used the non-reverse + // video for normal printing. + // + if (GetStringWidth (String) / 2 > 1) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + // + // Passing in a space results in the assumption that this is where typing will occur + // + if (String[0] == L' ') { + ClearLines (Start + 1, End - 1, Index + 1, Index + 1, POPUP_INVERSE_TEXT | POPUP_INVERSE_BACKGROUND); + } + + // + // Passing in a NULL results in a blank space + // + if (String[0] == CHAR_NULL) { + ClearLines (Start, End, Index + 1, Index + 1, POPUP_TEXT | POPUP_BACKGROUND); + } + + PrintStringAt ( + ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gScreenDimensions.LeftColumn + 1, + Index + 1, + String + ); + gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND); + PrintCharAt (Start, Index + 1, Character); + PrintCharAt (End - 1, Index + 1, Character); + } + + Character = BOXDRAW_UP_RIGHT; + PrintCharAt (Start, Bottom - 1, Character); + Character = BOXDRAW_HORIZONTAL; + for (Index = Start; Index + 2 < End; Index++) { + PrintChar (Character); + } + + Character = BOXDRAW_UP_LEFT; + PrintChar (Character); +} + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ArrayOfStrings The array of string to be printed. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +CreatePopUp ( + IN UINTN RequestedWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +{ + CreateSharedPopUp (RequestedWidth, NumberOfLines, &ArrayOfStrings); +} + + +/** + Update status bar on the bottom of menu. + + @param MessageType The type of message to be shown. + @param Flags The flags in Question header. + @param State Set or clear. + +**/ +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +{ + UINTN Index; + STATIC BOOLEAN InputError; + CHAR16 *NvUpdateMessage; + CHAR16 *InputErrorMessage; + + NvUpdateMessage = GetToken (STRING_TOKEN (NV_UPDATE_MESSAGE), gHiiHandle); + InputErrorMessage = GetToken (STRING_TOKEN (INPUT_ERROR_MESSAGE), gHiiHandle); + + switch (MessageType) { + case INPUT_ERROR: + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, ERROR_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth, + gScreenDimensions.BottomRow - 1, + InputErrorMessage + ); + InputError = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (InputErrorMessage) - 2) / 2; Index++) { + PrintAt (gScreenDimensions.LeftColumn + gPromptBlockWidth + Index, gScreenDimensions.BottomRow - 1, L" "); + } + + InputError = FALSE; + } + break; + + case NV_UPDATE_REQUIRED: + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (State) { + gST->ConOut->SetAttribute (gST->ConOut, INFO_TEXT); + PrintStringAt ( + gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth, + gScreenDimensions.BottomRow - 1, + NvUpdateMessage + ); + gResetRequired = (BOOLEAN) (gResetRequired | ((Flags & EFI_IFR_FLAG_RESET_REQUIRED) == EFI_IFR_FLAG_RESET_REQUIRED)); + + gNvUpdateRequired = TRUE; + } else { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT); + for (Index = 0; Index < (GetStringWidth (NvUpdateMessage) - 2) / 2; Index++) { + PrintAt ( + (gScreenDimensions.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + Index), + gScreenDimensions.BottomRow - 1, + L" " + ); + } + + gNvUpdateRequired = FALSE; + } + } + break; + + case REFRESH_STATUS_BAR: + if (InputError) { + UpdateStatusBar (INPUT_ERROR, Flags, TRUE); + } + + if (gNvUpdateRequired) { + UpdateStatusBar (NV_UPDATE_REQUIRED, Flags, TRUE); + } + break; + + default: + break; + } + + gBS->FreePool (InputErrorMessage); + gBS->FreePool (NvUpdateMessage); + return ; +} + + +/** + Get the supported width for a particular op-code + + @param Statement The FORM_BROWSER_STATEMENT structure passed in. + @param Handle The handle in the HII database being used + + @return Returns the number of CHAR16 characters that is support. + +**/ +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +{ + CHAR16 *String; + UINTN Size; + UINT16 Width; + + Size = 0; + + // + // See if the second text parameter is really NULL + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + String = GetToken (Statement->TextTwo, Handle); + Size = StrLen (String); + gBS->FreePool (String); + } + + if ((Statement->Operand == EFI_IFR_SUBTITLE_OP) || + (Statement->Operand == EFI_IFR_REF_OP) || + (Statement->Operand == EFI_IFR_PASSWORD_OP) || + (Statement->Operand == EFI_IFR_ACTION_OP) || + (Statement->Operand == EFI_IFR_RESET_BUTTON_OP) || + // + // Allow a wide display if text op-code and no secondary text op-code + // + ((Statement->Operand == EFI_IFR_TEXT_OP) && (Size == 0)) + ) { + Width = (UINT16) (gPromptBlockWidth + gOptionBlockWidth); + } else { + Width = (UINT16) gPromptBlockWidth; + } + + if (Statement->InSubtitle) { + Width -= SUBTITLE_INDENT; + } + + return Width; +} + + +STATIC BOOLEAN GetLineByWidthFinished = FALSE; + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +{ + UINT16 Count; + UINT16 Count2; + + if (GetLineByWidthFinished) { + GetLineByWidthFinished = FALSE; + return (UINT16) 0; + } + + Count = LineWidth; + Count2 = 0; + + *OutputString = AllocateZeroPool (((UINTN) (LineWidth + 1) * 2)); + + // + // Ensure we have got a valid buffer + // + if (*OutputString != NULL) { + + // + //NARROW_CHAR can not be printed in screen, so if a line only contain the two CHARs: 'NARROW_CHAR + CHAR_CARRIAGE_RETURN' , it is a empty line in Screen. + //To avoid displaying this empty line in screen, just skip the two CHARs here. + // + if ((InputString[*Index] == NARROW_CHAR) && (InputString[*Index + 1] == CHAR_CARRIAGE_RETURN)) { + *Index = *Index + 2; + } + + // + // Fast-forward the string and see if there is a carriage-return in the string + // + for (; (InputString[*Index + Count2] != CHAR_CARRIAGE_RETURN) && (Count2 != LineWidth); Count2++) + ; + + // + // Copy the desired LineWidth of data to the output buffer. + // Also make sure that we don't copy more than the string. + // Also make sure that if there are linefeeds, we account for them. + // + if ((StrSize (&InputString[*Index]) <= ((UINTN) (LineWidth + 1) * 2)) && + (StrSize (&InputString[*Index]) <= ((UINTN) (Count2 + 1) * 2)) + ) { + // + // Convert to CHAR16 value and show that we are done with this operation + // + LineWidth = (UINT16) ((StrSize (&InputString[*Index]) - 2) / 2); + if (LineWidth != 0) { + GetLineByWidthFinished = TRUE; + } + } else { + if (Count2 == LineWidth) { + // + // Rewind the string from the maximum size until we see a space to break the line + // + for (; (InputString[*Index + LineWidth] != CHAR_SPACE) && (LineWidth != 0); LineWidth--) + ; + if (LineWidth == 0) { + LineWidth = Count; + } + } else { + LineWidth = Count2; + } + } + + CopyMem (*OutputString, &InputString[*Index], LineWidth * 2); + + // + // If currently pointing to a space, increment the index to the first non-space character + // + for (; + (InputString[*Index + LineWidth] == CHAR_SPACE) || (InputString[*Index + LineWidth] == CHAR_CARRIAGE_RETURN); + (*Index)++ + ) + ; + *Index = (UINT16) (*Index + LineWidth); + return LineWidth; + } else { + return (UINT16) 0; + } +} + + +/** + Update display lines for a Menu Option. + + @param Selection The user's selection. + @param MenuOption The MenuOption to be checked. + @param OptionalString The option string. + @param SkipValue The number of lins to skip. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +VOID +UpdateOptionSkipLines ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + OUT CHAR16 **OptionalString, + IN UINTN SkipValue + ) +{ + UINTN Index; + UINT16 Width; + UINTN Row; + UINTN OriginalRow; + CHAR16 *OutputString; + CHAR16 *OptionString; + + Row = 0; + OptionString = *OptionalString; + OutputString = NULL; + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (SkipValue == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (SkipValue != 0) { + SkipValue--; + } + } + + Row = OriginalRow; + } + + *OptionalString = OptionString; +} + + +/** + Check whether this Menu Option could be highlighted. + + This is an internal function. + + @param MenuOption The MenuOption to be checked. + + @retval TRUE This Menu Option is selectable. + @retval FALSE This Menu Option could not be selected. + +**/ +BOOLEAN +IsSelectable ( + UI_MENU_OPTION *MenuOption + ) +{ + if ((MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) || + MenuOption->GrayOut || MenuOption->ReadOnly) { + return FALSE; + } else { + return TRUE; + } +} + + +/** + Determine if the menu is the last menu that can be selected. + + This is an internal function. + + @param Direction The scroll direction. False is down. True is up. + @param CurrentPos The current focus. + + @return FALSE -- the menu isn't the last menu that can be selected. + @return TRUE -- the menu is the last menu that can be selected. + +**/ +BOOLEAN +ValueIsScroll ( + IN BOOLEAN Direction, + IN LIST_ENTRY *CurrentPos + ) +{ + LIST_ENTRY *Temp; + UI_MENU_OPTION *MenuOption; + + Temp = Direction ? CurrentPos->BackLink : CurrentPos->ForwardLink; + + if (Temp == &Menu) { + return TRUE; + } + + for (; Temp != &Menu; Temp = Direction ? Temp->BackLink : Temp->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Temp); + if (IsSelectable (MenuOption)) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Move to next selectable statement. + + This is an internal function. + + @param GoUp The navigation direction. TRUE: up, FALSE: down. + @param CurrentPosition Current position. + + @return The row distance from current MenuOption to next selectable MenuOption. + +**/ +INTN +MoveToNextStatement ( + IN BOOLEAN GoUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + INTN Distance; + LIST_ENTRY *Pos; + BOOLEAN HitEnd; + UI_MENU_OPTION *NextMenuOption; + + Distance = 0; + Pos = *CurrentPosition; + HitEnd = FALSE; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + HitEnd = TRUE; + break; + } + Distance += NextMenuOption->Skip; + Pos = (GoUp ? Pos->BackLink : Pos->ForwardLink); + } + + if (HitEnd) { + // + // If we hit end there is still no statement can be focused, + // we go backwards to find the statement can be focused. + // + Distance = 0; + Pos = *CurrentPosition; + + while (TRUE) { + NextMenuOption = MENU_OPTION_FROM_LINK (Pos); + if (IsSelectable (NextMenuOption)) { + break; + } + if ((!GoUp ? Pos->BackLink : Pos->ForwardLink) == &Menu) { + ASSERT (FALSE); + break; + } + Distance -= NextMenuOption->Skip; + Pos = (!GoUp ? Pos->BackLink : Pos->ForwardLink); + } + } + + *CurrentPosition = &NextMenuOption->Link; + return Distance; +} + + +/** + Adjust Data and Time position accordingly. + Data format : [01/02/2004] [11:22:33] + Line number : 0 0 1 0 0 1 + + This is an internal function. + + @param DirectionUp the up or down direction. False is down. True is + up. + @param CurrentPosition Current position. On return: Point to the last + Option (Year or Second) if up; Point to the first + Option (Month or Hour) if down. + + @return Return line number to pad. It is possible that we stand on a zero-advance + @return data or time opcode, so pad one line when we judge if we are going to scroll outside. + +**/ +UINTN +AdjustDateAndTimePosition ( + IN BOOLEAN DirectionUp, + IN OUT LIST_ENTRY **CurrentPosition + ) +{ + UINTN Count; + LIST_ENTRY *NewPosition; + UI_MENU_OPTION *MenuOption; + UINTN PadLineNumber; + + PadLineNumber = 0; + NewPosition = *CurrentPosition; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + // + // Calculate the distance from current position to the last Date/Time MenuOption + // + Count = 0; + while (MenuOption->Skip == 0) { + Count++; + NewPosition = NewPosition->ForwardLink; + MenuOption = MENU_OPTION_FROM_LINK (NewPosition); + PadLineNumber = 1; + } + + NewPosition = *CurrentPosition; + if (DirectionUp) { + // + // Since the behavior of hitting the up arrow on a Date/Time MenuOption is intended + // to be one that back to the previous set of MenuOptions, we need to advance to the first + // Date/Time MenuOption and leave the remaining logic in CfUiUp intact so the appropriate + // checking can be done. + // + while (Count++ < 2) { + NewPosition = NewPosition->BackLink; + } + } else { + // + // Since the behavior of hitting the down arrow on a Date/Time MenuOption is intended + // to be one that progresses to the next set of MenuOptions, we need to advance to the last + // Date/Time MenuOption and leave the remaining logic in CfUiDown intact so the appropriate + // checking can be done. + // + while (Count-- > 0) { + NewPosition = NewPosition->ForwardLink; + } + } + + *CurrentPosition = NewPosition; + } + + return PadLineNumber; +} + + +/** + Display menu and wait for user to select one menu option, then return it. + If AutoBoot is enabled, then if user doesn't select any option, + after period of time, it will automatically return the first menu option. + + @param Selection Menu selection. + + @retval EFI_SUCESSS This function always return successfully for now. + +**/ +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +{ + INTN SkipValue; + INTN Difference; + INTN OldSkipValue; + UINTN DistanceValue; + UINTN Row; + UINTN Col; + UINTN Temp; + UINTN Temp2; + UINTN TopRow; + UINTN BottomRow; + UINTN OriginalRow; + UINTN Index; + UINT32 Count; + UINT16 Width; + CHAR16 *StringPtr; + CHAR16 *OptionString; + CHAR16 *OutputString; + CHAR16 *FormattedString; + CHAR16 YesResponse; + CHAR16 NoResponse; + BOOLEAN NewLine; + BOOLEAN Repaint; + BOOLEAN SavedValue; + EFI_STATUS Status; + EFI_INPUT_KEY Key; + LIST_ENTRY *Link; + LIST_ENTRY *NewPos; + LIST_ENTRY *TopOfScreen; + LIST_ENTRY *SavedListEntry; + UI_MENU_OPTION *MenuOption; + UI_MENU_OPTION *NextMenuOption; + UI_MENU_OPTION *SavedMenuOption; + UI_MENU_OPTION *PreviousMenuOption; + UI_CONTROL_FLAG ControlFlag; + EFI_SCREEN_DESCRIPTOR LocalScreen; + MENU_REFRESH_ENTRY *MenuRefreshEntry; + UI_SCREEN_OPERATION ScreenOperation; + UINT8 MinRefreshInterval; + UINTN BufferSize; + UINT16 DefaultId; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + FORM_BROWSER_STATEMENT *Statement; + + CopyMem (&LocalScreen, &gScreenDimensions, sizeof (EFI_SCREEN_DESCRIPTOR)); + + Status = EFI_SUCCESS; + FormattedString = NULL; + OptionString = NULL; + ScreenOperation = UiNoOperation; + NewLine = TRUE; + MinRefreshInterval = 0; + DefaultId = 0; + + OutputString = NULL; + gUpArrow = FALSE; + gDownArrow = FALSE; + SkipValue = 0; + OldSkipValue = 0; + MenuRefreshEntry = gMenuRefreshHead; + + NextMenuOption = NULL; + PreviousMenuOption = NULL; + SavedMenuOption = NULL; + + ZeroMem (&Key, sizeof (EFI_INPUT_KEY)); + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + TopRow = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } else { + TopRow = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + Row = LocalScreen.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT + SCROLL_ARROW_HEIGHT; + } + + Col = LocalScreen.LeftColumn; + BottomRow = LocalScreen.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - SCROLL_ARROW_HEIGHT - 1; + + Selection->TopRow = TopRow; + Selection->BottomRow = BottomRow; + Selection->PromptCol = Col; + Selection->OptionCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + Selection->Statement = NULL; + + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + MenuOption = NULL; + + // + // Get user's selection + // + NewPos = Menu.ForwardLink; + + gST->ConOut->EnableCursor (gST->ConOut, FALSE); + UpdateStatusBar (REFRESH_STATUS_BAR, (UINT8) 0, TRUE); + + ControlFlag = CfInitialization; + Selection->Action = UI_ACTION_NONE; + while (TRUE) { + switch (ControlFlag) { + case CfInitialization: + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } else { + ControlFlag = CfCheckSelection; + } + break; + + case CfCheckSelection: + if (Selection->Action != UI_ACTION_NONE) { + ControlFlag = CfExit; + } else { + ControlFlag = CfRepaint; + } + break; + + case CfRepaint: + ControlFlag = CfRefreshHighLight; + + if (Repaint) { + // + // Display menu + // + gDownArrow = FALSE; + gUpArrow = FALSE; + Row = TopRow; + + Temp = SkipValue; + Temp2 = SkipValue; + + ClearLines ( + LocalScreen.LeftColumn, + LocalScreen.RightColumn, + TopRow - SCROLL_ARROW_HEIGHT, + BottomRow + SCROLL_ARROW_HEIGHT, + FIELD_TEXT | FIELD_BACKGROUND + ); + + UiFreeRefreshList (); + MinRefreshInterval = 0; + + for (Link = TopOfScreen; Link != &Menu; Link = Link->ForwardLink) { + MenuOption = MENU_OPTION_FROM_LINK (Link); + MenuOption->Row = Row; + MenuOption->Col = Col; + MenuOption->OptCol = gPromptBlockWidth + 1 + LocalScreen.LeftColumn; + + Statement = MenuOption->ThisTag; + if (Statement->InSubtitle) { + MenuOption->Col += SUBTITLE_INDENT; + } + + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else { + if (Statement->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + } + + Width = GetWidth (Statement, MenuOption->Handle); + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->Col, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + if (Temp == 0) { + Row++; + } + } + + gBS->FreePool (OutputString); + if (Temp != 0) { + Temp--; + } + } + + Temp = 0; + Row = OriginalRow; + + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) { + MenuOption->OptCol++; + } + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + // + // If Question request refresh, register the op-code + // + if (Statement->RefreshInterval != 0) { + // + // Menu will be refreshed at minimal interval of all Questions + // which have refresh request + // + if (MinRefreshInterval == 0 || Statement->RefreshInterval < MinRefreshInterval) { + MinRefreshInterval = Statement->RefreshInterval; + } + + if (gMenuRefreshHead == NULL) { + MenuRefreshEntry = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry != NULL); + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + gMenuRefreshHead = MenuRefreshEntry; + } else { + // + // Advance to the last entry + // + for (MenuRefreshEntry = gMenuRefreshHead; + MenuRefreshEntry->Next != NULL; + MenuRefreshEntry = MenuRefreshEntry->Next + ) + ; + MenuRefreshEntry->Next = AllocateZeroPool (sizeof (MENU_REFRESH_ENTRY)); + ASSERT (MenuRefreshEntry->Next != NULL); + MenuRefreshEntry = MenuRefreshEntry->Next; + MenuRefreshEntry->MenuOption = MenuOption; + MenuRefreshEntry->Selection = Selection; + MenuRefreshEntry->CurrentColumn = MenuOption->OptCol; + MenuRefreshEntry->CurrentRow = MenuOption->Row; + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + } + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp2 == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Temp2 = 0; + Row = OriginalRow; + + gBS->FreePool (OptionString); + } + // + // If this is a text op with secondary text information + // + if ((Statement->Operand == EFI_IFR_TEXT_OP) && (Statement->TextTwo != 0)) { + StringPtr = GetToken (Statement->TextTwo, MenuOption->Handle); + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = Row; + + for (Index = 0; GetLineByWidth (StringPtr, Width, &Index, &OutputString) != 0x0000;) { + if ((Temp == 0) && (Row <= BottomRow)) { + PrintStringAt (MenuOption->OptCol, Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&StringPtr[Index])) { + if (Temp2 == 0) { + Row++; + // + // Since the Number of lines for this menu entry may or may not be reflected accurately + // since the prompt might be 1 lines and option might be many, and vice versa, we need to do + // some testing to ensure we are keeping this in-sync. + // + // If the difference in rows is greater than or equal to the skip value, increase the skip value + // + if ((Row - OriginalRow) >= MenuOption->Skip) { + MenuOption->Skip++; + } + } + } + + gBS->FreePool (OutputString); + if (Temp2 != 0) { + Temp2--; + } + } + + Row = OriginalRow; + gBS->FreePool (StringPtr); + } + + // + // Need to handle the bottom of the display + // + if (MenuOption->Skip > 1) { + Row += MenuOption->Skip - SkipValue; + SkipValue = 0; + } else { + Row += MenuOption->Skip; + } + + if (Row > BottomRow) { + if (!ValueIsScroll (FALSE, Link)) { + gDownArrow = TRUE; + } + + Row = BottomRow + 1; + break; + } + } + + if (!ValueIsScroll (TRUE, TopOfScreen)) { + gUpArrow = TRUE; + } + + if (gUpArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + TopRow - SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_UP + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + if (gDownArrow) { + gST->ConOut->SetAttribute (gST->ConOut, ARROW_TEXT | ARROW_BACKGROUND); + PrintAt ( + LocalScreen.LeftColumn + gPromptBlockWidth + gOptionBlockWidth + 1, + BottomRow + SCROLL_ARROW_HEIGHT, + L"%c", + ARROW_DOWN + ); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + + MenuOption = NULL; + } + break; + + case CfRefreshHighLight: + // + // MenuOption: Last menu option that need to remove hilight + // MenuOption is set to NULL in Repaint + // NewPos: Current menu option that need to hilight + // + ControlFlag = CfUpdateHelpString; + + // + // Repaint flag is normally reset when finish processing CfUpdateHelpString. Temporarily + // reset Repaint flag because we may break halfway and skip CfUpdateHelpString processing. + // + SavedValue = Repaint; + Repaint = FALSE; + + if (Selection->QuestionId != 0) { + NewPos = Menu.ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + while (SavedMenuOption->ThisTag->QuestionId != Selection->QuestionId && NewPos->ForwardLink != &Menu) { + NewPos = NewPos->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (NewPos); + } + if (SavedMenuOption->ThisTag->QuestionId == Selection->QuestionId) { + // + // Target Question found, find its MenuOption + // + Link = TopOfScreen; + + for (Index = TopRow; Index <= BottomRow && Link != NewPos;) { + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + Link = Link->ForwardLink; + } + + if (Link != NewPos || Index > BottomRow) { + // + // NewPos is not in the current page, simply scroll page so that NewPos is in the end of the page + // + Link = NewPos; + for (Index = TopRow; Index <= BottomRow; ) { + Link = Link->BackLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (Link); + Index += SavedMenuOption->Skip; + } + TopOfScreen = Link->ForwardLink; + + Repaint = TRUE; + NewLine = TRUE; + ControlFlag = CfRepaint; + break; + } + } else { + // + // Target Question not found, highlight the default menu option + // + NewPos = TopOfScreen; + } + + Selection->QuestionId = 0; + } + + if (NewPos != NULL && (MenuOption == NULL || NewPos != &MenuOption->Link)) { + if (MenuOption != NULL) { + // + // Remove highlight on last Menu Option + // + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + if (OptionString != NULL) { + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || + (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + + Width = (UINT16) gOptionBlockWidth; + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + if (MenuOption->GrayOut) { + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | FIELD_BACKGROUND); + } else if (MenuOption->ThisTag->Operand == EFI_IFR_SUBTITLE_OP) { + gST->ConOut->SetAttribute (gST->ConOut, SUBTITLE_TEXT | FIELD_BACKGROUND); + } + + OriginalRow = MenuOption->Row; + Width = GetWidth (MenuOption->ThisTag, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + } + } + + // + // This is only possible if we entered this page and the first menu option is + // a "non-menu" item. In that case, force it UiDown + // + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + ASSERT (ScreenOperation == UiNoOperation); + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + // + // This is the current selected statement + // + Statement = MenuOption->ThisTag; + Selection->Statement = Statement; + + // + // Set reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT); + gST->ConOut->SetCursorPosition (gST->ConOut, MenuOption->Col, MenuOption->Row); + + // + // Assuming that we have a refresh linked-list created, lets annotate the + // appropriate entry that we are highlighting with its new attribute. Just prior to this + // lets reset all of the entries' attribute so we do not get multiple highlights in he refresh + // + if (gMenuRefreshHead != NULL) { + for (MenuRefreshEntry = gMenuRefreshHead; MenuRefreshEntry != NULL; MenuRefreshEntry = MenuRefreshEntry->Next) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT | FIELD_BACKGROUND; + if (MenuRefreshEntry->MenuOption == MenuOption) { + MenuRefreshEntry->CurrentAttribute = FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT; + } + } + } + + ProcessOptions (Selection, MenuOption, FALSE, &OptionString); + if (OptionString != NULL) { + if (Statement->Operand == EFI_IFR_DATE_OP || Statement->Operand == EFI_IFR_TIME_OP) { + // + // If leading spaces on OptionString - remove the spaces + // + for (Index = 0; OptionString[Index] == L' '; Index++) + ; + + for (Count = 0; OptionString[Index] != CHAR_NULL; Index++) { + OptionString[Count] = OptionString[Index]; + Count++; + } + + OptionString[Count] = CHAR_NULL; + } + Width = (UINT16) gOptionBlockWidth; + + OriginalRow = MenuOption->Row; + + for (Index = 0; GetLineByWidth (OptionString, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->OptCol, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&OptionString[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + gBS->FreePool (OptionString); + } else { + if (NewLine) { + OriginalRow = MenuOption->Row; + + Width = GetWidth (Statement, MenuOption->Handle); + + for (Index = 0; GetLineByWidth (MenuOption->Description, Width, &Index, &OutputString) != 0x0000;) { + if (MenuOption->Row >= TopRow && MenuOption->Row <= BottomRow) { + PrintStringAt (MenuOption->Col, MenuOption->Row, OutputString); + } + // + // If there is more string to process print on the next row and increment the Skip value + // + if (StrLen (&MenuOption->Description[Index])) { + MenuOption->Row++; + } + + gBS->FreePool (OutputString); + } + + MenuOption->Row = OriginalRow; + + } + } + + if (((NewPos->ForwardLink != &Menu) && (ScreenOperation == UiDown)) || + ((NewPos->BackLink != &Menu) && (ScreenOperation == UiUp)) || + (ScreenOperation == UiNoOperation) + ) { + UpdateKeyHelp (MenuOption, FALSE); + } + // + // Clear reverse attribute + // + gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND); + } + // + // Repaint flag will be used when process CfUpdateHelpString, so restore its value + // if we didn't break halfway when process CfRefreshHighLight. + // + Repaint = SavedValue; + break; + + case CfUpdateHelpString: + ControlFlag = CfPrepareToReadKey; + + if ((Repaint || NewLine) && (gClassOfVfr != EFI_GENERAL_APPLICATION_SUBCLASS)) { + // + // Don't print anything if it is a NULL help token + // + if (MenuOption->ThisTag->Help == 0) { + StringPtr = L"\0"; + } else { + StringPtr = GetToken (MenuOption->ThisTag->Help, MenuOption->Handle); + } + + ProcessHelpString (StringPtr, &FormattedString, BottomRow - TopRow); + + gST->ConOut->SetAttribute (gST->ConOut, HELP_TEXT | FIELD_BACKGROUND); + + for (Index = 0; Index < BottomRow - TopRow; Index++) { + // + // Pad String with spaces to simulate a clearing of the previous line + // + for (; GetStringWidth (&FormattedString[Index * gHelpBlockWidth * 2]) / 2 < gHelpBlockWidth;) { + StrCat (&FormattedString[Index * gHelpBlockWidth * 2], L" "); + } + + PrintStringAt ( + LocalScreen.RightColumn - gHelpBlockWidth, + Index + TopRow, + &FormattedString[Index * gHelpBlockWidth * 2] + ); + } + } + // + // Reset this flag every time we finish using it. + // + Repaint = FALSE; + NewLine = FALSE; + break; + + case CfPrepareToReadKey: + ControlFlag = CfReadKey; + ScreenOperation = UiNoOperation; + break; + + case CfReadKey: + ControlFlag = CfScreenOperation; + + // + // Wait for user's selection + // + do { + Status = UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, MinRefreshInterval); + } while (Status == EFI_TIMEOUT); + + if (Status == EFI_TIMEOUT) { + Key.UnicodeChar = CHAR_CARRIAGE_RETURN; + } else { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + // + // if we encounter error, continue to read another key in. + // + if (EFI_ERROR (Status)) { + ControlFlag = CfReadKey; + continue; + } + } + + if (IsListEmpty (&Menu) && Key.UnicodeChar != CHAR_NULL) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // + break; + } + + switch (Key.UnicodeChar) { + case CHAR_CARRIAGE_RETURN: + ScreenOperation = UiSelect; + gDirection = 0; + break; + + // + // We will push the adjustment of these numeric values directly to the input handler + // NOTE: we won't handle manual input numeric + // + case '+': + case '-': + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_DATE_OP) + || (Statement->Operand == EFI_IFR_TIME_OP) + || ((Statement->Operand == EFI_IFR_NUMERIC_OP) && (Statement->Step != 0)) + ){ + if (Key.UnicodeChar == '+') { + gDirection = SCAN_RIGHT; + } else { + gDirection = SCAN_LEFT; + } + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + SafeFreePool (OptionString); + } + break; + + case '^': + ScreenOperation = UiUp; + break; + + case 'V': + case 'v': + ScreenOperation = UiDown; + break; + + case ' ': + if (gClassOfVfr != EFI_FRONT_PAGE_SUBCLASS) { + if (MenuOption->ThisTag->Operand == EFI_IFR_CHECKBOX_OP && !MenuOption->GrayOut) { + ScreenOperation = UiSelect; + } + } + break; + + case CHAR_NULL: + if (((Key.ScanCode == SCAN_F1) && ((gFunctionKeySetting & FUNCTION_ONE) != FUNCTION_ONE)) || + ((Key.ScanCode == SCAN_F2) && ((gFunctionKeySetting & FUNCTION_TWO) != FUNCTION_TWO)) || + ((Key.ScanCode == SCAN_F9) && ((gFunctionKeySetting & FUNCTION_NINE) != FUNCTION_NINE)) || + ((Key.ScanCode == SCAN_F10) && ((gFunctionKeySetting & FUNCTION_TEN) != FUNCTION_TEN)) + ) { + // + // If the function key has been disabled, just ignore the key. + // + } else { + for (Index = 0; Index < sizeof (gScanCodeToOperation) / sizeof (gScanCodeToOperation[0]); Index++) { + if (Key.ScanCode == gScanCodeToOperation[Index].ScanCode) { + if (Key.ScanCode == SCAN_F9) { + // + // Reset to standard default + // + DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD; + } + ScreenOperation = gScanCodeToOperation[Index].ScreenOperation; + break; + } + } + } + break; + } + break; + + case CfScreenOperation: + if (ScreenOperation != UiPrevious && ScreenOperation != UiReset) { + // + // If the screen has no menu items, and the user didn't select UiPrevious, or UiReset + // ignore the selection and go back to reading keys. + // + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + break; + } + // + // if there is nothing logical to place a cursor on, just move on to wait for a key. + // + for (Link = Menu.ForwardLink; Link != &Menu; Link = Link->ForwardLink) { + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + if (IsSelectable (NextMenuOption)) { + break; + } + } + + if (Link == &Menu) { + ControlFlag = CfPrepareToReadKey; + break; + } + } else if (ScreenOperation == UiReset) { + // + // Press ESC to exit FormSet + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + } + + for (Index = 0; + Index < sizeof (gScreenOperationToControlFlag) / sizeof (gScreenOperationToControlFlag[0]); + Index++ + ) { + if (ScreenOperation == gScreenOperationToControlFlag[Index].ScreenOperation) { + ControlFlag = gScreenOperationToControlFlag[Index].ControlFlag; + break; + } + } + break; + + case CfUiPrevious: + ControlFlag = CfCheckSelection; + + if (IsListEmpty (&gMenuList)) { + Selection->Action = UI_ACTION_NONE; + if (IsListEmpty (&Menu)) { + ControlFlag = CfReadKey; + } + break; + } + + // + // Remove the Cached page entry + // + UiRemoveMenuListEntry (Selection); + + Selection->Action = UI_ACTION_REFRESH_FORM; + Selection->Statement = NULL; + break; + + case CfUiSelect: + ControlFlag = CfCheckSelection; + + Statement = MenuOption->ThisTag; + if ((Statement->Operand == EFI_IFR_TEXT_OP) || + (Statement->Operand == EFI_IFR_DATE_OP) || + (Statement->Operand == EFI_IFR_TIME_OP) || + (Statement->Operand == EFI_IFR_NUMERIC_OP && Statement->Step != 0)) { + break; + } + + // + // Keep highlight on current MenuOption + // + Selection->QuestionId = Statement->QuestionId; + + switch (Statement->Operand) { + case EFI_IFR_REF_OP: + if (Statement->RefDevicePath != 0) { + // + // Goto another Hii Package list + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + StringPtr = GetToken (Statement->RefDevicePath, Selection->FormSet->HiiHandle); + if (StringPtr == NULL) { + // + // No device path string not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + BufferSize = StrLen (StringPtr) / 2; + DevicePath = AllocatePool (BufferSize); + + HexStringToBuffer ((UINT8 *) DevicePath, &BufferSize, StringPtr); + Selection->Handle = HiiLibDevicePathToHiiHandle (DevicePath); + if (Selection->Handle == NULL) { + // + // If target Hii Handle not found, exit + // + Selection->Action = UI_ACTION_EXIT; + Selection->Statement = NULL; + break; + } + + gBS->FreePool (StringPtr); + gBS->FreePool (DevicePath); + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (!CompareGuid (&Statement->RefFormSetId, &gZeroGuid)) { + // + // Goto another Formset, check for uncommitted data + // + ControlFlag = CfUiReset; + Selection->Action = UI_ACTION_REFRESH_FORMSET; + + CopyMem (&Selection->FormSetGuid, &Statement->RefFormSetId, sizeof (EFI_GUID)); + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefFormId != 0) { + // + // Goto another form inside this formset, + // + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Link current form so that we can always go back when someone hits the UiPrevious + // + UiAddMenuListEntry (Selection); + + Selection->FormId = Statement->RefFormId; + Selection->QuestionId = Statement->RefQuestionId; + } else if (Statement->RefQuestionId != 0) { + // + // Goto another Question + // + Selection->QuestionId = Statement->RefQuestionId; + + if ((Statement->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) { + Selection->Action = UI_ACTION_REFRESH_FORM; + } else { + Repaint = TRUE; + NewLine = TRUE; + break; + } + } + break; + + case EFI_IFR_ACTION_OP: + // + // Process the Config string + // + Status = ProcessQuestionConfig (Selection, Statement); + + if (EFI_ERROR (Status)) { + break; + } + + // + // The action button may change some Question value, so refresh the form + // + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + + case EFI_IFR_RESET_BUTTON_OP: + // + // Reset Question to default value specified by DefaultId + // + ControlFlag = CfUiDefault; + DefaultId = Statement->DefaultId; + break; + + default: + // + // Editable Questions: oneof, ordered list, checkbox, numeric, string, password + // + UpdateKeyHelp (MenuOption, TRUE); + Status = ProcessOptions (Selection, MenuOption, TRUE, &OptionString); + + if (EFI_ERROR (Status)) { + Repaint = TRUE; + NewLine = TRUE; + break; + } + + if (OptionString != NULL) { + PrintStringAt (LocalScreen.LeftColumn + gPromptBlockWidth + 1, MenuOption->Row, OptionString); + gBS->FreePool (OptionString); + } + + Selection->Action = UI_ACTION_REFRESH_FORM; + break; + } + break; + + case CfUiReset: + // + // We are going to leave current FormSet, so check uncommited data in this FormSet + // + ControlFlag = CfCheckSelection; + + if (gClassOfVfr == EFI_FRONT_PAGE_SUBCLASS) { + // + // There is no parent menu for FrontPage + // + Selection->Action = UI_ACTION_NONE; + Selection->Statement = MenuOption->ThisTag; + break; + } + + // + // If NV flag is up, prompt user + // + if (gNvUpdateRequired) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + YesResponse = gYesResponse[0]; + NoResponse = gNoResponse[0]; + + do { + CreateDialog (3, TRUE, 0, NULL, &Key, gEmptyString, gAreYouSure, gEmptyString); + } while + ( + (Key.ScanCode != SCAN_ESC) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (NoResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (YesResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + // + // If the user hits the YesResponse key + // + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (YesResponse | UPPER_LOWER_CASE_OFFSET)) { + } else { + Repaint = TRUE; + NewLine = TRUE; + + Selection->Action = UI_ACTION_NONE; + break; + } + } + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + + UiFreeMenuList (); + gST->ConOut->ClearScreen (gST->ConOut); + return EFI_SUCCESS; + + case CfUiLeft: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 0) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->BackLink; + } + } + break; + + case CfUiRight: + ControlFlag = CfCheckSelection; + if ((MenuOption->ThisTag->Operand == EFI_IFR_DATE_OP) || (MenuOption->ThisTag->Operand == EFI_IFR_TIME_OP)) { + if (MenuOption->Sequence != 2) { + // + // In the middle or tail of the Date/Time op-code set, go left. + // + NewPos = NewPos->ForwardLink; + } + } + break; + + case CfUiUp: + ControlFlag = CfCheckSelection; + + SavedListEntry = TopOfScreen; + + if (NewPos->BackLink != &Menu) { + NewLine = TRUE; + // + // Adjust Date/Time position before we advance forward. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Caution that we have already rewind to the top, don't go backward in this situation. + // + if (NewPos->BackLink != &Menu) { + NewPos = NewPos->BackLink; + } + + PreviousMenuOption = MENU_OPTION_FROM_LINK (NewPos); + DistanceValue = PreviousMenuOption->Skip; + + // + // Since the behavior of hitting the up arrow on a Date/Time op-code is intended + // to be one that back to the previous set of op-codes, we need to advance to the sencond + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. + // + DistanceValue += AdjustDateAndTimePosition (TRUE, &NewPos); + + // + // Check the previous menu entry to see if it was a zero-length advance. If it was, + // don't worry about a redraw. + // + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + Repaint = TRUE; + TopOfScreen = NewPos; + } + + Difference = MoveToNextStatement (TRUE, &NewPos); + if ((INTN) MenuOption->Row - (INTN) DistanceValue < (INTN) TopRow) { + if (Difference > 0) { + // + // Previous focus MenuOption is above the TopOfScreen, so we need to scroll + // + TopOfScreen = NewPos; + Repaint = TRUE; + } + } + if (Difference < 0) { + // + // We want to goto previous MenuOption, but finally we go down. + // it means that we hit the begining MenuOption that can be focused + // so we simply scroll to the top + // + if (SavedListEntry != Menu.ForwardLink) { + TopOfScreen = Menu.ForwardLink; + Repaint = TRUE; + } + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiDown; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + } + break; + + case CfUiPageUp: + ControlFlag = CfCheckSelection; + + if (NewPos->BackLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = BottomRow; + while ((Index >= TopRow) && (Link->BackLink != &Menu)) { + Index = Index - PreviousMenuOption->Skip; + Link = Link->BackLink; + PreviousMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + TopOfScreen = Link; + Difference = MoveToNextStatement (TRUE, &Link); + if (Difference > 0) { + // + // The focus MenuOption is above the TopOfScreen + // + TopOfScreen = Link; + } else if (Difference < 0) { + // + // This happens when there is no MenuOption can be focused from + // Current MenuOption to the first MenuOption + // + TopOfScreen = Menu.ForwardLink; + } + Index += Difference; + if (Index < TopRow) { + MenuOption = NULL; + } + + if (NewPos == Link) { + Repaint = FALSE; + NewLine = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the first page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiPageDown: + ControlFlag = CfCheckSelection; + + if (NewPos->ForwardLink == &Menu) { + NewLine = FALSE; + Repaint = FALSE; + break; + } + + NewLine = TRUE; + Repaint = TRUE; + Link = TopOfScreen; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + Index = TopRow; + while ((Index <= BottomRow) && (Link->ForwardLink != &Menu)) { + Index = Index + NextMenuOption->Skip; + Link = Link->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (Link); + } + + Index += MoveToNextStatement (FALSE, &Link); + if (Index > BottomRow) { + // + // There are more MenuOption needing scrolling + // + TopOfScreen = Link; + MenuOption = NULL; + } + if (NewPos == Link && Index <= BottomRow) { + // + // Finally we know that NewPos is the last MenuOption can be focused. + // + NewLine = FALSE; + Repaint = FALSE; + } else { + NewPos = Link; + } + + // + // If we encounter a Date/Time op-code set, rewind to the first op-code of the set. + // Don't do this when we are already in the last page. + // + AdjustDateAndTimePosition (TRUE, &TopOfScreen); + AdjustDateAndTimePosition (TRUE, &NewPos); + break; + + case CfUiDown: + ControlFlag = CfCheckSelection; + // + // Since the behavior of hitting the down arrow on a Date/Time op-code is intended + // to be one that progresses to the next set of op-codes, we need to advance to the last + // Date/Time op-code and leave the remaining logic in UiDown intact so the appropriate + // checking can be done. The only other logic we need to introduce is that if a Date/Time + // op-code is the last entry in the menu, we need to rewind back to the first op-code of + // the Date/Time op-code. + // + SavedListEntry = NewPos; + DistanceValue = AdjustDateAndTimePosition (FALSE, &NewPos); + + if (NewPos->ForwardLink != &Menu) { + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + NewLine = TRUE; + NewPos = NewPos->ForwardLink; + NextMenuOption = MENU_OPTION_FROM_LINK (NewPos); + + DistanceValue += NextMenuOption->Skip; + DistanceValue += MoveToNextStatement (FALSE, &NewPos); + // + // An option might be multi-line, so we need to reflect that data in the overall skip value + // + UpdateOptionSkipLines (Selection, NextMenuOption, &OptionString, SkipValue); + + Temp = MenuOption->Row + MenuOption->Skip + DistanceValue - 1; + if ((MenuOption->Row + MenuOption->Skip == BottomRow + 1) && + (NextMenuOption->ThisTag->Operand == EFI_IFR_DATE_OP || + NextMenuOption->ThisTag->Operand == EFI_IFR_TIME_OP) + ) { + Temp ++; + } + + // + // If we are going to scroll, update TopOfScreen + // + if (Temp > BottomRow) { + do { + // + // Is the current top of screen a zero-advance op-code? + // If so, keep moving forward till we hit a >0 advance op-code + // + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If bottom op-code is more than one line or top op-code is more than one line + // + if ((DistanceValue > 1) || (MenuOption->Skip > 1)) { + // + // Is the bottom op-code greater than or equal in size to the top op-code? + // + if ((Temp - BottomRow) >= (SavedMenuOption->Skip - OldSkipValue)) { + // + // Skip the top op-code + // + TopOfScreen = TopOfScreen->ForwardLink; + Difference = (Temp - BottomRow) - (SavedMenuOption->Skip - OldSkipValue); + + OldSkipValue = Difference; + + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + + // + // If we have a remainder, skip that many more op-codes until we drain the remainder + // + for (; + Difference >= (INTN) SavedMenuOption->Skip; + Difference = Difference - (INTN) SavedMenuOption->Skip + ) { + // + // Since the Difference is greater than or equal to this op-code's skip value, skip it + // + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + if (Difference < (INTN) SavedMenuOption->Skip) { + Difference = SavedMenuOption->Skip - Difference - 1; + break; + } else { + if (Difference == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + SavedMenuOption = MENU_OPTION_FROM_LINK (TopOfScreen); + Difference = SavedMenuOption->Skip - Difference; + break; + } + } + } + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = Difference - 1; + + } else { + // + // Since we will act on this op-code in the next routine, and increment the + // SkipValue, set the skips to one less than what is required. + // + SkipValue = OldSkipValue + (Temp - BottomRow) - 1; + } + } else { + if ((OldSkipValue + 1) == (INTN) SavedMenuOption->Skip) { + TopOfScreen = TopOfScreen->ForwardLink; + break; + } else { + SkipValue = OldSkipValue; + } + } + // + // If the op-code at the top of the screen is more than one line, let's not skip it yet + // Let's set a skip flag to smoothly scroll the top of the screen. + // + if (SavedMenuOption->Skip > 1) { + if (SavedMenuOption == NextMenuOption) { + SkipValue = 0; + } else { + SkipValue++; + } + } else { + SkipValue = 0; + TopOfScreen = TopOfScreen->ForwardLink; + } + } while (SavedMenuOption->Skip == 0); + + Repaint = TRUE; + OldSkipValue = SkipValue; + } + + MenuOption = MENU_OPTION_FROM_LINK (SavedListEntry); + + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + + } else { + SavedMenuOption = MenuOption; + MenuOption = MENU_OPTION_FROM_LINK (NewPos); + if (!IsSelectable (MenuOption)) { + // + // If we are at the end of the list and sitting on a text op, we need to more forward + // + ScreenOperation = UiUp; + ControlFlag = CfScreenOperation; + break; + } + + MenuOption = SavedMenuOption; + // + // If we are at the end of the list and sitting on a Date/Time op, rewind to the head. + // + AdjustDateAndTimePosition (TRUE, &NewPos); + } + break; + + case CfUiSave: + ControlFlag = CfCheckSelection; + + // + // Submit the form + // + Status = SubmitForm (Selection->FormSet, Selection->Form); + + if (!EFI_ERROR (Status)) { + UpdateStatusBar (INPUT_ERROR, MenuOption->ThisTag->QuestionFlags, FALSE); + UpdateStatusBar (NV_UPDATE_REQUIRED, MenuOption->ThisTag->QuestionFlags, FALSE); + } else { + do { + CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gSaveFailed, gPressEnter, gEmptyString); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + Repaint = TRUE; + NewLine = TRUE; + } + break; + + case CfUiDefault: + ControlFlag = CfCheckSelection; + + Status = ExtractFormDefault (Selection->FormSet, Selection->Form, DefaultId); + + if (!EFI_ERROR (Status)) { + Selection->Action = UI_ACTION_REFRESH_FORM; + + // + // Show NV update flag on status bar + // + gNvUpdateRequired = TRUE; + } + break; + + case CfUiNoOperation: + ControlFlag = CfCheckSelection; + break; + + case CfExit: + UiFreeRefreshList (); + + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, Row + 4); + gST->ConOut->EnableCursor (gST->ConOut, TRUE); + gST->ConOut->OutputString (gST->ConOut, L"\n"); + + return EFI_SUCCESS; + + default: + break; + } + } +} diff --git a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h index e402248204..6e6b8975c1 100644 --- a/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h +++ b/MdeModulePkg/Universal/SetupBrowserDxe/Ui.h @@ -1,474 +1,796 @@ -/** @file - -Copyright (c) 2004 - 2007, Intel Corporation -All rights reserved. This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -Module Name: - - Ui.h - -Abstract: - - Head file UI - -Revision History - - -**/ - -#ifndef _UI_H -#define _UI_H - -#include "Setup.h" - -// -// Globals -// -#define REGULAR_NUMERIC 0 -#define TIME_NUMERIC 1 -#define DATE_NUMERIC 2 - -#define SUBTITLE_INDENT 2 - -typedef enum { - UiNoOperation, - UiDefault, - UiSelect, - UiUp, - UiDown, - UiLeft, - UiRight, - UiReset, - UiSave, - UiPrevious, - UiPageUp, - UiPageDown, - UiMaxOperation -} UI_SCREEN_OPERATION; - -typedef enum { - CfInitialization, - CfCheckSelection, - CfRepaint, - CfRefreshHighLight, - CfUpdateHelpString, - CfPrepareToReadKey, - CfReadKey, - CfScreenOperation, - CfUiPrevious, - CfUiSelect, - CfUiReset, - CfUiLeft, - CfUiRight, - CfUiUp, - CfUiPageUp, - CfUiPageDown, - CfUiDown, - CfUiSave, - CfUiDefault, - CfUiNoOperation, - CfExit, - CfMaxControlFlag -} UI_CONTROL_FLAG; - -#define UI_ACTION_NONE 0 -#define UI_ACTION_REFRESH_FORM 1 -#define UI_ACTION_REFRESH_FORMSET 2 -#define UI_ACTION_EXIT 3 - -typedef struct { - EFI_HII_HANDLE Handle; - - // - // Target formset/form/Question information - // - EFI_GUID FormSetGuid; - UINT16 FormId; - UINT16 QuestionId; - - UINTN TopRow; - UINTN BottomRow; - UINTN PromptCol; - UINTN OptionCol; - UINTN CurrentRow; - - // - // Ation for Browser to taken: - // UI_ACTION_NONE - navigation inside a form - // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form - // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary - // - UINTN Action; - - // - // Current selected fomset/form/Question - // - FORM_BROWSER_FORMSET *FormSet; - FORM_BROWSER_FORM *Form; - FORM_BROWSER_STATEMENT *Statement; -} UI_MENU_SELECTION; - -#define UI_MENU_OPTION_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'm') -#define UI_MENU_LIST_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'l') - -typedef struct { - UINTN Signature; - LIST_ENTRY Link; - - EFI_HII_HANDLE Handle; - FORM_BROWSER_STATEMENT *ThisTag; - UINT16 EntryNumber; - - UINTN Row; - UINTN Col; - UINTN OptCol; - CHAR16 *Description; - UINTN Skip; // Number of lines - - // - // Display item sequence for date/time - // Date: Month/Day/Year - // Sequence: 0 1 2 - // - // Time: Hour : Minute : Second - // Sequence: 0 1 2 - // - // - UINTN Sequence; - - BOOLEAN GrayOut; - BOOLEAN ReadOnly; -} UI_MENU_OPTION; - -#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) - -typedef struct { - UINTN Signature; - LIST_ENTRY MenuLink; - - UINT16 FormId; - UINT16 QuestionId; -} UI_MENU_LIST; - -typedef struct _MENU_REFRESH_ENTRY { - struct _MENU_REFRESH_ENTRY *Next; - UI_MENU_OPTION *MenuOption; // Describes the entry needing an update - UI_MENU_SELECTION *Selection; - UINTN CurrentColumn; - UINTN CurrentRow; - UINTN CurrentAttribute; -} MENU_REFRESH_ENTRY; - -typedef struct { - UINT16 ScanCode; - UI_SCREEN_OPERATION ScreenOperation; -} SCAN_CODE_TO_SCREEN_OPERATION; - -typedef struct { - UI_SCREEN_OPERATION ScreenOperation; - UI_CONTROL_FLAG ControlFlag; -} SCREEN_OPERATION_T0_CONTROL_FLAG; - - -extern LIST_ENTRY gMenuList; -extern MENU_REFRESH_ENTRY *gMenuRefreshHead; -extern UI_MENU_SELECTION *gCurrentSelection; - -// -// Global Functions -// -VOID -UiInitMenu ( - VOID - ) -; - -VOID -UiInitMenuList ( - VOID - ) -; - -VOID -UiRemoveMenuListEntry ( - OUT UI_MENU_SELECTION *Selection - ) -; - -VOID -UiFreeMenuList ( - VOID - ) -; - -VOID -UiAddMenuListEntry ( - IN UI_MENU_SELECTION *Selection - ) -; - -VOID -UiFreeMenu ( - VOID - ) -; - -VOID -UiAddMenuOption ( - IN CHAR16 *String, - IN EFI_HII_HANDLE Handle, - IN FORM_BROWSER_STATEMENT *Statement, - IN UINT16 NumberOfLines, - IN UINT16 MenuItemCount - ) -; - -EFI_STATUS -UiDisplayMenu ( - IN OUT UI_MENU_SELECTION *Selection - ) -; - -VOID -FreeBrowserStrings ( - VOID - ) -; - -EFI_STATUS -SetupBrowser ( - IN OUT UI_MENU_SELECTION *Selection - ) -; - -VOID -ValueToString ( - IN CHAR16 *Buffer, - IN BOOLEAN Comma, - IN INT64 v - ) -; - -EFI_STATUS -UiIntToString ( - IN UINTN num, - IN OUT CHAR16 *str, - IN UINT16 size - ) -; - -VOID -SetUnicodeMem ( - IN VOID *Buffer, - IN UINTN Size, - IN CHAR16 Value - ) -; - -EFI_STATUS -UiWaitForSingleEvent ( - IN EFI_EVENT Event, - IN UINT64 Timeout, OPTIONAL - IN UINT8 RefreshInterval OPTIONAL - ) -; - -VOID -CreatePopUp ( - IN UINTN ScreenWidth, - IN UINTN NumberOfLines, - IN CHAR16 *ArrayOfStrings, - ... - ) -; - -EFI_STATUS -ReadString ( - IN UI_MENU_OPTION *MenuOption, - IN CHAR16 *Prompt, - OUT CHAR16 *StringPtr - ) -; - -EFI_STATUS -GetSelectionInputPopUp ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ) -; - -EFI_STATUS -GetNumericInput ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption - ) -; - -VOID -UpdateStatusBar ( - IN UINTN MessageType, - IN UINT8 Flags, - IN BOOLEAN State - ) -; - -EFI_STATUS -ProcessQuestionConfig ( - IN UI_MENU_SELECTION *Selection, - IN FORM_BROWSER_STATEMENT *Question - ) -; - -EFI_STATUS -PrintFormattedNumber ( - IN FORM_BROWSER_STATEMENT *Question, - IN OUT CHAR16 *FormattedNumber, - IN UINTN BufferSize - ) -; - -QUESTION_OPTION * -ValueToOption ( - IN FORM_BROWSER_STATEMENT *Question, - IN EFI_HII_VALUE *OptionValue - ) -; - -EFI_STATUS -ProcessOptions ( - IN UI_MENU_SELECTION *Selection, - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected, - OUT CHAR16 **OptionString - ) -; - -VOID -ProcessHelpString ( - IN CHAR16 *StringPtr, - OUT CHAR16 **FormattedString, - IN UINTN RowCount - ) -; - -VOID -UpdateKeyHelp ( - IN UI_MENU_OPTION *MenuOption, - IN BOOLEAN Selected - ) -; - -VOID -ClearLines ( - UINTN LeftColumn, - UINTN RightColumn, - UINTN TopRow, - UINTN BottomRow, - UINTN TextAttribute - ) -; - -UINTN -GetStringWidth ( - CHAR16 *String - ) -; - -UINT16 -GetLineByWidth ( - IN CHAR16 *InputString, - IN UINT16 LineWidth, - IN OUT UINTN *Index, - OUT CHAR16 **OutputString - ) -; - -UINT16 -GetWidth ( - IN FORM_BROWSER_STATEMENT *Statement, - IN EFI_HII_HANDLE Handle - ) -; - -VOID -NewStrCat ( - CHAR16 *Destination, - CHAR16 *Source - ) -; - -EFI_STATUS -WaitForKeyStroke ( - OUT EFI_INPUT_KEY *Key - ) -; - -VOID -ResetScopeStack ( - VOID - ) -; - -EFI_STATUS -PushScope ( - IN UINT8 Operand - ) -; - -EFI_STATUS -PopScope ( - OUT UINT8 *Operand - ) -; - -FORM_BROWSER_FORM * -IdToForm ( - IN FORM_BROWSER_FORMSET *FormSet, - IN UINT16 FormId -) -; - -FORM_BROWSER_STATEMENT * -IdToQuestion ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN UINT16 QuestionId - ) -; - -FORM_EXPRESSION * -IdToExpression ( - IN FORM_BROWSER_FORM *Form, - IN UINT8 RuleId - ) -; - -VOID -ExtendValueToU64 ( - IN EFI_HII_VALUE *Value - ) -; - -INTN -CompareHiiValue ( - IN EFI_HII_VALUE *Value1, - IN EFI_HII_VALUE *Value2, - IN EFI_HII_HANDLE HiiHandle OPTIONAL - ) -; - -EFI_STATUS -EvaluateExpression ( - IN FORM_BROWSER_FORMSET *FormSet, - IN FORM_BROWSER_FORM *Form, - IN OUT FORM_EXPRESSION *Expression - ) -; - -#endif // _UI_H +/** @file +Private structure, MACRO and function definitions for User Interface related functionalities. + +Copyright (c) 2004 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _UI_H_ +#define _UI_H_ + +#include "Setup.h" + +// +// Globals +// +#define REGULAR_NUMERIC 0 +#define TIME_NUMERIC 1 +#define DATE_NUMERIC 2 + +#define SUBTITLE_INDENT 2 + +typedef enum { + UiNoOperation, + UiDefault, + UiSelect, + UiUp, + UiDown, + UiLeft, + UiRight, + UiReset, + UiSave, + UiPrevious, + UiPageUp, + UiPageDown, + UiMaxOperation +} UI_SCREEN_OPERATION; + +typedef enum { + CfInitialization, + CfCheckSelection, + CfRepaint, + CfRefreshHighLight, + CfUpdateHelpString, + CfPrepareToReadKey, + CfReadKey, + CfScreenOperation, + CfUiPrevious, + CfUiSelect, + CfUiReset, + CfUiLeft, + CfUiRight, + CfUiUp, + CfUiPageUp, + CfUiPageDown, + CfUiDown, + CfUiSave, + CfUiDefault, + CfUiNoOperation, + CfExit, + CfMaxControlFlag +} UI_CONTROL_FLAG; + +#define UI_ACTION_NONE 0 +#define UI_ACTION_REFRESH_FORM 1 +#define UI_ACTION_REFRESH_FORMSET 2 +#define UI_ACTION_EXIT 3 + +typedef struct { + EFI_HII_HANDLE Handle; + + // + // Target formset/form/Question information + // + EFI_GUID FormSetGuid; + UINT16 FormId; + UINT16 QuestionId; + + UINTN TopRow; + UINTN BottomRow; + UINTN PromptCol; + UINTN OptionCol; + UINTN CurrentRow; + + // + // Ation for Browser to taken: + // UI_ACTION_NONE - navigation inside a form + // UI_ACTION_REFRESH_FORM - re-evaluate expressions and repaint form + // UI_ACTION_REFRESH_FORMSET - re-parse formset IFR binary + // + UINTN Action; + + // + // Current selected fomset/form/Question + // + FORM_BROWSER_FORMSET *FormSet; + FORM_BROWSER_FORM *Form; + FORM_BROWSER_STATEMENT *Statement; +} UI_MENU_SELECTION; + +#define UI_MENU_OPTION_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'm') +#define UI_MENU_LIST_SIGNATURE EFI_SIGNATURE_32 ('u', 'i', 'm', 'l') + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + + EFI_HII_HANDLE Handle; + FORM_BROWSER_STATEMENT *ThisTag; + UINT16 EntryNumber; + + UINTN Row; + UINTN Col; + UINTN OptCol; + CHAR16 *Description; + UINTN Skip; // Number of lines + + // + // Display item sequence for date/time + // Date: Month/Day/Year + // Sequence: 0 1 2 + // + // Time: Hour : Minute : Second + // Sequence: 0 1 2 + // + // + UINTN Sequence; + + BOOLEAN GrayOut; + BOOLEAN ReadOnly; +} UI_MENU_OPTION; + +#define MENU_OPTION_FROM_LINK(a) CR (a, UI_MENU_OPTION, Link, UI_MENU_OPTION_SIGNATURE) + +typedef struct { + UINTN Signature; + LIST_ENTRY MenuLink; + + UINT16 FormId; + UINT16 QuestionId; +} UI_MENU_LIST; + +typedef struct _MENU_REFRESH_ENTRY { + struct _MENU_REFRESH_ENTRY *Next; + UI_MENU_OPTION *MenuOption; // Describes the entry needing an update + UI_MENU_SELECTION *Selection; + UINTN CurrentColumn; + UINTN CurrentRow; + UINTN CurrentAttribute; +} MENU_REFRESH_ENTRY; + +typedef struct { + UINT16 ScanCode; + UI_SCREEN_OPERATION ScreenOperation; +} SCAN_CODE_TO_SCREEN_OPERATION; + +typedef struct { + UI_SCREEN_OPERATION ScreenOperation; + UI_CONTROL_FLAG ControlFlag; +} SCREEN_OPERATION_T0_CONTROL_FLAG; + + +extern LIST_ENTRY gMenuList; +extern MENU_REFRESH_ENTRY *gMenuRefreshHead; +extern UI_MENU_SELECTION *gCurrentSelection; + +// +// Global Functions +// +/** + Initialize Menu option list. + +**/ +VOID +UiInitMenu ( + VOID + ) +; + +/** + Initialize Menu option list. + +**/ +VOID +UiInitMenuList ( + VOID + ) +; + +/** + Remove a Menu in list, and return FormId/QuestionId for previous Menu. + + @param Selection Menu selection. + +**/ +VOID +UiRemoveMenuListEntry ( + OUT UI_MENU_SELECTION *Selection + ) +; + +/** + Free Menu option linked list. + +**/ +VOID +UiFreeMenuList ( + VOID + ) +; + +/** + Add one menu entry to the linked lst + + @param Selection Menu selection. + +**/ +VOID +UiAddMenuListEntry ( + IN UI_MENU_SELECTION *Selection + ) +; + +/** + Free Menu option linked list. + +**/ +VOID +UiFreeMenu ( + VOID + ) +; + +/** + Add one menu option by specified description and context. + + @param String String description for this option. + @param Handle Hii handle for the package list. + @param Statement Statement of this Menu Option. + @param NumberOfLines Display lines for this Menu Option. + @param MenuItemCount The index for this Option in the Menu. + +**/ +VOID +UiAddMenuOption ( + IN CHAR16 *String, + IN EFI_HII_HANDLE Handle, + IN FORM_BROWSER_STATEMENT *Statement, + IN UINT16 NumberOfLines, + IN UINT16 MenuItemCount + ) +; + +/** + Display menu and wait for user to select one menu option, then return it. + If AutoBoot is enabled, then if user doesn't select any option, + after period of time, it will automatically return the first menu option. + + @param Selection Menu selection. + + @return Return the pointer of the menu which selected, + @return otherwise return NULL. + +**/ +EFI_STATUS +UiDisplayMenu ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +/** + Free up the resource allocated for all strings required + by Setup Browser. + +**/ +VOID +FreeBrowserStrings ( + VOID + ) +; + +/** + The worker function that send the displays to the screen. On output, + the selection made by user is returned. + + @param Selection On input, Selection tell setup browser the information + about the Selection, form and formset to be displayed. + On output, Selection return the screen item that is selected + by user. + + @retval EFI_SUCCESS The page is displayed successfully. + @return Other value if the page failed to be diplayed. + +**/ +EFI_STATUS +SetupBrowser ( + IN OUT UI_MENU_SELECTION *Selection + ) +; + +/** + VSPrint worker function that prints a Value as a decimal number in Buffer. + + @param Buffer Location to place ascii decimal number string of Value. + @param Flags Flags to use in printing decimal string, see file header for + details. + @param Value Decimal value to convert to a string in Buffer. + + @return Number of characters printed. + +**/ +VOID +ValueToString ( + IN CHAR16 *Buffer, + IN BOOLEAN Flags, + IN INT64 Value + ) +; + +/** + Set Buffer to Value for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set + @param Value Value of the set operation. + +**/ +VOID +SetUnicodeMem ( + IN VOID *Buffer, + IN UINTN Size, + IN CHAR16 Value + ) +; + +/** + Wait for a given event to fire, or for an optional timeout to expire. + + @param Event The event to wait for + @param Timeout An optional timeout value in 100 ns units. + @param RefreshInterval Menu refresh interval (in seconds). + + @retval EFI_SUCCESS Event fired before Timeout expired. + @retval EFI_TIME_OUT Timout expired before Event fired. + +**/ +EFI_STATUS +UiWaitForSingleEvent ( + IN EFI_EVENT Event, + IN UINT64 Timeout, OPTIONAL + IN UINT8 RefreshInterval OPTIONAL + ) +; + +/** + Draw a pop up windows based on the dimension, number of lines and + strings specified. + + @param RequestedWidth The width of the pop-up. + @param NumberOfLines The number of lines. + @param ArrayOfStrings The array of string to be printed. + @param ... A series of text strings that displayed in the pop-up. + +**/ +VOID +CreatePopUp ( + IN UINTN ScreenWidth, + IN UINTN NumberOfLines, + IN CHAR16 *ArrayOfStrings, + ... + ) +; + +/** + Get string or password input from user. + + @param MenuOption Pointer to the current input menu. + @param Prompt The prompt string shown on popup window. + @param StringPtr Destination for use input string. + + @retval EFI_SUCCESS If string input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +ReadString ( + IN UI_MENU_OPTION *MenuOption, + IN CHAR16 *Prompt, + OUT CHAR16 *StringPtr + ) +; + +/** + 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 + ) +; + +/** + This routine reads a numeric value from the user input. + + @param Selection Pointer to current selection. + @param MenuOption Pointer to the current input menu. + + @retval EFI_SUCCESS If numerical input is read successfully + @retval EFI_DEVICE_ERROR If operation fails + +**/ +EFI_STATUS +GetNumericInput ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption + ) +; + +/** + Update status bar on the bottom of menu. + + @param MessageType The type of message to be shown. + @param Flags The flags in Question header. + @param State Set or clear. + +**/ +VOID +UpdateStatusBar ( + IN UINTN MessageType, + IN UINT8 Flags, + IN BOOLEAN State + ) +; + +/** + Process Question Config. + + @param Selection The UI menu selection. + @param Question The Question to be peocessed. + + @retval EFI_SUCCESS Question Config process success. + @retval Other Question Config process fail. + +**/ +EFI_STATUS +ProcessQuestionConfig ( + IN UI_MENU_SELECTION *Selection, + IN FORM_BROWSER_STATEMENT *Question + ) +; + +/** + Print Question Value according to it's storage width and display attributes. + + @param Question The Question to be printed. + @param FormattedNumber Buffer for output string. + @param BufferSize The FormattedNumber buffer size in bytes. + + @retval EFI_SUCCESS Print success. + @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number. + +**/ +EFI_STATUS +PrintFormattedNumber ( + IN FORM_BROWSER_STATEMENT *Question, + IN OUT CHAR16 *FormattedNumber, + IN UINTN BufferSize + ) +; + +/** + 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 + ) +; + +/** + Process a Question's Option (whether selected or un-selected). + + @param Selection Pointer to UI_MENU_SELECTION. + @param MenuOption The MenuOption for this Question. + @param Selected TRUE: if Question is selected. + @param OptionString Pointer of the Option String to be displayed. + + @retval EFI_SUCCESS Question Option process success. + @retval Other Question Option process fail. + +**/ +EFI_STATUS +ProcessOptions ( + IN UI_MENU_SELECTION *Selection, + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected, + OUT CHAR16 **OptionString + ) +; + +/** + Process the help string: Split StringPtr to several lines of strings stored in + FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth. + + @param StringPtr The entire help string. + @param FormattedString The oupput formatted string. + @param RowCount TRUE: if Question is selected. + +**/ +VOID +ProcessHelpString ( + IN CHAR16 *StringPtr, + OUT CHAR16 **FormattedString, + IN UINTN RowCount + ) +; + +/** + Update key's help imformation. + + @param MenuOption The Menu option + @param Selected Whether or not a tag be selected + +**/ +VOID +UpdateKeyHelp ( + IN UI_MENU_OPTION *MenuOption, + IN BOOLEAN Selected + ) +; + +/** + Clear retangle with specified text attribute. + + @param LeftColumn Left column of retangle. + @param RightColumn Right column of retangle. + @param TopRow Start row of retangle. + @param BottomRow End row of retangle. + @param TextAttribute The character foreground and background. + +**/ +VOID +ClearLines ( + UINTN LeftColumn, + UINTN RightColumn, + UINTN TopRow, + UINTN BottomRow, + UINTN TextAttribute + ) +; + +/** + Count the storage space of a Unicode string. + + This function handles the Unicode string with NARROW_CHAR + and WIDE_CHAR control characters. NARROW_HCAR and WIDE_CHAR + does not count in the resultant output. If a WIDE_CHAR is + hit, then 2 Unicode character will consume an output storage + space with size of CHAR16 till a NARROW_CHAR is hit. + + @param String The input string to be counted. + + @return Storage space for the input string. + +**/ +UINTN +GetStringWidth ( + CHAR16 *String + ) +; + +/** + Will copy LineWidth amount of a string in the OutputString buffer and return the + number of CHAR16 characters that were copied into the OutputString buffer. + + @param InputString String description for this option. + @param LineWidth Width of the desired string to extract in CHAR16 + characters + @param Index Where in InputString to start the copy process + @param OutputString Buffer to copy the string into + + @return Returns the number of CHAR16 characters that were copied into the OutputString buffer. + +**/ +UINT16 +GetLineByWidth ( + IN CHAR16 *InputString, + IN UINT16 LineWidth, + IN OUT UINTN *Index, + OUT CHAR16 **OutputString + ) +; + +/** + Get the supported width for a particular op-code + + @param Statement The FORM_BROWSER_STATEMENT structure passed in. + @param Handle The handle in the HII database being used + + @return Returns the number of CHAR16 characters that is support. + +**/ +UINT16 +GetWidth ( + IN FORM_BROWSER_STATEMENT *Statement, + IN EFI_HII_HANDLE Handle + ) +; + +/** + Concatenate a narrow string to another string. + + @param Destination The destination string. + @param Source The source string. The string to be concatenated. + to the end of Destination. + +**/ +VOID +NewStrCat ( + CHAR16 *Destination, + CHAR16 *Source + ) +; + +/** + Wait for a key to be pressed by user. + + @param Key The key which is pressed by user. + + @retval EFI_SUCCESS The function always completed successfully. + +**/ +EFI_STATUS +WaitForKeyStroke ( + OUT EFI_INPUT_KEY *Key + ) +; + +/** + Reset stack pointer to begin of the stack. + +**/ +VOID +ResetScopeStack ( + VOID + ) +; + +/** + Push an Operand onto the Stack + + @param Operand Operand to push. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PushScope ( + IN UINT8 Operand + ) +; + +/** + Pop an Operand from the Stack + + @param Operand Operand to pop. + + @retval EFI_SUCCESS The value was pushed onto the stack. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + +**/ +EFI_STATUS +PopScope ( + OUT UINT8 *Operand + ) +; + +/** + Get Form given its FormId. + + @param FormSet The formset which contains this form. + @param FormId Id of this form. + + @retval Pointer The form. + @retval NULL Specified Form is not found in the formset. + +**/ +FORM_BROWSER_FORM * +IdToForm ( + IN FORM_BROWSER_FORMSET *FormSet, + IN UINT16 FormId + ) +; + +/** + Search a Question in Formset scope using its QuestionId. + + @param FormSet The formset which contains this form. + @param Form The form which contains this Question. + @param QuestionId Id of this Question. + + @retval Pointer The Question. + @retval NULL Specified Question not found in the form. + +**/ +FORM_BROWSER_STATEMENT * +IdToQuestion ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN UINT16 QuestionId + ) +; + +/** + Zero extend integer/boolean/date/time to UINT64 for comparing. + + @param Value HII Value to be converted. + +**/ +VOID +ExtendValueToU64 ( + IN EFI_HII_VALUE *Value + ) +; + +/** + Compare two Hii value. + + @param Value1 Expression value to compare on left-hand. + @param Value2 Expression value to compare on right-hand. + @param HiiHandle Only required for string compare. + + @retval EFI_INVALID_PARAMETER Could not perform comparation on two values. + @retval 0 Two operators equeal. + @return Positive value if Value1 is greater than Value2. + @retval Negative value if Value1 is less than Value2. + +**/ +INTN +CompareHiiValue ( + IN EFI_HII_VALUE *Value1, + IN EFI_HII_VALUE *Value2, + IN EFI_HII_HANDLE HiiHandle OPTIONAL + ) +; + +/** + Evaluate the result of a HII expression + + @param FormSet FormSet associated with this expression. + @param Form Form associated with this expression. + @param Expression Expression to be evaluated. + + @retval EFI_SUCCESS The expression evaluated successfuly + @retval EFI_NOT_FOUND The Question which referenced by a QuestionId + could not be found. + @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the + stack. + @retval EFI_ACCESS_DENIED The pop operation underflowed the stack + @retval EFI_INVALID_PARAMETER Syntax error with the Expression + +**/ +EFI_STATUS +EvaluateExpression ( + IN FORM_BROWSER_FORMSET *FormSet, + IN FORM_BROWSER_FORM *Form, + IN OUT FORM_EXPRESSION *Expression + ) +; + +#endif // _UI_H