2 Implementation for handling the User Interface option processing.
5 Copyright (c) 2004 - 2020, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "FormDisplay.h"
12 #define MAX_TIME_OUT_LEN 0x10
15 Concatenate a narrow string to another string.
17 @param Destination The destination string.
18 @param DestMax The Max length of destination string.
19 @param Source The source string. The string to be concatenated.
20 to the end of Destination.
25 IN OUT CHAR16
*Destination
,
32 for (Length
= 0; Destination
[Length
] != 0; Length
++)
36 // We now have the length of the original string
37 // We can safely assume for now that we are concatenating a narrow value to this string.
38 // For instance, the string is "XYZ" and cat'ing ">"
39 // If this assumption changes, we need to make this routine a bit more complex
41 Destination
[Length
] = NARROW_CHAR
;
44 StrCpyS (Destination
+ Length
, DestMax
- Length
, Source
);
48 Get UINT64 type value.
50 @param Value Input Hii value.
52 @retval UINT64 Return the UINT64 type value.
57 IN EFI_HII_VALUE
*Value
64 switch (Value
->Type
) {
65 case EFI_IFR_TYPE_NUM_SIZE_8
:
66 RetVal
= Value
->Value
.u8
;
69 case EFI_IFR_TYPE_NUM_SIZE_16
:
70 RetVal
= Value
->Value
.u16
;
73 case EFI_IFR_TYPE_NUM_SIZE_32
:
74 RetVal
= Value
->Value
.u32
;
77 case EFI_IFR_TYPE_BOOLEAN
:
78 RetVal
= Value
->Value
.b
;
81 case EFI_IFR_TYPE_DATE
:
82 RetVal
= *(UINT64
*) &Value
->Value
.date
;
85 case EFI_IFR_TYPE_TIME
:
86 RetVal
= (*(UINT64
*) &Value
->Value
.time
) & 0xffffff;
90 RetVal
= Value
->Value
.u64
;
98 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
100 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
101 EFI_IFR_TYPE_BUFFER when do the value compare.
103 @param Value Expression value to compare on.
105 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
106 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
111 IN EFI_HII_VALUE
*Value
114 switch (Value
->Type
) {
115 case EFI_IFR_TYPE_BUFFER
:
116 case EFI_IFR_TYPE_DATE
:
117 case EFI_IFR_TYPE_TIME
:
118 case EFI_IFR_TYPE_REF
:
127 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
129 @param Value Expression value to compare on.
131 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
132 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
137 IN EFI_HII_VALUE
*Value
140 switch (Value
->Type
) {
141 case EFI_IFR_TYPE_NUM_SIZE_8
:
142 case EFI_IFR_TYPE_NUM_SIZE_16
:
143 case EFI_IFR_TYPE_NUM_SIZE_32
:
144 case EFI_IFR_TYPE_NUM_SIZE_64
:
145 case EFI_IFR_TYPE_BOOLEAN
:
154 Return the buffer length and buffer pointer for this value.
156 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
157 EFI_IFR_TYPE_BUFFER when do the value compare.
159 @param Value Expression value to compare on.
160 @param Buf Return the buffer pointer.
161 @param BufLen Return the buffer length.
165 GetBufAndLenForValue (
166 IN EFI_HII_VALUE
*Value
,
171 switch (Value
->Type
) {
172 case EFI_IFR_TYPE_BUFFER
:
173 *Buf
= Value
->Buffer
;
174 *BufLen
= Value
->BufferLen
;
177 case EFI_IFR_TYPE_DATE
:
178 *Buf
= (UINT8
*) (&Value
->Value
.date
);
179 *BufLen
= (UINT16
) sizeof (EFI_HII_DATE
);
182 case EFI_IFR_TYPE_TIME
:
183 *Buf
= (UINT8
*) (&Value
->Value
.time
);
184 *BufLen
= (UINT16
) sizeof (EFI_HII_TIME
);
187 case EFI_IFR_TYPE_REF
:
188 *Buf
= (UINT8
*) (&Value
->Value
.ref
);
189 *BufLen
= (UINT16
) sizeof (EFI_HII_REF
);
199 Compare two Hii value.
201 @param Value1 Expression value to compare on left-hand.
202 @param Value2 Expression value to compare on right-hand.
203 @param Result Return value after compare.
204 retval 0 Two operators equal.
205 return Positive value if Value1 is greater than Value2.
206 retval Negative value if Value1 is less than Value2.
207 @param HiiHandle Only required for string compare.
209 @retval other Could not perform compare on two values.
210 @retval EFI_SUCCESS Compare the value success.
215 IN EFI_HII_VALUE
*Value1
,
216 IN EFI_HII_VALUE
*Value2
,
218 IN EFI_HII_HANDLE HiiHandle OPTIONAL
230 if (Value1
->Type
== EFI_IFR_TYPE_STRING
&& Value2
->Type
== EFI_IFR_TYPE_STRING
) {
231 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
233 // StringId 0 is reserved
235 return EFI_INVALID_PARAMETER
;
238 if (Value1
->Value
.string
== Value2
->Value
.string
) {
243 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
248 return EFI_NOT_FOUND
;
251 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
254 return EFI_NOT_FOUND
;
257 *Result
= StrCmp (Str1
, Str2
);
266 // Take types(date, time, ref, buffer) as buffer
268 if (IsTypeInBuffer(Value1
) && IsTypeInBuffer(Value2
)) {
269 GetBufAndLenForValue(Value1
, &Buf1
, &Buf1Len
);
270 GetBufAndLenForValue(Value2
, &Buf2
, &Buf2Len
);
272 Len
= Buf1Len
> Buf2Len
? Buf2Len
: Buf1Len
;
273 *Result
= CompareMem (Buf1
, Buf2
, Len
);
274 if ((*Result
== 0) && (Buf1Len
!= Buf2Len
)) {
276 // In this case, means base on samll number buffer, the data is same
277 // So which value has more data, which value is bigger.
279 *Result
= Buf1Len
> Buf2Len
? 1 : -1;
285 // Take remain types(integer, boolean, date/time) as integer
287 if (IsTypeInUINT64(Value1
) && IsTypeInUINT64(Value2
)) {
288 Temp64
= HiiValueToUINT64(Value1
) - HiiValueToUINT64(Value2
);
291 } else if (Temp64
< 0) {
299 return EFI_UNSUPPORTED
;
303 Search an Option of a Question by its value.
305 @param Question The Question
306 @param OptionValue Value for Option to be searched.
308 @retval Pointer Pointer to the found Option.
309 @retval NULL Option not found.
312 DISPLAY_QUESTION_OPTION
*
314 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
315 IN EFI_HII_VALUE
*OptionValue
319 DISPLAY_QUESTION_OPTION
*Option
;
323 Link
= GetFirstNode (&Question
->OptionListHead
);
324 while (!IsNull (&Question
->OptionListHead
, Link
)) {
325 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
327 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
328 Value
.Type
= Option
->OptionOpCode
->Type
;
329 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
331 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
335 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
343 Return data element in an Array by its Index.
345 @param Array The data array.
346 @param Type Type of the data in this array.
347 @param Index Zero based index for data in this array.
349 @retval Value The data to be returned
361 ASSERT (Array
!= NULL
);
365 case EFI_IFR_TYPE_NUM_SIZE_8
:
366 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
369 case EFI_IFR_TYPE_NUM_SIZE_16
:
370 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
373 case EFI_IFR_TYPE_NUM_SIZE_32
:
374 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
377 case EFI_IFR_TYPE_NUM_SIZE_64
:
378 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
390 Set value of a data element in an Array by its Index.
392 @param Array The data array.
393 @param Type Type of the data in this array.
394 @param Index Zero based index for data in this array.
395 @param Value The value to be set.
407 ASSERT (Array
!= NULL
);
410 case EFI_IFR_TYPE_NUM_SIZE_8
:
411 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
414 case EFI_IFR_TYPE_NUM_SIZE_16
:
415 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
418 case EFI_IFR_TYPE_NUM_SIZE_32
:
419 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
422 case EFI_IFR_TYPE_NUM_SIZE_64
:
423 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
432 Check whether this value already in the array, if yes, return the index.
434 @param Array The data array.
435 @param Type Type of the data in this array.
436 @param Value The value to be find.
437 @param Index The index in the array which has same value with Value.
439 @retval TRUE Found the value in the array.
440 @retval FALSE Not found the value.
448 OUT UINTN
*Index OPTIONAL
455 ASSERT (Array
!= NULL
);
461 case EFI_IFR_TYPE_NUM_SIZE_8
:
462 ValueComp
= (UINT8
) Value
;
465 case EFI_IFR_TYPE_NUM_SIZE_16
:
466 ValueComp
= (UINT16
) Value
;
469 case EFI_IFR_TYPE_NUM_SIZE_32
:
470 ValueComp
= (UINT32
) Value
;
473 case EFI_IFR_TYPE_NUM_SIZE_64
:
474 ValueComp
= (UINT64
) Value
;
482 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
483 if (ValueComp
== TmpValue
) {
497 Print Question Value according to it's storage width and display attributes.
499 @param Question The Question to be printed.
500 @param FormattedNumber Buffer for output string.
501 @param BufferSize The FormattedNumber buffer size in bytes.
503 @retval EFI_SUCCESS Print success.
504 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
508 PrintFormattedNumber (
509 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
510 IN OUT CHAR16
*FormattedNumber
,
516 EFI_HII_VALUE
*QuestionValue
;
517 EFI_IFR_NUMERIC
*NumericOp
;
519 if (BufferSize
< (21 * sizeof (CHAR16
))) {
520 return EFI_BUFFER_TOO_SMALL
;
523 QuestionValue
= &Question
->CurrentValue
;
524 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
526 Value
= (INT64
) QuestionValue
->Value
.u64
;
527 switch (NumericOp
->Flags
& EFI_IFR_DISPLAY
) {
528 case EFI_IFR_DISPLAY_INT_DEC
:
529 switch (QuestionValue
->Type
) {
530 case EFI_IFR_NUMERIC_SIZE_1
:
531 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
534 case EFI_IFR_NUMERIC_SIZE_2
:
535 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
538 case EFI_IFR_NUMERIC_SIZE_4
:
539 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
542 case EFI_IFR_NUMERIC_SIZE_8
:
555 case EFI_IFR_DISPLAY_UINT_DEC
:
559 case EFI_IFR_DISPLAY_UINT_HEX
:
564 return EFI_UNSUPPORTED
;
567 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
574 Draw a pop up windows based on the dimension, number of lines and
577 @param RequestedWidth The width of the pop-up.
578 @param NumberOfLines The number of lines.
579 @param Marker The variable argument list for the list of string to be printed.
584 IN UINTN RequestedWidth
,
585 IN UINTN NumberOfLines
,
597 UINTN DimensionsWidth
;
598 UINTN DimensionsHeight
;
600 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
601 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
603 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
605 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
606 RequestedWidth
= DimensionsWidth
- 2;
610 // Subtract the PopUp width from total Columns, allow for one space extra on
611 // each end plus a border.
613 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
614 End
= Start
+ RequestedWidth
+ 1;
616 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gStatementDimensions
.TopRow
- 1;
617 Bottom
= Top
+ NumberOfLines
+ 2;
619 Character
= BOXDRAW_DOWN_RIGHT
;
620 PrintCharAt (Start
, Top
, Character
);
621 Character
= BOXDRAW_HORIZONTAL
;
622 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
623 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
626 Character
= BOXDRAW_DOWN_LEFT
;
627 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
628 Character
= BOXDRAW_VERTICAL
;
631 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
632 String
= VA_ARG (Marker
, CHAR16
*);
635 // This will clear the background of the line - we never know who might have been
636 // here before us. This differs from the next clear in that it used the non-reverse
637 // video for normal printing.
639 if (GetStringWidth (String
) / 2 > 1) {
640 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
644 // Passing in a space results in the assumption that this is where typing will occur
646 if (String
[0] == L
' ') {
647 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, GetPopupInverseColor ());
651 // Passing in a NULL results in a blank space
653 if (String
[0] == CHAR_NULL
) {
654 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
658 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gStatementDimensions
.LeftColumn
+ 1,
662 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
663 PrintCharAt (Start
, Index
+ 1, Character
);
664 PrintCharAt (End
- 1, Index
+ 1, Character
);
667 Character
= BOXDRAW_UP_RIGHT
;
668 PrintCharAt (Start
, Bottom
- 1, Character
);
669 Character
= BOXDRAW_HORIZONTAL
;
670 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
671 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
674 Character
= BOXDRAW_UP_LEFT
;
675 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
679 Draw a pop up windows based on the dimension, number of lines and
682 @param RequestedWidth The width of the pop-up.
683 @param NumberOfLines The number of lines.
684 @param ... A series of text strings that displayed in the pop-up.
689 CreateMultiStringPopUp (
690 IN UINTN RequestedWidth
,
691 IN UINTN NumberOfLines
,
697 VA_START (Marker
, NumberOfLines
);
699 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
707 @param Event The Event need to be process
708 @param Context The context of the event.
721 Process for the refresh interval statement.
723 @param Event The Event need to be process
724 @param Context The context of the event.
729 RefreshTimeOutProcess (
734 WARNING_IF_CONTEXT
*EventInfo
;
735 CHAR16 TimeOutString
[MAX_TIME_OUT_LEN
];
737 EventInfo
= (WARNING_IF_CONTEXT
*) Context
;
739 if (*(EventInfo
->TimeOut
) == 0) {
740 gBS
->CloseEvent (Event
);
742 gBS
->SignalEvent (EventInfo
->SyncEvent
);
746 UnicodeSPrint(TimeOutString
, MAX_TIME_OUT_LEN
, L
"%d", *(EventInfo
->TimeOut
));
748 CreateDialog (NULL
, gEmptyString
, EventInfo
->ErrorInfo
, gPressEnter
, gEmptyString
, TimeOutString
, NULL
);
750 *(EventInfo
->TimeOut
) -= 1;
754 Display error message for invalid password.
765 // Invalid password, prompt error message
768 CreateDialog (&Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
, NULL
);
769 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
773 Process password op code.
775 @param MenuOption The menu for current password op code.
777 @retval EFI_SUCCESS Question Option process success.
778 @retval Other Question Option process fail.
783 IN UI_MENU_OPTION
*MenuOption
790 EFI_IFR_PASSWORD
*PasswordInfo
;
791 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
794 Question
= MenuOption
->ThisTag
;
795 PasswordInfo
= (EFI_IFR_PASSWORD
*) Question
->OpCode
;
796 Maximum
= PasswordInfo
->MaxSize
;
797 Status
= EFI_SUCCESS
;
799 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
803 // Use a NULL password to test whether old password is required
806 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
807 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
809 // Password can't be set now.
811 if (Status
== EFI_UNSUPPORTED
) {
813 CreateDialog (&Key
, gEmptyString
, gPasswordUnsupported
, gPressEnter
, gEmptyString
, NULL
);
814 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
816 FreePool (StringPtr
);
820 if (EFI_ERROR (Status
)) {
822 // Old password exist, ask user for the old password
824 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
825 if (EFI_ERROR (Status
)) {
826 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
827 FreePool (StringPtr
);
832 // Check user input old password
834 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
835 if (EFI_ERROR (Status
)) {
836 if (Status
== EFI_NOT_READY
) {
838 // Typed in old password incorrect
842 Status
= EFI_SUCCESS
;
844 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
845 FreePool (StringPtr
);
851 // Ask for new password
853 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
854 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
855 if (EFI_ERROR (Status
)) {
857 // Reset state machine for password
859 Question
->PasswordCheck (gFormData
, Question
, NULL
);
860 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
861 FreePool (StringPtr
);
866 // Confirm new password
868 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
870 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
871 if (EFI_ERROR (Status
)) {
873 // Reset state machine for password
875 Question
->PasswordCheck (gFormData
, Question
, NULL
);
876 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
877 ZeroMem (TempString
, (Maximum
+ 1) * sizeof (CHAR16
));
878 FreePool (StringPtr
);
879 FreePool (TempString
);
884 // Compare two typed-in new passwords
886 if (StrCmp (StringPtr
, TempString
) == 0) {
887 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
888 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
889 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
890 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
892 Status
= EFI_SUCCESS
;
895 // Reset state machine for password
897 Question
->PasswordCheck (gFormData
, Question
, NULL
);
900 // Two password mismatch, prompt error message
903 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
904 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
906 Status
= EFI_INVALID_PARAMETER
;
908 ZeroMem (TempString
, (Maximum
+ 1) * sizeof (CHAR16
));
909 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
910 FreePool (TempString
);
911 FreePool (StringPtr
);
917 Process a Question's Option (whether selected or un-selected).
919 @param MenuOption The MenuOption for this Question.
920 @param Selected TRUE: if Question is selected.
921 @param OptionString Pointer of the Option String to be displayed.
922 @param SkipErrorValue Whether need to return when value without option for it.
924 @retval EFI_SUCCESS Question Option process success.
925 @retval Other Question Option process fail.
930 IN UI_MENU_OPTION
*MenuOption
,
932 OUT CHAR16
**OptionString
,
933 IN BOOLEAN SkipErrorValue
939 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
940 CHAR16 FormattedNumber
[21];
945 DISPLAY_QUESTION_OPTION
*OneOfOption
;
947 EFI_HII_VALUE HiiValue
;
948 EFI_HII_VALUE
*QuestionValue
;
949 DISPLAY_QUESTION_OPTION
*Option
;
953 EFI_IFR_ORDERED_LIST
*OrderList
;
954 BOOLEAN ValueInvalid
;
957 Status
= EFI_SUCCESS
;
960 Character
[1] = L
'\0';
961 *OptionString
= NULL
;
962 ValueInvalid
= FALSE
;
964 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
965 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
967 Question
= MenuOption
->ThisTag
;
968 QuestionValue
= &Question
->CurrentValue
;
970 switch (Question
->OpCode
->OpCode
) {
971 case EFI_IFR_ORDERED_LIST_OP
:
974 // Check whether there are Options of this OrderedList
976 if (IsListEmpty (&Question
->OptionListHead
)) {
980 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
982 Link
= GetFirstNode (&Question
->OptionListHead
);
983 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
985 ValueType
= OneOfOption
->OptionOpCode
->Type
;
986 ValueArray
= Question
->CurrentValue
.Buffer
;
992 Status
= GetSelectionInputPopUp (MenuOption
);
995 // We now know how many strings we will have, so we can allocate the
996 // space required for the array or strings.
998 MaxLen
= OrderList
->MaxContainers
* BufferSize
/ sizeof (CHAR16
);
999 *OptionString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
1000 ASSERT (*OptionString
);
1002 HiiValue
.Type
= ValueType
;
1003 HiiValue
.Value
.u64
= 0;
1004 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1005 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1006 if (HiiValue
.Value
.u64
== 0) {
1008 // Values for the options in ordered lists should never be a 0
1013 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1014 if (OneOfOption
== NULL
) {
1015 if (SkipErrorValue
) {
1017 // Just try to get the option string, skip the value which not has option.
1023 // Show error message
1026 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1027 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1030 // The initial value of the orderedlist is invalid, force to be valid value
1031 // Exit current DisplayForm with new value.
1033 gUserInput
->SelectedStatement
= Question
;
1035 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1036 ASSERT (ValueArray
!= NULL
);
1037 gUserInput
->InputValue
.Buffer
= ValueArray
;
1038 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1039 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1041 Link
= GetFirstNode (&Question
->OptionListHead
);
1043 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
1044 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1045 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1046 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
1049 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
1051 FreePool (*OptionString
);
1052 *OptionString
= NULL
;
1053 return EFI_NOT_FOUND
;
1056 Character
[0] = LEFT_ONEOF_DELIMITER
;
1057 NewStrCat (OptionString
[0], MaxLen
, Character
);
1058 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1059 ASSERT (StringPtr
!= NULL
);
1060 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1061 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1062 NewStrCat (OptionString
[0], MaxLen
, Character
);
1063 Character
[0] = CHAR_CARRIAGE_RETURN
;
1064 NewStrCat (OptionString
[0], MaxLen
, Character
);
1065 FreePool (StringPtr
);
1069 // If valid option more than the max container, skip these options.
1071 if (Index
>= OrderList
->MaxContainers
) {
1076 // Search the other options, try to find the one not in the container.
1078 Link
= GetFirstNode (&Question
->OptionListHead
);
1079 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1080 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1081 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1083 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
1087 if (SkipErrorValue
) {
1089 // Not report error, just get the correct option string info.
1091 Character
[0] = LEFT_ONEOF_DELIMITER
;
1092 NewStrCat (OptionString
[0], MaxLen
, Character
);
1093 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1094 ASSERT (StringPtr
!= NULL
);
1095 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1096 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1097 NewStrCat (OptionString
[0], MaxLen
, Character
);
1098 Character
[0] = CHAR_CARRIAGE_RETURN
;
1099 NewStrCat (OptionString
[0], MaxLen
, Character
);
1100 FreePool (StringPtr
);
1105 if (!ValueInvalid
) {
1106 ValueInvalid
= TRUE
;
1108 // Show error message
1111 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1112 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1115 // The initial value of the orderedlist is invalid, force to be valid value
1116 // Exit current DisplayForm with new value.
1118 gUserInput
->SelectedStatement
= Question
;
1120 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
1121 ASSERT (ValueArray
!= NULL
);
1122 gUserInput
->InputValue
.Buffer
= ValueArray
;
1123 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1124 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1127 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
1131 FreePool (*OptionString
);
1132 *OptionString
= NULL
;
1133 return EFI_NOT_FOUND
;
1138 case EFI_IFR_ONE_OF_OP
:
1140 // Check whether there are Options of this OneOf
1142 if (IsListEmpty (&Question
->OptionListHead
)) {
1149 Status
= GetSelectionInputPopUp (MenuOption
);
1151 MaxLen
= BufferSize
/ sizeof(CHAR16
);
1152 *OptionString
= AllocateZeroPool (BufferSize
);
1153 ASSERT (*OptionString
);
1155 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1156 if (OneOfOption
== NULL
) {
1157 if (SkipErrorValue
) {
1159 // Not report error, just get the correct option string info.
1161 Link
= GetFirstNode (&Question
->OptionListHead
);
1162 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1165 // Show error message
1168 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1169 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1172 // Force the Question value to be valid
1173 // Exit current DisplayForm with new value.
1175 Link
= GetFirstNode (&Question
->OptionListHead
);
1176 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1178 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1179 switch (gUserInput
->InputValue
.Type
) {
1180 case EFI_IFR_TYPE_NUM_SIZE_8
:
1181 gUserInput
->InputValue
.Value
.u8
= Option
->OptionOpCode
->Value
.u8
;
1183 case EFI_IFR_TYPE_NUM_SIZE_16
:
1184 CopyMem (&gUserInput
->InputValue
.Value
.u16
, &Option
->OptionOpCode
->Value
.u16
, sizeof (UINT16
));
1186 case EFI_IFR_TYPE_NUM_SIZE_32
:
1187 CopyMem (&gUserInput
->InputValue
.Value
.u32
, &Option
->OptionOpCode
->Value
.u32
, sizeof (UINT32
));
1189 case EFI_IFR_TYPE_NUM_SIZE_64
:
1190 CopyMem (&gUserInput
->InputValue
.Value
.u64
, &Option
->OptionOpCode
->Value
.u64
, sizeof (UINT64
));
1196 gUserInput
->SelectedStatement
= Question
;
1198 FreePool (*OptionString
);
1199 *OptionString
= NULL
;
1200 return EFI_NOT_FOUND
;
1204 Character
[0] = LEFT_ONEOF_DELIMITER
;
1205 NewStrCat (OptionString
[0], MaxLen
, Character
);
1206 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1207 ASSERT (StringPtr
!= NULL
);
1208 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1209 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1210 NewStrCat (OptionString
[0], MaxLen
, Character
);
1212 FreePool (StringPtr
);
1216 case EFI_IFR_CHECKBOX_OP
:
1219 // Since this is a BOOLEAN operation, flip it upon selection
1221 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1222 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
1225 // Perform inconsistent check
1229 *OptionString
= AllocateZeroPool (BufferSize
);
1230 ASSERT (*OptionString
);
1232 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1234 if (QuestionValue
->Value
.b
) {
1235 *(OptionString
[0] + 1) = CHECK_ON
;
1237 *(OptionString
[0] + 1) = CHECK_OFF
;
1239 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1243 case EFI_IFR_NUMERIC_OP
:
1248 Status
= GetNumericInput (MenuOption
);
1250 *OptionString
= AllocateZeroPool (BufferSize
);
1251 ASSERT (*OptionString
);
1253 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1258 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1259 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
1260 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1262 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1266 case EFI_IFR_DATE_OP
:
1269 // This is similar to numerics
1271 Status
= GetNumericInput (MenuOption
);
1273 *OptionString
= AllocateZeroPool (BufferSize
);
1274 ASSERT (*OptionString
);
1276 switch (MenuOption
->Sequence
) {
1278 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1279 if (QuestionValue
->Value
.date
.Month
== 0xff){
1280 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1282 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1284 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1288 SetUnicodeMem (OptionString
[0], 4, L
' ');
1289 if (QuestionValue
->Value
.date
.Day
== 0xff){
1290 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1292 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1294 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1298 SetUnicodeMem (OptionString
[0], 7, L
' ');
1299 if (QuestionValue
->Value
.date
.Year
== 0xff){
1300 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"????");
1302 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1304 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1310 case EFI_IFR_TIME_OP
:
1313 // This is similar to numerics
1315 Status
= GetNumericInput (MenuOption
);
1317 *OptionString
= AllocateZeroPool (BufferSize
);
1318 ASSERT (*OptionString
);
1320 switch (MenuOption
->Sequence
) {
1322 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1323 if (QuestionValue
->Value
.time
.Hour
== 0xff){
1324 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1326 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1328 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1332 SetUnicodeMem (OptionString
[0], 4, L
' ');
1333 if (QuestionValue
->Value
.time
.Minute
== 0xff){
1334 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1336 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1338 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1342 SetUnicodeMem (OptionString
[0], 7, L
' ');
1343 if (QuestionValue
->Value
.time
.Second
== 0xff){
1344 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"??");
1346 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1348 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1354 case EFI_IFR_STRING_OP
:
1356 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1358 CopyMem(StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1360 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1361 if (EFI_ERROR (Status
)) {
1362 FreePool (StringPtr
);
1366 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1367 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1368 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1369 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1370 FreePool (StringPtr
);
1373 *OptionString
= AllocateZeroPool (BufferSize
);
1374 ASSERT (*OptionString
);
1376 if (((CHAR16
*) Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1377 *(OptionString
[0]) = '_';
1379 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1380 BufferSize
= Question
->CurrentValue
.BufferLen
;
1382 CopyMem (OptionString
[0], (CHAR16
*) Question
->CurrentValue
.Buffer
, BufferSize
);
1387 case EFI_IFR_PASSWORD_OP
:
1389 Status
= PasswordProcess (MenuOption
);
1402 Process the help string: Split StringPtr to several lines of strings stored in
1403 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1405 @param StringPtr The entire help string.
1406 @param FormattedString The oupput formatted string.
1407 @param EachLineWidth The max string length of each line in the formatted string.
1408 @param RowCount TRUE: if Question is selected.
1413 IN CHAR16
*StringPtr
,
1414 OUT CHAR16
**FormattedString
,
1415 OUT UINT16
*EachLineWidth
,
1420 CHAR16
*OutputString
;
1425 UINT16 MaxStringLen
;
1436 // Set default help string width.
1438 LineWidth
= (UINT16
) (gHelpBlockWidth
- 1);
1441 // Get row number of the String.
1443 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1444 if (StringLen
> MaxStringLen
) {
1445 MaxStringLen
= StringLen
;
1449 FreePool (OutputString
);
1451 *EachLineWidth
= MaxStringLen
;
1453 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1454 ASSERT (*FormattedString
!= NULL
);
1457 // Generate formatted help string array.
1461 while((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1462 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1464 FreePool (OutputString
);