]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
Update Browser to provide the customization possibilities.
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / ProcessOptions.c
1 /** @file
2 Implementation for handling the User Interface option processing.
3
4
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
10
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.
13
14 **/
15
16 #include "FormDisplay.h"
17
18 /**
19 Concatenate a narrow string to another string.
20
21 @param Destination The destination string.
22 @param Source The source string. The string to be concatenated.
23 to the end of Destination.
24
25 **/
26 VOID
27 NewStrCat (
28 IN OUT CHAR16 *Destination,
29 IN CHAR16 *Source
30 )
31 {
32 UINTN Length;
33
34 for (Length = 0; Destination[Length] != 0; Length++)
35 ;
36
37 //
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
42 //
43 Destination[Length] = NARROW_CHAR;
44 Length++;
45
46 StrCpy (Destination + Length, Source);
47 }
48
49 /**
50 Compare two Hii value.
51
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.
59
60 @retval other Could not perform compare on two values.
61 @retval EFI_SUCCESS Compare the value success.
62
63 **/
64 EFI_STATUS
65 CompareHiiValue (
66 IN EFI_HII_VALUE *Value1,
67 IN EFI_HII_VALUE *Value2,
68 OUT INTN *Result,
69 IN EFI_HII_HANDLE HiiHandle OPTIONAL
70 )
71 {
72 INT64 Temp64;
73 CHAR16 *Str1;
74 CHAR16 *Str2;
75 UINTN Len;
76
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;
80 }
81 }
82
83 if (Value1->Type == EFI_IFR_TYPE_STRING || Value2->Type == EFI_IFR_TYPE_STRING ) {
84 if (Value1->Type != Value2->Type) {
85 //
86 // Both Operator should be type of String
87 //
88 return EFI_UNSUPPORTED;
89 }
90
91 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
92 //
93 // StringId 0 is reserved
94 //
95 return EFI_INVALID_PARAMETER;
96 }
97
98 if (Value1->Value.string == Value2->Value.string) {
99 *Result = 0;
100 return EFI_SUCCESS;
101 }
102
103 Str1 = GetToken (Value1->Value.string, HiiHandle);
104 if (Str1 == NULL) {
105 //
106 // String not found
107 //
108 return EFI_NOT_FOUND;
109 }
110
111 Str2 = GetToken (Value2->Value.string, HiiHandle);
112 if (Str2 == NULL) {
113 FreePool (Str1);
114 return EFI_NOT_FOUND;
115 }
116
117 *Result = StrCmp (Str1, Str2);
118
119 FreePool (Str1);
120 FreePool (Str2);
121
122 return EFI_SUCCESS;
123 }
124
125 if (Value1->Type == EFI_IFR_TYPE_BUFFER || Value2->Type == EFI_IFR_TYPE_BUFFER ) {
126 if (Value1->Type != Value2->Type) {
127 //
128 // Both Operator should be type of Buffer.
129 //
130 return EFI_UNSUPPORTED;
131 }
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))
135 {
136 //
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.
139 //
140 *Result = Value1->BufferLen > Value2->BufferLen ? 1 : -1;
141 }
142 return EFI_SUCCESS;
143 }
144
145 //
146 // Take remain types(integer, boolean, date/time) as integer
147 //
148 Temp64 = (INT64) (Value1->Value.u64 - Value2->Value.u64);
149 if (Temp64 > 0) {
150 *Result = 1;
151 } else if (Temp64 < 0) {
152 *Result = -1;
153 } else {
154 *Result = 0;
155 }
156
157 return EFI_SUCCESS;
158 }
159
160 /**
161 Search an Option of a Question by its value.
162
163 @param Question The Question
164 @param OptionValue Value for Option to be searched.
165
166 @retval Pointer Pointer to the found Option.
167 @retval NULL Option not found.
168
169 **/
170 DISPLAY_QUESTION_OPTION *
171 ValueToOption (
172 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
173 IN EFI_HII_VALUE *OptionValue
174 )
175 {
176 LIST_ENTRY *Link;
177 DISPLAY_QUESTION_OPTION *Option;
178 INTN Result;
179 EFI_HII_VALUE Value;
180
181 Link = GetFirstNode (&Question->OptionListHead);
182 while (!IsNull (&Question->OptionListHead, Link)) {
183 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
184
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));
188
189 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
190 return Option;
191 }
192
193 Link = GetNextNode (&Question->OptionListHead, Link);
194 }
195
196 return NULL;
197 }
198
199
200 /**
201 Return data element in an Array by its Index.
202
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.
206
207 @retval Value The data to be returned
208
209 **/
210 UINT64
211 GetArrayData (
212 IN VOID *Array,
213 IN UINT8 Type,
214 IN UINTN Index
215 )
216 {
217 UINT64 Data;
218
219 ASSERT (Array != NULL);
220
221 Data = 0;
222 switch (Type) {
223 case EFI_IFR_TYPE_NUM_SIZE_8:
224 Data = (UINT64) *(((UINT8 *) Array) + Index);
225 break;
226
227 case EFI_IFR_TYPE_NUM_SIZE_16:
228 Data = (UINT64) *(((UINT16 *) Array) + Index);
229 break;
230
231 case EFI_IFR_TYPE_NUM_SIZE_32:
232 Data = (UINT64) *(((UINT32 *) Array) + Index);
233 break;
234
235 case EFI_IFR_TYPE_NUM_SIZE_64:
236 Data = (UINT64) *(((UINT64 *) Array) + Index);
237 break;
238
239 default:
240 break;
241 }
242
243 return Data;
244 }
245
246
247 /**
248 Set value of a data element in an Array by its Index.
249
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.
254
255 **/
256 VOID
257 SetArrayData (
258 IN VOID *Array,
259 IN UINT8 Type,
260 IN UINTN Index,
261 IN UINT64 Value
262 )
263 {
264
265 ASSERT (Array != NULL);
266
267 switch (Type) {
268 case EFI_IFR_TYPE_NUM_SIZE_8:
269 *(((UINT8 *) Array) + Index) = (UINT8) Value;
270 break;
271
272 case EFI_IFR_TYPE_NUM_SIZE_16:
273 *(((UINT16 *) Array) + Index) = (UINT16) Value;
274 break;
275
276 case EFI_IFR_TYPE_NUM_SIZE_32:
277 *(((UINT32 *) Array) + Index) = (UINT32) Value;
278 break;
279
280 case EFI_IFR_TYPE_NUM_SIZE_64:
281 *(((UINT64 *) Array) + Index) = (UINT64) Value;
282 break;
283
284 default:
285 break;
286 }
287 }
288
289 /**
290 Check whether this value already in the array, if yes, return the index.
291
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.
296
297 @retval TRUE Found the value in the array.
298 @retval FALSE Not found the value.
299
300 **/
301 BOOLEAN
302 FindArrayData (
303 IN VOID *Array,
304 IN UINT8 Type,
305 IN UINT64 Value,
306 OUT UINTN *Index OPTIONAL
307 )
308 {
309 UINTN Count;
310 UINT64 TmpValue;
311 UINT64 ValueComp;
312
313 ASSERT (Array != NULL);
314
315 Count = 0;
316 TmpValue = 0;
317
318 switch (Type) {
319 case EFI_IFR_TYPE_NUM_SIZE_8:
320 ValueComp = (UINT8) Value;
321 break;
322
323 case EFI_IFR_TYPE_NUM_SIZE_16:
324 ValueComp = (UINT16) Value;
325 break;
326
327 case EFI_IFR_TYPE_NUM_SIZE_32:
328 ValueComp = (UINT32) Value;
329 break;
330
331 case EFI_IFR_TYPE_NUM_SIZE_64:
332 ValueComp = (UINT64) Value;
333 break;
334
335 default:
336 ValueComp = 0;
337 break;
338 }
339
340 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
341 if (ValueComp == TmpValue) {
342 if (Index != NULL) {
343 *Index = Count;
344 }
345 return TRUE;
346 }
347
348 Count ++;
349 }
350
351 return FALSE;
352 }
353
354 /**
355 Print Question Value according to it's storage width and display attributes.
356
357 @param Question The Question to be printed.
358 @param FormattedNumber Buffer for output string.
359 @param BufferSize The FormattedNumber buffer size in bytes.
360
361 @retval EFI_SUCCESS Print success.
362 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
363
364 **/
365 EFI_STATUS
366 PrintFormattedNumber (
367 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
368 IN OUT CHAR16 *FormattedNumber,
369 IN UINTN BufferSize
370 )
371 {
372 INT64 Value;
373 CHAR16 *Format;
374 EFI_HII_VALUE *QuestionValue;
375 EFI_IFR_NUMERIC *NumericOp;
376
377 if (BufferSize < (21 * sizeof (CHAR16))) {
378 return EFI_BUFFER_TOO_SMALL;
379 }
380
381 QuestionValue = &Question->CurrentValue;
382 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
383
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);
390 break;
391
392 case EFI_IFR_NUMERIC_SIZE_2:
393 Value = (INT64) ((INT16) QuestionValue->Value.u16);
394 break;
395
396 case EFI_IFR_NUMERIC_SIZE_4:
397 Value = (INT64) ((INT32) QuestionValue->Value.u32);
398 break;
399
400 case EFI_IFR_NUMERIC_SIZE_8:
401 default:
402 break;
403 }
404
405 if (Value < 0) {
406 Value = -Value;
407 Format = L"-%ld";
408 } else {
409 Format = L"%ld";
410 }
411 break;
412
413 case EFI_IFR_DISPLAY_UINT_DEC:
414 Format = L"%ld";
415 break;
416
417 case EFI_IFR_DISPLAY_UINT_HEX:
418 Format = L"%lx";
419 break;
420
421 default:
422 return EFI_UNSUPPORTED;
423 break;
424 }
425
426 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
427
428 return EFI_SUCCESS;
429 }
430
431
432 /**
433 Draw a pop up windows based on the dimension, number of lines and
434 strings specified.
435
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.
439
440 **/
441 VOID
442 CreateSharedPopUp (
443 IN UINTN RequestedWidth,
444 IN UINTN NumberOfLines,
445 IN VA_LIST Marker
446 )
447 {
448 UINTN Index;
449 UINTN Count;
450 CHAR16 Character;
451 UINTN Start;
452 UINTN End;
453 UINTN Top;
454 UINTN Bottom;
455 CHAR16 *String;
456 UINTN DimensionsWidth;
457 UINTN DimensionsHeight;
458
459 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
460 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
461
462 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
463
464 if ((RequestedWidth + 2) > DimensionsWidth) {
465 RequestedWidth = DimensionsWidth - 2;
466 }
467
468 //
469 // Subtract the PopUp width from total Columns, allow for one space extra on
470 // each end plus a border.
471 //
472 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;
473 End = Start + RequestedWidth + 1;
474
475 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;
476 Bottom = Top + NumberOfLines + 2;
477
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);
483 }
484
485 Character = BOXDRAW_DOWN_LEFT;
486 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
487 Character = BOXDRAW_VERTICAL;
488
489 Count = 0;
490 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
491 String = VA_ARG (Marker, CHAR16*);
492
493 //
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.
497 //
498 if (GetStringWidth (String) / 2 > 1) {
499 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
500 }
501
502 //
503 // Passing in a space results in the assumption that this is where typing will occur
504 //
505 if (String[0] == L' ') {
506 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());
507 }
508
509 //
510 // Passing in a NULL results in a blank space
511 //
512 if (String[0] == CHAR_NULL) {
513 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
514 }
515
516 PrintStringAt (
517 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,
518 Index + 1,
519 String
520 );
521 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
522 PrintCharAt (Start, Index + 1, Character);
523 PrintCharAt (End - 1, Index + 1, Character);
524 }
525
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);
531 }
532
533 Character = BOXDRAW_UP_LEFT;
534 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
535 }
536
537 /**
538 Draw a pop up windows based on the dimension, number of lines and
539 strings specified.
540
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.
544
545 **/
546 VOID
547 EFIAPI
548 CreateMultiStringPopUp (
549 IN UINTN RequestedWidth,
550 IN UINTN NumberOfLines,
551 ...
552 )
553 {
554 VA_LIST Marker;
555
556 VA_START (Marker, NumberOfLines);
557
558 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);
559
560 VA_END (Marker);
561 }
562
563 /**
564 Process validate for one question.
565
566 @param Question The question need to be validate.
567
568 @retval EFI_SUCCESS Question Option process success.
569 @retval EFI_INVALID_PARAMETER Question Option process fail.
570
571 **/
572 EFI_STATUS
573 ValidateQuestion (
574 IN FORM_DISPLAY_ENGINE_STATEMENT *Question
575 )
576 {
577 CHAR16 *ErrorInfo;
578 EFI_INPUT_KEY Key;
579 EFI_STATUS Status;
580 STATEMENT_ERROR_INFO RetInfo;
581 UINT32 RetVal;
582
583 if (Question->ValidateQuestion == NULL) {
584 return EFI_SUCCESS;
585 }
586
587 Status = EFI_SUCCESS;
588 RetVal = Question->ValidateQuestion(gFormData, Question, &gUserInput->InputValue, &RetInfo);
589
590 switch (RetVal) {
591 case INCOSISTENT_IF_TRUE:
592 //
593 // Condition meet, show up error message
594 //
595 ASSERT (RetInfo.StringId != 0);
596 ErrorInfo = GetToken (RetInfo.StringId, gFormData->HiiHandle);
597 do {
598 CreateDialog (&Key, gEmptyString, ErrorInfo, gPressEnter, gEmptyString, NULL);
599 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
600 FreePool (ErrorInfo);
601
602 Status = EFI_INVALID_PARAMETER;
603 break;
604
605 default:
606 break;
607 }
608
609 return Status;
610 }
611
612 /**
613 Display error message for invalid password.
614
615 **/
616 VOID
617 PasswordInvalid (
618 VOID
619 )
620 {
621 EFI_INPUT_KEY Key;
622
623 //
624 // Invalid password, prompt error message
625 //
626 do {
627 CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);
628 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
629 }
630
631 /**
632 Process password op code.
633
634 @param MenuOption The menu for current password op code.
635
636 @retval EFI_SUCCESS Question Option process success.
637 @retval Other Question Option process fail.
638
639 **/
640 EFI_STATUS
641 PasswordProcess (
642 IN UI_MENU_OPTION *MenuOption
643 )
644 {
645 CHAR16 *StringPtr;
646 CHAR16 *TempString;
647 UINTN Maximum;
648 EFI_STATUS Status;
649 EFI_IFR_PASSWORD *PasswordInfo;
650 FORM_DISPLAY_ENGINE_STATEMENT *Question;
651 EFI_INPUT_KEY Key;
652
653 Question = MenuOption->ThisTag;
654 PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;
655 Maximum = PasswordInfo->MaxSize;
656 Status = EFI_SUCCESS;
657
658 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
659 ASSERT (StringPtr);
660
661 //
662 // Use a NULL password to test whether old password is required
663 //
664 *StringPtr = 0;
665 Status = Question->PasswordCheck (gFormData, Question, StringPtr);
666 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
667 //
668 // Password can't be set now.
669 //
670 FreePool (StringPtr);
671 return EFI_SUCCESS;
672 }
673
674 if (EFI_ERROR (Status)) {
675 //
676 // Old password exist, ask user for the old password
677 //
678 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
679 if (EFI_ERROR (Status)) {
680 FreePool (StringPtr);
681 return Status;
682 }
683
684 //
685 // Check user input old password
686 //
687 Status = Question->PasswordCheck (gFormData, Question, StringPtr);
688 if (EFI_ERROR (Status)) {
689 if (Status == EFI_NOT_READY) {
690 //
691 // Typed in old password incorrect
692 //
693 PasswordInvalid ();
694 } else {
695 Status = EFI_SUCCESS;
696 }
697
698 FreePool (StringPtr);
699 return Status;
700 }
701 }
702
703 //
704 // Ask for new password
705 //
706 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
707 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
708 if (EFI_ERROR (Status)) {
709 //
710 // Reset state machine for password
711 //
712 Question->PasswordCheck (gFormData, Question, NULL);
713 FreePool (StringPtr);
714 return Status;
715 }
716
717 //
718 // Confirm new password
719 //
720 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
721 ASSERT (TempString);
722 Status = ReadString (MenuOption, gConfirmPassword, TempString);
723 if (EFI_ERROR (Status)) {
724 //
725 // Reset state machine for password
726 //
727 Question->PasswordCheck (gFormData, Question, NULL);
728 FreePool (StringPtr);
729 FreePool (TempString);
730 return Status;
731 }
732
733 //
734 // Compare two typed-in new passwords
735 //
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);
742
743 Status = ValidateQuestion (Question);
744
745 if (EFI_ERROR (Status)) {
746 //
747 // Reset state machine for password
748 //
749 Question->PasswordCheck (gFormData, Question, NULL);
750 }
751
752 return Status;
753 } else {
754 //
755 // Reset state machine for password
756 //
757 Question->PasswordCheck (gFormData, Question, NULL);
758
759 //
760 // Two password mismatch, prompt error message
761 //
762 do {
763 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
764 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
765
766 Status = EFI_INVALID_PARAMETER;
767 }
768
769 FreePool (TempString);
770 FreePool (StringPtr);
771
772 return Status;
773 }
774
775 /**
776 Process a Question's Option (whether selected or un-selected).
777
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.
782
783 @retval EFI_SUCCESS Question Option process success.
784 @retval Other Question Option process fail.
785
786 **/
787 EFI_STATUS
788 ProcessOptions (
789 IN UI_MENU_OPTION *MenuOption,
790 IN BOOLEAN Selected,
791 OUT CHAR16 **OptionString,
792 IN BOOLEAN SkipErrorValue
793 )
794 {
795 EFI_STATUS Status;
796 CHAR16 *StringPtr;
797 UINTN Index;
798 FORM_DISPLAY_ENGINE_STATEMENT *Question;
799 CHAR16 FormattedNumber[21];
800 UINT16 Number;
801 CHAR16 Character[2];
802 EFI_INPUT_KEY Key;
803 UINTN BufferSize;
804 DISPLAY_QUESTION_OPTION *OneOfOption;
805 LIST_ENTRY *Link;
806 EFI_HII_VALUE HiiValue;
807 EFI_HII_VALUE *QuestionValue;
808 DISPLAY_QUESTION_OPTION *Option;
809 UINTN Index2;
810 UINT8 *ValueArray;
811 UINT8 ValueType;
812 EFI_STRING_ID StringId;
813 EFI_IFR_ORDERED_LIST *OrderList;
814 BOOLEAN ValueInvalid;
815
816 Status = EFI_SUCCESS;
817
818 StringPtr = NULL;
819 Character[1] = L'\0';
820 *OptionString = NULL;
821 StringId = 0;
822 ValueInvalid = FALSE;
823
824 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
825 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
826
827 Question = MenuOption->ThisTag;
828 QuestionValue = &Question->CurrentValue;
829
830 switch (Question->OpCode->OpCode) {
831 case EFI_IFR_ORDERED_LIST_OP:
832
833 //
834 // Check whether there are Options of this OrderedList
835 //
836 if (IsListEmpty (&Question->OptionListHead)) {
837 break;
838 }
839
840 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
841
842 Link = GetFirstNode (&Question->OptionListHead);
843 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
844
845 ValueType = OneOfOption->OptionOpCode->Type;
846 ValueArray = Question->CurrentValue.Buffer;
847
848 if (Selected) {
849 //
850 // Go ask for input
851 //
852 Status = GetSelectionInputPopUp (MenuOption);
853 } else {
854 //
855 // We now know how many strings we will have, so we can allocate the
856 // space required for the array or strings.
857 //
858 *OptionString = AllocateZeroPool (OrderList->MaxContainers * BufferSize);
859 ASSERT (*OptionString);
860
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) {
866 //
867 // Values for the options in ordered lists should never be a 0
868 //
869 break;
870 }
871
872 OneOfOption = ValueToOption (Question, &HiiValue);
873 if (OneOfOption == NULL) {
874 if (SkipErrorValue) {
875 //
876 // Just try to get the option string, skip the value which not has option.
877 //
878 continue;
879 }
880
881 //
882 // Show error message
883 //
884 do {
885 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
886 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
887
888 //
889 // The initial value of the orderedlist is invalid, force to be valid value
890 // Exit current DisplayForm with new value.
891 //
892 gUserInput->SelectedStatement = Question;
893
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;
899
900 Link = GetFirstNode (&Question->OptionListHead);
901 Index2 = 0;
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);
906 Index2++;
907 }
908 SetArrayData (ValueArray, ValueType, Index2, 0);
909
910 FreePool (*OptionString);
911 *OptionString = NULL;
912 return EFI_NOT_FOUND;
913 }
914
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);
925 }
926
927 //
928 // If valid option more than the max container, skip these options.
929 //
930 if (Index >= OrderList->MaxContainers) {
931 break;
932 }
933
934 //
935 // Search the other options, try to find the one not in the container.
936 //
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);
941
942 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
943 continue;
944 }
945
946 if (SkipErrorValue) {
947 //
948 // Not report error, just get the correct option string info.
949 //
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);
960
961 continue;
962 }
963
964 if (!ValueInvalid) {
965 ValueInvalid = TRUE;
966 //
967 // Show error message
968 //
969 do {
970 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
971 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
972
973 //
974 // The initial value of the orderedlist is invalid, force to be valid value
975 // Exit current DisplayForm with new value.
976 //
977 gUserInput->SelectedStatement = Question;
978
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;
984 }
985
986 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
987 }
988
989 if (ValueInvalid) {
990 FreePool (*OptionString);
991 *OptionString = NULL;
992 return EFI_NOT_FOUND;
993 }
994 }
995 break;
996
997 case EFI_IFR_ONE_OF_OP:
998 //
999 // Check whether there are Options of this OneOf
1000 //
1001 if (IsListEmpty (&Question->OptionListHead)) {
1002 break;
1003 }
1004 if (Selected) {
1005 //
1006 // Go ask for input
1007 //
1008 Status = GetSelectionInputPopUp (MenuOption);
1009 } else {
1010 *OptionString = AllocateZeroPool (BufferSize);
1011 ASSERT (*OptionString);
1012
1013 OneOfOption = ValueToOption (Question, QuestionValue);
1014 if (OneOfOption == NULL) {
1015 if (SkipErrorValue) {
1016 //
1017 // Not report error, just get the correct option string info.
1018 //
1019 Link = GetFirstNode (&Question->OptionListHead);
1020 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1021 } else {
1022 //
1023 // Show error message
1024 //
1025 do {
1026 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1027 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1028
1029 //
1030 // Force the Question value to be valid
1031 // Exit current DisplayForm with new value.
1032 //
1033 Link = GetFirstNode (&Question->OptionListHead);
1034 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1035
1036 CopyMem (&gUserInput->InputValue.Value, &Option->OptionOpCode->Value, sizeof (EFI_IFR_TYPE_VALUE));
1037 gUserInput->InputValue.Type = Option->OptionOpCode->Type;
1038 gUserInput->SelectedStatement = Question;
1039
1040 FreePool (*OptionString);
1041 *OptionString = NULL;
1042 return EFI_NOT_FOUND;
1043 }
1044 }
1045
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);
1053
1054 FreePool (StringPtr);
1055 }
1056 break;
1057
1058 case EFI_IFR_CHECKBOX_OP:
1059 if (Selected) {
1060 //
1061 // Since this is a BOOLEAN operation, flip it upon selection
1062 //
1063 gUserInput->InputValue.Type = QuestionValue->Type;
1064 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
1065
1066 //
1067 // Perform inconsistent check
1068 //
1069 return ValidateQuestion (Question);
1070 } else {
1071 *OptionString = AllocateZeroPool (BufferSize);
1072 ASSERT (*OptionString);
1073
1074 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
1075
1076 if (QuestionValue->Value.b) {
1077 *(OptionString[0] + 1) = CHECK_ON;
1078 } else {
1079 *(OptionString[0] + 1) = CHECK_OFF;
1080 }
1081 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
1082 }
1083 break;
1084
1085 case EFI_IFR_NUMERIC_OP:
1086 if (Selected) {
1087 //
1088 // Go ask for input
1089 //
1090 Status = GetNumericInput (MenuOption);
1091 } else {
1092 *OptionString = AllocateZeroPool (BufferSize);
1093 ASSERT (*OptionString);
1094
1095 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1096
1097 //
1098 // Formatted print
1099 //
1100 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
1101 Number = (UINT16) GetStringWidth (FormattedNumber);
1102 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
1103
1104 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
1105 }
1106 break;
1107
1108 case EFI_IFR_DATE_OP:
1109 if (Selected) {
1110 //
1111 // This is similar to numerics
1112 //
1113 Status = GetNumericInput (MenuOption);
1114 } else {
1115 *OptionString = AllocateZeroPool (BufferSize);
1116 ASSERT (*OptionString);
1117
1118 switch (MenuOption->Sequence) {
1119 case 0:
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;
1123 break;
1124
1125 case 1:
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;
1129 break;
1130
1131 case 2:
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;
1135 break;
1136 }
1137 }
1138 break;
1139
1140 case EFI_IFR_TIME_OP:
1141 if (Selected) {
1142 //
1143 // This is similar to numerics
1144 //
1145 Status = GetNumericInput (MenuOption);
1146 } else {
1147 *OptionString = AllocateZeroPool (BufferSize);
1148 ASSERT (*OptionString);
1149
1150 switch (MenuOption->Sequence) {
1151 case 0:
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;
1155 break;
1156
1157 case 1:
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;
1161 break;
1162
1163 case 2:
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;
1167 break;
1168 }
1169 }
1170 break;
1171
1172 case EFI_IFR_STRING_OP:
1173 if (Selected) {
1174 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
1175 ASSERT (StringPtr);
1176 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
1177
1178 Status = ReadString (MenuOption, gPromptForData, StringPtr);
1179 if (EFI_ERROR (Status)) {
1180 FreePool (StringPtr);
1181 return Status;
1182 }
1183
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);
1190 } else {
1191 *OptionString = AllocateZeroPool (BufferSize);
1192 ASSERT (*OptionString);
1193
1194 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
1195 *(OptionString[0]) = '_';
1196 } else {
1197 if (Question->CurrentValue.BufferLen < BufferSize) {
1198 BufferSize = Question->CurrentValue.BufferLen;
1199 }
1200 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
1201 }
1202 }
1203 break;
1204
1205 case EFI_IFR_PASSWORD_OP:
1206 if (Selected) {
1207 Status = PasswordProcess (MenuOption);
1208 }
1209 break;
1210
1211 default:
1212 break;
1213 }
1214
1215 return Status;
1216 }
1217
1218
1219 /**
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.
1222
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.
1227
1228 **/
1229 UINTN
1230 ProcessHelpString (
1231 IN CHAR16 *StringPtr,
1232 OUT CHAR16 **FormattedString,
1233 OUT UINT16 *EachLineWidth,
1234 IN UINTN RowCount
1235 )
1236 {
1237 UINTN Index;
1238 CHAR16 *OutputString;
1239 UINTN TotalRowNum;
1240 UINTN CheckedNum;
1241 UINT16 GlyphWidth;
1242 UINT16 LineWidth;
1243 UINT16 MaxStringLen;
1244 UINT16 StringLen;
1245
1246 TotalRowNum = 0;
1247 CheckedNum = 0;
1248 GlyphWidth = 1;
1249 Index = 0;
1250 MaxStringLen = 0;
1251 StringLen = 0;
1252
1253 //
1254 // Set default help string width.
1255 //
1256 LineWidth = (UINT16) (gHelpBlockWidth - 1);
1257
1258 //
1259 // Get row number of the String.
1260 //
1261 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1262 if (StringLen > MaxStringLen) {
1263 MaxStringLen = StringLen;
1264 }
1265
1266 TotalRowNum ++;
1267 FreePool (OutputString);
1268 }
1269 *EachLineWidth = MaxStringLen;
1270
1271 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
1272 ASSERT (*FormattedString != NULL);
1273
1274 //
1275 // Generate formatted help string array.
1276 //
1277 GlyphWidth = 1;
1278 Index = 0;
1279 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1280 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
1281 CheckedNum ++;
1282 FreePool (OutputString);
1283 }
1284
1285 return TotalRowNum;
1286 }