bin/projects/dbatools/dbatools/Utility/UtilityHost.cs

using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Reflection;
 
namespace Sqlcollaborative.Dbatools.Utility
{
    /// <summary>
    /// Provides static resources to utility-namespaced stuff
    /// </summary>
    public static class UtilityHost
    {
        /// <summary>
        /// Restores all DateTime objects to their default display behavior
        /// </summary>
        public static bool DisableCustomDateTime = false;
 
        /// <summary>
        /// Restores all timespan objects to their default display behavior.
        /// </summary>
        public static bool DisableCustomTimeSpan = false;
 
        /// <summary>
        /// Formating string for date-style datetime objects.
        /// </summary>
        public static string FormatDate = "dd MMM yyyy";
 
        /// <summary>
        /// Formating string for datetime-style datetime objects
        /// </summary>
        public static string FormatDateTime = "yyyy-MM-dd HH:mm:ss.fff";
 
        /// <summary>
        /// Formating string for time-style datetime objects
        /// </summary>
        public static string FormatTime = "HH:mm:ss";
 
        /// <summary>
        /// The number of digits a size object shows by default
        /// </summary>
        public static int SizeDigits = 2;
 
        /// <summary>
        /// The way size objects are usually displayed
        /// </summary>
        public static SizeStyle SizeStyle = SizeStyle.Dynamic;
 
        /// <summary>
        /// Implement's VB's Like operator logic.
        /// </summary>
        /// <param name="CaseSensitive">Whether the comparison is case sensitive</param>
        /// <param name="Pattern">The pattern the string is compared with</param>
        /// <param name="String">The string that is being compared with a pattern</param>
        public static bool IsLike(string String, string Pattern, bool CaseSensitive = false)
        {
            if (!CaseSensitive)
            {
                String = String.ToLower();
                Pattern = Pattern.ToLower();
            }
 
            // Characters matched so far
            int matched = 0;
 
            // Loop through pattern string
            for (int i = 0; i < Pattern.Length;)
            {
                // Check for end of string
                if (matched > String.Length)
                    return false;
 
                // Get next pattern character
                char c = Pattern[i++];
                if (c == '[') // Character list
                {
                    // Test for exclude character
                    bool exclude = (i < Pattern.Length && Pattern[i] == '!');
                    if (exclude)
                        i++;
                    // Build character list
                    int j = Pattern.IndexOf(']', i);
                    if (j < 0)
                        j = String.Length;
                    HashSet<char> charList = CharListToSet(Pattern.Substring(i, j - i));
                    i = j + 1;
 
                    if (charList.Contains(String[matched]) == exclude)
                        return false;
                    matched++;
                }
                else if (c == '?') // Any single character
                {
                    matched++;
                }
                else if (c == '#') // Any single digit
                {
                    if (!Char.IsDigit(String[matched]))
                        return false;
                    matched++;
                }
                else if (c == '*') // Zero or more characters
                {
                    if (i < Pattern.Length)
                    {
                        // Matches all characters until
                        // next character in pattern
                        char next = Pattern[i];
                        int j = String.IndexOf(next, matched);
                        if (j < 0)
                            return false;
                        matched = j;
                    }
                    else
                    {
                        // Matches all remaining characters
                        matched = String.Length;
                        break;
                    }
                }
                else // Exact character
                {
                    if (matched >= String.Length || c != String[matched])
                        return false;
                    matched++;
                }
            }
            // Return true if all characters matched
            return (matched == String.Length);
        }
 
        /// <summary>
        /// Converts a string of characters to a HashSet of characters. If the string
        /// contains character ranges, such as A-Z, all characters in the range are
        /// also added to the returned set of characters.
        /// </summary>
        /// <param name="charList">Character list string</param>
        private static HashSet<char> CharListToSet(string charList)
        {
            HashSet<char> set = new HashSet<char>();
 
            for (int i = 0; i < charList.Length; i++)
            {
                if ((i + 1) < charList.Length && charList[i + 1] == '-')
                {
                    // Character range
                    char startChar = charList[i++];
                    i++; // Hyphen
                    char endChar = (char)0;
                    if (i < charList.Length)
                        endChar = charList[i++];
                    for (int j = startChar; j <= endChar; j++)
                        set.Add((char)j);
                }
                else set.Add(charList[i]);
            }
            return set;
        }
 
        /// <summary>
        /// Returns the current callstack
        /// </summary>
        public static IEnumerable<CallStackFrame> Callstack
        {
            get
            {
                // Works on PS4+
                try { return _CallstackNew; }
 
                // Needed for PS3
                catch { return _CallstackOld; }
            }
        }
 
        /// <summary>
        /// Returns the current callstack on PS4+
        /// </summary>
        private static IEnumerable<CallStackFrame> _CallstackNew
        {
            get
            {
                return System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Debugger.GetCallStack();
            }
        }
 
        /// <summary>
        /// Returns the current callstack on PS3
        /// </summary>
        private static IEnumerable<CallStackFrame> _CallstackOld
        {
            get
            {
                MethodInfo method = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Debugger.GetType().GetMethod("GetCallStack", BindingFlags.NonPublic | BindingFlags.Instance);
                return (IEnumerable<CallStackFrame>)method.Invoke(System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Debugger, null);
            }
        }
    }
}