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