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