2 Implementation for handling the User Interface option processing.
5 Copyright (c) 2004 - 2012, 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"
19 Concatenate a narrow string to another string.
21 @param Destination The destination string.
22 @param Source The source string. The string to be concatenated.
23 to the end of Destination.
28 IN OUT CHAR16
*Destination
,
34 for (Length
= 0; Destination
[Length
] != 0; Length
++)
38 // We now have the length of the original string
39 // We can safely assume for now that we are concatenating a narrow value to this string.
40 // For instance, the string is "XYZ" and cat'ing ">"
41 // If this assumption changes, we need to make this routine a bit more complex
43 Destination
[Length
] = NARROW_CHAR
;
46 StrCpy (Destination
+ Length
, Source
);
50 Compare two Hii value.
52 @param Value1 Expression value to compare on left-hand.
53 @param Value2 Expression value to compare on right-hand.
54 @param Result Return value after compare.
55 retval 0 Two operators equal.
56 return Positive value if Value1 is greater than Value2.
57 retval Negative value if Value1 is less than Value2.
58 @param HiiHandle Only required for string compare.
60 @retval other Could not perform compare on two values.
61 @retval EFI_SUCCESS Compare the value success.
66 IN EFI_HII_VALUE
*Value1
,
67 IN EFI_HII_VALUE
*Value2
,
69 IN EFI_HII_HANDLE HiiHandle OPTIONAL
77 if (Value1
->Type
>= EFI_IFR_TYPE_OTHER
|| Value2
->Type
>= EFI_IFR_TYPE_OTHER
) {
78 if (Value1
->Type
!= EFI_IFR_TYPE_BUFFER
&& Value2
->Type
!= EFI_IFR_TYPE_BUFFER
) {
79 return EFI_UNSUPPORTED
;
83 if (Value1
->Type
== EFI_IFR_TYPE_STRING
|| Value2
->Type
== EFI_IFR_TYPE_STRING
) {
84 if (Value1
->Type
!= Value2
->Type
) {
86 // Both Operator should be type of String
88 return EFI_UNSUPPORTED
;
91 if (Value1
->Value
.string
== 0 || Value2
->Value
.string
== 0) {
93 // StringId 0 is reserved
95 return EFI_INVALID_PARAMETER
;
98 if (Value1
->Value
.string
== Value2
->Value
.string
) {
103 Str1
= GetToken (Value1
->Value
.string
, HiiHandle
);
108 return EFI_NOT_FOUND
;
111 Str2
= GetToken (Value2
->Value
.string
, HiiHandle
);
114 return EFI_NOT_FOUND
;
117 *Result
= StrCmp (Str1
, Str2
);
125 if (Value1
->Type
== EFI_IFR_TYPE_BUFFER
|| Value2
->Type
== EFI_IFR_TYPE_BUFFER
) {
126 if (Value1
->Type
!= Value2
->Type
) {
128 // Both Operator should be type of Buffer.
130 return EFI_UNSUPPORTED
;
132 Len
= Value1
->BufferLen
> Value2
->BufferLen
? Value2
->BufferLen
: Value1
->BufferLen
;
133 *Result
= CompareMem (Value1
->Buffer
, Value2
->Buffer
, Len
);
134 if ((*Result
== 0) && (Value1
->BufferLen
!= Value2
->BufferLen
))
137 // In this case, means base on samll number buffer, the data is same
138 // So which value has more data, which value is bigger.
140 *Result
= Value1
->BufferLen
> Value2
->BufferLen
? 1 : -1;
146 // Take remain types(integer, boolean, date/time) as integer
148 Temp64
= (INT64
) (Value1
->Value
.u64
- Value2
->Value
.u64
);
151 } else if (Temp64
< 0) {
161 Search an Option of a Question by its value.
163 @param Question The Question
164 @param OptionValue Value for Option to be searched.
166 @retval Pointer Pointer to the found Option.
167 @retval NULL Option not found.
170 DISPLAY_QUESTION_OPTION
*
172 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
173 IN EFI_HII_VALUE
*OptionValue
177 DISPLAY_QUESTION_OPTION
*Option
;
181 Link
= GetFirstNode (&Question
->OptionListHead
);
182 while (!IsNull (&Question
->OptionListHead
, Link
)) {
183 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
185 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
186 Value
.Type
= Option
->OptionOpCode
->Type
;
187 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
189 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
193 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
201 Return data element in an Array by its Index.
203 @param Array The data array.
204 @param Type Type of the data in this array.
205 @param Index Zero based index for data in this array.
207 @retval Value The data to be returned
219 ASSERT (Array
!= NULL
);
223 case EFI_IFR_TYPE_NUM_SIZE_8
:
224 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
227 case EFI_IFR_TYPE_NUM_SIZE_16
:
228 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
231 case EFI_IFR_TYPE_NUM_SIZE_32
:
232 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
235 case EFI_IFR_TYPE_NUM_SIZE_64
:
236 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
248 Set value of a data element in an Array by its Index.
250 @param Array The data array.
251 @param Type Type of the data in this array.
252 @param Index Zero based index for data in this array.
253 @param Value The value to be set.
265 ASSERT (Array
!= NULL
);
268 case EFI_IFR_TYPE_NUM_SIZE_8
:
269 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
272 case EFI_IFR_TYPE_NUM_SIZE_16
:
273 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
276 case EFI_IFR_TYPE_NUM_SIZE_32
:
277 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
280 case EFI_IFR_TYPE_NUM_SIZE_64
:
281 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
290 Check whether this value already in the array, if yes, return the index.
292 @param Array The data array.
293 @param Type Type of the data in this array.
294 @param Value The value to be find.
295 @param Index The index in the array which has same value with Value.
297 @retval TRUE Found the value in the array.
298 @retval FALSE Not found the value.
306 OUT UINTN
*Index OPTIONAL
313 ASSERT (Array
!= NULL
);
319 case EFI_IFR_TYPE_NUM_SIZE_8
:
320 ValueComp
= (UINT8
) Value
;
323 case EFI_IFR_TYPE_NUM_SIZE_16
:
324 ValueComp
= (UINT16
) Value
;
327 case EFI_IFR_TYPE_NUM_SIZE_32
:
328 ValueComp
= (UINT32
) Value
;
331 case EFI_IFR_TYPE_NUM_SIZE_64
:
332 ValueComp
= (UINT64
) Value
;
340 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
341 if (ValueComp
== TmpValue
) {
355 Print Question Value according to it's storage width and display attributes.
357 @param Question The Question to be printed.
358 @param FormattedNumber Buffer for output string.
359 @param BufferSize The FormattedNumber buffer size in bytes.
361 @retval EFI_SUCCESS Print success.
362 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
366 PrintFormattedNumber (
367 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
368 IN OUT CHAR16
*FormattedNumber
,
374 EFI_HII_VALUE
*QuestionValue
;
375 EFI_IFR_NUMERIC
*NumericOp
;
377 if (BufferSize
< (21 * sizeof (CHAR16
))) {
378 return EFI_BUFFER_TOO_SMALL
;
381 QuestionValue
= &Question
->CurrentValue
;
382 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
384 Value
= (INT64
) QuestionValue
->Value
.u64
;
385 switch (NumericOp
->Flags
& EFI_IFR_DISPLAY
) {
386 case EFI_IFR_DISPLAY_INT_DEC
:
387 switch (QuestionValue
->Type
) {
388 case EFI_IFR_NUMERIC_SIZE_1
:
389 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
392 case EFI_IFR_NUMERIC_SIZE_2
:
393 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
396 case EFI_IFR_NUMERIC_SIZE_4
:
397 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
400 case EFI_IFR_NUMERIC_SIZE_8
:
413 case EFI_IFR_DISPLAY_UINT_DEC
:
417 case EFI_IFR_DISPLAY_UINT_HEX
:
422 return EFI_UNSUPPORTED
;
426 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
433 Draw a pop up windows based on the dimension, number of lines and
436 @param RequestedWidth The width of the pop-up.
437 @param NumberOfLines The number of lines.
438 @param Marker The variable argument list for the list of string to be printed.
443 IN UINTN RequestedWidth
,
444 IN UINTN NumberOfLines
,
456 UINTN DimensionsWidth
;
457 UINTN DimensionsHeight
;
459 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
460 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
462 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
464 if ((RequestedWidth
+ 2) > DimensionsWidth
) {
465 RequestedWidth
= DimensionsWidth
- 2;
469 // Subtract the PopUp width from total Columns, allow for one space extra on
470 // each end plus a border.
472 Start
= (DimensionsWidth
- RequestedWidth
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
473 End
= Start
+ RequestedWidth
+ 1;
475 Top
= ((DimensionsHeight
- NumberOfLines
- 2) / 2) + gStatementDimensions
.TopRow
- 1;
476 Bottom
= Top
+ NumberOfLines
+ 2;
478 Character
= BOXDRAW_DOWN_RIGHT
;
479 PrintCharAt (Start
, Top
, Character
);
480 Character
= BOXDRAW_HORIZONTAL
;
481 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
482 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
485 Character
= BOXDRAW_DOWN_LEFT
;
486 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
487 Character
= BOXDRAW_VERTICAL
;
490 for (Index
= Top
; Index
+ 2 < Bottom
; Index
++, Count
++) {
491 String
= VA_ARG (Marker
, CHAR16
*);
494 // This will clear the background of the line - we never know who might have been
495 // here before us. This differs from the next clear in that it used the non-reverse
496 // video for normal printing.
498 if (GetStringWidth (String
) / 2 > 1) {
499 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
503 // Passing in a space results in the assumption that this is where typing will occur
505 if (String
[0] == L
' ') {
506 ClearLines (Start
+ 1, End
- 1, Index
+ 1, Index
+ 1, GetPopupInverseColor ());
510 // Passing in a NULL results in a blank space
512 if (String
[0] == CHAR_NULL
) {
513 ClearLines (Start
, End
, Index
+ 1, Index
+ 1, GetPopupColor ());
517 ((DimensionsWidth
- GetStringWidth (String
) / 2) / 2) + gStatementDimensions
.LeftColumn
+ 1,
521 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
522 PrintCharAt (Start
, Index
+ 1, Character
);
523 PrintCharAt (End
- 1, Index
+ 1, Character
);
526 Character
= BOXDRAW_UP_RIGHT
;
527 PrintCharAt (Start
, Bottom
- 1, Character
);
528 Character
= BOXDRAW_HORIZONTAL
;
529 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
530 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
533 Character
= BOXDRAW_UP_LEFT
;
534 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
538 Draw a pop up windows based on the dimension, number of lines and
541 @param RequestedWidth The width of the pop-up.
542 @param NumberOfLines The number of lines.
543 @param ... A series of text strings that displayed in the pop-up.
548 CreateMultiStringPopUp (
549 IN UINTN RequestedWidth
,
550 IN UINTN NumberOfLines
,
556 VA_START (Marker
, NumberOfLines
);
558 CreateSharedPopUp (RequestedWidth
, NumberOfLines
, Marker
);
564 Process validate for one question.
566 @param Question The question need to be validate.
568 @retval EFI_SUCCESS Question Option process success.
569 @retval EFI_INVALID_PARAMETER Question Option process fail.
574 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
580 STATEMENT_ERROR_INFO RetInfo
;
583 if (Question
->ValidateQuestion
== NULL
) {
587 Status
= EFI_SUCCESS
;
588 RetVal
= Question
->ValidateQuestion(gFormData
, Question
, &gUserInput
->InputValue
, &RetInfo
);
591 case INCOSISTENT_IF_TRUE
:
593 // Condition meet, show up error message
595 ASSERT (RetInfo
.StringId
!= 0);
596 ErrorInfo
= GetToken (RetInfo
.StringId
, gFormData
->HiiHandle
);
598 CreateDialog (&Key
, gEmptyString
, ErrorInfo
, gPressEnter
, gEmptyString
, NULL
);
599 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
600 FreePool (ErrorInfo
);
602 Status
= EFI_INVALID_PARAMETER
;
613 Display error message for invalid password.
624 // Invalid password, prompt error message
627 CreateDialog (&Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
, NULL
);
628 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
632 Process password op code.
634 @param MenuOption The menu for current password op code.
636 @retval EFI_SUCCESS Question Option process success.
637 @retval Other Question Option process fail.
642 IN UI_MENU_OPTION
*MenuOption
649 EFI_IFR_PASSWORD
*PasswordInfo
;
650 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
653 Question
= MenuOption
->ThisTag
;
654 PasswordInfo
= (EFI_IFR_PASSWORD
*) Question
->OpCode
;
655 Maximum
= PasswordInfo
->MaxSize
;
656 Status
= EFI_SUCCESS
;
658 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
662 // Use a NULL password to test whether old password is required
665 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
666 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
668 // Password can't be set now.
670 FreePool (StringPtr
);
674 if (EFI_ERROR (Status
)) {
676 // Old password exist, ask user for the old password
678 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
679 if (EFI_ERROR (Status
)) {
680 FreePool (StringPtr
);
685 // Check user input old password
687 Status
= Question
->PasswordCheck (gFormData
, Question
, StringPtr
);
688 if (EFI_ERROR (Status
)) {
689 if (Status
== EFI_NOT_READY
) {
691 // Typed in old password incorrect
695 Status
= EFI_SUCCESS
;
698 FreePool (StringPtr
);
704 // Ask for new password
706 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
707 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
708 if (EFI_ERROR (Status
)) {
710 // Reset state machine for password
712 Question
->PasswordCheck (gFormData
, Question
, NULL
);
713 FreePool (StringPtr
);
718 // Confirm new password
720 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
722 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
723 if (EFI_ERROR (Status
)) {
725 // Reset state machine for password
727 Question
->PasswordCheck (gFormData
, Question
, NULL
);
728 FreePool (StringPtr
);
729 FreePool (TempString
);
734 // Compare two typed-in new passwords
736 if (StrCmp (StringPtr
, TempString
) == 0) {
737 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
738 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
739 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
740 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
741 FreePool (StringPtr
);
743 Status
= ValidateQuestion (Question
);
745 if (EFI_ERROR (Status
)) {
747 // Reset state machine for password
749 Question
->PasswordCheck (gFormData
, Question
, NULL
);
755 // Reset state machine for password
757 Question
->PasswordCheck (gFormData
, Question
, NULL
);
760 // Two password mismatch, prompt error message
763 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
764 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
766 Status
= EFI_INVALID_PARAMETER
;
769 FreePool (TempString
);
770 FreePool (StringPtr
);
776 Process a Question's Option (whether selected or un-selected).
778 @param MenuOption The MenuOption for this Question.
779 @param Selected TRUE: if Question is selected.
780 @param OptionString Pointer of the Option String to be displayed.
781 @param SkipErrorValue Whether need to return when value without option for it.
783 @retval EFI_SUCCESS Question Option process success.
784 @retval Other Question Option process fail.
789 IN UI_MENU_OPTION
*MenuOption
,
791 OUT CHAR16
**OptionString
,
792 IN BOOLEAN SkipErrorValue
798 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
799 CHAR16 FormattedNumber
[21];
804 DISPLAY_QUESTION_OPTION
*OneOfOption
;
806 EFI_HII_VALUE HiiValue
;
807 EFI_HII_VALUE
*QuestionValue
;
808 DISPLAY_QUESTION_OPTION
*Option
;
812 EFI_STRING_ID StringId
;
813 EFI_IFR_ORDERED_LIST
*OrderList
;
814 BOOLEAN ValueInvalid
;
816 Status
= EFI_SUCCESS
;
819 Character
[1] = L
'\0';
820 *OptionString
= NULL
;
822 ValueInvalid
= FALSE
;
824 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
825 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
827 Question
= MenuOption
->ThisTag
;
828 QuestionValue
= &Question
->CurrentValue
;
830 switch (Question
->OpCode
->OpCode
) {
831 case EFI_IFR_ORDERED_LIST_OP
:
834 // Check whether there are Options of this OrderedList
836 if (IsListEmpty (&Question
->OptionListHead
)) {
840 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
842 Link
= GetFirstNode (&Question
->OptionListHead
);
843 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
845 ValueType
= OneOfOption
->OptionOpCode
->Type
;
846 ValueArray
= Question
->CurrentValue
.Buffer
;
852 Status
= GetSelectionInputPopUp (MenuOption
);
855 // We now know how many strings we will have, so we can allocate the
856 // space required for the array or strings.
858 *OptionString
= AllocateZeroPool (OrderList
->MaxContainers
* BufferSize
);
859 ASSERT (*OptionString
);
861 HiiValue
.Type
= ValueType
;
862 HiiValue
.Value
.u64
= 0;
863 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
864 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
865 if (HiiValue
.Value
.u64
== 0) {
867 // Values for the options in ordered lists should never be a 0
872 OneOfOption
= ValueToOption (Question
, &HiiValue
);
873 if (OneOfOption
== NULL
) {
874 if (SkipErrorValue
) {
876 // Just try to get the option string, skip the value which not has option.
882 // Show error message
885 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
886 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
889 // The initial value of the orderedlist is invalid, force to be valid value
890 // Exit current DisplayForm with new value.
892 gUserInput
->SelectedStatement
= Question
;
894 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
895 ASSERT (ValueArray
!= NULL
);
896 gUserInput
->InputValue
.Buffer
= ValueArray
;
897 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
898 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
900 Link
= GetFirstNode (&Question
->OptionListHead
);
902 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
903 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
904 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
905 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
908 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
910 FreePool (*OptionString
);
911 *OptionString
= NULL
;
912 return EFI_NOT_FOUND
;
915 Character
[0] = LEFT_ONEOF_DELIMITER
;
916 NewStrCat (OptionString
[0], Character
);
917 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
918 ASSERT (StringPtr
!= NULL
);
919 NewStrCat (OptionString
[0], StringPtr
);
920 Character
[0] = RIGHT_ONEOF_DELIMITER
;
921 NewStrCat (OptionString
[0], Character
);
922 Character
[0] = CHAR_CARRIAGE_RETURN
;
923 NewStrCat (OptionString
[0], Character
);
924 FreePool (StringPtr
);
928 // If valid option more than the max container, skip these options.
930 if (Index
>= OrderList
->MaxContainers
) {
935 // Search the other options, try to find the one not in the container.
937 Link
= GetFirstNode (&Question
->OptionListHead
);
938 while (!IsNull (&Question
->OptionListHead
, Link
)) {
939 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
940 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
942 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
946 if (SkipErrorValue
) {
948 // Not report error, just get the correct option string info.
950 Character
[0] = LEFT_ONEOF_DELIMITER
;
951 NewStrCat (OptionString
[0], Character
);
952 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
953 ASSERT (StringPtr
!= NULL
);
954 NewStrCat (OptionString
[0], StringPtr
);
955 Character
[0] = RIGHT_ONEOF_DELIMITER
;
956 NewStrCat (OptionString
[0], Character
);
957 Character
[0] = CHAR_CARRIAGE_RETURN
;
958 NewStrCat (OptionString
[0], Character
);
959 FreePool (StringPtr
);
967 // Show error message
970 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
971 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
974 // The initial value of the orderedlist is invalid, force to be valid value
975 // Exit current DisplayForm with new value.
977 gUserInput
->SelectedStatement
= Question
;
979 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
980 ASSERT (ValueArray
!= NULL
);
981 gUserInput
->InputValue
.Buffer
= ValueArray
;
982 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
983 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
986 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
990 FreePool (*OptionString
);
991 *OptionString
= NULL
;
992 return EFI_NOT_FOUND
;
997 case EFI_IFR_ONE_OF_OP
:
999 // Check whether there are Options of this OneOf
1001 if (IsListEmpty (&Question
->OptionListHead
)) {
1008 Status
= GetSelectionInputPopUp (MenuOption
);
1010 *OptionString
= AllocateZeroPool (BufferSize
);
1011 ASSERT (*OptionString
);
1013 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1014 if (OneOfOption
== NULL
) {
1015 if (SkipErrorValue
) {
1017 // Not report error, just get the correct option string info.
1019 Link
= GetFirstNode (&Question
->OptionListHead
);
1020 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1023 // Show error message
1026 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1027 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1030 // Force the Question value to be valid
1031 // Exit current DisplayForm with new value.
1033 Link
= GetFirstNode (&Question
->OptionListHead
);
1034 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1036 CopyMem (&gUserInput
->InputValue
.Value
, &Option
->OptionOpCode
->Value
, sizeof (EFI_IFR_TYPE_VALUE
));
1037 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1038 gUserInput
->SelectedStatement
= Question
;
1040 FreePool (*OptionString
);
1041 *OptionString
= NULL
;
1042 return EFI_NOT_FOUND
;
1046 Character
[0] = LEFT_ONEOF_DELIMITER
;
1047 NewStrCat (OptionString
[0], Character
);
1048 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1049 ASSERT (StringPtr
!= NULL
);
1050 NewStrCat (OptionString
[0], StringPtr
);
1051 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1052 NewStrCat (OptionString
[0], Character
);
1054 FreePool (StringPtr
);
1058 case EFI_IFR_CHECKBOX_OP
:
1061 // Since this is a BOOLEAN operation, flip it upon selection
1063 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1064 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
1067 // Perform inconsistent check
1069 return ValidateQuestion (Question
);
1071 *OptionString
= AllocateZeroPool (BufferSize
);
1072 ASSERT (*OptionString
);
1074 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1076 if (QuestionValue
->Value
.b
) {
1077 *(OptionString
[0] + 1) = CHECK_ON
;
1079 *(OptionString
[0] + 1) = CHECK_OFF
;
1081 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1085 case EFI_IFR_NUMERIC_OP
:
1090 Status
= GetNumericInput (MenuOption
);
1092 *OptionString
= AllocateZeroPool (BufferSize
);
1093 ASSERT (*OptionString
);
1095 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1100 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1101 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
1102 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1104 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1108 case EFI_IFR_DATE_OP
:
1111 // This is similar to numerics
1113 Status
= GetNumericInput (MenuOption
);
1115 *OptionString
= AllocateZeroPool (BufferSize
);
1116 ASSERT (*OptionString
);
1118 switch (MenuOption
->Sequence
) {
1120 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1121 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1122 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1126 SetUnicodeMem (OptionString
[0], 4, L
' ');
1127 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1128 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1132 SetUnicodeMem (OptionString
[0], 7, L
' ');
1133 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1134 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1140 case EFI_IFR_TIME_OP
:
1143 // This is similar to numerics
1145 Status
= GetNumericInput (MenuOption
);
1147 *OptionString
= AllocateZeroPool (BufferSize
);
1148 ASSERT (*OptionString
);
1150 switch (MenuOption
->Sequence
) {
1152 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1153 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1154 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1158 SetUnicodeMem (OptionString
[0], 4, L
' ');
1159 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1160 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1164 SetUnicodeMem (OptionString
[0], 7, L
' ');
1165 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1166 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1172 case EFI_IFR_STRING_OP
:
1174 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1176 CopyMem(StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1178 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1179 if (EFI_ERROR (Status
)) {
1180 FreePool (StringPtr
);
1184 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1185 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1186 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1187 gUserInput
->InputValue
.Value
.string
= HiiSetString(gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1188 FreePool (StringPtr
);
1189 return ValidateQuestion (Question
);
1191 *OptionString
= AllocateZeroPool (BufferSize
);
1192 ASSERT (*OptionString
);
1194 if (((CHAR16
*) Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1195 *(OptionString
[0]) = '_';
1197 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1198 BufferSize
= Question
->CurrentValue
.BufferLen
;
1200 CopyMem (OptionString
[0], (CHAR16
*) Question
->CurrentValue
.Buffer
, BufferSize
);
1205 case EFI_IFR_PASSWORD_OP
:
1207 Status
= PasswordProcess (MenuOption
);
1220 Process the help string: Split StringPtr to several lines of strings stored in
1221 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1223 @param StringPtr The entire help string.
1224 @param FormattedString The oupput formatted string.
1225 @param EachLineWidth The max string length of each line in the formatted string.
1226 @param RowCount TRUE: if Question is selected.
1231 IN CHAR16
*StringPtr
,
1232 OUT CHAR16
**FormattedString
,
1233 OUT UINT16
*EachLineWidth
,
1238 CHAR16
*OutputString
;
1243 UINT16 MaxStringLen
;
1254 // Set default help string width.
1256 LineWidth
= (UINT16
) (gHelpBlockWidth
- 1);
1259 // Get row number of the String.
1261 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1262 if (StringLen
> MaxStringLen
) {
1263 MaxStringLen
= StringLen
;
1267 FreePool (OutputString
);
1269 *EachLineWidth
= MaxStringLen
;
1271 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1272 ASSERT (*FormattedString
!= NULL
);
1275 // Generate formatted help string array.
1279 while((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1280 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1282 FreePool (OutputString
);