]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
Update to use DOS format
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / ProcessOptions.c
CommitLineData
93e3992d 1/** @file
7936fb6a 2Implementation for handling the User Interface option processing.
3
93e3992d 4
5Copyright (c) 2004 - 2007, Intel Corporation
6All rights reserved. This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution. The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
93e3992d 14**/
15
16#include "Ui.h"
17#include "Setup.h"
18
19
20/**
21 Process Question Config.
22
23 @param Selection The UI menu selection.
24 @param Question The Question to be peocessed.
25
26 @retval EFI_SUCCESS Question Config process success.
27 @retval Other Question Config process fail.
28
29**/
30EFI_STATUS
31ProcessQuestionConfig (
32 IN UI_MENU_SELECTION *Selection,
33 IN FORM_BROWSER_STATEMENT *Question
34 )
35{
36 EFI_STATUS Status;
37 CHAR16 *ConfigResp;
38 CHAR16 *Progress;
39 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
40
41 if (Question->QuestionConfig == 0) {
42 return EFI_SUCCESS;
43 }
44
45 //
46 // Get <ConfigResp>
47 //
48 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);
49 if (ConfigResp == NULL) {
50 return EFI_NOT_FOUND;
51 }
52
53 //
54 // Send config to Configuration Driver
55 //
56 ConfigAccess = Selection->FormSet->ConfigAccess;
57 if (ConfigAccess == NULL) {
58 return EFI_UNSUPPORTED;
59 }
60 Status = ConfigAccess->RouteConfig (
61 ConfigAccess,
62 ConfigResp,
63 &Progress
64 );
65
66 return Status;
67}
68
69
70/**
71 Search an Option of a Question by its value.
72
73 @param Question The Question
74 @param OptionValue Value for Option to be searched.
75
76 @retval Pointer Pointer to the found Option.
77 @retval NULL Option not found.
78
79**/
80QUESTION_OPTION *
81ValueToOption (
82 IN FORM_BROWSER_STATEMENT *Question,
83 IN EFI_HII_VALUE *OptionValue
84 )
85{
86 LIST_ENTRY *Link;
87 QUESTION_OPTION *Option;
88
89 Link = GetFirstNode (&Question->OptionListHead);
90 while (!IsNull (&Question->OptionListHead, Link)) {
91 Option = QUESTION_OPTION_FROM_LINK (Link);
92
93 if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) {
94 return Option;
95 }
96
97 Link = GetNextNode (&Question->OptionListHead, Link);
98 }
99
100 return NULL;
101}
102
103
104/**
105 Print Question Value according to it's storage width and display attributes.
106
7936fb6a 107 @param Question The Question to be printed.
93e3992d 108 @param FormattedNumber Buffer for output string.
109 @param BufferSize The FormattedNumber buffer size in bytes.
110
111 @retval EFI_SUCCESS Print success.
112 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
113
114**/
115EFI_STATUS
116PrintFormattedNumber (
117 IN FORM_BROWSER_STATEMENT *Question,
118 IN OUT CHAR16 *FormattedNumber,
119 IN UINTN BufferSize
120 )
121{
122 INT64 Value;
123 CHAR16 *Format;
124 EFI_HII_VALUE *QuestionValue;
125
126 if (BufferSize < (21 * sizeof (CHAR16))) {
127 return EFI_BUFFER_TOO_SMALL;
128 }
129
130 QuestionValue = &Question->HiiValue;
131
132 Value = (INT64) QuestionValue->Value.u64;
133 switch (Question->Flags & EFI_IFR_DISPLAY) {
134 case EFI_IFR_DISPLAY_INT_DEC:
135 switch (QuestionValue->Type) {
136 case EFI_IFR_NUMERIC_SIZE_1:
137 Value = (INT64) ((INT8) QuestionValue->Value.u8);
138 break;
139
140 case EFI_IFR_NUMERIC_SIZE_2:
141 Value = (INT64) ((INT16) QuestionValue->Value.u16);
142 break;
143
144 case EFI_IFR_NUMERIC_SIZE_4:
145 Value = (INT64) ((INT32) QuestionValue->Value.u32);
146 break;
147
148 case EFI_IFR_NUMERIC_SIZE_8:
149 default:
150 break;
151 }
152
153 if (Value < 0) {
154 Value = -Value;
155 Format = L"-%ld";
156 } else {
157 Format = L"%ld";
158 }
159 break;
160
161 case EFI_IFR_DISPLAY_UINT_DEC:
162 Format = L"%ld";
163 break;
164
165 case EFI_IFR_DISPLAY_UINT_HEX:
166 Format = L"%lx";
167 break;
168
169 default:
170 return EFI_UNSUPPORTED;
171 break;
172 }
173
174 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
175
176 return EFI_SUCCESS;
177}
178
179
180/**
181 Password may be stored as encrypted by Configuration Driver. When change a
182 password, user will be challenged with old password. To validate user input old
183 password, we will send the clear text to Configuration Driver via Callback().
184 Configuration driver is responsible to check the passed in password and return
185 the validation result. If validation pass, state machine in password Callback()
186 will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.
187 After user type in new password twice, Callback() will be invoked to send the
188 new password to Configuration Driver.
189
190 @param Selection Pointer to UI_MENU_SELECTION.
191 @param MenuOption The MenuOption for this password Question.
192 @param String The clear text of password.
193
194 @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.
195 @return In state of BROWSER_STATE_VALIDATE_PASSWORD:
196 @retval EFI_SUCCESS Password correct, Browser will prompt for new
197 password.
198 @retval EFI_NOT_READY Password incorrect, Browser will show error
199 message.
200 @retval Other Browser will do nothing.
201 @return In state of BROWSER_STATE_SET_PASSWORD:
202 @retval EFI_SUCCESS Set password success.
203 @retval Other Set password failed.
204
205**/
206EFI_STATUS
207PasswordCallback (
208 IN UI_MENU_SELECTION *Selection,
209 IN UI_MENU_OPTION *MenuOption,
210 IN CHAR16 *String
211 )
212{
213 EFI_STATUS Status;
214 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
215 EFI_BROWSER_ACTION_REQUEST ActionRequest;
216 EFI_HII_VALUE *QuestionValue;
217
218 QuestionValue = &MenuOption->ThisTag->HiiValue;
219 ConfigAccess = Selection->FormSet->ConfigAccess;
220 if (ConfigAccess == NULL) {
221 return EFI_UNSUPPORTED;
222 }
223
224 //
225 // Prepare password string in HII database
226 //
227 if (String != NULL) {
228 QuestionValue->Value.string = NewString (String, Selection->FormSet->HiiHandle);
229 } else {
230 QuestionValue->Value.string = 0;
231 }
232
233 //
234 // Send password to Configuration Driver for validation
235 //
236 Status = ConfigAccess->Callback (
237 ConfigAccess,
238 EFI_BROWSER_ACTION_CHANGING,
239 MenuOption->ThisTag->QuestionId,
240 QuestionValue->Type,
241 &QuestionValue->Value,
242 &ActionRequest
243 );
244
245 //
246 // Remove password string from HII database
247 //
248 if (String != NULL) {
249 DeleteString (QuestionValue->Value.string, Selection->FormSet->HiiHandle);
250 }
251
252 return Status;
253}
254
255
256/**
257 Display error message for invalid password.
258
93e3992d 259**/
260VOID
261PasswordInvalid (
262 VOID
263 )
264{
265 EFI_INPUT_KEY Key;
266
267 //
268 // Invalid password, prompt error message
269 //
270 do {
271 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);
272 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
273}
274
275
276/**
277 Process a Question's Option (whether selected or un-selected).
278
279 @param Selection Pointer to UI_MENU_SELECTION.
280 @param MenuOption The MenuOption for this Question.
281 @param Selected TRUE: if Question is selected.
282 @param OptionString Pointer of the Option String to be displayed.
283
284 @retval EFI_SUCCESS Question Option process success.
285 @retval Other Question Option process fail.
286
287**/
288EFI_STATUS
289ProcessOptions (
290 IN UI_MENU_SELECTION *Selection,
291 IN UI_MENU_OPTION *MenuOption,
292 IN BOOLEAN Selected,
293 OUT CHAR16 **OptionString
294 )
295{
296 EFI_STATUS Status;
297 CHAR16 *StringPtr;
298 CHAR16 *TempString;
299 UINTN Index;
300 FORM_BROWSER_STATEMENT *Question;
301 CHAR16 FormattedNumber[21];
302 UINT16 Number;
303 CHAR16 Character[2];
304 EFI_INPUT_KEY Key;
305 UINTN BufferSize;
306 QUESTION_OPTION *OneOfOption;
307 LIST_ENTRY *Link;
308 EFI_HII_VALUE HiiValue;
309 EFI_HII_VALUE *QuestionValue;
310 BOOLEAN Suppress;
311 UINT16 Maximum;
312
313 Status = EFI_SUCCESS;
314
315 StringPtr = NULL;
316 Character[1] = L'\0';
317 *OptionString = NULL;
318
319 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
320 BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;
321
322 Question = MenuOption->ThisTag;
323 QuestionValue = &Question->HiiValue;
324 Maximum = (UINT16) Question->Maximum;
325
326 switch (Question->Operand) {
327 case EFI_IFR_ORDERED_LIST_OP:
328 //
329 // Initialize Option value array
330 //
ebe43565 331
93e3992d 332 if (Question->BufferValue[0] == 0) {
333 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);
334 }
335
336 if (Selected) {
337 //
338 // Go ask for input
339 //
340 Status = GetSelectionInputPopUp (Selection, MenuOption);
341 } else {
342 //
343 // We now know how many strings we will have, so we can allocate the
344 // space required for the array or strings.
345 //
346 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);
347 ASSERT (*OptionString);
348
349 HiiValue.Type = EFI_IFR_TYPE_NUM_SIZE_8;
350 HiiValue.Value.u64 = 0;
351 for (Index = 0; Index < Question->MaxContainers; Index++) {
352 HiiValue.Value.u8 = Question->BufferValue[Index];
353 if (HiiValue.Value.u8 == 0) {
354 //
355 // Values for the options in ordered lists should never be a 0
356 //
357 break;
358 }
359
360 OneOfOption = ValueToOption (Question, &HiiValue);
361 if (OneOfOption == NULL) {
362 gBS->FreePool (*OptionString);
363 return EFI_NOT_FOUND;
364 }
365
366 Suppress = FALSE;
367 if ((OneOfOption->SuppressExpression != NULL) &&
368 (OneOfOption->SuppressExpression->Result.Value.b)) {
369 //
370 // This option is suppressed
371 //
372 Suppress = TRUE;
373 }
374
375 if (!Suppress) {
376 Character[0] = LEFT_ONEOF_DELIMITER;
377 NewStrCat (OptionString[0], Character);
378 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
379 NewStrCat (OptionString[0], StringPtr);
380 Character[0] = RIGHT_ONEOF_DELIMITER;
381 NewStrCat (OptionString[0], Character);
382 Character[0] = CHAR_CARRIAGE_RETURN;
383 NewStrCat (OptionString[0], Character);
384
385 gBS->FreePool (StringPtr);
386 }
387 }
388 }
389 break;
390
391 case EFI_IFR_ONE_OF_OP:
392 if (Selected) {
393 //
394 // Go ask for input
395 //
396 Status = GetSelectionInputPopUp (Selection, MenuOption);
397 } else {
398 *OptionString = AllocateZeroPool (BufferSize);
399 ASSERT (*OptionString);
400
401 OneOfOption = ValueToOption (Question, QuestionValue);
402 if (OneOfOption == NULL) {
403 gBS->FreePool (*OptionString);
404 return EFI_NOT_FOUND;
405 }
406
407 if ((OneOfOption->SuppressExpression != NULL) &&
408 (OneOfOption->SuppressExpression->Result.Value.b)) {
409 //
410 // This option is suppressed
411 //
412 Suppress = TRUE;
413 } else {
414 Suppress = FALSE;
415 }
416
417 if (Suppress) {
418 //
419 // Current selected option happen to be suppressed,
420 // enforce to select on a non-suppressed option
421 //
422 Link = GetFirstNode (&Question->OptionListHead);
423 while (!IsNull (&Question->OptionListHead, Link)) {
424 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
425
426 if ((OneOfOption->SuppressExpression == NULL) ||
427 !OneOfOption->SuppressExpression->Result.Value.b) {
428 Suppress = FALSE;
429 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));
430 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
431 break;
432 }
433
434 Link = GetNextNode (&Question->OptionListHead, Link);
435 }
436 }
437
438 if (!Suppress) {
439 Character[0] = LEFT_ONEOF_DELIMITER;
440 NewStrCat (OptionString[0], Character);
441 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);
442 NewStrCat (OptionString[0], StringPtr);
443 Character[0] = RIGHT_ONEOF_DELIMITER;
444 NewStrCat (OptionString[0], Character);
445
446 gBS->FreePool (StringPtr);
447 }
448 }
449 break;
450
451 case EFI_IFR_CHECKBOX_OP:
452 *OptionString = AllocateZeroPool (BufferSize);
453 ASSERT (*OptionString);
454
455 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
456
457 if (Selected) {
458 //
459 // Since this is a BOOLEAN operation, flip it upon selection
460 //
461 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
462
463 //
464 // Perform inconsistent check
465 //
466 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
467 if (EFI_ERROR (Status)) {
468 //
469 // Inconsistent check fail, restore Question Value
470 //
471 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
472 gBS->FreePool (*OptionString);
473 return Status;
474 }
475
476 //
477 // Save Question value
478 //
479 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
480 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
481 }
482
483 if (QuestionValue->Value.b) {
484 *(OptionString[0] + 1) = CHECK_ON;
485 } else {
486 *(OptionString[0] + 1) = CHECK_OFF;
487 }
488 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
489 break;
490
491 case EFI_IFR_NUMERIC_OP:
492 if (Selected) {
493 //
494 // Go ask for input
495 //
496 Status = GetNumericInput (Selection, MenuOption);
497 } else {
498 *OptionString = AllocateZeroPool (BufferSize);
499 ASSERT (*OptionString);
500
501 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
502
503 //
504 // Formatted print
505 //
506 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
507 Number = (UINT16) GetStringWidth (FormattedNumber);
508 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
509
510 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
511 }
512 break;
513
514 case EFI_IFR_DATE_OP:
515 if (Selected) {
516 //
517 // This is similar to numerics
518 //
519 Status = GetNumericInput (Selection, MenuOption);
520 } else {
521 *OptionString = AllocateZeroPool (BufferSize);
522 ASSERT (*OptionString);
523
524 switch (MenuOption->Sequence) {
525 case 0:
526 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
527 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
528 *(OptionString[0] + 3) = DATE_SEPARATOR;
529 break;
530
531 case 1:
532 SetUnicodeMem (OptionString[0], 4, L' ');
533 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
534 *(OptionString[0] + 6) = DATE_SEPARATOR;
535 break;
536
537 case 2:
538 SetUnicodeMem (OptionString[0], 7, L' ');
539 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);
540 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
541 break;
542 }
543 }
544 break;
545
546 case EFI_IFR_TIME_OP:
547 if (Selected) {
548 //
549 // This is similar to numerics
550 //
551 Status = GetNumericInput (Selection, MenuOption);
552 } else {
553 *OptionString = AllocateZeroPool (BufferSize);
554 ASSERT (*OptionString);
555
556 switch (MenuOption->Sequence) {
557 case 0:
558 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
559 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
560 *(OptionString[0] + 3) = TIME_SEPARATOR;
561 break;
562
563 case 1:
564 SetUnicodeMem (OptionString[0], 4, L' ');
565 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
566 *(OptionString[0] + 6) = TIME_SEPARATOR;
567 break;
568
569 case 2:
570 SetUnicodeMem (OptionString[0], 7, L' ');
571 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
572 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
573 break;
574 }
575 }
576 break;
577
578 case EFI_IFR_STRING_OP:
579 if (Selected) {
580 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
581 ASSERT (StringPtr);
582
583 Status = ReadString (MenuOption, gPromptForData, StringPtr);
584 if (!EFI_ERROR (Status)) {
585 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
586 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
587
588 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
589 }
590
591 gBS->FreePool (StringPtr);
592 } else {
593 *OptionString = AllocateZeroPool (BufferSize);
594 ASSERT (*OptionString);
595
596 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {
597 *(OptionString[0]) = '_';
598 } else {
599 if ((Maximum * sizeof (CHAR16)) < BufferSize) {
600 BufferSize = Maximum * sizeof (CHAR16);
601 }
602 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);
603 }
604 }
605 break;
606
607 case EFI_IFR_PASSWORD_OP:
608 if (Selected) {
609 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
610 ASSERT (StringPtr);
611
612 //
613 // For interactive passwords, old password is validated by callback
614 //
7936fb6a 615 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
93e3992d 616 //
617 // Use a NULL password to test whether old password is required
618 //
619 *StringPtr = 0;
620 Status = PasswordCallback (Selection, MenuOption, StringPtr);
621 if (Status == EFI_NOT_AVAILABLE_YET) {
622 //
623 // Callback request to terminate password input
624 //
625 gBS->FreePool (StringPtr);
626 return EFI_SUCCESS;
627 }
628
629 if (EFI_ERROR (Status)) {
630 //
631 // Old password exist, ask user for the old password
632 //
633 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
634 if (EFI_ERROR (Status)) {
635 gBS->FreePool (StringPtr);
636 return Status;
637 }
638
639 //
640 // Check user input old password
641 //
642 Status = PasswordCallback (Selection, MenuOption, StringPtr);
643 if (EFI_ERROR (Status)) {
644 if (Status == EFI_NOT_READY) {
645 //
646 // Typed in old password incorrect
647 //
648 PasswordInvalid ();
649 } else {
650 Status = EFI_SUCCESS;
651 }
652
653 gBS->FreePool (StringPtr);
654 return Status;
655 }
656 }
657 } else {
658 //
659 // For non-interactive password, validate old password in local
660 //
661 if (*((CHAR16 *) Question->BufferValue) != 0) {
662 //
663 // There is something there! Prompt for password
664 //
665 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
666 if (EFI_ERROR (Status)) {
667 gBS->FreePool (StringPtr);
668 return Status;
669 }
670
671 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);
672 TempString[Maximum] = L'\0';
673
674 if (StrCmp (StringPtr, TempString) != 0) {
675 //
676 // Typed in old password incorrect
677 //
678 PasswordInvalid ();
679
680 gBS->FreePool (StringPtr);
681 gBS->FreePool (TempString);
682 return Status;
683 }
684
685 gBS->FreePool (TempString);
686 }
687 }
688
689 //
690 // Ask for new password
691 //
692 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
693 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
694 if (EFI_ERROR (Status)) {
695 //
696 // Reset state machine for interactive password
697 //
7936fb6a 698 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
93e3992d 699 PasswordCallback (Selection, MenuOption, NULL);
700 }
701
702 gBS->FreePool (StringPtr);
703 return Status;
704 }
705
706 //
707 // Confirm new password
708 //
709 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
710 ASSERT (TempString);
711 Status = ReadString (MenuOption, gConfirmPassword, TempString);
712 if (EFI_ERROR (Status)) {
713 //
714 // Reset state machine for interactive password
715 //
7936fb6a 716 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
93e3992d 717 PasswordCallback (Selection, MenuOption, NULL);
718 }
719
720 gBS->FreePool (StringPtr);
721 gBS->FreePool (TempString);
722 return Status;
723 }
724
725 //
726 // Compare two typed-in new passwords
727 //
728 if (StrCmp (StringPtr, TempString) == 0) {
729 //
730 // Two password match, send it to Configuration Driver
731 //
7936fb6a 732 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
93e3992d 733 PasswordCallback (Selection, MenuOption, StringPtr);
734 } else {
735 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));
736 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);
737 }
738 } else {
739 //
740 // Reset state machine for interactive password
741 //
7936fb6a 742 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {
93e3992d 743 PasswordCallback (Selection, MenuOption, NULL);
744 }
745
746 //
747 // Two password mismatch, prompt error message
748 //
749 do {
750 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);
751 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
752 }
753
754 gBS->FreePool (TempString);
755 gBS->FreePool (StringPtr);
756 }
757 break;
758
759 default:
760 break;
761 }
762
763 return Status;
764}
765
766
767/**
768 Process the help string: Split StringPtr to several lines of strings stored in
769 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
770
771 @param StringPtr The entire help string.
7936fb6a 772 @param FormattedString The oupput formatted string.
93e3992d 773 @param RowCount TRUE: if Question is selected.
93e3992d 774
775**/
776VOID
777ProcessHelpString (
778 IN CHAR16 *StringPtr,
779 OUT CHAR16 **FormattedString,
780 IN UINTN RowCount
781 )
782{
783 CONST UINTN BlockWidth = (UINTN) gHelpBlockWidth - 1;
784 UINTN AllocateSize;
785 //
786 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line
787 //
788 UINTN CurrIndex;
789 UINTN PrevCurrIndex;
790 UINTN LineCount;
791 UINTN VirtualLineCount;
792 //
793 // GlyphOffset stores glyph width of current screen-line
794 //
795 UINTN GlyphOffset;
796 //
797 // GlyphWidth equals to 2 if we meet width directive
798 //
799 UINTN GlyphWidth;
800 //
801 // during scanning, we remember the position of last space character
802 // in case that if next word cannot put in current line, we could restore back to the position
803 // of last space character
804 // while we should also remmeber the glyph width of the last space character for restoring
805 //
806 UINTN LastSpaceIndex;
807 UINTN LastSpaceGlyphWidth;
808 //
809 // every time we begin to form a new screen-line, we should remember glyph width of single character
810 // of last line
811 //
812 UINTN LineStartGlyphWidth;
813 UINTN *IndexArray;
814 UINTN *OldIndexArray;
815
816 //
817 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )
818 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want
819 // to bring the width directive of the last line to current screen-line.
820 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line
821 // different from that of "\wideabcde", we should remember the width directive.
822 //
823 AllocateSize = 0x20;
824 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
825
826 if (*FormattedString != NULL) {
827 gBS->FreePool (*FormattedString);
828 *FormattedString = NULL;
829 }
830
831 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,
832 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;
833 (StringPtr[CurrIndex] != CHAR_NULL);
834 CurrIndex ++) {
835
836 if (LineCount == AllocateSize) {
837 AllocateSize += 0x10;
838 OldIndexArray = IndexArray;
839 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);
840 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);
841 gBS->FreePool (OldIndexArray);
842 }
843 switch (StringPtr[CurrIndex]) {
844
845 case NARROW_CHAR:
846 case WIDE_CHAR:
847 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);
848 if (CurrIndex == 0) {
849 LineStartGlyphWidth = GlyphWidth;
850 }
851 break;
852
853 //
854 // char is '\n'
855 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN
856 //
857 case CHAR_LINEFEED:
858 //
859 // Store a range of string as a line
860 //
861 IndexArray[LineCount*3] = PrevCurrIndex;
862 IndexArray[LineCount*3+1] = CurrIndex;
863 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
864 LineCount ++;
865 //
866 // Reset offset and save begin position of line
867 //
868 GlyphOffset = 0;
869 LineStartGlyphWidth = GlyphWidth;
870 PrevCurrIndex = CurrIndex + 1;
871 break;
872
873 //
874 // char is '\r'
875 // "\r\n" and "\r" both are handled here
876 //
877 case CHAR_CARRIAGE_RETURN:
878 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {
879 //
880 // next char is '\n'
881 //
882 IndexArray[LineCount*3] = PrevCurrIndex;
883 IndexArray[LineCount*3+1] = CurrIndex;
884 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
885 LineCount ++;
886 CurrIndex ++;
887 }
888 GlyphOffset = 0;
889 LineStartGlyphWidth = GlyphWidth;
890 PrevCurrIndex = CurrIndex + 1;
891 break;
892
893 //
894 // char is space or other char
895 //
896 default:
897 GlyphOffset += GlyphWidth;
898 if (GlyphOffset >= BlockWidth) {
899 if (LastSpaceIndex > PrevCurrIndex) {
900 //
901 // LastSpaceIndex points to space inside current screen-line,
902 // restore to LastSpaceIndex
903 // (Otherwise the word is too long to fit one screen-line, just cut it)
904 //
905 CurrIndex = LastSpaceIndex;
906 GlyphWidth = LastSpaceGlyphWidth;
907 } else if (GlyphOffset > BlockWidth) {
908 //
909 // the word is too long to fit one screen-line and we don't get the chance
910 // of GlyphOffset == BlockWidth because GlyphWidth = 2
911 //
912 CurrIndex --;
913 }
914
915 IndexArray[LineCount*3] = PrevCurrIndex;
916 IndexArray[LineCount*3+1] = CurrIndex + 1;
917 IndexArray[LineCount*3+2] = LineStartGlyphWidth;
918 LineStartGlyphWidth = GlyphWidth;
919 LineCount ++;
920 //
921 // Reset offset and save begin position of line
922 //
923 GlyphOffset = 0;
924 PrevCurrIndex = CurrIndex + 1;
925 }
926
927 //
928 // LastSpaceIndex: remember position of last space
929 //
930 if (StringPtr[CurrIndex] == CHAR_SPACE) {
931 LastSpaceIndex = CurrIndex;
932 LastSpaceGlyphWidth = GlyphWidth;
933 }
934 break;
935 }
936 }
937
938 if (GlyphOffset > 0) {
939 IndexArray[LineCount*3] = PrevCurrIndex;
940 IndexArray[LineCount*3+1] = CurrIndex;
941 IndexArray[LineCount*3+2] = GlyphWidth;
942 LineCount ++;
943 }
944
945 if (LineCount == 0) {
946 //
947 // in case we meet null string
948 //
949 IndexArray[0] = 0;
950 IndexArray[1] = 1;
951 //
952 // we assume null string's glyph width is 1
953 //
954 IndexArray[1] = 1;
955 LineCount ++;
956 }
957
958 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));
959 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);
960
961 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {
962 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);
963 StrnCpy (
964 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,
965 StringPtr + IndexArray[CurrIndex*3],
966 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]
967 );
968 }
969
970 gBS->FreePool (IndexArray);
971}