<commit_before>#region auto-generated FILE INFORMATION

// ==============================================
// This file is distributed under the MIT License
// ==============================================
// 
// Filename: ProcessEx.cs
// Version:  2020-01-04 12:38
// 
// Copyright (c) 2020, Si13n7 Developments (r)
// All rights reserved.
// ______________________________________________

#endregion

namespace SilDev
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Management;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using Intern;
    using Microsoft.Win32.SafeHandles;
    using Properties;

    /// <summary>
    ///     Provides static methods based on the <see cref="Process"/> class to enable you to start
    ///     local system processes.
    /// </summary>
    public static class ProcessEx
    {
        private static Process _current;

        /// <summary>
        ///     Gets the currently active process.
        /// </summary>
        public static Process Current
        {
            get
            {
                if (_current != default)
                    return _current;
                _current = Process.GetCurrentProcess();
                return _current;
            }
        }

        /// <summary>
        ///     Gets the handle of the current process instance.
        /// </summary>
        public static IntPtr CurrentHandle =>
            Current.Handle;

        /// <summary>
        ///     Gets the unique identifier of the current process instance.
        /// </summary>
        public static int CurrentId =>
            Current.Id;

        /// <summary>
        ///     Gets the name of the current process instance.
        /// </summary>
        public static string CurrentName =>
            Current.ProcessName;

        /// <summary>
        ///     Gets the parent process of the current process instance.
        /// </summary>
        public static Process CurrentParent =>
            Current.GetParent();

        /// <summary>
        ///     Gets the parent process of this <see cref="Process"/>.
        /// </summary>
        /// <param name="process">
        ///     The <see cref="Process"/> component.
        /// </param>
        public static Process GetParent(this Process process)
        {
            try
            {
                if (process == null)
                    throw new ArgumentNullException(nameof(process));
                var childId = process.Id;
                var childName = Process.GetProcessById(childId).ProcessName;
                var processes = Process.GetProcessesByName(childName);
                string parentName = null;
                for (var i = 0; i < processes.Length; i++)
                {
                    parentName = i == 0 ? childName : $"{childName}#{i}";
                    using (var tmpId = new PerformanceCounter("Process", "ID Process", parentName))
                        if ((int)tmpId.NextValue() == childId)
                            break;
                }
                using (var parentId = new PerformanceCounter("Process", "Creating Process ID", parentName))
                    return Process.GetProcessById((int)parentId.NextValue());
            }
            catch (Exception ex) when (ex.IsCaught())
            {
                Log.Write(ex);
            }
            return null;
        }

        /// <summary>
        ///     Gets all active instances associated with the specified application.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to get firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param>
        public static IEnumerable<Process> GetInstances(string nameOrPath, bool doubleTap = false)
        {
            try
            {
                IEnumerable<Process> instances;
                var path = PathEx.Combine(default(char[]), nameOrPath);
                var name = Path.GetFileNameWithoutExtension(path);
                try
                {
                    if (!path.ContainsEx(Path.DirectorySeparatorChar) || !File.Exists(path))
                    {
                        doubleTap = true;
                        throw new ArgumentException();
                    }
                    instances = Process.GetProcesses().Where(p => p.ProcessName.EqualsEx(name) && (p.MainModule ?? throw new ArgumentException()).FileName.EqualsEx(path));
                }
                catch (Exception ex) when (ex.IsCaught())
                {
                    if (!doubleTap)
                        return null;
                    instances = Process.GetProcessesByName(name);
                }
                return instances;
            }
            catch (Exception ex) when (ex.IsCaught())
            {
                Log.Write(ex);
                return null;
            }
        }

        /// <summary>
        ///     Returns the number of all active instances associated with the specified
        ///     application.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to check firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param>
        public static int InstancesCount(string nameOrPath, bool doubleTap = false)
        {
            var count = 0;
            try
            {
                foreach (var p in GetInstances(nameOrPath, doubleTap))
                {
                    count++;
                    p?.Dispose();
                }
            }
            catch (Exception ex) when (ex.IsCaught())
            {
                Log.Write(ex);
            }
            return count;
        }

        /// <summary>
        ///     Determines whether the specified file is matched with a running process.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to check firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param><commit_msg>Improve enumeration of Process instances.<commit_after>#region auto-generated FILE INFORMATION

// ==============================================
// This file is distributed under the MIT License
// ==============================================
// 
// Filename: ProcessEx.cs
// Version:  2020-01-04 12:40
// 
// Copyright (c) 2020, Si13n7 Developments (r)
// All rights reserved.
// ______________________________________________

#endregion

namespace SilDev
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Management;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;
    using Intern;
    using Microsoft.Win32.SafeHandles;
    using Properties;

    /// <summary>
    ///     Provides static methods based on the <see cref="Process"/> class to enable you to start
    ///     local system processes.
    /// </summary>
    public static class ProcessEx
    {
        private static Process _current;

        /// <summary>
        ///     Gets the currently active process.
        /// </summary>
        public static Process Current
        {
            get
            {
                if (_current != default)
                    return _current;
                _current = Process.GetCurrentProcess();
                return _current;
            }
        }

        /// <summary>
        ///     Gets the handle of the current process instance.
        /// </summary>
        public static IntPtr CurrentHandle =>
            Current.Handle;

        /// <summary>
        ///     Gets the unique identifier of the current process instance.
        /// </summary>
        public static int CurrentId =>
            Current.Id;

        /// <summary>
        ///     Gets the name of the current process instance.
        /// </summary>
        public static string CurrentName =>
            Current.ProcessName;

        /// <summary>
        ///     Gets the parent process of the current process instance.
        /// </summary>
        public static Process CurrentParent =>
            Current.GetParent();

        /// <summary>
        ///     Gets the parent process of this <see cref="Process"/>.
        /// </summary>
        /// <param name="process">
        ///     The <see cref="Process"/> component.
        /// </param>
        public static Process GetParent(this Process process)
        {
            try
            {
                if (process == null)
                    throw new ArgumentNullException(nameof(process));
                var childId = process.Id;
                var childName = Process.GetProcessById(childId).ProcessName;
                var processes = Process.GetProcessesByName(childName);
                string parentName = null;
                for (var i = 0; i < processes.Length; i++)
                {
                    parentName = i == 0 ? childName : $"{childName}#{i}";
                    using (var tmpId = new PerformanceCounter("Process", "ID Process", parentName))
                        if ((int)tmpId.NextValue() == childId)
                            break;
                }
                using (var parentId = new PerformanceCounter("Process", "Creating Process ID", parentName))
                    return Process.GetProcessById((int)parentId.NextValue());
            }
            catch (Exception ex) when (ex.IsCaught())
            {
                Log.Write(ex);
            }
            return null;
        }

        /// <summary>
        ///     Gets all active instances associated with the specified application. If the
        ///     specified name/path is null, all running processes are returned.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to get firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param>
        public static IEnumerable<Process> GetInstances(string nameOrPath, bool doubleTap = false)
        {
            if (nameOrPath != null && string.IsNullOrWhiteSpace(nameOrPath))
                yield break;
            var path = nameOrPath;
            if (path?.StartsWith("\\", StringComparison.Ordinal) ?? false)
                path = path.TrimStart('\t', ' ', '?', '\\');
            path = PathEx.Combine(path);
            var isPath = path.ContainsEx(Path.DirectorySeparatorChar);
            if (isPath && !File.Exists(path))
                yield break;
            if (!isPath && !doubleTap)
                doubleTap = true;
            var name = nameOrPath;
            if (!string.IsNullOrEmpty(name))
                name = path.EndsWithEx(".com", ".exe", ".scr") ? Path.GetFileNameWithoutExtension(path) : Path.GetFileName(path);
            foreach (var p in Process.GetProcesses())
            {
                if (name == null)
                {
                    yield return p;
                    continue;
                }
                if (!p.ProcessName.EqualsEx(name))
                    continue;
                var mPath = default(string);
                if (isPath)
                    try
                    {
                        mPath = p.MainModule?.FileName;
                    }
                    catch (Exception ex) when (ex.IsCaught())
                    {
                        if (!(ex is ArgumentException))
                            Log.Write(ex);
                    }
                if (mPath?.EqualsEx(path) ?? isPath && doubleTap || doubleTap)
                    yield return p;
            }
        }

        /// <summary>
        ///     Returns the number of all active instances associated with the specified
        ///     application. If the specified name/path is null, the number of all running
        ///     processes is returned.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to check firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param>
        public static int InstancesCount(string nameOrPath, bool doubleTap = false) =>
            GetInstances(nameOrPath, doubleTap).Count();

        /// <summary>
        ///     Determines whether the specified file is matched with a running process.
        /// </summary>
        /// <param name="nameOrPath">
        ///     The filename or the full path to the application to check.
        /// </param>
        /// <param name="doubleTap">
        ///     true to try to check firstly by the path, then by name; otherwise, false.
        ///     <para>
        ///         Please note that this option has no effect if the first parameter contains
        ///         only a name.
        ///     </para>
        /// </param>
{'fraction_non_alphanumeric': 0.11674495717048909, 'fraction_numerical': 0.003246753246753247, 'mean_word_length': 1.3767854211131176, 'pattern_counts': {'":': 0, '<': 94, '<?xml version=': 0, '>': 102, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '886639', 'n_tokens_mistral': 3498, 'n_tokens_neox': 3366, 'n_words': 1081}