2 Implementation for handling the User Interface option processing.
5 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "FormDisplay.h"
18 #define MAX_TIME_OUT_LEN 0x10
21 Concatenate a narrow string to another string.
23 @param Destination The destination string.
24 @param DestMax The Max length of destination string.
25 @param Source The source string. The string to be concatenated.
26 to the end of Destination.
31 IN OUT CHAR16
*Destination
,
38 for (Length
= 0; Destination
[Length
] != 0; Length
++)
42 // We now have the length of the original string
43 // We can safely assume for now that we are concatenating a narrow value to this string.
44 // For instance, the string is "XYZ" and cat'ing ">"
45 // If this assumption changes, we need to make this routine a bit more complex
47 Destination
[Length
] = NARROW_CHAR
;
50 StrCpyS (Destination
+ Length
, DestMax
- Length
, Source
);
54 Get UINT64 type value.
56 @param Value Input Hii value.
58 @retval UINT64 Return the UINT64 type value.
63 IN EFI_HII_VALUE
*Value
70 switch (Value
->Type
) {
71 case EFI_IFR_TYPE_NUM_SIZE_8
:
72 RetVal
= Value
->Value
.u8
;
75 case EFI_IFR_TYPE_NUM_SIZE_16
:
76 RetVal
= Value
->Value
.u16
;
79 case EFI_IFR_TYPE_NUM_SIZE_32
:
80 RetVal
= Value
->Value
.u32
;
83 case EFI_IFR_TYPE_BOOLEAN
:
84 RetVal
= Value
->Value
.b
;
87 case EFI_IFR_TYPE_DATE
:
88 RetVal
= *(UINT64
*) &Value
->Value
.date
;
91 case EFI_IFR_TYPE_TIME
:
92 RetVal
= (*(UINT64
*) &Value
->Value
.time
) & 0xffffff;
96 RetVal
= Value
->Value
.u64
;
104 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
106 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
107 EFI_IFR_TYPE_BUFFER when do the value compare.
109 @param Value Expression value to compare on.
111 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
112 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
117 IN EFI_HII_VALUE
*Value
120 switch (Value
->Type
) {
121 case EFI_IFR_TYPE_BUFFER
:
122 case EFI_IFR_TYPE_DATE
:
123 case EFI_IFR_TYPE_TIME
:
124 case EFI_IFR_TYPE_REF
:
133 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
135 @param Value Expression value to compare on.
137 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
138 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
143 IN EFI_HII_VALUE
*Value
146 switch (Value
->Type
) {
147 case EFI_IFR_TYPE_NUM_SIZE_8
:
148 case EFI_IFR_TYPE_NUM_SIZE_16
:
149 case EFI_IFR_TYPE_NUM_SIZE_32
:
150 case EFI_IFR_TYPE_NUM_SIZE_64
:
151 case EFI_IFR_TYPE_BOOLEAN
:
160 Return the buffer length and buffer pointer for this value.
162 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
163 EFI_IFR_TYPE_BUFFER when do the value compare.
165 @param Value Expression value to compare on.
166 @param Buf Return the buffer pointer.
167 @param BufLen Return the buffer length.
171 GetBufAndLenForValue (
172 IN EFI_HII_VALUE
*Value
,
177 switch (Value
->Type
) {
178 case EFI_IFR_TYPE_BUFFER
:
179 *Buf
= Value
->Buffer
;
180 *BufLen
= Value
->BufferLen
;
183 case EFI_IFR_TYPE_DATE
:
184 *Buf
= (UINT8
*) (&Value
->Value
.date
);
185 *BufLen
= (UINT16
) sizeof (EFI_HII_DATE
);
188 case EFI_IFR_TYPE_TIME
:
189 *Buf
= (UINT8
*) (&Value
->Value
.time
);
190 *BufLen
= (UINT16
) sizeof (EFI_HII_TIME
);
193 case EFI_IFR_TYPE_REF
:
194 *Buf
= (UINT8
*) (&Value
->Value
.ref
);
195 *BufLen
= (UINT16
) sizeof (EFI_HII_REF
);
205 Compare two Hii value.
207 @param Value1 Expression value to compare on left-hand.
208 @param Value2 Expression value to compare on right-hand.
209 @param Result Return value after compare.
210 retval 0 Two operators equal.
211 return Positive value if Value1 is greater than Value2.
212 retval Negative value if Value1 is less than Value2.
213 @param HiiHandle Only required for string compare.
215 @retval other Could not perform compare on two values.
216 @retval EFI_SUCCESS Compare the value success.
221 IN EFI_HII_VALUE
*Value1
,
222 IN EFI_HII_VALUE
*Value2
,
224 IN EFI_HII_HANDLE HiiHandle OPTIONAL
236 if (Value1
->Type
== EFI_IFR_TYPE_STRING
&& Value2
->Type
== EFI_IFR_TYPE_STRING
) {
237 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
239 // StringId 0 is reserved
241 return EFI_INVALID_PARAMETER
;
244 if (Value1
->Value
.string
== Value2
->Value
.string
) {
249 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
254 return EFI_NOT_FOUND
;
257 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
260 return EFI_NOT_FOUND
;
263 *Result
= StrCmp (Str1
, Str2
);
272 // Take types(date, time, ref, buffer) as buffer
274 if (IsTypeInBuffer(Value1
) && IsTypeInBuffer(Value2
)) {
275 GetBufAndLenForValue(Value1
, &Buf1
, &Buf1Len
);
276 GetBufAndLenForValue(Value2
, &Buf2
, &Buf2Len
);
278 Len
= Buf1Len
> Buf2Len
? Buf2Len
: Buf1Len
;
279 *Result
= CompareMem (Buf1
, Buf2
, Len
);
280 if ((*Result
== 0) && (Buf1Len
!= Buf2Len
)) {
282 // In this case, means base on samll number buffer, the data is same
283 // So which value has more data, which value is bigger.
285 *Result
= Buf1Len
> Buf2Len
? 1 : -1;
291 // Take remain types(integer, boolean, date/time) as integer
293 if (IsTypeInUINT64(Value1
) && IsTypeInUINT64(Value2
)) {
294 Temp64
= HiiValueToUINT64(Value1
) - HiiValueToUINT64(Value2
);
297 } else if (Temp64
< 0) {
305 return EFI_UNSUPPORTED
;
309 Search an Option of a Question by its value.
311 @param Question The Question
312 @param OptionValue Value for Option to be searched.
314 @retval Pointer Pointer to the found Option.
315 @retval NULL Option not found.
318 DISPLAY_QUESTION_OPTION
*
320 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
321 IN EFI_HII_VALUE
*OptionValue
325 DISPLAY_QUESTION_OPTION
*Option
;
329 Link
= GetFirstNode (&Question
->OptionListHead
);
330 while (!IsNull (&Question
->OptionListHead
, Link
)) {
331 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
333 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
334 Value
.Type
= Option
->OptionOpCode
->Type
;
335 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
337 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
341 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
349 Return data element in an Array by its Index.
351 @param Array The data array.
352 @param Type Type of the data in this array.
353 @param Index Zero based index for data in this array.
355 @retval Value The data to be returned
367 ASSERT (Array
!= NULL
);
371 case EFI_IFR_TYPE_NUM_SIZE_8
:
372 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
375 case EFI_IFR_TYPE_NUM_SIZE_16
:
376 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
379 case EFI_IFR_TYPE_NUM_SIZE_32
:
380 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
383 case EFI_IFR_TYPE_NUM_SIZE_64
:
384 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
396 Set value of a data element in an Array by its Index.
398 @param Array The data array.
399 @param Type Type of the data in this array.
400 @param Index Zero based index for data in this array.
401 @param Value The value to be set.
413 ASSERT (Array
!= NULL
);
416 case EFI_IFR_TYPE_NUM_SIZE_8
:
417 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
420 case EFI_IFR_TYPE_NUM_SIZE_16
:
421 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
424 case EFI_IFR_TYPE_NUM_SIZE_32
:
425 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
428 case EFI_IFR_TYPE_NUM_SIZE_64
:
429 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
438 Check whether this value already in the array, if yes, return the index.
440 @param Array The data array.
441 @param Type Type of the data in this array.
442 @param Value The value to be find.
443 @param Index The index in the array which has same value with Value.
445 @retval TRUE Found the value in the array.
446 @retval FALSE Not found the value.
454 OUT UINTN
*Index OPTIONAL
461 ASSERT (Array
!= NULL
);
467 case EFI_IFR_TYPE_NUM_SIZE_8
:
468 ValueComp
= (UINT8
) Value
;
471 case EFI_IFR_TYPE_NUM_SIZE_16
:
472 ValueComp
= (UINT16
) Value
;
475 case EFI_IFR_TYPE_NUM_SIZE_32
:
476 ValueComp
= (UINT32
) Value
;
479 case EFI_IFR_TYPE_NUM_SIZE_64
:
480 ValueComp
= (UINT64
) Value
;
488 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
489 if (ValueComp
== TmpValue
) {
503 Print Question Value according to it's storage width and display attributes.
505 @param Question The Question to be printed.
506 @param FormattedNumber Buffer for output string.
507 @param BufferSize The FormattedNumber buffer size in bytes.
509 @retval EFI_SUCCESS Print success.
510 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
514 PrintFormattedNumber (
515 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
516 IN OUT CHAR16
*FormattedNumber
,
522 EFI_HII_VALUE
*QuestionValue
;
523 EFI_IFR_NUMERIC
*NumericOp
;
525 if (BufferSize
< (21 * sizeof (CHAR16
))) {
526 return EFI_BUFFER_TOO_SMALL
;
529 QuestionValue
= &Question
->CurrentValue
;
530 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
532 Value
= (INT64
) QuestionValue
->Value
.u64
;
533 switch (NumericOp
->Flags
& EFI_IFR_DISPLAY
) {
534 case EFI_IFR_DISPLAY_INT_DEC
:
535 switch (QuestionValue
->Type
) {
536 case EFI_IFR_NUMERIC_SIZE_1
:
537 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
540 case EFI_IFR_NUMERIC_SIZE_2
:
541 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
544 case EFI_IFR_NUMERIC_SIZE_4
:
545 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
548 case EFI_IFR_NUMERIC_SIZE_8
:
561 case EFI_IFR_DISPLAY_UINT_DEC
:
565 case EFI_IFR_DISPLAY_UINT_HEX
:
570 return EFI_UNSUPPORTED
;
574 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
581 Draw a pop up windows based on the dimension, number of lines and
584 @param RequestedWidth The width of the pop-up.
585 @param NumberOfLines The number of lines.
586 @param Marker The variable argument list for the list of string to be printed.
591 IN UINTN RequestedWidth
,
592 IN UINTN NumberOfLines
,
604 UINTN DimensionsWidth
;
605 UINTN DimensionsHeight
;
607 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
608 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
610 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
612 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
613 RequestedWidth
= DimensionsWidth
- 2;
617 // Subtract the PopUp width from total Columns, allow for one space extra on
618 // each end plus a border.
620 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
621 End
= Start
+ RequestedWidth
+ 1;
623 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gStatementDimensions
.TopRow
- 1;
624 Bottom
= Top
+ NumberOfLines
+ 2;
626 Character
= BOXDRAW_DOWN_RIGHT
;
627 PrintCharAt (Start
, Top
, Character
);
628 Character
= BOXDRAW_HORIZONTAL
;
629 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
630 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
633 Character
= BOXDRAW_DOWN_LEFT
;
634 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
635 Character
= BOXDRAW_VERTICAL
;
638 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
639 String
= VA_ARG (Marker
, CHAR16
*);
642 // This will clear the background of the line - we never know who might have been
643 // here before us. This differs from the next clear in that it used the non-reverse
644 // video for normal printing.
646 if (GetStringWidth (String
) / 2 > 1) {
647 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
651 // Passing in a space results in the assumption that this is where typing will occur
653 if (String
[0] == L
' ') {
654 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, GetPopupInverseColor ());
658 // Passing in a NULL results in a blank space
660 if (String
[0] == CHAR_NULL
) {
661 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
665 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gStatementDimensions
.LeftColumn
+ 1,
669 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
670 PrintCharAt (Start
, Index
+ 1, Character
);
671 PrintCharAt (End
- 1, Index
+ 1, Character
);
674 Character
= BOXDRAW_UP_RIGHT
;
675 PrintCharAt (Start
, Bottom
- 1, Character
);
676 Character
= BOXDRAW_HORIZONTAL
;
677 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
678 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
681 Character
= BOXDRAW_UP_LEFT
;
682 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
686 Draw a pop up windows based on the dimension, number of lines and
689 @param RequestedWidth The width of the pop-up.
690 @param NumberOfLines The number of lines.
691 @param ... A series of text strings that displayed in the pop-up.
696 CreateMultiStringPopUp (
697 IN UINTN RequestedWidth
,
698 IN UINTN NumberOfLines
,
704 VA_START (Marker
, NumberOfLines
);
706 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
714 @param Event The Event need to be process
715 @param Context The context of the event.
728 Process for the refresh interval statement.
730 @param Event The Event need to be process
731 @param Context The context of the event.
736 RefreshTimeOutProcess (
741 WARNING_IF_CONTEXT
*EventInfo
;
742 CHAR16 TimeOutString
[MAX_TIME_OUT_LEN
];
744 EventInfo
= (WARNING_IF_CONTEXT
*) Context
;
746 if (*(EventInfo
->TimeOut
) == 0) {
747 gBS
->CloseEvent (Event
);
749 gBS
->SignalEvent (EventInfo
->SyncEvent
);
753 UnicodeSPrint(TimeOutString
, MAX_TIME_OUT_LEN
, L
"%d", *(EventInfo
->TimeOut
));
755 CreateDialog (NULL
, gEmptyString
, EventInfo
->ErrorInfo
, gPressEnter
, gEmptyString
, TimeOutString
, NULL
);
757 *(EventInfo
->TimeOut
) -= 1;
761 Display error message for invalid password.
772 // Invalid password, prompt error message
775 CreateDialog (&Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
, NULL
);
776 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
780 Process password op code.
782 @param MenuOption The menu for current password op code.
784 @retval EFI_SUCCESS Question Option process success.
785 @retval Other Question Option process fail.
790 IN UI_MENU_OPTION
*MenuOption
797 EFI_IFR_PASSWORD
*PasswordInfo
;
798 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
801 Question
= MenuOption
->ThisTag
;
802 PasswordInfo
= (EFI_IFR_PASSWORD
*) Question
->OpCode
;
803 Maximum
= PasswordInfo
->MaxSize
;
804 Status
= EFI_SUCCESS
;
806 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
810 // Use a NULL password to test whether old password is required
813 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
814 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
816 // Password can't be set now.
818 FreePool (StringPtr
);
822 if (EFI_ERROR (Status
)) {
824 // Old password exist, ask user for the old password
826 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
827 if (EFI_ERROR (Status
)) {
828 FreePool (StringPtr
);
833 // Check user input old password
835 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
836 if (EFI_ERROR (Status
)) {
837 if (Status
== EFI_NOT_READY
) {
839 // Typed in old password incorrect
843 Status
= EFI_SUCCESS
;
846 FreePool (StringPtr
);
852 // Ask for new password
854 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
855 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
856 if (EFI_ERROR (Status
)) {
858 // Reset state machine for password
860 Question
->PasswordCheck (gFormData
, Question
, NULL
);
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 FreePool (StringPtr
);
877 FreePool (TempString
);
882 // Compare two typed-in new passwords
884 if (StrCmp (StringPtr
, TempString
) == 0) {
885 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
886 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
887 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
888 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
889 FreePool (StringPtr
);
891 Status
= EFI_SUCCESS
;
893 if (EFI_ERROR (Status
)) {
895 // Reset state machine for password
897 Question
->PasswordCheck (gFormData
, Question
, NULL
);
903 // Reset state machine for password
905 Question
->PasswordCheck (gFormData
, Question
, NULL
);
908 // Two password mismatch, prompt error message
911 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
912 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
914 Status
= EFI_INVALID_PARAMETER
;
917 FreePool (TempString
);
918 FreePool (StringPtr
);
924 Process a Question's Option (whether selected or un-selected).
926 @param MenuOption The MenuOption for this Question.
927 @param Selected TRUE: if Question is selected.
928 @param OptionString Pointer of the Option String to be displayed.
929 @param SkipErrorValue Whether need to return when value without option for it.
931 @retval EFI_SUCCESS Question Option process success.
932 @retval Other Question Option process fail.
937 IN UI_MENU_OPTION
*MenuOption
,
939 OUT CHAR16
**OptionString
,
940 IN BOOLEAN SkipErrorValue
946 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
947 CHAR16 FormattedNumber
[21];
952 DISPLAY_QUESTION_OPTION
*OneOfOption
;
954 EFI_HII_VALUE HiiValue
;
955 EFI_HII_VALUE
*QuestionValue
;
956 DISPLAY_QUESTION_OPTION
*Option
;
960 EFI_IFR_ORDERED_LIST
*OrderList
;
961 BOOLEAN ValueInvalid
;
964 Status
= EFI_SUCCESS
;
967 Character
[1] = L
'\0';
968 *OptionString
= NULL
;
969 ValueInvalid
= FALSE
;
971 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
972 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
974 Question
= MenuOption
->ThisTag
;
975 QuestionValue
= &Question
->CurrentValue
;
977 switch (Question
->OpCode
->OpCode
) {
978 case EFI_IFR_ORDERED_LIST_OP
:
981 // Check whether there are Options of this OrderedList
983 if (IsListEmpty (&Question
->OptionListHead
)) {
987 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
989 Link
= GetFirstNode (&Question
->OptionListHead
);
990 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
992 ValueType
= OneOfOption
->OptionOpCode
->Type
;
993 ValueArray
= Question
->CurrentValue
.Buffer
;
999 Status
= GetSelectionInputPopUp (MenuOption
);
1002 // We now know how many strings we will have, so we can allocate the
1003 // space required for the array or strings.
1005 MaxLen
= OrderList
->MaxContainers
* BufferSize
/ sizeof (CHAR16
);
1006 *OptionString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
1007 ASSERT (*OptionString
);
1009 HiiValue
.Type
= ValueType
;
1010 HiiValue
.Value
.u64
= 0;
1011 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1012 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1013 if (HiiValue
.Value
.u64
== 0) {
1015 // Values for the options in ordered lists should never be a 0
1020 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1021 if (OneOfOption
== NULL
) {
1022 if (SkipErrorValue
) {
1024 // Just try to get the option string, skip the value which not has option.
1030 // Show error message
1033 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1034 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1037 // The initial value of the orderedlist is invalid, force to be valid value
1038 // Exit current DisplayForm with new value.
1040 gUserInput
->SelectedStatement
= Question
;
1042 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1043 ASSERT (ValueArray
!= NULL
);
1044 gUserInput
->InputValue
.Buffer
= ValueArray
;
1045 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1046 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1048 Link
= GetFirstNode (&Question
->OptionListHead
);
1050 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
1051 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1052 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1053 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
1056 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
1058 FreePool (*OptionString
);
1059 *OptionString
= NULL
;
1060 return EFI_NOT_FOUND
;
1063 Character
[0] = LEFT_ONEOF_DELIMITER
;
1064 NewStrCat (OptionString
[0], MaxLen
, Character
);
1065 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1066 ASSERT (StringPtr
!= NULL
);
1067 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1068 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1069 NewStrCat (OptionString
[0], MaxLen
, Character
);
1070 Character
[0] = CHAR_CARRIAGE_RETURN
;
1071 NewStrCat (OptionString
[0], MaxLen
, Character
);
1072 FreePool (StringPtr
);
1076 // If valid option more than the max container, skip these options.
1078 if (Index
>= OrderList
->MaxContainers
) {
1083 // Search the other options, try to find the one not in the container.
1085 Link
= GetFirstNode (&Question
->OptionListHead
);
1086 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1087 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1088 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1090 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
1094 if (SkipErrorValue
) {
1096 // Not report error, just get the correct option string info.
1098 Character
[0] = LEFT_ONEOF_DELIMITER
;
1099 NewStrCat (OptionString
[0], MaxLen
, Character
);
1100 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1101 ASSERT (StringPtr
!= NULL
);
1102 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1103 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1104 NewStrCat (OptionString
[0], MaxLen
, Character
);
1105 Character
[0] = CHAR_CARRIAGE_RETURN
;
1106 NewStrCat (OptionString
[0], MaxLen
, Character
);
1107 FreePool (StringPtr
);
1112 if (!ValueInvalid
) {
1113 ValueInvalid
= TRUE
;
1115 // Show error message
1118 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1119 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1122 // The initial value of the orderedlist is invalid, force to be valid value
1123 // Exit current DisplayForm with new value.
1125 gUserInput
->SelectedStatement
= Question
;
1127 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
1128 ASSERT (ValueArray
!= NULL
);
1129 gUserInput
->InputValue
.Buffer
= ValueArray
;
1130 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1131 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1134 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
1138 FreePool (*OptionString
);
1139 *OptionString
= NULL
;
1140 return EFI_NOT_FOUND
;
1145 case EFI_IFR_ONE_OF_OP
:
1147 // Check whether there are Options of this OneOf
1149 if (IsListEmpty (&Question
->OptionListHead
)) {
1156 Status
= GetSelectionInputPopUp (MenuOption
);
1158 MaxLen
= BufferSize
/ sizeof(CHAR16
);
1159 *OptionString
= AllocateZeroPool (BufferSize
);
1160 ASSERT (*OptionString
);
1162 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1163 if (OneOfOption
== NULL
) {
1164 if (SkipErrorValue
) {
1166 // Not report error, just get the correct option string info.
1168 Link
= GetFirstNode (&Question
->OptionListHead
);
1169 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1172 // Show error message
1175 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1176 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1179 // Force the Question value to be valid
1180 // Exit current DisplayForm with new value.
1182 Link
= GetFirstNode (&Question
->OptionListHead
);
1183 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1185 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1186 switch (gUserInput
->InputValue
.Type
) {
1187 case EFI_IFR_TYPE_NUM_SIZE_8
:
1188 gUserInput
->InputValue
.Value
.u8
= Option
->OptionOpCode
->Value
.u8
;
1190 case EFI_IFR_TYPE_NUM_SIZE_16
:
1191 CopyMem (&gUserInput
->InputValue
.Value
.u16
, &Option
->OptionOpCode
->Value
.u16
, sizeof (UINT16
));
1193 case EFI_IFR_TYPE_NUM_SIZE_32
:
1194 CopyMem (&gUserInput
->InputValue
.Value
.u32
, &Option
->OptionOpCode
->Value
.u32
, sizeof (UINT32
));
1196 case EFI_IFR_TYPE_NUM_SIZE_64
:
1197 CopyMem (&gUserInput
->InputValue
.Value
.u64
, &Option
->OptionOpCode
->Value
.u64
, sizeof (UINT64
));
1203 gUserInput
->SelectedStatement
= Question
;
1205 FreePool (*OptionString
);
1206 *OptionString
= NULL
;
1207 return EFI_NOT_FOUND
;
1211 Character
[0] = LEFT_ONEOF_DELIMITER
;
1212 NewStrCat (OptionString
[0], MaxLen
, Character
);
1213 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1214 ASSERT (StringPtr
!= NULL
);
1215 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1216 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1217 NewStrCat (OptionString
[0], MaxLen
, Character
);
1219 FreePool (StringPtr
);
1223 case EFI_IFR_CHECKBOX_OP
:
1226 // Since this is a BOOLEAN operation, flip it upon selection
1228 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1229 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
1232 // Perform inconsistent check
1236 *OptionString
= AllocateZeroPool (BufferSize
);
1237 ASSERT (*OptionString
);
1239 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1241 if (QuestionValue
->Value
.b
) {
1242 *(OptionString
[0] + 1) = CHECK_ON
;
1244 *(OptionString
[0] + 1) = CHECK_OFF
;
1246 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1250 case EFI_IFR_NUMERIC_OP
:
1255 Status
= GetNumericInput (MenuOption
);
1257 *OptionString
= AllocateZeroPool (BufferSize
);
1258 ASSERT (*OptionString
);
1260 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1265 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1266 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
1267 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1269 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1273 case EFI_IFR_DATE_OP
:
1276 // This is similar to numerics
1278 Status
= GetNumericInput (MenuOption
);
1280 *OptionString
= AllocateZeroPool (BufferSize
);
1281 ASSERT (*OptionString
);
1283 switch (MenuOption
->Sequence
) {
1285 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1286 if (QuestionValue
->Value
.date
.Month
== 0xff){
1287 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1289 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1291 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1295 SetUnicodeMem (OptionString
[0], 4, L
' ');
1296 if (QuestionValue
->Value
.date
.Day
== 0xff){
1297 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1299 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1301 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1305 SetUnicodeMem (OptionString
[0], 7, L
' ');
1306 if (QuestionValue
->Value
.date
.Year
== 0xff){
1307 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"????");
1309 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1311 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1317 case EFI_IFR_TIME_OP
:
1320 // This is similar to numerics
1322 Status
= GetNumericInput (MenuOption
);
1324 *OptionString
= AllocateZeroPool (BufferSize
);
1325 ASSERT (*OptionString
);
1327 switch (MenuOption
->Sequence
) {
1329 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1330 if (QuestionValue
->Value
.time
.Hour
== 0xff){
1331 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1333 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1335 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1339 SetUnicodeMem (OptionString
[0], 4, L
' ');
1340 if (QuestionValue
->Value
.time
.Minute
== 0xff){
1341 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1343 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1345 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1349 SetUnicodeMem (OptionString
[0], 7, L
' ');
1350 if (QuestionValue
->Value
.time
.Second
== 0xff){
1351 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"??");
1353 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1355 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1361 case EFI_IFR_STRING_OP
:
1363 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1365 CopyMem(StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1367 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1368 if (EFI_ERROR (Status
)) {
1369 FreePool (StringPtr
);
1373 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1374 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1375 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1376 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1377 FreePool (StringPtr
);
1380 *OptionString
= AllocateZeroPool (BufferSize
);
1381 ASSERT (*OptionString
);
1383 if (((CHAR16
*) Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1384 *(OptionString
[0]) = '_';
1386 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1387 BufferSize
= Question
->CurrentValue
.BufferLen
;
1389 CopyMem (OptionString
[0], (CHAR16
*) Question
->CurrentValue
.Buffer
, BufferSize
);
1394 case EFI_IFR_PASSWORD_OP
:
1396 Status
= PasswordProcess (MenuOption
);
1409 Process the help string: Split StringPtr to several lines of strings stored in
1410 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1412 @param StringPtr The entire help string.
1413 @param FormattedString The oupput formatted string.
1414 @param EachLineWidth The max string length of each line in the formatted string.
1415 @param RowCount TRUE: if Question is selected.
1420 IN CHAR16
*StringPtr
,
1421 OUT CHAR16
**FormattedString
,
1422 OUT UINT16
*EachLineWidth
,
1427 CHAR16
*OutputString
;
1432 UINT16 MaxStringLen
;
1443 // Set default help string width.
1445 LineWidth
= (UINT16
) (gHelpBlockWidth
- 1);
1448 // Get row number of the String.
1450 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1451 if (StringLen
> MaxStringLen
) {
1452 MaxStringLen
= StringLen
;
1456 FreePool (OutputString
);
1458 *EachLineWidth
= MaxStringLen
;
1460 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1461 ASSERT (*FormattedString
!= NULL
);
1464 // Generate formatted help string array.
1468 while((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1469 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1471 FreePool (OutputString
);