]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/ProcessOptions.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[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
25 IN OUT CHAR16 *Destination,\r
5ad66ec6 26 IN UINTN DestMax,\r
7c6c064c
ED
27 IN CHAR16 *Source\r
28 )\r
29{\r
30 UINTN Length;\r
31\r
32 for (Length = 0; Destination[Length] != 0; Length++)\r
33 ;\r
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
57 IN EFI_HII_VALUE *Value\r
58 )\r
59{\r
60 UINT64 RetVal;\r
61\r
62 RetVal = 0;\r
63\r
64 switch (Value->Type) {\r
65 case EFI_IFR_TYPE_NUM_SIZE_8:\r
66 RetVal = Value->Value.u8;\r
67 break;\r
68\r
69 case EFI_IFR_TYPE_NUM_SIZE_16:\r
70 RetVal = Value->Value.u16;\r
71 break;\r
72\r
73 case EFI_IFR_TYPE_NUM_SIZE_32:\r
74 RetVal = Value->Value.u32;\r
75 break;\r
76\r
77 case EFI_IFR_TYPE_BOOLEAN:\r
78 RetVal = Value->Value.b;\r
79 break;\r
80\r
81 case EFI_IFR_TYPE_DATE:\r
82 RetVal = *(UINT64*) &Value->Value.date;\r
83 break;\r
84\r
85 case EFI_IFR_TYPE_TIME:\r
86 RetVal = (*(UINT64*) &Value->Value.time) & 0xffffff;\r
87 break;\r
88\r
89 default:\r
90 RetVal = Value->Value.u64;\r
91 break;\r
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
111 IN EFI_HII_VALUE *Value\r
112 )\r
113{\r
114 switch (Value->Type) {\r
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
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
137 IN EFI_HII_VALUE *Value\r
138 )\r
139{\r
140 switch (Value->Type) {\r
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
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
166 IN EFI_HII_VALUE *Value,\r
167 OUT UINT8 **Buf,\r
168 OUT UINT16 *BufLen\r
169 )\r
170{\r
171 switch (Value->Type) {\r
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
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
40578d09 230 if (Value1->Type == EFI_IFR_TYPE_STRING && Value2->Type == EFI_IFR_TYPE_STRING) {\r
7c6c064c
ED
231 if (Value1->Value.string == 0 || Value2->Value.string == 0) {\r
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
268 if (IsTypeInBuffer(Value1) && IsTypeInBuffer(Value2)) {\r
269 GetBufAndLenForValue(Value1, &Buf1, &Buf1Len);\r
270 GetBufAndLenForValue(Value2, &Buf2, &Buf2Len);\r
271\r
272 Len = Buf1Len > Buf2Len ? Buf2Len : Buf1Len;\r
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
ED
280 }\r
281 return EFI_SUCCESS;\r
d1102dba 282 }\r
7c6c064c
ED
283\r
284 //\r
285 // Take remain types(integer, boolean, date/time) as integer\r
286 //\r
40578d09
ED
287 if (IsTypeInUINT64(Value1) && IsTypeInUINT64(Value2)) {\r
288 Temp64 = HiiValueToUINT64(Value1) - HiiValueToUINT64(Value2);\r
289 if (Temp64 > 0) {\r
290 *Result = 1;\r
291 } else if (Temp64 < 0) {\r
292 *Result = -1;\r
293 } else {\r
294 *Result = 0;\r
295 }\r
296 return EFI_SUCCESS;\r
7c6c064c
ED
297 }\r
298\r
40578d09 299 return EFI_UNSUPPORTED;\r
7c6c064c
ED
300}\r
301\r
302/**\r
303 Search an Option of a Question by its value.\r
304\r
305 @param Question The Question\r
306 @param OptionValue Value for Option to be searched.\r
307\r
308 @retval Pointer Pointer to the found Option.\r
309 @retval NULL Option not found.\r
310\r
311**/\r
312DISPLAY_QUESTION_OPTION *\r
313ValueToOption (\r
314 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
315 IN EFI_HII_VALUE *OptionValue\r
316 )\r
317{\r
318 LIST_ENTRY *Link;\r
319 DISPLAY_QUESTION_OPTION *Option;\r
320 INTN Result;\r
321 EFI_HII_VALUE Value;\r
322\r
323 Link = GetFirstNode (&Question->OptionListHead);\r
324 while (!IsNull (&Question->OptionListHead, Link)) {\r
325 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
326\r
327 ZeroMem (&Value, sizeof (EFI_HII_VALUE));\r
328 Value.Type = Option->OptionOpCode->Type;\r
329 CopyMem (&Value.Value, &Option->OptionOpCode->Value, Option->OptionOpCode->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));\r
d1102dba 330\r
7c6c064c
ED
331 if ((CompareHiiValue (&Value, OptionValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
332 return Option;\r
333 }\r
334\r
335 Link = GetNextNode (&Question->OptionListHead, Link);\r
336 }\r
337\r
338 return NULL;\r
339}\r
340\r
341\r
342/**\r
343 Return data element in an Array by its Index.\r
344\r
345 @param Array The data array.\r
346 @param Type Type of the data in this array.\r
347 @param Index Zero based index for data in this array.\r
348\r
349 @retval Value The data to be returned\r
350\r
351**/\r
352UINT64\r
353GetArrayData (\r
354 IN VOID *Array,\r
355 IN UINT8 Type,\r
356 IN UINTN Index\r
357 )\r
358{\r
359 UINT64 Data;\r
360\r
361 ASSERT (Array != NULL);\r
362\r
363 Data = 0;\r
364 switch (Type) {\r
365 case EFI_IFR_TYPE_NUM_SIZE_8:\r
366 Data = (UINT64) *(((UINT8 *) Array) + Index);\r
367 break;\r
368\r
369 case EFI_IFR_TYPE_NUM_SIZE_16:\r
370 Data = (UINT64) *(((UINT16 *) Array) + Index);\r
371 break;\r
372\r
373 case EFI_IFR_TYPE_NUM_SIZE_32:\r
374 Data = (UINT64) *(((UINT32 *) Array) + Index);\r
375 break;\r
376\r
377 case EFI_IFR_TYPE_NUM_SIZE_64:\r
378 Data = (UINT64) *(((UINT64 *) Array) + Index);\r
379 break;\r
380\r
381 default:\r
382 break;\r
383 }\r
384\r
385 return Data;\r
386}\r
387\r
388\r
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
400 IN VOID *Array,\r
401 IN UINT8 Type,\r
402 IN UINTN Index,\r
403 IN UINT64 Value\r
404 )\r
405{\r
406\r
407 ASSERT (Array != NULL);\r
408\r
409 switch (Type) {\r
410 case EFI_IFR_TYPE_NUM_SIZE_8:\r
411 *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
412 break;\r
413\r
414 case EFI_IFR_TYPE_NUM_SIZE_16:\r
415 *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
416 break;\r
417\r
418 case EFI_IFR_TYPE_NUM_SIZE_32:\r
419 *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
420 break;\r
421\r
422 case EFI_IFR_TYPE_NUM_SIZE_64:\r
423 *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
424 break;\r
425\r
426 default:\r
427 break;\r
428 }\r
429}\r
430\r
431/**\r
432 Check whether this value already in the array, if yes, return the index.\r
433\r
434 @param Array The data array.\r
435 @param Type Type of the data in this array.\r
436 @param Value The value to be find.\r
437 @param Index The index in the array which has same value with Value.\r
d1102dba 438\r
7c6c064c
ED
439 @retval TRUE Found the value in the array.\r
440 @retval FALSE Not found the value.\r
441\r
442**/\r
d1102dba 443BOOLEAN\r
7c6c064c
ED
444FindArrayData (\r
445 IN VOID *Array,\r
446 IN UINT8 Type,\r
447 IN UINT64 Value,\r
448 OUT UINTN *Index OPTIONAL\r
449 )\r
450{\r
451 UINTN Count;\r
452 UINT64 TmpValue;\r
453 UINT64 ValueComp;\r
d1102dba 454\r
7c6c064c
ED
455 ASSERT (Array != NULL);\r
456\r
457 Count = 0;\r
458 TmpValue = 0;\r
459\r
460 switch (Type) {\r
461 case EFI_IFR_TYPE_NUM_SIZE_8:\r
462 ValueComp = (UINT8) Value;\r
463 break;\r
464\r
465 case EFI_IFR_TYPE_NUM_SIZE_16:\r
466 ValueComp = (UINT16) Value;\r
467 break;\r
468\r
469 case EFI_IFR_TYPE_NUM_SIZE_32:\r
470 ValueComp = (UINT32) Value;\r
471 break;\r
472\r
473 case EFI_IFR_TYPE_NUM_SIZE_64:\r
474 ValueComp = (UINT64) Value;\r
475 break;\r
476\r
477 default:\r
478 ValueComp = 0;\r
479 break;\r
480 }\r
481\r
482 while ((TmpValue = GetArrayData (Array, Type, Count)) != 0) {\r
483 if (ValueComp == TmpValue) {\r
484 if (Index != NULL) {\r
485 *Index = Count;\r
486 }\r
487 return TRUE;\r
488 }\r
489\r
490 Count ++;\r
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
509 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
510 IN OUT CHAR16 *FormattedNumber,\r
511 IN UINTN BufferSize\r
512 )\r
513{\r
514 INT64 Value;\r
515 CHAR16 *Format;\r
516 EFI_HII_VALUE *QuestionValue;\r
517 EFI_IFR_NUMERIC *NumericOp;\r
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
524 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;\r
525\r
526 Value = (INT64) QuestionValue->Value.u64;\r
527 switch (NumericOp->Flags & EFI_IFR_DISPLAY) {\r
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
533\r
534 case EFI_IFR_NUMERIC_SIZE_2:\r
535 Value = (INT64) ((INT16) QuestionValue->Value.u16);\r
536 break;\r
537\r
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
553 break;\r
554\r
555 case EFI_IFR_DISPLAY_UINT_DEC:\r
556 Format = L"%ld";\r
557 break;\r
558\r
559 case EFI_IFR_DISPLAY_UINT_HEX:\r
560 Format = L"%lx";\r
561 break;\r
562\r
563 default:\r
564 return EFI_UNSUPPORTED;\r
7c6c064c
ED
565 }\r
566\r
567 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);\r
568\r
569 return EFI_SUCCESS;\r
570}\r
571\r
572\r
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
584 IN UINTN RequestedWidth,\r
585 IN UINTN NumberOfLines,\r
586 IN VA_LIST Marker\r
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
600 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
601 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
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
613 Start = (DimensionsWidth - RequestedWidth - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
614 End = Start + RequestedWidth + 1;\r
615\r
616 Top = ((DimensionsHeight - NumberOfLines - 2) / 2) + gStatementDimensions.TopRow - 1;\r
617 Bottom = Top + NumberOfLines + 2;\r
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
632 String = VA_ARG (Marker, CHAR16*);\r
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
690 IN UINTN RequestedWidth,\r
691 IN UINTN NumberOfLines,\r
692 ...\r
693 )\r
694{\r
695 VA_LIST Marker;\r
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
714 IN EFI_EVENT Event,\r
715 IN VOID *Context\r
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
730 IN EFI_EVENT Event,\r
731 IN VOID *Context\r
732 )\r
733{\r
734 WARNING_IF_CONTEXT *EventInfo;\r
735 CHAR16 TimeOutString[MAX_TIME_OUT_LEN];\r
736\r
737 EventInfo = (WARNING_IF_CONTEXT *) Context;\r
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
746 UnicodeSPrint(TimeOutString, MAX_TIME_OUT_LEN, L"%d", *(EventInfo->TimeOut));\r
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
783 IN UI_MENU_OPTION *MenuOption\r
784 )\r
785{\r
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
793\r
794 Question = MenuOption->ThisTag;\r
795 PasswordInfo = (EFI_IFR_PASSWORD *) Question->OpCode;\r
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
806 Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
807 if (Status == EFI_NOT_AVAILABLE_YET || Status == EFI_UNSUPPORTED) {\r
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
7c6c064c
ED
816 FreePool (StringPtr);\r
817 return EFI_SUCCESS;\r
818 }\r
819\r
820 if (EFI_ERROR (Status)) {\r
821 //\r
822 // Old password exist, ask user for the old password\r
823 //\r
824 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
825 if (EFI_ERROR (Status)) {\r
f1d78c48 826 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
827 FreePool (StringPtr);\r
828 return Status;\r
829 }\r
830\r
831 //\r
832 // Check user input old password\r
833 //\r
834 Status = Question->PasswordCheck (gFormData, Question, StringPtr);\r
835 if (EFI_ERROR (Status)) {\r
836 if (Status == EFI_NOT_READY) {\r
837 //\r
838 // Typed in old password incorrect\r
839 //\r
840 PasswordInvalid ();\r
841 } else {\r
842 Status = EFI_SUCCESS;\r
843 }\r
f1d78c48 844 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
845 FreePool (StringPtr);\r
846 return Status;\r
847 }\r
848 }\r
d1102dba 849\r
7c6c064c
ED
850 //\r
851 // Ask for new password\r
852 //\r
853 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
854 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
855 if (EFI_ERROR (Status)) {\r
856 //\r
857 // Reset state machine for password\r
858 //\r
859 Question->PasswordCheck (gFormData, Question, NULL);\r
f1d78c48 860 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
861 FreePool (StringPtr);\r
862 return Status;\r
863 }\r
d1102dba 864\r
7c6c064c
ED
865 //\r
866 // Confirm new password\r
867 //\r
868 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
869 ASSERT (TempString);\r
870 Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
871 if (EFI_ERROR (Status)) {\r
872 //\r
873 // Reset state machine for password\r
874 //\r
875 Question->PasswordCheck (gFormData, Question, NULL);\r
f1d78c48
DB
876 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
877 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
878 FreePool (StringPtr);\r
879 FreePool (TempString);\r
880 return Status;\r
881 }\r
d1102dba 882\r
7c6c064c
ED
883 //\r
884 // Compare two typed-in new passwords\r
885 //\r
d1102dba 886 if (StrCmp (StringPtr, TempString) == 0) {\r
7c6c064c
ED
887 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
888 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
889 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
890 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
7c6c064c 891\r
bfae1330 892 Status = EFI_SUCCESS;\r
7c6c064c
ED
893 } else {\r
894 //\r
895 // Reset state machine for password\r
896 //\r
897 Question->PasswordCheck (gFormData, Question, NULL);\r
d1102dba 898\r
7c6c064c
ED
899 //\r
900 // Two password mismatch, prompt error message\r
901 //\r
902 do {\r
903 CreateDialog (&Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString, NULL);\r
904 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
905\r
906 Status = EFI_INVALID_PARAMETER;\r
907 }\r
a275df8f
DB
908 ZeroMem (TempString, (Maximum + 1) * sizeof (CHAR16));\r
909 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
7c6c064c
ED
910 FreePool (TempString);\r
911 FreePool (StringPtr);\r
912\r
913 return Status;\r
914}\r
915\r
1da651cd
DB
916/**\r
917 Print some debug message about mismatched menu info.\r
918\r
919 @param MenuOption The MenuOption for this Question.\r
920\r
921**/\r
922VOID\r
923PrintMismatchMenuInfo (\r
924 IN UI_MENU_OPTION *MenuOption\r
925)\r
926{\r
927 CHAR16 *FormTitleStr;\r
928 CHAR16 *FormSetTitleStr;\r
929 CHAR16 *OneOfOptionStr;\r
930 CHAR16 *QuestionName;\r
931 LIST_ENTRY *Link;\r
932 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
933 EFI_IFR_ORDERED_LIST *OrderList;\r
934 UINT8 Index;\r
935 EFI_HII_VALUE HiiValue;\r
936 EFI_HII_VALUE *QuestionValue;\r
937 DISPLAY_QUESTION_OPTION *Option;\r
938 UINT8 *ValueArray;\r
939 UINT8 ValueType;\r
940 EFI_IFR_FORM_SET *FormsetBuffer;\r
941 UINTN FormsetBufferSize;\r
942\r
943 Question = MenuOption->ThisTag;\r
944 HiiGetFormSetFromHiiHandle (gFormData->HiiHandle, &FormsetBuffer, &FormsetBufferSize);\r
945\r
946 FormSetTitleStr = GetToken (FormsetBuffer->FormSetTitle, gFormData->HiiHandle);\r
947 FormTitleStr = GetToken (gFormData->FormTitle, gFormData->HiiHandle);\r
948\r
949 DEBUG ((DEBUG_ERROR, "\n[%a]: Mismatch Formset : Formset Guid = %g, FormSet title = %s\n", gEfiCallerBaseName, &gFormData->FormSetGuid, FormSetTitleStr));\r
950 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Form : FormId = %d, Form title = %s.\n", gEfiCallerBaseName, gFormData->FormId, FormTitleStr));\r
951\r
952 if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
953 QuestionName = GetToken (((EFI_IFR_ORDERED_LIST*)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);\r
954 Link = GetFirstNode (&Question->OptionListHead);\r
955 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
956 ValueType = Option->OptionOpCode->Type;\r
957 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OrderedList value in the array doesn't match with option value.\n", gEfiCallerBaseName));\r
958 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: Name = %s.\n", gEfiCallerBaseName, QuestionName));\r
959 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OrderedList: OrderedList array value :\n", gEfiCallerBaseName));\r
960\r
961 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
962 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
963 ValueArray = Question->CurrentValue.Buffer;\r
964 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
965 DEBUG ((DEBUG_ERROR, " Value[%d] =%ld.\n", Index, HiiValue.Value.u64));\r
966 }\r
967 } else if (Question->OpCode->OpCode == EFI_IFR_ONE_OF_OP) {\r
968 QuestionName = GetToken (((EFI_IFR_ONE_OF*)MenuOption->ThisTag->OpCode)->Question.Header.Prompt, gFormData->HiiHandle);\r
969 QuestionValue = &Question->CurrentValue;\r
970 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch Error : OneOf value doesn't match with option value.\n", gEfiCallerBaseName));\r
971 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : Name = %s.\n", gEfiCallerBaseName, QuestionName));\r
972 switch (QuestionValue->Type) {\r
973 case EFI_IFR_TYPE_NUM_SIZE_64:\r
974 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %ld.\n",gEfiCallerBaseName, QuestionValue->Value.u64));\r
975 break;\r
976\r
977 case EFI_IFR_TYPE_NUM_SIZE_32:\r
978 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u32));\r
979 break;\r
980\r
981 case EFI_IFR_TYPE_NUM_SIZE_16:\r
982 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u16));\r
983 break;\r
984\r
985 case EFI_IFR_TYPE_NUM_SIZE_8:\r
986 DEBUG ((DEBUG_ERROR, "[%a]: Mismatch OneOf : OneOf value = %d.\n",gEfiCallerBaseName, QuestionValue->Value.u8));\r
987 break;\r
988\r
989 default:\r
990 ASSERT (FALSE);\r
991 break;\r
992 }\r
993 }\r
994\r
995 Index = 0;\r
996 Link = GetFirstNode (&Question->OptionListHead);\r
997 while (!IsNull (&Question->OptionListHead, Link)) {\r
998 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
999 OneOfOptionStr = GetToken (Option->OptionOpCode->Option, gFormData->HiiHandle);\r
1000 switch (Option->OptionOpCode->Type) {\r
1001 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1002 DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %ld, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u64, OneOfOptionStr));\r
1003 break;\r
1004\r
1005 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1006 DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u32, OneOfOptionStr));\r
1007 break;\r
1008\r
1009 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1010 DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u16, OneOfOptionStr));\r
1011 break;\r
1012\r
1013 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1014 DEBUG ((DEBUG_ERROR, "[%a]: Option %d : Option Value = %d, Option Name = %s.\n",gEfiCallerBaseName, Index, Option->OptionOpCode->Value.u8, OneOfOptionStr));\r
1015 break;\r
1016\r
1017 default:\r
1018 ASSERT (FALSE);\r
1019 break;\r
1020 }\r
1021 Link = GetNextNode (&Question->OptionListHead, Link);\r
1022 Index++;\r
1023 }\r
1024}\r
1025\r
7c6c064c
ED
1026/**\r
1027 Process a Question's Option (whether selected or un-selected).\r
1028\r
1029 @param MenuOption The MenuOption for this Question.\r
1030 @param Selected TRUE: if Question is selected.\r
1031 @param OptionString Pointer of the Option String to be displayed.\r
1032 @param SkipErrorValue Whether need to return when value without option for it.\r
1033\r
1034 @retval EFI_SUCCESS Question Option process success.\r
1035 @retval Other Question Option process fail.\r
1036\r
1037**/\r
1038EFI_STATUS\r
1039ProcessOptions (\r
1040 IN UI_MENU_OPTION *MenuOption,\r
1041 IN BOOLEAN Selected,\r
1042 OUT CHAR16 **OptionString,\r
1043 IN BOOLEAN SkipErrorValue\r
1044 )\r
1045{\r
1046 EFI_STATUS Status;\r
1047 CHAR16 *StringPtr;\r
1048 UINTN Index;\r
1049 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
1050 CHAR16 FormattedNumber[21];\r
1051 UINT16 Number;\r
1052 CHAR16 Character[2];\r
1053 EFI_INPUT_KEY Key;\r
1054 UINTN BufferSize;\r
1055 DISPLAY_QUESTION_OPTION *OneOfOption;\r
1056 LIST_ENTRY *Link;\r
1057 EFI_HII_VALUE HiiValue;\r
1058 EFI_HII_VALUE *QuestionValue;\r
1059 DISPLAY_QUESTION_OPTION *Option;\r
1060 UINTN Index2;\r
1061 UINT8 *ValueArray;\r
1062 UINT8 ValueType;\r
7c6c064c
ED
1063 EFI_IFR_ORDERED_LIST *OrderList;\r
1064 BOOLEAN ValueInvalid;\r
5ad66ec6 1065 UINTN MaxLen;\r
7c6c064c
ED
1066\r
1067 Status = EFI_SUCCESS;\r
1068\r
1069 StringPtr = NULL;\r
1070 Character[1] = L'\0';\r
1071 *OptionString = NULL;\r
7c6c064c
ED
1072 ValueInvalid = FALSE;\r
1073\r
1074 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
1075 BufferSize = (gOptionBlockWidth + 1) * 2 * gStatementDimensions.BottomRow;\r
1076\r
1077 Question = MenuOption->ThisTag;\r
1078 QuestionValue = &Question->CurrentValue;\r
1079\r
1080 switch (Question->OpCode->OpCode) {\r
1081 case EFI_IFR_ORDERED_LIST_OP:\r
1082\r
1083 //\r
1084 // Check whether there are Options of this OrderedList\r
1085 //\r
1086 if (IsListEmpty (&Question->OptionListHead)) {\r
1087 break;\r
1088 }\r
1089\r
1090 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
1091\r
1092 Link = GetFirstNode (&Question->OptionListHead);\r
1093 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1094\r
1095 ValueType = OneOfOption->OptionOpCode->Type;\r
1096 ValueArray = Question->CurrentValue.Buffer;\r
1097\r
1098 if (Selected) {\r
1099 //\r
1100 // Go ask for input\r
1101 //\r
1102 Status = GetSelectionInputPopUp (MenuOption);\r
1103 } else {\r
1104 //\r
1105 // We now know how many strings we will have, so we can allocate the\r
1106 // space required for the array or strings.\r
1107 //\r
5ad66ec6
DB
1108 MaxLen = OrderList->MaxContainers * BufferSize / sizeof (CHAR16);\r
1109 *OptionString = AllocateZeroPool (MaxLen * sizeof (CHAR16));\r
7c6c064c
ED
1110 ASSERT (*OptionString);\r
1111\r
1112 HiiValue.Type = ValueType;\r
1113 HiiValue.Value.u64 = 0;\r
1114 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
1115 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1116 if (HiiValue.Value.u64 == 0) {\r
1117 //\r
1118 // Values for the options in ordered lists should never be a 0\r
1119 //\r
1120 break;\r
1121 }\r
1122\r
1123 OneOfOption = ValueToOption (Question, &HiiValue);\r
1124 if (OneOfOption == NULL) {\r
1da651cd
DB
1125 //\r
1126 // Print debug msg for the mistach menu.\r
1127 //\r
1128 PrintMismatchMenuInfo (MenuOption);\r
1129\r
7c6c064c
ED
1130 if (SkipErrorValue) {\r
1131 //\r
1132 // Just try to get the option string, skip the value which not has option.\r
1133 //\r
1134 continue;\r
1135 }\r
1136\r
1137 //\r
1138 // Show error message\r
1139 //\r
1140 do {\r
1141 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1142 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1143\r
1144 //\r
1145 // The initial value of the orderedlist is invalid, force to be valid value\r
1146 // Exit current DisplayForm with new value.\r
1147 //\r
1148 gUserInput->SelectedStatement = Question;\r
42645c3d 1149 gMisMatch = TRUE;\r
7c6c064c
ED
1150 ValueArray = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
1151 ASSERT (ValueArray != NULL);\r
1152 gUserInput->InputValue.Buffer = ValueArray;\r
1153 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1154 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
d1102dba 1155\r
7c6c064c
ED
1156 Link = GetFirstNode (&Question->OptionListHead);\r
1157 Index2 = 0;\r
1158 while (!IsNull (&Question->OptionListHead, Link) && Index2 < OrderList->MaxContainers) {\r
1159 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1160 Link = GetNextNode (&Question->OptionListHead, Link);\r
1161 SetArrayData (ValueArray, ValueType, Index2, Option->OptionOpCode->Value.u64);\r
1162 Index2++;\r
1163 }\r
1164 SetArrayData (ValueArray, ValueType, Index2, 0);\r
1165\r
1166 FreePool (*OptionString);\r
1167 *OptionString = NULL;\r
1168 return EFI_NOT_FOUND;\r
1169 }\r
1170\r
1171 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1172 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1173 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1174 ASSERT (StringPtr != NULL);\r
5ad66ec6 1175 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1176 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1177 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c 1178 Character[0] = CHAR_CARRIAGE_RETURN;\r
5ad66ec6 1179 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1180 FreePool (StringPtr);\r
1181 }\r
1182\r
1183 //\r
1184 // If valid option more than the max container, skip these options.\r
1185 //\r
1186 if (Index >= OrderList->MaxContainers) {\r
1187 break;\r
1188 }\r
1189\r
1190 //\r
1191 // Search the other options, try to find the one not in the container.\r
1192 //\r
1193 Link = GetFirstNode (&Question->OptionListHead);\r
1194 while (!IsNull (&Question->OptionListHead, Link)) {\r
1195 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1196 Link = GetNextNode (&Question->OptionListHead, Link);\r
1197\r
1198 if (FindArrayData (ValueArray, ValueType, OneOfOption->OptionOpCode->Value.u64, NULL)) {\r
1199 continue;\r
1200 }\r
1201\r
1da651cd
DB
1202 //\r
1203 // Print debug msg for the mistach menu.\r
1204 //\r
1205 PrintMismatchMenuInfo (MenuOption);\r
1206\r
7c6c064c
ED
1207 if (SkipErrorValue) {\r
1208 //\r
1209 // Not report error, just get the correct option string info.\r
1210 //\r
1211 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1212 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1213 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1214 ASSERT (StringPtr != NULL);\r
5ad66ec6 1215 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1216 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1217 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c 1218 Character[0] = CHAR_CARRIAGE_RETURN;\r
5ad66ec6 1219 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1220 FreePool (StringPtr);\r
1221\r
1222 continue;\r
1223 }\r
1224\r
1225 if (!ValueInvalid) {\r
1226 ValueInvalid = TRUE;\r
1227 //\r
1228 // Show error message\r
1229 //\r
1230 do {\r
1231 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1232 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1233\r
1234 //\r
1235 // The initial value of the orderedlist is invalid, force to be valid value\r
1236 // Exit current DisplayForm with new value.\r
1237 //\r
1238 gUserInput->SelectedStatement = Question;\r
42645c3d 1239 gMisMatch = TRUE;\r
7c6c064c
ED
1240 ValueArray = AllocateCopyPool (Question->CurrentValue.BufferLen, Question->CurrentValue.Buffer);\r
1241 ASSERT (ValueArray != NULL);\r
1242 gUserInput->InputValue.Buffer = ValueArray;\r
1243 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1244 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
1245 }\r
d1102dba 1246\r
7c6c064c
ED
1247 SetArrayData (ValueArray, ValueType, Index++, OneOfOption->OptionOpCode->Value.u64);\r
1248 }\r
1249\r
1250 if (ValueInvalid) {\r
1251 FreePool (*OptionString);\r
1252 *OptionString = NULL;\r
1253 return EFI_NOT_FOUND;\r
1254 }\r
1255 }\r
1256 break;\r
1257\r
1258 case EFI_IFR_ONE_OF_OP:\r
1259 //\r
1260 // Check whether there are Options of this OneOf\r
1261 //\r
1262 if (IsListEmpty (&Question->OptionListHead)) {\r
1263 break;\r
1264 }\r
1265 if (Selected) {\r
1266 //\r
1267 // Go ask for input\r
1268 //\r
1269 Status = GetSelectionInputPopUp (MenuOption);\r
1270 } else {\r
5ad66ec6 1271 MaxLen = BufferSize / sizeof(CHAR16);\r
7c6c064c
ED
1272 *OptionString = AllocateZeroPool (BufferSize);\r
1273 ASSERT (*OptionString);\r
1274\r
1275 OneOfOption = ValueToOption (Question, QuestionValue);\r
1276 if (OneOfOption == NULL) {\r
1da651cd
DB
1277 //\r
1278 // Print debug msg for the mistach menu.\r
1279 //\r
1280 PrintMismatchMenuInfo (MenuOption);\r
1281\r
7c6c064c
ED
1282 if (SkipErrorValue) {\r
1283 //\r
1284 // Not report error, just get the correct option string info.\r
d1102dba 1285 //\r
7c6c064c
ED
1286 Link = GetFirstNode (&Question->OptionListHead);\r
1287 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1288 } else {\r
1289 //\r
1290 // Show error message\r
1291 //\r
1292 do {\r
1293 CreateDialog (&Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString, NULL);\r
1294 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1295\r
1296 //\r
1297 // Force the Question value to be valid\r
1298 // Exit current DisplayForm with new value.\r
1299 //\r
1300 Link = GetFirstNode (&Question->OptionListHead);\r
1301 Option = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1302\r
7c6c064c 1303 gUserInput->InputValue.Type = Option->OptionOpCode->Type;\r
d63a9eb4
ED
1304 switch (gUserInput->InputValue.Type) {\r
1305 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1306 gUserInput->InputValue.Value.u8 = Option->OptionOpCode->Value.u8;\r
1307 break;\r
1308 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1309 CopyMem (&gUserInput->InputValue.Value.u16, &Option->OptionOpCode->Value.u16, sizeof (UINT16));\r
1310 break;\r
1311 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1312 CopyMem (&gUserInput->InputValue.Value.u32, &Option->OptionOpCode->Value.u32, sizeof (UINT32));\r
1313 break;\r
1314 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1315 CopyMem (&gUserInput->InputValue.Value.u64, &Option->OptionOpCode->Value.u64, sizeof (UINT64));\r
1316 break;\r
1317 default:\r
1318 ASSERT (FALSE);\r
1319 break;\r
1320 }\r
7c6c064c 1321 gUserInput->SelectedStatement = Question;\r
42645c3d 1322 gMisMatch = TRUE;\r
7c6c064c
ED
1323 FreePool (*OptionString);\r
1324 *OptionString = NULL;\r
1325 return EFI_NOT_FOUND;\r
1326 }\r
1327 }\r
1328\r
1329 Character[0] = LEFT_ONEOF_DELIMITER;\r
5ad66ec6 1330 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1331 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1332 ASSERT (StringPtr != NULL);\r
5ad66ec6 1333 NewStrCat (OptionString[0], MaxLen, StringPtr);\r
7c6c064c 1334 Character[0] = RIGHT_ONEOF_DELIMITER;\r
5ad66ec6 1335 NewStrCat (OptionString[0], MaxLen, Character);\r
7c6c064c
ED
1336\r
1337 FreePool (StringPtr);\r
1338 }\r
1339 break;\r
1340\r
1341 case EFI_IFR_CHECKBOX_OP:\r
1342 if (Selected) {\r
1343 //\r
1344 // Since this is a BOOLEAN operation, flip it upon selection\r
1345 //\r
1346 gUserInput->InputValue.Type = QuestionValue->Type;\r
1347 gUserInput->InputValue.Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
1348\r
1349 //\r
1350 // Perform inconsistent check\r
1351 //\r
bfae1330 1352 return EFI_SUCCESS;\r
d1102dba 1353 } else {\r
7c6c064c
ED
1354 *OptionString = AllocateZeroPool (BufferSize);\r
1355 ASSERT (*OptionString);\r
1356\r
1357 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
1358\r
1359 if (QuestionValue->Value.b) {\r
1360 *(OptionString[0] + 1) = CHECK_ON;\r
1361 } else {\r
1362 *(OptionString[0] + 1) = CHECK_OFF;\r
1363 }\r
1364 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
1365 }\r
1366 break;\r
1367\r
1368 case EFI_IFR_NUMERIC_OP:\r
1369 if (Selected) {\r
1370 //\r
1371 // Go ask for input\r
1372 //\r
1373 Status = GetNumericInput (MenuOption);\r
1374 } else {\r
1375 *OptionString = AllocateZeroPool (BufferSize);\r
1376 ASSERT (*OptionString);\r
1377\r
1378 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
1379\r
1380 //\r
1381 // Formatted print\r
1382 //\r
1383 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
1384 Number = (UINT16) GetStringWidth (FormattedNumber);\r
1385 CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
1386\r
1387 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
1388 }\r
1389 break;\r
1390\r
1391 case EFI_IFR_DATE_OP:\r
1392 if (Selected) {\r
1393 //\r
1394 // This is similar to numerics\r
1395 //\r
1396 Status = GetNumericInput (MenuOption);\r
1397 } else {\r
1398 *OptionString = AllocateZeroPool (BufferSize);\r
1399 ASSERT (*OptionString);\r
1400\r
1401 switch (MenuOption->Sequence) {\r
1402 case 0:\r
1403 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
cc63add8
DB
1404 if (QuestionValue->Value.date.Month == 0xff){\r
1405 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");\r
1406 } else {\r
1407 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
1408 }\r
7c6c064c
ED
1409 *(OptionString[0] + 3) = DATE_SEPARATOR;\r
1410 break;\r
1411\r
1412 case 1:\r
1413 SetUnicodeMem (OptionString[0], 4, L' ');\r
cc63add8
DB
1414 if (QuestionValue->Value.date.Day == 0xff){\r
1415 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");\r
1416 } else {\r
1417 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
1418 }\r
7c6c064c
ED
1419 *(OptionString[0] + 6) = DATE_SEPARATOR;\r
1420 break;\r
1421\r
1422 case 2:\r
1423 SetUnicodeMem (OptionString[0], 7, L' ');\r
cc63add8
DB
1424 if (QuestionValue->Value.date.Year == 0xff){\r
1425 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"????");\r
1426 } else {\r
1427 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%04d", QuestionValue->Value.date.Year);\r
1428 }\r
7c6c064c
ED
1429 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
1430 break;\r
1431 }\r
1432 }\r
1433 break;\r
1434\r
1435 case EFI_IFR_TIME_OP:\r
1436 if (Selected) {\r
1437 //\r
1438 // This is similar to numerics\r
1439 //\r
1440 Status = GetNumericInput (MenuOption);\r
1441 } else {\r
1442 *OptionString = AllocateZeroPool (BufferSize);\r
1443 ASSERT (*OptionString);\r
1444\r
1445 switch (MenuOption->Sequence) {\r
1446 case 0:\r
1447 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
cc63add8
DB
1448 if (QuestionValue->Value.time.Hour == 0xff){\r
1449 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"??");\r
1450 } else {\r
1451 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
1452 }\r
7c6c064c
ED
1453 *(OptionString[0] + 3) = TIME_SEPARATOR;\r
1454 break;\r
1455\r
1456 case 1:\r
1457 SetUnicodeMem (OptionString[0], 4, L' ');\r
cc63add8
DB
1458 if (QuestionValue->Value.time.Minute == 0xff){\r
1459 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"??");\r
1460 } else {\r
1461 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
1462 }\r
7c6c064c
ED
1463 *(OptionString[0] + 6) = TIME_SEPARATOR;\r
1464 break;\r
1465\r
1466 case 2:\r
1467 SetUnicodeMem (OptionString[0], 7, L' ');\r
cc63add8
DB
1468 if (QuestionValue->Value.time.Second == 0xff){\r
1469 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"??");\r
1470 } else {\r
1471 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
1472 }\r
7c6c064c
ED
1473 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
1474 break;\r
1475 }\r
1476 }\r
1477 break;\r
1478\r
1479 case EFI_IFR_STRING_OP:\r
1480 if (Selected) {\r
1481 StringPtr = AllocateZeroPool (Question->CurrentValue.BufferLen + sizeof (CHAR16));\r
1482 ASSERT (StringPtr);\r
1483 CopyMem(StringPtr, Question->CurrentValue.Buffer, Question->CurrentValue.BufferLen);\r
1484\r
1485 Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
1486 if (EFI_ERROR (Status)) {\r
1487 FreePool (StringPtr);\r
1488 return Status;\r
1489 }\r
d1102dba 1490\r
7c6c064c
ED
1491 gUserInput->InputValue.Buffer = AllocateCopyPool (Question->CurrentValue.BufferLen, StringPtr);\r
1492 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
1493 gUserInput->InputValue.Type = Question->CurrentValue.Type;\r
1494 gUserInput->InputValue.Value.string = HiiSetString(gFormData->HiiHandle, gUserInput->InputValue.Value.string, StringPtr, NULL);\r
1495 FreePool (StringPtr);\r
bfae1330 1496 return EFI_SUCCESS;\r
7c6c064c
ED
1497 } else {\r
1498 *OptionString = AllocateZeroPool (BufferSize);\r
1499 ASSERT (*OptionString);\r
1500\r
1501 if (((CHAR16 *) Question->CurrentValue.Buffer)[0] == 0x0000) {\r
1502 *(OptionString[0]) = '_';\r
1503 } else {\r
1504 if (Question->CurrentValue.BufferLen < BufferSize) {\r
1505 BufferSize = Question->CurrentValue.BufferLen;\r
1506 }\r
1507 CopyMem (OptionString[0], (CHAR16 *) Question->CurrentValue.Buffer, BufferSize);\r
1508 }\r
1509 }\r
1510 break;\r
1511\r
1512 case EFI_IFR_PASSWORD_OP:\r
1513 if (Selected) {\r
1514 Status = PasswordProcess (MenuOption);\r
1515 }\r
1516 break;\r
1517\r
1518 default:\r
1519 break;\r
1520 }\r
1521\r
1522 return Status;\r
1523}\r
1524\r
1525\r
1526/**\r
1527 Process the help string: Split StringPtr to several lines of strings stored in\r
1528 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
1529\r
1530 @param StringPtr The entire help string.\r
1531 @param FormattedString The oupput formatted string.\r
1532 @param EachLineWidth The max string length of each line in the formatted string.\r
1533 @param RowCount TRUE: if Question is selected.\r
1534\r
1535**/\r
1536UINTN\r
1537ProcessHelpString (\r
1538 IN CHAR16 *StringPtr,\r
1539 OUT CHAR16 **FormattedString,\r
1540 OUT UINT16 *EachLineWidth,\r
1541 IN UINTN RowCount\r
1542 )\r
1543{\r
1544 UINTN Index;\r
1545 CHAR16 *OutputString;\r
1546 UINTN TotalRowNum;\r
1547 UINTN CheckedNum;\r
1548 UINT16 GlyphWidth;\r
1549 UINT16 LineWidth;\r
1550 UINT16 MaxStringLen;\r
1551 UINT16 StringLen;\r
1552\r
1553 TotalRowNum = 0;\r
1554 CheckedNum = 0;\r
1555 GlyphWidth = 1;\r
1556 Index = 0;\r
1557 MaxStringLen = 0;\r
1558 StringLen = 0;\r
1559\r
1560 //\r
1561 // Set default help string width.\r
1562 //\r
1563 LineWidth = (UINT16) (gHelpBlockWidth - 1);\r
1564\r
1565 //\r
1566 // Get row number of the String.\r
1567 //\r
1568 while ((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
1569 if (StringLen > MaxStringLen) {\r
1570 MaxStringLen = StringLen;\r
1571 }\r
1572\r
1573 TotalRowNum ++;\r
1574 FreePool (OutputString);\r
1575 }\r
1576 *EachLineWidth = MaxStringLen;\r
1577\r
1578 *FormattedString = AllocateZeroPool (TotalRowNum * MaxStringLen * sizeof (CHAR16));\r
1579 ASSERT (*FormattedString != NULL);\r
1580\r
1581 //\r
1582 // Generate formatted help string array.\r
1583 //\r
1584 GlyphWidth = 1;\r
1585 Index = 0;\r
1586 while((StringLen = GetLineByWidth (StringPtr, LineWidth, &GlyphWidth, &Index, &OutputString)) != 0) {\r
1587 CopyMem (*FormattedString + CheckedNum * MaxStringLen, OutputString, StringLen * sizeof (CHAR16));\r
1588 CheckedNum ++;\r
1589 FreePool (OutputString);\r
1590 }\r
1591\r
d1102dba 1592 return TotalRowNum;\r
7c6c064c 1593}\r