<commit_before>/** @file
  Provides interface to shell internal functions for shell commands.

  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include "UefiShellCommandLib.h"

// STATIC local variables
STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY  mCommandList;
STATIC SCRIPT_FILE_LIST                   mScriptList;
STATIC ALIAS_LIST                         mAliasList;
STATIC BOOLEAN                            mEchoState;
STATIC BOOLEAN                            mExitRequested;
STATIC UINT64                             mExitCode;
STATIC BOOLEAN                            mExitScript;
STATIC CHAR16                             *mProfileList;
STATIC UINTN                              mProfileListSize;
STATIC UINTN                              mFsMaxCount = 0;
STATIC UINTN                              mBlkMaxCount = 0;
STATIC BUFFER_LIST                        mFileHandleList;

// global variables required by library class.
EFI_UNICODE_COLLATION_PROTOCOL    *gUnicodeCollation            = NULL;
SHELL_MAP_LIST                    gShellMapList;
SHELL_MAP_LIST                    *gShellCurDir                 = NULL;

CONST CHAR16* SupportLevel[] = {
  L"Minimal",
  L"Scripting",
  L"Basic",
  L"Interactive"
};

/**
  Function to make sure that the global protocol pointers are valid.
  must be called after constructor before accessing the pointers.
**/
EFI_STATUS
EFIAPI
CommandInit(
  VOID
  )
{
  EFI_STATUS Status;
  if (gUnicodeCollation == NULL) {
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
    if (EFI_ERROR(Status)) {
      return (EFI_DEVICE_ERROR);
    }
  }
  return (EFI_SUCCESS);
}

/**
  Constructor for the Shell Command library.

  Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.

  @param ImageHandle    the image handle of the process
  @param SystemTable    the EFI System Table pointer

  @retval EFI_SUCCESS   the initialization was complete sucessfully
**/
RETURN_STATUS
EFIAPI
ShellCommandLibConstructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS        Status;
  InitializeListHead(&gShellMapList.Link);
  InitializeListHead(&mCommandList.Link);
  InitializeListHead(&mAliasList.Link);
  InitializeListHead(&mScriptList.Link);
  InitializeListHead(&mFileHandleList.Link);
  mEchoState = TRUE;

  mExitRequested    = FALSE;
  mExitScript       = FALSE;
  mProfileListSize  = 0;
  mProfileList      = NULL;

  if (gUnicodeCollation == NULL) {
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
    if (EFI_ERROR(Status)) {
      return (EFI_DEVICE_ERROR);
    }
  }

  return (RETURN_SUCCESS);
}

/**
  Destructor for the library.  free any resources.

  @param ImageHandle    the image handle of the process
  @param SystemTable    the EFI System Table pointer

  @retval RETURN_SUCCESS this function always returns success
**/
RETURN_STATUS
EFIAPI
ShellCommandLibDestructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
  ALIAS_LIST                        *Node2;
  SCRIPT_FILE_LIST                  *Node3;
  SHELL_MAP_LIST                    *MapNode;
  //
  // enumerate throught the list and free all the memory
  //
  while (!IsListEmpty (&mCommandList.Link)) {
    Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);
    RemoveEntryList(&Node->Link);
    SHELL_FREE_NON_NULL(Node->CommandString);
    FreePool(Node);
    DEBUG_CODE(Node = NULL;);
  }

  //
  // enumerate through the alias list and free all memory
  //
  while (!IsListEmpty (&mAliasList.Link)) {
    Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);
    RemoveEntryList(&Node2->Link);
    SHELL_FREE_NON_NULL(Node2->CommandString);
    SHELL_FREE_NON_NULL(Node2->Alias);
    SHELL_FREE_NON_NULL(Node2);
    DEBUG_CODE(Node2 = NULL;);
  }

  //
  // enumerate throught the list and free all the memory
  //
  while (!IsListEmpty (&mScriptList.Link)) {
    Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
    RemoveEntryList(&Node3->Link);
    DeleteScriptFileStruct(Node3->Data);
    FreePool(Node3);
  }

  //
  // enumerate throught the mappings list and free all the memory
  //
  if (!IsListEmpty(&gShellMapList.Link)) {
    for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
         ; !IsListEmpty (&gShellMapList.Link)
         ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
        ){
      ASSERT(MapNode != NULL);
      RemoveEntryList(&MapNode->Link);
      SHELL_FREE_NON_NULL(MapNode->DevicePath);
      SHELL_FREE_NON_NULL(MapNode->MapName);
      SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);
      FreePool(MapNode);
    }
  }
  if (!IsListEmpty(&mFileHandleList.Link)){
    FreeBufferList(&mFileHandleList);
  }

  if (mProfileList != NULL) {
    FreePool(mProfileList);
  }

  gUnicodeCollation            = NULL;
  gShellCurDir                 = NULL;

  return (RETURN_SUCCESS);
}

