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