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