]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
MdeModulePkg: Clean up source files
[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 - 2018, 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 #define MAX_TIME_OUT_LEN 0x10
19
20 /**
21 Concatenate a narrow string to another string.
22
23 @param Destination The destination string.
24 @param DestMax The Max length of destination string.
25 @param Source The source string. The string to be concatenated.
26 to the end of Destination.
27
28 **/
29 VOID
30 NewStrCat (
31 IN OUT CHAR16 *Destination,
32 IN UINTN DestMax,
33 IN CHAR16 *Source
34 )
35 {
36 UINTN Length;
37
38 for (Length = 0; Destination[Length] != 0; Length++)
39 ;
40
41 //
42 // We now have the length of the original string
43 // We can safely assume for now that we are concatenating a narrow value to this string.
44 // For instance, the string is "XYZ" and cat'ing ">"
45 // If this assumption changes, we need to make this routine a bit more complex
46 //
47 Destination[Length] = NARROW_CHAR;
48 Length++;
49
50 StrCpyS (Destination + Length, DestMax - Length, Source);
51 }
52
53 /**
54 Get UINT64 type value.
55
56 @param Value Input Hii value.
57
58 @retval UINT64 Return the UINT64 type value.
59
60 **/
61 UINT64
62 HiiValueToUINT64 (
63 IN EFI_HII_VALUE *Value
64 )
65 {
66 UINT64 RetVal;
67
68 RetVal = 0;
69
70 switch (Value->Type) {
71 case EFI_IFR_TYPE_NUM_SIZE_8:
72 RetVal = Value->Value.u8;
73 break;
74
75 case EFI_IFR_TYPE_NUM_SIZE_16:
76 RetVal = Value->Value.u16;
77 break;
78
79 case EFI_IFR_TYPE_NUM_SIZE_32:
80 RetVal = Value->Value.u32;
81 break;
82
83 case EFI_IFR_TYPE_BOOLEAN:
84 RetVal = Value->Value.b;
85 break;
86
87 case EFI_IFR_TYPE_DATE:
88 RetVal = *(UINT64*) &Value->Value.date;
89 break;
90
91 case EFI_IFR_TYPE_TIME:
92 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;
93 break;
94
95 default:
96 RetVal = Value->Value.u64;
97 break;
98 }
99
100 return RetVal;
101 }
102
103 /**
104 Check whether this value type can be transfer to EFI_IFR_TYPE_BUFFER type.
105
106 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
107 EFI_IFR_TYPE_BUFFER when do the value compare.
108
109 @param Value Expression value to compare on.
110
111 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
112 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
113
114 **/
115 BOOLEAN
116 IsTypeInBuffer (
117 IN EFI_HII_VALUE *Value
118 )
119 {
120 switch (Value->Type) {
121 case EFI_IFR_TYPE_BUFFER:
122 case EFI_IFR_TYPE_DATE:
123 case EFI_IFR_TYPE_TIME:
124 case EFI_IFR_TYPE_REF:
125 return TRUE;
126
127 default:
128 return FALSE;
129 }
130 }
131
132 /**
133 Check whether this value type can be transfer to EFI_IFR_TYPE_UINT64
134
135 @param Value Expression value to compare on.
136
137 @retval TRUE This value type can be transter to EFI_IFR_TYPE_BUFFER type.
138 @retval FALSE This value type can't be transter to EFI_IFR_TYPE_BUFFER type.
139
140 **/
141 BOOLEAN
142 IsTypeInUINT64 (
143 IN EFI_HII_VALUE *Value
144 )
145 {
146 switch (Value->Type) {
147 case EFI_IFR_TYPE_NUM_SIZE_8:
148 case EFI_IFR_TYPE_NUM_SIZE_16:
149 case EFI_IFR_TYPE_NUM_SIZE_32:
150 case EFI_IFR_TYPE_NUM_SIZE_64:
151 case EFI_IFR_TYPE_BOOLEAN:
152 return TRUE;
153
154 default:
155 return FALSE;
156 }
157 }
158
159 /**
160 Return the buffer length and buffer pointer for this value.
161
162 EFI_IFR_TYPE_REF, EFI_IFR_TYPE_DATE and EFI_IFR_TYPE_TIME are converted to
163 EFI_IFR_TYPE_BUFFER when do the value compare.
164
165 @param Value Expression value to compare on.
166 @param Buf Return the buffer pointer.
167 @param BufLen Return the buffer length.
168
169 **/
170 VOID
171 GetBufAndLenForValue (
172 IN EFI_HII_VALUE *Value,
173 OUT UINT8 **Buf,
174 OUT UINT16 *BufLen
175 )
176 {
177 switch (Value->Type) {
178 case EFI_IFR_TYPE_BUFFER:
179 *Buf = Value->Buffer;
180 *BufLen = Value->BufferLen;
181 break;
182
183 case EFI_IFR_TYPE_DATE:
184 *Buf = (UINT8 *) (&Value->Value.date);
185 *BufLen = (UINT16) sizeof (EFI_HII_DATE);
186 break;
187
188 case EFI_IFR_TYPE_TIME:
189 *Buf = (UINT8 *) (&Value->Value.time);
190 *BufLen = (UINT16) sizeof (EFI_HII_TIME);
191 break;
192
193 case EFI_IFR_TYPE_REF:
194 *Buf = (UINT8 *) (&Value->Value.ref);
195 *BufLen = (UINT16) sizeof (EFI_HII_REF);
196 break;
197
198 default:
199 *Buf = NULL;
200 *BufLen = 0;
201 }
202 }
203
204 /**
205 Compare two Hii value.
206
207 @param Value1 Expression value to compare on left-hand.
208 @param Value2 Expression value to compare on right-hand.
209 @param Result Return value after compare.
210 retval 0 Two operators equal.
211 return Positive value if Value1 is greater than Value2.
212 retval Negative value if Value1 is less than Value2.
213 @param HiiHandle Only required for string compare.
214
215 @retval other Could not perform compare on two values.
216 @retval EFI_SUCCESS Compare the value success.
217
218 **/
219 EFI_STATUS
220 CompareHiiValue (
221 IN EFI_HII_VALUE *Value1,
222 IN EFI_HII_VALUE *Value2,
223 OUT INTN *Result,
224 IN EFI_HII_HANDLE HiiHandle OPTIONAL
225 )
226 {
227 INT64 Temp64;
228 CHAR16 *Str1;
229 CHAR16 *Str2;
230 UINTN Len;
231 UINT8 *Buf1;
232 UINT16 Buf1Len;
233 UINT8 *Buf2;
234 UINT16 Buf2Len;
235
236 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {
237 if (Value1->Value.string == 0 || Value2->Value.string == 0) {
238 //
239 // StringId 0 is reserved
240 //
241 return EFI_INVALID_PARAMETER;
242 }
243
244 if (Value1->Value.string == Value2->Value.string) {
245 *Result = 0;
246 return EFI_SUCCESS;
247 }
248
249 Str1 = GetToken (Value1->Value.string, HiiHandle);
250 if (Str1 == NULL) {
251 //
252 // String not found
253 //
254 return EFI_NOT_FOUND;
255 }
256
257 Str2 = GetToken (Value2->Value.string, HiiHandle);
258 if (Str2 == NULL) {
259 FreePool (Str1);
260 return EFI_NOT_FOUND;
261 }
262
263 *Result = StrCmp (Str1, Str2);
264
265 FreePool (Str1);
266 FreePool (Str2);
267
268 return EFI_SUCCESS;
269 }
270
271 //
272 // Take types(date, time, ref, buffer) as buffer
273 //
274 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {
275 GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);
276 GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);
277
278 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;
279 *Result = CompareMem (Buf1, Buf2, Len);
280 if ((*Result == 0) && (Buf1Len != Buf2Len)) {
281 //
282 // In this case, means base on samll number buffer, the data is same
283 // So which value has more data, which value is bigger.
284 //
285 *Result = Buf1Len > Buf2Len ? 1 : -1;
286 }
287 return EFI_SUCCESS;
288 }
289
290 //
291 // Take remain types(integer, boolean, date/time) as integer
292 //
293 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {
294 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);
295 if (Temp64 > 0) {
296 *Result = 1;
297 } else if (Temp64 < 0) {
298 *Result = -1;
299 } else {
300 *Result = 0;
301 }
302 return EFI_SUCCESS;
303 }
304
305 return EFI_UNSUPPORTED;
306 }
307
308 /**
309 Search an Option of a Question by its value.
310
311 @param Question The Question
312 @param OptionValue Value for Option to be searched.
313
314 @retval Pointer Pointer to the found Option.
315 @retval NULL Option not found.
316
317 **/
318 DISPLAY_QUESTION_OPTION *
319 ValueToOption (
320 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
321 IN EFI_HII_VALUE *OptionValue
322 )
323 {
324 LIST_ENTRY *Link;
325 DISPLAY_QUESTION_OPTION *Option;
326 INTN Result;
327 EFI_HII_VALUE Value;
328
329 Link = GetFirstNode (&Question->OptionListHead);
330 while (!IsNull (&Question->OptionListHead, Link)) {
331 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
332
333 ZeroMem (&Value, sizeof (EFI_HII_VALUE));
334 Value.Type = Option->OptionOpCode->Type;
335 CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
336
337 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
338 return Option;
339 }
340
341 Link = GetNextNode (&Question->OptionListHead, Link);
342 }
343
344 return NULL;
345 }
346
347
348 /**
349 Return data element in an Array by its Index.
350
351 @param Array The data array.
352 @param Type Type of the data in this array.
353 @param Index Zero based index for data in this array.
354
355 @retval Value The data to be returned
356
357 **/
358 UINT64
359 GetArrayData (
360 IN VOID *Array,
361 IN UINT8 Type,
362 IN UINTN Index
363 )
364 {
365 UINT64 Data;
366
367 ASSERT (Array != NULL);
368
369 Data = 0;
370 switch (Type) {
371 case EFI_IFR_TYPE_NUM_SIZE_8:
372 Data = (UINT64) *(((UINT8 *) Array) + Index);
373 break;
374
375 case EFI_IFR_TYPE_NUM_SIZE_16:
376 Data = (UINT64) *(((UINT16 *) Array) + Index);
377 break;
378
379 case EFI_IFR_TYPE_NUM_SIZE_32:
380 Data = (UINT64) *(((UINT32 *) Array) + Index);
381 break;
382
383 case EFI_IFR_TYPE_NUM_SIZE_64:
384 Data = (UINT64) *(((UINT64 *) Array) + Index);
385 break;
386
387 default:
388 break;
389 }
390
391 return Data;
392 }
393
394
395 /**
396 Set value of a data element in an Array by its Index.
397
398 @param Array The data array.
399 @param Type Type of the data in this array.
400 @param Index Zero based index for data in this array.
401 @param Value The value to be set.
402
403 **/
404 VOID
405 SetArrayData (
406 IN VOID *Array,
407 IN UINT8 Type,
408 IN UINTN Index,
409 IN UINT64 Value
410 )
411 {
412
413 ASSERT (Array != NULL);
414
415 switch (Type) {
416 case EFI_IFR_TYPE_NUM_SIZE_8:
417 *(((UINT8 *) Array) + Index) = (UINT8) Value;
418 break;
419
420 case EFI_IFR_TYPE_NUM_SIZE_16:
421 *(((UINT16 *) Array) + Index) = (UINT16) Value;
422 break;
423
424 case EFI_IFR_TYPE_NUM_SIZE_32:
425 *(((UINT32 *) Array) + Index) = (UINT32) Value;
426 break;
427
428 case EFI_IFR_TYPE_NUM_SIZE_64:
429 *(((UINT64 *) Array) + Index) = (UINT64) Value;
430 break;
431
432 default:
433 break;
434 }
435 }
436
437 /**
438 Check whether this value already in the array, if yes, return the index.
439
440 @param Array The data array.
441 @param Type Type of the data in this array.
442 @param Value The value to be find.
443 @param Index The index in the array which has same value with Value.
444
445 @retval TRUE Found the value in the array.
446 @retval FALSE Not found the value.
447
448 **/
449 BOOLEAN
450 FindArrayData (
451 IN VOID *Array,
452 IN UINT8 Type,
453 IN UINT64 Value,
454 OUT UINTN *Index OPTIONAL
455 )
456 {
457 UINTN Count;
458 UINT64 TmpValue;
459 UINT64 ValueComp;
460
461 ASSERT (Array != NULL);
462
463 Count = 0;
464 TmpValue = 0;
465
466 switch (Type) {
467 case EFI_IFR_TYPE_NUM_SIZE_8:
468 ValueComp = (UINT8) Value;
469 break;
470
471 case EFI_IFR_TYPE_NUM_SIZE_16:
472 ValueComp = (UINT16) Value;
473 break;
474
475 case EFI_IFR_TYPE_NUM_SIZE_32:
476 ValueComp = (UINT32) Value;
477 break;
478
479 case EFI_IFR_TYPE_NUM_SIZE_64:
480 ValueComp = (UINT64) Value;
481 break;
482
483 default:
484 ValueComp = 0;
485 break;
486 }
487
488 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {
489 if (ValueComp == TmpValue) {
490 if (Index != NULL) {
491 *Index = Count;
492 }
493 return TRUE;
494 }
495
496 Count ++;
497 }
498
499 return FALSE;
500 }
501
502 /**
503 Print Question Value according to it's storage width and display attributes.
504
505 @param Question The Question to be printed.
506 @param FormattedNumber Buffer for output string.
507 @param BufferSize The FormattedNumber buffer size in bytes.
508
509 @retval EFI_SUCCESS Print success.
510 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.
511
512 **/
513 EFI_STATUS
514 PrintFormattedNumber (
515 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
516 IN OUT CHAR16 *FormattedNumber,
517 IN UINTN BufferSize
518 )
519 {
520 INT64 Value;
521 CHAR16 *Format;
522 EFI_HII_VALUE *QuestionValue;
523 EFI_IFR_NUMERIC *NumericOp;
524
525 if (BufferSize < (21 * sizeof (CHAR16))) {
526 return EFI_BUFFER_TOO_SMALL;
527 }
528
529 QuestionValue = &Question->CurrentValue;
530 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;
531
532 Value = (INT64) QuestionValue->Value.u64;
533 switch (NumericOp->Flags & EFI_IFR_DISPLAY) {
534 case EFI_IFR_DISPLAY_INT_DEC:
535 switch (QuestionValue->Type) {
536 case EFI_IFR_NUMERIC_SIZE_1:
537 Value = (INT64) ((INT8) QuestionValue->Value.u8);
538 break;
539
540 case EFI_IFR_NUMERIC_SIZE_2:
541 Value = (INT64) ((INT16) QuestionValue->Value.u16);
542 break;
543
544 case EFI_IFR_NUMERIC_SIZE_4:
545 Value = (INT64) ((INT32) QuestionValue->Value.u32);
546 break;
547
548 case EFI_IFR_NUMERIC_SIZE_8:
549 default:
550 break;
551 }
552
553 if (Value < 0) {
554 Value = -Value;
555 Format = L"-%ld";
556 } else {
557 Format = L"%ld";
558 }
559 break;
560
561 case EFI_IFR_DISPLAY_UINT_DEC:
562 Format = L"%ld";
563 break;
564
565 case EFI_IFR_DISPLAY_UINT_HEX:
566 Format = L"%lx";
567 break;
568
569 default:
570 return EFI_UNSUPPORTED;
571 }
572
573 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);
574
575 return EFI_SUCCESS;
576 }
577
578
579 /**
580 Draw a pop up windows based on the dimension, number of lines and
581 strings specified.
582
583 @param RequestedWidth The width of the pop-up.
584 @param NumberOfLines The number of lines.
585 @param Marker The variable argument list for the list of string to be printed.
586
587 **/
588 VOID
589 CreateSharedPopUp (
590 IN UINTN RequestedWidth,
591 IN UINTN NumberOfLines,
592 IN VA_LIST Marker
593 )
594 {
595 UINTN Index;
596 UINTN Count;
597 CHAR16 Character;
598 UINTN Start;
599 UINTN End;
600 UINTN Top;
601 UINTN Bottom;
602 CHAR16 *String;
603 UINTN DimensionsWidth;
604 UINTN DimensionsHeight;
605
606 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
607 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
608
609 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
610
611 if ((RequestedWidth + 2) > DimensionsWidth) {
612 RequestedWidth = DimensionsWidth - 2;
613 }
614
615 //
616 // Subtract the PopUp width from total Columns, allow for one space extra on
617 // each end plus a border.
618 //
619 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;
620 End = Start + RequestedWidth + 1;
621
622 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;
623 Bottom = Top + NumberOfLines + 2;
624
625 Character = BOXDRAW_DOWN_RIGHT;
626 PrintCharAt (Start, Top, Character);
627 Character = BOXDRAW_HORIZONTAL;
628 for (Index = Start; Index + 2 < End; Index++) {
629 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
630 }
631
632 Character = BOXDRAW_DOWN_LEFT;
633 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
634 Character = BOXDRAW_VERTICAL;
635
636 Count = 0;
637 for (Index = Top; Index + 2 < Bottom; Index++, Count++) {
638 String = VA_ARG (Marker, CHAR16*);
639
640 //
641 // This will clear the background of the line - we never know who might have been
642 // here before us. This differs from the next clear in that it used the non-reverse
643 // video for normal printing.
644 //
645 if (GetStringWidth (String) / 2 > 1) {
646 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
647 }
648
649 //
650 // Passing in a space results in the assumption that this is where typing will occur
651 //
652 if (String[0] == L' ') {
653 ClearLines (Start + 1, End - 1, Index + 1, Index + 1, GetPopupInverseColor ());
654 }
655
656 //
657 // Passing in a NULL results in a blank space
658 //
659 if (String[0] == CHAR_NULL) {
660 ClearLines (Start, End, Index + 1, Index + 1, GetPopupColor ());
661 }
662
663 PrintStringAt (
664 ((DimensionsWidth - GetStringWidth (String) / 2) / 2) + gStatementDimensions.LeftColumn + 1,
665 Index + 1,
666 String
667 );
668 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
669 PrintCharAt (Start, Index + 1, Character);
670 PrintCharAt (End - 1, Index + 1, Character);
671 }
672
673 Character = BOXDRAW_UP_RIGHT;
674 PrintCharAt (Start, Bottom - 1, Character);
675 Character = BOXDRAW_HORIZONTAL;
676 for (Index = Start; Index + 2 < End; Index++) {
677 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
678 }
679
680 Character = BOXDRAW_UP_LEFT;
681 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
682 }
683
684 /**
685 Draw a pop up windows based on the dimension, number of lines and
686 strings specified.
687
688 @param RequestedWidth The width of the pop-up.
689 @param NumberOfLines The number of lines.
690 @param ... A series of text strings that displayed in the pop-up.
691
692 **/
693 VOID
694 EFIAPI
695 CreateMultiStringPopUp (
696 IN UINTN RequestedWidth,
697 IN UINTN NumberOfLines,
698 ...
699 )
700 {
701 VA_LIST Marker;
702
703 VA_START (Marker, NumberOfLines);
704
705 CreateSharedPopUp (RequestedWidth, NumberOfLines, Marker);
706
707 VA_END (Marker);
708 }
709
710 /**
711 Process nothing.
712
713 @param Event The Event need to be process
714 @param Context The context of the event.
715
716 **/
717 VOID
718 EFIAPI
719 EmptyEventProcess (
720 IN EFI_EVENT Event,
721 IN VOID *Context
722 )
723 {
724 }
725
726 /**
727 Process for the refresh interval statement.
728
729 @param Event The Event need to be process
730 @param Context The context of the event.
731
732 **/
733 VOID
734 EFIAPI
735 RefreshTimeOutProcess (
736 IN EFI_EVENT Event,
737 IN VOID *Context
738 )
739 {
740 WARNING_IF_CONTEXT *EventInfo;
741 CHAR16 TimeOutString[MAX_TIME_OUT_LEN];
742
743 EventInfo = (WARNING_IF_CONTEXT *) Context;
744
745 if (*(EventInfo->TimeOut) == 0) {
746 gBS->CloseEvent (Event);
747
748 gBS->SignalEvent (EventInfo->SyncEvent);
749 return;
750 }
751
752 UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));
753
754 CreateDialog (NULL, gEmptyString, EventInfo->ErrorInfo, gPressEnter, gEmptyString, TimeOutString, NULL);
755
756 *(EventInfo->TimeOut) -= 1;
757 }
758
759 /**
760 Display error message for invalid password.
761
762 **/
763 VOID
764 PasswordInvalid (
765 VOID
766 )
767 {
768 EFI_INPUT_KEY Key;
769
770 //
771 // Invalid password, prompt error message
772 //
773 do {
774 CreateDialog (&Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString, NULL);
775 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
776 }
777
778 /**
779 Process password op code.
780
781 @param MenuOption The menu for current password op code.
782
783 @retval EFI_SUCCESS Question Option process success.
784 @retval Other Question Option process fail.
785
786 **/
787 EFI_STATUS
788 PasswordProcess (
789 IN UI_MENU_OPTION *MenuOption
790 )
791 {
792 CHAR16 *StringPtr;
793 CHAR16 *TempString;
794 UINTN Maximum;
795 EFI_STATUS Status;
796 EFI_IFR_PASSWORD *PasswordInfo;
797 FORM_DISPLAY_ENGINE_STATEMENT *Question;
798 EFI_INPUT_KEY Key;
799
800 Question = MenuOption->ThisTag;
801 PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;
802 Maximum = PasswordInfo->MaxSize;
803 Status = EFI_SUCCESS;
804
805 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
806 ASSERT (StringPtr);
807
808 //
809 // Use a NULL password to test whether old password is required
810 //
811 *StringPtr = 0;
812 Status = Question->PasswordCheck (gFormData, Question, StringPtr);
813 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {
814 //
815 // Password can't be set now.
816 //
817 if (Status == EFI_UNSUPPORTED) {
818 do {
819 CreateDialog (&Key, gEmptyString, gPasswordUnsupported, gPressEnter, gEmptyString, NULL);
820 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
821 }
822 FreePool (StringPtr);
823 return EFI_SUCCESS;
824 }
825
826 if (EFI_ERROR (Status)) {
827 //
828 // Old password exist, ask user for the old password
829 //
830 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);
831 if (EFI_ERROR (Status)) {
832 FreePool (StringPtr);
833 return Status;
834 }
835
836 //
837 // Check user input old password
838 //
839 Status = Question->PasswordCheck (gFormData, Question, StringPtr);
840 if (EFI_ERROR (Status)) {
841 if (Status == EFI_NOT_READY) {
842 //
843 // Typed in old password incorrect
844 //
845 PasswordInvalid ();
846 } else {
847 Status = EFI_SUCCESS;
848 }
849
850 FreePool (StringPtr);
851 return Status;
852 }
853 }
854
855 //
856 // Ask for new password
857 //
858 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
859 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);
860 if (EFI_ERROR (Status)) {
861 //
862 // Reset state machine for password
863 //
864 Question->PasswordCheck (gFormData, Question, NULL);
865 FreePool (StringPtr);
866 return Status;
867 }
868
869 //
870 // Confirm new password
871 //
872 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));
873 ASSERT (TempString);
874 Status = ReadString (MenuOption, gConfirmPassword, TempString);
875 if (EFI_ERROR (Status)) {
876 //
877 // Reset state machine for password
878 //
879 Question->PasswordCheck (gFormData, Question, NULL);
880 FreePool (StringPtr);
881 FreePool (TempString);
882 return Status;
883 }
884
885 //
886 // Compare two typed-in new passwords
887 //
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);
893
894 Status = EFI_SUCCESS;
895 } else {
896 //
897 // Reset state machine for password
898 //
899 Question->PasswordCheck (gFormData, Question, NULL);
900
901 //
902 // Two password mismatch, prompt error message
903 //
904 do {
905 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);
906 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
907
908 Status = EFI_INVALID_PARAMETER;
909 }
910 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));
911 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));
912 FreePool (TempString);
913 FreePool (StringPtr);
914
915 return Status;
916 }
917
918 /**
919 Process a Question's Option (whether selected or un-selected).
920
921 @param MenuOption The MenuOption for this Question.
922 @param Selected TRUE: if Question is selected.
923 @param OptionString Pointer of the Option String to be displayed.
924 @param SkipErrorValue Whether need to return when value without option for it.
925
926 @retval EFI_SUCCESS Question Option process success.
927 @retval Other Question Option process fail.
928
929 **/
930 EFI_STATUS
931 ProcessOptions (
932 IN UI_MENU_OPTION *MenuOption,
933 IN BOOLEAN Selected,
934 OUT CHAR16 **OptionString,
935 IN BOOLEAN SkipErrorValue
936 )
937 {
938 EFI_STATUS Status;
939 CHAR16 *StringPtr;
940 UINTN Index;
941 FORM_DISPLAY_ENGINE_STATEMENT *Question;
942 CHAR16 FormattedNumber[21];
943 UINT16 Number;
944 CHAR16 Character[2];
945 EFI_INPUT_KEY Key;
946 UINTN BufferSize;
947 DISPLAY_QUESTION_OPTION *OneOfOption;
948 LIST_ENTRY *Link;
949 EFI_HII_VALUE HiiValue;
950 EFI_HII_VALUE *QuestionValue;
951 DISPLAY_QUESTION_OPTION *Option;
952 UINTN Index2;
953 UINT8 *ValueArray;
954 UINT8 ValueType;
955 EFI_IFR_ORDERED_LIST *OrderList;
956 BOOLEAN ValueInvalid;
957 UINTN MaxLen;
958
959 Status = EFI_SUCCESS;
960
961 StringPtr = NULL;
962 Character[1] = L'\0';
963 *OptionString = NULL;
964 ValueInvalid = FALSE;
965
966 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
967 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;
968
969 Question = MenuOption->ThisTag;
970 QuestionValue = &Question->CurrentValue;
971
972 switch (Question->OpCode->OpCode) {
973 case EFI_IFR_ORDERED_LIST_OP:
974
975 //
976 // Check whether there are Options of this OrderedList
977 //
978 if (IsListEmpty (&Question->OptionListHead)) {
979 break;
980 }
981
982 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
983
984 Link = GetFirstNode (&Question->OptionListHead);
985 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
986
987 ValueType = OneOfOption->OptionOpCode->Type;
988 ValueArray = Question->CurrentValue.Buffer;
989
990 if (Selected) {
991 //
992 // Go ask for input
993 //
994 Status = GetSelectionInputPopUp (MenuOption);
995 } else {
996 //
997 // We now know how many strings we will have, so we can allocate the
998 // space required for the array or strings.
999 //
1000 MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);
1001 *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1002 ASSERT (*OptionString);
1003
1004 HiiValue.Type = ValueType;
1005 HiiValue.Value.u64 = 0;
1006 for (Index = 0; Index < OrderList->MaxContainers; Index++) {
1007 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1008 if (HiiValue.Value.u64 == 0) {
1009 //
1010 // Values for the options in ordered lists should never be a 0
1011 //
1012 break;
1013 }
1014
1015 OneOfOption = ValueToOption (Question, &HiiValue);
1016 if (OneOfOption == NULL) {
1017 if (SkipErrorValue) {
1018 //
1019 // Just try to get the option string, skip the value which not has option.
1020 //
1021 continue;
1022 }
1023
1024 //
1025 // Show error message
1026 //
1027 do {
1028 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1029 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1030
1031 //
1032 // The initial value of the orderedlist is invalid, force to be valid value
1033 // Exit current DisplayForm with new value.
1034 //
1035 gUserInput->SelectedStatement = Question;
1036 gMisMatch = TRUE;
1037 ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);
1038 ASSERT (ValueArray != NULL);
1039 gUserInput->InputValue.Buffer = ValueArray;
1040 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1041 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1042
1043 Link = GetFirstNode (&Question->OptionListHead);
1044 Index2 = 0;
1045 while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {
1046 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1047 Link = GetNextNode (&Question->OptionListHead, Link);
1048 SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);
1049 Index2++;
1050 }
1051 SetArrayData (ValueArray, ValueType, Index2, 0);
1052
1053 FreePool (*OptionString);
1054 *OptionString = NULL;
1055 return EFI_NOT_FOUND;
1056 }
1057
1058 Character[0] = LEFT_ONEOF_DELIMITER;
1059 NewStrCat (OptionString[0], MaxLen, Character);
1060 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1061 ASSERT (StringPtr != NULL);
1062 NewStrCat (OptionString[0], MaxLen, StringPtr);
1063 Character[0] = RIGHT_ONEOF_DELIMITER;
1064 NewStrCat (OptionString[0], MaxLen, Character);
1065 Character[0] = CHAR_CARRIAGE_RETURN;
1066 NewStrCat (OptionString[0], MaxLen, Character);
1067 FreePool (StringPtr);
1068 }
1069
1070 //
1071 // If valid option more than the max container, skip these options.
1072 //
1073 if (Index >= OrderList->MaxContainers) {
1074 break;
1075 }
1076
1077 //
1078 // Search the other options, try to find the one not in the container.
1079 //
1080 Link = GetFirstNode (&Question->OptionListHead);
1081 while (!IsNull (&Question->OptionListHead, Link)) {
1082 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1083 Link = GetNextNode (&Question->OptionListHead, Link);
1084
1085 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {
1086 continue;
1087 }
1088
1089 if (SkipErrorValue) {
1090 //
1091 // Not report error, just get the correct option string info.
1092 //
1093 Character[0] = LEFT_ONEOF_DELIMITER;
1094 NewStrCat (OptionString[0], MaxLen, Character);
1095 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1096 ASSERT (StringPtr != NULL);
1097 NewStrCat (OptionString[0], MaxLen, StringPtr);
1098 Character[0] = RIGHT_ONEOF_DELIMITER;
1099 NewStrCat (OptionString[0], MaxLen, Character);
1100 Character[0] = CHAR_CARRIAGE_RETURN;
1101 NewStrCat (OptionString[0], MaxLen, Character);
1102 FreePool (StringPtr);
1103
1104 continue;
1105 }
1106
1107 if (!ValueInvalid) {
1108 ValueInvalid = TRUE;
1109 //
1110 // Show error message
1111 //
1112 do {
1113 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1114 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1115
1116 //
1117 // The initial value of the orderedlist is invalid, force to be valid value
1118 // Exit current DisplayForm with new value.
1119 //
1120 gUserInput->SelectedStatement = Question;
1121 gMisMatch = TRUE;
1122 ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);
1123 ASSERT (ValueArray != NULL);
1124 gUserInput->InputValue.Buffer = ValueArray;
1125 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1126 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1127 }
1128
1129 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);
1130 }
1131
1132 if (ValueInvalid) {
1133 FreePool (*OptionString);
1134 *OptionString = NULL;
1135 return EFI_NOT_FOUND;
1136 }
1137 }
1138 break;
1139
1140 case EFI_IFR_ONE_OF_OP:
1141 //
1142 // Check whether there are Options of this OneOf
1143 //
1144 if (IsListEmpty (&Question->OptionListHead)) {
1145 break;
1146 }
1147 if (Selected) {
1148 //
1149 // Go ask for input
1150 //
1151 Status = GetSelectionInputPopUp (MenuOption);
1152 } else {
1153 MaxLen = BufferSize / sizeof(CHAR16);
1154 *OptionString = AllocateZeroPool (BufferSize);
1155 ASSERT (*OptionString);
1156
1157 OneOfOption = ValueToOption (Question, QuestionValue);
1158 if (OneOfOption == NULL) {
1159 if (SkipErrorValue) {
1160 //
1161 // Not report error, just get the correct option string info.
1162 //
1163 Link = GetFirstNode (&Question->OptionListHead);
1164 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1165 } else {
1166 //
1167 // Show error message
1168 //
1169 do {
1170 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);
1171 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
1172
1173 //
1174 // Force the Question value to be valid
1175 // Exit current DisplayForm with new value.
1176 //
1177 Link = GetFirstNode (&Question->OptionListHead);
1178 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1179
1180 gUserInput->InputValue.Type = Option->OptionOpCode->Type;
1181 switch (gUserInput->InputValue.Type) {
1182 case EFI_IFR_TYPE_NUM_SIZE_8:
1183 gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;
1184 break;
1185 case EFI_IFR_TYPE_NUM_SIZE_16:
1186 CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));
1187 break;
1188 case EFI_IFR_TYPE_NUM_SIZE_32:
1189 CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));
1190 break;
1191 case EFI_IFR_TYPE_NUM_SIZE_64:
1192 CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));
1193 break;
1194 default:
1195 ASSERT (FALSE);
1196 break;
1197 }
1198 gUserInput->SelectedStatement = Question;
1199 gMisMatch = TRUE;
1200 FreePool (*OptionString);
1201 *OptionString = NULL;
1202 return EFI_NOT_FOUND;
1203 }
1204 }
1205
1206 Character[0] = LEFT_ONEOF_DELIMITER;
1207 NewStrCat (OptionString[0], MaxLen, Character);
1208 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1209 ASSERT (StringPtr != NULL);
1210 NewStrCat (OptionString[0], MaxLen, StringPtr);
1211 Character[0] = RIGHT_ONEOF_DELIMITER;
1212 NewStrCat (OptionString[0], MaxLen, Character);
1213
1214 FreePool (StringPtr);
1215 }
1216 break;
1217
1218 case EFI_IFR_CHECKBOX_OP:
1219 if (Selected) {
1220 //
1221 // Since this is a BOOLEAN operation, flip it upon selection
1222 //
1223 gUserInput->InputValue.Type = QuestionValue->Type;
1224 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);
1225
1226 //
1227 // Perform inconsistent check
1228 //
1229 return EFI_SUCCESS;
1230 } else {
1231 *OptionString = AllocateZeroPool (BufferSize);
1232 ASSERT (*OptionString);
1233
1234 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;
1235
1236 if (QuestionValue->Value.b) {
1237 *(OptionString[0] + 1) = CHECK_ON;
1238 } else {
1239 *(OptionString[0] + 1) = CHECK_OFF;
1240 }
1241 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;
1242 }
1243 break;
1244
1245 case EFI_IFR_NUMERIC_OP:
1246 if (Selected) {
1247 //
1248 // Go ask for input
1249 //
1250 Status = GetNumericInput (MenuOption);
1251 } else {
1252 *OptionString = AllocateZeroPool (BufferSize);
1253 ASSERT (*OptionString);
1254
1255 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1256
1257 //
1258 // Formatted print
1259 //
1260 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
1261 Number = (UINT16) GetStringWidth (FormattedNumber);
1262 CopyMem (OptionString[0] + 1, FormattedNumber, Number);
1263
1264 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;
1265 }
1266 break;
1267
1268 case EFI_IFR_DATE_OP:
1269 if (Selected) {
1270 //
1271 // This is similar to numerics
1272 //
1273 Status = GetNumericInput (MenuOption);
1274 } else {
1275 *OptionString = AllocateZeroPool (BufferSize);
1276 ASSERT (*OptionString);
1277
1278 switch (MenuOption->Sequence) {
1279 case 0:
1280 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1281 if (QuestionValue->Value.date.Month == 0xff){
1282 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1283 } else {
1284 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);
1285 }
1286 *(OptionString[0] + 3) = DATE_SEPARATOR;
1287 break;
1288
1289 case 1:
1290 SetUnicodeMem (OptionString[0], 4, L' ');
1291 if (QuestionValue->Value.date.Day == 0xff){
1292 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1293 } else {
1294 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);
1295 }
1296 *(OptionString[0] + 6) = DATE_SEPARATOR;
1297 break;
1298
1299 case 2:
1300 SetUnicodeMem (OptionString[0], 7, L' ');
1301 if (QuestionValue->Value.date.Year == 0xff){
1302 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");
1303 } else {
1304 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);
1305 }
1306 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;
1307 break;
1308 }
1309 }
1310 break;
1311
1312 case EFI_IFR_TIME_OP:
1313 if (Selected) {
1314 //
1315 // This is similar to numerics
1316 //
1317 Status = GetNumericInput (MenuOption);
1318 } else {
1319 *OptionString = AllocateZeroPool (BufferSize);
1320 ASSERT (*OptionString);
1321
1322 switch (MenuOption->Sequence) {
1323 case 0:
1324 *OptionString[0] = LEFT_NUMERIC_DELIMITER;
1325 if (QuestionValue->Value.time.Hour == 0xff){
1326 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");
1327 } else {
1328 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);
1329 }
1330 *(OptionString[0] + 3) = TIME_SEPARATOR;
1331 break;
1332
1333 case 1:
1334 SetUnicodeMem (OptionString[0], 4, L' ');
1335 if (QuestionValue->Value.time.Minute == 0xff){
1336 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");
1337 } else {
1338 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);
1339 }
1340 *(OptionString[0] + 6) = TIME_SEPARATOR;
1341 break;
1342
1343 case 2:
1344 SetUnicodeMem (OptionString[0], 7, L' ');
1345 if (QuestionValue->Value.time.Second == 0xff){
1346 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");
1347 } else {
1348 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);
1349 }
1350 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;
1351 break;
1352 }
1353 }
1354 break;
1355
1356 case EFI_IFR_STRING_OP:
1357 if (Selected) {
1358 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));
1359 ASSERT (StringPtr);
1360 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);
1361
1362 Status = ReadString (MenuOption, gPromptForData, StringPtr);
1363 if (EFI_ERROR (Status)) {
1364 FreePool (StringPtr);
1365 return Status;
1366 }
1367
1368 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);
1369 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1370 gUserInput->InputValue.Type = Question->CurrentValue.Type;
1371 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);
1372 FreePool (StringPtr);
1373 return EFI_SUCCESS;
1374 } else {
1375 *OptionString = AllocateZeroPool (BufferSize);
1376 ASSERT (*OptionString);
1377
1378 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {
1379 *(OptionString[0]) = '_';
1380 } else {
1381 if (Question->CurrentValue.BufferLen < BufferSize) {
1382 BufferSize = Question->CurrentValue.BufferLen;
1383 }
1384 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);
1385 }
1386 }
1387 break;
1388
1389 case EFI_IFR_PASSWORD_OP:
1390 if (Selected) {
1391 Status = PasswordProcess (MenuOption);
1392 }
1393 break;
1394
1395 default:
1396 break;
1397 }
1398
1399 return Status;
1400 }
1401
1402
1403 /**
1404 Process the help string: Split StringPtr to several lines of strings stored in
1405 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.
1406
1407 @param StringPtr The entire help string.
1408 @param FormattedString The oupput formatted string.
1409 @param EachLineWidth The max string length of each line in the formatted string.
1410 @param RowCount TRUE: if Question is selected.
1411
1412 **/
1413 UINTN
1414 ProcessHelpString (
1415 IN CHAR16 *StringPtr,
1416 OUT CHAR16 **FormattedString,
1417 OUT UINT16 *EachLineWidth,
1418 IN UINTN RowCount
1419 )
1420 {
1421 UINTN Index;
1422 CHAR16 *OutputString;
1423 UINTN TotalRowNum;
1424 UINTN CheckedNum;
1425 UINT16 GlyphWidth;
1426 UINT16 LineWidth;
1427 UINT16 MaxStringLen;
1428 UINT16 StringLen;
1429
1430 TotalRowNum = 0;
1431 CheckedNum = 0;
1432 GlyphWidth = 1;
1433 Index = 0;
1434 MaxStringLen = 0;
1435 StringLen = 0;
1436
1437 //
1438 // Set default help string width.
1439 //
1440 LineWidth = (UINT16) (gHelpBlockWidth - 1);
1441
1442 //
1443 // Get row number of the String.
1444 //
1445 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1446 if (StringLen > MaxStringLen) {
1447 MaxStringLen = StringLen;
1448 }
1449
1450 TotalRowNum ++;
1451 FreePool (OutputString);
1452 }
1453 *EachLineWidth = MaxStringLen;
1454
1455 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));
1456 ASSERT (*FormattedString != NULL);
1457
1458 //
1459 // Generate formatted help string array.
1460 //
1461 GlyphWidth = 1;
1462 Index = 0;
1463 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {
1464 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));
1465 CheckedNum ++;
1466 FreePool (OutputString);
1467 }
1468
1469 return TotalRowNum;
1470 }