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;
286 // Take remain types(integer, boolean, date/time) as integer
288 if (IsTypeInUINT64 (Value1
) && IsTypeInUINT64 (Value2
)) {
289 Temp64
= HiiValueToUINT64 (Value1
) - HiiValueToUINT64 (Value2
);
292 } else if (Temp64
< 0) {
301 return EFI_UNSUPPORTED
;
305 Search an Option of a Question by its value.
307 @param Question The Question
308 @param OptionValue Value for Option to be searched.
310 @retval Pointer Pointer to the found Option.
311 @retval NULL Option not found.
314 DISPLAY_QUESTION_OPTION
*
316 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
317 IN EFI_HII_VALUE
*OptionValue
321 DISPLAY_QUESTION_OPTION
*Option
;
325 Link
= GetFirstNode (&Question
->OptionListHead
);
326 while (!IsNull (&Question
->OptionListHead
, Link
)) {
327 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
329 ZeroMem (&Value
, sizeof (EFI_HII_VALUE
));
330 Value
.Type
= Option
->OptionOpCode
->Type
;
331 CopyMem (&Value
.Value
, &Option
->OptionOpCode
->Value
, Option
->OptionOpCode
->Header
.Length
- OFFSET_OF (EFI_IFR_ONE_OF_OPTION
, Value
));
333 if ((CompareHiiValue (&Value
, OptionValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
337 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
344 Return data element in an Array by its Index.
346 @param Array The data array.
347 @param Type Type of the data in this array.
348 @param Index Zero based index for data in this array.
350 @retval Value The data to be returned
362 ASSERT (Array
!= NULL
);
366 case EFI_IFR_TYPE_NUM_SIZE_8
:
367 Data
= (UINT64
)*(((UINT8
*)Array
) + Index
);
370 case EFI_IFR_TYPE_NUM_SIZE_16
:
371 Data
= (UINT64
)*(((UINT16
*)Array
) + Index
);
374 case EFI_IFR_TYPE_NUM_SIZE_32
:
375 Data
= (UINT64
)*(((UINT32
*)Array
) + Index
);
378 case EFI_IFR_TYPE_NUM_SIZE_64
:
379 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.
406 ASSERT (Array
!= NULL
);
409 case EFI_IFR_TYPE_NUM_SIZE_8
:
410 *(((UINT8
*)Array
) + Index
) = (UINT8
)Value
;
413 case EFI_IFR_TYPE_NUM_SIZE_16
:
414 *(((UINT16
*)Array
) + Index
) = (UINT16
)Value
;
417 case EFI_IFR_TYPE_NUM_SIZE_32
:
418 *(((UINT32
*)Array
) + Index
) = (UINT32
)Value
;
421 case EFI_IFR_TYPE_NUM_SIZE_64
:
422 *(((UINT64
*)Array
) + Index
) = (UINT64
)Value
;
431 Check whether this value already in the array, if yes, return the index.
433 @param Array The data array.
434 @param Type Type of the data in this array.
435 @param Value The value to be find.
436 @param Index The index in the array which has same value with Value.
438 @retval TRUE Found the value in the array.
439 @retval FALSE Not found the value.
447 OUT UINTN
*Index OPTIONAL
454 ASSERT (Array
!= NULL
);
460 case EFI_IFR_TYPE_NUM_SIZE_8
:
461 ValueComp
= (UINT8
)Value
;
464 case EFI_IFR_TYPE_NUM_SIZE_16
:
465 ValueComp
= (UINT16
)Value
;
468 case EFI_IFR_TYPE_NUM_SIZE_32
:
469 ValueComp
= (UINT32
)Value
;
472 case EFI_IFR_TYPE_NUM_SIZE_64
:
473 ValueComp
= (UINT64
)Value
;
481 while ((TmpValue
= GetArrayData (Array
, Type
, Count
)) != 0) {
482 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
:
556 case EFI_IFR_DISPLAY_UINT_DEC
:
560 case EFI_IFR_DISPLAY_UINT_HEX
:
565 return EFI_UNSUPPORTED
;
568 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
);
817 FreePool (StringPtr
);
821 if (EFI_ERROR (Status
)) {
823 // Old password exist, ask user for the old password
825 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
826 if (EFI_ERROR (Status
)) {
827 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
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 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
847 FreePool (StringPtr
);
853 // Ask for new password
855 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
856 Status
= ReadString (MenuOption
, gPromptForNewPassword
, StringPtr
);
857 if (EFI_ERROR (Status
)) {
859 // Reset state machine for password
861 Question
->PasswordCheck (gFormData
, Question
, NULL
);
862 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
863 FreePool (StringPtr
);
868 // Confirm new password
870 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
872 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
873 if (EFI_ERROR (Status
)) {
875 // Reset state machine for password
877 Question
->PasswordCheck (gFormData
, Question
, NULL
);
878 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
879 ZeroMem (TempString
, (Maximum
+ 1) * sizeof (CHAR16
));
880 FreePool (StringPtr
);
881 FreePool (TempString
);
886 // Compare two typed-in new passwords
888 if (StrCmp (StringPtr
, TempString
) == 0) {
889 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
890 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
891 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
892 gUserInput
->InputValue
.Value
.string
= HiiSetString (gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
894 Status
= EFI_SUCCESS
;
897 // Reset state machine for password
899 Question
->PasswordCheck (gFormData
, Question
, NULL
);
902 // Two password mismatch, prompt error message
905 CreateDialog (&Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
, NULL
);
906 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
908 Status
= EFI_INVALID_PARAMETER
;
911 ZeroMem (TempString
, (Maximum
+ 1) * sizeof (CHAR16
));
912 ZeroMem (StringPtr
, (Maximum
+ 1) * sizeof (CHAR16
));
913 FreePool (TempString
);
914 FreePool (StringPtr
);
920 Print some debug message about mismatched menu info.
922 @param MenuOption The MenuOption for this Question.
926 PrintMismatchMenuInfo (
927 IN UI_MENU_OPTION
*MenuOption
930 CHAR16
*FormTitleStr
;
931 CHAR16
*FormSetTitleStr
;
932 CHAR16
*OneOfOptionStr
;
933 CHAR16
*QuestionName
;
935 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
936 EFI_IFR_ORDERED_LIST
*OrderList
;
938 EFI_HII_VALUE HiiValue
;
939 EFI_HII_VALUE
*QuestionValue
;
940 DISPLAY_QUESTION_OPTION
*Option
;
943 EFI_IFR_FORM_SET
*FormsetBuffer
;
944 UINTN FormsetBufferSize
;
946 Question
= MenuOption
->ThisTag
;
947 HiiGetFormSetFromHiiHandle (gFormData
->HiiHandle
, &FormsetBuffer
, &FormsetBufferSize
);
949 FormSetTitleStr
= GetToken (FormsetBuffer
->FormSetTitle
, gFormData
->HiiHandle
);
950 FormTitleStr
= GetToken (gFormData
->FormTitle
, gFormData
->HiiHandle
);
952 DEBUG ((DEBUG_ERROR
, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName
, &gFormData
->FormSetGuid
, FormSetTitleStr
));
953 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName
, gFormData
->FormId
, FormTitleStr
));
955 if (Question
->OpCode
->OpCode
== EFI_IFR_ORDERED_LIST_OP
) {
956 QuestionName
= GetToken (((EFI_IFR_ORDERED_LIST
*)MenuOption
->ThisTag
->OpCode
)->Question
.Header
.Prompt
, gFormData
->HiiHandle
);
957 Link
= GetFirstNode (&Question
->OptionListHead
);
958 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
959 ValueType
= Option
->OptionOpCode
->Type
;
960 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName
));
961 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName
, QuestionName
));
962 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName
));
964 OrderList
= (EFI_IFR_ORDERED_LIST
*)Question
->OpCode
;
965 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
966 ValueArray
= Question
->CurrentValue
.Buffer
;
967 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
968 DEBUG ((DEBUG_ERROR
, " Value[%d] =%ld.\n", Index
, HiiValue
.Value
.u64
));
970 } else if (Question
->OpCode
->OpCode
== EFI_IFR_ONE_OF_OP
) {
971 QuestionName
= GetToken (((EFI_IFR_ONE_OF
*)MenuOption
->ThisTag
->OpCode
)->Question
.Header
.Prompt
, gFormData
->HiiHandle
);
972 QuestionValue
= &Question
->CurrentValue
;
973 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName
));
974 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName
, QuestionName
));
975 switch (QuestionValue
->Type
) {
976 case EFI_IFR_TYPE_NUM_SIZE_64
:
977 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OneOf : OneOf value = %ld.\n", gEfiCallerBaseName
, QuestionValue
->Value
.u64
));
980 case EFI_IFR_TYPE_NUM_SIZE_32
:
981 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName
, QuestionValue
->Value
.u32
));
984 case EFI_IFR_TYPE_NUM_SIZE_16
:
985 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName
, QuestionValue
->Value
.u16
));
988 case EFI_IFR_TYPE_NUM_SIZE_8
:
989 DEBUG ((DEBUG_ERROR
, "[%a]: Mismatch OneOf : OneOf value = %d.\n", gEfiCallerBaseName
, QuestionValue
->Value
.u8
));
999 Link
= GetFirstNode (&Question
->OptionListHead
);
1000 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1001 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1002 OneOfOptionStr
= GetToken (Option
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1003 switch (Option
->OptionOpCode
->Type
) {
1004 case EFI_IFR_TYPE_NUM_SIZE_64
:
1005 DEBUG ((DEBUG_ERROR
, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n", gEfiCallerBaseName
, Index
, Option
->OptionOpCode
->Value
.u64
, OneOfOptionStr
));
1008 case EFI_IFR_TYPE_NUM_SIZE_32
:
1009 DEBUG ((DEBUG_ERROR
, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName
, Index
, Option
->OptionOpCode
->Value
.u32
, OneOfOptionStr
));
1012 case EFI_IFR_TYPE_NUM_SIZE_16
:
1013 DEBUG ((DEBUG_ERROR
, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName
, Index
, Option
->OptionOpCode
->Value
.u16
, OneOfOptionStr
));
1016 case EFI_IFR_TYPE_NUM_SIZE_8
:
1017 DEBUG ((DEBUG_ERROR
, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n", gEfiCallerBaseName
, Index
, Option
->OptionOpCode
->Value
.u8
, OneOfOptionStr
));
1025 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1031 Process a Question's Option (whether selected or un-selected).
1033 @param MenuOption The MenuOption for this Question.
1034 @param Selected TRUE: if Question is selected.
1035 @param OptionString Pointer of the Option String to be displayed.
1036 @param SkipErrorValue Whether need to return when value without option for it.
1038 @retval EFI_SUCCESS Question Option process success.
1039 @retval Other Question Option process fail.
1044 IN UI_MENU_OPTION
*MenuOption
,
1045 IN BOOLEAN Selected
,
1046 OUT CHAR16
**OptionString
,
1047 IN BOOLEAN SkipErrorValue
1053 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
1054 CHAR16 FormattedNumber
[21];
1056 CHAR16 Character
[2];
1059 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1061 EFI_HII_VALUE HiiValue
;
1062 EFI_HII_VALUE
*QuestionValue
;
1063 DISPLAY_QUESTION_OPTION
*Option
;
1067 EFI_IFR_ORDERED_LIST
*OrderList
;
1068 BOOLEAN ValueInvalid
;
1071 Status
= EFI_SUCCESS
;
1074 Character
[1] = L
'\0';
1075 *OptionString
= NULL
;
1076 ValueInvalid
= FALSE
;
1078 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
1079 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gStatementDimensions
.BottomRow
;
1081 Question
= MenuOption
->ThisTag
;
1082 QuestionValue
= &Question
->CurrentValue
;
1084 switch (Question
->OpCode
->OpCode
) {
1085 case EFI_IFR_ORDERED_LIST_OP
:
1088 // Check whether there are Options of this OrderedList
1090 if (IsListEmpty (&Question
->OptionListHead
)) {
1094 OrderList
= (EFI_IFR_ORDERED_LIST
*)Question
->OpCode
;
1096 Link
= GetFirstNode (&Question
->OptionListHead
);
1097 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1099 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1100 ValueArray
= Question
->CurrentValue
.Buffer
;
1106 Status
= GetSelectionInputPopUp (MenuOption
);
1109 // We now know how many strings we will have, so we can allocate the
1110 // space required for the array or strings.
1112 MaxLen
= OrderList
->MaxContainers
* BufferSize
/ sizeof (CHAR16
);
1113 *OptionString
= AllocateZeroPool (MaxLen
* sizeof (CHAR16
));
1114 ASSERT (*OptionString
);
1116 HiiValue
.Type
= ValueType
;
1117 HiiValue
.Value
.u64
= 0;
1118 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1119 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1120 if (HiiValue
.Value
.u64
== 0) {
1122 // Values for the options in ordered lists should never be a 0
1127 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1128 if (OneOfOption
== NULL
) {
1130 // Print debug msg for the mistach menu.
1132 PrintMismatchMenuInfo (MenuOption
);
1134 if (SkipErrorValue
) {
1136 // Just try to get the option string, skip the value which not has option.
1142 // Show error message
1145 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1146 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1149 // The initial value of the orderedlist is invalid, force to be valid value
1150 // Exit current DisplayForm with new value.
1152 gUserInput
->SelectedStatement
= Question
;
1154 ValueArray
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1155 ASSERT (ValueArray
!= NULL
);
1156 gUserInput
->InputValue
.Buffer
= ValueArray
;
1157 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1158 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1160 Link
= GetFirstNode (&Question
->OptionListHead
);
1162 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< OrderList
->MaxContainers
) {
1163 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1164 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1165 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->OptionOpCode
->Value
.u64
);
1169 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
1171 FreePool (*OptionString
);
1172 *OptionString
= NULL
;
1173 return EFI_NOT_FOUND
;
1176 Character
[0] = LEFT_ONEOF_DELIMITER
;
1177 NewStrCat (OptionString
[0], MaxLen
, Character
);
1178 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1179 ASSERT (StringPtr
!= NULL
);
1180 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1181 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1182 NewStrCat (OptionString
[0], MaxLen
, Character
);
1183 Character
[0] = CHAR_CARRIAGE_RETURN
;
1184 NewStrCat (OptionString
[0], MaxLen
, Character
);
1185 FreePool (StringPtr
);
1189 // If valid option more than the max container, skip these options.
1191 if (Index
>= OrderList
->MaxContainers
) {
1196 // Search the other options, try to find the one not in the container.
1198 Link
= GetFirstNode (&Question
->OptionListHead
);
1199 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1200 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1201 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1203 if (FindArrayData (ValueArray
, ValueType
, OneOfOption
->OptionOpCode
->Value
.u64
, NULL
)) {
1208 // Print debug msg for the mistach menu.
1210 PrintMismatchMenuInfo (MenuOption
);
1212 if (SkipErrorValue
) {
1214 // Not report error, just get the correct option string info.
1216 Character
[0] = LEFT_ONEOF_DELIMITER
;
1217 NewStrCat (OptionString
[0], MaxLen
, Character
);
1218 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1219 ASSERT (StringPtr
!= NULL
);
1220 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1221 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1222 NewStrCat (OptionString
[0], MaxLen
, Character
);
1223 Character
[0] = CHAR_CARRIAGE_RETURN
;
1224 NewStrCat (OptionString
[0], MaxLen
, Character
);
1225 FreePool (StringPtr
);
1230 if (!ValueInvalid
) {
1231 ValueInvalid
= TRUE
;
1233 // Show error message
1236 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1237 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1240 // The initial value of the orderedlist is invalid, force to be valid value
1241 // Exit current DisplayForm with new value.
1243 gUserInput
->SelectedStatement
= Question
;
1245 ValueArray
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, Question
->CurrentValue
.Buffer
);
1246 ASSERT (ValueArray
!= NULL
);
1247 gUserInput
->InputValue
.Buffer
= ValueArray
;
1248 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1249 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1252 SetArrayData (ValueArray
, ValueType
, Index
++, OneOfOption
->OptionOpCode
->Value
.u64
);
1256 FreePool (*OptionString
);
1257 *OptionString
= NULL
;
1258 return EFI_NOT_FOUND
;
1264 case EFI_IFR_ONE_OF_OP
:
1266 // Check whether there are Options of this OneOf
1268 if (IsListEmpty (&Question
->OptionListHead
)) {
1276 Status
= GetSelectionInputPopUp (MenuOption
);
1278 MaxLen
= BufferSize
/ sizeof (CHAR16
);
1279 *OptionString
= AllocateZeroPool (BufferSize
);
1280 ASSERT (*OptionString
);
1282 OneOfOption
= ValueToOption (Question
, QuestionValue
);
1283 if (OneOfOption
== NULL
) {
1285 // Print debug msg for the mistach menu.
1287 PrintMismatchMenuInfo (MenuOption
);
1289 if (SkipErrorValue
) {
1291 // Not report error, just get the correct option string info.
1293 Link
= GetFirstNode (&Question
->OptionListHead
);
1294 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1297 // Show error message
1300 CreateDialog (&Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
, NULL
);
1301 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
1304 // Force the Question value to be valid
1305 // Exit current DisplayForm with new value.
1307 Link
= GetFirstNode (&Question
->OptionListHead
);
1308 Option
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1310 gUserInput
->InputValue
.Type
= Option
->OptionOpCode
->Type
;
1311 switch (gUserInput
->InputValue
.Type
) {
1312 case EFI_IFR_TYPE_NUM_SIZE_8
:
1313 gUserInput
->InputValue
.Value
.u8
= Option
->OptionOpCode
->Value
.u8
;
1315 case EFI_IFR_TYPE_NUM_SIZE_16
:
1316 CopyMem (&gUserInput
->InputValue
.Value
.u16
, &Option
->OptionOpCode
->Value
.u16
, sizeof (UINT16
));
1318 case EFI_IFR_TYPE_NUM_SIZE_32
:
1319 CopyMem (&gUserInput
->InputValue
.Value
.u32
, &Option
->OptionOpCode
->Value
.u32
, sizeof (UINT32
));
1321 case EFI_IFR_TYPE_NUM_SIZE_64
:
1322 CopyMem (&gUserInput
->InputValue
.Value
.u64
, &Option
->OptionOpCode
->Value
.u64
, sizeof (UINT64
));
1329 gUserInput
->SelectedStatement
= Question
;
1331 FreePool (*OptionString
);
1332 *OptionString
= NULL
;
1333 return EFI_NOT_FOUND
;
1337 Character
[0] = LEFT_ONEOF_DELIMITER
;
1338 NewStrCat (OptionString
[0], MaxLen
, Character
);
1339 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1340 ASSERT (StringPtr
!= NULL
);
1341 NewStrCat (OptionString
[0], MaxLen
, StringPtr
);
1342 Character
[0] = RIGHT_ONEOF_DELIMITER
;
1343 NewStrCat (OptionString
[0], MaxLen
, Character
);
1345 FreePool (StringPtr
);
1350 case EFI_IFR_CHECKBOX_OP
:
1353 // Since this is a BOOLEAN operation, flip it upon selection
1355 gUserInput
->InputValue
.Type
= QuestionValue
->Type
;
1356 gUserInput
->InputValue
.Value
.b
= (BOOLEAN
)(QuestionValue
->Value
.b
? FALSE
: TRUE
);
1359 // Perform inconsistent check
1363 *OptionString
= AllocateZeroPool (BufferSize
);
1364 ASSERT (*OptionString
);
1366 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
1368 if (QuestionValue
->Value
.b
) {
1369 *(OptionString
[0] + 1) = CHECK_ON
;
1371 *(OptionString
[0] + 1) = CHECK_OFF
;
1374 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
1379 case EFI_IFR_NUMERIC_OP
:
1384 Status
= GetNumericInput (MenuOption
);
1386 *OptionString
= AllocateZeroPool (BufferSize
);
1387 ASSERT (*OptionString
);
1389 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1394 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
1395 Number
= (UINT16
)GetStringWidth (FormattedNumber
);
1396 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
1398 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
1403 case EFI_IFR_DATE_OP
:
1406 // This is similar to numerics
1408 Status
= GetNumericInput (MenuOption
);
1410 *OptionString
= AllocateZeroPool (BufferSize
);
1411 ASSERT (*OptionString
);
1413 switch (MenuOption
->Sequence
) {
1415 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1416 if (QuestionValue
->Value
.date
.Month
== 0xff) {
1417 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1419 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
1422 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
1426 SetUnicodeMem (OptionString
[0], 4, L
' ');
1427 if (QuestionValue
->Value
.date
.Day
== 0xff) {
1428 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1430 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
1433 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
1437 SetUnicodeMem (OptionString
[0], 7, L
' ');
1438 if (QuestionValue
->Value
.date
.Year
== 0xff) {
1439 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"????");
1441 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%04d", QuestionValue
->Value
.date
.Year
);
1444 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
1451 case EFI_IFR_TIME_OP
:
1454 // This is similar to numerics
1456 Status
= GetNumericInput (MenuOption
);
1458 *OptionString
= AllocateZeroPool (BufferSize
);
1459 ASSERT (*OptionString
);
1461 switch (MenuOption
->Sequence
) {
1463 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
1464 if (QuestionValue
->Value
.time
.Hour
== 0xff) {
1465 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"??");
1467 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
1470 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
1474 SetUnicodeMem (OptionString
[0], 4, L
' ');
1475 if (QuestionValue
->Value
.time
.Minute
== 0xff) {
1476 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"??");
1478 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
1481 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
1485 SetUnicodeMem (OptionString
[0], 7, L
' ');
1486 if (QuestionValue
->Value
.time
.Second
== 0xff) {
1487 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"??");
1489 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
1492 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
1499 case EFI_IFR_STRING_OP
:
1501 StringPtr
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
+ sizeof (CHAR16
));
1503 CopyMem (StringPtr
, Question
->CurrentValue
.Buffer
, Question
->CurrentValue
.BufferLen
);
1505 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
1506 if (EFI_ERROR (Status
)) {
1507 FreePool (StringPtr
);
1511 gUserInput
->InputValue
.Buffer
= AllocateCopyPool (Question
->CurrentValue
.BufferLen
, StringPtr
);
1512 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1513 gUserInput
->InputValue
.Type
= Question
->CurrentValue
.Type
;
1514 gUserInput
->InputValue
.Value
.string
= HiiSetString (gFormData
->HiiHandle
, gUserInput
->InputValue
.Value
.string
, StringPtr
, NULL
);
1515 FreePool (StringPtr
);
1518 *OptionString
= AllocateZeroPool (BufferSize
);
1519 ASSERT (*OptionString
);
1521 if (((CHAR16
*)Question
->CurrentValue
.Buffer
)[0] == 0x0000) {
1522 *(OptionString
[0]) = '_';
1524 if (Question
->CurrentValue
.BufferLen
< BufferSize
) {
1525 BufferSize
= Question
->CurrentValue
.BufferLen
;
1528 CopyMem (OptionString
[0], (CHAR16
*)Question
->CurrentValue
.Buffer
, BufferSize
);
1534 case EFI_IFR_PASSWORD_OP
:
1536 Status
= PasswordProcess (MenuOption
);
1549 Process the help string: Split StringPtr to several lines of strings stored in
1550 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1552 @param StringPtr The entire help string.
1553 @param FormattedString The oupput formatted string.
1554 @param EachLineWidth The max string length of each line in the formatted string.
1555 @param RowCount TRUE: if Question is selected.
1560 IN CHAR16
*StringPtr
,
1561 OUT CHAR16
**FormattedString
,
1562 OUT UINT16
*EachLineWidth
,
1567 CHAR16
*OutputString
;
1572 UINT16 MaxStringLen
;
1583 // Set default help string width.
1585 LineWidth
= (UINT16
)(gHelpBlockWidth
- 1);
1588 // Get row number of the String.
1590 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1591 if (StringLen
> MaxStringLen
) {
1592 MaxStringLen
= StringLen
;
1596 FreePool (OutputString
);
1599 *EachLineWidth
= MaxStringLen
;
1601 *FormattedString
= AllocateZeroPool (TotalRowNum
* MaxStringLen
* sizeof (CHAR16
));
1602 ASSERT (*FormattedString
!= NULL
);
1605 // Generate formatted help string array.
1609 while ((StringLen
= GetLineByWidth (StringPtr
, LineWidth
, &GlyphWidth
, &Index
, &OutputString
)) != 0) {
1610 CopyMem (*FormattedString
+ CheckedNum
* MaxStringLen
, OutputString
, StringLen
* sizeof (CHAR16
));
1612 FreePool (OutputString
);