2 This is THE shell (application)
4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2013, Hewlett-Packard Development Company, L.P.
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 // Initialize the global structure
21 SHELL_INFO ShellInfoObject
= {
56 {{NULL
, NULL
}, NULL
, NULL
},
57 {{NULL
, NULL
}, NULL
, NULL
},
69 STATIC CONST CHAR16 mScriptExtension
[] = L
".NSH";
70 STATIC CONST CHAR16 mExecutableExtensions
[] = L
".NSH;.EFI";
71 STATIC CONST CHAR16 mStartupScript
[] = L
"startup.nsh";
74 Function to start monitoring for CTRL-S using SimpleTextInputEx. This
75 feature's enabled state was not known when the shell initially launched.
77 @retval EFI_SUCCESS The feature is enabled.
78 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
82 InternalEfiShellStartCtrlSMonitor(
86 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
90 Status
= gBS
->OpenProtocol(
92 &gEfiSimpleTextInputExProtocolGuid
,
96 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
97 if (EFI_ERROR(Status
)) {
102 STRING_TOKEN (STR_SHELL_NO_IN_EX
),
103 ShellInfoObject
.HiiHandle
);
104 return (EFI_SUCCESS
);
107 KeyData
.KeyState
.KeyToggleState
= 0;
108 KeyData
.Key
.ScanCode
= 0;
109 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
110 KeyData
.Key
.UnicodeChar
= L
's';
112 Status
= SimpleEx
->RegisterKeyNotify(
115 NotificationFunction
,
116 &ShellInfoObject
.CtrlSNotifyHandle1
);
118 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
119 if (!EFI_ERROR(Status
)) {
120 Status
= SimpleEx
->RegisterKeyNotify(
123 NotificationFunction
,
124 &ShellInfoObject
.CtrlSNotifyHandle2
);
126 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
127 KeyData
.Key
.UnicodeChar
= 19;
129 if (!EFI_ERROR(Status
)) {
130 Status
= SimpleEx
->RegisterKeyNotify(
133 NotificationFunction
,
134 &ShellInfoObject
.CtrlSNotifyHandle3
);
136 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
137 if (!EFI_ERROR(Status
)) {
138 Status
= SimpleEx
->RegisterKeyNotify(
141 NotificationFunction
,
142 &ShellInfoObject
.CtrlSNotifyHandle4
);
150 The entry point for the application.
152 @param[in] ImageHandle The firmware allocated handle for the EFI image.
153 @param[in] SystemTable A pointer to the EFI System Table.
155 @retval EFI_SUCCESS The entry point is executed successfully.
156 @retval other Some error occurs when executing this entry point.
162 IN EFI_HANDLE ImageHandle
,
163 IN EFI_SYSTEM_TABLE
*SystemTable
169 EFI_HANDLE ConInHandle
;
170 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*OldConIn
;
172 if (PcdGet8(PcdShellSupportLevel
) > 3) {
173 return (EFI_UNSUPPORTED
);
179 Status
= gST
->ConOut
->ClearScreen(gST
->ConOut
);
180 if (EFI_ERROR(Status
)) {
185 // Populate the global structure from PCDs
187 ShellInfoObject
.ImageDevPath
= NULL
;
188 ShellInfoObject
.FileDevPath
= NULL
;
189 ShellInfoObject
.PageBreakEnabled
= PcdGetBool(PcdShellPageBreakDefault
);
190 ShellInfoObject
.ViewingSettings
.InsertMode
= PcdGetBool(PcdShellInsertModeDefault
);
191 ShellInfoObject
.LogScreenCount
= PcdGet8 (PcdShellScreenLogCount
);
194 // verify we dont allow for spec violation
196 ASSERT(ShellInfoObject
.LogScreenCount
>= 3);
199 // Initialize the LIST ENTRY objects...
201 InitializeListHead(&ShellInfoObject
.BufferToFreeList
.Link
);
202 InitializeListHead(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
);
203 InitializeListHead(&ShellInfoObject
.SplitList
.Link
);
206 // Check PCDs for optional features that are not implemented yet.
208 if ( PcdGetBool(PcdShellSupportOldProtocols
)
209 || !FeaturePcdGet(PcdShellRequireHiiPlatform
)
210 || FeaturePcdGet(PcdShellSupportFrameworkHii
)
212 return (EFI_UNSUPPORTED
);
216 // turn off the watchdog timer
218 gBS
->SetWatchdogTimer (0, 0, 0, NULL
);
221 // install our console logger. This will keep a log of the output for back-browsing
223 Status
= ConsoleLoggerInstall(ShellInfoObject
.LogScreenCount
, &ShellInfoObject
.ConsoleInfo
);
224 if (!EFI_ERROR(Status
)) {
226 // Enable the cursor to be visible
228 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
231 // If supporting EFI 1.1 we need to install HII protocol
232 // only do this if PcdShellRequireHiiPlatform == FALSE
234 // remove EFI_UNSUPPORTED check above when complete.
235 ///@todo add support for Framework HII
238 // install our (solitary) HII package
240 ShellInfoObject
.HiiHandle
= HiiAddPackages (&gEfiCallerIdGuid
, gImageHandle
, ShellStrings
, NULL
);
241 if (ShellInfoObject
.HiiHandle
== NULL
) {
242 if (PcdGetBool(PcdShellSupportFrameworkHii
)) {
243 ///@todo Add our package into Framework HII
245 if (ShellInfoObject
.HiiHandle
== NULL
) {
246 return (EFI_NOT_STARTED
);
251 // create and install the EfiShellParametersProtocol
253 Status
= CreatePopulateInstallShellParametersProtocol(&ShellInfoObject
.NewShellParametersProtocol
, &ShellInfoObject
.RootShellInstance
);
254 ASSERT_EFI_ERROR(Status
);
255 ASSERT(ShellInfoObject
.NewShellParametersProtocol
!= NULL
);
258 // create and install the EfiShellProtocol
260 Status
= CreatePopulateInstallShellProtocol(&ShellInfoObject
.NewEfiShellProtocol
);
261 ASSERT_EFI_ERROR(Status
);
262 ASSERT(ShellInfoObject
.NewEfiShellProtocol
!= NULL
);
265 // Now initialize the shell library (it requires Shell Parameters protocol)
267 Status
= ShellInitialize();
268 ASSERT_EFI_ERROR(Status
);
270 Status
= CommandInit();
271 ASSERT_EFI_ERROR(Status
);
274 // Check the command line
276 Status
= ProcessCommandLine();
279 // If shell support level is >= 1 create the mappings and paths
281 if (PcdGet8(PcdShellSupportLevel
) >= 1) {
282 Status
= ShellCommandCreateInitialMappingsAndPaths();
286 // save the device path for the loaded image and the device path for the filepath (under loaded image)
287 // These are where to look for the startup.nsh file
289 Status
= GetDevicePathsForImageAndFile(&ShellInfoObject
.ImageDevPath
, &ShellInfoObject
.FileDevPath
);
290 ASSERT_EFI_ERROR(Status
);
293 // Display the version
295 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoVersion
) {
298 gST
->ConOut
->Mode
->CursorRow
,
300 STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL
),
301 ShellInfoObject
.HiiHandle
,
302 SupportLevel
[PcdGet8(PcdShellSupportLevel
)],
303 gEfiShellProtocol
->MajorVersion
,
304 gEfiShellProtocol
->MinorVersion
311 STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER
),
312 ShellInfoObject
.HiiHandle
,
313 (CHAR16
*) PcdGetPtr (PcdShellSupplier
)
320 STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI
),
321 ShellInfoObject
.HiiHandle
,
322 (gST
->Hdr
.Revision
&0xffff0000)>>16,
323 (gST
->Hdr
.Revision
&0x0000ffff),
325 gST
->FirmwareRevision
330 // Display the mapping
332 if (PcdGet8(PcdShellSupportLevel
) >= 2 && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoMap
) {
333 Status
= RunCommand(L
"map");
334 ASSERT_EFI_ERROR(Status
);
338 // init all the built in alias'
340 Status
= SetBuiltInAlias();
341 ASSERT_EFI_ERROR(Status
);
344 // Initialize environment variables
346 if (ShellCommandGetProfileList() != NULL
) {
347 Status
= InternalEfiShellSetEnv(L
"profiles", ShellCommandGetProfileList(), TRUE
);
348 ASSERT_EFI_ERROR(Status
);
352 TempString
= AllocateZeroPool(Size
);
354 UnicodeSPrint(TempString
, Size
, L
"%d", PcdGet8(PcdShellSupportLevel
));
355 Status
= InternalEfiShellSetEnv(L
"uefishellsupport", TempString
, TRUE
);
356 ASSERT_EFI_ERROR(Status
);
358 UnicodeSPrint(TempString
, Size
, L
"%d.%d", ShellInfoObject
.NewEfiShellProtocol
->MajorVersion
, ShellInfoObject
.NewEfiShellProtocol
->MinorVersion
);
359 Status
= InternalEfiShellSetEnv(L
"uefishellversion", TempString
, TRUE
);
360 ASSERT_EFI_ERROR(Status
);
362 UnicodeSPrint(TempString
, Size
, L
"%d.%d", (gST
->Hdr
.Revision
& 0xFFFF0000) >> 16, gST
->Hdr
.Revision
& 0x0000FFFF);
363 Status
= InternalEfiShellSetEnv(L
"uefiversion", TempString
, TRUE
);
364 ASSERT_EFI_ERROR(Status
);
366 FreePool(TempString
);
368 if (!EFI_ERROR(Status
)) {
369 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
) {
371 // Set up the event for CTRL-C monitoring...
373 Status
= InernalEfiShellStartMonitor();
376 if (!EFI_ERROR(Status
) && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
378 // Set up the event for CTRL-S monitoring...
380 Status
= InternalEfiShellStartCtrlSMonitor();
383 if (!EFI_ERROR(Status
) && ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
385 // close off the gST->ConIn
387 OldConIn
= gST
->ConIn
;
388 ConInHandle
= gST
->ConsoleInHandle
;
389 gST
->ConIn
= CreateSimpleTextInOnFile((SHELL_FILE_HANDLE
)&FileInterfaceNulFile
, &gST
->ConsoleInHandle
);
395 if (!EFI_ERROR(Status
) && PcdGet8(PcdShellSupportLevel
) >= 1) {
397 // process the startup script or launch the called app.
399 Status
= DoStartupScript(ShellInfoObject
.ImageDevPath
, ShellInfoObject
.FileDevPath
);
402 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Exit
&& !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel
) >= 3 || PcdGetBool(PcdShellForceConsole
)) && !EFI_ERROR(Status
) && !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
404 // begin the UI waiting loop
408 // clean out all the memory allocated for CONST <something> * return values
409 // between each shell prompt presentation
411 if (!IsListEmpty(&ShellInfoObject
.BufferToFreeList
.Link
)){
412 FreeBufferList(&ShellInfoObject
.BufferToFreeList
);
416 // Reset page break back to default.
418 ShellInfoObject
.PageBreakEnabled
= PcdGetBool(PcdShellPageBreakDefault
);
419 ShellInfoObject
.ConsoleInfo
->Enabled
= TRUE
;
420 ShellInfoObject
.ConsoleInfo
->RowCounter
= 0;
423 // Reset the CTRL-C event (yes we ignore the return values)
425 Status
= gBS
->CheckEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
);
430 Status
= DoShellPrompt();
431 } while (!ShellCommandGetExit());
433 if (OldConIn
!= NULL
&& ConInHandle
!= NULL
) {
434 CloseSimpleTextInOnFile (gST
->ConIn
);
435 gST
->ConIn
= OldConIn
;
436 gST
->ConsoleInHandle
= ConInHandle
;
442 // uninstall protocols / free memory / etc...
444 if (ShellInfoObject
.UserBreakTimer
!= NULL
) {
445 gBS
->CloseEvent(ShellInfoObject
.UserBreakTimer
);
446 DEBUG_CODE(ShellInfoObject
.UserBreakTimer
= NULL
;);
448 if (ShellInfoObject
.ImageDevPath
!= NULL
) {
449 FreePool(ShellInfoObject
.ImageDevPath
);
450 DEBUG_CODE(ShellInfoObject
.ImageDevPath
= NULL
;);
452 if (ShellInfoObject
.FileDevPath
!= NULL
) {
453 FreePool(ShellInfoObject
.FileDevPath
);
454 DEBUG_CODE(ShellInfoObject
.FileDevPath
= NULL
;);
456 if (ShellInfoObject
.NewShellParametersProtocol
!= NULL
) {
457 CleanUpShellParametersProtocol(ShellInfoObject
.NewShellParametersProtocol
);
458 DEBUG_CODE(ShellInfoObject
.NewShellParametersProtocol
= NULL
;);
460 if (ShellInfoObject
.NewEfiShellProtocol
!= NULL
){
461 if (ShellInfoObject
.NewEfiShellProtocol
->IsRootShell()){
462 InternalEfiShellSetEnv(L
"cwd", NULL
, TRUE
);
464 CleanUpShellProtocol(ShellInfoObject
.NewEfiShellProtocol
);
465 DEBUG_CODE(ShellInfoObject
.NewEfiShellProtocol
= NULL
;);
468 if (!IsListEmpty(&ShellInfoObject
.BufferToFreeList
.Link
)){
469 FreeBufferList(&ShellInfoObject
.BufferToFreeList
);
472 if (!IsListEmpty(&ShellInfoObject
.SplitList
.Link
)){
473 ASSERT(FALSE
); ///@todo finish this de-allocation.
476 if (ShellInfoObject
.ShellInitSettings
.FileName
!= NULL
) {
477 FreePool(ShellInfoObject
.ShellInitSettings
.FileName
);
478 DEBUG_CODE(ShellInfoObject
.ShellInitSettings
.FileName
= NULL
;);
481 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
482 FreePool(ShellInfoObject
.ShellInitSettings
.FileOptions
);
483 DEBUG_CODE(ShellInfoObject
.ShellInitSettings
.FileOptions
= NULL
;);
486 if (ShellInfoObject
.HiiHandle
!= NULL
) {
487 HiiRemovePackages(ShellInfoObject
.HiiHandle
);
488 DEBUG_CODE(ShellInfoObject
.HiiHandle
= NULL
;);
491 if (!IsListEmpty(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
)){
492 FreeBufferList(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
495 ASSERT(ShellInfoObject
.ConsoleInfo
!= NULL
);
496 if (ShellInfoObject
.ConsoleInfo
!= NULL
) {
497 ConsoleLoggerUninstall(ShellInfoObject
.ConsoleInfo
);
498 FreePool(ShellInfoObject
.ConsoleInfo
);
499 DEBUG_CODE(ShellInfoObject
.ConsoleInfo
= NULL
;);
502 if (ShellCommandGetExit()) {
503 return ((EFI_STATUS
)ShellCommandGetExitCode());
509 Sets all the alias' that were registered with the ShellCommandLib library.
511 @retval EFI_SUCCESS all init commands were run sucessfully.
519 CONST ALIAS_LIST
*List
;
523 // Get all the commands we want to run
525 List
= ShellCommandGetInitAliasList();
528 // for each command in the List
530 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&List
->Link
)
531 ; !IsNull (&List
->Link
, &Node
->Link
)
532 ; Node
= (ALIAS_LIST
*)GetNextNode(&List
->Link
, &Node
->Link
)
535 // install the alias'
537 Status
= InternalSetAlias(Node
->CommandString
, Node
->Alias
, TRUE
);
538 ASSERT_EFI_ERROR(Status
);
540 return (EFI_SUCCESS
);
544 Internal function to determine if 2 command names are really the same.
546 @param[in] Command1 The pointer to the first command name.
547 @param[in] Command2 The pointer to the second command name.
549 @retval TRUE The 2 command names are the same.
550 @retval FALSE The 2 command names are not the same.
555 IN CONST CHAR16
*Command1
,
556 IN CONST CHAR16
*Command2
559 if (StringNoCaseCompare(&Command1
, &Command2
) == 0) {
566 Internal function to determine if a command is a script only command.
568 @param[in] CommandName The pointer to the command name.
570 @retval TRUE The command is a script only command.
571 @retval FALSE The command is not a script only command.
576 IN CONST CHAR16
*CommandName
579 if (IsCommand(CommandName
, L
"for")
580 ||IsCommand(CommandName
, L
"endfor")
581 ||IsCommand(CommandName
, L
"if")
582 ||IsCommand(CommandName
, L
"else")
583 ||IsCommand(CommandName
, L
"endif")
584 ||IsCommand(CommandName
, L
"goto")) {
591 This function will populate the 2 device path protocol parameters based on the
592 global gImageHandle. The DevPath will point to the device path for the handle that has
593 loaded image protocol installed on it. The FilePath will point to the device path
594 for the file that was loaded.
596 @param[in, out] DevPath On a sucessful return the device path to the loaded image.
597 @param[in, out] FilePath On a sucessful return the device path to the file.
599 @retval EFI_SUCCESS The 2 device paths were sucessfully returned.
600 @retval other A error from gBS->HandleProtocol.
606 GetDevicePathsForImageAndFile (
607 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevPath
,
608 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
612 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
613 EFI_DEVICE_PATH_PROTOCOL
*ImageDevicePath
;
615 ASSERT(DevPath
!= NULL
);
616 ASSERT(FilePath
!= NULL
);
618 Status
= gBS
->OpenProtocol (
620 &gEfiLoadedImageProtocolGuid
,
621 (VOID
**)&LoadedImage
,
624 EFI_OPEN_PROTOCOL_GET_PROTOCOL
626 if (!EFI_ERROR (Status
)) {
627 Status
= gBS
->OpenProtocol (
628 LoadedImage
->DeviceHandle
,
629 &gEfiDevicePathProtocolGuid
,
630 (VOID
**)&ImageDevicePath
,
633 EFI_OPEN_PROTOCOL_GET_PROTOCOL
635 if (!EFI_ERROR (Status
)) {
636 *DevPath
= DuplicateDevicePath (ImageDevicePath
);
637 *FilePath
= DuplicateDevicePath (LoadedImage
->FilePath
);
639 LoadedImage
->DeviceHandle
,
640 &gEfiDevicePathProtocolGuid
,
646 &gEfiLoadedImageProtocolGuid
,
653 STATIC CONST SHELL_PARAM_ITEM mShellParamList
[] = {
654 {L
"-nostartup", TypeFlag
},
655 {L
"-startup", TypeFlag
},
656 {L
"-noconsoleout", TypeFlag
},
657 {L
"-noconsolein", TypeFlag
},
658 {L
"-nointerrupt", TypeFlag
},
659 {L
"-nomap", TypeFlag
},
660 {L
"-noversion", TypeFlag
},
661 {L
"-startup", TypeFlag
},
662 {L
"-delay", TypeValue
},
663 {L
"-_exit", TypeFlag
},
668 Process all Uefi Shell 2.0 command line options.
670 see Uefi Shell 2.0 section 3.2 for full details.
672 the command line must resemble the following:
674 shell.efi [ShellOpt-options] [options] [file-name [file-name-options]]
676 ShellOpt-options Options which control the initialization behavior of the shell.
677 These options are read from the EFI global variable "ShellOpt"
678 and are processed before options or file-name.
680 options Options which control the initialization behavior of the shell.
682 file-name The name of a UEFI shell application or script to be executed
683 after initialization is complete. By default, if file-name is
684 specified, then -nostartup is implied. Scripts are not supported
687 file-name-options The command-line options that are passed to file-name when it
690 This will initialize the ShellInfoObject.ShellInitSettings global variable.
692 @retval EFI_SUCCESS The variable is initialized.
703 CONST CHAR16
*TempConst
;
706 CHAR16
*ProblemParam
;
712 Status
= ShellCommandLineParse (mShellParamList
, &Package
, NULL
, FALSE
);
716 TempConst
= ShellCommandLineGetRawValue(Package
, Count
++);
717 if (TempConst
!= NULL
&& StrLen(TempConst
)) {
718 ShellInfoObject
.ShellInitSettings
.FileName
= AllocateZeroPool(StrSize(TempConst
));
719 if (ShellInfoObject
.ShellInitSettings
.FileName
== NULL
) {
720 return (EFI_OUT_OF_RESOURCES
);
722 StrCpy(ShellInfoObject
.ShellInitSettings
.FileName
, TempConst
);
723 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
= 1;
724 for (LoopVar
= 0 ; LoopVar
< gEfiShellParametersProtocol
->Argc
; LoopVar
++) {
725 if (StrCmp(gEfiShellParametersProtocol
->Argv
[LoopVar
], ShellInfoObject
.ShellInitSettings
.FileName
)==0) {
728 // We found the file... add the rest of the params...
730 for ( ; LoopVar
< gEfiShellParametersProtocol
->Argc
; LoopVar
++) {
731 ASSERT((ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
&& Size
== 0) || (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
));
732 StrnCatGrow(&ShellInfoObject
.ShellInitSettings
.FileOptions
,
736 if (ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
) {
737 SHELL_FREE_NON_NULL(ShellInfoObject
.ShellInitSettings
.FileName
);
738 return (EFI_OUT_OF_RESOURCES
);
740 StrnCatGrow(&ShellInfoObject
.ShellInitSettings
.FileOptions
,
742 gEfiShellParametersProtocol
->Argv
[LoopVar
],
744 if (ShellInfoObject
.ShellInitSettings
.FileOptions
== NULL
) {
745 SHELL_FREE_NON_NULL(ShellInfoObject
.ShellInitSettings
.FileName
);
746 return (EFI_OUT_OF_RESOURCES
);
752 ShellCommandLineFreeVarList(Package
);
754 Status
= ShellCommandLineParse (mShellParamList
, &Package
, &ProblemParam
, FALSE
);
755 if (EFI_ERROR(Status
)) {
756 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), ShellInfoObject
.HiiHandle
, ProblemParam
);
757 FreePool(ProblemParam
);
758 ShellCommandLineFreeVarList(Package
);
759 return (EFI_INVALID_PARAMETER
);
763 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
= ShellCommandLineGetFlag(Package
, L
"-startup");
764 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
= ShellCommandLineGetFlag(Package
, L
"-nostartup");
765 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
= ShellCommandLineGetFlag(Package
, L
"-noconsoleout");
766 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
= ShellCommandLineGetFlag(Package
, L
"-noconsolein");
767 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
= ShellCommandLineGetFlag(Package
, L
"-nointerrupt");
768 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoMap
= ShellCommandLineGetFlag(Package
, L
"-nomap");
769 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoVersion
= ShellCommandLineGetFlag(Package
, L
"-noversion");
770 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Delay
= ShellCommandLineGetFlag(Package
, L
"-delay");
771 ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Exit
= ShellCommandLineGetFlag(Package
, L
"-_exit");
773 ShellInfoObject
.ShellInitSettings
.Delay
= 5;
775 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoInterrupt
) {
776 ShellInfoObject
.ShellInitSettings
.Delay
= 0;
777 } else if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Delay
) {
778 TempConst
= ShellCommandLineGetValue(Package
, L
"-delay");
779 if (TempConst
!= NULL
&& *TempConst
== L
':') {
782 if (TempConst
!= NULL
&& !EFI_ERROR(ShellConvertStringToUint64(TempConst
, &Intermediate
, FALSE
, FALSE
))) {
783 ShellInfoObject
.ShellInitSettings
.Delay
= (UINTN
)Intermediate
;
786 ShellCommandLineFreeVarList(Package
);
792 Handles all interaction with the default startup script.
794 this will check that the correct command line parameters were passed, handle the delay, and then start running the script.
796 @param ImagePath the path to the image for shell. first place to look for the startup script
797 @param FilePath the path to the file for shell. second place to look for the startup script.
799 @retval EFI_SUCCESS the variable is initialized.
804 EFI_DEVICE_PATH_PROTOCOL
*ImagePath
,
805 EFI_DEVICE_PATH_PROTOCOL
*FilePath
811 SHELL_FILE_HANDLE FileHandle
;
812 EFI_DEVICE_PATH_PROTOCOL
*NewPath
;
813 EFI_DEVICE_PATH_PROTOCOL
*NamePath
;
814 CHAR16
*FileStringPath
;
817 CONST CHAR16
*MapName
;
819 Key
.UnicodeChar
= CHAR_NULL
;
823 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
&& ShellInfoObject
.ShellInitSettings
.FileName
!= NULL
) {
825 // launch something else instead
827 NewSize
= StrSize(ShellInfoObject
.ShellInitSettings
.FileName
);
828 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
829 NewSize
+= StrSize(ShellInfoObject
.ShellInitSettings
.FileOptions
) + sizeof(CHAR16
);
831 FileStringPath
= AllocateZeroPool(NewSize
);
832 if (FileStringPath
== NULL
) {
833 return (EFI_OUT_OF_RESOURCES
);
835 StrCpy(FileStringPath
, ShellInfoObject
.ShellInitSettings
.FileName
);
836 if (ShellInfoObject
.ShellInitSettings
.FileOptions
!= NULL
) {
837 StrCat(FileStringPath
, L
" ");
838 StrCat(FileStringPath
, ShellInfoObject
.ShellInitSettings
.FileOptions
);
840 Status
= RunCommand(FileStringPath
);
841 FreePool(FileStringPath
);
847 // for shell level 0 we do no scripts
848 // Without the Startup bit overriding we allow for nostartup to prevent scripts
850 if ( (PcdGet8(PcdShellSupportLevel
) < 1)
851 || (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoStartup
&& !ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.Startup
)
853 return (EFI_SUCCESS
);
856 gST
->ConOut
->EnableCursor(gST
->ConOut
, FALSE
);
858 // print out our warning and see if they press a key
860 for ( Status
= EFI_UNSUPPORTED
, Delay
= ShellInfoObject
.ShellInitSettings
.Delay
861 ; Delay
!= 0 && EFI_ERROR(Status
)
864 ShellPrintHiiEx(0, gST
->ConOut
->Mode
->CursorRow
, NULL
, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION
), ShellInfoObject
.HiiHandle
, Delay
);
865 gBS
->Stall (1000000);
866 if (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleIn
) {
867 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
870 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CRLF
), ShellInfoObject
.HiiHandle
);
871 gST
->ConOut
->EnableCursor(gST
->ConOut
, TRUE
);
876 if (Status
== EFI_SUCCESS
&& Key
.UnicodeChar
== 0 && Key
.ScanCode
== SCAN_ESC
) {
877 return (EFI_SUCCESS
);
881 // Try the first location (must be file system)
883 MapName
= ShellInfoObject
.NewEfiShellProtocol
->GetMapFromDevicePath(&ImagePath
);
884 if (MapName
!= NULL
) {
885 FileStringPath
= NULL
;
887 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, MapName
, 0);
888 if (FileStringPath
== NULL
) {
889 Status
= EFI_OUT_OF_RESOURCES
;
891 TempSpot
= StrStr(FileStringPath
, L
";");
892 if (TempSpot
!= NULL
) {
893 *TempSpot
= CHAR_NULL
;
895 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, ((FILEPATH_DEVICE_PATH
*)FilePath
)->PathName
, 0);
896 PathRemoveLastItem(FileStringPath
);
897 FileStringPath
= StrnCatGrow(&FileStringPath
, &NewSize
, mStartupScript
, 0);
898 Status
= ShellInfoObject
.NewEfiShellProtocol
->OpenFileByName(FileStringPath
, &FileHandle
, EFI_FILE_MODE_READ
);
899 FreePool(FileStringPath
);
902 if (EFI_ERROR(Status
)) {
903 NamePath
= FileDevicePath (NULL
, mStartupScript
);
904 NewPath
= AppendDevicePathNode (ImagePath
, NamePath
);
910 Status
= InternalOpenFileDevicePath(NewPath
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
914 // If we got a file, run it
916 if (!EFI_ERROR(Status
) && FileHandle
!= NULL
) {
917 Status
= RunScriptFileHandle (FileHandle
, mStartupScript
);
918 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(FileHandle
);
920 FileStringPath
= ShellFindFilePath(mStartupScript
);
921 if (FileStringPath
== NULL
) {
923 // we return success since we dont need to have a startup script
925 Status
= EFI_SUCCESS
;
926 ASSERT(FileHandle
== NULL
);
928 Status
= RunScriptFile(FileStringPath
);
929 FreePool(FileStringPath
);
938 Function to perform the shell prompt looping. It will do a single prompt,
939 dispatch the result, and then return. It is expected that the caller will
940 call this function in a loop many times.
943 @retval RETURN_ABORTED
954 CONST CHAR16
*CurDir
;
961 // Get screen setting to decide size of the command line buffer
963 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &Column
, &Row
);
964 BufferSize
= Column
* Row
* sizeof (CHAR16
);
965 CmdLine
= AllocateZeroPool (BufferSize
);
966 if (CmdLine
== NULL
) {
967 return EFI_OUT_OF_RESOURCES
;
970 CurDir
= ShellInfoObject
.NewEfiShellProtocol
->GetEnv(L
"cwd");
975 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, 0, gST
->ConOut
->Mode
->CursorRow
);
977 if (CurDir
!= NULL
&& StrLen(CurDir
) > 1) {
978 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CURDIR
), ShellInfoObject
.HiiHandle
, CurDir
);
980 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_SHELL
), ShellInfoObject
.HiiHandle
);
984 // Read a line from the console
986 Status
= ShellInfoObject
.NewEfiShellProtocol
->ReadFile(ShellInfoObject
.NewShellParametersProtocol
->StdIn
, &BufferSize
, CmdLine
);
989 // Null terminate the string and parse it
991 if (!EFI_ERROR (Status
)) {
992 CmdLine
[BufferSize
/ sizeof (CHAR16
)] = CHAR_NULL
;
993 Status
= RunCommand(CmdLine
);
997 // Done with this command
1004 Add a buffer to the Buffer To Free List for safely returning buffers to other
1005 places without risking letting them modify internal shell information.
1007 @param Buffer Something to pass to FreePool when the shell is exiting.
1011 AddBufferToFreeList(
1015 BUFFER_LIST
*BufferListEntry
;
1017 if (Buffer
== NULL
) {
1021 BufferListEntry
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1022 ASSERT(BufferListEntry
!= NULL
);
1023 BufferListEntry
->Buffer
= Buffer
;
1024 InsertTailList(&ShellInfoObject
.BufferToFreeList
.Link
, &BufferListEntry
->Link
);
1029 Add a buffer to the Line History List
1031 @param Buffer The line buffer to add.
1035 AddLineToCommandHistory(
1036 IN CONST CHAR16
*Buffer
1041 Node
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1042 ASSERT(Node
!= NULL
);
1043 Node
->Buffer
= AllocateZeroPool(StrSize(Buffer
));
1044 ASSERT(Node
->Buffer
!= NULL
);
1045 StrCpy(Node
->Buffer
, Buffer
);
1047 InsertTailList(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
);
1051 Checks if a string is an alias for another command. If yes, then it replaces the alias name
1052 with the correct command name.
1054 @param[in, out] CommandString Upon entry the potential alias. Upon return the
1055 command name if it was an alias. If it was not
1056 an alias it will be unchanged. This function may
1057 change the buffer to fit the command name.
1059 @retval EFI_SUCCESS The name was changed.
1060 @retval EFI_SUCCESS The name was not an alias.
1061 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1066 IN OUT CHAR16
**CommandString
1069 CONST CHAR16
*NewString
;
1071 NewString
= ShellInfoObject
.NewEfiShellProtocol
->GetAlias(*CommandString
, NULL
);
1072 if (NewString
== NULL
) {
1073 return (EFI_SUCCESS
);
1075 FreePool(*CommandString
);
1076 *CommandString
= AllocateZeroPool(StrSize(NewString
));
1077 if (*CommandString
== NULL
) {
1078 return (EFI_OUT_OF_RESOURCES
);
1080 StrCpy(*CommandString
, NewString
);
1081 return (EFI_SUCCESS
);
1085 Function allocates a new command line and replaces all instances of environment
1086 variable names that are correctly preset to their values.
1088 If the return value is not NULL the memory must be caller freed.
1090 @param[in] OriginalCommandLine The original command line
1092 @retval NULL An error ocurred.
1093 @return The new command line with no environment variables present.
1097 ShellConvertVariables (
1098 IN CONST CHAR16
*OriginalCommandLine
1101 CONST CHAR16
*MasterEnvList
;
1103 CHAR16
*NewCommandLine1
;
1104 CHAR16
*NewCommandLine2
;
1109 SCRIPT_FILE
*CurrentScriptFile
;
1110 ALIAS_LIST
*AliasListNode
;
1112 ASSERT(OriginalCommandLine
!= NULL
);
1115 NewSize
= StrSize(OriginalCommandLine
);
1116 CurrentScriptFile
= ShellCommandGetCurrentScriptFile();
1119 ///@todo update this to handle the %0 - %9 for scripting only (borrow from line 1256 area) ? ? ?
1122 // calculate the size required for the post-conversion string...
1124 if (CurrentScriptFile
!= NULL
) {
1125 for (AliasListNode
= (ALIAS_LIST
*)GetFirstNode(&CurrentScriptFile
->SubstList
)
1126 ; !IsNull(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1127 ; AliasListNode
= (ALIAS_LIST
*)GetNextNode(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1129 for (Temp
= StrStr(OriginalCommandLine
, AliasListNode
->Alias
)
1131 ; Temp
= StrStr(Temp
+1, AliasListNode
->Alias
)
1134 // we need a preceeding and if there is space no ^ preceeding (if no space ignore)
1136 if ((((Temp
-OriginalCommandLine
)>2) && *(Temp
-2) != L
'^') || ((Temp
-OriginalCommandLine
)<=2)) {
1137 NewSize
+= StrSize(AliasListNode
->CommandString
);
1143 for (MasterEnvList
= EfiShellGetEnv(NULL
)
1144 ; MasterEnvList
!= NULL
&& *MasterEnvList
!= CHAR_NULL
//&& *(MasterEnvList+1) != CHAR_NULL
1145 ; MasterEnvList
+= StrLen(MasterEnvList
) + 1
1147 if (StrSize(MasterEnvList
) > ItemSize
) {
1148 ItemSize
= StrSize(MasterEnvList
);
1150 for (Temp
= StrStr(OriginalCommandLine
, MasterEnvList
)
1152 ; Temp
= StrStr(Temp
+1, MasterEnvList
)
1155 // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)
1157 if (*(Temp
-1) == L
'%' && *(Temp
+StrLen(MasterEnvList
)) == L
'%' &&
1158 ((((Temp
-OriginalCommandLine
)>2) && *(Temp
-2) != L
'^') || ((Temp
-OriginalCommandLine
)<=2))) {
1159 NewSize
+=StrSize(EfiShellGetEnv(MasterEnvList
));
1165 // now do the replacements...
1167 NewCommandLine1
= AllocateZeroPool(NewSize
);
1168 NewCommandLine2
= AllocateZeroPool(NewSize
);
1169 ItemTemp
= AllocateZeroPool(ItemSize
+(2*sizeof(CHAR16
)));
1170 if (NewCommandLine1
== NULL
|| NewCommandLine2
== NULL
|| ItemTemp
== NULL
) {
1171 SHELL_FREE_NON_NULL(NewCommandLine1
);
1172 SHELL_FREE_NON_NULL(NewCommandLine2
);
1173 SHELL_FREE_NON_NULL(ItemTemp
);
1176 StrCpy(NewCommandLine1
, OriginalCommandLine
);
1177 for (MasterEnvList
= EfiShellGetEnv(NULL
)
1178 ; MasterEnvList
!= NULL
&& *MasterEnvList
!= CHAR_NULL
//&& *(MasterEnvList+1) != CHAR_NULL
1179 ; MasterEnvList
+= StrLen(MasterEnvList
) + 1
1181 StrCpy(ItemTemp
, L
"%");
1182 StrCat(ItemTemp
, MasterEnvList
);
1183 StrCat(ItemTemp
, L
"%");
1184 ShellCopySearchAndReplace(NewCommandLine1
, NewCommandLine2
, NewSize
, ItemTemp
, EfiShellGetEnv(MasterEnvList
), TRUE
, FALSE
);
1185 StrCpy(NewCommandLine1
, NewCommandLine2
);
1187 if (CurrentScriptFile
!= NULL
) {
1188 for (AliasListNode
= (ALIAS_LIST
*)GetFirstNode(&CurrentScriptFile
->SubstList
)
1189 ; !IsNull(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1190 ; AliasListNode
= (ALIAS_LIST
*)GetNextNode(&CurrentScriptFile
->SubstList
, &AliasListNode
->Link
)
1192 ShellCopySearchAndReplace(NewCommandLine1
, NewCommandLine2
, NewSize
, AliasListNode
->Alias
, AliasListNode
->CommandString
, TRUE
, FALSE
);
1193 StrCpy(NewCommandLine1
, NewCommandLine2
);
1197 // Remove non-existant environment variables in scripts only
1199 for (Temp
= NewCommandLine1
; Temp
!= NULL
; ) {
1200 Temp
= StrStr(Temp
, L
"%");
1204 while (*(Temp
- 1) == L
'^') {
1205 Temp
= StrStr(Temp
+ 1, L
"%");
1214 Temp2
= StrStr(Temp
+ 1, L
"%");
1215 if (Temp2
== NULL
) {
1218 while (*(Temp2
- 1) == L
'^') {
1219 Temp2
= StrStr(Temp2
+ 1, L
"%");
1220 if (Temp2
== NULL
) {
1224 if (Temp2
== NULL
) {
1229 CopyMem(Temp
, Temp2
, StrSize(Temp2
));
1235 // Now cleanup any straggler intentionally ignored "%" characters
1237 ShellCopySearchAndReplace(NewCommandLine1
, NewCommandLine2
, NewSize
, L
"^%", L
"%", TRUE
, FALSE
);
1238 StrCpy(NewCommandLine1
, NewCommandLine2
);
1240 FreePool(NewCommandLine2
);
1243 return (NewCommandLine1
);
1247 Internal function to run a command line with pipe usage.
1249 @param[in] CmdLine The pointer to the command line.
1250 @param[in] StdIn The pointer to the Standard input.
1251 @param[in] StdOut The pointer to the Standard output.
1253 @retval EFI_SUCCESS The split command is executed successfully.
1254 @retval other Some error occurs when executing the split command.
1259 IN CONST CHAR16
*CmdLine
,
1260 IN SHELL_FILE_HANDLE
*StdIn
,
1261 IN SHELL_FILE_HANDLE
*StdOut
1265 CHAR16
*NextCommandLine
;
1266 CHAR16
*OurCommandLine
;
1270 SHELL_FILE_HANDLE
*TempFileHandle
;
1273 ASSERT(StdOut
== NULL
);
1275 ASSERT(StrStr(CmdLine
, L
"|") != NULL
);
1277 Status
= EFI_SUCCESS
;
1278 NextCommandLine
= NULL
;
1279 OurCommandLine
= NULL
;
1283 NextCommandLine
= StrnCatGrow(&NextCommandLine
, &Size1
, StrStr(CmdLine
, L
"|")+1, 0);
1284 OurCommandLine
= StrnCatGrow(&OurCommandLine
, &Size2
, CmdLine
, StrStr(CmdLine
, L
"|") - CmdLine
);
1286 if (NextCommandLine
== NULL
|| OurCommandLine
== NULL
) {
1287 SHELL_FREE_NON_NULL(OurCommandLine
);
1288 SHELL_FREE_NON_NULL(NextCommandLine
);
1289 return (EFI_OUT_OF_RESOURCES
);
1290 } else if (StrStr(OurCommandLine
, L
"|") != NULL
|| Size1
== 0 || Size2
== 0) {
1291 SHELL_FREE_NON_NULL(OurCommandLine
);
1292 SHELL_FREE_NON_NULL(NextCommandLine
);
1293 return (EFI_INVALID_PARAMETER
);
1294 } else if (NextCommandLine
[0] != CHAR_NULL
&&
1295 NextCommandLine
[0] == L
'a' &&
1296 NextCommandLine
[1] == L
' '
1298 CopyMem(NextCommandLine
, NextCommandLine
+1, StrSize(NextCommandLine
) - sizeof(NextCommandLine
[0]));
1306 // make a SPLIT_LIST item and add to list
1308 Split
= AllocateZeroPool(sizeof(SPLIT_LIST
));
1309 ASSERT(Split
!= NULL
);
1310 Split
->SplitStdIn
= StdIn
;
1311 Split
->SplitStdOut
= ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode
), NULL
);
1312 ASSERT(Split
->SplitStdOut
!= NULL
);
1313 InsertHeadList(&ShellInfoObject
.SplitList
.Link
, &Split
->Link
);
1315 Status
= RunCommand(OurCommandLine
);
1318 // move the output from the first to the in to the second.
1320 TempFileHandle
= Split
->SplitStdOut
;
1321 if (Split
->SplitStdIn
== StdIn
) {
1322 Split
->SplitStdOut
= NULL
;
1324 Split
->SplitStdOut
= Split
->SplitStdIn
;
1326 Split
->SplitStdIn
= TempFileHandle
;
1327 ShellInfoObject
.NewEfiShellProtocol
->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdIn
), 0);
1329 if (!EFI_ERROR(Status
)) {
1330 Status
= RunCommand(NextCommandLine
);
1334 // remove the top level from the ScriptList
1336 ASSERT((SPLIT_LIST
*)GetFirstNode(&ShellInfoObject
.SplitList
.Link
) == Split
);
1337 RemoveEntryList(&Split
->Link
);
1340 // Note that the original StdIn is now the StdOut...
1342 if (Split
->SplitStdOut
!= NULL
&& Split
->SplitStdOut
!= StdIn
) {
1343 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdOut
));
1345 if (Split
->SplitStdIn
!= NULL
) {
1346 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(ConvertShellHandleToEfiFileProtocol(Split
->SplitStdIn
));
1350 FreePool(NextCommandLine
);
1351 FreePool(OurCommandLine
);
1357 Function will process and run a command line.
1359 This will determine if the command line represents an internal shell
1360 command or dispatch an external application.
1362 @param[in] CmdLine The command line to parse.
1364 @retval EFI_SUCCESS The command was completed.
1365 @retval EFI_ABORTED The command's operation was aborted.
1370 IN CONST CHAR16
*CmdLine
1374 EFI_STATUS StatusCode
;
1375 CHAR16
*CommandName
;
1376 SHELL_STATUS ShellStatus
;
1380 CHAR16 LeString
[19];
1381 CHAR16
*PostAliasCmdLine
;
1382 UINTN PostAliasSize
;
1383 CHAR16
*PostVariableCmdLine
;
1384 CHAR16
*CommandWithPath
;
1385 CONST EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1386 CONST CHAR16
*TempLocation
;
1387 CONST CHAR16
*TempLocation2
;
1388 SHELL_FILE_HANDLE OriginalStdIn
;
1389 SHELL_FILE_HANDLE OriginalStdOut
;
1390 SHELL_FILE_HANDLE OriginalStdErr
;
1391 SYSTEM_TABLE_INFO OriginalSystemTableInfo
;
1392 CHAR16
*TempLocation3
;
1395 CHAR16
*CleanOriginal
;
1398 ASSERT(CmdLine
!= NULL
);
1399 if (StrLen(CmdLine
) == 0) {
1400 return (EFI_SUCCESS
);
1404 PostVariableCmdLine
= NULL
;
1405 PostAliasCmdLine
= NULL
;
1406 CommandWithPath
= NULL
;
1408 Status
= EFI_SUCCESS
;
1409 CleanOriginal
= NULL
;
1412 CleanOriginal
= StrnCatGrow(&CleanOriginal
, NULL
, CmdLine
, 0);
1413 if (CleanOriginal
== NULL
) {
1414 return (EFI_OUT_OF_RESOURCES
);
1418 // Remove any spaces and tabs at the beginning of the string.
1420 while ((CleanOriginal
[0] == L
' ') || (CleanOriginal
[0] == L
'\t')) {
1421 CopyMem(CleanOriginal
, CleanOriginal
+1, StrSize(CleanOriginal
) - sizeof(CleanOriginal
[0]));
1425 // Handle case that passed in command line is just 1 or more " " characters.
1427 if (StrLen (CleanOriginal
) == 0) {
1428 if (CleanOriginal
!= NULL
) {
1429 FreePool(CleanOriginal
);
1430 CleanOriginal
= NULL
;
1432 return (EFI_SUCCESS
);
1436 // Remove any spaces at the end of the string.
1438 while (CleanOriginal
[StrLen(CleanOriginal
)-1] == L
' ') {
1439 CleanOriginal
[StrLen(CleanOriginal
)-1] = CHAR_NULL
;
1443 if (StrStr(CleanOriginal
, L
" ") == NULL
){
1444 StrnCatGrow(&CommandName
, NULL
, CleanOriginal
, 0);
1446 StrnCatGrow(&CommandName
, NULL
, CleanOriginal
, StrStr(CleanOriginal
, L
" ") - CleanOriginal
);
1449 ASSERT(PostAliasCmdLine
== NULL
);
1450 if (!ShellCommandIsCommandOnList(CommandName
)) {
1452 // Convert via alias
1454 Status
= ShellConvertAlias(&CommandName
);
1456 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, &PostAliasSize
, CommandName
, 0);
1457 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, &PostAliasSize
, StrStr(CleanOriginal
, L
" "), 0);
1458 ASSERT_EFI_ERROR(Status
);
1460 PostAliasCmdLine
= StrnCatGrow(&PostAliasCmdLine
, NULL
, CleanOriginal
, 0);
1463 if (CleanOriginal
!= NULL
) {
1464 FreePool(CleanOriginal
);
1465 CleanOriginal
= NULL
;
1468 if (CommandName
!= NULL
) {
1469 FreePool(CommandName
);
1473 PostVariableCmdLine
= ShellConvertVariables(PostAliasCmdLine
);
1476 // we can now free the modified by alias command line
1478 if (PostAliasCmdLine
!= NULL
) {
1479 FreePool(PostAliasCmdLine
);
1480 PostAliasCmdLine
= NULL
;
1483 if (PostVariableCmdLine
== NULL
) {
1484 return (EFI_OUT_OF_RESOURCES
);
1487 while (PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] == L
' ') {
1488 PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] = CHAR_NULL
;
1490 while (PostVariableCmdLine
[0] == L
' ') {
1491 CopyMem(PostVariableCmdLine
, PostVariableCmdLine
+1, StrSize(PostVariableCmdLine
) - sizeof(PostVariableCmdLine
[0]));
1495 // We dont do normal processing with a split command line (output from one command input to another)
1497 TempLocation3
= NULL
;
1498 if (StrStr(PostVariableCmdLine
, L
"|") != NULL
) {
1499 for (TempLocation3
= PostVariableCmdLine
; TempLocation3
!= NULL
&& *TempLocation3
!= CHAR_NULL
; TempLocation3
++) {
1500 if (*TempLocation3
== L
'^' && *(TempLocation3
+1) == L
'|') {
1502 } else if (*TempLocation3
== L
'|') {
1507 if (TempLocation3
!= NULL
&& *TempLocation3
!= CHAR_NULL
) {
1509 // are we in an existing split???
1511 if (!IsListEmpty(&ShellInfoObject
.SplitList
.Link
)) {
1512 Split
= (SPLIT_LIST
*)GetFirstNode(&ShellInfoObject
.SplitList
.Link
);
1515 if (Split
== NULL
) {
1516 Status
= RunSplitCommand(PostVariableCmdLine
, NULL
, NULL
);
1518 Status
= RunSplitCommand(PostVariableCmdLine
, Split
->SplitStdIn
, Split
->SplitStdOut
);
1520 if (EFI_ERROR(Status
)) {
1521 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_INVALID_SPLIT
), ShellInfoObject
.HiiHandle
, PostVariableCmdLine
);
1526 // If this is a mapped drive change handle that...
1528 if (PostVariableCmdLine
[(StrLen(PostVariableCmdLine
)-1)] == L
':' && StrStr(PostVariableCmdLine
, L
" ") == NULL
) {
1529 Status
= ShellInfoObject
.NewEfiShellProtocol
->SetCurDir(NULL
, PostVariableCmdLine
);
1530 if (EFI_ERROR(Status
)) {
1531 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_INVALID_MAPPING
), ShellInfoObject
.HiiHandle
, PostVariableCmdLine
);
1533 FreePool(PostVariableCmdLine
);
1537 ///@todo update this section to divide into 3 ways - run internal command, run split (above), and run an external file...
1538 /// We waste a lot of time doing processing like StdIn,StdOut,Argv,Argc for things that are external files...
1542 Status
= UpdateStdInStdOutStdErr(ShellInfoObject
.NewShellParametersProtocol
, PostVariableCmdLine
, &OriginalStdIn
, &OriginalStdOut
, &OriginalStdErr
, &OriginalSystemTableInfo
);
1543 if (EFI_ERROR(Status
)) {
1544 if (Status
== EFI_NOT_FOUND
) {
1545 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR
), ShellInfoObject
.HiiHandle
);
1547 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_INVALID_REDIR
), ShellInfoObject
.HiiHandle
);
1550 while (PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] == L
' ') {
1551 PostVariableCmdLine
[StrLen(PostVariableCmdLine
)-1] = CHAR_NULL
;
1553 while (PostVariableCmdLine
[0] == L
' ') {
1554 CopyMem(PostVariableCmdLine
, PostVariableCmdLine
+1, StrSize(PostVariableCmdLine
) - sizeof(PostVariableCmdLine
[0]));
1558 // get the argc and argv updated for internal commands
1560 Status
= UpdateArgcArgv(ShellInfoObject
.NewShellParametersProtocol
, PostVariableCmdLine
, &Argv
, &Argc
);
1561 ASSERT_EFI_ERROR(Status
);
1563 for (Count
= 0 ; Count
< ShellInfoObject
.NewShellParametersProtocol
->Argc
; Count
++) {
1564 if (StrStr(ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
], L
"-?") == ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
]
1565 || (ShellInfoObject
.NewShellParametersProtocol
->Argv
[0][0] == L
'?' && ShellInfoObject
.NewShellParametersProtocol
->Argv
[0][1] == CHAR_NULL
)
1568 // We need to redo the arguments since a parameter was -?
1569 // move them all down 1 to the end, then up one then replace the first with help
1571 FreePool(ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
]);
1572 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count
] = NULL
;
1573 for (Count2
= Count
; (Count2
+ 1) < ShellInfoObject
.NewShellParametersProtocol
->Argc
; Count2
++) {
1574 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
+1];
1576 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = NULL
;
1577 for (Count2
= ShellInfoObject
.NewShellParametersProtocol
->Argc
-1 ; Count2
> 0 ; Count2
--) {
1578 ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
] = ShellInfoObject
.NewShellParametersProtocol
->Argv
[Count2
-1];
1580 ShellInfoObject
.NewShellParametersProtocol
->Argv
[0] = NULL
;
1581 ShellInfoObject
.NewShellParametersProtocol
->Argv
[0] = StrnCatGrow(&ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], NULL
, L
"help", 0);
1589 if (ShellCommandIsCommandOnList(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0])) {
1591 // Run the command (which was converted if it was an alias)
1593 if (!EFI_ERROR(Status
)) {
1594 Status
= ShellCommandRunCommandHandler(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], &ShellStatus
, &LastError
);
1595 ASSERT_EFI_ERROR(Status
);
1597 if (sizeof(EFI_STATUS
) == sizeof(UINT64
)) {
1598 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%Lx", ShellStatus
);
1600 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%x", ShellStatus
);
1602 DEBUG_CODE(InternalEfiShellSetEnv(L
"debuglasterror", LeString
, TRUE
););
1604 InternalEfiShellSetEnv(L
"lasterror", LeString
, TRUE
);
1607 // Pass thru the exitcode from the app.
1609 if (ShellCommandGetExit()) {
1610 Status
= ShellStatus
;
1611 } else if (ShellStatus
!= 0 && IsScriptOnlyCommand(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0])) {
1612 Status
= EFI_ABORTED
;
1617 // run an external file (or script)
1619 if (StrStr(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], L
":") != NULL
) {
1620 ASSERT (CommandWithPath
== NULL
);
1621 if (ShellIsFile(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0]) == EFI_SUCCESS
) {
1622 CommandWithPath
= StrnCatGrow(&CommandWithPath
, NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], 0);
1625 if (CommandWithPath
== NULL
) {
1626 CommandWithPath
= ShellFindFilePathEx(ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], mExecutableExtensions
);
1628 if (CommandWithPath
== NULL
|| ShellIsDirectory(CommandWithPath
) == EFI_SUCCESS
) {
1629 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_NOT_FOUND
), ShellInfoObject
.HiiHandle
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0]);
1631 if (sizeof(EFI_STATUS
) == sizeof(UINT64
)) {
1632 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%Lx", EFI_NOT_FOUND
);
1634 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%x", EFI_NOT_FOUND
);
1636 DEBUG_CODE(InternalEfiShellSetEnv(L
"debuglasterror", LeString
, TRUE
););
1637 InternalEfiShellSetEnv(L
"lasterror", LeString
, TRUE
);
1640 // Check if it's a NSH (script) file.
1642 TempLocation
= CommandWithPath
+StrLen(CommandWithPath
)-4;
1643 TempLocation2
= mScriptExtension
;
1644 if ((StrLen(CommandWithPath
) > 4) && (StringNoCaseCompare((VOID
*)(&TempLocation
), (VOID
*)(&TempLocation2
)) == 0)) {
1645 Status
= RunScriptFile (CommandWithPath
);
1647 DevPath
= ShellInfoObject
.NewEfiShellProtocol
->GetDevicePathFromFilePath(CommandWithPath
);
1648 ASSERT(DevPath
!= NULL
);
1649 Status
= InternalShellExecuteDevicePath(
1652 PostVariableCmdLine
,
1658 // Update last error status.
1660 if (sizeof(EFI_STATUS
) == sizeof(UINT64
)) {
1661 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%Lx", StatusCode
);
1663 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%x", StatusCode
);
1665 DEBUG_CODE(InternalEfiShellSetEnv(L
"debuglasterror", LeString
, TRUE
););
1666 InternalEfiShellSetEnv(L
"lasterror", LeString
, TRUE
);
1672 // Print some error info.
1674 if (EFI_ERROR(Status
)) {
1675 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_ERROR
), ShellInfoObject
.HiiHandle
, (VOID
*)(Status
));
1678 CommandName
= StrnCatGrow(&CommandName
, NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[0], 0);
1680 RestoreArgcArgv(ShellInfoObject
.NewShellParametersProtocol
, &Argv
, &Argc
);
1682 RestoreStdInStdOutStdErr(ShellInfoObject
.NewShellParametersProtocol
, &OriginalStdIn
, &OriginalStdOut
, &OriginalStdErr
, &OriginalSystemTableInfo
);
1684 if (CommandName
!= NULL
) {
1685 if (ShellCommandGetCurrentScriptFile() != NULL
&& !IsScriptOnlyCommand(CommandName
)) {
1687 // if this is NOT a scipt only command return success so the script won't quit.
1688 // prevent killing the script - this is the only place where we know the actual command name (after alias and variable replacement...)
1690 Status
= EFI_SUCCESS
;
1695 SHELL_FREE_NON_NULL(CommandName
);
1696 SHELL_FREE_NON_NULL(CommandWithPath
);
1697 SHELL_FREE_NON_NULL(PostVariableCmdLine
);
1702 STATIC CONST UINT16 InvalidChars
[] = {L
'*', L
'?', L
'<', L
'>', L
'\\', L
'/', L
'\"', 0x0001, 0x0002};
1704 Function determins if the CommandName COULD be a valid command. It does not determine whether
1705 this is a valid command. It only checks for invalid characters.
1707 @param[in] CommandName The name to check
1709 @retval TRUE CommandName could be a command name
1710 @retval FALSE CommandName could not be a valid command name
1715 IN CONST CHAR16
*CommandName
1719 if (CommandName
== NULL
) {
1724 ; Count
< sizeof(InvalidChars
) / sizeof(InvalidChars
[0])
1727 if (ScanMem16(CommandName
, StrSize(CommandName
), InvalidChars
[Count
]) != NULL
) {
1735 Function to process a NSH script file via SHELL_FILE_HANDLE.
1737 @param[in] Handle The handle to the already opened file.
1738 @param[in] Name The name of the script file.
1740 @retval EFI_SUCCESS the script completed sucessfully
1744 RunScriptFileHandle (
1745 IN SHELL_FILE_HANDLE Handle
,
1746 IN CONST CHAR16
*Name
1750 SCRIPT_FILE
*NewScriptFile
;
1752 CHAR16
*CommandLine
;
1753 CHAR16
*CommandLine2
;
1754 CHAR16
*CommandLine3
;
1755 SCRIPT_COMMAND_LIST
*LastCommand
;
1757 BOOLEAN PreScriptEchoState
;
1758 BOOLEAN PreCommandEchoState
;
1759 CONST CHAR16
*CurDir
;
1761 CHAR16 LeString
[50];
1763 ASSERT(!ShellCommandGetScriptExit());
1765 PreScriptEchoState
= ShellCommandGetEchoState();
1767 NewScriptFile
= (SCRIPT_FILE
*)AllocateZeroPool(sizeof(SCRIPT_FILE
));
1768 if (NewScriptFile
== NULL
) {
1769 return (EFI_OUT_OF_RESOURCES
);
1775 ASSERT(NewScriptFile
->ScriptName
== NULL
);
1776 NewScriptFile
->ScriptName
= StrnCatGrow(&NewScriptFile
->ScriptName
, NULL
, Name
, 0);
1777 if (NewScriptFile
->ScriptName
== NULL
) {
1778 DeleteScriptFileStruct(NewScriptFile
);
1779 return (EFI_OUT_OF_RESOURCES
);
1783 // Save the parameters (used to replace %0 to %9 later on)
1785 NewScriptFile
->Argc
= ShellInfoObject
.NewShellParametersProtocol
->Argc
;
1786 if (NewScriptFile
->Argc
!= 0) {
1787 NewScriptFile
->Argv
= (CHAR16
**)AllocateZeroPool(NewScriptFile
->Argc
* sizeof(CHAR16
*));
1788 if (NewScriptFile
->Argv
== NULL
) {
1789 DeleteScriptFileStruct(NewScriptFile
);
1790 return (EFI_OUT_OF_RESOURCES
);
1792 for (LoopVar
= 0 ; LoopVar
< 10 && LoopVar
< NewScriptFile
->Argc
; LoopVar
++) {
1793 ASSERT(NewScriptFile
->Argv
[LoopVar
] == NULL
);
1794 NewScriptFile
->Argv
[LoopVar
] = StrnCatGrow(&NewScriptFile
->Argv
[LoopVar
], NULL
, ShellInfoObject
.NewShellParametersProtocol
->Argv
[LoopVar
], 0);
1795 if (NewScriptFile
->Argv
[LoopVar
] == NULL
) {
1796 DeleteScriptFileStruct(NewScriptFile
);
1797 return (EFI_OUT_OF_RESOURCES
);
1801 NewScriptFile
->Argv
= NULL
;
1804 InitializeListHead(&NewScriptFile
->CommandList
);
1805 InitializeListHead(&NewScriptFile
->SubstList
);
1808 // Now build the list of all script commands.
1811 while(!ShellFileHandleEof(Handle
)) {
1812 CommandLine
= ShellFileHandleReturnLine(Handle
, &Ascii
);
1814 if (CommandLine
== NULL
|| StrLen(CommandLine
) == 0) {
1817 NewScriptFile
->CurrentCommand
= AllocateZeroPool(sizeof(SCRIPT_COMMAND_LIST
));
1818 if (NewScriptFile
->CurrentCommand
== NULL
) {
1819 DeleteScriptFileStruct(NewScriptFile
);
1820 return (EFI_OUT_OF_RESOURCES
);
1823 NewScriptFile
->CurrentCommand
->Cl
= CommandLine
;
1824 NewScriptFile
->CurrentCommand
->Data
= NULL
;
1825 NewScriptFile
->CurrentCommand
->Line
= LineCount
;
1827 InsertTailList(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
1831 // Add this as the topmost script file
1833 ShellCommandSetNewScript (NewScriptFile
);
1836 // Now enumerate through the commands and run each one.
1838 CommandLine
= AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize
));
1839 if (CommandLine
== NULL
) {
1840 DeleteScriptFileStruct(NewScriptFile
);
1841 return (EFI_OUT_OF_RESOURCES
);
1843 CommandLine2
= AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize
));
1844 if (CommandLine2
== NULL
) {
1845 FreePool(CommandLine
);
1846 DeleteScriptFileStruct(NewScriptFile
);
1847 return (EFI_OUT_OF_RESOURCES
);
1850 for ( NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&NewScriptFile
->CommandList
)
1851 ; !IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)
1852 ; // conditional increment in the body of the loop
1854 ASSERT(CommandLine2
!= NULL
);
1855 StrCpy(CommandLine2
, NewScriptFile
->CurrentCommand
->Cl
);
1858 // NULL out comments
1860 for (CommandLine3
= CommandLine2
; CommandLine3
!= NULL
&& *CommandLine3
!= CHAR_NULL
; CommandLine3
++) {
1861 if (*CommandLine3
== L
'^') {
1862 if (*(CommandLine3
+1) == L
'#' || *(CommandLine3
+1) == L
':') {
1863 CopyMem(CommandLine3
, CommandLine3
+1, StrSize(CommandLine3
) - sizeof(CommandLine3
[0]));
1865 } else if (*CommandLine3
== L
'#') {
1866 *CommandLine3
= CHAR_NULL
;
1870 if (CommandLine2
!= NULL
&& StrLen(CommandLine2
) >= 1) {
1872 // Due to variability in starting the find and replace action we need to have both buffers the same.
1874 StrCpy(CommandLine
, CommandLine2
);
1877 // Remove the %0 to %9 from the command line (if we have some arguments)
1879 if (NewScriptFile
->Argv
!= NULL
) {
1880 switch (NewScriptFile
->Argc
) {
1882 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%9", NewScriptFile
->Argv
[9], FALSE
, TRUE
);
1883 ASSERT_EFI_ERROR(Status
);
1885 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%8", NewScriptFile
->Argv
[8], FALSE
, TRUE
);
1886 ASSERT_EFI_ERROR(Status
);
1888 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%7", NewScriptFile
->Argv
[7], FALSE
, TRUE
);
1889 ASSERT_EFI_ERROR(Status
);
1891 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%6", NewScriptFile
->Argv
[6], FALSE
, TRUE
);
1892 ASSERT_EFI_ERROR(Status
);
1894 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%5", NewScriptFile
->Argv
[5], FALSE
, TRUE
);
1895 ASSERT_EFI_ERROR(Status
);
1897 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%4", NewScriptFile
->Argv
[4], FALSE
, TRUE
);
1898 ASSERT_EFI_ERROR(Status
);
1900 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%3", NewScriptFile
->Argv
[3], FALSE
, TRUE
);
1901 ASSERT_EFI_ERROR(Status
);
1903 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%2", NewScriptFile
->Argv
[2], FALSE
, TRUE
);
1904 ASSERT_EFI_ERROR(Status
);
1906 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%1", NewScriptFile
->Argv
[1], FALSE
, TRUE
);
1907 ASSERT_EFI_ERROR(Status
);
1909 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%0", NewScriptFile
->Argv
[0], FALSE
, TRUE
);
1910 ASSERT_EFI_ERROR(Status
);
1916 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%1", L
"\"\"", FALSE
, FALSE
);
1917 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%2", L
"\"\"", FALSE
, FALSE
);
1918 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%3", L
"\"\"", FALSE
, FALSE
);
1919 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%4", L
"\"\"", FALSE
, FALSE
);
1920 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%5", L
"\"\"", FALSE
, FALSE
);
1921 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%6", L
"\"\"", FALSE
, FALSE
);
1922 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%7", L
"\"\"", FALSE
, FALSE
);
1923 Status
= ShellCopySearchAndReplace(CommandLine
, CommandLine2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%8", L
"\"\"", FALSE
, FALSE
);
1924 Status
= ShellCopySearchAndReplace(CommandLine2
, CommandLine
, PcdGet16 (PcdShellPrintBufferSize
), L
"%9", L
"\"\"", FALSE
, FALSE
);
1926 StrCpy(CommandLine2
, CommandLine
);
1928 LastCommand
= NewScriptFile
->CurrentCommand
;
1930 for (CommandLine3
= CommandLine2
; CommandLine3
[0] == L
' ' ; CommandLine3
++);
1932 if (CommandLine3
!= NULL
&& CommandLine3
[0] == L
':' ) {
1934 // This line is a goto target / label
1937 if (CommandLine3
!= NULL
&& StrLen(CommandLine3
) > 0) {
1938 if (CommandLine3
[0] == L
'@') {
1940 // We need to save the current echo state
1941 // and disable echo for just this command.
1943 PreCommandEchoState
= ShellCommandGetEchoState();
1944 ShellCommandSetEchoState(FALSE
);
1945 Status
= RunCommand(CommandLine3
+1);
1948 // If command was "@echo -off" or "@echo -on" then don't restore echo state
1950 if (StrCmp (L
"@echo -off", CommandLine3
) != 0 &&
1951 StrCmp (L
"@echo -on", CommandLine3
) != 0) {
1953 // Now restore the pre-'@' echo state.
1955 ShellCommandSetEchoState(PreCommandEchoState
);
1958 if (ShellCommandGetEchoState()) {
1959 CurDir
= ShellInfoObject
.NewEfiShellProtocol
->GetEnv(L
"cwd");
1960 if (CurDir
!= NULL
&& StrLen(CurDir
) > 1) {
1961 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_CURDIR
), ShellInfoObject
.HiiHandle
, CurDir
);
1963 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_SHELL_SHELL
), ShellInfoObject
.HiiHandle
);
1965 ShellPrintEx(-1, -1, L
"%s\r\n", CommandLine2
);
1967 Status
= RunCommand(CommandLine3
);
1971 if (ShellCommandGetScriptExit()) {
1973 // ShellCommandGetExitCode() always returns a UINT64
1975 UnicodeSPrint(LeString
, sizeof(LeString
), L
"0x%Lx", ShellCommandGetExitCode());
1976 DEBUG_CODE(InternalEfiShellSetEnv(L
"debuglasterror", LeString
, TRUE
););
1977 InternalEfiShellSetEnv(L
"lasterror", LeString
, TRUE
);
1979 ShellCommandRegisterExit(FALSE
, 0);
1980 Status
= EFI_SUCCESS
;
1983 if (ShellGetExecutionBreakFlag()) {
1986 if (EFI_ERROR(Status
)) {
1989 if (ShellCommandGetExit()) {
1994 // If that commend did not update the CurrentCommand then we need to advance it...
1996 if (LastCommand
== NewScriptFile
->CurrentCommand
) {
1997 NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetNextNode(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
1998 if (!IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)) {
1999 NewScriptFile
->CurrentCommand
->Reset
= TRUE
;
2003 NewScriptFile
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetNextNode(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
);
2004 if (!IsNull(&NewScriptFile
->CommandList
, &NewScriptFile
->CurrentCommand
->Link
)) {
2005 NewScriptFile
->CurrentCommand
->Reset
= TRUE
;
2011 FreePool(CommandLine
);
2012 FreePool(CommandLine2
);
2013 ShellCommandSetNewScript (NULL
);
2016 // Only if this was the last script reset the state.
2018 if (ShellCommandGetCurrentScriptFile()==NULL
) {
2019 ShellCommandSetEchoState(PreScriptEchoState
);
2021 return (EFI_SUCCESS
);
2025 Function to process a NSH script file.
2027 @param[in] ScriptPath Pointer to the script file name (including file system path).
2029 @retval EFI_SUCCESS the script completed sucessfully
2034 IN CONST CHAR16
*ScriptPath
2038 SHELL_FILE_HANDLE FileHandle
;
2040 if (ShellIsFile(ScriptPath
) != EFI_SUCCESS
) {
2041 return (EFI_INVALID_PARAMETER
);
2044 Status
= ShellOpenFileByName(ScriptPath
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
2045 if (EFI_ERROR(Status
)) {
2049 Status
= RunScriptFileHandle(FileHandle
, ScriptPath
);
2051 ShellCloseFile(&FileHandle
);