]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
TPL of Pcd Dxe driver was changed to TPL_CALLBACK from TPL_NOTIFY to follow UEFI...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / ProcessOptions.c
CommitLineData
c60a0616 1/** @file\r
2Implementation for handling the User Interface option processing.\r
3\r
4\r
d02847d3 5Copyright (c) 2004 - 2009, Intel Corporation\r
c60a0616 6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
c60a0616 16#include "Setup.h"\r
17\r
18\r
19/**\r
20 Process Question Config.\r
21\r
22 @param Selection The UI menu selection.\r
23 @param Question The Question to be peocessed.\r
24\r
25 @retval EFI_SUCCESS Question Config process success.\r
26 @retval Other Question Config process fail.\r
27\r
28**/\r
29EFI_STATUS\r
30ProcessQuestionConfig (\r
31 IN UI_MENU_SELECTION *Selection,\r
32 IN FORM_BROWSER_STATEMENT *Question\r
33 )\r
34{\r
35 EFI_STATUS Status;\r
36 CHAR16 *ConfigResp;\r
37 CHAR16 *Progress;\r
38 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
39\r
40 if (Question->QuestionConfig == 0) {\r
41 return EFI_SUCCESS;\r
42 }\r
43\r
44 //\r
45 // Get <ConfigResp>\r
46 //\r
47 ConfigResp = GetToken (Question->QuestionConfig, Selection->FormSet->HiiHandle);\r
48 if (ConfigResp == NULL) {\r
49 return EFI_NOT_FOUND;\r
50 }\r
51\r
52 //\r
53 // Send config to Configuration Driver\r
54 //\r
55 ConfigAccess = Selection->FormSet->ConfigAccess;\r
56 if (ConfigAccess == NULL) {\r
57 return EFI_UNSUPPORTED;\r
58 }\r
59 Status = ConfigAccess->RouteConfig (\r
60 ConfigAccess,\r
61 ConfigResp,\r
62 &Progress\r
63 );\r
64\r
65 return Status;\r
66}\r
67\r
68\r
69/**\r
70 Search an Option of a Question by its value.\r
71\r
72 @param Question The Question\r
73 @param OptionValue Value for Option to be searched.\r
74\r
75 @retval Pointer Pointer to the found Option.\r
76 @retval NULL Option not found.\r
77\r
78**/\r
79QUESTION_OPTION *\r
80ValueToOption (\r
81 IN FORM_BROWSER_STATEMENT *Question,\r
82 IN EFI_HII_VALUE *OptionValue\r
83 )\r
84{\r
85 LIST_ENTRY *Link;\r
86 QUESTION_OPTION *Option;\r
87\r
88 Link = GetFirstNode (&Question->OptionListHead);\r
89 while (!IsNull (&Question->OptionListHead, Link)) {\r
90 Option = QUESTION_OPTION_FROM_LINK (Link);\r
91\r
92 if (CompareHiiValue (&Option->Value, OptionValue, NULL) == 0) {\r
93 return Option;\r
94 }\r
95\r
96 Link = GetNextNode (&Question->OptionListHead, Link);\r
97 }\r
98\r
99 return NULL;\r
100}\r
101\r
102\r
d02847d3 103/**\r
104 Return data element in an Array by its Index.\r
105\r
106 @param Array The data array.\r
107 @param Type Type of the data in this array.\r
108 @param Index Zero based index for data in this array.\r
109\r
110 @retval Value The data to be returned\r
111\r
112**/\r
113UINT64\r
114GetArrayData (\r
115 IN VOID *Array,\r
116 IN UINT8 Type,\r
117 IN UINTN Index\r
118 )\r
119{\r
120 UINT64 Data;\r
121\r
122 ASSERT (Array != NULL);\r
123\r
124 Data = 0;\r
125 switch (Type) {\r
126 case EFI_IFR_TYPE_NUM_SIZE_8:\r
127 Data = (UINT64) *(((UINT8 *) Array) + Index);\r
128 break;\r
129\r
130 case EFI_IFR_TYPE_NUM_SIZE_16:\r
131 Data = (UINT64) *(((UINT16 *) Array) + Index);\r
132 break;\r
133\r
134 case EFI_IFR_TYPE_NUM_SIZE_32:\r
135 Data = (UINT64) *(((UINT32 *) Array) + Index);\r
136 break;\r
137\r
138 case EFI_IFR_TYPE_NUM_SIZE_64:\r
139 Data = (UINT64) *(((UINT64 *) Array) + Index);\r
140 break;\r
141\r
142 default:\r
143 break;\r
144 }\r
145\r
146 return Data;\r
147}\r
148\r
149\r
150/**\r
151 Set value of a data element in an Array by its Index.\r
152\r
153 @param Array The data array.\r
154 @param Type Type of the data in this array.\r
155 @param Index Zero based index for data in this array.\r
156 @param Value The value to be set.\r
157\r
158**/\r
159VOID\r
160SetArrayData (\r
161 IN VOID *Array,\r
162 IN UINT8 Type,\r
163 IN UINTN Index,\r
164 IN UINT64 Value\r
165 )\r
166{\r
167\r
168 ASSERT (Array != NULL);\r
169\r
170 switch (Type) {\r
171 case EFI_IFR_TYPE_NUM_SIZE_8:\r
172 *(((UINT8 *) Array) + Index) = (UINT8) Value;\r
173 break;\r
174\r
175 case EFI_IFR_TYPE_NUM_SIZE_16:\r
176 *(((UINT16 *) Array) + Index) = (UINT16) Value;\r
177 break;\r
178\r
179 case EFI_IFR_TYPE_NUM_SIZE_32:\r
180 *(((UINT32 *) Array) + Index) = (UINT32) Value;\r
181 break;\r
182\r
183 case EFI_IFR_TYPE_NUM_SIZE_64:\r
184 *(((UINT64 *) Array) + Index) = (UINT64) Value;\r
185 break;\r
186\r
187 default:\r
188 break;\r
189 }\r
190}\r
191\r
192\r
c60a0616 193/**\r
194 Print Question Value according to it's storage width and display attributes.\r
195\r
196 @param Question The Question to be printed.\r
197 @param FormattedNumber Buffer for output string.\r
198 @param BufferSize The FormattedNumber buffer size in bytes.\r
199\r
200 @retval EFI_SUCCESS Print success.\r
201 @retval EFI_BUFFER_TOO_SMALL Buffer size is not enough for formatted number.\r
202\r
203**/\r
204EFI_STATUS\r
205PrintFormattedNumber (\r
206 IN FORM_BROWSER_STATEMENT *Question,\r
207 IN OUT CHAR16 *FormattedNumber,\r
208 IN UINTN BufferSize\r
209 )\r
210{\r
211 INT64 Value;\r
212 CHAR16 *Format;\r
213 EFI_HII_VALUE *QuestionValue;\r
214\r
215 if (BufferSize < (21 * sizeof (CHAR16))) {\r
216 return EFI_BUFFER_TOO_SMALL;\r
217 }\r
218\r
219 QuestionValue = &Question->HiiValue;\r
220\r
221 Value = (INT64) QuestionValue->Value.u64;\r
222 switch (Question->Flags & EFI_IFR_DISPLAY) {\r
223 case EFI_IFR_DISPLAY_INT_DEC:\r
224 switch (QuestionValue->Type) {\r
225 case EFI_IFR_NUMERIC_SIZE_1:\r
226 Value = (INT64) ((INT8) QuestionValue->Value.u8);\r
227 break;\r
228\r
229 case EFI_IFR_NUMERIC_SIZE_2:\r
230 Value = (INT64) ((INT16) QuestionValue->Value.u16);\r
231 break;\r
232\r
233 case EFI_IFR_NUMERIC_SIZE_4:\r
234 Value = (INT64) ((INT32) QuestionValue->Value.u32);\r
235 break;\r
236\r
237 case EFI_IFR_NUMERIC_SIZE_8:\r
238 default:\r
239 break;\r
240 }\r
241\r
242 if (Value < 0) {\r
243 Value = -Value;\r
244 Format = L"-%ld";\r
245 } else {\r
246 Format = L"%ld";\r
247 }\r
248 break;\r
249\r
250 case EFI_IFR_DISPLAY_UINT_DEC:\r
251 Format = L"%ld";\r
252 break;\r
253\r
254 case EFI_IFR_DISPLAY_UINT_HEX:\r
255 Format = L"%lx";\r
256 break;\r
257\r
258 default:\r
259 return EFI_UNSUPPORTED;\r
260 break;\r
261 }\r
262\r
263 UnicodeSPrint (FormattedNumber, BufferSize, Format, Value);\r
264\r
265 return EFI_SUCCESS;\r
266}\r
267\r
268\r
269/**\r
270 Password may be stored as encrypted by Configuration Driver. When change a\r
271 password, user will be challenged with old password. To validate user input old\r
272 password, we will send the clear text to Configuration Driver via Callback().\r
273 Configuration driver is responsible to check the passed in password and return\r
274 the validation result. If validation pass, state machine in password Callback()\r
275 will transit from BROWSER_STATE_VALIDATE_PASSWORD to BROWSER_STATE_SET_PASSWORD.\r
276 After user type in new password twice, Callback() will be invoked to send the\r
277 new password to Configuration Driver.\r
278\r
279 @param Selection Pointer to UI_MENU_SELECTION.\r
280 @param MenuOption The MenuOption for this password Question.\r
281 @param String The clear text of password.\r
282\r
283 @retval EFI_NOT_AVAILABLE_YET Callback() request to terminate password input.\r
284 @return In state of BROWSER_STATE_VALIDATE_PASSWORD:\r
285 @retval EFI_SUCCESS Password correct, Browser will prompt for new\r
286 password.\r
287 @retval EFI_NOT_READY Password incorrect, Browser will show error\r
288 message.\r
289 @retval Other Browser will do nothing.\r
290 @return In state of BROWSER_STATE_SET_PASSWORD:\r
291 @retval EFI_SUCCESS Set password success.\r
292 @retval Other Set password failed.\r
293\r
294**/\r
295EFI_STATUS\r
296PasswordCallback (\r
297 IN UI_MENU_SELECTION *Selection,\r
298 IN UI_MENU_OPTION *MenuOption,\r
299 IN CHAR16 *String\r
300 )\r
301{\r
302 EFI_STATUS Status;\r
303 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
304 EFI_BROWSER_ACTION_REQUEST ActionRequest;\r
305 EFI_HII_VALUE *QuestionValue;\r
306\r
307 QuestionValue = &MenuOption->ThisTag->HiiValue;\r
308 ConfigAccess = Selection->FormSet->ConfigAccess;\r
309 if (ConfigAccess == NULL) {\r
310 return EFI_UNSUPPORTED;\r
311 }\r
312\r
313 //\r
314 // Prepare password string in HII database\r
315 //\r
316 if (String != NULL) {\r
317 QuestionValue->Value.string = NewString (String, Selection->FormSet->HiiHandle);\r
318 } else {\r
319 QuestionValue->Value.string = 0;\r
320 }\r
321\r
322 //\r
323 // Send password to Configuration Driver for validation\r
324 //\r
325 Status = ConfigAccess->Callback (\r
326 ConfigAccess,\r
327 EFI_BROWSER_ACTION_CHANGING,\r
328 MenuOption->ThisTag->QuestionId,\r
329 QuestionValue->Type,\r
330 &QuestionValue->Value,\r
331 &ActionRequest\r
332 );\r
333\r
334 //\r
335 // Remove password string from HII database\r
336 //\r
337 if (String != NULL) {\r
338 DeleteString (QuestionValue->Value.string, Selection->FormSet->HiiHandle);\r
339 }\r
340\r
341 return Status;\r
342}\r
343\r
344\r
345/**\r
346 Display error message for invalid password.\r
347\r
348**/\r
349VOID\r
350PasswordInvalid (\r
351 VOID\r
352 )\r
353{\r
354 EFI_INPUT_KEY Key;\r
355\r
356 //\r
357 // Invalid password, prompt error message\r
358 //\r
359 do {\r
360 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gPassowordInvalid, gPressEnter, gEmptyString);\r
361 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
362}\r
363\r
364\r
365/**\r
366 Process a Question's Option (whether selected or un-selected).\r
367\r
368 @param Selection Pointer to UI_MENU_SELECTION.\r
369 @param MenuOption The MenuOption for this Question.\r
370 @param Selected TRUE: if Question is selected.\r
371 @param OptionString Pointer of the Option String to be displayed.\r
372\r
373 @retval EFI_SUCCESS Question Option process success.\r
374 @retval Other Question Option process fail.\r
375\r
376**/\r
377EFI_STATUS\r
378ProcessOptions (\r
379 IN UI_MENU_SELECTION *Selection,\r
380 IN UI_MENU_OPTION *MenuOption,\r
381 IN BOOLEAN Selected,\r
382 OUT CHAR16 **OptionString\r
383 )\r
384{\r
385 EFI_STATUS Status;\r
386 CHAR16 *StringPtr;\r
387 CHAR16 *TempString;\r
388 UINTN Index;\r
389 FORM_BROWSER_STATEMENT *Question;\r
390 CHAR16 FormattedNumber[21];\r
391 UINT16 Number;\r
392 CHAR16 Character[2];\r
393 EFI_INPUT_KEY Key;\r
394 UINTN BufferSize;\r
395 QUESTION_OPTION *OneOfOption;\r
396 LIST_ENTRY *Link;\r
397 EFI_HII_VALUE HiiValue;\r
398 EFI_HII_VALUE *QuestionValue;\r
399 BOOLEAN Suppress;\r
400 UINT16 Maximum;\r
8d00a0f1 401 QUESTION_OPTION *Option;\r
402 UINTN Index2;\r
d02847d3 403 UINT8 *ValueArray;\r
404 UINT8 ValueType;\r
c60a0616 405\r
406 Status = EFI_SUCCESS;\r
407\r
408 StringPtr = NULL;\r
409 Character[1] = L'\0';\r
410 *OptionString = NULL;\r
411\r
412 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
413 BufferSize = (gOptionBlockWidth + 1) * 2 * gScreenDimensions.BottomRow;\r
414\r
415 Question = MenuOption->ThisTag;\r
416 QuestionValue = &Question->HiiValue;\r
417 Maximum = (UINT16) Question->Maximum;\r
418\r
d02847d3 419 ValueArray = Question->BufferValue;\r
420 ValueType = Question->ValueType;\r
421\r
c60a0616 422 switch (Question->Operand) {\r
423 case EFI_IFR_ORDERED_LIST_OP:\r
424 //\r
425 // Initialize Option value array\r
426 //\r
d02847d3 427 if (GetArrayData (ValueArray, ValueType, 0) == 0) {\r
c60a0616 428 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);\r
429 }\r
430\r
431 if (Selected) {\r
432 //\r
433 // Go ask for input\r
434 //\r
435 Status = GetSelectionInputPopUp (Selection, MenuOption);\r
436 } else {\r
437 //\r
438 // We now know how many strings we will have, so we can allocate the\r
439 // space required for the array or strings.\r
440 //\r
441 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);\r
442 ASSERT (*OptionString);\r
443\r
d02847d3 444 HiiValue.Type = ValueType;\r
c60a0616 445 HiiValue.Value.u64 = 0;\r
446 for (Index = 0; Index < Question->MaxContainers; Index++) {\r
d02847d3 447 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
448 if (HiiValue.Value.u64 == 0) {\r
c60a0616 449 //\r
450 // Values for the options in ordered lists should never be a 0\r
451 //\r
452 break;\r
453 }\r
454\r
455 OneOfOption = ValueToOption (Question, &HiiValue);\r
456 if (OneOfOption == NULL) {\r
8d00a0f1 457 //\r
458 // Show error message\r
459 //\r
460 do {\r
461 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
462 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
463\r
464 //\r
465 // The initial value of the orderedlist is invalid, force to be valid value\r
466 //\r
467 Link = GetFirstNode (&Question->OptionListHead);\r
468 Index2 = 0;\r
469 while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {\r
470 Option = QUESTION_OPTION_FROM_LINK (Link);\r
d02847d3 471 SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);\r
472 Index2++;\r
8d00a0f1 473 Link = GetNextNode (&Question->OptionListHead, Link);\r
474 }\r
d02847d3 475 SetArrayData (ValueArray, ValueType, Index2, 0);\r
8d00a0f1 476\r
477 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
478 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
479\r
f4113e1f 480 FreePool (*OptionString);\r
8d00a0f1 481 *OptionString = NULL;\r
c60a0616 482 return EFI_NOT_FOUND;\r
483 }\r
484\r
485 Suppress = FALSE;\r
486 if ((OneOfOption->SuppressExpression != NULL) &&\r
487 (OneOfOption->SuppressExpression->Result.Value.b)) {\r
488 //\r
489 // This option is suppressed\r
490 //\r
491 Suppress = TRUE;\r
492 }\r
493\r
494 if (!Suppress) {\r
495 Character[0] = LEFT_ONEOF_DELIMITER;\r
496 NewStrCat (OptionString[0], Character);\r
497 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
498 NewStrCat (OptionString[0], StringPtr);\r
499 Character[0] = RIGHT_ONEOF_DELIMITER;\r
500 NewStrCat (OptionString[0], Character);\r
501 Character[0] = CHAR_CARRIAGE_RETURN;\r
502 NewStrCat (OptionString[0], Character);\r
503\r
f4113e1f 504 FreePool (StringPtr);\r
c60a0616 505 }\r
506 }\r
507 }\r
508 break;\r
509\r
510 case EFI_IFR_ONE_OF_OP:\r
511 if (Selected) {\r
512 //\r
513 // Go ask for input\r
514 //\r
515 Status = GetSelectionInputPopUp (Selection, MenuOption);\r
516 } else {\r
517 *OptionString = AllocateZeroPool (BufferSize);\r
518 ASSERT (*OptionString);\r
519\r
520 OneOfOption = ValueToOption (Question, QuestionValue);\r
521 if (OneOfOption == NULL) {\r
8d00a0f1 522 //\r
523 // Show error message\r
524 //\r
525 do {\r
526 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
527 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
528\r
529 //\r
530 // Force the Question value to be valid\r
531 //\r
532 Link = GetFirstNode (&Question->OptionListHead);\r
533 while (!IsNull (&Question->OptionListHead, Link)) {\r
534 Option = QUESTION_OPTION_FROM_LINK (Link);\r
535\r
536 if ((Option->SuppressExpression == NULL) ||\r
537 !Option->SuppressExpression->Result.Value.b) {\r
538 CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
539 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
540 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
541 break;\r
542 }\r
543\r
544 Link = GetNextNode (&Question->OptionListHead, Link);\r
545 }\r
546\r
f4113e1f 547 FreePool (*OptionString);\r
8d00a0f1 548 *OptionString = NULL;\r
40a06b0c 549 return EFI_NOT_FOUND;\r
c60a0616 550 }\r
551\r
552 if ((OneOfOption->SuppressExpression != NULL) &&\r
553 (OneOfOption->SuppressExpression->Result.Value.b)) {\r
554 //\r
555 // This option is suppressed\r
556 //\r
557 Suppress = TRUE;\r
558 } else {\r
559 Suppress = FALSE;\r
560 }\r
561\r
562 if (Suppress) {\r
563 //\r
564 // Current selected option happen to be suppressed,\r
565 // enforce to select on a non-suppressed option\r
566 //\r
567 Link = GetFirstNode (&Question->OptionListHead);\r
568 while (!IsNull (&Question->OptionListHead, Link)) {\r
569 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
570\r
571 if ((OneOfOption->SuppressExpression == NULL) ||\r
572 !OneOfOption->SuppressExpression->Result.Value.b) {\r
573 Suppress = FALSE;\r
574 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));\r
575 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
8d00a0f1 576 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
577 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
c60a0616 578 break;\r
579 }\r
580\r
581 Link = GetNextNode (&Question->OptionListHead, Link);\r
582 }\r
583 }\r
584\r
585 if (!Suppress) {\r
586 Character[0] = LEFT_ONEOF_DELIMITER;\r
587 NewStrCat (OptionString[0], Character);\r
588 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
589 NewStrCat (OptionString[0], StringPtr);\r
590 Character[0] = RIGHT_ONEOF_DELIMITER;\r
591 NewStrCat (OptionString[0], Character);\r
592\r
f4113e1f 593 FreePool (StringPtr);\r
c60a0616 594 }\r
595 }\r
596 break;\r
597\r
598 case EFI_IFR_CHECKBOX_OP:\r
599 *OptionString = AllocateZeroPool (BufferSize);\r
600 ASSERT (*OptionString);\r
601\r
602 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
603\r
604 if (Selected) {\r
605 //\r
606 // Since this is a BOOLEAN operation, flip it upon selection\r
607 //\r
608 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
609\r
610 //\r
611 // Perform inconsistent check\r
612 //\r
613 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
614 if (EFI_ERROR (Status)) {\r
615 //\r
616 // Inconsistent check fail, restore Question Value\r
617 //\r
618 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
f4113e1f 619 FreePool (*OptionString);\r
8d00a0f1 620 *OptionString = NULL;\r
c60a0616 621 return Status;\r
622 }\r
623\r
624 //\r
625 // Save Question value\r
626 //\r
627 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
628 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
629 }\r
630\r
631 if (QuestionValue->Value.b) {\r
632 *(OptionString[0] + 1) = CHECK_ON;\r
633 } else {\r
634 *(OptionString[0] + 1) = CHECK_OFF;\r
635 }\r
636 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
637 break;\r
638\r
639 case EFI_IFR_NUMERIC_OP:\r
640 if (Selected) {\r
641 //\r
642 // Go ask for input\r
643 //\r
644 Status = GetNumericInput (Selection, MenuOption);\r
645 } else {\r
646 *OptionString = AllocateZeroPool (BufferSize);\r
647 ASSERT (*OptionString);\r
648\r
649 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
650\r
651 //\r
652 // Formatted print\r
653 //\r
654 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
655 Number = (UINT16) GetStringWidth (FormattedNumber);\r
656 CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
657\r
658 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
659 }\r
660 break;\r
661\r
662 case EFI_IFR_DATE_OP:\r
663 if (Selected) {\r
664 //\r
665 // This is similar to numerics\r
666 //\r
667 Status = GetNumericInput (Selection, MenuOption);\r
668 } else {\r
669 *OptionString = AllocateZeroPool (BufferSize);\r
670 ASSERT (*OptionString);\r
671\r
672 switch (MenuOption->Sequence) {\r
673 case 0:\r
674 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
675 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
676 *(OptionString[0] + 3) = DATE_SEPARATOR;\r
677 break;\r
678\r
679 case 1:\r
680 SetUnicodeMem (OptionString[0], 4, L' ');\r
681 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
682 *(OptionString[0] + 6) = DATE_SEPARATOR;\r
683 break;\r
684\r
685 case 2:\r
686 SetUnicodeMem (OptionString[0], 7, L' ');\r
687 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);\r
688 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
689 break;\r
690 }\r
691 }\r
692 break;\r
693\r
694 case EFI_IFR_TIME_OP:\r
695 if (Selected) {\r
696 //\r
697 // This is similar to numerics\r
698 //\r
699 Status = GetNumericInput (Selection, MenuOption);\r
700 } else {\r
701 *OptionString = AllocateZeroPool (BufferSize);\r
702 ASSERT (*OptionString);\r
703\r
704 switch (MenuOption->Sequence) {\r
705 case 0:\r
706 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
707 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
708 *(OptionString[0] + 3) = TIME_SEPARATOR;\r
709 break;\r
710\r
711 case 1:\r
712 SetUnicodeMem (OptionString[0], 4, L' ');\r
713 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
714 *(OptionString[0] + 6) = TIME_SEPARATOR;\r
715 break;\r
716\r
717 case 2:\r
718 SetUnicodeMem (OptionString[0], 7, L' ');\r
719 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
720 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
721 break;\r
722 }\r
723 }\r
724 break;\r
725\r
726 case EFI_IFR_STRING_OP:\r
727 if (Selected) {\r
728 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
729 ASSERT (StringPtr);\r
730\r
731 Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
732 if (!EFI_ERROR (Status)) {\r
733 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
734 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
735\r
736 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
737 }\r
738\r
f4113e1f 739 FreePool (StringPtr);\r
c60a0616 740 } else {\r
741 *OptionString = AllocateZeroPool (BufferSize);\r
742 ASSERT (*OptionString);\r
743\r
744 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {\r
745 *(OptionString[0]) = '_';\r
746 } else {\r
747 if ((Maximum * sizeof (CHAR16)) < BufferSize) {\r
748 BufferSize = Maximum * sizeof (CHAR16);\r
749 }\r
750 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);\r
751 }\r
752 }\r
753 break;\r
754\r
755 case EFI_IFR_PASSWORD_OP:\r
756 if (Selected) {\r
757 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
758 ASSERT (StringPtr);\r
759\r
760 //\r
761 // For interactive passwords, old password is validated by callback\r
762 //\r
763 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
764 //\r
765 // Use a NULL password to test whether old password is required\r
766 //\r
767 *StringPtr = 0;\r
768 Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
769 if (Status == EFI_NOT_AVAILABLE_YET) {\r
770 //\r
771 // Callback request to terminate password input\r
772 //\r
f4113e1f 773 FreePool (StringPtr);\r
c60a0616 774 return EFI_SUCCESS;\r
775 }\r
776\r
777 if (EFI_ERROR (Status)) {\r
778 //\r
779 // Old password exist, ask user for the old password\r
780 //\r
781 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
782 if (EFI_ERROR (Status)) {\r
f4113e1f 783 FreePool (StringPtr);\r
c60a0616 784 return Status;\r
785 }\r
786\r
787 //\r
788 // Check user input old password\r
789 //\r
790 Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
791 if (EFI_ERROR (Status)) {\r
792 if (Status == EFI_NOT_READY) {\r
793 //\r
794 // Typed in old password incorrect\r
795 //\r
796 PasswordInvalid ();\r
797 } else {\r
798 Status = EFI_SUCCESS;\r
799 }\r
800\r
f4113e1f 801 FreePool (StringPtr);\r
c60a0616 802 return Status;\r
803 }\r
804 }\r
805 } else {\r
806 //\r
807 // For non-interactive password, validate old password in local\r
808 //\r
809 if (*((CHAR16 *) Question->BufferValue) != 0) {\r
810 //\r
811 // There is something there! Prompt for password\r
812 //\r
813 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
814 if (EFI_ERROR (Status)) {\r
f4113e1f 815 FreePool (StringPtr);\r
c60a0616 816 return Status;\r
817 }\r
818\r
819 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);\r
40a06b0c 820 ASSERT (TempString != NULL);\r
8b0fc5c1 821\r
c60a0616 822 TempString[Maximum] = L'\0';\r
823\r
824 if (StrCmp (StringPtr, TempString) != 0) {\r
825 //\r
826 // Typed in old password incorrect\r
827 //\r
828 PasswordInvalid ();\r
829\r
f4113e1f 830 FreePool (StringPtr);\r
831 FreePool (TempString);\r
c60a0616 832 return Status;\r
833 }\r
834\r
f4113e1f 835 FreePool (TempString);\r
c60a0616 836 }\r
837 }\r
838\r
839 //\r
840 // Ask for new password\r
841 //\r
842 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
843 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
844 if (EFI_ERROR (Status)) {\r
845 //\r
846 // Reset state machine for interactive password\r
847 //\r
848 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
849 PasswordCallback (Selection, MenuOption, NULL);\r
850 }\r
851\r
f4113e1f 852 FreePool (StringPtr);\r
c60a0616 853 return Status;\r
854 }\r
855\r
856 //\r
857 // Confirm new password\r
858 //\r
859 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
860 ASSERT (TempString);\r
861 Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
862 if (EFI_ERROR (Status)) {\r
863 //\r
864 // Reset state machine for interactive password\r
865 //\r
866 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
867 PasswordCallback (Selection, MenuOption, NULL);\r
868 }\r
869\r
f4113e1f 870 FreePool (StringPtr);\r
871 FreePool (TempString);\r
c60a0616 872 return Status;\r
873 }\r
874\r
875 //\r
876 // Compare two typed-in new passwords\r
877 //\r
878 if (StrCmp (StringPtr, TempString) == 0) {\r
879 //\r
880 // Two password match, send it to Configuration Driver\r
881 //\r
882 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
883 PasswordCallback (Selection, MenuOption, StringPtr);\r
884 } else {\r
885 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
886 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
887 }\r
888 } else {\r
889 //\r
890 // Reset state machine for interactive password\r
891 //\r
892 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
893 PasswordCallback (Selection, MenuOption, NULL);\r
894 }\r
895\r
896 //\r
897 // Two password mismatch, prompt error message\r
898 //\r
899 do {\r
900 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);\r
901 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
902 }\r
903\r
f4113e1f 904 FreePool (TempString);\r
905 FreePool (StringPtr);\r
c60a0616 906 }\r
907 break;\r
908\r
909 default:\r
910 break;\r
911 }\r
912\r
913 return Status;\r
914}\r
915\r
916\r
917/**\r
918 Process the help string: Split StringPtr to several lines of strings stored in\r
919 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
920\r
921 @param StringPtr The entire help string.\r
922 @param FormattedString The oupput formatted string.\r
923 @param RowCount TRUE: if Question is selected.\r
924\r
925**/\r
926VOID\r
927ProcessHelpString (\r
928 IN CHAR16 *StringPtr,\r
929 OUT CHAR16 **FormattedString,\r
930 IN UINTN RowCount\r
931 )\r
932{\r
f4113e1f 933 UINTN BlockWidth;\r
c60a0616 934 UINTN AllocateSize;\r
935 //\r
936 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line\r
937 //\r
938 UINTN CurrIndex;\r
939 UINTN PrevCurrIndex;\r
940 UINTN LineCount;\r
941 UINTN VirtualLineCount;\r
942 //\r
943 // GlyphOffset stores glyph width of current screen-line\r
944 //\r
945 UINTN GlyphOffset;\r
946 //\r
947 // GlyphWidth equals to 2 if we meet width directive\r
948 //\r
949 UINTN GlyphWidth;\r
950 //\r
951 // during scanning, we remember the position of last space character\r
952 // in case that if next word cannot put in current line, we could restore back to the position\r
953 // of last space character\r
954 // while we should also remmeber the glyph width of the last space character for restoring\r
955 //\r
956 UINTN LastSpaceIndex;\r
957 UINTN LastSpaceGlyphWidth;\r
958 //\r
959 // every time we begin to form a new screen-line, we should remember glyph width of single character\r
960 // of last line\r
961 //\r
962 UINTN LineStartGlyphWidth;\r
963 UINTN *IndexArray;\r
964 UINTN *OldIndexArray;\r
965\r
f4113e1f 966 BlockWidth = (UINTN) gHelpBlockWidth - 1;\r
8b0fc5c1 967\r
c60a0616 968 //\r
969 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )\r
970 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want\r
971 // to bring the width directive of the last line to current screen-line.\r
972 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line\r
973 // different from that of "\wideabcde", we should remember the width directive.\r
974 //\r
975 AllocateSize = 0x20;\r
976 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
40a06b0c 977 ASSERT (IndexArray != NULL);\r
c60a0616 978\r
979 if (*FormattedString != NULL) {\r
f4113e1f 980 FreePool (*FormattedString);\r
c60a0616 981 *FormattedString = NULL;\r
982 }\r
983\r
984 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,\r
985 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;\r
986 (StringPtr[CurrIndex] != CHAR_NULL);\r
987 CurrIndex ++) {\r
988\r
989 if (LineCount == AllocateSize) {\r
990 AllocateSize += 0x10;\r
991 OldIndexArray = IndexArray;\r
992 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
bc166db3 993 ASSERT (IndexArray != NULL);\r
8b0fc5c1 994\r
c60a0616 995 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);\r
f4113e1f 996 FreePool (OldIndexArray);\r
c60a0616 997 }\r
998 switch (StringPtr[CurrIndex]) {\r
999\r
1000 case NARROW_CHAR:\r
1001 case WIDE_CHAR:\r
1002 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);\r
1003 if (CurrIndex == 0) {\r
1004 LineStartGlyphWidth = GlyphWidth;\r
1005 }\r
1006 break;\r
1007\r
1008 //\r
1009 // char is '\n'\r
1010 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN\r
1011 //\r
1012 case CHAR_LINEFEED:\r
1013 //\r
1014 // Store a range of string as a line\r
1015 //\r
1016 IndexArray[LineCount*3] = PrevCurrIndex;\r
1017 IndexArray[LineCount*3+1] = CurrIndex;\r
1018 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1019 LineCount ++;\r
1020 //\r
1021 // Reset offset and save begin position of line\r
1022 //\r
1023 GlyphOffset = 0;\r
1024 LineStartGlyphWidth = GlyphWidth;\r
1025 PrevCurrIndex = CurrIndex + 1;\r
1026 break;\r
1027\r
1028 //\r
1029 // char is '\r'\r
1030 // "\r\n" and "\r" both are handled here\r
1031 //\r
1032 case CHAR_CARRIAGE_RETURN:\r
1033 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {\r
1034 //\r
1035 // next char is '\n'\r
1036 //\r
1037 IndexArray[LineCount*3] = PrevCurrIndex;\r
1038 IndexArray[LineCount*3+1] = CurrIndex;\r
1039 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1040 LineCount ++;\r
1041 CurrIndex ++;\r
1042 }\r
1043 GlyphOffset = 0;\r
1044 LineStartGlyphWidth = GlyphWidth;\r
1045 PrevCurrIndex = CurrIndex + 1;\r
1046 break;\r
1047\r
1048 //\r
1049 // char is space or other char\r
1050 //\r
1051 default:\r
1052 GlyphOffset += GlyphWidth;\r
1053 if (GlyphOffset >= BlockWidth) {\r
1054 if (LastSpaceIndex > PrevCurrIndex) {\r
1055 //\r
1056 // LastSpaceIndex points to space inside current screen-line,\r
1057 // restore to LastSpaceIndex\r
1058 // (Otherwise the word is too long to fit one screen-line, just cut it)\r
1059 //\r
1060 CurrIndex = LastSpaceIndex;\r
1061 GlyphWidth = LastSpaceGlyphWidth;\r
1062 } else if (GlyphOffset > BlockWidth) {\r
1063 //\r
1064 // the word is too long to fit one screen-line and we don't get the chance\r
1065 // of GlyphOffset == BlockWidth because GlyphWidth = 2\r
1066 //\r
1067 CurrIndex --;\r
1068 }\r
1069\r
1070 IndexArray[LineCount*3] = PrevCurrIndex;\r
1071 IndexArray[LineCount*3+1] = CurrIndex + 1;\r
1072 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1073 LineStartGlyphWidth = GlyphWidth;\r
1074 LineCount ++;\r
1075 //\r
1076 // Reset offset and save begin position of line\r
1077 //\r
1078 GlyphOffset = 0;\r
1079 PrevCurrIndex = CurrIndex + 1;\r
1080 }\r
1081\r
1082 //\r
1083 // LastSpaceIndex: remember position of last space\r
1084 //\r
1085 if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
1086 LastSpaceIndex = CurrIndex;\r
1087 LastSpaceGlyphWidth = GlyphWidth;\r
1088 }\r
1089 break;\r
1090 }\r
1091 }\r
1092\r
1093 if (GlyphOffset > 0) {\r
1094 IndexArray[LineCount*3] = PrevCurrIndex;\r
1095 IndexArray[LineCount*3+1] = CurrIndex;\r
1096 IndexArray[LineCount*3+2] = GlyphWidth;\r
1097 LineCount ++;\r
1098 }\r
1099\r
1100 if (LineCount == 0) {\r
1101 //\r
1102 // in case we meet null string\r
1103 //\r
1104 IndexArray[0] = 0;\r
1105 IndexArray[1] = 1;\r
1106 //\r
1107 // we assume null string's glyph width is 1\r
1108 //\r
1109 IndexArray[1] = 1;\r
1110 LineCount ++;\r
1111 }\r
1112\r
1113 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));\r
1114 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);\r
40a06b0c 1115 ASSERT (*FormattedString != NULL);\r
c60a0616 1116\r
1117 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {\r
1118 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);\r
1119 StrnCpy (\r
1120 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,\r
1121 StringPtr + IndexArray[CurrIndex*3],\r
1122 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]\r
1123 );\r
1124 }\r
1125\r
f4113e1f 1126 FreePool (IndexArray);\r
c60a0616 1127}\r