/**
  Checks if a command is already on the list.

  @param[in] CommandString        The command string to check for on the list.
**/
BOOLEAN
EFIAPI
ShellCommandIsCommandOnList (
  IN CONST  CHAR16                      *CommandString
  )
{
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
<commit_msg>ShellPkg: remove memory leak in file handle list<commit_after>/** @file
  Provides interface to shell internal functions for shell commands.

  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
  This program and the accompanying materials
  are licensed and made available under the terms and conditions of the BSD License
  which accompanies this distribution.  The full text of the license may be found at
  http://opensource.org/licenses/bsd-license.php

  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include "UefiShellCommandLib.h"

// STATIC local variables
STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY  mCommandList;
STATIC SCRIPT_FILE_LIST                   mScriptList;
STATIC ALIAS_LIST                         mAliasList;
STATIC BOOLEAN                            mEchoState;
STATIC BOOLEAN                            mExitRequested;
STATIC UINT64                             mExitCode;
STATIC BOOLEAN                            mExitScript;
STATIC CHAR16                             *mProfileList;
STATIC UINTN                              mProfileListSize;
STATIC UINTN                              mFsMaxCount = 0;
STATIC UINTN                              mBlkMaxCount = 0;
STATIC BUFFER_LIST                        mFileHandleList;

// global variables required by library class.
EFI_UNICODE_COLLATION_PROTOCOL    *gUnicodeCollation            = NULL;
SHELL_MAP_LIST                    gShellMapList;
SHELL_MAP_LIST                    *gShellCurDir                 = NULL;

CONST CHAR16* SupportLevel[] = {
  L"Minimal",
  L"Scripting",
  L"Basic",
  L"Interactive"
};

/**
  Function to make sure that the global protocol pointers are valid.
  must be called after constructor before accessing the pointers.
**/
EFI_STATUS
EFIAPI
CommandInit(
  VOID
  )
{
  EFI_STATUS Status;
  if (gUnicodeCollation == NULL) {
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
    if (EFI_ERROR(Status)) {
      return (EFI_DEVICE_ERROR);
    }
  }
  return (EFI_SUCCESS);
}

/**
  Constructor for the Shell Command library.

  Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.

  @param ImageHandle    the image handle of the process
  @param SystemTable    the EFI System Table pointer

  @retval EFI_SUCCESS   the initialization was complete sucessfully
**/
RETURN_STATUS
EFIAPI
ShellCommandLibConstructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS        Status;
  InitializeListHead(&gShellMapList.Link);
  InitializeListHead(&mCommandList.Link);
  InitializeListHead(&mAliasList.Link);
  InitializeListHead(&mScriptList.Link);
  InitializeListHead(&mFileHandleList.Link);
  mEchoState = TRUE;

  mExitRequested    = FALSE;
  mExitScript       = FALSE;
  mProfileListSize  = 0;
  mProfileList      = NULL;

  if (gUnicodeCollation == NULL) {
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
    if (EFI_ERROR(Status)) {
      return (EFI_DEVICE_ERROR);
    }
  }

  return (RETURN_SUCCESS);
}

/**
  Frees list of file handles.

  @param[in] List     The list to free.
**/
VOID
EFIAPI
FreeFileHandleList (
  IN BUFFER_LIST *List
  )
{
  BUFFER_LIST               *BufferListEntry;

  if (List == NULL){
    return;
  }
  //
  // enumerate through the buffer list and free all memory
  //
  for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
      ; !IsListEmpty (&List->Link)
      ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
     ){
    RemoveEntryList(&BufferListEntry->Link);
    ASSERT(BufferListEntry->Buffer != NULL);
    SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE*)(BufferListEntry->Buffer))->Path);
    SHELL_FREE_NON_NULL(BufferListEntry->Buffer);
    SHELL_FREE_NON_NULL(BufferListEntry);
  }
}

/**
  Destructor for the library.  free any resources.

  @param ImageHandle    the image handle of the process
  @param SystemTable    the EFI System Table pointer

  @retval RETURN_SUCCESS this function always returns success
**/
RETURN_STATUS
EFIAPI
ShellCommandLibDestructor (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
  ALIAS_LIST                        *Node2;
  SCRIPT_FILE_LIST                  *Node3;
  SHELL_MAP_LIST                    *MapNode;
  //
  // enumerate throught the list and free all the memory
  //
  while (!IsListEmpty (&mCommandList.Link)) {
    Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);
    RemoveEntryList(&Node->Link);
    SHELL_FREE_NON_NULL(Node->CommandString);
    FreePool(Node);
    DEBUG_CODE(Node = NULL;);
  }

  //
  // enumerate through the alias list and free all memory
  //
  while (!IsListEmpty (&mAliasList.Link)) {
    Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);
    RemoveEntryList(&Node2->Link);
    SHELL_FREE_NON_NULL(Node2->CommandString);
    SHELL_FREE_NON_NULL(Node2->Alias);
    SHELL_FREE_NON_NULL(Node2);
    DEBUG_CODE(Node2 = NULL;);
  }

  //
  // enumerate throught the list and free all the memory
  //
  while (!IsListEmpty (&mScriptList.Link)) {
    Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
    RemoveEntryList(&Node3->Link);
    DeleteScriptFileStruct(Node3->Data);
    FreePool(Node3);
  }

  //
  // enumerate throught the mappings list and free all the memory
  //
  if (!IsListEmpty(&gShellMapList.Link)) {
    for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
         ; !IsListEmpty (&gShellMapList.Link)
         ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
        ){
      ASSERT(MapNode != NULL);
      RemoveEntryList(&MapNode->Link);
      SHELL_FREE_NON_NULL(MapNode->DevicePath);
      SHELL_FREE_NON_NULL(MapNode->MapName);
      SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);
      FreePool(MapNode);
    }
  }
  if (!IsListEmpty(&mFileHandleList.Link)){
    FreeFileHandleList(&mFileHandleList);
  }

  if (mProfileList != NULL) {
    FreePool(mProfileList);
  }

  gUnicodeCollation            = NULL;
  gShellCurDir                 = NULL;

  return (RETURN_SUCCESS);
}

/**
  Checks if a command is already on the list.

  @param[in] CommandString        The command string to check for on the list.
**/
BOOLEAN
EFIAPI
ShellCommandIsCommandOnList (
  IN CONST  CHAR16                      *CommandString
  )
{
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;

{'fraction_non_alphanumeric': 0.08570738773539353, 'fraction_numerical': 0.005633349428617415, 'mean_word_length': 2.867724867724868, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4889968', 'n_tokens_mistral': 3933, 'n_tokens_neox': 3826, 'n_words': 936}