]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg-UefiShellCommandLib: Add EFIAPI in VA_List library function
[mirror_edk2.git] / ShellPkg / Library / UefiShellCommandLib / UefiShellCommandLib.c
CommitLineData
a405b86d 1/** @file\r
2 Provides interface to shell internal functions for shell commands.\r
3\r
cf041fd7
RN
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
5 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
7\r
a405b86d 8 This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "UefiShellCommandLib.h"\r
19\r
a405b86d 20// STATIC local variables\r
21STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;\r
22STATIC SCRIPT_FILE_LIST mScriptList;\r
23STATIC ALIAS_LIST mAliasList;\r
24STATIC BOOLEAN mEchoState;\r
25STATIC BOOLEAN mExitRequested;\r
b6b22b13 26STATIC UINT64 mExitCode;\r
a405b86d 27STATIC BOOLEAN mExitScript;\r
28STATIC CHAR16 *mProfileList;\r
29STATIC UINTN mProfileListSize;\r
30STATIC UINTN mFsMaxCount = 0;\r
31STATIC UINTN mBlkMaxCount = 0;\r
32STATIC BUFFER_LIST mFileHandleList;\r
0fcf8d4d 33STATIC CHAR16 *mRawCmdLine = NULL;\r
a405b86d 34\r
3bd89603
LE
35STATIC CONST CHAR8 Hex[] = {\r
36 '0',\r
37 '1',\r
38 '2',\r
39 '3',\r
40 '4',\r
41 '5',\r
42 '6',\r
43 '7',\r
44 '8',\r
45 '9',\r
46 'A',\r
47 'B',\r
48 'C',\r
49 'D',\r
50 'E',\r
51 'F'\r
52};\r
53\r
a405b86d 54// global variables required by library class.\r
a405b86d 55EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;\r
a405b86d 56SHELL_MAP_LIST gShellMapList;\r
57SHELL_MAP_LIST *gShellCurDir = NULL;\r
58\r
59CONST CHAR16* SupportLevel[] = {\r
60 L"Minimal",\r
61 L"Scripting",\r
62 L"Basic",\r
63 L"Interactive"\r
64};\r
65\r
66/**\r
67 Function to make sure that the global protocol pointers are valid.\r
68 must be called after constructor before accessing the pointers.\r
69**/\r
70EFI_STATUS\r
71EFIAPI\r
72CommandInit(\r
73 VOID\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
a405b86d 77 if (gUnicodeCollation == NULL) {\r
78 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
79 if (EFI_ERROR(Status)) {\r
80 return (EFI_DEVICE_ERROR);\r
81 }\r
82 }\r
a405b86d 83 return (EFI_SUCCESS);\r
84}\r
85\r
c0bcd343
RN
86/**\r
87 Return the pointer to the first occurrence of any character from a list of characters.\r
88\r
89 @param[in] String The string to parse\r
90 @param[in] CharacterList The list of character to look for\r
91 @param[in] IgnoreEscapedCharacter TRUE to ignore escaped characters\r
92\r
93 @return The location of the first character in the String.\r
94 @return Pointer to the ending NULL character of the String.\r
95**/\r
96CONST CHAR16*\r
97EFIAPI\r
98ShellFindFirstCharacter (\r
99 IN CONST CHAR16 *String,\r
100 IN CONST CHAR16 *CharacterList,\r
101 IN CONST BOOLEAN IgnoreEscapedCharacter\r
102 )\r
103{\r
104 UINTN WalkChar;\r
105 UINTN WalkStr;\r
106\r
107 for (WalkStr = 0; WalkStr < StrLen (String); WalkStr++) {\r
108 if (IgnoreEscapedCharacter && (String[WalkStr] == L'^')) {\r
109 WalkStr++;\r
110 continue;\r
111 }\r
112 for (WalkChar = 0; WalkChar < StrLen (CharacterList); WalkChar++) {\r
113 if (String[WalkStr] == CharacterList[WalkChar]) {\r
114 return &String[WalkStr];\r
115 }\r
116 }\r
117 }\r
118 return &String[WalkStr];\r
119}\r
120\r
121/**\r
122 Return the next parameter's end from a command line string.\r
123\r
124 @param[in] String the string to parse\r
125**/\r
126CONST CHAR16*\r
127FindEndOfParameter(\r
128 IN CONST CHAR16 *String\r
129 )\r
130{\r
131 CONST CHAR16 *First;\r
132 CONST CHAR16 *CloseQuote;\r
133\r
134 First = ShellFindFirstCharacter (String, L" \"", TRUE);\r
135\r
136 //\r
137 // nothing, all one parameter remaining\r
138 //\r
139 if (*First == CHAR_NULL) {\r
140 return (First);\r
141 }\r
142\r
143 //\r
144 // If space before a quote (or neither found, i.e. both CHAR_NULL),\r
145 // then that's the end.\r
146 //\r
147 if (*First == L' ') {\r
148 return (First);\r
149 }\r
150\r
151 CloseQuote = ShellFindFirstCharacter (First+1, L"\"", TRUE);\r
152\r
153 //\r
154 // We did not find a terminator...\r
155 //\r
156 if (*CloseQuote == CHAR_NULL) {\r
157 return (NULL);\r
158 }\r
159\r
160 return (FindEndOfParameter (CloseQuote+1));\r
161}\r
162\r
163/**\r
164 Return the next parameter from a command line string.\r
165\r
166 This function moves the next parameter from Walker into NextParameter and moves\r
167 Walker up past that parameter for recursive calling. When the final parameter\r
168 is moved *Walker will be set to NULL;\r
169\r
170 This will also remove all remaining ^ characters after processing.\r
171\r
172 @param[in, out] Walker pointer to string of command line. Adjusted to\r
173 reminaing command line on return\r
174 @param[in, out] NextParameter pointer to string of command line item extracted.\r
175 @param[in] Length buffer size of TempParameter.\r
176 @param[in] StripQuotation if TRUE then strip the quotation marks surrounding\r
177 the parameters.\r
178\r
179 @return EFI_INALID_PARAMETER A required parameter was NULL or pointed to a NULL or empty string.\r
180 @return EFI_NOT_FOUND A closing " could not be found on the specified string\r
181**/\r
182EFI_STATUS\r
183EFIAPI\r
184ShellGetNextParameter (\r
185 IN OUT CHAR16 **Walker,\r
186 IN OUT CHAR16 *NextParameter,\r
187 IN CONST UINTN Length,\r
188 IN BOOLEAN StripQuotation\r
189 )\r
190{\r
191 CONST CHAR16 *NextDelim;\r
192\r
193 if (Walker == NULL\r
194 ||*Walker == NULL\r
195 ||NextParameter == NULL\r
196 ){\r
197 return EFI_INVALID_PARAMETER;\r
198 }\r
199\r
200 //\r
201 // make sure we dont have any leading spaces\r
202 //\r
203 while ((*Walker)[0] == L' ') {\r
204 (*Walker)++;\r
205 }\r
206\r
207 //\r
208 // make sure we still have some params now...\r
209 //\r
210 if (StrLen(*Walker) == 0) {\r
211 DEBUG_CODE (\r
212 *Walker = NULL;\r
213 );\r
214 return (EFI_INVALID_PARAMETER);\r
215 }\r
216\r
217 NextDelim = FindEndOfParameter(*Walker);\r
218\r
219 if (NextDelim == NULL){\r
220 DEBUG_CODE (\r
221 *Walker = NULL;\r
222 );\r
223 return (EFI_NOT_FOUND);\r
224 }\r
225\r
226 StrnCpyS(NextParameter, Length / sizeof(CHAR16), (*Walker), NextDelim - *Walker);\r
227\r
228 //\r
229 // Add a CHAR_NULL if we didnt get one via the copy\r
230 //\r
231 if (*NextDelim != CHAR_NULL) {\r
232 NextParameter[NextDelim - *Walker] = CHAR_NULL;\r
233 }\r
234\r
235 //\r
236 // Update Walker for the next iteration through the function\r
237 //\r
238 *Walker = (CHAR16*)NextDelim;\r
239\r
240 //\r
241 // Remove any non-escaped quotes in the string\r
242 // Remove any remaining escape characters in the string\r
243 //\r
244 for (NextDelim = ShellFindFirstCharacter(NextParameter, L"\"^", FALSE)\r
245 ; *NextDelim != CHAR_NULL\r
246 ; NextDelim = ShellFindFirstCharacter(NextDelim, L"\"^", FALSE)\r
247 ) {\r
248 if (*NextDelim == L'^') {\r
249\r
250 //\r
251 // eliminate the escape ^\r
252 //\r
253 CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));\r
254 NextDelim++;\r
255 } else if (*NextDelim == L'\"') {\r
256\r
257 //\r
258 // eliminate the unescaped quote\r
259 //\r
260 if (StripQuotation) {\r
261 CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));\r
262 } else {\r
263 NextDelim++;\r
264 }\r
265 }\r
266 }\r
267\r
268 return EFI_SUCCESS;\r
269}\r
270\r
a405b86d 271/**\r
272 Constructor for the Shell Command library.\r
273\r
274 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.\r
275\r
276 @param ImageHandle the image handle of the process\r
277 @param SystemTable the EFI System Table pointer\r
278\r
279 @retval EFI_SUCCESS the initialization was complete sucessfully\r
280**/\r
281RETURN_STATUS\r
282EFIAPI\r
283ShellCommandLibConstructor (\r
284 IN EFI_HANDLE ImageHandle,\r
285 IN EFI_SYSTEM_TABLE *SystemTable\r
286 )\r
287{\r
288 EFI_STATUS Status;\r
289 InitializeListHead(&gShellMapList.Link);\r
290 InitializeListHead(&mCommandList.Link);\r
291 InitializeListHead(&mAliasList.Link);\r
292 InitializeListHead(&mScriptList.Link);\r
293 InitializeListHead(&mFileHandleList.Link);\r
294 mEchoState = TRUE;\r
295\r
296 mExitRequested = FALSE;\r
297 mExitScript = FALSE;\r
298 mProfileListSize = 0;\r
299 mProfileList = NULL;\r
300\r
301 if (gUnicodeCollation == NULL) {\r
302 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
303 if (EFI_ERROR(Status)) {\r
304 return (EFI_DEVICE_ERROR);\r
305 }\r
306 }\r
307\r
308 return (RETURN_SUCCESS);\r
309}\r
310\r
4f67c7ff
JC
311/**\r
312 Frees list of file handles.\r
313\r
314 @param[in] List The list to free.\r
315**/\r
316VOID\r
317EFIAPI\r
318FreeFileHandleList (\r
319 IN BUFFER_LIST *List\r
320 )\r
321{\r
322 BUFFER_LIST *BufferListEntry;\r
323\r
324 if (List == NULL){\r
325 return;\r
326 }\r
327 //\r
328 // enumerate through the buffer list and free all memory\r
329 //\r
330 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
331 ; !IsListEmpty (&List->Link)\r
332 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
333 ){\r
334 RemoveEntryList(&BufferListEntry->Link);\r
335 ASSERT(BufferListEntry->Buffer != NULL);\r
336 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);\r
337 SHELL_FREE_NON_NULL(BufferListEntry->Buffer);\r
338 SHELL_FREE_NON_NULL(BufferListEntry);\r
339 }\r
340}\r
341\r
a405b86d 342/**\r
343 Destructor for the library. free any resources.\r
344\r
345 @param ImageHandle the image handle of the process\r
346 @param SystemTable the EFI System Table pointer\r
347\r
348 @retval RETURN_SUCCESS this function always returns success\r
349**/\r
350RETURN_STATUS\r
351EFIAPI\r
352ShellCommandLibDestructor (\r
353 IN EFI_HANDLE ImageHandle,\r
354 IN EFI_SYSTEM_TABLE *SystemTable\r
355 )\r
356{\r
357 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
3f869579 358 ALIAS_LIST *Node2;\r
a405b86d 359 SCRIPT_FILE_LIST *Node3;\r
360 SHELL_MAP_LIST *MapNode;\r
361 //\r
362 // enumerate throught the list and free all the memory\r
363 //\r
364 while (!IsListEmpty (&mCommandList.Link)) {\r
365 Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);\r
366 RemoveEntryList(&Node->Link);\r
367 SHELL_FREE_NON_NULL(Node->CommandString);\r
368 FreePool(Node);\r
369 DEBUG_CODE(Node = NULL;);\r
370 }\r
371\r
372 //\r
3f869579 373 // enumerate through the alias list and free all memory\r
a405b86d 374 //\r
375 while (!IsListEmpty (&mAliasList.Link)) {\r
3f869579 376 Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);\r
a405b86d 377 RemoveEntryList(&Node2->Link);\r
378 SHELL_FREE_NON_NULL(Node2->CommandString);\r
3f869579 379 SHELL_FREE_NON_NULL(Node2->Alias);\r
380 SHELL_FREE_NON_NULL(Node2);\r
a405b86d 381 DEBUG_CODE(Node2 = NULL;);\r
382 }\r
383\r
384 //\r
385 // enumerate throught the list and free all the memory\r
386 //\r
387 while (!IsListEmpty (&mScriptList.Link)) {\r
388 Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
389 RemoveEntryList(&Node3->Link);\r
390 DeleteScriptFileStruct(Node3->Data);\r
391 FreePool(Node3);\r
392 }\r
393\r
394 //\r
395 // enumerate throught the mappings list and free all the memory\r
396 //\r
397 if (!IsListEmpty(&gShellMapList.Link)) {\r
398 for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
399 ; !IsListEmpty (&gShellMapList.Link)\r
400 ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
401 ){\r
402 ASSERT(MapNode != NULL);\r
403 RemoveEntryList(&MapNode->Link);\r
404 SHELL_FREE_NON_NULL(MapNode->DevicePath);\r
405 SHELL_FREE_NON_NULL(MapNode->MapName);\r
406 SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);\r
407 FreePool(MapNode);\r
408 }\r
409 }\r
410 if (!IsListEmpty(&mFileHandleList.Link)){\r
4f67c7ff 411 FreeFileHandleList(&mFileHandleList);\r
a405b86d 412 }\r
413\r
414 if (mProfileList != NULL) {\r
415 FreePool(mProfileList);\r
416 }\r
417\r
1a63ec8f 418 gUnicodeCollation = NULL;\r
1a63ec8f 419 gShellCurDir = NULL;\r
420\r
a405b86d 421 return (RETURN_SUCCESS);\r
422}\r
423\r
424/**\r
f5ba4007 425 Find a dynamic command protocol instance given a command name string.\r
cf812a20
JC
426\r
427 @param CommandString the command name string\r
428\r
429 @return instance the command protocol instance, if dynamic command instance found\r
430 @retval NULL no dynamic command protocol instance found for name\r
431**/\r
432CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *\r
433EFIAPI\r
434ShellCommandFindDynamicCommand (\r
435 IN CONST CHAR16 *CommandString\r
436 )\r
437{\r
438 EFI_STATUS Status;\r
439 EFI_HANDLE *CommandHandleList;\r
440 EFI_HANDLE *NextCommand;\r
441 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
442\r
443 CommandHandleList = GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid);\r
444 if (CommandHandleList == NULL) {\r
445 //\r
446 // not found or out of resources\r
447 //\r
448 return NULL; \r
449 }\r
450\r
451 for (NextCommand = CommandHandleList; *NextCommand != NULL; NextCommand++) {\r
452 Status = gBS->HandleProtocol(\r
453 *NextCommand,\r
454 &gEfiShellDynamicCommandProtocolGuid,\r
455 (VOID **)&DynamicCommand\r
456 );\r
457\r
458 if (EFI_ERROR(Status)) {\r
459 continue;\r
460 }\r
461\r
462 if (gUnicodeCollation->StriColl(\r
463 gUnicodeCollation,\r
464 (CHAR16*)CommandString,\r
465 (CHAR16*)DynamicCommand->CommandName) == 0 \r
466 ){\r
467 FreePool(CommandHandleList);\r
468 return (DynamicCommand);\r
469 }\r
470 }\r
471\r
472 FreePool(CommandHandleList);\r
473 return (NULL);\r
474}\r
475\r
476/**\r
477 Checks if a command exists as a dynamic command protocol instance\r
a405b86d 478\r
479 @param[in] CommandString The command string to check for on the list.\r
480**/\r
481BOOLEAN\r
482EFIAPI\r
cf812a20
JC
483ShellCommandDynamicCommandExists (\r
484 IN CONST CHAR16 *CommandString\r
485 )\r
486{\r
f5ba4007 487 return (BOOLEAN) ((ShellCommandFindDynamicCommand(CommandString) != NULL));\r
cf812a20
JC
488}\r
489\r
490/**\r
491 Checks if a command is already on the internal command list.\r
492\r
493 @param[in] CommandString The command string to check for on the list.\r
494**/\r
495BOOLEAN\r
496EFIAPI\r
497ShellCommandIsCommandOnInternalList(\r
498 IN CONST CHAR16 *CommandString\r
a405b86d 499 )\r
500{\r
501 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
502\r
503 //\r
504 // assert for NULL parameter\r
505 //\r
506 ASSERT(CommandString != NULL);\r
507\r
508 //\r
509 // check for the command\r
510 //\r
511 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
512 ; !IsNull(&mCommandList.Link, &Node->Link)\r
513 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
514 ){\r
515 ASSERT(Node->CommandString != NULL);\r
516 if (gUnicodeCollation->StriColl(\r
517 gUnicodeCollation,\r
518 (CHAR16*)CommandString,\r
519 Node->CommandString) == 0\r
520 ){\r
521 return (TRUE);\r
522 }\r
523 }\r
524 return (FALSE);\r
525}\r
526\r
527/**\r
cf812a20
JC
528 Checks if a command exists, either internally or through the dynamic command protocol.\r
529\r
530 @param[in] CommandString The command string to check for on the list.\r
531**/\r
532BOOLEAN\r
533EFIAPI\r
534ShellCommandIsCommandOnList(\r
535 IN CONST CHAR16 *CommandString\r
536 )\r
537{\r
538 if (ShellCommandIsCommandOnInternalList(CommandString)) {\r
539 return TRUE;\r
540 }\r
541\r
542 return ShellCommandDynamicCommandExists(CommandString);\r
543}\r
544\r
545/**\r
546 Get the help text for a dynamic command.\r
547\r
548 @param[in] CommandString The command name.\r
549\r
550 @retval NULL No help text was found.\r
551 @return String of help text. Caller required to free.\r
552**/\r
553CHAR16*\r
554EFIAPI\r
555ShellCommandGetDynamicCommandHelp(\r
556 IN CONST CHAR16 *CommandString\r
557 )\r
558{\r
559 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
560\r
561 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
562 if (DynamicCommand == NULL) {\r
563 return (NULL);\r
564 }\r
565\r
566 //\r
567 // TODO: how to get proper language?\r
568 //\r
569 return DynamicCommand->GetHelp(DynamicCommand, "en"); \r
570}\r
571\r
572/**\r
573 Get the help text for an internal command.\r
a405b86d 574\r
575 @param[in] CommandString The command name.\r
576\r
577 @retval NULL No help text was found.\r
578 @return String of help text. Caller reuiqred to free.\r
579**/\r
580CHAR16*\r
581EFIAPI\r
cf812a20 582ShellCommandGetInternalCommandHelp(\r
a405b86d 583 IN CONST CHAR16 *CommandString\r
584 )\r
585{\r
586 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
587\r
588 //\r
589 // assert for NULL parameter\r
590 //\r
591 ASSERT(CommandString != NULL);\r
592\r
593 //\r
594 // check for the command\r
595 //\r
596 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
597 ; !IsNull(&mCommandList.Link, &Node->Link)\r
598 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
599 ){\r
600 ASSERT(Node->CommandString != NULL);\r
601 if (gUnicodeCollation->StriColl(\r
602 gUnicodeCollation,\r
603 (CHAR16*)CommandString,\r
604 Node->CommandString) == 0\r
605 ){\r
606 return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));\r
607 }\r
608 }\r
609 return (NULL);\r
610}\r
611\r
cf812a20
JC
612/**\r
613 Get the help text for a command.\r
614\r
615 @param[in] CommandString The command name.\r
616\r
617 @retval NULL No help text was found.\r
618 @return String of help text.Caller reuiqred to free.\r
619**/\r
620CHAR16*\r
621EFIAPI\r
622ShellCommandGetCommandHelp (\r
623 IN CONST CHAR16 *CommandString\r
624 )\r
625{\r
626 CHAR16 *HelpStr;\r
627 HelpStr = ShellCommandGetInternalCommandHelp(CommandString);\r
628\r
629 if (HelpStr == NULL) {\r
630 HelpStr = ShellCommandGetDynamicCommandHelp(CommandString);\r
631 }\r
632\r
633 return HelpStr;\r
634}\r
635\r
636\r
a405b86d 637/**\r
638 Registers handlers of type SHELL_RUN_COMMAND and\r
639 SHELL_GET_MAN_FILENAME for each shell command.\r
640\r
641 If the ShellSupportLevel is greater than the value of the\r
642 PcdShellSupportLevel then return RETURN_UNSUPPORTED.\r
643\r
644 Registers the handlers specified by GetHelpInfoHandler and CommandHandler\r
645 with the command specified by CommandString. If the command named by\r
646 CommandString has already been registered, then return\r
647 RETURN_ALREADY_STARTED.\r
648\r
649 If there are not enough resources available to register the handlers then\r
650 RETURN_OUT_OF_RESOURCES is returned.\r
651\r
652 If CommandString is NULL, then ASSERT().\r
653 If GetHelpInfoHandler is NULL, then ASSERT().\r
654 If CommandHandler is NULL, then ASSERT().\r
655 If ProfileName is NULL, then ASSERT().\r
656\r
657 @param[in] CommandString Pointer to the command name. This is the\r
658 name to look for on the command line in\r
659 the shell.\r
660 @param[in] CommandHandler Pointer to a function that runs the\r
661 specified command.\r
662 @param[in] GetManFileName Pointer to a function that provides man\r
663 filename.\r
664 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this\r
665 function.\r
666 @param[in] ProfileName profile name to require for support of this\r
667 function.\r
668 @param[in] CanAffectLE indicates whether this command's return value\r
669 can change the LASTERROR environment variable.\r
670 @param[in] HiiHandle Handle of this command's HII entry.\r
671 @param[in] ManFormatHelp HII locator for the help text.\r
672\r
673 @retval RETURN_SUCCESS The handlers were registered.\r
674 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
675 register the shell command.\r
676 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the\r
677 currently allowed support level.\r
678 @retval RETURN_ALREADY_STARTED The CommandString represents a command that\r
679 is already registered. Only 1 handler set for\r
680 a given command is allowed.\r
681 @sa SHELL_GET_MAN_FILENAME\r
682 @sa SHELL_RUN_COMMAND\r
683**/\r
684RETURN_STATUS\r
685EFIAPI\r
686ShellCommandRegisterCommandName (\r
687 IN CONST CHAR16 *CommandString,\r
688 IN SHELL_RUN_COMMAND CommandHandler,\r
689 IN SHELL_GET_MAN_FILENAME GetManFileName,\r
690 IN UINT32 ShellMinSupportLevel,\r
691 IN CONST CHAR16 *ProfileName,\r
692 IN CONST BOOLEAN CanAffectLE,\r
693 IN CONST EFI_HANDLE HiiHandle,\r
694 IN CONST EFI_STRING_ID ManFormatHelp\r
695 )\r
696{\r
697 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
d51088b7 698 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Command;\r
699 SHELL_COMMAND_INTERNAL_LIST_ENTRY *PrevCommand;\r
700 INTN LexicalMatchValue;\r
701\r
702 //\r
703 // Initialize local variables.\r
704 //\r
705 Command = NULL;\r
706 PrevCommand = NULL;\r
707 LexicalMatchValue = 0;\r
a405b86d 708\r
709 //\r
710 // ASSERTs for NULL parameters\r
711 //\r
712 ASSERT(CommandString != NULL);\r
713 ASSERT(GetManFileName != NULL);\r
714 ASSERT(CommandHandler != NULL);\r
715 ASSERT(ProfileName != NULL);\r
716\r
717 //\r
718 // check for shell support level\r
719 //\r
720 if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {\r
721 return (RETURN_UNSUPPORTED);\r
722 }\r
723\r
724 //\r
725 // check for already on the list\r
726 //\r
727 if (ShellCommandIsCommandOnList(CommandString)) {\r
728 return (RETURN_ALREADY_STARTED);\r
729 }\r
730\r
731 //\r
732 // allocate memory for new struct\r
733 //\r
1a63ec8f 734 Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));\r
107d05a4
RN
735 if (Node == NULL) {\r
736 return RETURN_OUT_OF_RESOURCES;\r
737 }\r
53173337 738 Node->CommandString = AllocateCopyPool(StrSize(CommandString), CommandString);\r
107d05a4
RN
739 if (Node->CommandString == NULL) {\r
740 FreePool (Node);\r
741 return RETURN_OUT_OF_RESOURCES;\r
742 }\r
a405b86d 743\r
a405b86d 744 Node->GetManFileName = GetManFileName;\r
745 Node->CommandHandler = CommandHandler;\r
746 Node->LastError = CanAffectLE;\r
747 Node->HiiHandle = HiiHandle;\r
748 Node->ManFormatHelp = ManFormatHelp;\r
749\r
750 if ( StrLen(ProfileName)>0\r
751 && ((mProfileList != NULL\r
752 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)\r
753 ){\r
754 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));\r
755 if (mProfileList == NULL) {\r
756 //\r
757 // If this is the first make a leading ';'\r
758 //\r
759 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
760 }\r
761 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);\r
762 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
763 }\r
764\r
765 //\r
d51088b7 766 // Insert a new entry on top of the list\r
767 //\r
768 InsertHeadList (&mCommandList.Link, &Node->Link);\r
769\r
770 //\r
771 // Move a new registered command to its sorted ordered location in the list\r
a405b86d 772 //\r
d51088b7 773 for (Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link),\r
774 PrevCommand = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode (&mCommandList.Link)\r
775 ; !IsNull (&mCommandList.Link, &Command->Link)\r
776 ; Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode (&mCommandList.Link, &Command->Link)) {\r
777\r
778 //\r
779 // Get Lexical Comparison Value between PrevCommand and Command list entry\r
780 //\r
781 LexicalMatchValue = gUnicodeCollation->StriColl (\r
782 gUnicodeCollation,\r
783 PrevCommand->CommandString,\r
784 Command->CommandString\r
785 );\r
786\r
787 //\r
788 // Swap PrevCommand and Command list entry if PrevCommand list entry\r
789 // is alphabetically greater than Command list entry\r
790 //\r
791 if (LexicalMatchValue > 0){\r
792 Command = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *) SwapListEntries (&PrevCommand->Link, &Command->Link);\r
793 } else if (LexicalMatchValue < 0) {\r
794 //\r
795 // PrevCommand entry is lexically lower than Command entry\r
796 //\r
797 break;\r
798 }\r
799 }\r
a405b86d 800\r
801 return (RETURN_SUCCESS);\r
802}\r
803\r
804/**\r
805 Function to get the current Profile string.\r
806\r
807 @retval NULL There are no installed profiles.\r
808 @return A semi-colon delimited list of profiles.\r
809**/\r
810CONST CHAR16 *\r
811EFIAPI\r
812ShellCommandGetProfileList (\r
813 VOID\r
814 )\r
815{\r
816 return (mProfileList);\r
817}\r
818\r
819/**\r
820 Checks if a command string has been registered for CommandString and if so it runs\r
821 the previously registered handler for that command with the command line.\r
822\r
823 If CommandString is NULL, then ASSERT().\r
824\r
825 If Sections is specified, then each section name listed will be compared in a casesensitive\r
826 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,\r
827 it will be appended to the returned help text. If the section does not exist, no\r
828 information will be returned. If Sections is NULL, then all help text information\r
829 available will be returned.\r
830\r
4ff7e37b
ED
831 @param[in] CommandString Pointer to the command name. This is the name\r
832 found on the command line in the shell.\r
833 @param[in, out] RetVal Pointer to the return vaule from the command handler.\r
a405b86d 834\r
4ff7e37b
ED
835 @param[in, out] CanAffectLE indicates whether this command's return value\r
836 needs to be placed into LASTERROR environment variable.\r
a405b86d 837\r
838 @retval RETURN_SUCCESS The handler was run.\r
839 @retval RETURN_NOT_FOUND The CommandString did not match a registered\r
840 command name.\r
841 @sa SHELL_RUN_COMMAND\r
842**/\r
843RETURN_STATUS\r
844EFIAPI\r
845ShellCommandRunCommandHandler (\r
846 IN CONST CHAR16 *CommandString,\r
847 IN OUT SHELL_STATUS *RetVal,\r
848 IN OUT BOOLEAN *CanAffectLE OPTIONAL\r
849 )\r
850{\r
cf812a20
JC
851 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
852 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *DynamicCommand;\r
a405b86d 853\r
854 //\r
855 // assert for NULL parameters\r
856 //\r
857 ASSERT(CommandString != NULL);\r
858\r
859 //\r
860 // check for the command\r
861 //\r
862 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
863 ; !IsNull(&mCommandList.Link, &Node->Link)\r
864 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
865 ){\r
866 ASSERT(Node->CommandString != NULL);\r
867 if (gUnicodeCollation->StriColl(\r
868 gUnicodeCollation,\r
869 (CHAR16*)CommandString,\r
870 Node->CommandString) == 0\r
cf812a20 871 ){\r
a405b86d 872 if (CanAffectLE != NULL) {\r
873 *CanAffectLE = Node->LastError;\r
874 }\r
875 if (RetVal != NULL) {\r
876 *RetVal = Node->CommandHandler(NULL, gST);\r
877 } else {\r
878 Node->CommandHandler(NULL, gST);\r
879 }\r
880 return (RETURN_SUCCESS);\r
881 }\r
882 }\r
cf812a20
JC
883\r
884 //\r
885 // An internal command was not found, try to find a dynamic command\r
886 //\r
887 DynamicCommand = (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL *)ShellCommandFindDynamicCommand(CommandString);\r
888 if (DynamicCommand != NULL) {\r
889 if (RetVal != NULL) {\r
890 *RetVal = DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
891 } else {\r
892 DynamicCommand->Handler(DynamicCommand, gST, gEfiShellParametersProtocol, gEfiShellProtocol);\r
893 }\r
894 return (RETURN_SUCCESS);\r
895 }\r
896\r
a405b86d 897 return (RETURN_NOT_FOUND);\r
898}\r
899\r
900/**\r
901 Checks if a command string has been registered for CommandString and if so it\r
902 returns the MAN filename specified for that command.\r
903\r
904 If CommandString is NULL, then ASSERT().\r
905\r
906 @param[in] CommandString Pointer to the command name. This is the name\r
907 found on the command line in the shell.\\r
908\r
909 @retval NULL the commandString was not a registered command.\r
910 @return other the name of the MAN file.\r
911 @sa SHELL_GET_MAN_FILENAME\r
912**/\r
913CONST CHAR16*\r
914EFIAPI\r
915ShellCommandGetManFileNameHandler (\r
916 IN CONST CHAR16 *CommandString\r
917 )\r
918{\r
919 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
920\r
921 //\r
922 // assert for NULL parameters\r
923 //\r
924 ASSERT(CommandString != NULL);\r
925\r
926 //\r
927 // check for the command\r
928 //\r
929 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
930 ; !IsNull(&mCommandList.Link, &Node->Link)\r
931 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
932 ){\r
933 ASSERT(Node->CommandString != NULL);\r
934 if (gUnicodeCollation->StriColl(\r
935 gUnicodeCollation,\r
936 (CHAR16*)CommandString,\r
937 Node->CommandString) == 0\r
938 ){\r
939 return (Node->GetManFileName());\r
940 }\r
941 }\r
942 return (NULL);\r
943}\r
944\r
945/**\r
946 Get the list of all available shell internal commands. This is a linked list\r
947 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
948 list functions. do not modify the values.\r
949\r
1a63ec8f 950 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.\r
951\r
a405b86d 952 @return a Linked list of all available shell commands.\r
953**/\r
954CONST COMMAND_LIST*\r
955EFIAPI\r
956ShellCommandGetCommandList (\r
1a63ec8f 957 IN CONST BOOLEAN Sort\r
a405b86d 958 )\r
959{\r
1a63ec8f 960// if (!Sort) {\r
961// return ((COMMAND_LIST*)(&mCommandList));\r
962// }\r
a405b86d 963 return ((COMMAND_LIST*)(&mCommandList));\r
964}\r
965\r
966/**\r
967 Registers aliases to be set as part of the initialization of the shell application.\r
968\r
969 If Command is NULL, then ASSERT().\r
970 If Alias is NULL, then ASSERT().\r
971\r
972 @param[in] Command Pointer to the Command\r
973 @param[in] Alias Pointer to Alias\r
974\r
975 @retval RETURN_SUCCESS The handlers were registered.\r
976 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
977 register the shell command.\r
978**/\r
979RETURN_STATUS\r
980EFIAPI\r
981ShellCommandRegisterAlias (\r
982 IN CONST CHAR16 *Command,\r
983 IN CONST CHAR16 *Alias\r
984 )\r
985{\r
986 ALIAS_LIST *Node;\r
4ba9b812
TS
987 ALIAS_LIST *CommandAlias;\r
988 ALIAS_LIST *PrevCommandAlias; \r
989 INTN LexicalMatchValue;\r
a405b86d 990\r
991 //\r
992 // Asserts for NULL\r
993 //\r
994 ASSERT(Command != NULL);\r
995 ASSERT(Alias != NULL);\r
996\r
997 //\r
998 // allocate memory for new struct\r
999 //\r
1a63ec8f 1000 Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
107d05a4
RN
1001 if (Node == NULL) {\r
1002 return RETURN_OUT_OF_RESOURCES;\r
1003 }\r
53173337 1004 Node->CommandString = AllocateCopyPool(StrSize(Command), Command);\r
107d05a4
RN
1005 if (Node->CommandString == NULL) {\r
1006 FreePool (Node);\r
1007 return RETURN_OUT_OF_RESOURCES;\r
1008 }\r
53173337 1009 Node->Alias = AllocateCopyPool(StrSize(Alias), Alias);\r
107d05a4
RN
1010 if (Node->Alias == NULL) {\r
1011 FreePool (Node->CommandString);\r
1012 FreePool (Node);\r
1013 return RETURN_OUT_OF_RESOURCES;\r
1014 }\r
a405b86d 1015\r
4ba9b812
TS
1016 InsertHeadList (&mAliasList.Link, &Node->Link);\r
1017\r
a405b86d 1018 //\r
4ba9b812 1019 // Move a new pre-defined registered alias to its sorted ordered location in the list\r
a405b86d 1020 //\r
4ba9b812
TS
1021 for ( CommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link),\r
1022 PrevCommandAlias = (ALIAS_LIST *)GetFirstNode (&mAliasList.Link)\r
1023 ; !IsNull (&mAliasList.Link, &CommandAlias->Link)\r
1024 ; CommandAlias = (ALIAS_LIST *) GetNextNode (&mAliasList.Link, &CommandAlias->Link) ) {\r
1025 //\r
1026 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry\r
1027 //\r
1028 LexicalMatchValue = gUnicodeCollation->StriColl (\r
1029 gUnicodeCollation,\r
1030 PrevCommandAlias->Alias,\r
1031 CommandAlias->Alias\r
1032 );\r
1033\r
1034 //\r
1035 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry\r
1036 // is alphabetically greater than CommandAlias list entry\r
1037 // \r
1038 if (LexicalMatchValue > 0) {\r
1039 CommandAlias = (ALIAS_LIST *) SwapListEntries (&PrevCommandAlias->Link, &CommandAlias->Link);\r
1040 } else if (LexicalMatchValue < 0) {\r
1041 //\r
1042 // PrevCommandAlias entry is lexically lower than CommandAlias entry\r
1043 //\r
1044 break;\r
1045 }\r
1046 }\r
a405b86d 1047\r
1048 return (RETURN_SUCCESS);\r
1049}\r
1050\r
1051/**\r
1052 Get the list of all shell alias commands. This is a linked list\r
1053 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
1054 list functions. do not modify the values.\r
1055\r
1056 @return a Linked list of all requested shell alias'.\r
1057**/\r
1058CONST ALIAS_LIST*\r
1059EFIAPI\r
1060ShellCommandGetInitAliasList (\r
1061 VOID\r
1062 )\r
1063{\r
1064 return (&mAliasList);\r
1065}\r
1066\r
1067/**\r
1a63ec8f 1068 Determine if a given alias is on the list of built in alias'.\r
a405b86d 1069\r
1070 @param[in] Alias The alias to test for\r
1071\r
1072 @retval TRUE The alias is a built in alias\r
1073 @retval FALSE The alias is not a built in alias\r
1074**/\r
1075BOOLEAN\r
1076EFIAPI\r
1077ShellCommandIsOnAliasList(\r
1078 IN CONST CHAR16 *Alias\r
1079 )\r
1080{\r
1081 ALIAS_LIST *Node;\r
1082\r
1083 //\r
1084 // assert for NULL parameter\r
1085 //\r
1086 ASSERT(Alias != NULL);\r
1087\r
1088 //\r
1089 // check for the Alias\r
1090 //\r
1091 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)\r
1092 ; !IsNull(&mAliasList.Link, &Node->Link)\r
1093 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)\r
1094 ){\r
1095 ASSERT(Node->CommandString != NULL);\r
1096 ASSERT(Node->Alias != NULL);\r
1097 if (gUnicodeCollation->StriColl(\r
1098 gUnicodeCollation,\r
1099 (CHAR16*)Alias,\r
1100 Node->CommandString) == 0\r
1101 ){\r
1102 return (TRUE);\r
1103 }\r
1104 if (gUnicodeCollation->StriColl(\r
1105 gUnicodeCollation,\r
1106 (CHAR16*)Alias,\r
1107 Node->Alias) == 0\r
1108 ){\r
1109 return (TRUE);\r
1110 }\r
1111 }\r
1112 return (FALSE);\r
1113}\r
1114\r
1115/**\r
cceb4ebd 1116 Function to determine current state of ECHO. Echo determines if lines from scripts\r
a405b86d 1117 and ECHO commands are enabled.\r
1118\r
1119 @retval TRUE Echo is currently enabled\r
1120 @retval FALSE Echo is currently disabled\r
1121**/\r
1122BOOLEAN\r
1123EFIAPI\r
1124ShellCommandGetEchoState(\r
1125 VOID\r
1126 )\r
1127{\r
1128 return (mEchoState);\r
1129}\r
1130\r
1131/**\r
cceb4ebd 1132 Function to set current state of ECHO. Echo determines if lines from scripts\r
a405b86d 1133 and ECHO commands are enabled.\r
1134\r
1135 If State is TRUE, Echo will be enabled.\r
1136 If State is FALSE, Echo will be disabled.\r
1a63ec8f 1137\r
1138 @param[in] State How to set echo.\r
a405b86d 1139**/\r
1140VOID\r
1141EFIAPI\r
1142ShellCommandSetEchoState(\r
1143 IN BOOLEAN State\r
1144 )\r
1145{\r
1146 mEchoState = State;\r
1147}\r
1148\r
1149/**\r
1150 Indicate that the current shell or script should exit.\r
1151\r
b6b22b13 1152 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.\r
1153 @param[in] ErrorCode The 64 bit error code to return.\r
a405b86d 1154**/\r
1155VOID\r
1156EFIAPI\r
1157ShellCommandRegisterExit (\r
b6b22b13 1158 IN BOOLEAN ScriptOnly,\r
1159 IN CONST UINT64 ErrorCode\r
a405b86d 1160 )\r
1161{\r
1162 mExitRequested = (BOOLEAN)(!mExitRequested);\r
1163 if (mExitRequested) {\r
1164 mExitScript = ScriptOnly;\r
1165 } else {\r
1166 mExitScript = FALSE;\r
1167 }\r
b6b22b13 1168 mExitCode = ErrorCode;\r
a405b86d 1169}\r
1170\r
1171/**\r
1172 Retrieve the Exit indicator.\r
1173\r
1174 @retval TRUE Exit was indicated.\r
1175 @retval FALSE Exis was not indicated.\r
1176**/\r
1177BOOLEAN\r
1178EFIAPI\r
1179ShellCommandGetExit (\r
1180 VOID\r
1181 )\r
1182{\r
1183 return (mExitRequested);\r
1184}\r
1185\r
b6b22b13 1186/**\r
1187 Retrieve the Exit code.\r
1188\r
1189 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
1190\r
1191 @return the value passed into RegisterExit.\r
1192**/\r
1193UINT64\r
1194EFIAPI\r
1195ShellCommandGetExitCode (\r
1196 VOID\r
1197 )\r
1198{\r
1199 return (mExitCode);\r
1200}\r
a405b86d 1201/**\r
1202 Retrieve the Exit script indicator.\r
1203\r
1204 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
1205\r
1206 @retval TRUE ScriptOnly was indicated.\r
1207 @retval FALSE ScriptOnly was not indicated.\r
1208**/\r
1209BOOLEAN\r
1210EFIAPI\r
1211ShellCommandGetScriptExit (\r
1212 VOID\r
1213 )\r
1214{\r
1215 return (mExitScript);\r
1216}\r
1217\r
1218/**\r
1219 Function to cleanup all memory from a SCRIPT_FILE structure.\r
1220\r
1221 @param[in] Script The pointer to the structure to cleanup.\r
1222**/\r
1223VOID\r
1224EFIAPI\r
1225DeleteScriptFileStruct (\r
1226 IN SCRIPT_FILE *Script\r
1227 )\r
1228{\r
1229 UINT8 LoopVar;\r
0ab85bef 1230\r
1231 if (Script == NULL) {\r
1232 return;\r
1233 }\r
1234\r
a405b86d 1235 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {\r
0ab85bef 1236 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);\r
a405b86d 1237 }\r
1238 if (Script->Argv != NULL) {\r
0ab85bef 1239 SHELL_FREE_NON_NULL(Script->Argv);\r
a405b86d 1240 }\r
1241 Script->CurrentCommand = NULL;\r
1242 while (!IsListEmpty (&Script->CommandList)) {\r
1243 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);\r
1244 if (Script->CurrentCommand != NULL) {\r
1245 RemoveEntryList(&Script->CurrentCommand->Link);\r
1246 if (Script->CurrentCommand->Cl != NULL) {\r
0ab85bef 1247 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);\r
a405b86d 1248 }\r
1249 if (Script->CurrentCommand->Data != NULL) {\r
0ab85bef 1250 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);\r
a405b86d 1251 }\r
0ab85bef 1252 SHELL_FREE_NON_NULL(Script->CurrentCommand);\r
a405b86d 1253 }\r
1254 }\r
0ab85bef 1255 SHELL_FREE_NON_NULL(Script->ScriptName);\r
1256 SHELL_FREE_NON_NULL(Script);\r
a405b86d 1257}\r
1258\r
1259/**\r
1260 Function to return a pointer to the currently running script file object.\r
1261\r
1262 @retval NULL A script file is not currently running.\r
1263 @return A pointer to the current script file object.\r
1264**/\r
1265SCRIPT_FILE*\r
1266EFIAPI\r
1267ShellCommandGetCurrentScriptFile (\r
1268 VOID\r
1269 )\r
1270{\r
1271 SCRIPT_FILE_LIST *List;\r
1272 if (IsListEmpty (&mScriptList.Link)) {\r
1273 return (NULL);\r
1274 }\r
1275 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));\r
1276 return (List->Data);\r
1277}\r
1278\r
1279/**\r
1280 Function to set a new script as the currently running one.\r
1281\r
1282 This function will correctly stack and unstack nested scripts.\r
1283\r
1284 @param[in] Script Pointer to new script information structure. if NULL\r
1285 will remove and de-allocate the top-most Script structure.\r
1286\r
1287 @return A pointer to the current running script file after this\r
1288 change. NULL if removing the final script.\r
1289**/\r
1290SCRIPT_FILE*\r
1291EFIAPI\r
1292ShellCommandSetNewScript (\r
1293 IN SCRIPT_FILE *Script OPTIONAL\r
1294 )\r
1295{\r
1296 SCRIPT_FILE_LIST *Node;\r
1297 if (Script == NULL) {\r
1298 if (IsListEmpty (&mScriptList.Link)) {\r
a405b86d 1299 return (NULL);\r
1300 }\r
1301 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
1302 RemoveEntryList(&Node->Link);\r
1303 DeleteScriptFileStruct(Node->Data);\r
1304 FreePool(Node);\r
1305 } else {\r
1306 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));\r
0ab85bef 1307 if (Node == NULL) {\r
1308 return (NULL);\r
1309 }\r
a405b86d 1310 Node->Data = Script;\r
1311 InsertHeadList(&mScriptList.Link, &Node->Link);\r
1312 }\r
1313 return (ShellCommandGetCurrentScriptFile());\r
1314}\r
1315\r
1316/**\r
1317 Function to generate the next default mapping name.\r
1318\r
1319 If the return value is not NULL then it must be callee freed.\r
1320\r
1321 @param Type What kind of mapping name to make.\r
1322\r
1323 @retval NULL a memory allocation failed.\r
1324 @return a new map name string\r
1325**/\r
1326CHAR16*\r
1327EFIAPI\r
1328ShellCommandCreateNewMappingName(\r
1329 IN CONST SHELL_MAPPING_TYPE Type\r
1330 )\r
1331{\r
1332 CHAR16 *String;\r
1333 ASSERT(Type < MappingTypeMax);\r
1334\r
1335 String = NULL;\r
1336\r
1337 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));\r
1338 UnicodeSPrint(\r
1339 String,\r
1340 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),\r
1341 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",\r
1342 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);\r
1343\r
1344 return (String);\r
1345}\r
1346\r
1347/**\r
1348 Function to add a map node to the list of map items and update the "path" environment variable (optionally).\r
1349\r
1350 If Path is TRUE (during initialization only), the path environment variable will also be updated to include\r
1351 default paths on the new map name...\r
1352\r
1353 Path should be FALSE when this function is called from the protocol SetMap function.\r
1354\r
1355 @param[in] Name The human readable mapped name.\r
1356 @param[in] DevicePath The Device Path for this map.\r
1357 @param[in] Flags The Flags attribute for this map item.\r
1358 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).\r
1359\r
1360 @retval EFI_SUCCESS The addition was sucessful.\r
1361 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
1362 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
1363**/\r
1364EFI_STATUS\r
1365EFIAPI\r
1366ShellCommandAddMapItemAndUpdatePath(\r
1367 IN CONST CHAR16 *Name,\r
1368 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1369 IN CONST UINT64 Flags,\r
1370 IN CONST BOOLEAN Path\r
1371 )\r
1372{\r
1373 EFI_STATUS Status;\r
1374 SHELL_MAP_LIST *MapListNode;\r
1375 CONST CHAR16 *OriginalPath;\r
1376 CHAR16 *NewPath;\r
1377 UINTN NewPathSize;\r
1378\r
1379 NewPathSize = 0;\r
1380 NewPath = NULL;\r
1381 OriginalPath = NULL;\r
1382 Status = EFI_SUCCESS;\r
1383\r
1384 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));\r
1385 if (MapListNode == NULL) {\r
1386 Status = EFI_OUT_OF_RESOURCES;\r
1387 } else {\r
1388 MapListNode->Flags = Flags;\r
3957a5a5 1389 MapListNode->MapName = AllocateCopyPool(StrSize(Name), Name);\r
a405b86d 1390 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
1391 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
1392 Status = EFI_OUT_OF_RESOURCES;\r
1393 } else {\r
a405b86d 1394 InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
1395 }\r
1396 }\r
1397 if (EFI_ERROR(Status)) {\r
1398 if (MapListNode != NULL) {\r
1399 if (MapListNode->DevicePath != NULL) {\r
1400 FreePool(MapListNode->DevicePath);\r
1401 }\r
1402 if (MapListNode->MapName != NULL) {\r
1403 FreePool(MapListNode->MapName);\r
1404 }\r
1405 FreePool(MapListNode);\r
1406 }\r
1407 } else if (Path) {\r
1408 //\r
1409 // Since there was no error and Path was TRUE\r
1410 // Now add the correct path for that mapping\r
1411 //\r
1412 OriginalPath = gEfiShellProtocol->GetEnv(L"path");\r
1413 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
1414 if (OriginalPath != NULL) {\r
1415 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
1416 } else {\r
1417 StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);\r
1418 }\r
1419 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
1420 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1421 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
1422 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1423 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);\r
1424 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
1425 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);\r
1426\r
1427 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);\r
1428 ASSERT_EFI_ERROR(Status);\r
1429 FreePool(NewPath);\r
1430 }\r
1431 return (Status);\r
1432}\r
1433\r
1434/**\r
1435 Creates the default map names for each device path in the system with\r
1436 a protocol depending on the Type.\r
1437\r
1438 Creates the consistent map names for each device path in the system with\r
1439 a protocol depending on the Type.\r
1440\r
1441 Note: This will reset all mappings in the system("map -r").\r
1442\r
1443 Also sets up the default path environment variable if Type is FileSystem.\r
1444\r
1445 @retval EFI_SUCCESS All map names were created sucessfully.\r
1446 @retval EFI_NOT_FOUND No protocols were found in the system.\r
1447 @return Error returned from gBS->LocateHandle().\r
1448\r
1449 @sa LocateHandle\r
1450**/\r
1451EFI_STATUS\r
1452EFIAPI\r
1453ShellCommandCreateInitialMappingsAndPaths(\r
1454 VOID\r
1455 )\r
1456{\r
1457 EFI_STATUS Status;\r
1458 EFI_HANDLE *HandleList;\r
1459 UINTN Count;\r
1460 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1461 CHAR16 *NewDefaultName;\r
1462 CHAR16 *NewConsistName;\r
1463 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1464 SHELL_MAP_LIST *MapListNode;\r
1465\r
1466 HandleList = NULL;\r
1467\r
1468 //\r
1469 // Reset the static members back to zero\r
1470 //\r
1471 mFsMaxCount = 0;\r
1472 mBlkMaxCount = 0;\r
1473\r
1474 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);\r
1475\r
1476 //\r
1477 // First empty out the existing list.\r
1478 //\r
1479 if (!IsListEmpty(&gShellMapList.Link)) {\r
1480 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1481 ; !IsListEmpty(&gShellMapList.Link)\r
1482 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1483 ){\r
1484 RemoveEntryList(&MapListNode->Link);\r
c8cfd83a
JY
1485 SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
1486 SHELL_FREE_NON_NULL(MapListNode->MapName);\r
1487 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
a405b86d 1488 FreePool(MapListNode);\r
1489 } // for loop\r
1490 }\r
1491\r
1492 //\r
1493 // Find each handle with Simple File System\r
1494 //\r
0ab85bef 1495 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
a405b86d 1496 if (HandleList != NULL) {\r
1497 //\r
1498 // Do a count of the handles\r
1499 //\r
1500 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1501\r
1502 //\r
1503 // Get all Device Paths\r
1504 //\r
1a63ec8f 1505 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
107d05a4
RN
1506 if (DevicePathList == NULL) {\r
1507 SHELL_FREE_NON_NULL (HandleList);\r
1508 return EFI_OUT_OF_RESOURCES;\r
1509 }\r
a405b86d 1510\r
1511 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1512 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1513 }\r
1514\r
1515 //\r
1516 // Sort all DevicePaths\r
1517 //\r
1518 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1519\r
1520 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1521 //\r
1522 // Assign new Mappings to all...\r
1523 //\r
1524 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1525 //\r
1526 // Get default name first\r
1527 //\r
1528 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
1529 ASSERT(NewDefaultName != NULL);\r
1530 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);\r
1531 ASSERT_EFI_ERROR(Status);\r
1532 FreePool(NewDefaultName);\r
1533\r
1534 //\r
1535 // Now do consistent name\r
1536 //\r
1537 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1538 if (NewConsistName != NULL) {\r
1539 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);\r
1540 ASSERT_EFI_ERROR(Status);\r
1541 FreePool(NewConsistName);\r
1542 }\r
1543 }\r
1544\r
1545 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1546\r
1547 SHELL_FREE_NON_NULL(HandleList);\r
1548 SHELL_FREE_NON_NULL(DevicePathList);\r
1549\r
1550 HandleList = NULL;\r
1551 } else {\r
1552 Count = (UINTN)-1;\r
1553 }\r
1554\r
1555 //\r
1556 // Find each handle with Block Io\r
1557 //\r
0ab85bef 1558 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);\r
a405b86d 1559 if (HandleList != NULL) {\r
1560 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1561\r
1562 //\r
1563 // Get all Device Paths\r
1564 //\r
1a63ec8f 1565 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
107d05a4
RN
1566 if (DevicePathList == NULL) {\r
1567 SHELL_FREE_NON_NULL (HandleList);\r
1568 return EFI_OUT_OF_RESOURCES;\r
1569 }\r
a405b86d 1570\r
1571 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1572 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1573 }\r
1574\r
1575 //\r
1576 // Sort all DevicePaths\r
1577 //\r
1578 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1579\r
1580 //\r
1581 // Assign new Mappings to all...\r
1582 //\r
1583 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1584 //\r
1585 // Get default name first\r
1586 //\r
1587 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);\r
1588 ASSERT(NewDefaultName != NULL);\r
1589 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);\r
1590 ASSERT_EFI_ERROR(Status);\r
1591 FreePool(NewDefaultName);\r
1592 }\r
1593\r
1594 SHELL_FREE_NON_NULL(HandleList);\r
1595 SHELL_FREE_NON_NULL(DevicePathList);\r
1596 } else if (Count == (UINTN)-1) {\r
1597 return (EFI_NOT_FOUND);\r
1598 }\r
1599\r
1600 return (EFI_SUCCESS);\r
cf812a20
JC
1601}\r
1602\r
1603/**\r
1604 Add mappings for any devices without one. Do not change any existing maps.\r
1605\r
1606 @retval EFI_SUCCESS The operation was successful.\r
1607**/\r
1608EFI_STATUS\r
1609EFIAPI\r
1610ShellCommandUpdateMapping (\r
1611 VOID\r
1612 )\r
1613{\r
1614 EFI_STATUS Status;\r
1615 EFI_HANDLE *HandleList;\r
1616 UINTN Count;\r
1617 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1618 CHAR16 *NewDefaultName;\r
1619 CHAR16 *NewConsistName;\r
1620 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1621\r
1622 HandleList = NULL;\r
1623 Status = EFI_SUCCESS;\r
1624\r
1625 //\r
1626 // remove mappings that represent removed devices.\r
1627 //\r
1628\r
1629 //\r
1630 // Find each handle with Simple File System\r
1631 //\r
1632 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
1633 if (HandleList != NULL) {\r
1634 //\r
1635 // Do a count of the handles\r
1636 //\r
1637 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1638\r
1639 //\r
1640 // Get all Device Paths\r
1641 //\r
1642 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
ae315cc2
JC
1643 if (DevicePathList == NULL) {\r
1644 return (EFI_OUT_OF_RESOURCES);\r
1645 }\r
cf812a20
JC
1646\r
1647 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1648 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1649 }\r
1650\r
1651 //\r
1652 // Sort all DevicePaths\r
1653 //\r
1654 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1655\r
1656 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1657\r
1658 //\r
1659 // Assign new Mappings to remainders\r
1660 //\r
ae315cc2 1661 for (Count = 0 ; !EFI_ERROR(Status) && HandleList[Count] != NULL && !EFI_ERROR(Status); Count++) {\r
cf812a20
JC
1662 //\r
1663 // Skip ones that already have\r
1664 //\r
1665 if (gEfiShellProtocol->GetMapFromDevicePath(&DevicePathList[Count]) != NULL) {\r
1666 continue;\r
1667 }\r
1668 //\r
1669 // Get default name\r
1670 //\r
1671 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
ae315cc2
JC
1672 if (NewDefaultName == NULL) {\r
1673 Status = EFI_OUT_OF_RESOURCES;\r
1674 break;\r
1675 }\r
cf812a20
JC
1676\r
1677 //\r
1678 // Call shell protocol SetMap function now...\r
1679 //\r
1680 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewDefaultName);\r
1681\r
1682 if (!EFI_ERROR(Status)) {\r
1683 //\r
1684 // Now do consistent name\r
1685 //\r
1686 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1687 if (NewConsistName != NULL) {\r
1688 Status = gEfiShellProtocol->SetMap(DevicePathList[Count], NewConsistName);\r
1689 FreePool(NewConsistName);\r
1690 }\r
1691 }\r
1692\r
1693 FreePool(NewDefaultName);\r
1694 }\r
1695 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1696 SHELL_FREE_NON_NULL(HandleList);\r
1697 SHELL_FREE_NON_NULL(DevicePathList);\r
1698\r
1699 HandleList = NULL;\r
1700 } else {\r
1701 Count = (UINTN)-1;\r
1702 }\r
1703 //\r
1704 // Do it all over again for gEfiBlockIoProtocolGuid\r
1705 //\r
1706\r
1707 return (Status);\r
1708}\r
1709\r
1710/**\r
1711 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
1712\r
1713 @param[in] Handle The SHELL_FILE_HANDLE to convert.\r
a405b86d 1714\r
1715 @return a EFI_FILE_PROTOCOL* representing the same file.\r
1716**/\r
1717EFI_FILE_PROTOCOL*\r
1718EFIAPI\r
1719ConvertShellHandleToEfiFileProtocol(\r
1720 IN CONST SHELL_FILE_HANDLE Handle\r
1721 )\r
1722{\r
1723 return ((EFI_FILE_PROTOCOL*)(Handle));\r
1724}\r
1725\r
1726/**\r
1727 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.\r
1728\r
1729 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.\r
1730 @param[in] Path The path to the file for verification.\r
1731\r
ff51746b 1732 @return A SHELL_FILE_HANDLE representing the same file.\r
1733 @retval NULL There was not enough memory.\r
a405b86d 1734**/\r
1735SHELL_FILE_HANDLE\r
1736EFIAPI\r
1737ConvertEfiFileProtocolToShellHandle(\r
1738 IN CONST EFI_FILE_PROTOCOL *Handle,\r
1739 IN CONST CHAR16 *Path\r
1740 )\r
1741{\r
1742 SHELL_COMMAND_FILE_HANDLE *Buffer;\r
1743 BUFFER_LIST *NewNode;\r
1744\r
1745 if (Path != NULL) {\r
1746 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));\r
ff51746b 1747 if (Buffer == NULL) {\r
1748 return (NULL);\r
1749 }\r
1a63ec8f 1750 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ff51746b 1751 if (NewNode == NULL) {\r
ae315cc2 1752 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1753 return (NULL);\r
1754 }\r
a405b86d 1755 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;\r
1756 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
ff51746b 1757 if (Buffer->Path == NULL) {\r
ae315cc2
JC
1758 SHELL_FREE_NON_NULL(NewNode);\r
1759 SHELL_FREE_NON_NULL(Buffer);\r
ff51746b 1760 return (NULL);\r
1761 }\r
a405b86d 1762 NewNode->Buffer = Buffer;\r
1763\r
1764 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);\r
1765 }\r
1766 return ((SHELL_FILE_HANDLE)(Handle));\r
1767}\r
1768\r
1769/**\r
1770 Find the path that was logged with the specified SHELL_FILE_HANDLE.\r
1771\r
1772 @param[in] Handle The SHELL_FILE_HANDLE to query on.\r
1773\r
1774 @return A pointer to the path for the file.\r
1775**/\r
1776CONST CHAR16*\r
1777EFIAPI\r
1778ShellFileHandleGetPath(\r
1779 IN CONST SHELL_FILE_HANDLE Handle\r
1780 )\r
1781{\r
1782 BUFFER_LIST *Node;\r
1783\r
1784 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1785 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1786 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1787 ){\r
1788 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
1789 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1790 }\r
1791 }\r
1792 return (NULL);\r
1793}\r
1794\r
1795/**\r
1a63ec8f 1796 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.\r
a405b86d 1797\r
1798 @param[in] Handle The SHELL_FILE_HANDLE to remove.\r
1799\r
1800 @retval TRUE The item was removed.\r
1801 @retval FALSE The item was not found.\r
1802**/\r
1803BOOLEAN\r
1804EFIAPI\r
1805ShellFileHandleRemove(\r
1806 IN CONST SHELL_FILE_HANDLE Handle\r
1807 )\r
1808{\r
1809 BUFFER_LIST *Node;\r
1810\r
1811 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1812 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1813 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1814 ){\r
1815 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
a405b86d 1816 RemoveEntryList(&Node->Link);\r
ff51746b 1817 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1818 SHELL_FREE_NON_NULL(Node->Buffer);\r
1819 SHELL_FREE_NON_NULL(Node);\r
a405b86d 1820 return (TRUE);\r
1821 }\r
1822 }\r
1823 return (FALSE);\r
1824}\r
1825\r
1826/**\r
1827 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.\r
1828\r
1829 This will NOT work on directories.\r
1830\r
1831 If Handle is NULL, then ASSERT.\r
1832\r
1833 @param[in] Handle the file handle\r
1834\r
1835 @retval TRUE the position is at the end of the file\r
1836 @retval FALSE the position is not at the end of the file\r
1837**/\r
1838BOOLEAN\r
1839EFIAPI\r
1840ShellFileHandleEof(\r
1841 IN SHELL_FILE_HANDLE Handle\r
1842 )\r
1843{\r
1844 EFI_FILE_INFO *Info;\r
1845 UINT64 Pos;\r
1846 BOOLEAN RetVal;\r
1847\r
1848 //\r
1849 // ASSERT if Handle is NULL\r
1850 //\r
1851 ASSERT(Handle != NULL);\r
1852\r
1853 gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
1854 Info = gEfiShellProtocol->GetFileInfo (Handle);\r
a405b86d 1855 gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
1856\r
1857 if (Info == NULL) {\r
1858 return (FALSE);\r
1859 }\r
1860\r
1861 if (Pos == Info->FileSize) {\r
1862 RetVal = TRUE;\r
1863 } else {\r
1864 RetVal = FALSE;\r
1865 }\r
1866\r
1867 FreePool (Info);\r
1868\r
1869 return (RetVal);\r
1870}\r
1871\r
0fcf8d4d
RN
1872/**\r
1873 Function to get the original CmdLine string for current command.\r
1874\r
1875 @return A pointer to the buffer of the original command string.\r
1876 It's the caller's responsibility to free the buffer.\r
1877**/\r
1878CHAR16*\r
1879EFIAPI\r
1880ShellGetRawCmdLine (\r
1881 VOID\r
1882 )\r
1883{\r
1884 if (mRawCmdLine == NULL) {\r
1885 return NULL;\r
1886 } else {\r
1887 return AllocateCopyPool(StrSize(mRawCmdLine), mRawCmdLine);\r
1888 }\r
1889}\r
1890\r
1891/**\r
1892 Function to store the raw command string.\r
1893\r
1894 The alias and variables have been replaced and spaces are trimmed.\r
1895\r
1896 @param[in] CmdLine the command line string to store.\r
1897**/\r
1898VOID\r
1899EFIAPI\r
1900ShellSetRawCmdLine (\r
1901 IN CONST CHAR16 *CmdLine\r
1902 )\r
1903{\r
1904 SHELL_FREE_NON_NULL(mRawCmdLine);\r
1905\r
1906 if (CmdLine != NULL) {\r
1907 //\r
1908 // The spaces in the beginning and end are trimmed.\r
1909 //\r
1910 ASSERT (*CmdLine != L' ');\r
1911 ASSERT (CmdLine[StrLen (CmdLine) - 1] != L' ');\r
1912 mRawCmdLine = AllocateCopyPool (StrSize(CmdLine), CmdLine);\r
1913 }\r
1914}\r
1915\r
a405b86d 1916/**\r
1917 Frees any BUFFER_LIST defined type.\r
1a63ec8f 1918\r
1919 @param[in] List The BUFFER_LIST object to free.\r
a405b86d 1920**/\r
1921VOID\r
1922EFIAPI\r
1923FreeBufferList (\r
1924 IN BUFFER_LIST *List\r
1925 )\r
1926{\r
1927 BUFFER_LIST *BufferListEntry;\r
1928\r
1929 if (List == NULL){\r
1930 return;\r
1931 }\r
1932 //\r
1933 // enumerate through the buffer list and free all memory\r
1934 //\r
1935 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
1936 ; !IsListEmpty (&List->Link)\r
1937 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
1938 ){\r
1939 RemoveEntryList(&BufferListEntry->Link);\r
a405b86d 1940 if (BufferListEntry->Buffer != NULL) {\r
1941 FreePool(BufferListEntry->Buffer);\r
1942 }\r
1943 FreePool(BufferListEntry);\r
1944 }\r
1945}\r
1946\r
3bd89603
LE
1947/**\r
1948 Dump some hexadecimal data to the screen.\r
1949\r
1950 @param[in] Indent How many spaces to indent the output.\r
1951 @param[in] Offset The offset of the printing.\r
1952 @param[in] DataSize The size in bytes of UserData.\r
1953 @param[in] UserData The data to print out.\r
1954**/\r
1955VOID\r
1956DumpHex (\r
1957 IN UINTN Indent,\r
1958 IN UINTN Offset,\r
1959 IN UINTN DataSize,\r
1960 IN VOID *UserData\r
1961 )\r
1962{\r
1963 UINT8 *Data;\r
1964\r
1965 CHAR8 Val[50];\r
1966\r
1967 CHAR8 Str[20];\r
1968\r
1969 UINT8 TempByte;\r
1970 UINTN Size;\r
1971 UINTN Index;\r
1972\r
1973 Data = UserData;\r
1974 while (DataSize != 0) {\r
1975 Size = 16;\r
1976 if (Size > DataSize) {\r
1977 Size = DataSize;\r
1978 }\r
1979\r
1980 for (Index = 0; Index < Size; Index += 1) {\r
1981 TempByte = Data[Index];\r
1982 Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
1983 Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
1984 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
1985 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
1986 }\r
1987\r
1988 Val[Index * 3] = 0;\r
1989 Str[Index] = 0;\r
1990 ShellPrintEx(-1, -1, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
1991\r
1992 Data += Size;\r
1993 Offset += Size;\r
1994 DataSize -= Size;\r
1995 }\r
1996}\r
cf041fd7
RN
1997\r
1998/**\r
1999 Dump HEX data into buffer.\r
2000\r
2001 @param[in] Buffer HEX data to be dumped in Buffer.\r
2002 @param[in] Indent How many spaces to indent the output.\r
2003 @param[in] Offset The offset of the printing.\r
2004 @param[in] DataSize The size in bytes of UserData.\r
2005 @param[in] UserData The data to print out.\r
2006**/\r
2007CHAR16*\r
2008CatSDumpHex (\r
2009 IN CHAR16 *Buffer,\r
2010 IN UINTN Indent,\r
2011 IN UINTN Offset,\r
2012 IN UINTN DataSize,\r
2013 IN VOID *UserData\r
2014 )\r
2015{\r
2016 UINT8 *Data;\r
2017 UINT8 TempByte;\r
2018 UINTN Size;\r
2019 UINTN Index;\r
2020 CHAR8 Val[50];\r
2021 CHAR8 Str[20];\r
2022 CHAR16 *RetVal;\r
2023 CHAR16 *TempRetVal;\r
2024\r
2025 Data = UserData;\r
2026 RetVal = Buffer;\r
2027 while (DataSize != 0) {\r
2028 Size = 16;\r
2029 if (Size > DataSize) {\r
2030 Size = DataSize;\r
2031 }\r
2032\r
2033 for (Index = 0; Index < Size; Index += 1) {\r
2034 TempByte = Data[Index];\r
2035 Val[Index * 3 + 0] = Hex[TempByte >> 4];\r
2036 Val[Index * 3 + 1] = Hex[TempByte & 0xF];\r
2037 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
2038 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
2039 }\r
2040\r
2041 Val[Index * 3] = 0;\r
2042 Str[Index] = 0;\r
2043 TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
2044 SHELL_FREE_NON_NULL (RetVal);\r
2045 RetVal = TempRetVal;\r
2046\r
2047 Data += Size;\r
2048 Offset += Size;\r
2049 DataSize -= Size;\r
2050 }\r
2051\r
2052 return RetVal;\r
2053}\r