2 Implementation for handling the User Interface option processing.
5 Copyright (c) 2004 - 2010, 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.
20 Process Question Config.
22 @param Selection The UI menu selection.
23 @param Question The Question to be peocessed.
25 @retval EFI_SUCCESS Question Config process success.
26 @retval Other Question Config process fail.
30 ProcessQuestionConfig (
31 IN UI_MENU_SELECTION
*Selection
,
32 IN FORM_BROWSER_STATEMENT
*Question
38 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
40 if (Question
->QuestionConfig
== 0) {
47 ConfigResp
= GetToken (Question
->QuestionConfig
, Selection
->FormSet
->HiiHandle
);
48 if (ConfigResp
== NULL
) {
53 // Send config to Configuration Driver
55 ConfigAccess
= Selection
->FormSet
->ConfigAccess
;
56 if (ConfigAccess
== NULL
) {
57 return EFI_UNSUPPORTED
;
59 Status
= ConfigAccess
->RouteConfig (
70 Search an Option of a Question by its value.
72 @param Question The Question
73 @param OptionValue Value for Option to be searched.
75 @retval Pointer Pointer to the found Option.
76 @retval NULL Option not found.
81 IN FORM_BROWSER_STATEMENT
*Question
,
82 IN EFI_HII_VALUE
*OptionValue
86 QUESTION_OPTION
*Option
;
88 Link
= GetFirstNode (&Question
->OptionListHead
);
89 while (!IsNull (&Question
->OptionListHead
, Link
)) {
90 Option
= QUESTION_OPTION_FROM_LINK (Link
);
92 if (CompareHiiValue (&Option
->Value
, OptionValue
, NULL
) == 0) {
96 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
104 Return data element in an Array by its Index.
106 @param Array The data array.
107 @param Type Type of the data in this array.
108 @param Index Zero based index for data in this array.
110 @retval Value The data to be returned
122 ASSERT (Array
!= NULL
);
126 case EFI_IFR_TYPE_NUM_SIZE_8
:
127 Data
= (UINT64
) *(((UINT8
*) Array
) + Index
);
130 case EFI_IFR_TYPE_NUM_SIZE_16
:
131 Data
= (UINT64
) *(((UINT16
*) Array
) + Index
);
134 case EFI_IFR_TYPE_NUM_SIZE_32
:
135 Data
= (UINT64
) *(((UINT32
*) Array
) + Index
);
138 case EFI_IFR_TYPE_NUM_SIZE_64
:
139 Data
= (UINT64
) *(((UINT64
*) Array
) + Index
);
151 Set value of a data element in an Array by its Index.
153 @param Array The data array.
154 @param Type Type of the data in this array.
155 @param Index Zero based index for data in this array.
156 @param Value The value to be set.
168 ASSERT (Array
!= NULL
);
171 case EFI_IFR_TYPE_NUM_SIZE_8
:
172 *(((UINT8
*) Array
) + Index
) = (UINT8
) Value
;
175 case EFI_IFR_TYPE_NUM_SIZE_16
:
176 *(((UINT16
*) Array
) + Index
) = (UINT16
) Value
;
179 case EFI_IFR_TYPE_NUM_SIZE_32
:
180 *(((UINT32
*) Array
) + Index
) = (UINT32
) Value
;
183 case EFI_IFR_TYPE_NUM_SIZE_64
:
184 *(((UINT64
*) Array
) + Index
) = (UINT64
) Value
;
194 Print Question Value according to it's storage width and display attributes.
196 @param Question The Question to be printed.
197 @param FormattedNumber Buffer for output string.
198 @param BufferSize The FormattedNumber buffer size in bytes.
200 @retval EFI_SUCCESS Print success.
201 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
205 PrintFormattedNumber (
206 IN FORM_BROWSER_STATEMENT
*Question
,
207 IN OUT CHAR16
*FormattedNumber
,
213 EFI_HII_VALUE
*QuestionValue
;
215 if (BufferSize
< (21 * sizeof (CHAR16
))) {
216 return EFI_BUFFER_TOO_SMALL
;
219 QuestionValue
= &Question
->HiiValue
;
221 Value
= (INT64
) QuestionValue
->Value
.u64
;
222 switch (Question
->Flags
& EFI_IFR_DISPLAY
) {
223 case EFI_IFR_DISPLAY_INT_DEC
:
224 switch (QuestionValue
->Type
) {
225 case EFI_IFR_NUMERIC_SIZE_1
:
226 Value
= (INT64
) ((INT8
) QuestionValue
->Value
.u8
);
229 case EFI_IFR_NUMERIC_SIZE_2
:
230 Value
= (INT64
) ((INT16
) QuestionValue
->Value
.u16
);
233 case EFI_IFR_NUMERIC_SIZE_4
:
234 Value
= (INT64
) ((INT32
) QuestionValue
->Value
.u32
);
237 case EFI_IFR_NUMERIC_SIZE_8
:
250 case EFI_IFR_DISPLAY_UINT_DEC
:
254 case EFI_IFR_DISPLAY_UINT_HEX
:
259 return EFI_UNSUPPORTED
;
263 UnicodeSPrint (FormattedNumber
, BufferSize
, Format
, Value
);
270 Password may be stored as encrypted by Configuration Driver. When change a
271 password, user will be challenged with old password. To validate user input old
272 password, we will send the clear text to Configuration Driver via Callback().
273 Configuration driver is responsible to check the passed in password and return
274 the validation result. If validation pass, state machine in password Callback()
275 will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
276 After user type in new password twice, Callback() will be invoked to send the
277 new password to Configuration Driver.
279 @param Selection Pointer to UI_MENU_SELECTION.
280 @param MenuOption The MenuOption for this password Question.
281 @param String The clear text of password.
283 @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
284 @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
285 @retval EFI_SUCCESS Password correct, Browser will prompt for new
287 @retval EFI_NOT_READY Password incorrect, Browser will show error
289 @retval Other Browser will do nothing.
290 @return In state of BROWSER_STATE_SET_PASSWORD:
291 @retval EFI_SUCCESS Set password success.
292 @retval Other Set password failed.
297 IN UI_MENU_SELECTION
*Selection
,
298 IN UI_MENU_OPTION
*MenuOption
,
303 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
304 EFI_BROWSER_ACTION_REQUEST ActionRequest
;
305 EFI_HII_VALUE
*QuestionValue
;
307 QuestionValue
= &MenuOption
->ThisTag
->HiiValue
;
308 ConfigAccess
= Selection
->FormSet
->ConfigAccess
;
309 if (ConfigAccess
== NULL
) {
310 return EFI_UNSUPPORTED
;
314 // Prepare password string in HII database
316 if (String
!= NULL
) {
317 QuestionValue
->Value
.string
= NewString (String
, Selection
->FormSet
->HiiHandle
);
319 QuestionValue
->Value
.string
= 0;
323 // Send password to Configuration Driver for validation
325 Status
= ConfigAccess
->Callback (
327 EFI_BROWSER_ACTION_CHANGING
,
328 MenuOption
->ThisTag
->QuestionId
,
330 &QuestionValue
->Value
,
335 // Remove password string from HII database
337 if (String
!= NULL
) {
338 DeleteString (QuestionValue
->Value
.string
, Selection
->FormSet
->HiiHandle
);
346 Display error message for invalid password.
357 // Invalid password, prompt error message
360 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gPassowordInvalid
, gPressEnter
, gEmptyString
);
361 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
366 Process a Question's Option (whether selected or un-selected).
368 @param Selection Pointer to UI_MENU_SELECTION.
369 @param MenuOption The MenuOption for this Question.
370 @param Selected TRUE: if Question is selected.
371 @param OptionString Pointer of the Option String to be displayed.
373 @retval EFI_SUCCESS Question Option process success.
374 @retval Other Question Option process fail.
379 IN UI_MENU_SELECTION
*Selection
,
380 IN UI_MENU_OPTION
*MenuOption
,
382 OUT CHAR16
**OptionString
389 FORM_BROWSER_STATEMENT
*Question
;
390 CHAR16 FormattedNumber
[21];
395 QUESTION_OPTION
*OneOfOption
;
397 EFI_HII_VALUE HiiValue
;
398 EFI_HII_VALUE
*QuestionValue
;
401 QUESTION_OPTION
*Option
;
406 Status
= EFI_SUCCESS
;
409 Character
[1] = L
'\0';
410 *OptionString
= NULL
;
412 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
413 BufferSize
= (gOptionBlockWidth
+ 1) * 2 * gScreenDimensions
.BottomRow
;
415 Question
= MenuOption
->ThisTag
;
416 QuestionValue
= &Question
->HiiValue
;
417 Maximum
= (UINT16
) Question
->Maximum
;
419 ValueArray
= Question
->BufferValue
;
420 ValueType
= Question
->ValueType
;
422 switch (Question
->Operand
) {
423 case EFI_IFR_ORDERED_LIST_OP
:
425 // Check whether there are Options of this OrderedList
427 if (IsListEmpty (&Question
->OptionListHead
)) {
431 // Initialize Option value array
433 if (GetArrayData (ValueArray
, ValueType
, 0) == 0) {
434 GetQuestionDefault (Selection
->FormSet
, Selection
->Form
, Question
, 0);
441 Status
= GetSelectionInputPopUp (Selection
, MenuOption
);
444 // We now know how many strings we will have, so we can allocate the
445 // space required for the array or strings.
447 *OptionString
= AllocateZeroPool (Question
->MaxContainers
* BufferSize
);
448 ASSERT (*OptionString
);
450 HiiValue
.Type
= ValueType
;
451 HiiValue
.Value
.u64
= 0;
452 for (Index
= 0; Index
< Question
->MaxContainers
; Index
++) {
453 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
454 if (HiiValue
.Value
.u64
== 0) {
456 // Values for the options in ordered lists should never be a 0
461 OneOfOption
= ValueToOption (Question
, &HiiValue
);
462 if (OneOfOption
== NULL
) {
464 // Show error message
467 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
);
468 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
471 // The initial value of the orderedlist is invalid, force to be valid value
473 Link
= GetFirstNode (&Question
->OptionListHead
);
475 while (!IsNull (&Question
->OptionListHead
, Link
) && Index2
< Question
->MaxContainers
) {
476 Option
= QUESTION_OPTION_FROM_LINK (Link
);
477 SetArrayData (ValueArray
, ValueType
, Index2
, Option
->Value
.Value
.u64
);
479 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
481 SetArrayData (ValueArray
, ValueType
, Index2
, 0);
483 Status
= SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, TRUE
);
484 UpdateStatusBar (NV_UPDATE_REQUIRED
, Question
->QuestionFlags
, TRUE
);
486 FreePool (*OptionString
);
487 *OptionString
= NULL
;
488 return EFI_NOT_FOUND
;
492 if ((OneOfOption
->SuppressExpression
!= NULL
) &&
493 (OneOfOption
->SuppressExpression
->Result
.Value
.b
)) {
495 // This option is suppressed
501 Character
[0] = LEFT_ONEOF_DELIMITER
;
502 NewStrCat (OptionString
[0], Character
);
503 StringPtr
= GetToken (OneOfOption
->Text
, Selection
->Handle
);
504 NewStrCat (OptionString
[0], StringPtr
);
505 Character
[0] = RIGHT_ONEOF_DELIMITER
;
506 NewStrCat (OptionString
[0], Character
);
507 Character
[0] = CHAR_CARRIAGE_RETURN
;
508 NewStrCat (OptionString
[0], Character
);
510 FreePool (StringPtr
);
516 case EFI_IFR_ONE_OF_OP
:
518 // Check whether there are Options of this OneOf
520 if (IsListEmpty (&Question
->OptionListHead
)) {
527 Status
= GetSelectionInputPopUp (Selection
, MenuOption
);
529 *OptionString
= AllocateZeroPool (BufferSize
);
530 ASSERT (*OptionString
);
532 OneOfOption
= ValueToOption (Question
, QuestionValue
);
533 if (OneOfOption
== NULL
) {
535 // Show error message
538 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gOptionMismatch
, gPressEnter
, gEmptyString
);
539 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
542 // Force the Question value to be valid
544 Link
= GetFirstNode (&Question
->OptionListHead
);
545 while (!IsNull (&Question
->OptionListHead
, Link
)) {
546 Option
= QUESTION_OPTION_FROM_LINK (Link
);
548 if ((Option
->SuppressExpression
== NULL
) ||
549 !Option
->SuppressExpression
->Result
.Value
.b
) {
550 CopyMem (QuestionValue
, &Option
->Value
, sizeof (EFI_HII_VALUE
));
551 SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, TRUE
);
552 UpdateStatusBar (NV_UPDATE_REQUIRED
, Question
->QuestionFlags
, TRUE
);
556 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
559 FreePool (*OptionString
);
560 *OptionString
= NULL
;
561 return EFI_NOT_FOUND
;
564 if ((OneOfOption
->SuppressExpression
!= NULL
) &&
565 (OneOfOption
->SuppressExpression
->Result
.Value
.b
)) {
567 // This option is suppressed
576 // Current selected option happen to be suppressed,
577 // enforce to select on a non-suppressed option
579 Link
= GetFirstNode (&Question
->OptionListHead
);
580 while (!IsNull (&Question
->OptionListHead
, Link
)) {
581 OneOfOption
= QUESTION_OPTION_FROM_LINK (Link
);
583 if ((OneOfOption
->SuppressExpression
== NULL
) ||
584 !OneOfOption
->SuppressExpression
->Result
.Value
.b
) {
586 CopyMem (QuestionValue
, &OneOfOption
->Value
, sizeof (EFI_HII_VALUE
));
587 SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, TRUE
);
588 UpdateStatusBar (NV_UPDATE_REQUIRED
, Question
->QuestionFlags
, TRUE
);
589 gST
->ConOut
->SetAttribute (gST
->ConOut
, FIELD_TEXT
| FIELD_BACKGROUND
);
593 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
598 Character
[0] = LEFT_ONEOF_DELIMITER
;
599 NewStrCat (OptionString
[0], Character
);
600 StringPtr
= GetToken (OneOfOption
->Text
, Selection
->Handle
);
601 NewStrCat (OptionString
[0], StringPtr
);
602 Character
[0] = RIGHT_ONEOF_DELIMITER
;
603 NewStrCat (OptionString
[0], Character
);
605 FreePool (StringPtr
);
610 case EFI_IFR_CHECKBOX_OP
:
611 *OptionString
= AllocateZeroPool (BufferSize
);
612 ASSERT (*OptionString
);
614 *OptionString
[0] = LEFT_CHECKBOX_DELIMITER
;
618 // Since this is a BOOLEAN operation, flip it upon selection
620 QuestionValue
->Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
623 // Perform inconsistent check
625 Status
= ValidateQuestion (Selection
->FormSet
, Selection
->Form
, Question
, EFI_HII_EXPRESSION_INCONSISTENT_IF
);
626 if (EFI_ERROR (Status
)) {
628 // Inconsistent check fail, restore Question Value
630 QuestionValue
->Value
.b
= (BOOLEAN
) (QuestionValue
->Value
.b
? FALSE
: TRUE
);
631 FreePool (*OptionString
);
632 *OptionString
= NULL
;
637 // Save Question value
639 Status
= SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, TRUE
);
640 UpdateStatusBar (NV_UPDATE_REQUIRED
, Question
->QuestionFlags
, TRUE
);
643 if (QuestionValue
->Value
.b
) {
644 *(OptionString
[0] + 1) = CHECK_ON
;
646 *(OptionString
[0] + 1) = CHECK_OFF
;
648 *(OptionString
[0] + 2) = RIGHT_CHECKBOX_DELIMITER
;
651 case EFI_IFR_NUMERIC_OP
:
656 Status
= GetNumericInput (Selection
, MenuOption
);
658 *OptionString
= AllocateZeroPool (BufferSize
);
659 ASSERT (*OptionString
);
661 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
666 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
667 Number
= (UINT16
) GetStringWidth (FormattedNumber
);
668 CopyMem (OptionString
[0] + 1, FormattedNumber
, Number
);
670 *(OptionString
[0] + Number
/ 2) = RIGHT_NUMERIC_DELIMITER
;
674 case EFI_IFR_DATE_OP
:
677 // This is similar to numerics
679 Status
= GetNumericInput (Selection
, MenuOption
);
681 *OptionString
= AllocateZeroPool (BufferSize
);
682 ASSERT (*OptionString
);
684 switch (MenuOption
->Sequence
) {
686 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
687 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Month
);
688 *(OptionString
[0] + 3) = DATE_SEPARATOR
;
692 SetUnicodeMem (OptionString
[0], 4, L
' ');
693 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.date
.Day
);
694 *(OptionString
[0] + 6) = DATE_SEPARATOR
;
698 SetUnicodeMem (OptionString
[0], 7, L
' ');
699 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%4d", QuestionValue
->Value
.date
.Year
);
700 *(OptionString
[0] + 11) = RIGHT_NUMERIC_DELIMITER
;
706 case EFI_IFR_TIME_OP
:
709 // This is similar to numerics
711 Status
= GetNumericInput (Selection
, MenuOption
);
713 *OptionString
= AllocateZeroPool (BufferSize
);
714 ASSERT (*OptionString
);
716 switch (MenuOption
->Sequence
) {
718 *OptionString
[0] = LEFT_NUMERIC_DELIMITER
;
719 UnicodeSPrint (OptionString
[0] + 1, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Hour
);
720 *(OptionString
[0] + 3) = TIME_SEPARATOR
;
724 SetUnicodeMem (OptionString
[0], 4, L
' ');
725 UnicodeSPrint (OptionString
[0] + 4, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Minute
);
726 *(OptionString
[0] + 6) = TIME_SEPARATOR
;
730 SetUnicodeMem (OptionString
[0], 7, L
' ');
731 UnicodeSPrint (OptionString
[0] + 7, 21 * sizeof (CHAR16
), L
"%02d", QuestionValue
->Value
.time
.Second
);
732 *(OptionString
[0] + 9) = RIGHT_NUMERIC_DELIMITER
;
738 case EFI_IFR_STRING_OP
:
740 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
743 Status
= ReadString (MenuOption
, gPromptForData
, StringPtr
);
744 if (!EFI_ERROR (Status
)) {
745 CopyMem (Question
->BufferValue
, StringPtr
, Maximum
* sizeof (CHAR16
));
746 SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, TRUE
);
748 UpdateStatusBar (NV_UPDATE_REQUIRED
, Question
->QuestionFlags
, TRUE
);
751 FreePool (StringPtr
);
753 *OptionString
= AllocateZeroPool (BufferSize
);
754 ASSERT (*OptionString
);
756 if (((CHAR16
*) Question
->BufferValue
)[0] == 0x0000) {
757 *(OptionString
[0]) = '_';
759 if ((Maximum
* sizeof (CHAR16
)) < BufferSize
) {
760 BufferSize
= Maximum
* sizeof (CHAR16
);
762 CopyMem (OptionString
[0], (CHAR16
*) Question
->BufferValue
, BufferSize
);
767 case EFI_IFR_PASSWORD_OP
:
769 StringPtr
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
773 // For interactive passwords, old password is validated by callback
775 if ((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
777 // Use a NULL password to test whether old password is required
780 Status
= PasswordCallback (Selection
, MenuOption
, StringPtr
);
781 if (Status
== EFI_NOT_AVAILABLE_YET
|| Status
== EFI_UNSUPPORTED
) {
783 // Callback is not supported, or
784 // Callback request to terminate password input
786 FreePool (StringPtr
);
790 if (EFI_ERROR (Status
)) {
792 // Old password exist, ask user for the old password
794 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
795 if (EFI_ERROR (Status
)) {
796 FreePool (StringPtr
);
801 // Check user input old password
803 Status
= PasswordCallback (Selection
, MenuOption
, StringPtr
);
804 if (EFI_ERROR (Status
)) {
805 if (Status
== EFI_NOT_READY
) {
807 // Typed in old password incorrect
811 Status
= EFI_SUCCESS
;
814 FreePool (StringPtr
);
820 // For non-interactive password, validate old password in local
822 if (*((CHAR16
*) Question
->BufferValue
) != 0) {
824 // There is something there! Prompt for password
826 Status
= ReadString (MenuOption
, gPromptForPassword
, StringPtr
);
827 if (EFI_ERROR (Status
)) {
828 FreePool (StringPtr
);
832 TempString
= AllocateCopyPool ((Maximum
+ 1) * sizeof (CHAR16
), Question
->BufferValue
);
833 ASSERT (TempString
!= NULL
);
835 TempString
[Maximum
] = L
'\0';
837 if (StrCmp (StringPtr
, TempString
) != 0) {
839 // Typed in old password incorrect
843 FreePool (StringPtr
);
844 FreePool (TempString
);
848 FreePool (TempString
);
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 interactive password
861 if ((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
862 PasswordCallback (Selection
, MenuOption
, NULL
);
865 FreePool (StringPtr
);
870 // Confirm new password
872 TempString
= AllocateZeroPool ((Maximum
+ 1) * sizeof (CHAR16
));
874 Status
= ReadString (MenuOption
, gConfirmPassword
, TempString
);
875 if (EFI_ERROR (Status
)) {
877 // Reset state machine for interactive password
879 if ((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
880 PasswordCallback (Selection
, MenuOption
, NULL
);
883 FreePool (StringPtr
);
884 FreePool (TempString
);
889 // Compare two typed-in new passwords
891 if (StrCmp (StringPtr
, TempString
) == 0) {
893 // Two password match, send it to Configuration Driver
895 if ((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
896 PasswordCallback (Selection
, MenuOption
, StringPtr
);
898 CopyMem (Question
->BufferValue
, StringPtr
, Maximum
* sizeof (CHAR16
));
899 SetQuestionValue (Selection
->FormSet
, Selection
->Form
, Question
, FALSE
);
903 // Reset state machine for interactive password
905 if ((Question
->QuestionFlags
& EFI_IFR_FLAG_CALLBACK
) != 0) {
906 PasswordCallback (Selection
, MenuOption
, NULL
);
910 // Two password mismatch, prompt error message
913 CreateDialog (4, TRUE
, 0, NULL
, &Key
, gEmptyString
, gConfirmError
, gPressEnter
, gEmptyString
);
914 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
917 FreePool (TempString
);
918 FreePool (StringPtr
);
931 Process the help string: Split StringPtr to several lines of strings stored in
932 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
934 @param StringPtr The entire help string.
935 @param FormattedString The oupput formatted string.
936 @param RowCount TRUE: if Question is selected.
941 IN CHAR16
*StringPtr
,
942 OUT CHAR16
**FormattedString
,
949 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
954 UINTN VirtualLineCount
;
956 // GlyphOffset stores glyph width of current screen-line
960 // GlyphWidth equals to 2 if we meet width directive
964 // during scanning, we remember the position of last space character
965 // in case that if next word cannot put in current line, we could restore back to the position
966 // of last space character
967 // while we should also remmeber the glyph width of the last space character for restoring
969 UINTN LastSpaceIndex
;
970 UINTN LastSpaceGlyphWidth
;
972 // every time we begin to form a new screen-line, we should remember glyph width of single character
975 UINTN LineStartGlyphWidth
;
977 UINTN
*OldIndexArray
;
979 BlockWidth
= (UINTN
) gHelpBlockWidth
- 1;
982 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
983 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
984 // to bring the width directive of the last line to current screen-line.
985 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
986 // different from that of "\wideabcde", we should remember the width directive.
989 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
990 ASSERT (IndexArray
!= NULL
);
992 if (*FormattedString
!= NULL
) {
993 FreePool (*FormattedString
);
994 *FormattedString
= NULL
;
997 for (PrevCurrIndex
= 0, CurrIndex
= 0, LineCount
= 0, LastSpaceIndex
= 0,
998 IndexArray
[0] = 0, GlyphWidth
= 1, GlyphOffset
= 0, LastSpaceGlyphWidth
= 1, LineStartGlyphWidth
= 1;
999 (StringPtr
[CurrIndex
] != CHAR_NULL
);
1002 if (LineCount
== AllocateSize
) {
1003 AllocateSize
+= 0x10;
1004 OldIndexArray
= IndexArray
;
1005 IndexArray
= AllocatePool (AllocateSize
* sizeof (UINTN
) * 3);
1006 ASSERT (IndexArray
!= NULL
);
1008 CopyMem (IndexArray
, OldIndexArray
, LineCount
* sizeof (UINTN
) * 3);
1009 FreePool (OldIndexArray
);
1011 switch (StringPtr
[CurrIndex
]) {
1015 GlyphWidth
= ((StringPtr
[CurrIndex
] == WIDE_CHAR
) ? 2 : 1);
1016 if (CurrIndex
== 0) {
1017 LineStartGlyphWidth
= GlyphWidth
;
1023 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
1027 // Store a range of string as a line
1029 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1030 IndexArray
[LineCount
*3+1] = CurrIndex
;
1031 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1034 // Reset offset and save begin position of line
1037 LineStartGlyphWidth
= GlyphWidth
;
1038 PrevCurrIndex
= CurrIndex
+ 1;
1043 // "\r\n" and "\r" both are handled here
1045 case CHAR_CARRIAGE_RETURN
:
1046 if (StringPtr
[CurrIndex
+ 1] == CHAR_LINEFEED
) {
1048 // next char is '\n'
1050 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1051 IndexArray
[LineCount
*3+1] = CurrIndex
;
1052 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1057 LineStartGlyphWidth
= GlyphWidth
;
1058 PrevCurrIndex
= CurrIndex
+ 1;
1062 // char is space or other char
1065 GlyphOffset
+= GlyphWidth
;
1066 if (GlyphOffset
>= BlockWidth
) {
1067 if (LastSpaceIndex
> PrevCurrIndex
) {
1069 // LastSpaceIndex points to space inside current screen-line,
1070 // restore to LastSpaceIndex
1071 // (Otherwise the word is too long to fit one screen-line, just cut it)
1073 CurrIndex
= LastSpaceIndex
;
1074 GlyphWidth
= LastSpaceGlyphWidth
;
1075 } else if (GlyphOffset
> BlockWidth
) {
1077 // the word is too long to fit one screen-line and we don't get the chance
1078 // of GlyphOffset == BlockWidth because GlyphWidth = 2
1083 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1084 IndexArray
[LineCount
*3+1] = CurrIndex
+ 1;
1085 IndexArray
[LineCount
*3+2] = LineStartGlyphWidth
;
1086 LineStartGlyphWidth
= GlyphWidth
;
1089 // Reset offset and save begin position of line
1092 PrevCurrIndex
= CurrIndex
+ 1;
1096 // LastSpaceIndex: remember position of last space
1098 if (StringPtr
[CurrIndex
] == CHAR_SPACE
) {
1099 LastSpaceIndex
= CurrIndex
;
1100 LastSpaceGlyphWidth
= GlyphWidth
;
1106 if (GlyphOffset
> 0) {
1107 IndexArray
[LineCount
*3] = PrevCurrIndex
;
1108 IndexArray
[LineCount
*3+1] = CurrIndex
;
1109 IndexArray
[LineCount
*3+2] = GlyphWidth
;
1113 if (LineCount
== 0) {
1115 // in case we meet null string
1120 // we assume null string's glyph width is 1
1126 VirtualLineCount
= RowCount
* (LineCount
/ RowCount
+ (LineCount
% RowCount
> 0));
1127 *FormattedString
= AllocateZeroPool (VirtualLineCount
* (BlockWidth
+ 1) * sizeof (CHAR16
) * 2);
1128 ASSERT (*FormattedString
!= NULL
);
1130 for (CurrIndex
= 0; CurrIndex
< LineCount
; CurrIndex
++) {
1131 *(*FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1)) = (CHAR16
) ((IndexArray
[CurrIndex
*3+2] == 2) ? WIDE_CHAR
: NARROW_CHAR
);
1133 *FormattedString
+ CurrIndex
* 2 * (BlockWidth
+ 1) + 1,
1134 StringPtr
+ IndexArray
[CurrIndex
*3],
1135 IndexArray
[CurrIndex
*3+1]-IndexArray
[CurrIndex
*3]
1139 FreePool (IndexArray
);