/********************************************************************++ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System; using System.Collections.Generic; using System.Threading; using Dbg=System.Management.Automation; #pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings #pragma warning disable 56500 namespace System.Management.Automation { /// /// Holds the state of a Monad Shell session /// internal sealed partial class SessionStateInternal { /// /// The current scope. It is either the global scope or /// a nested scope within the global scope. The current /// scope is implied or can be accessed using $local in /// the shell. /// private SessionStateScope currentScope; /// /// Given a scope identifier, returns the proper session state scope. /// /// /// /// A scope identifier that is either one of the "special" scopes like /// "global", "local", or "private, or a numeric ID of a relative scope /// to the current scope. /// /// /// /// The scope identified by the scope ID or the current scope if the /// scope ID is not defined as a special or numeric scope identifier. /// /// /// /// If is less than zero, or not /// a number and not "script", "global", "local", or "private" /// /// /// /// If is less than zero or greater than the number of currently /// active scopes. /// /// internal SessionStateScope GetScopeByID(string scopeID) { SessionStateScope result = currentScope; if (!string.IsNullOrEmpty(scopeID)) { if (String.Equals( scopeID, StringLiterals.Global, StringComparison.OrdinalIgnoreCase)) { result = _globalScope; } else if (String.Equals( scopeID, StringLiterals.Local, StringComparison.OrdinalIgnoreCase)) { result = currentScope; } else if (String.Equals( scopeID, StringLiterals.Private, StringComparison.OrdinalIgnoreCase)) { result = currentScope; } else if (String.Equals( scopeID, StringLiterals.Script, StringComparison.OrdinalIgnoreCase)) { // Get the current script scope from the stack. result = currentScope.ScriptScope; } else { // Since the scope is not any of the special scopes // try parsing it as an ID try { int scopeNumericID = Int32.Parse(scopeID, System.Globalization.CultureInfo.CurrentCulture); if (scopeNumericID < 0) { throw PSTraceSource.NewArgumentOutOfRangeException("scopeID", scopeID); } result = GetScopeByID(scopeNumericID) ?? currentScope; } catch (FormatException) { throw PSTraceSource.NewArgumentException("scopeID", AutomationExceptions.InvalidScopeIdArgument, "scopeID"); } catch (OverflowException) { throw PSTraceSource.NewArgumentOutOfRangeException("scopeID", scopeID); } } } return result; } // GetScopeByID /// /// Given a scope ID, walks the scope list to the appropriate scope and returns it. /// /// /// /// The numeric indexer to the scope relative to the current scope. /// /// /// /// The scope at the index specified. The index is relative to the current /// scope. /// /// /// /// If is less than zero or greater than the number of currently /// active scopes. /// /// internal SessionStateScope GetScopeByID(int scopeID) { SessionStateScope processingScope = currentScope; int originalID = scopeID; while (scopeID > 0 && processingScope != null) { processingScope = processingScope.Parent; scopeID--; } if (processingScope == null && scopeID >= 0) { ArgumentOutOfRangeException outOfRange = PSTraceSource.NewArgumentOutOfRangeException( "scopeID", originalID, SessionStateStrings.ScopeIDExceedsAvailableScopes, originalID); throw outOfRange; } return processingScope; } // GetScopeByID /// /// The global scope of session state. Can be accessed /// using $global in the shell. /// internal SessionStateScope GlobalScope { get { return _globalScope; } } private readonly SessionStateScope _globalScope; /// /// The module scope of a session state. This is only used internally /// by the engine. There is no module scope qualifier. /// internal SessionStateScope ModuleScope { get { return _moduleScope; } } private readonly SessionStateScope _moduleScope; /// /// Gets the session state current scope. /// internal SessionStateScope CurrentScope { get { return currentScope; } set { Diagnostics.Assert( value != null, "A null scope should never be set"); #if DEBUG // This code is ifdef'd for DEBUG because it may pose a significant // performance hit and is only really required to validate our internal // code. There is no way anyone outside the Monad codebase can cause // these error conditions to be hit. // Need to make sure the new scope is in the global scope lineage SessionStateScope scope = value; bool inGlobalScopeLineage = false; while (scope != null) { if (scope == _globalScope) { inGlobalScopeLineage = true; break; } scope = scope.Parent; } Diagnostics.Assert( inGlobalScopeLineage, "The scope specified to be set in CurrentScope is not in the global scope lineage. All scopes must originate from the global scope."); #endif currentScope = value; } } // CurrentScope /// /// Gets the session state current script scope. /// internal SessionStateScope ScriptScope { get { return currentScope.ScriptScope; } } /// /// Creates a new scope in the scope tree and assigns the parent /// and child scopes appropriately. /// /// /// /// If true, the new scope is pushed on to the script scope stack and /// can be referenced using $script: /// /// /// /// A new SessionStateScope which is a child of the current scope. /// /// internal SessionStateScope NewScope(bool isScriptScope) { Diagnostics.Assert( currentScope != null, "The currentScope should always be set."); // Create the new child scope. SessionStateScope newScope = new SessionStateScope(currentScope); if (isScriptScope) { newScope.ScriptScope = newScope; } return newScope; } // NewScope /// /// Removes the current scope from the scope tree and /// changes the current scope to the parent scope. /// /// /// /// The scope to cleanup and remove. /// /// /// /// The global scope cannot be removed. /// /// internal void RemoveScope(SessionStateScope scope) { Diagnostics.Assert( currentScope != null, "The currentScope should always be set."); if (scope == _globalScope) { SessionStateUnauthorizedAccessException e = new SessionStateUnauthorizedAccessException( StringLiterals.Global, SessionStateCategory.Scope, "GlobalScopeCannotRemove", SessionStateStrings.GlobalScopeCannotRemove); throw e; } // Give the provider a chance to cleanup the drive data associated // with drives in this scope foreach (PSDriveInfo drive in scope.Drives) { if (drive == null) { continue; } CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext); // Call CanRemoveDrive to give the provider a chance to cleanup // but ignore the return value and exceptions try { CanRemoveDrive(drive, context); } catch (LoopFlowException) { throw; } catch (PipelineStoppedException) { throw; } catch (ActionPreferenceStopException) { throw; } catch (Exception e) // Catch-all OK, 3rd party callout. { CommandProcessorBase.CheckForSevereException(e); // Ignore all exceptions from the provider as we are // going to force the removal anyway } } // foreach drive scope.RemoveAllDrives(); // If the scope being removed is the current scope, // then it must be removed from the tree. if (scope == currentScope && currentScope.Parent != null) { currentScope = currentScope.Parent; } scope.Parent = null; } // RemoveScope } // SessionStateInternal class } #pragma warning restore 56500