/// <summary>
        /// Given an exception thrown by a process, determines whether the debugger should
        /// log, ignore, or stop on this exception, based on the type of exception and the
        /// existing exception settings.
        /// </summary>
        /// <returns>stop, log, or ignore</returns>
        protected DebuggerBehavior DetermineBehavior(string exceptionType)
        {
            ExceptionStopOptionPolicyItem currentItem;
            string regex;

            // Check entries in m_items to see if this exception type or a regular expression
            // matching it already exists in m_items. We loop backwards through the array because
            // entries added later have precedence over those added earlier.
            for (int i = m_items.Count - 1; i >= 0; i--)
            {
                currentItem = m_items[i];
                if (MDbgUtil.IsRegex(currentItem.ExceptionType))
                {
                    // current entry in m_items is a regular expression
                    regex = MDbgUtil.ConvertSimpleExpToRegExp(currentItem.ExceptionType);
                    if (Regex.IsMatch(exceptionType, regex))
                    {
                        return(currentItem.Behavior);
                    }
                }
                else
                {
                    if (currentItem.ExceptionType == exceptionType)
                    {
                        return(currentItem.Behavior);
                    }
                }
            }

            return(m_default);
        }
        /// <summary>
        /// Acts on the current callback, based on the current debugger behavior for this stop
        /// option policy.
        /// </summary>
        /// <param name="currentProcess">Current MDbgProcess.</param>
        /// <param name="args">Callback arguments.</param>
        public override void ActOnCallback(MDbgProcess currentProcess, CustomPostCallbackEventArgs args)
        {
            var eventArgs = args.CallbackArgs as CorEventArgs;

            switch (m_behavior)
            {
            case DebuggerBehavior.Stop:
                args.Controller.Stop(eventArgs.Thread,
                                     MDbgUtil.CreateStopReasonFromEventArgs(eventArgs, currentProcess));
                break;

            case DebuggerBehavior.Log:
                CommandBase.WriteOutput(eventArgs + "\n");
                break;
            }
        }
        /// <summary>
        /// Modifies the exception settings, given an exception type and corresponding debugger behavior.
        /// </summary>
        /// <param name="behavior">stop, log, or ignore</param>
        /// <param name="arguments">A type of exception, or a regular expression.</param>
        public override void SetBehavior(DebuggerBehavior behavior, string arguments)
        {
            ExceptionStopOptionPolicyItem exceptionItem;
            string regex;
            int    existingItemIndex = -1;
            bool   redundantEntry    = false;
            bool   regexSubset       = false;

            if (arguments == null)
            {
                // If no exception types are specified, then all existing settings are cleared and the
                // behavior becomes the default behavior for all exceptions.
                m_items.Clear();
                m_default = behavior;
                if (behavior == DebuggerBehavior.Ignore)
                {
                    // To preserve legacy behavior, ignoring all exceptions also turns the exception
                    // enhanced switch off.
                    m_exceptionEnhancedOn = false;
                }
            }
            else
            {
                // The arguments string can contain multiple exception types and regular expressions,
                // so the arguments are split into a string array. For example, if the arguments string
                // is "System.Exception System.A*", it is split into {"System.Exception", "System.A*"}.
                // The behavior for all of these arguments is then set to the given behavior.
                string[] exceptionTypes = arguments.Split();
                string   exceptionType;
                foreach (string type in exceptionTypes)
                {
                    exceptionType = type.Trim();
                    if (MDbgUtil.IsRegex(exceptionType))
                    {
                        // Input is a regular expression. Go through the existing exception items
                        // and check if any of them match the input regular expression. If they do,
                        // remove them, because the input regular expression is added after them
                        // and has precedence. For example, if input is "System.*" and an exception
                        // item already exists for "System.Exception", we remove the System.Exception
                        // item.
                        for (int i = 0; i < m_items.Count; i++)
                        {
                            exceptionItem = m_items[i];
                            regex         = MDbgUtil.ConvertSimpleExpToRegExp(exceptionType);
                            if (Regex.IsMatch(exceptionItem.ExceptionType, regex))
                            {
                                m_items.Remove(exceptionItem);
                                i--;
                            }
                        }
                    }
                    else
                    {
                        // Input is not a regular expression. Check if m_items already contains
                        // an entry for this exception type.
                        foreach (ExceptionStopOptionPolicyItem item in m_items)
                        {
                            if (item.ExceptionType == type)
                            {
                                existingItemIndex = m_items.IndexOf(item);
                                break;
                            }
                        }
                    }

                    // Check if input is redundant. An input is redundant if it does not change the existing
                    // behavior. There are two cases in which an input is redundant:
                    //
                    // - An exception item already exists that is a regular expression accepting the
                    // input exception type, and specifying the same debugger behavior. For example,
                    // if a "log System.*" exception item already exists, an input of "log System.Exception"
                    // if redundant. However, an input of "ignore System.Exception" is NOT redundant,
                    // because it is added after the "log System.*" item and has precedence over it.
                    //
                    // - The input behavior is the same as the default behavior. For example, if the
                    // default behavior is ignore, an input of "ignore System.Exception" is redundant,
                    // UNLESS the input matches some existing exception item regular expression (as in
                    // the example above).

                    for (int i = m_items.Count - 1; i >= 0; i--)
                    {
                        exceptionItem = m_items[i];
                        if (m_items.IndexOf(exceptionItem) == existingItemIndex)
                        {
                            break;
                        }
                        if (MDbgUtil.IsRegex(exceptionItem.ExceptionType))
                        {
                            regex = MDbgUtil.ConvertSimpleExpToRegExp(exceptionItem.ExceptionType);
                            if (Regex.IsMatch(type, regex))
                            {
                                regexSubset = true;
                                if (behavior == exceptionItem.Behavior)
                                {
                                    redundantEntry = true;
                                }
                                break;
                            }
                        }
                    }
                    if (!regexSubset)
                    {
                        if (behavior == m_default)
                        {
                            redundantEntry = true;
                        }
                    }

                    // If the input modifies some existing exception item existing entry and the behavior
                    // is redundant, remove the existing item. If no matching item exists and the input
                    // is redundant, do nothing.
                    if (existingItemIndex != -1)
                    {
                        if (redundantEntry)
                        {
                            m_items.RemoveAt(existingItemIndex);
                        }
                        else
                        {
                            m_items[existingItemIndex].Behavior = behavior;
                        }
                    }
                    else
                    {
                        if (!redundantEntry)
                        {
                            m_items.Add(new ExceptionStopOptionPolicyItem(type, behavior));
                        }
                    }
                }
            }
        }