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