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