/** @file Main file for NULL named library for level 1 shell command functions. (C) Copyright 2013 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "UefiShellLevel1CommandsLib.h" STATIC CONST CHAR16 mFileName[] = L"ShellCommands"; EFI_HII_HANDLE gShellLevel1HiiHandle = NULL; /** Return the help text filename. Only used if no HII information found. @retval the filename. **/ CONST CHAR16 * EFIAPI ShellCommandGetManFileNameLevel1 ( VOID ) { return (mFileName); } /** Constructor for the Shell Level 1 Commands library. Install the handlers for level 1 UEFI Shell 2.0 commands. @param ImageHandle the image handle of the process @param SystemTable the EFI System Table pointer @retval EFI_SUCCESS the shell command handlers were installed successfully @retval EFI_UNSUPPORTED the shell level required was not found. **/ EFI_STATUS EFIAPI ShellLevel1CommandsLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { // // if shell level is less than 2 do nothing // if (PcdGet8 (PcdShellSupportLevel) < 1) { return (EFI_SUCCESS); } gShellLevel1HiiHandle = HiiAddPackages (&gShellLevel1HiiGuid, gImageHandle, UefiShellLevel1CommandsLibStrings, NULL); if (gShellLevel1HiiHandle == NULL) { return (EFI_DEVICE_ERROR); } // // install our shell command handlers that are always installed // ShellCommandRegisterCommandName (L"stall", ShellCommandRunStall, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_STALL))); ShellCommandRegisterCommandName (L"for", ShellCommandRunFor, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_FOR))); ShellCommandRegisterCommandName (L"goto", ShellCommandRunGoto, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_GOTO))); ShellCommandRegisterCommandName (L"if", ShellCommandRunIf, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_IF))); ShellCommandRegisterCommandName (L"shift", ShellCommandRunShift, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_SHIFT))); ShellCommandRegisterCommandName (L"exit", ShellCommandRunExit, ShellCommandGetManFileNameLevel1, 1, L"", TRUE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_EXIT))); ShellCommandRegisterCommandName (L"else", ShellCommandRunElse, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_ELSE))); ShellCommandRegisterCommandName (L"endif", ShellCommandRunEndIf, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_ENDIF))); ShellCommandRegisterCommandName (L"endfor", ShellCommandRunEndFor, ShellCommandGetManFileNameLevel1, 1, L"", FALSE, gShellLevel1HiiHandle, (EFI_STRING_ID)(PcdGet8 (PcdShellSupportLevel) < 3 ? 0 : STRING_TOKEN (STR_GET_HELP_ENDFOR))); return (EFI_SUCCESS); } /** Destructor for the library. free any resources. @param ImageHandle The image handle of the process. @param SystemTable The EFI System Table pointer. **/ EFI_STATUS EFIAPI ShellLevel1CommandsLibDestructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { if (gShellLevel1HiiHandle != NULL) { HiiRemovePackages (gShellLevel1HiiHandle); } return (EFI_SUCCESS); } /** Test a node to see if meets the criterion. It functions so that count starts at 1 and it increases or decreases when it hits the specified tags. when it hits zero the location has been found. DecrementerTag and IncrementerTag are used to get around for/endfor and similar paired types where the entire middle should be ignored. If label is used it will be used instead of the count. @param[in] Function The function to use to enumerate through the list. Normally GetNextNode or GetPreviousNode. @param[in] DecrementerTag The tag to decrement the count at. @param[in] IncrementerTag The tag to increment the count at. @param[in] Label A label to look for. @param[in, out] ScriptFile The pointer to the current script file structure. @param[in] MovePast TRUE makes function return 1 past the found location. @param[in] FindOnly TRUE to not change the ScriptFile. @param[in] CommandNode The pointer to the Node to test. @param[in, out] TargetCount The pointer to the current count. **/ BOOLEAN TestNodeForMove ( IN CONST LIST_MANIP_FUNC Function, IN CONST CHAR16 *DecrementerTag, IN CONST CHAR16 *IncrementerTag, IN CONST CHAR16 *Label OPTIONAL, IN OUT SCRIPT_FILE *ScriptFile, IN CONST BOOLEAN MovePast, IN CONST BOOLEAN FindOnly, IN CONST SCRIPT_COMMAND_LIST *CommandNode, IN OUT UINTN *TargetCount ) { BOOLEAN Found; CHAR16 *CommandName; CHAR16 *CommandNameWalker; CHAR16 *TempLocation; Found = FALSE; // // get just the first part of the command line... // CommandName = NULL; CommandName = StrnCatGrow (&CommandName, NULL, CommandNode->Cl, 0); if (CommandName == NULL) { return (FALSE); } CommandNameWalker = CommandName; // // Skip leading spaces and tabs. // while ((CommandNameWalker[0] == L' ') || (CommandNameWalker[0] == L'\t')) { CommandNameWalker++; } TempLocation = StrStr (CommandNameWalker, L" "); if (TempLocation != NULL) { *TempLocation = CHAR_NULL; } // // did we find a nested item ? // if (gUnicodeCollation->StriColl ( gUnicodeCollation, (CHAR16 *)CommandNameWalker, (CHAR16 *)IncrementerTag ) == 0) { (*TargetCount)++; } else if (gUnicodeCollation->StriColl ( gUnicodeCollation, (CHAR16 *)CommandNameWalker, (CHAR16 *)DecrementerTag ) == 0) { if (*TargetCount > 0) { (*TargetCount)--; } } // // did we find the matching one... // if (Label == NULL) { if (*TargetCount == 0) { Found = TRUE; if (!FindOnly) { if (MovePast) { ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); } else { ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; } } } } else { if ( (gUnicodeCollation->StriColl ( gUnicodeCollation, (CHAR16 *)CommandNameWalker, (CHAR16 *)Label ) == 0) && ((*TargetCount) == 0)) { Found = TRUE; if (!FindOnly) { // // we found the target label without loops // if (MovePast) { ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link); } else { ScriptFile->CurrentCommand = (SCRIPT_COMMAND_LIST *)CommandNode; } } } } // // Free the memory for this loop... // FreePool (CommandName); return (Found); } /** Move the script pointer from 1 tag (line) to another. It functions so that count starts at 1 and it increases or decreases when it hits the specified tags. when it hits zero the location has been found. DecrementerTag and IncrementerTag are used to get around for/endfor and similar paired types where the entire middle should be ignored. If label is used it will be used instead of the count. @param[in] Function The function to use to enumerate through the list. Normally GetNextNode or GetPreviousNode. @param[in] DecrementerTag The tag to decrement the count at. @param[in] IncrementerTag The tag to increment the count at. @param[in] Label A label to look for. @param[in, out] ScriptFile The pointer to the current script file structure. @param[in] MovePast TRUE makes function return 1 past the found location. @param[in] FindOnly TRUE to not change the ScriptFile. @param[in] WrapAroundScript TRUE to wrap end-to-beginning or vise versa in searching. **/ BOOLEAN MoveToTag ( IN CONST LIST_MANIP_FUNC Function, IN CONST CHAR16 *DecrementerTag, IN CONST CHAR16 *IncrementerTag, IN CONST CHAR16 *Label OPTIONAL, IN OUT SCRIPT_FILE *ScriptFile, IN CONST BOOLEAN MovePast, IN CONST BOOLEAN FindOnly, IN CONST BOOLEAN WrapAroundScript ) { SCRIPT_COMMAND_LIST *CommandNode; BOOLEAN Found; UINTN TargetCount; if (Label == NULL) { TargetCount = 1; } else { TargetCount = 0; } if (ScriptFile == NULL) { return FALSE; } for (CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &ScriptFile->CurrentCommand->Link), Found = FALSE ; !IsNull (&ScriptFile->CommandList, &CommandNode->Link) && !Found ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) ) { Found = TestNodeForMove ( Function, DecrementerTag, IncrementerTag, Label, ScriptFile, MovePast, FindOnly, CommandNode, &TargetCount ); } if (WrapAroundScript && !Found) { for (CommandNode = (SCRIPT_COMMAND_LIST *)GetFirstNode (&ScriptFile->CommandList), Found = FALSE ; CommandNode != ScriptFile->CurrentCommand && !Found ; CommandNode = (SCRIPT_COMMAND_LIST *)(*Function)(&ScriptFile->CommandList, &CommandNode->Link) ) { Found = TestNodeForMove ( Function, DecrementerTag, IncrementerTag, Label, ScriptFile, MovePast, FindOnly, CommandNode, &TargetCount ); } } return (Found); }