]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/Shell.c
ARM Packages: Removed 'inline' keyword
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
CommitLineData
a405b86d 1/** @file\r
2 This is THE shell (application)\r
3\r
ca79c798 4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
ed34da40 5 Copyright (c) 2013, Hewlett-Packard Development Company, L.P.\r
a405b86d 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Shell.h"\r
17\r
18//\r
19// Initialize the global structure\r
20//\r
21SHELL_INFO ShellInfoObject = {\r
22 NULL,\r
23 NULL,\r
24 FALSE,\r
25 FALSE,\r
26 {\r
ce68d3bc
SZ
27 {{\r
28 0,\r
29 0,\r
30 0,\r
31 0,\r
32 0,\r
33 0,\r
34 0,\r
35 0,\r
36 0\r
37 }},\r
a405b86d 38 0,\r
39 NULL,\r
40 NULL\r
41 },\r
ce68d3bc 42 {{NULL, NULL}, NULL},\r
a405b86d 43 {\r
ce68d3bc 44 {{NULL, NULL}, NULL},\r
a405b86d 45 0,\r
46 0,\r
47 TRUE\r
48 },\r
49 NULL,\r
50 0,\r
51 NULL,\r
52 NULL,\r
53 NULL,\r
54 NULL,\r
55 NULL,\r
ce68d3bc
SZ
56 {{NULL, NULL}, NULL, NULL},\r
57 {{NULL, NULL}, NULL, NULL},\r
58 NULL,\r
59 NULL,\r
60 NULL,\r
61 NULL,\r
8be0ba36 62 NULL,\r
63 NULL,\r
64 NULL,\r
a49f6a2f 65 NULL,\r
66 FALSE\r
a405b86d 67};\r
68\r
69STATIC CONST CHAR16 mScriptExtension[] = L".NSH";\r
70STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI";\r
3c865f20 71STATIC CONST CHAR16 mStartupScript[] = L"startup.nsh";\r
a405b86d 72\r
733f138d 73/**\r
74 Function to start monitoring for CTRL-S using SimpleTextInputEx. This \r
75 feature's enabled state was not known when the shell initially launched.\r
76\r
77 @retval EFI_SUCCESS The feature is enabled.\r
78 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.\r
79**/\r
80EFI_STATUS\r
81EFIAPI\r
82InternalEfiShellStartCtrlSMonitor(\r
83 VOID\r
84 )\r
85{\r
86 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
87 EFI_KEY_DATA KeyData;\r
88 EFI_STATUS Status;\r
89\r
90 Status = gBS->OpenProtocol(\r
91 gST->ConsoleInHandle,\r
92 &gEfiSimpleTextInputExProtocolGuid,\r
93 (VOID**)&SimpleEx,\r
94 gImageHandle,\r
95 NULL,\r
96 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
97 if (EFI_ERROR(Status)) {\r
98 ShellPrintHiiEx(\r
99 -1, \r
100 -1, \r
101 NULL,\r
102 STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
103 ShellInfoObject.HiiHandle);\r
104 return (EFI_SUCCESS);\r
105 }\r
106\r
107 KeyData.KeyState.KeyToggleState = 0;\r
108 KeyData.Key.ScanCode = 0;\r
109 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
110 KeyData.Key.UnicodeChar = L's';\r
111\r
112 Status = SimpleEx->RegisterKeyNotify(\r
113 SimpleEx,\r
114 &KeyData,\r
115 NotificationFunction,\r
116 &ShellInfoObject.CtrlSNotifyHandle1);\r
117 \r
118 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
119 if (!EFI_ERROR(Status)) {\r
120 Status = SimpleEx->RegisterKeyNotify(\r
121 SimpleEx,\r
122 &KeyData,\r
123 NotificationFunction,\r
124 &ShellInfoObject.CtrlSNotifyHandle2);\r
125 }\r
126 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
127 KeyData.Key.UnicodeChar = 19;\r
128\r
129 if (!EFI_ERROR(Status)) {\r
130 Status = SimpleEx->RegisterKeyNotify(\r
131 SimpleEx,\r
132 &KeyData,\r
133 NotificationFunction,\r
ed8b5297 134 &ShellInfoObject.CtrlSNotifyHandle3);\r
733f138d 135 } \r
136 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
137 if (!EFI_ERROR(Status)) {\r
138 Status = SimpleEx->RegisterKeyNotify(\r
139 SimpleEx,\r
140 &KeyData,\r
141 NotificationFunction,\r
ed8b5297 142 &ShellInfoObject.CtrlSNotifyHandle4);\r
733f138d 143 }\r
144 return (Status);\r
145}\r
146\r
147\r
148\r
a405b86d 149/**\r
150 The entry point for the application.\r
151\r
152 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
153 @param[in] SystemTable A pointer to the EFI System Table.\r
154\r
155 @retval EFI_SUCCESS The entry point is executed successfully.\r
156 @retval other Some error occurs when executing this entry point.\r
157\r
158**/\r
159EFI_STATUS\r
160EFIAPI\r
161UefiMain (\r
162 IN EFI_HANDLE ImageHandle,\r
163 IN EFI_SYSTEM_TABLE *SystemTable\r
164 )\r
165{\r
a49f6a2f 166 EFI_STATUS Status;\r
167 CHAR16 *TempString;\r
168 UINTN Size;\r
169 EFI_HANDLE ConInHandle;\r
170 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn;\r
a405b86d 171\r
172 if (PcdGet8(PcdShellSupportLevel) > 3) {\r
173 return (EFI_UNSUPPORTED);\r
174 }\r
175\r
176 //\r
177 // Clear the screen\r
178 //\r
179 Status = gST->ConOut->ClearScreen(gST->ConOut);\r
3c865f20 180 if (EFI_ERROR(Status)) {\r
181 return (Status);\r
182 }\r
a405b86d 183\r
184 //\r
185 // Populate the global structure from PCDs\r
186 //\r
187 ShellInfoObject.ImageDevPath = NULL;\r
188 ShellInfoObject.FileDevPath = NULL;\r
189 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
190 ShellInfoObject.ViewingSettings.InsertMode = PcdGetBool(PcdShellInsertModeDefault);\r
191 ShellInfoObject.LogScreenCount = PcdGet8 (PcdShellScreenLogCount );\r
192\r
193 //\r
194 // verify we dont allow for spec violation\r
195 //\r
196 ASSERT(ShellInfoObject.LogScreenCount >= 3);\r
197\r
198 //\r
199 // Initialize the LIST ENTRY objects...\r
200 //\r
201 InitializeListHead(&ShellInfoObject.BufferToFreeList.Link);\r
202 InitializeListHead(&ShellInfoObject.ViewingSettings.CommandHistory.Link);\r
203 InitializeListHead(&ShellInfoObject.SplitList.Link);\r
204\r
205 //\r
206 // Check PCDs for optional features that are not implemented yet.\r
207 //\r
208 if ( PcdGetBool(PcdShellSupportOldProtocols)\r
209 || !FeaturePcdGet(PcdShellRequireHiiPlatform)\r
210 || FeaturePcdGet(PcdShellSupportFrameworkHii)\r
211 ) {\r
212 return (EFI_UNSUPPORTED);\r
213 }\r
214\r
215 //\r
216 // turn off the watchdog timer\r
217 //\r
218 gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
219\r
220 //\r
221 // install our console logger. This will keep a log of the output for back-browsing\r
222 //\r
223 Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo);\r
3c865f20 224 if (!EFI_ERROR(Status)) {\r
225 //\r
226 // Enable the cursor to be visible\r
227 //\r
228 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
a405b86d 229\r
3c865f20 230 //\r
231 // If supporting EFI 1.1 we need to install HII protocol\r
232 // only do this if PcdShellRequireHiiPlatform == FALSE\r
233 //\r
234 // remove EFI_UNSUPPORTED check above when complete.\r
235 ///@todo add support for Framework HII\r
a405b86d 236\r
3c865f20 237 //\r
238 // install our (solitary) HII package\r
239 //\r
240 ShellInfoObject.HiiHandle = HiiAddPackages (&gEfiCallerIdGuid, gImageHandle, ShellStrings, NULL);\r
a405b86d 241 if (ShellInfoObject.HiiHandle == NULL) {\r
3c865f20 242 if (PcdGetBool(PcdShellSupportFrameworkHii)) {\r
243 ///@todo Add our package into Framework HII\r
244 }\r
245 if (ShellInfoObject.HiiHandle == NULL) {\r
246 return (EFI_NOT_STARTED);\r
247 }\r
a405b86d 248 }\r
a405b86d 249\r
3c865f20 250 //\r
251 // create and install the EfiShellParametersProtocol\r
252 //\r
253 Status = CreatePopulateInstallShellParametersProtocol(&ShellInfoObject.NewShellParametersProtocol, &ShellInfoObject.RootShellInstance);\r
254 ASSERT_EFI_ERROR(Status);\r
255 ASSERT(ShellInfoObject.NewShellParametersProtocol != NULL);\r
a405b86d 256\r
3c865f20 257 //\r
258 // create and install the EfiShellProtocol\r
259 //\r
260 Status = CreatePopulateInstallShellProtocol(&ShellInfoObject.NewEfiShellProtocol);\r
261 ASSERT_EFI_ERROR(Status);\r
262 ASSERT(ShellInfoObject.NewEfiShellProtocol != NULL);\r
a405b86d 263\r
3c865f20 264 //\r
265 // Now initialize the shell library (it requires Shell Parameters protocol)\r
266 //\r
267 Status = ShellInitialize();\r
268 ASSERT_EFI_ERROR(Status);\r
a405b86d 269\r
3c865f20 270 Status = CommandInit();\r
271 ASSERT_EFI_ERROR(Status);\r
a405b86d 272\r
3c865f20 273 //\r
274 // Check the command line\r
275 //\r
276 Status = ProcessCommandLine();\r
a405b86d 277\r
3c865f20 278 //\r
279 // If shell support level is >= 1 create the mappings and paths\r
280 //\r
281 if (PcdGet8(PcdShellSupportLevel) >= 1) {\r
282 Status = ShellCommandCreateInitialMappingsAndPaths();\r
283 }\r
a405b86d 284\r
3c865f20 285 //\r
286 // save the device path for the loaded image and the device path for the filepath (under loaded image)\r
287 // These are where to look for the startup.nsh file\r
288 //\r
289 Status = GetDevicePathsForImageAndFile(&ShellInfoObject.ImageDevPath, &ShellInfoObject.FileDevPath);\r
a405b86d 290 ASSERT_EFI_ERROR(Status);\r
a405b86d 291\r
3c865f20 292 //\r
293 // Display the version\r
294 //\r
295 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion) {\r
296 ShellPrintHiiEx (\r
297 0,\r
298 gST->ConOut->Mode->CursorRow,\r
299 NULL,\r
284e034f 300 STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL),\r
3c865f20 301 ShellInfoObject.HiiHandle,\r
302 SupportLevel[PcdGet8(PcdShellSupportLevel)],\r
303 gEfiShellProtocol->MajorVersion,\r
284e034f
CP
304 gEfiShellProtocol->MinorVersion\r
305 );\r
306\r
307 ShellPrintHiiEx (\r
308 -1,\r
309 -1,\r
310 NULL,\r
311 STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER),\r
312 ShellInfoObject.HiiHandle,\r
313 (CHAR16 *) PcdGetPtr (PcdShellSupplier)\r
314 );\r
315\r
316 ShellPrintHiiEx (\r
317 -1,\r
318 -1,\r
319 NULL,\r
320 STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI),\r
321 ShellInfoObject.HiiHandle,\r
3c865f20 322 (gST->Hdr.Revision&0xffff0000)>>16,\r
323 (gST->Hdr.Revision&0x0000ffff),\r
324 gST->FirmwareVendor,\r
325 gST->FirmwareRevision\r
326 );\r
327 }\r
a405b86d 328\r
3c865f20 329 //\r
330 // Display the mapping\r
331 //\r
332 if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {\r
333 Status = RunCommand(L"map");\r
334 ASSERT_EFI_ERROR(Status);\r
335 }\r
a405b86d 336\r
3c865f20 337 //\r
338 // init all the built in alias'\r
339 //\r
340 Status = SetBuiltInAlias();\r
341 ASSERT_EFI_ERROR(Status);\r
a405b86d 342\r
3c865f20 343 //\r
344 // Initialize environment variables\r
345 //\r
346 if (ShellCommandGetProfileList() != NULL) {\r
347 Status = InternalEfiShellSetEnv(L"profiles", ShellCommandGetProfileList(), TRUE);\r
348 ASSERT_EFI_ERROR(Status);\r
349 }\r
a405b86d 350\r
3c865f20 351 Size = 100;\r
352 TempString = AllocateZeroPool(Size);\r
a405b86d 353\r
3c865f20 354 UnicodeSPrint(TempString, Size, L"%d", PcdGet8(PcdShellSupportLevel));\r
355 Status = InternalEfiShellSetEnv(L"uefishellsupport", TempString, TRUE);\r
356 ASSERT_EFI_ERROR(Status);\r
a405b86d 357\r
3c865f20 358 UnicodeSPrint(TempString, Size, L"%d.%d", ShellInfoObject.NewEfiShellProtocol->MajorVersion, ShellInfoObject.NewEfiShellProtocol->MinorVersion);\r
359 Status = InternalEfiShellSetEnv(L"uefishellversion", TempString, TRUE);\r
360 ASSERT_EFI_ERROR(Status);\r
a405b86d 361\r
3c865f20 362 UnicodeSPrint(TempString, Size, L"%d.%d", (gST->Hdr.Revision & 0xFFFF0000) >> 16, gST->Hdr.Revision & 0x0000FFFF);\r
363 Status = InternalEfiShellSetEnv(L"uefiversion", TempString, TRUE);\r
364 ASSERT_EFI_ERROR(Status);\r
a405b86d 365\r
3c865f20 366 FreePool(TempString);\r
a405b86d 367\r
3c865f20 368 if (!EFI_ERROR(Status)) {\r
369 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {\r
a405b86d 370 //\r
3c865f20 371 // Set up the event for CTRL-C monitoring...\r
a405b86d 372 //\r
8be0ba36 373 Status = InernalEfiShellStartMonitor();\r
3c865f20 374 }\r
375\r
733f138d 376 if (!EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
377 //\r
378 // Set up the event for CTRL-S monitoring...\r
379 //\r
380 Status = InternalEfiShellStartCtrlSMonitor();\r
381 }\r
382\r
a49f6a2f 383 if (!EFI_ERROR(Status) && ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
384 //\r
385 // close off the gST->ConIn\r
386 //\r
387 OldConIn = gST->ConIn;\r
388 ConInHandle = gST->ConsoleInHandle;\r
389 gST->ConIn = CreateSimpleTextInOnFile((SHELL_FILE_HANDLE)&FileInterfaceNulFile, &gST->ConsoleInHandle);\r
390 } else {\r
391 OldConIn = NULL;\r
392 ConInHandle = NULL;\r
393 }\r
394\r
3c865f20 395 if (!EFI_ERROR(Status) && PcdGet8(PcdShellSupportLevel) >= 1) {\r
a405b86d 396 //\r
3c865f20 397 // process the startup script or launch the called app.\r
a405b86d 398 //\r
3c865f20 399 Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
400 }\r
a405b86d 401\r
ca79c798 402 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
a405b86d 403 //\r
3c865f20 404 // begin the UI waiting loop\r
a405b86d 405 //\r
3c865f20 406 do {\r
407 //\r
408 // clean out all the memory allocated for CONST <something> * return values\r
409 // between each shell prompt presentation\r
410 //\r
411 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){\r
412 FreeBufferList(&ShellInfoObject.BufferToFreeList);\r
413 }\r
414\r
415 //\r
416 // Reset page break back to default.\r
417 //\r
418 ShellInfoObject.PageBreakEnabled = PcdGetBool(PcdShellPageBreakDefault);\r
419 ShellInfoObject.ConsoleInfo->Enabled = TRUE;\r
420 ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
421\r
8be0ba36 422 //\r
423 // Reset the CTRL-C event (yes we ignore the return values)\r
424 //\r
425 Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
426\r
3c865f20 427 //\r
428 // Display Prompt\r
429 //\r
430 Status = DoShellPrompt();\r
431 } while (!ShellCommandGetExit());\r
432 }\r
a49f6a2f 433 if (OldConIn != NULL && ConInHandle != NULL) {\r
434 CloseSimpleTextInOnFile (gST->ConIn);\r
435 gST->ConIn = OldConIn;\r
436 gST->ConsoleInHandle = ConInHandle;\r
437 }\r
a405b86d 438 }\r
439 }\r
3c865f20 440\r
a405b86d 441 //\r
442 // uninstall protocols / free memory / etc...\r
443 //\r
444 if (ShellInfoObject.UserBreakTimer != NULL) {\r
445 gBS->CloseEvent(ShellInfoObject.UserBreakTimer);\r
446 DEBUG_CODE(ShellInfoObject.UserBreakTimer = NULL;);\r
447 }\r
a405b86d 448 if (ShellInfoObject.ImageDevPath != NULL) {\r
449 FreePool(ShellInfoObject.ImageDevPath);\r
450 DEBUG_CODE(ShellInfoObject.ImageDevPath = NULL;);\r
451 }\r
452 if (ShellInfoObject.FileDevPath != NULL) {\r
453 FreePool(ShellInfoObject.FileDevPath);\r
454 DEBUG_CODE(ShellInfoObject.FileDevPath = NULL;);\r
455 }\r
456 if (ShellInfoObject.NewShellParametersProtocol != NULL) {\r
457 CleanUpShellParametersProtocol(ShellInfoObject.NewShellParametersProtocol);\r
458 DEBUG_CODE(ShellInfoObject.NewShellParametersProtocol = NULL;);\r
459 }\r
460 if (ShellInfoObject.NewEfiShellProtocol != NULL){\r
8be0ba36 461 if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){\r
92670471 462 InternalEfiShellSetEnv(L"cwd", NULL, TRUE);\r
8be0ba36 463 }\r
a405b86d 464 CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol);\r
465 DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;);\r
466 }\r
467\r
468 if (!IsListEmpty(&ShellInfoObject.BufferToFreeList.Link)){\r
469 FreeBufferList(&ShellInfoObject.BufferToFreeList);\r
470 }\r
471\r
472 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){\r
3c865f20 473 ASSERT(FALSE); ///@todo finish this de-allocation.\r
a405b86d 474 }\r
475\r
476 if (ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
477 FreePool(ShellInfoObject.ShellInitSettings.FileName);\r
478 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileName = NULL;);\r
479 }\r
480\r
481 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
482 FreePool(ShellInfoObject.ShellInitSettings.FileOptions);\r
483 DEBUG_CODE(ShellInfoObject.ShellInitSettings.FileOptions = NULL;);\r
484 }\r
485\r
486 if (ShellInfoObject.HiiHandle != NULL) {\r
487 HiiRemovePackages(ShellInfoObject.HiiHandle);\r
488 DEBUG_CODE(ShellInfoObject.HiiHandle = NULL;);\r
489 }\r
490\r
491 if (!IsListEmpty(&ShellInfoObject.ViewingSettings.CommandHistory.Link)){\r
492 FreeBufferList(&ShellInfoObject.ViewingSettings.CommandHistory);\r
493 }\r
494\r
495 ASSERT(ShellInfoObject.ConsoleInfo != NULL);\r
496 if (ShellInfoObject.ConsoleInfo != NULL) {\r
497 ConsoleLoggerUninstall(ShellInfoObject.ConsoleInfo);\r
498 FreePool(ShellInfoObject.ConsoleInfo);\r
499 DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
500 }\r
501\r
b6b22b13 502 if (ShellCommandGetExit()) {\r
503 return ((EFI_STATUS)ShellCommandGetExitCode());\r
504 }\r
a405b86d 505 return (Status);\r
506}\r
507\r
508/**\r
509 Sets all the alias' that were registered with the ShellCommandLib library.\r
510\r
511 @retval EFI_SUCCESS all init commands were run sucessfully.\r
512**/\r
513EFI_STATUS\r
514EFIAPI\r
515SetBuiltInAlias(\r
516 )\r
517{\r
518 EFI_STATUS Status;\r
519 CONST ALIAS_LIST *List;\r
520 ALIAS_LIST *Node;\r
521\r
522 //\r
523 // Get all the commands we want to run\r
524 //\r
525 List = ShellCommandGetInitAliasList();\r
526\r
527 //\r
528 // for each command in the List\r
529 //\r
530 for ( Node = (ALIAS_LIST*)GetFirstNode(&List->Link)\r
531 ; !IsNull (&List->Link, &Node->Link)\r
532 ; Node = (ALIAS_LIST *)GetNextNode(&List->Link, &Node->Link)\r
533 ){\r
534 //\r
535 // install the alias'\r
536 //\r
537 Status = InternalSetAlias(Node->CommandString, Node->Alias, TRUE);\r
538 ASSERT_EFI_ERROR(Status);\r
539 }\r
540 return (EFI_SUCCESS);\r
541}\r
542\r
543/**\r
544 Internal function to determine if 2 command names are really the same.\r
545\r
546 @param[in] Command1 The pointer to the first command name.\r
547 @param[in] Command2 The pointer to the second command name.\r
548\r
549 @retval TRUE The 2 command names are the same.\r
550 @retval FALSE The 2 command names are not the same.\r
551**/\r
552BOOLEAN\r
553EFIAPI\r
554IsCommand(\r
555 IN CONST CHAR16 *Command1,\r
556 IN CONST CHAR16 *Command2\r
557 )\r
558{\r
559 if (StringNoCaseCompare(&Command1, &Command2) == 0) {\r
560 return (TRUE);\r
561 }\r
562 return (FALSE);\r
563}\r
564\r
565/**\r
566 Internal function to determine if a command is a script only command.\r
567\r
568 @param[in] CommandName The pointer to the command name.\r
569\r
570 @retval TRUE The command is a script only command.\r
571 @retval FALSE The command is not a script only command.\r
572**/\r
573BOOLEAN\r
574EFIAPI\r
575IsScriptOnlyCommand(\r
576 IN CONST CHAR16 *CommandName\r
577 )\r
578{\r
579 if (IsCommand(CommandName, L"for")\r
580 ||IsCommand(CommandName, L"endfor")\r
581 ||IsCommand(CommandName, L"if")\r
582 ||IsCommand(CommandName, L"else")\r
583 ||IsCommand(CommandName, L"endif")\r
584 ||IsCommand(CommandName, L"goto")) {\r
585 return (TRUE);\r
586 }\r
587 return (FALSE);\r
588}\r
589\r
a405b86d 590/**\r
591 This function will populate the 2 device path protocol parameters based on the\r
592 global gImageHandle. The DevPath will point to the device path for the handle that has\r
593 loaded image protocol installed on it. The FilePath will point to the device path\r
594 for the file that was loaded.\r
595\r
4ff7e37b
ED
596 @param[in, out] DevPath On a sucessful return the device path to the loaded image.\r
597 @param[in, out] FilePath On a sucessful return the device path to the file.\r
a405b86d 598\r
599 @retval EFI_SUCCESS The 2 device paths were sucessfully returned.\r
600 @retval other A error from gBS->HandleProtocol.\r
601\r
602 @sa HandleProtocol\r
603**/\r
604EFI_STATUS\r
605EFIAPI\r
606GetDevicePathsForImageAndFile (\r
607 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath,\r
608 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath\r
609 )\r
610{\r
611 EFI_STATUS Status;\r
612 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
613 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
614\r
615 ASSERT(DevPath != NULL);\r
616 ASSERT(FilePath != NULL);\r
617\r
618 Status = gBS->OpenProtocol (\r
619 gImageHandle,\r
620 &gEfiLoadedImageProtocolGuid,\r
621 (VOID**)&LoadedImage,\r
622 gImageHandle,\r
623 NULL,\r
624 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
625 );\r
626 if (!EFI_ERROR (Status)) {\r
627 Status = gBS->OpenProtocol (\r
628 LoadedImage->DeviceHandle,\r
629 &gEfiDevicePathProtocolGuid,\r
630 (VOID**)&ImageDevicePath,\r
631 gImageHandle,\r
632 NULL,\r
633 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
634 );\r
635 if (!EFI_ERROR (Status)) {\r
636 *DevPath = DuplicateDevicePath (ImageDevicePath);\r
637 *FilePath = DuplicateDevicePath (LoadedImage->FilePath);\r
a49f6a2f 638 gBS->CloseProtocol(\r
639 LoadedImage->DeviceHandle,\r
640 &gEfiDevicePathProtocolGuid,\r
641 gImageHandle,\r
642 NULL);\r
a405b86d 643 }\r
644 gBS->CloseProtocol(\r
645 gImageHandle,\r
646 &gEfiLoadedImageProtocolGuid,\r
647 gImageHandle,\r
648 NULL);\r
649 }\r
650 return (Status);\r
651}\r
652\r
653STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = {\r
654 {L"-nostartup", TypeFlag},\r
655 {L"-startup", TypeFlag},\r
656 {L"-noconsoleout", TypeFlag},\r
657 {L"-noconsolein", TypeFlag},\r
658 {L"-nointerrupt", TypeFlag},\r
659 {L"-nomap", TypeFlag},\r
660 {L"-noversion", TypeFlag},\r
661 {L"-startup", TypeFlag},\r
662 {L"-delay", TypeValue},\r
ca79c798 663 {L"-_exit", TypeFlag},\r
a405b86d 664 {NULL, TypeMax}\r
665 };\r
a49f6a2f 666\r
a405b86d 667/**\r
668 Process all Uefi Shell 2.0 command line options.\r
669\r
670 see Uefi Shell 2.0 section 3.2 for full details.\r
671\r
672 the command line must resemble the following:\r
673\r
674 shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]\r
675\r
676 ShellOpt-options Options which control the initialization behavior of the shell.\r
677 These options are read from the EFI global variable "ShellOpt"\r
678 and are processed before options or file-name.\r
679\r
680 options Options which control the initialization behavior of the shell.\r
681\r
682 file-name The name of a UEFI shell application or script to be executed\r
683 after initialization is complete. By default, if file-name is\r
684 specified, then -nostartup is implied. Scripts are not supported\r
685 by level 0.\r
686\r
687 file-name-options The command-line options that are passed to file-name when it\r
688 is invoked.\r
689\r
690 This will initialize the ShellInfoObject.ShellInitSettings global variable.\r
691\r
692 @retval EFI_SUCCESS The variable is initialized.\r
693**/\r
694EFI_STATUS\r
695EFIAPI\r
696ProcessCommandLine(\r
697 VOID\r
698 )\r
699{\r
700 EFI_STATUS Status;\r
701 LIST_ENTRY *Package;\r
702 UINTN Size;\r
703 CONST CHAR16 *TempConst;\r
704 UINTN Count;\r
705 UINTN LoopVar;\r
706 CHAR16 *ProblemParam;\r
733f138d 707 UINT64 Intermediate;\r
a405b86d 708\r
709 Package = NULL;\r
710 ProblemParam = NULL;\r
711 \r
712 Status = ShellCommandLineParse (mShellParamList, &Package, NULL, FALSE);\r
713\r
714 Count = 1;\r
715 Size = 0;\r
716 TempConst = ShellCommandLineGetRawValue(Package, Count++);\r
717 if (TempConst != NULL && StrLen(TempConst)) {\r
733f138d 718 ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(TempConst));\r
3c865f20 719 if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
720 return (EFI_OUT_OF_RESOURCES);\r
721 }\r
a405b86d 722 StrCpy(ShellInfoObject.ShellInitSettings.FileName, TempConst);\r
723 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
724 for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
725 if (StrCmp(gEfiShellParametersProtocol->Argv[LoopVar], ShellInfoObject.ShellInitSettings.FileName)==0) {\r
726 LoopVar++;\r
727 //\r
728 // We found the file... add the rest of the params...\r
729 //\r
730 for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
731 ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
732 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
733 &Size,\r
734 L" ",\r
735 0);\r
3c865f20 736 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
737 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
738 return (EFI_OUT_OF_RESOURCES);\r
739 }\r
a405b86d 740 StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
741 &Size,\r
742 gEfiShellParametersProtocol->Argv[LoopVar],\r
743 0);\r
3c865f20 744 if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
745 SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
746 return (EFI_OUT_OF_RESOURCES);\r
747 }\r
a405b86d 748 }\r
749 }\r
750 }\r
751 } else {\r
752 ShellCommandLineFreeVarList(Package);\r
753 Package = NULL;\r
754 Status = ShellCommandLineParse (mShellParamList, &Package, &ProblemParam, FALSE);\r
755 if (EFI_ERROR(Status)) {\r
756 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), ShellInfoObject.HiiHandle, ProblemParam);\r
757 FreePool(ProblemParam);\r
758 ShellCommandLineFreeVarList(Package);\r
759 return (EFI_INVALID_PARAMETER);\r
760 }\r
761 }\r
762\r
763 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup = ShellCommandLineGetFlag(Package, L"-startup");\r
764 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = ShellCommandLineGetFlag(Package, L"-nostartup");\r
765 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut = ShellCommandLineGetFlag(Package, L"-noconsoleout");\r
766 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn = ShellCommandLineGetFlag(Package, L"-noconsolein");\r
767 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt = ShellCommandLineGetFlag(Package, L"-nointerrupt");\r
768 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap = ShellCommandLineGetFlag(Package, L"-nomap");\r
769 ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion = ShellCommandLineGetFlag(Package, L"-noversion");\r
770 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay = ShellCommandLineGetFlag(Package, L"-delay");\r
ca79c798 771 ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit = ShellCommandLineGetFlag(Package, L"-_exit");\r
a405b86d 772\r
733f138d 773 ShellInfoObject.ShellInitSettings.Delay = 5;\r
774\r
775 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoInterrupt) {\r
776 ShellInfoObject.ShellInitSettings.Delay = 0;\r
777 } else if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay) {\r
a405b86d 778 TempConst = ShellCommandLineGetValue(Package, L"-delay");\r
33c031ee 779 if (TempConst != NULL && *TempConst == L':') {\r
733f138d 780 TempConst++;\r
781 }\r
782 if (TempConst != NULL && !EFI_ERROR(ShellConvertStringToUint64(TempConst, &Intermediate, FALSE, FALSE))) {\r
783 ShellInfoObject.ShellInitSettings.Delay = (UINTN)Intermediate;\r
a405b86d 784 }\r
a405b86d 785 }\r
a405b86d 786 ShellCommandLineFreeVarList(Package);\r
787\r
788 return (Status);\r
789}\r
790\r
791/**\r
792 Handles all interaction with the default startup script.\r
793\r
794 this will check that the correct command line parameters were passed, handle the delay, and then start running the script.\r
795\r
796 @param ImagePath the path to the image for shell. first place to look for the startup script\r
797 @param FilePath the path to the file for shell. second place to look for the startup script.\r
798\r
799 @retval EFI_SUCCESS the variable is initialized.\r
800**/\r
801EFI_STATUS\r
802EFIAPI\r
803DoStartupScript(\r
804 EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
805 EFI_DEVICE_PATH_PROTOCOL *FilePath\r
806 )\r
807{\r
808 EFI_STATUS Status;\r
809 UINTN Delay;\r
810 EFI_INPUT_KEY Key;\r
811 SHELL_FILE_HANDLE FileHandle;\r
812 EFI_DEVICE_PATH_PROTOCOL *NewPath;\r
813 EFI_DEVICE_PATH_PROTOCOL *NamePath;\r
814 CHAR16 *FileStringPath;\r
733f138d 815 CHAR16 *TempSpot;\r
a405b86d 816 UINTN NewSize;\r
733f138d 817 CONST CHAR16 *MapName;\r
a405b86d 818\r
819 Key.UnicodeChar = CHAR_NULL;\r
820 Key.ScanCode = 0;\r
821 FileHandle = NULL;\r
822\r
823 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
824 //\r
825 // launch something else instead\r
826 //\r
827 NewSize = StrSize(ShellInfoObject.ShellInitSettings.FileName);\r
828 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
829 NewSize += StrSize(ShellInfoObject.ShellInitSettings.FileOptions) + sizeof(CHAR16);\r
830 }\r
831 FileStringPath = AllocateZeroPool(NewSize);\r
3c865f20 832 if (FileStringPath == NULL) {\r
833 return (EFI_OUT_OF_RESOURCES);\r
834 }\r
a405b86d 835 StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
836 if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
3c865f20 837 StrCat(FileStringPath, L" ");\r
a405b86d 838 StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);\r
839 }\r
840 Status = RunCommand(FileStringPath);\r
841 FreePool(FileStringPath);\r
842 return (Status);\r
843\r
844 }\r
845\r
846 //\r
847 // for shell level 0 we do no scripts\r
848 // Without the Startup bit overriding we allow for nostartup to prevent scripts\r
849 //\r
850 if ( (PcdGet8(PcdShellSupportLevel) < 1)\r
851 || (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup)\r
852 ){\r
853 return (EFI_SUCCESS);\r
854 }\r
855\r
5559a41a 856 gST->ConOut->EnableCursor(gST->ConOut, FALSE);\r
a405b86d 857 //\r
858 // print out our warning and see if they press a key\r
859 //\r
284e034f 860 for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay\r
733f138d 861 ; Delay != 0 && EFI_ERROR(Status)\r
a405b86d 862 ; Delay--\r
863 ){\r
284e034f
CP
864 ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay);\r
865 gBS->Stall (1000000);\r
733f138d 866 if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
867 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
868 }\r
a405b86d 869 }\r
870 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle);\r
5559a41a 871 gST->ConOut->EnableCursor(gST->ConOut, TRUE);\r
a405b86d 872\r
873 //\r
874 // ESC was pressed\r
875 //\r
876 if (Status == EFI_SUCCESS && Key.UnicodeChar == 0 && Key.ScanCode == SCAN_ESC) {\r
877 return (EFI_SUCCESS);\r
878 }\r
879\r
a405b86d 880 //\r
733f138d 881 // Try the first location (must be file system)\r
a405b86d 882 //\r
733f138d 883 MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath(&ImagePath);\r
884 if (MapName != NULL) {\r
885 FileStringPath = NULL;\r
886 NewSize = 0;\r
887 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, MapName, 0);\r
532691c8 888 if (FileStringPath == NULL) {\r
889 Status = EFI_OUT_OF_RESOURCES;\r
890 } else {\r
891 TempSpot = StrStr(FileStringPath, L";");\r
892 if (TempSpot != NULL) {\r
893 *TempSpot = CHAR_NULL;\r
894 }\r
895 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, ((FILEPATH_DEVICE_PATH*)FilePath)->PathName, 0);\r
896 PathRemoveLastItem(FileStringPath);\r
897 FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, mStartupScript, 0);\r
898 Status = ShellInfoObject.NewEfiShellProtocol->OpenFileByName(FileStringPath, &FileHandle, EFI_FILE_MODE_READ);\r
899 FreePool(FileStringPath);\r
733f138d 900 }\r
733f138d 901 }\r
a405b86d 902 if (EFI_ERROR(Status)) {\r
733f138d 903 NamePath = FileDevicePath (NULL, mStartupScript);\r
904 NewPath = AppendDevicePathNode (ImagePath, NamePath);\r
905 FreePool(NamePath);\r
906\r
a405b86d 907 //\r
733f138d 908 // Try the location\r
a405b86d 909 //\r
a405b86d 910 Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
733f138d 911 FreePool(NewPath);\r
a405b86d 912 }\r
a405b86d 913 //\r
914 // If we got a file, run it\r
915 //\r
733f138d 916 if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
3c865f20 917 Status = RunScriptFileHandle (FileHandle, mStartupScript);\r
a405b86d 918 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
919 } else {\r
3c865f20 920 FileStringPath = ShellFindFilePath(mStartupScript);\r
921 if (FileStringPath == NULL) {\r
922 //\r
923 // we return success since we dont need to have a startup script\r
924 //\r
925 Status = EFI_SUCCESS;\r
926 ASSERT(FileHandle == NULL);\r
927 } else {\r
928 Status = RunScriptFile(FileStringPath);\r
929 FreePool(FileStringPath);\r
930 }\r
a405b86d 931 }\r
932\r
a405b86d 933\r
934 return (Status);\r
935}\r
936\r
937/**\r
938 Function to perform the shell prompt looping. It will do a single prompt,\r
939 dispatch the result, and then return. It is expected that the caller will\r
940 call this function in a loop many times.\r
941\r
942 @retval EFI_SUCCESS\r
943 @retval RETURN_ABORTED\r
944**/\r
945EFI_STATUS\r
946EFIAPI\r
947DoShellPrompt (\r
948 VOID\r
949 )\r
950{\r
951 UINTN Column;\r
952 UINTN Row;\r
953 CHAR16 *CmdLine;\r
954 CONST CHAR16 *CurDir;\r
955 UINTN BufferSize;\r
956 EFI_STATUS Status;\r
957\r
958 CurDir = NULL;\r
959\r
960 //\r
961 // Get screen setting to decide size of the command line buffer\r
962 //\r
963 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &Column, &Row);\r
964 BufferSize = Column * Row * sizeof (CHAR16);\r
965 CmdLine = AllocateZeroPool (BufferSize);\r
966 if (CmdLine == NULL) {\r
967 return EFI_OUT_OF_RESOURCES;\r
968 }\r
969\r
970 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
971\r
972 //\r
973 // Prompt for input\r
974 //\r
975 gST->ConOut->SetCursorPosition (gST->ConOut, 0, gST->ConOut->Mode->CursorRow);\r
976\r
977 if (CurDir != NULL && StrLen(CurDir) > 1) {\r
978 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);\r
979 } else {\r
980 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);\r
981 }\r
982\r
983 //\r
984 // Read a line from the console\r
985 //\r
986 Status = ShellInfoObject.NewEfiShellProtocol->ReadFile(ShellInfoObject.NewShellParametersProtocol->StdIn, &BufferSize, CmdLine);\r
987\r
988 //\r
989 // Null terminate the string and parse it\r
990 //\r
991 if (!EFI_ERROR (Status)) {\r
992 CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
993 Status = RunCommand(CmdLine);\r
994 }\r
995\r
996 //\r
997 // Done with this command\r
998 //\r
999 FreePool (CmdLine);\r
1000 return Status;\r
1001}\r
1002\r
1003/**\r
1004 Add a buffer to the Buffer To Free List for safely returning buffers to other\r
1005 places without risking letting them modify internal shell information.\r
1006\r
1007 @param Buffer Something to pass to FreePool when the shell is exiting.\r
1008**/\r
1009VOID*\r
1010EFIAPI\r
1011AddBufferToFreeList(\r
1012 VOID *Buffer\r
1013 )\r
1014{\r
1015 BUFFER_LIST *BufferListEntry;\r
1016\r
1017 if (Buffer == NULL) {\r
1018 return (NULL);\r
1019 }\r
1020\r
1021 BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST));\r
1022 ASSERT(BufferListEntry != NULL);\r
1023 BufferListEntry->Buffer = Buffer;\r
1024 InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
1025 return (Buffer);\r
1026}\r
1027\r
1028/**\r
1029 Add a buffer to the Line History List\r
1030\r
1031 @param Buffer The line buffer to add.\r
1032**/\r
1033VOID\r
1034EFIAPI\r
1035AddLineToCommandHistory(\r
1036 IN CONST CHAR16 *Buffer\r
1037 )\r
1038{\r
1039 BUFFER_LIST *Node;\r
1040\r
1041 Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
1042 ASSERT(Node != NULL);\r
1043 Node->Buffer = AllocateZeroPool(StrSize(Buffer));\r
1044 ASSERT(Node->Buffer != NULL);\r
1045 StrCpy(Node->Buffer, Buffer);\r
1046\r
1047 InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
1048}\r
1049\r
1050/**\r
1051 Checks if a string is an alias for another command. If yes, then it replaces the alias name\r
1052 with the correct command name.\r
1053\r
4ff7e37b
ED
1054 @param[in, out] CommandString Upon entry the potential alias. Upon return the\r
1055 command name if it was an alias. If it was not\r
1056 an alias it will be unchanged. This function may\r
1057 change the buffer to fit the command name.\r
a405b86d 1058\r
1059 @retval EFI_SUCCESS The name was changed.\r
1060 @retval EFI_SUCCESS The name was not an alias.\r
1061 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
1062**/\r
1063EFI_STATUS\r
1064EFIAPI\r
1065ShellConvertAlias(\r
1066 IN OUT CHAR16 **CommandString\r
1067 )\r
1068{\r
1069 CONST CHAR16 *NewString;\r
1070\r
1071 NewString = ShellInfoObject.NewEfiShellProtocol->GetAlias(*CommandString, NULL);\r
1072 if (NewString == NULL) {\r
1073 return (EFI_SUCCESS);\r
1074 }\r
1075 FreePool(*CommandString);\r
733f138d 1076 *CommandString = AllocateZeroPool(StrSize(NewString));\r
a405b86d 1077 if (*CommandString == NULL) {\r
1078 return (EFI_OUT_OF_RESOURCES);\r
1079 }\r
1080 StrCpy(*CommandString, NewString);\r
1081 return (EFI_SUCCESS);\r
1082}\r
1083\r
1084/**\r
1085 Function allocates a new command line and replaces all instances of environment\r
1086 variable names that are correctly preset to their values.\r
1087\r
1088 If the return value is not NULL the memory must be caller freed.\r
1089\r
1090 @param[in] OriginalCommandLine The original command line\r
1091\r
1092 @retval NULL An error ocurred.\r
1093 @return The new command line with no environment variables present.\r
1094**/\r
1095CHAR16*\r
1096EFIAPI\r
1097ShellConvertVariables (\r
1098 IN CONST CHAR16 *OriginalCommandLine\r
1099 )\r
1100{\r
1101 CONST CHAR16 *MasterEnvList;\r
1102 UINTN NewSize;\r
1103 CHAR16 *NewCommandLine1;\r
1104 CHAR16 *NewCommandLine2;\r
1105 CHAR16 *Temp;\r
df07baea 1106 CHAR16 *Temp2;\r
a405b86d 1107 UINTN ItemSize;\r
1108 CHAR16 *ItemTemp;\r
1109 SCRIPT_FILE *CurrentScriptFile;\r
1110 ALIAS_LIST *AliasListNode;\r
1111\r
1112 ASSERT(OriginalCommandLine != NULL);\r
1113\r
1114 ItemSize = 0;\r
1115 NewSize = StrSize(OriginalCommandLine);\r
1116 CurrentScriptFile = ShellCommandGetCurrentScriptFile();\r
1117 Temp = NULL;\r
1118\r
1119 ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ?\r
1120\r
1121 //\r
1122 // calculate the size required for the post-conversion string...\r
1123 //\r
1124 if (CurrentScriptFile != NULL) {\r
1125 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
1126 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1127 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1128 ){\r
1129 for (Temp = StrStr(OriginalCommandLine, AliasListNode->Alias)\r
1130 ; Temp != NULL\r
1131 ; Temp = StrStr(Temp+1, AliasListNode->Alias)\r
1132 ){\r
1133 //\r
1134 // we need a preceeding and if there is space no ^ preceeding (if no space ignore)\r
1135 //\r
1136 if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) {\r
1137 NewSize += StrSize(AliasListNode->CommandString);\r
1138 }\r
1139 }\r
1140 }\r
1141 }\r
1142\r
1143 for (MasterEnvList = EfiShellGetEnv(NULL)\r
1144 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
1145 ; MasterEnvList += StrLen(MasterEnvList) + 1\r
1146 ){\r
1147 if (StrSize(MasterEnvList) > ItemSize) {\r
1148 ItemSize = StrSize(MasterEnvList);\r
1149 }\r
1150 for (Temp = StrStr(OriginalCommandLine, MasterEnvList)\r
1151 ; Temp != NULL\r
1152 ; Temp = StrStr(Temp+1, MasterEnvList)\r
1153 ){\r
1154 //\r
1155 // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)\r
1156 //\r
1157 if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' &&\r
1158 ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) {\r
1159 NewSize+=StrSize(EfiShellGetEnv(MasterEnvList));\r
1160 }\r
1161 }\r
1162 }\r
1163\r
a405b86d 1164 //\r
1165 // now do the replacements...\r
1166 //\r
1167 NewCommandLine1 = AllocateZeroPool(NewSize);\r
1168 NewCommandLine2 = AllocateZeroPool(NewSize);\r
1169 ItemTemp = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
3c865f20 1170 if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
1171 SHELL_FREE_NON_NULL(NewCommandLine1);\r
1172 SHELL_FREE_NON_NULL(NewCommandLine2);\r
1173 SHELL_FREE_NON_NULL(ItemTemp);\r
1174 return (NULL);\r
1175 }\r
a405b86d 1176 StrCpy(NewCommandLine1, OriginalCommandLine);\r
1177 for (MasterEnvList = EfiShellGetEnv(NULL)\r
1178 ; MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
1179 ; MasterEnvList += StrLen(MasterEnvList) + 1\r
1180 ){\r
1181 StrCpy(ItemTemp, L"%");\r
1182 StrCat(ItemTemp, MasterEnvList);\r
1183 StrCat(ItemTemp, L"%");\r
1184 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
1185 StrCpy(NewCommandLine1, NewCommandLine2);\r
1186 }\r
1187 if (CurrentScriptFile != NULL) {\r
1188 for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
1189 ; !IsNull(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1190 ; AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
1191 ){\r
1192 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
1193 StrCpy(NewCommandLine1, NewCommandLine2);\r
1194 }\r
df07baea
JC
1195\r
1196 //\r
1197 // Remove non-existant environment variables in scripts only\r
1198 //\r
1199 for (Temp = NewCommandLine1 ; Temp != NULL ; ) {\r
1200 Temp = StrStr(Temp, L"%");\r
1201 if (Temp == NULL) {\r
1202 break;\r
1203 }\r
1204 while (*(Temp - 1) == L'^') {\r
1205 Temp = StrStr(Temp + 1, L"%");\r
1206 if (Temp == NULL) {\r
1207 break;\r
1208 }\r
1209 }\r
1210 if (Temp == NULL) {\r
1211 break;\r
1212 }\r
1213 \r
1214 Temp2 = StrStr(Temp + 1, L"%");\r
1215 if (Temp2 == NULL) {\r
1216 break;\r
1217 }\r
1218 while (*(Temp2 - 1) == L'^') {\r
1219 Temp2 = StrStr(Temp2 + 1, L"%");\r
1220 if (Temp2 == NULL) {\r
1221 break;\r
1222 }\r
1223 }\r
1224 if (Temp2 == NULL) {\r
1225 break;\r
1226 }\r
1227 \r
1228 Temp2++;\r
1229 CopyMem(Temp, Temp2, StrSize(Temp2));\r
1230 }\r
1231\r
a405b86d 1232 }\r
1233\r
df07baea
JC
1234 //\r
1235 // Now cleanup any straggler intentionally ignored "%" characters\r
1236 //\r
1237 ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
1238 StrCpy(NewCommandLine1, NewCommandLine2);\r
1239 \r
a405b86d 1240 FreePool(NewCommandLine2);\r
1241 FreePool(ItemTemp);\r
1242\r
1243 return (NewCommandLine1);\r
1244}\r
1245\r
1246/**\r
1247 Internal function to run a command line with pipe usage.\r
1248\r
1249 @param[in] CmdLine The pointer to the command line.\r
1250 @param[in] StdIn The pointer to the Standard input.\r
1251 @param[in] StdOut The pointer to the Standard output.\r
1252\r
1253 @retval EFI_SUCCESS The split command is executed successfully.\r
1254 @retval other Some error occurs when executing the split command.\r
1255**/\r
1256EFI_STATUS\r
1257EFIAPI\r
1258RunSplitCommand(\r
1259 IN CONST CHAR16 *CmdLine,\r
1260 IN SHELL_FILE_HANDLE *StdIn,\r
1261 IN SHELL_FILE_HANDLE *StdOut\r
1262 )\r
1263{\r
1264 EFI_STATUS Status;\r
1265 CHAR16 *NextCommandLine;\r
1266 CHAR16 *OurCommandLine;\r
1267 UINTN Size1;\r
1268 UINTN Size2;\r
1269 SPLIT_LIST *Split;\r
1270 SHELL_FILE_HANDLE *TempFileHandle;\r
1271 BOOLEAN Unicode;\r
1272\r
1273 ASSERT(StdOut == NULL);\r
1274\r
1275 ASSERT(StrStr(CmdLine, L"|") != NULL);\r
1276\r
1277 Status = EFI_SUCCESS;\r
1278 NextCommandLine = NULL;\r
1279 OurCommandLine = NULL;\r
1280 Size1 = 0;\r
1281 Size2 = 0;\r
1282\r
1283 NextCommandLine = StrnCatGrow(&NextCommandLine, &Size1, StrStr(CmdLine, L"|")+1, 0);\r
1284 OurCommandLine = StrnCatGrow(&OurCommandLine , &Size2, CmdLine , StrStr(CmdLine, L"|") - CmdLine);\r
532691c8 1285\r
1286 if (NextCommandLine == NULL || OurCommandLine == NULL) {\r
1287 SHELL_FREE_NON_NULL(OurCommandLine);\r
1288 SHELL_FREE_NON_NULL(NextCommandLine);\r
1289 return (EFI_OUT_OF_RESOURCES);\r
19216573 1290 } else if (StrStr(OurCommandLine, L"|") != NULL || Size1 == 0 || Size2 == 0) {\r
1291 SHELL_FREE_NON_NULL(OurCommandLine);\r
1292 SHELL_FREE_NON_NULL(NextCommandLine);\r
1293 return (EFI_INVALID_PARAMETER);\r
1294 } else if (NextCommandLine[0] != CHAR_NULL &&\r
a405b86d 1295 NextCommandLine[0] == L'a' &&\r
1296 NextCommandLine[1] == L' '\r
1297 ){\r
1298 CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0]));\r
1299 Unicode = FALSE;\r
1300 } else {\r
1301 Unicode = TRUE;\r
1302 }\r
1303\r
1304\r
1305 //\r
1306 // make a SPLIT_LIST item and add to list\r
1307 //\r
1308 Split = AllocateZeroPool(sizeof(SPLIT_LIST));\r
1309 ASSERT(Split != NULL);\r
1310 Split->SplitStdIn = StdIn;\r
1311 Split->SplitStdOut = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL);\r
1312 ASSERT(Split->SplitStdOut != NULL);\r
1313 InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);\r
1314\r
a405b86d 1315 Status = RunCommand(OurCommandLine);\r
1316\r
1317 //\r
1318 // move the output from the first to the in to the second.\r
1319 //\r
1320 TempFileHandle = Split->SplitStdOut;\r
1321 if (Split->SplitStdIn == StdIn) {\r
1322 Split->SplitStdOut = NULL;\r
1323 } else {\r
1324 Split->SplitStdOut = Split->SplitStdIn;\r
1325 }\r
1326 Split->SplitStdIn = TempFileHandle;\r
1327 ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
1328\r
1329 if (!EFI_ERROR(Status)) {\r
1330 Status = RunCommand(NextCommandLine);\r
1331 }\r
1332\r
1333 //\r
1334 // remove the top level from the ScriptList\r
1335 //\r
1336 ASSERT((SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link) == Split);\r
1337 RemoveEntryList(&Split->Link);\r
1338\r
1339 //\r
1340 // Note that the original StdIn is now the StdOut...\r
1341 //\r
1342 if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) {\r
1343 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));\r
1344 }\r
1345 if (Split->SplitStdIn != NULL) {\r
1346 ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));\r
1347 }\r
1348\r
1349 FreePool(Split);\r
1350 FreePool(NextCommandLine);\r
1351 FreePool(OurCommandLine);\r
1352\r
1353 return (Status);\r
1354}\r
1355\r
1356/**\r
1357 Function will process and run a command line.\r
1358\r
1359 This will determine if the command line represents an internal shell \r
1360 command or dispatch an external application.\r
1361\r
1362 @param[in] CmdLine The command line to parse.\r
1363\r
1364 @retval EFI_SUCCESS The command was completed.\r
1365 @retval EFI_ABORTED The command's operation was aborted.\r
1366**/\r
1367EFI_STATUS\r
1368EFIAPI\r
1369RunCommand(\r
1370 IN CONST CHAR16 *CmdLine\r
1371 )\r
1372{\r
1373 EFI_STATUS Status;\r
64c7a749 1374 EFI_STATUS StatusCode;\r
a405b86d 1375 CHAR16 *CommandName;\r
1376 SHELL_STATUS ShellStatus;\r
1377 UINTN Argc;\r
1378 CHAR16 **Argv;\r
1379 BOOLEAN LastError;\r
ed34da40 1380 CHAR16 LeString[19];\r
a405b86d 1381 CHAR16 *PostAliasCmdLine;\r
1382 UINTN PostAliasSize;\r
1383 CHAR16 *PostVariableCmdLine;\r
1384 CHAR16 *CommandWithPath;\r
733f138d 1385 CONST EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
a405b86d 1386 CONST CHAR16 *TempLocation;\r
1387 CONST CHAR16 *TempLocation2;\r
1388 SHELL_FILE_HANDLE OriginalStdIn;\r
1389 SHELL_FILE_HANDLE OriginalStdOut;\r
1390 SHELL_FILE_HANDLE OriginalStdErr;\r
8be0ba36 1391 SYSTEM_TABLE_INFO OriginalSystemTableInfo;\r
a405b86d 1392 CHAR16 *TempLocation3;\r
1393 UINTN Count;\r
1394 UINTN Count2;\r
1395 CHAR16 *CleanOriginal;\r
1396 SPLIT_LIST *Split;\r
1397\r
1398 ASSERT(CmdLine != NULL);\r
1399 if (StrLen(CmdLine) == 0) {\r
1400 return (EFI_SUCCESS);\r
1401 }\r
1402\r
1403 CommandName = NULL;\r
1404 PostVariableCmdLine = NULL;\r
1405 PostAliasCmdLine = NULL;\r
1406 CommandWithPath = NULL;\r
1407 DevPath = NULL;\r
1408 Status = EFI_SUCCESS;\r
1409 CleanOriginal = NULL;\r
1410 Split = NULL;\r
1411\r
1412 CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0);\r
532691c8 1413 if (CleanOriginal == NULL) {\r
1414 return (EFI_OUT_OF_RESOURCES);\r
1415 }\r
284e034f
CP
1416\r
1417 //\r
13acebbd 1418 // Remove any spaces and tabs at the beginning of the string.\r
284e034f 1419 //\r
13acebbd 1420 while ((CleanOriginal[0] == L' ') || (CleanOriginal[0] == L'\t')) {\r
a405b86d 1421 CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));\r
1422 }\r
1423\r
284e034f
CP
1424 //\r
1425 // Handle case that passed in command line is just 1 or more " " characters.\r
1426 //\r
1427 if (StrLen (CleanOriginal) == 0) {\r
1428 if (CleanOriginal != NULL) {\r
1429 FreePool(CleanOriginal);\r
1430 CleanOriginal = NULL;\r
1431 }\r
1432 return (EFI_SUCCESS);\r
1433 }\r
1434\r
1435 //\r
1436 // Remove any spaces at the end of the string.\r
1437 //\r
1438 while (CleanOriginal[StrLen(CleanOriginal)-1] == L' ') {\r
1439 CleanOriginal[StrLen(CleanOriginal)-1] = CHAR_NULL;\r
1440 }\r
1441\r
a405b86d 1442 CommandName = NULL;\r
1443 if (StrStr(CleanOriginal, L" ") == NULL){\r
1444 StrnCatGrow(&CommandName, NULL, CleanOriginal, 0);\r
1445 } else {\r
1446 StrnCatGrow(&CommandName, NULL, CleanOriginal, StrStr(CleanOriginal, L" ") - CleanOriginal);\r
1447 }\r
1448\r
1449 ASSERT(PostAliasCmdLine == NULL);\r
1450 if (!ShellCommandIsCommandOnList(CommandName)) {\r
1451 //\r
1452 // Convert via alias\r
1453 //\r
1454 Status = ShellConvertAlias(&CommandName);\r
1455 PostAliasSize = 0;\r
1456 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, CommandName, 0);\r
1457 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, &PostAliasSize, StrStr(CleanOriginal, L" "), 0);\r
1458 ASSERT_EFI_ERROR(Status);\r
1459 } else {\r
1460 PostAliasCmdLine = StrnCatGrow(&PostAliasCmdLine, NULL, CleanOriginal, 0);\r
1461 }\r
1462\r
1463 if (CleanOriginal != NULL) {\r
1464 FreePool(CleanOriginal);\r
1465 CleanOriginal = NULL;\r
1466 }\r
1467\r
1468 if (CommandName != NULL) {\r
1469 FreePool(CommandName);\r
1470 CommandName = NULL;\r
1471 }\r
1472\r
1473 PostVariableCmdLine = ShellConvertVariables(PostAliasCmdLine);\r
1474\r
1475 //\r
1476 // we can now free the modified by alias command line\r
1477 //\r
1478 if (PostAliasCmdLine != NULL) {\r
1479 FreePool(PostAliasCmdLine);\r
1480 PostAliasCmdLine = NULL;\r
1481 }\r
1482\r
3c865f20 1483 if (PostVariableCmdLine == NULL) {\r
1484 return (EFI_OUT_OF_RESOURCES);\r
1485 }\r
1486\r
a405b86d 1487 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {\r
1488 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;\r
1489 }\r
1490 while (PostVariableCmdLine[0] == L' ') {\r
1491 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));\r
1492 }\r
1493\r
1494 //\r
1495 // We dont do normal processing with a split command line (output from one command input to another)\r
1496 //\r
1497 TempLocation3 = NULL;\r
1498 if (StrStr(PostVariableCmdLine, L"|") != NULL) {\r
1499 for (TempLocation3 = PostVariableCmdLine ; TempLocation3 != NULL && *TempLocation3 != CHAR_NULL ; TempLocation3++) {\r
1500 if (*TempLocation3 == L'^' && *(TempLocation3+1) == L'|') {\r
1501 TempLocation3++;\r
1502 } else if (*TempLocation3 == L'|') {\r
1503 break;\r
1504 }\r
1505 }\r
1506 }\r
1507 if (TempLocation3 != NULL && *TempLocation3 != CHAR_NULL) {\r
1508 //\r
1509 // are we in an existing split???\r
1510 //\r
1511 if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {\r
1512 Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);\r
1513 }\r
1514\r
1515 if (Split == NULL) {\r
1516 Status = RunSplitCommand(PostVariableCmdLine, NULL, NULL);\r
1517 } else {\r
1518 Status = RunSplitCommand(PostVariableCmdLine, Split->SplitStdIn, Split->SplitStdOut);\r
1519 }\r
19216573 1520 if (EFI_ERROR(Status)) {\r
1521 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, PostVariableCmdLine);\r
1522 }\r
a405b86d 1523 } else {\r
1524\r
1525 //\r
1526 // If this is a mapped drive change handle that...\r
1527 //\r
1528 if (PostVariableCmdLine[(StrLen(PostVariableCmdLine)-1)] == L':' && StrStr(PostVariableCmdLine, L" ") == NULL) {\r
1529 Status = ShellInfoObject.NewEfiShellProtocol->SetCurDir(NULL, PostVariableCmdLine);\r
1530 if (EFI_ERROR(Status)) {\r
1531 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_MAPPING), ShellInfoObject.HiiHandle, PostVariableCmdLine);\r
1532 }\r
1533 FreePool(PostVariableCmdLine);\r
1534 return (Status);\r
1535 }\r
1536\r
1537 ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file...\r
1538 /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files...\r
1539\r
1540\r
1541\r
8be0ba36 1542 Status = UpdateStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);\r
a405b86d 1543 if (EFI_ERROR(Status)) {\r
733f138d 1544 if (Status == EFI_NOT_FOUND) {\r
1545 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle);\r
1546 } else {\r
1547 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);\r
1548 }\r
a405b86d 1549 } else {\r
a405b86d 1550 while (PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] == L' ') {\r
1551 PostVariableCmdLine[StrLen(PostVariableCmdLine)-1] = CHAR_NULL;\r
1552 }\r
1553 while (PostVariableCmdLine[0] == L' ') {\r
1554 CopyMem(PostVariableCmdLine, PostVariableCmdLine+1, StrSize(PostVariableCmdLine) - sizeof(PostVariableCmdLine[0]));\r
1555 }\r
1556\r
1557 //\r
1558 // get the argc and argv updated for internal commands\r
1559 //\r
1560 Status = UpdateArgcArgv(ShellInfoObject.NewShellParametersProtocol, PostVariableCmdLine, &Argv, &Argc);\r
1561 ASSERT_EFI_ERROR(Status);\r
1562\r
1563 for (Count = 0 ; Count < ShellInfoObject.NewShellParametersProtocol->Argc ; Count++) {\r
1564 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[Count], L"-?") == ShellInfoObject.NewShellParametersProtocol->Argv[Count]\r
1565 || (ShellInfoObject.NewShellParametersProtocol->Argv[0][0] == L'?' && ShellInfoObject.NewShellParametersProtocol->Argv[0][1] == CHAR_NULL)\r
1566 ) {\r
1567 //\r
1568 // We need to redo the arguments since a parameter was -?\r
1569 // move them all down 1 to the end, then up one then replace the first with help\r
1570 //\r
1571 FreePool(ShellInfoObject.NewShellParametersProtocol->Argv[Count]);\r
1572 ShellInfoObject.NewShellParametersProtocol->Argv[Count] = NULL;\r
1573 for (Count2 = Count ; (Count2 + 1) < ShellInfoObject.NewShellParametersProtocol->Argc ; Count2++) {\r
1574 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2+1];\r
1575 }\r
1576 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = NULL;\r
1577 for (Count2 = ShellInfoObject.NewShellParametersProtocol->Argc -1 ; Count2 > 0 ; Count2--) {\r
1578 ShellInfoObject.NewShellParametersProtocol->Argv[Count2] = ShellInfoObject.NewShellParametersProtocol->Argv[Count2-1];\r
1579 }\r
1580 ShellInfoObject.NewShellParametersProtocol->Argv[0] = NULL;\r
1581 ShellInfoObject.NewShellParametersProtocol->Argv[0] = StrnCatGrow(&ShellInfoObject.NewShellParametersProtocol->Argv[0], NULL, L"help", 0);\r
1582 break;\r
1583 }\r
1584 }\r
1585\r
1586 //\r
1587 // command or file?\r
1588 //\r
1589 if (ShellCommandIsCommandOnList(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1590 //\r
1591 // Run the command (which was converted if it was an alias)\r
1592 //\r
1593 if (!EFI_ERROR(Status)) {\r
1594 Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError);\r
1595 ASSERT_EFI_ERROR(Status);\r
5b5cd144
CP
1596\r
1597 if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
1598 UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellStatus);\r
1599 } else {\r
1600 UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", ShellStatus);\r
1601 }\r
1602 DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
a405b86d 1603 if (LastError) {\r
5b5cd144 1604 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
a405b86d 1605 }\r
1606 //\r
1607 // Pass thru the exitcode from the app.\r
1608 //\r
1609 if (ShellCommandGetExit()) {\r
1610 Status = ShellStatus;\r
1611 } else if (ShellStatus != 0 && IsScriptOnlyCommand(ShellInfoObject.NewShellParametersProtocol->Argv[0])) {\r
1612 Status = EFI_ABORTED;\r
1613 }\r
1614 }\r
1615 } else {\r
1616 //\r
1617 // run an external file (or script)\r
1618 //\r
1619 if (StrStr(ShellInfoObject.NewShellParametersProtocol->Argv[0], L":") != NULL) {\r
1620 ASSERT (CommandWithPath == NULL);\r
1621 if (ShellIsFile(ShellInfoObject.NewShellParametersProtocol->Argv[0]) == EFI_SUCCESS) {\r
1622 CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1623 }\r
1624 }\r
1625 if (CommandWithPath == NULL) {\r
1626 CommandWithPath = ShellFindFilePathEx(ShellInfoObject.NewShellParametersProtocol->Argv[0], mExecutableExtensions);\r
1627 }\r
1628 if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) {\r
1629 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]);\r
5b5cd144
CP
1630\r
1631 if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
1632 UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", EFI_NOT_FOUND);\r
1633 } else {\r
1634 UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", EFI_NOT_FOUND);\r
1635 }\r
1636 DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
1637 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
a405b86d 1638 } else {\r
1639 //\r
1640 // Check if it's a NSH (script) file.\r
1641 //\r
1642 TempLocation = CommandWithPath+StrLen(CommandWithPath)-4;\r
1643 TempLocation2 = mScriptExtension;\r
1644 if ((StrLen(CommandWithPath) > 4) && (StringNoCaseCompare((VOID*)(&TempLocation), (VOID*)(&TempLocation2)) == 0)) {\r
1645 Status = RunScriptFile (CommandWithPath);\r
1646 } else {\r
1647 DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath);\r
1648 ASSERT(DevPath != NULL);\r
1649 Status = InternalShellExecuteDevicePath(\r
1650 &gImageHandle,\r
1651 DevPath,\r
1652 PostVariableCmdLine,\r
1653 NULL,\r
64c7a749 1654 &StatusCode\r
a405b86d 1655 );\r
64c7a749
ED
1656\r
1657 //\r
5b5cd144 1658 // Update last error status.\r
64c7a749 1659 //\r
5b5cd144
CP
1660 if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
1661 UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", StatusCode);\r
1662 } else {\r
1663 UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", StatusCode);\r
1664 }\r
1665 DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
1666 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
a405b86d 1667 }\r
1668 }\r
1669 }\r
64c7a749
ED
1670\r
1671 //\r
1672 // Print some error info.\r
1673 //\r
1674 if (EFI_ERROR(Status)) {\r
1675 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
1676 }\r
1677\r
a405b86d 1678 CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
1679\r
1680 RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);\r
1681\r
8be0ba36 1682 RestoreStdInStdOutStdErr(ShellInfoObject.NewShellParametersProtocol, &OriginalStdIn, &OriginalStdOut, &OriginalStdErr, &OriginalSystemTableInfo);\r
a405b86d 1683 }\r
1684 if (CommandName != NULL) {\r
1685 if (ShellCommandGetCurrentScriptFile() != NULL && !IsScriptOnlyCommand(CommandName)) {\r
1686 //\r
1687 // if this is NOT a scipt only command return success so the script won't quit.\r
1688 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)\r
1689 //\r
1690 Status = EFI_SUCCESS;\r
1691 }\r
1692 }\r
1693 }\r
1694\r
1695 SHELL_FREE_NON_NULL(CommandName);\r
1696 SHELL_FREE_NON_NULL(CommandWithPath);\r
1697 SHELL_FREE_NON_NULL(PostVariableCmdLine);\r
a405b86d 1698\r
1699 return (Status);\r
1700}\r
1701\r
1702STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
1703/**\r
1704 Function determins if the CommandName COULD be a valid command. It does not determine whether\r
1705 this is a valid command. It only checks for invalid characters.\r
1706\r
1707 @param[in] CommandName The name to check\r
1708\r
1709 @retval TRUE CommandName could be a command name\r
1710 @retval FALSE CommandName could not be a valid command name\r
1711**/\r
1712BOOLEAN\r
1713EFIAPI\r
1714IsValidCommandName(\r
1715 IN CONST CHAR16 *CommandName\r
1716 )\r
1717{\r
1718 UINTN Count;\r
1719 if (CommandName == NULL) {\r
1720 ASSERT(FALSE);\r
1721 return (FALSE);\r
1722 }\r
1723 for ( Count = 0\r
1724 ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
1725 ; Count++\r
1726 ){\r
1727 if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
1728 return (FALSE);\r
1729 }\r
1730 }\r
1731 return (TRUE);\r
1732}\r
1733\r
1734/**\r
1735 Function to process a NSH script file via SHELL_FILE_HANDLE.\r
1736\r
1737 @param[in] Handle The handle to the already opened file.\r
1738 @param[in] Name The name of the script file.\r
1739\r
1740 @retval EFI_SUCCESS the script completed sucessfully\r
1741**/\r
1742EFI_STATUS\r
1743EFIAPI\r
1744RunScriptFileHandle (\r
1745 IN SHELL_FILE_HANDLE Handle,\r
1746 IN CONST CHAR16 *Name\r
1747 )\r
1748{\r
1749 EFI_STATUS Status;\r
1750 SCRIPT_FILE *NewScriptFile;\r
1751 UINTN LoopVar;\r
1752 CHAR16 *CommandLine;\r
1753 CHAR16 *CommandLine2;\r
1754 CHAR16 *CommandLine3;\r
1755 SCRIPT_COMMAND_LIST *LastCommand;\r
1756 BOOLEAN Ascii;\r
1757 BOOLEAN PreScriptEchoState;\r
848997b5 1758 BOOLEAN PreCommandEchoState;\r
a405b86d 1759 CONST CHAR16 *CurDir;\r
1760 UINTN LineCount;\r
b6b22b13 1761 CHAR16 LeString[50];\r
a405b86d 1762\r
1763 ASSERT(!ShellCommandGetScriptExit());\r
1764\r
1765 PreScriptEchoState = ShellCommandGetEchoState();\r
1766\r
1767 NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));\r
3c865f20 1768 if (NewScriptFile == NULL) {\r
1769 return (EFI_OUT_OF_RESOURCES);\r
1770 }\r
a405b86d 1771\r
1772 //\r
1773 // Set up the name\r
1774 //\r
1775 ASSERT(NewScriptFile->ScriptName == NULL);\r
1776 NewScriptFile->ScriptName = StrnCatGrow(&NewScriptFile->ScriptName, NULL, Name, 0);\r
3c865f20 1777 if (NewScriptFile->ScriptName == NULL) {\r
1778 DeleteScriptFileStruct(NewScriptFile);\r
1779 return (EFI_OUT_OF_RESOURCES);\r
1780 }\r
a405b86d 1781\r
1782 //\r
1783 // Save the parameters (used to replace %0 to %9 later on)\r
1784 //\r
1785 NewScriptFile->Argc = ShellInfoObject.NewShellParametersProtocol->Argc;\r
1786 if (NewScriptFile->Argc != 0) {\r
1787 NewScriptFile->Argv = (CHAR16**)AllocateZeroPool(NewScriptFile->Argc * sizeof(CHAR16*));\r
3c865f20 1788 if (NewScriptFile->Argv == NULL) {\r
1789 DeleteScriptFileStruct(NewScriptFile);\r
1790 return (EFI_OUT_OF_RESOURCES);\r
1791 }\r
a405b86d 1792 for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
1793 ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
1794 NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
3c865f20 1795 if (NewScriptFile->Argv[LoopVar] == NULL) {\r
1796 DeleteScriptFileStruct(NewScriptFile);\r
1797 return (EFI_OUT_OF_RESOURCES);\r
1798 }\r
a405b86d 1799 }\r
1800 } else {\r
1801 NewScriptFile->Argv = NULL;\r
1802 }\r
1803\r
1804 InitializeListHead(&NewScriptFile->CommandList);\r
1805 InitializeListHead(&NewScriptFile->SubstList);\r
1806\r
1807 //\r
1808 // Now build the list of all script commands.\r
1809 //\r
1810 LineCount = 0;\r
1811 while(!ShellFileHandleEof(Handle)) {\r
1812 CommandLine = ShellFileHandleReturnLine(Handle, &Ascii);\r
1813 LineCount++;\r
1814 if (CommandLine == NULL || StrLen(CommandLine) == 0) {\r
1815 continue;\r
1816 }\r
1817 NewScriptFile->CurrentCommand = AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST));\r
3c865f20 1818 if (NewScriptFile->CurrentCommand == NULL) {\r
1819 DeleteScriptFileStruct(NewScriptFile);\r
1820 return (EFI_OUT_OF_RESOURCES);\r
1821 }\r
a405b86d 1822\r
1823 NewScriptFile->CurrentCommand->Cl = CommandLine;\r
1824 NewScriptFile->CurrentCommand->Data = NULL;\r
1825 NewScriptFile->CurrentCommand->Line = LineCount;\r
1826\r
1827 InsertTailList(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1828 }\r
1829\r
1830 //\r
1831 // Add this as the topmost script file\r
1832 //\r
1833 ShellCommandSetNewScript (NewScriptFile);\r
1834\r
1835 //\r
1836 // Now enumerate through the commands and run each one.\r
1837 //\r
733f138d 1838 CommandLine = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1839 if (CommandLine == NULL) {\r
1840 DeleteScriptFileStruct(NewScriptFile);\r
1841 return (EFI_OUT_OF_RESOURCES);\r
1842 }\r
733f138d 1843 CommandLine2 = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
3c865f20 1844 if (CommandLine2 == NULL) {\r
1845 FreePool(CommandLine);\r
1846 DeleteScriptFileStruct(NewScriptFile);\r
1847 return (EFI_OUT_OF_RESOURCES);\r
1848 }\r
a405b86d 1849\r
1850 for ( NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&NewScriptFile->CommandList)\r
1851 ; !IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)\r
1852 ; // conditional increment in the body of the loop\r
1853 ){\r
3c865f20 1854 ASSERT(CommandLine2 != NULL);\r
a405b86d 1855 StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
1856\r
1857 //\r
1858 // NULL out comments\r
1859 //\r
1860 for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
1861 if (*CommandLine3 == L'^') {\r
1862 if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
1863 CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
1864 }\r
1865 } else if (*CommandLine3 == L'#') {\r
1866 *CommandLine3 = CHAR_NULL;\r
1867 }\r
1868 }\r
1869\r
1870 if (CommandLine2 != NULL && StrLen(CommandLine2) >= 1) {\r
1871 //\r
1872 // Due to variability in starting the find and replace action we need to have both buffers the same.\r
1873 //\r
1874 StrCpy(CommandLine, CommandLine2);\r
1875\r
1876 //\r
1877 // Remove the %0 to %9 from the command line (if we have some arguments)\r
1878 //\r
1879 if (NewScriptFile->Argv != NULL) {\r
1880 switch (NewScriptFile->Argc) {\r
1881 default:\r
1882 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);\r
1883 ASSERT_EFI_ERROR(Status);\r
1884 case 9:\r
1885 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);\r
1886 ASSERT_EFI_ERROR(Status);\r
1887 case 8:\r
1888 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);\r
1889 ASSERT_EFI_ERROR(Status);\r
1890 case 7:\r
1891 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);\r
1892 ASSERT_EFI_ERROR(Status);\r
1893 case 6:\r
1894 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);\r
1895 ASSERT_EFI_ERROR(Status);\r
1896 case 5:\r
1897 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);\r
1898 ASSERT_EFI_ERROR(Status);\r
1899 case 4:\r
1900 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);\r
1901 ASSERT_EFI_ERROR(Status);\r
1902 case 3:\r
1903 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);\r
1904 ASSERT_EFI_ERROR(Status);\r
1905 case 2:\r
1906 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);\r
1907 ASSERT_EFI_ERROR(Status);\r
1908 case 1:\r
1909 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);\r
1910 ASSERT_EFI_ERROR(Status);\r
1911 break;\r
1912 case 0:\r
1913 break;\r
1914 }\r
1915 }\r
1916 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE);\r
1917 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE);\r
1918 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE);\r
1919 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE);\r
1920 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE);\r
1921 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE);\r
1922 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE);\r
1923 Status = ShellCopySearchAndReplace(CommandLine, CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
1924 Status = ShellCopySearchAndReplace(CommandLine2, CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
1925\r
1926 StrCpy(CommandLine2, CommandLine);\r
1927\r
1928 LastCommand = NewScriptFile->CurrentCommand;\r
1929\r
1930 for (CommandLine3 = CommandLine2 ; CommandLine3[0] == L' ' ; CommandLine3++);\r
1931\r
3c865f20 1932 if (CommandLine3 != NULL && CommandLine3[0] == L':' ) {\r
a405b86d 1933 //\r
1934 // This line is a goto target / label\r
1935 //\r
1936 } else {\r
1937 if (CommandLine3 != NULL && StrLen(CommandLine3) > 0) {\r
848997b5 1938 if (CommandLine3[0] == L'@') {\r
1939 //\r
1940 // We need to save the current echo state\r
1941 // and disable echo for just this command.\r
1942 //\r
1943 PreCommandEchoState = ShellCommandGetEchoState();\r
1944 ShellCommandSetEchoState(FALSE);\r
1945 Status = RunCommand(CommandLine3+1);\r
1946\r
1947 //\r
284e034f 1948 // If command was "@echo -off" or "@echo -on" then don't restore echo state\r
848997b5 1949 //\r
284e034f
CP
1950 if (StrCmp (L"@echo -off", CommandLine3) != 0 &&\r
1951 StrCmp (L"@echo -on", CommandLine3) != 0) {\r
1952 //\r
1953 // Now restore the pre-'@' echo state.\r
1954 //\r
1955 ShellCommandSetEchoState(PreCommandEchoState);\r
1956 }\r
848997b5 1957 } else {\r
0d11446d 1958 if (ShellCommandGetEchoState()) {\r
1959 CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
1960 if (CurDir != NULL && StrLen(CurDir) > 1) {\r
1961 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CURDIR), ShellInfoObject.HiiHandle, CurDir);\r
1962 } else {\r
1963 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_SHELL), ShellInfoObject.HiiHandle);\r
1964 }\r
1965 ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);\r
1966 }\r
848997b5 1967 Status = RunCommand(CommandLine3);\r
1968 }\r
a405b86d 1969 }\r
1970\r
1971 if (ShellCommandGetScriptExit()) {\r
5b5cd144
CP
1972 //\r
1973 // ShellCommandGetExitCode() always returns a UINT64\r
1974 //\r
ed34da40 1975 UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode());\r
5b5cd144
CP
1976 DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
1977 InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
b6b22b13 1978\r
1979 ShellCommandRegisterExit(FALSE, 0);\r
a405b86d 1980 Status = EFI_SUCCESS;\r
1981 break;\r
1982 }\r
c6a7fef8
ED
1983 if (ShellGetExecutionBreakFlag()) {\r
1984 break;\r
1985 }\r
a405b86d 1986 if (EFI_ERROR(Status)) {\r
1987 break;\r
1988 }\r
1989 if (ShellCommandGetExit()) {\r
1990 break;\r
1991 }\r
1992 }\r
1993 //\r
1994 // If that commend did not update the CurrentCommand then we need to advance it...\r
1995 //\r
1996 if (LastCommand == NewScriptFile->CurrentCommand) {\r
1997 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
1998 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
1999 NewScriptFile->CurrentCommand->Reset = TRUE;\r
2000 }\r
2001 }\r
2002 } else {\r
2003 NewScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetNextNode(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link);\r
2004 if (!IsNull(&NewScriptFile->CommandList, &NewScriptFile->CurrentCommand->Link)) {\r
2005 NewScriptFile->CurrentCommand->Reset = TRUE;\r
2006 }\r
2007 }\r
2008 }\r
2009\r
a405b86d 2010\r
2011 FreePool(CommandLine);\r
2012 FreePool(CommandLine2);\r
2013 ShellCommandSetNewScript (NULL);\r
733f138d 2014\r
2015 //\r
2016 // Only if this was the last script reset the state.\r
2017 //\r
2018 if (ShellCommandGetCurrentScriptFile()==NULL) {\r
2019 ShellCommandSetEchoState(PreScriptEchoState);\r
2020 }\r
a405b86d 2021 return (EFI_SUCCESS);\r
2022}\r
2023\r
2024/**\r
2025 Function to process a NSH script file.\r
2026\r
2027 @param[in] ScriptPath Pointer to the script file name (including file system path).\r
2028\r
2029 @retval EFI_SUCCESS the script completed sucessfully\r
2030**/\r
2031EFI_STATUS\r
2032EFIAPI\r
2033RunScriptFile (\r
2034 IN CONST CHAR16 *ScriptPath\r
2035 )\r
2036{\r
2037 EFI_STATUS Status;\r
2038 SHELL_FILE_HANDLE FileHandle;\r
2039\r
2040 if (ShellIsFile(ScriptPath) != EFI_SUCCESS) {\r
2041 return (EFI_INVALID_PARAMETER);\r
2042 }\r
2043\r
2044 Status = ShellOpenFileByName(ScriptPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
2045 if (EFI_ERROR(Status)) {\r
2046 return (Status);\r
2047 }\r
2048\r
2049 Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
2050\r
2051 ShellCloseFile(&FileHandle);\r
2052\r
2053 return (Status);\r
2054}\r