]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/ProcessOptions.c
Update the copyright notice format
[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
e5eed7d3
HT
5Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
c60a0616 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
b86b413a
LG
424 //\r
425 // Check whether there are Options of this OrderedList\r
426 //\r
427 if (IsListEmpty (&Question->OptionListHead)) {\r
428 break;\r
429 }\r
c60a0616 430 //\r
431 // Initialize Option value array\r
432 //\r
d02847d3 433 if (GetArrayData (ValueArray, ValueType, 0) == 0) {\r
c60a0616 434 GetQuestionDefault (Selection->FormSet, Selection->Form, Question, 0);\r
435 }\r
436\r
437 if (Selected) {\r
438 //\r
439 // Go ask for input\r
440 //\r
441 Status = GetSelectionInputPopUp (Selection, MenuOption);\r
442 } else {\r
443 //\r
444 // We now know how many strings we will have, so we can allocate the\r
445 // space required for the array or strings.\r
446 //\r
447 *OptionString = AllocateZeroPool (Question->MaxContainers * BufferSize);\r
448 ASSERT (*OptionString);\r
449\r
d02847d3 450 HiiValue.Type = ValueType;\r
c60a0616 451 HiiValue.Value.u64 = 0;\r
452 for (Index = 0; Index < Question->MaxContainers; Index++) {\r
d02847d3 453 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
454 if (HiiValue.Value.u64 == 0) {\r
c60a0616 455 //\r
456 // Values for the options in ordered lists should never be a 0\r
457 //\r
458 break;\r
459 }\r
460\r
461 OneOfOption = ValueToOption (Question, &HiiValue);\r
462 if (OneOfOption == NULL) {\r
8d00a0f1 463 //\r
464 // Show error message\r
465 //\r
466 do {\r
467 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
468 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
469\r
470 //\r
471 // The initial value of the orderedlist is invalid, force to be valid value\r
472 //\r
473 Link = GetFirstNode (&Question->OptionListHead);\r
474 Index2 = 0;\r
475 while (!IsNull (&Question->OptionListHead, Link) && Index2 < Question->MaxContainers) {\r
476 Option = QUESTION_OPTION_FROM_LINK (Link);\r
d02847d3 477 SetArrayData (ValueArray, ValueType, Index2, Option->Value.Value.u64);\r
478 Index2++;\r
8d00a0f1 479 Link = GetNextNode (&Question->OptionListHead, Link);\r
480 }\r
d02847d3 481 SetArrayData (ValueArray, ValueType, Index2, 0);\r
8d00a0f1 482\r
483 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
484 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
485\r
f4113e1f 486 FreePool (*OptionString);\r
8d00a0f1 487 *OptionString = NULL;\r
c60a0616 488 return EFI_NOT_FOUND;\r
489 }\r
490\r
491 Suppress = FALSE;\r
492 if ((OneOfOption->SuppressExpression != NULL) &&\r
493 (OneOfOption->SuppressExpression->Result.Value.b)) {\r
494 //\r
495 // This option is suppressed\r
496 //\r
497 Suppress = TRUE;\r
498 }\r
499\r
500 if (!Suppress) {\r
501 Character[0] = LEFT_ONEOF_DELIMITER;\r
502 NewStrCat (OptionString[0], Character);\r
503 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
504 NewStrCat (OptionString[0], StringPtr);\r
505 Character[0] = RIGHT_ONEOF_DELIMITER;\r
506 NewStrCat (OptionString[0], Character);\r
507 Character[0] = CHAR_CARRIAGE_RETURN;\r
508 NewStrCat (OptionString[0], Character);\r
509\r
f4113e1f 510 FreePool (StringPtr);\r
c60a0616 511 }\r
512 }\r
513 }\r
514 break;\r
515\r
516 case EFI_IFR_ONE_OF_OP:\r
b86b413a
LG
517 //\r
518 // Check whether there are Options of this OneOf\r
519 //\r
520 if (IsListEmpty (&Question->OptionListHead)) {\r
521 break;\r
522 }\r
c60a0616 523 if (Selected) {\r
524 //\r
525 // Go ask for input\r
526 //\r
527 Status = GetSelectionInputPopUp (Selection, MenuOption);\r
528 } else {\r
529 *OptionString = AllocateZeroPool (BufferSize);\r
530 ASSERT (*OptionString);\r
531\r
532 OneOfOption = ValueToOption (Question, QuestionValue);\r
533 if (OneOfOption == NULL) {\r
8d00a0f1 534 //\r
535 // Show error message\r
536 //\r
537 do {\r
538 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gOptionMismatch, gPressEnter, gEmptyString);\r
539 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
540\r
541 //\r
542 // Force the Question value to be valid\r
543 //\r
544 Link = GetFirstNode (&Question->OptionListHead);\r
545 while (!IsNull (&Question->OptionListHead, Link)) {\r
546 Option = QUESTION_OPTION_FROM_LINK (Link);\r
547\r
548 if ((Option->SuppressExpression == NULL) ||\r
549 !Option->SuppressExpression->Result.Value.b) {\r
550 CopyMem (QuestionValue, &Option->Value, sizeof (EFI_HII_VALUE));\r
551 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
552 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
553 break;\r
554 }\r
555\r
556 Link = GetNextNode (&Question->OptionListHead, Link);\r
557 }\r
558\r
f4113e1f 559 FreePool (*OptionString);\r
8d00a0f1 560 *OptionString = NULL;\r
40a06b0c 561 return EFI_NOT_FOUND;\r
c60a0616 562 }\r
563\r
564 if ((OneOfOption->SuppressExpression != NULL) &&\r
565 (OneOfOption->SuppressExpression->Result.Value.b)) {\r
566 //\r
567 // This option is suppressed\r
568 //\r
569 Suppress = TRUE;\r
570 } else {\r
571 Suppress = FALSE;\r
572 }\r
573\r
574 if (Suppress) {\r
575 //\r
576 // Current selected option happen to be suppressed,\r
577 // enforce to select on a non-suppressed option\r
578 //\r
579 Link = GetFirstNode (&Question->OptionListHead);\r
580 while (!IsNull (&Question->OptionListHead, Link)) {\r
581 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
582\r
583 if ((OneOfOption->SuppressExpression == NULL) ||\r
584 !OneOfOption->SuppressExpression->Result.Value.b) {\r
585 Suppress = FALSE;\r
586 CopyMem (QuestionValue, &OneOfOption->Value, sizeof (EFI_HII_VALUE));\r
587 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
8d00a0f1 588 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
589 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
c60a0616 590 break;\r
591 }\r
592\r
593 Link = GetNextNode (&Question->OptionListHead, Link);\r
594 }\r
595 }\r
596\r
597 if (!Suppress) {\r
598 Character[0] = LEFT_ONEOF_DELIMITER;\r
599 NewStrCat (OptionString[0], Character);\r
600 StringPtr = GetToken (OneOfOption->Text, Selection->Handle);\r
601 NewStrCat (OptionString[0], StringPtr);\r
602 Character[0] = RIGHT_ONEOF_DELIMITER;\r
603 NewStrCat (OptionString[0], Character);\r
604\r
f4113e1f 605 FreePool (StringPtr);\r
c60a0616 606 }\r
607 }\r
608 break;\r
609\r
610 case EFI_IFR_CHECKBOX_OP:\r
611 *OptionString = AllocateZeroPool (BufferSize);\r
612 ASSERT (*OptionString);\r
613\r
614 *OptionString[0] = LEFT_CHECKBOX_DELIMITER;\r
615\r
616 if (Selected) {\r
617 //\r
618 // Since this is a BOOLEAN operation, flip it upon selection\r
619 //\r
620 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
621\r
622 //\r
623 // Perform inconsistent check\r
624 //\r
625 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
626 if (EFI_ERROR (Status)) {\r
627 //\r
628 // Inconsistent check fail, restore Question Value\r
629 //\r
630 QuestionValue->Value.b = (BOOLEAN) (QuestionValue->Value.b ? FALSE : TRUE);\r
f4113e1f 631 FreePool (*OptionString);\r
8d00a0f1 632 *OptionString = NULL;\r
c60a0616 633 return Status;\r
634 }\r
635\r
636 //\r
637 // Save Question value\r
638 //\r
639 Status = SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
640 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
641 }\r
642\r
643 if (QuestionValue->Value.b) {\r
644 *(OptionString[0] + 1) = CHECK_ON;\r
645 } else {\r
646 *(OptionString[0] + 1) = CHECK_OFF;\r
647 }\r
648 *(OptionString[0] + 2) = RIGHT_CHECKBOX_DELIMITER;\r
649 break;\r
650\r
651 case EFI_IFR_NUMERIC_OP:\r
652 if (Selected) {\r
653 //\r
654 // Go ask for input\r
655 //\r
656 Status = GetNumericInput (Selection, MenuOption);\r
657 } else {\r
658 *OptionString = AllocateZeroPool (BufferSize);\r
659 ASSERT (*OptionString);\r
660\r
661 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
662\r
663 //\r
664 // Formatted print\r
665 //\r
666 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
667 Number = (UINT16) GetStringWidth (FormattedNumber);\r
668 CopyMem (OptionString[0] + 1, FormattedNumber, Number);\r
669\r
670 *(OptionString[0] + Number / 2) = RIGHT_NUMERIC_DELIMITER;\r
671 }\r
672 break;\r
673\r
674 case EFI_IFR_DATE_OP:\r
675 if (Selected) {\r
676 //\r
677 // This is similar to numerics\r
678 //\r
679 Status = GetNumericInput (Selection, MenuOption);\r
680 } else {\r
681 *OptionString = AllocateZeroPool (BufferSize);\r
682 ASSERT (*OptionString);\r
683\r
684 switch (MenuOption->Sequence) {\r
685 case 0:\r
686 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
687 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Month);\r
688 *(OptionString[0] + 3) = DATE_SEPARATOR;\r
689 break;\r
690\r
691 case 1:\r
692 SetUnicodeMem (OptionString[0], 4, L' ');\r
693 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.date.Day);\r
694 *(OptionString[0] + 6) = DATE_SEPARATOR;\r
695 break;\r
696\r
697 case 2:\r
698 SetUnicodeMem (OptionString[0], 7, L' ');\r
699 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%4d", QuestionValue->Value.date.Year);\r
700 *(OptionString[0] + 11) = RIGHT_NUMERIC_DELIMITER;\r
701 break;\r
702 }\r
703 }\r
704 break;\r
705\r
706 case EFI_IFR_TIME_OP:\r
707 if (Selected) {\r
708 //\r
709 // This is similar to numerics\r
710 //\r
711 Status = GetNumericInput (Selection, MenuOption);\r
712 } else {\r
713 *OptionString = AllocateZeroPool (BufferSize);\r
714 ASSERT (*OptionString);\r
715\r
716 switch (MenuOption->Sequence) {\r
717 case 0:\r
718 *OptionString[0] = LEFT_NUMERIC_DELIMITER;\r
719 UnicodeSPrint (OptionString[0] + 1, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Hour);\r
720 *(OptionString[0] + 3) = TIME_SEPARATOR;\r
721 break;\r
722\r
723 case 1:\r
724 SetUnicodeMem (OptionString[0], 4, L' ');\r
725 UnicodeSPrint (OptionString[0] + 4, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Minute);\r
726 *(OptionString[0] + 6) = TIME_SEPARATOR;\r
727 break;\r
728\r
729 case 2:\r
730 SetUnicodeMem (OptionString[0], 7, L' ');\r
731 UnicodeSPrint (OptionString[0] + 7, 21 * sizeof (CHAR16), L"%02d", QuestionValue->Value.time.Second);\r
732 *(OptionString[0] + 9) = RIGHT_NUMERIC_DELIMITER;\r
733 break;\r
734 }\r
735 }\r
736 break;\r
737\r
738 case EFI_IFR_STRING_OP:\r
739 if (Selected) {\r
740 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
741 ASSERT (StringPtr);\r
742\r
743 Status = ReadString (MenuOption, gPromptForData, StringPtr);\r
744 if (!EFI_ERROR (Status)) {\r
745 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
746 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
747\r
748 UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
749 }\r
750\r
f4113e1f 751 FreePool (StringPtr);\r
c60a0616 752 } else {\r
753 *OptionString = AllocateZeroPool (BufferSize);\r
754 ASSERT (*OptionString);\r
755\r
756 if (((CHAR16 *) Question->BufferValue)[0] == 0x0000) {\r
757 *(OptionString[0]) = '_';\r
758 } else {\r
759 if ((Maximum * sizeof (CHAR16)) < BufferSize) {\r
760 BufferSize = Maximum * sizeof (CHAR16);\r
761 }\r
762 CopyMem (OptionString[0], (CHAR16 *) Question->BufferValue, BufferSize);\r
763 }\r
764 }\r
765 break;\r
766\r
767 case EFI_IFR_PASSWORD_OP:\r
768 if (Selected) {\r
769 StringPtr = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
770 ASSERT (StringPtr);\r
771\r
772 //\r
773 // For interactive passwords, old password is validated by callback\r
774 //\r
775 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
776 //\r
777 // Use a NULL password to test whether old password is required\r
778 //\r
779 *StringPtr = 0;\r
780 Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
781 if (Status == EFI_NOT_AVAILABLE_YET) {\r
782 //\r
783 // Callback request to terminate password input\r
784 //\r
f4113e1f 785 FreePool (StringPtr);\r
c60a0616 786 return EFI_SUCCESS;\r
787 }\r
788\r
789 if (EFI_ERROR (Status)) {\r
790 //\r
791 // Old password exist, ask user for the old password\r
792 //\r
793 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
794 if (EFI_ERROR (Status)) {\r
f4113e1f 795 FreePool (StringPtr);\r
c60a0616 796 return Status;\r
797 }\r
798\r
799 //\r
800 // Check user input old password\r
801 //\r
802 Status = PasswordCallback (Selection, MenuOption, StringPtr);\r
803 if (EFI_ERROR (Status)) {\r
804 if (Status == EFI_NOT_READY) {\r
805 //\r
806 // Typed in old password incorrect\r
807 //\r
808 PasswordInvalid ();\r
809 } else {\r
810 Status = EFI_SUCCESS;\r
811 }\r
812\r
f4113e1f 813 FreePool (StringPtr);\r
c60a0616 814 return Status;\r
815 }\r
816 }\r
817 } else {\r
818 //\r
819 // For non-interactive password, validate old password in local\r
820 //\r
821 if (*((CHAR16 *) Question->BufferValue) != 0) {\r
822 //\r
823 // There is something there! Prompt for password\r
824 //\r
825 Status = ReadString (MenuOption, gPromptForPassword, StringPtr);\r
826 if (EFI_ERROR (Status)) {\r
f4113e1f 827 FreePool (StringPtr);\r
c60a0616 828 return Status;\r
829 }\r
830\r
831 TempString = AllocateCopyPool ((Maximum + 1) * sizeof (CHAR16), Question->BufferValue);\r
40a06b0c 832 ASSERT (TempString != NULL);\r
8b0fc5c1 833\r
c60a0616 834 TempString[Maximum] = L'\0';\r
835\r
836 if (StrCmp (StringPtr, TempString) != 0) {\r
837 //\r
838 // Typed in old password incorrect\r
839 //\r
840 PasswordInvalid ();\r
841\r
f4113e1f 842 FreePool (StringPtr);\r
843 FreePool (TempString);\r
c60a0616 844 return Status;\r
845 }\r
846\r
f4113e1f 847 FreePool (TempString);\r
c60a0616 848 }\r
849 }\r
850\r
851 //\r
852 // Ask for new password\r
853 //\r
854 ZeroMem (StringPtr, (Maximum + 1) * sizeof (CHAR16));\r
855 Status = ReadString (MenuOption, gPromptForNewPassword, StringPtr);\r
856 if (EFI_ERROR (Status)) {\r
857 //\r
858 // Reset state machine for interactive password\r
859 //\r
860 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
861 PasswordCallback (Selection, MenuOption, NULL);\r
862 }\r
863\r
f4113e1f 864 FreePool (StringPtr);\r
c60a0616 865 return Status;\r
866 }\r
867\r
868 //\r
869 // Confirm new password\r
870 //\r
871 TempString = AllocateZeroPool ((Maximum + 1) * sizeof (CHAR16));\r
872 ASSERT (TempString);\r
873 Status = ReadString (MenuOption, gConfirmPassword, TempString);\r
874 if (EFI_ERROR (Status)) {\r
875 //\r
876 // Reset state machine for interactive password\r
877 //\r
878 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
879 PasswordCallback (Selection, MenuOption, NULL);\r
880 }\r
881\r
f4113e1f 882 FreePool (StringPtr);\r
883 FreePool (TempString);\r
c60a0616 884 return Status;\r
885 }\r
886\r
887 //\r
888 // Compare two typed-in new passwords\r
889 //\r
890 if (StrCmp (StringPtr, TempString) == 0) {\r
891 //\r
892 // Two password match, send it to Configuration Driver\r
893 //\r
894 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
895 PasswordCallback (Selection, MenuOption, StringPtr);\r
896 } else {\r
897 CopyMem (Question->BufferValue, StringPtr, Maximum * sizeof (CHAR16));\r
898 SetQuestionValue (Selection->FormSet, Selection->Form, Question, FALSE);\r
899 }\r
900 } else {\r
901 //\r
902 // Reset state machine for interactive password\r
903 //\r
904 if ((Question->QuestionFlags & EFI_IFR_FLAG_CALLBACK) != 0) {\r
905 PasswordCallback (Selection, MenuOption, NULL);\r
906 }\r
907\r
908 //\r
909 // Two password mismatch, prompt error message\r
910 //\r
911 do {\r
912 CreateDialog (4, TRUE, 0, NULL, &Key, gEmptyString, gConfirmError, gPressEnter, gEmptyString);\r
913 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
914 }\r
915\r
f4113e1f 916 FreePool (TempString);\r
917 FreePool (StringPtr);\r
c60a0616 918 }\r
919 break;\r
920\r
921 default:\r
922 break;\r
923 }\r
924\r
925 return Status;\r
926}\r
927\r
928\r
929/**\r
930 Process the help string: Split StringPtr to several lines of strings stored in\r
931 FormattedString and the glyph width of each line cannot exceed gHelpBlockWidth.\r
932\r
933 @param StringPtr The entire help string.\r
934 @param FormattedString The oupput formatted string.\r
935 @param RowCount TRUE: if Question is selected.\r
936\r
937**/\r
938VOID\r
939ProcessHelpString (\r
940 IN CHAR16 *StringPtr,\r
941 OUT CHAR16 **FormattedString,\r
942 IN UINTN RowCount\r
943 )\r
944{\r
f4113e1f 945 UINTN BlockWidth;\r
c60a0616 946 UINTN AllocateSize;\r
947 //\r
948 // [PrevCurrIndex, CurrIndex) forms a range of a screen-line\r
949 //\r
950 UINTN CurrIndex;\r
951 UINTN PrevCurrIndex;\r
952 UINTN LineCount;\r
953 UINTN VirtualLineCount;\r
954 //\r
955 // GlyphOffset stores glyph width of current screen-line\r
956 //\r
957 UINTN GlyphOffset;\r
958 //\r
959 // GlyphWidth equals to 2 if we meet width directive\r
960 //\r
961 UINTN GlyphWidth;\r
962 //\r
963 // during scanning, we remember the position of last space character\r
964 // in case that if next word cannot put in current line, we could restore back to the position\r
965 // of last space character\r
966 // while we should also remmeber the glyph width of the last space character for restoring\r
967 //\r
968 UINTN LastSpaceIndex;\r
969 UINTN LastSpaceGlyphWidth;\r
970 //\r
971 // every time we begin to form a new screen-line, we should remember glyph width of single character\r
972 // of last line\r
973 //\r
974 UINTN LineStartGlyphWidth;\r
975 UINTN *IndexArray;\r
976 UINTN *OldIndexArray;\r
977\r
f4113e1f 978 BlockWidth = (UINTN) gHelpBlockWidth - 1;\r
8b0fc5c1 979\r
c60a0616 980 //\r
981 // every three elements of IndexArray form a screen-line of string:[ IndexArray[i*3], IndexArray[i*3+1] )\r
982 // IndexArray[i*3+2] stores the initial glyph width of single character. to save this is because we want\r
983 // to bring the width directive of the last line to current screen-line.\r
984 // e.g.: "\wideabcde ... fghi", if "fghi" also has width directive but is splitted to the next screen-line\r
985 // different from that of "\wideabcde", we should remember the width directive.\r
986 //\r
987 AllocateSize = 0x20;\r
988 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
40a06b0c 989 ASSERT (IndexArray != NULL);\r
c60a0616 990\r
991 if (*FormattedString != NULL) {\r
f4113e1f 992 FreePool (*FormattedString);\r
c60a0616 993 *FormattedString = NULL;\r
994 }\r
995\r
996 for (PrevCurrIndex = 0, CurrIndex = 0, LineCount = 0, LastSpaceIndex = 0,\r
997 IndexArray[0] = 0, GlyphWidth = 1, GlyphOffset = 0, LastSpaceGlyphWidth = 1, LineStartGlyphWidth = 1;\r
998 (StringPtr[CurrIndex] != CHAR_NULL);\r
999 CurrIndex ++) {\r
1000\r
1001 if (LineCount == AllocateSize) {\r
1002 AllocateSize += 0x10;\r
1003 OldIndexArray = IndexArray;\r
1004 IndexArray = AllocatePool (AllocateSize * sizeof (UINTN) * 3);\r
bc166db3 1005 ASSERT (IndexArray != NULL);\r
8b0fc5c1 1006\r
c60a0616 1007 CopyMem (IndexArray, OldIndexArray, LineCount * sizeof (UINTN) * 3);\r
f4113e1f 1008 FreePool (OldIndexArray);\r
c60a0616 1009 }\r
1010 switch (StringPtr[CurrIndex]) {\r
1011\r
1012 case NARROW_CHAR:\r
1013 case WIDE_CHAR:\r
1014 GlyphWidth = ((StringPtr[CurrIndex] == WIDE_CHAR) ? 2 : 1);\r
1015 if (CurrIndex == 0) {\r
1016 LineStartGlyphWidth = GlyphWidth;\r
1017 }\r
1018 break;\r
1019\r
1020 //\r
1021 // char is '\n'\r
1022 // "\r\n" isn't handled here, handled by case CHAR_CARRIAGE_RETURN\r
1023 //\r
1024 case CHAR_LINEFEED:\r
1025 //\r
1026 // Store a range of string as a line\r
1027 //\r
1028 IndexArray[LineCount*3] = PrevCurrIndex;\r
1029 IndexArray[LineCount*3+1] = CurrIndex;\r
1030 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1031 LineCount ++;\r
1032 //\r
1033 // Reset offset and save begin position of line\r
1034 //\r
1035 GlyphOffset = 0;\r
1036 LineStartGlyphWidth = GlyphWidth;\r
1037 PrevCurrIndex = CurrIndex + 1;\r
1038 break;\r
1039\r
1040 //\r
1041 // char is '\r'\r
1042 // "\r\n" and "\r" both are handled here\r
1043 //\r
1044 case CHAR_CARRIAGE_RETURN:\r
1045 if (StringPtr[CurrIndex + 1] == CHAR_LINEFEED) {\r
1046 //\r
1047 // next char is '\n'\r
1048 //\r
1049 IndexArray[LineCount*3] = PrevCurrIndex;\r
1050 IndexArray[LineCount*3+1] = CurrIndex;\r
1051 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1052 LineCount ++;\r
1053 CurrIndex ++;\r
1054 }\r
1055 GlyphOffset = 0;\r
1056 LineStartGlyphWidth = GlyphWidth;\r
1057 PrevCurrIndex = CurrIndex + 1;\r
1058 break;\r
1059\r
1060 //\r
1061 // char is space or other char\r
1062 //\r
1063 default:\r
1064 GlyphOffset += GlyphWidth;\r
1065 if (GlyphOffset >= BlockWidth) {\r
1066 if (LastSpaceIndex > PrevCurrIndex) {\r
1067 //\r
1068 // LastSpaceIndex points to space inside current screen-line,\r
1069 // restore to LastSpaceIndex\r
1070 // (Otherwise the word is too long to fit one screen-line, just cut it)\r
1071 //\r
1072 CurrIndex = LastSpaceIndex;\r
1073 GlyphWidth = LastSpaceGlyphWidth;\r
1074 } else if (GlyphOffset > BlockWidth) {\r
1075 //\r
1076 // the word is too long to fit one screen-line and we don't get the chance\r
1077 // of GlyphOffset == BlockWidth because GlyphWidth = 2\r
1078 //\r
1079 CurrIndex --;\r
1080 }\r
1081\r
1082 IndexArray[LineCount*3] = PrevCurrIndex;\r
1083 IndexArray[LineCount*3+1] = CurrIndex + 1;\r
1084 IndexArray[LineCount*3+2] = LineStartGlyphWidth;\r
1085 LineStartGlyphWidth = GlyphWidth;\r
1086 LineCount ++;\r
1087 //\r
1088 // Reset offset and save begin position of line\r
1089 //\r
1090 GlyphOffset = 0;\r
1091 PrevCurrIndex = CurrIndex + 1;\r
1092 }\r
1093\r
1094 //\r
1095 // LastSpaceIndex: remember position of last space\r
1096 //\r
1097 if (StringPtr[CurrIndex] == CHAR_SPACE) {\r
1098 LastSpaceIndex = CurrIndex;\r
1099 LastSpaceGlyphWidth = GlyphWidth;\r
1100 }\r
1101 break;\r
1102 }\r
1103 }\r
1104\r
1105 if (GlyphOffset > 0) {\r
1106 IndexArray[LineCount*3] = PrevCurrIndex;\r
1107 IndexArray[LineCount*3+1] = CurrIndex;\r
1108 IndexArray[LineCount*3+2] = GlyphWidth;\r
1109 LineCount ++;\r
1110 }\r
1111\r
1112 if (LineCount == 0) {\r
1113 //\r
1114 // in case we meet null string\r
1115 //\r
1116 IndexArray[0] = 0;\r
1117 IndexArray[1] = 1;\r
1118 //\r
1119 // we assume null string's glyph width is 1\r
1120 //\r
1121 IndexArray[1] = 1;\r
1122 LineCount ++;\r
1123 }\r
1124\r
1125 VirtualLineCount = RowCount * (LineCount / RowCount + (LineCount % RowCount > 0));\r
1126 *FormattedString = AllocateZeroPool (VirtualLineCount * (BlockWidth + 1) * sizeof (CHAR16) * 2);\r
40a06b0c 1127 ASSERT (*FormattedString != NULL);\r
c60a0616 1128\r
1129 for (CurrIndex = 0; CurrIndex < LineCount; CurrIndex ++) {\r
1130 *(*FormattedString + CurrIndex * 2 * (BlockWidth + 1)) = (CHAR16) ((IndexArray[CurrIndex*3+2] == 2) ? WIDE_CHAR : NARROW_CHAR);\r
1131 StrnCpy (\r
1132 *FormattedString + CurrIndex * 2 * (BlockWidth + 1) + 1,\r
1133 StringPtr + IndexArray[CurrIndex*3],\r
1134 IndexArray[CurrIndex*3+1]-IndexArray[CurrIndex*3]\r
1135 );\r
1136 }\r
1137\r
f4113e1f 1138 FreePool (IndexArray);\r
c60a0616 1139}\r