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