/** @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 sucessfully @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-begining 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); }