MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Diagnostics;5using System.Diagnostics.CodeAnalysis;6 7namespace System.Management.Automation8{9 [Flags]10 internal enum VariablePathFlags11 {12 None = 0x00,13 Local = 0x01,14 Script = 0x02,15 Global = 0x04,16 Private = 0x08,17 Variable = 0x10,18 Function = 0x20,19 DriveQualified = 0x40,20 Unqualified = 0x80,21 22 // If any of these bits are set, the path does not represent an unscoped variable.23 UnscopedVariableMask = Local | Script | Global | Private | Function | DriveQualified,24 }25 26 /// <summary>27 /// A variable path that you can query the scope and drive of the variable reference.28 /// </summary>29 public class VariablePath30 {31 #region private data32 33 /// <summary>34 /// Stores the path that was passed to the constructor.35 /// </summary>36 private string _userPath;37 38 /// <summary>39 /// The name of the variable without any scope or drive.40 /// </summary>41 private string _unqualifiedPath;42 43 /// <summary>44 /// Store flags about the path, such as private/global/local/etc.45 /// </summary>46 private VariablePathFlags _flags = VariablePathFlags.None;47 48 #endregion private data49 50 #region Constructor51 52 /// <summary>53 /// Private constructor for CloneAndSetLocal().54 /// </summary>55 private VariablePath()56 {57 }58 59 /// <summary>60 /// Constructs a variable path.61 /// </summary>62 /// <param name="path">The path to parse.</param>63 /// <exception cref="ArgumentNullException">64 /// If <paramref name="path"/> is null.65 /// </exception>66 public VariablePath(string path)67 : this(path, VariablePathFlags.None)68 {69 }70 71 /// <summary>72 /// Constructs a scoped item lookup path.73 /// </summary>74 /// <param name="path">The path to parse.</param>75 /// <param name="knownFlags">76 /// These flags for anything known about the path (such as, is it a function) before77 /// being scanned.78 /// </param>79 /// <exception cref="ArgumentNullException">80 /// If <paramref name="path"/> is null.81 /// </exception>82 internal VariablePath(string path, VariablePathFlags knownFlags)83 {84 if (string.IsNullOrEmpty(path))85 {86 throw PSTraceSource.NewArgumentException(nameof(path));87 }88 89 _userPath = path;90 _flags = knownFlags;91 92 string candidateScope = null;93 string candidateScopeUpper = null;94 VariablePathFlags candidateFlags = VariablePathFlags.Unqualified;95 96 int currentCharIndex = 0;97 int lastScannedColon = -1;98 99 scanScope:100 switch (path[0])101 {102 case 'g':103 case 'G':104 candidateScope = "lobal";105 candidateScopeUpper = "LOBAL";106 candidateFlags = VariablePathFlags.Global;107 break;108 case 'l':109 case 'L':110 candidateScope = "ocal";111 candidateScopeUpper = "OCAL";112 candidateFlags = VariablePathFlags.Local;113 break;114 case 'p':115 case 'P':116 candidateScope = "rivate";117 candidateScopeUpper = "RIVATE";118 candidateFlags = VariablePathFlags.Private;119 break;120 case 's':121 case 'S':122 candidateScope = "cript";123 candidateScopeUpper = "CRIPT";124 candidateFlags = VariablePathFlags.Script;125 break;126 case 'v':127 case 'V':128 if (knownFlags == VariablePathFlags.None)129 {130 // If we see 'variable:', our namespaceId will be empty, and131 // we'll also need to scan for the scope again.132 candidateScope = "ariable";133 candidateScopeUpper = "ARIABLE";134 candidateFlags = VariablePathFlags.Variable;135 }136 137 break;138 }139 140 if (candidateScope != null)141 {142 currentCharIndex += 1; // First character already matched.143 int j;144 for (j = 0; currentCharIndex < path.Length && j < candidateScope.Length; ++j, ++currentCharIndex)145 {146 if (path[currentCharIndex] != candidateScope[j] && path[currentCharIndex] != candidateScopeUpper[j])147 {148 break;149 }150 }151 152 if (j == candidateScope.Length &&153 currentCharIndex < path.Length &&154 path[currentCharIndex] == ':')155 {156 if (_flags == VariablePathFlags.None)157 {158 _flags = VariablePathFlags.Variable;159 }160 161 _flags |= candidateFlags;162 lastScannedColon = currentCharIndex;163 currentCharIndex += 1;164 165 // If saw 'variable:', we need to look for a scope after 'variable:'.166 if (candidateFlags == VariablePathFlags.Variable)167 {168 knownFlags = VariablePathFlags.Variable;169 candidateScope = candidateScopeUpper = null;170 candidateFlags = VariablePathFlags.None;171 goto scanScope;172 }173 }174 }175 176 if (_flags == VariablePathFlags.None)177 {178 lastScannedColon = path.IndexOf(':', currentCharIndex);179 // No colon, or a colon as the first character means we have180 // a simple variable, otherwise it's a drive.181 if (lastScannedColon > 0)182 {183 _flags = VariablePathFlags.DriveQualified;184 }185 }186 187 if (lastScannedColon == -1)188 {189 _unqualifiedPath = _userPath;190 }191 else192 {193 _unqualifiedPath = _userPath.Substring(lastScannedColon + 1);194 }195 196 if (_flags == VariablePathFlags.None)197 {198 _flags = VariablePathFlags.Unqualified | VariablePathFlags.Variable;199 }200 }201 202 internal VariablePath CloneAndSetLocal()203 {204 Debug.Assert(IsUnscopedVariable, "Special method to clone, input must be unqualified");205 206 VariablePath result = new VariablePath();207 result._userPath = _userPath;208 result._unqualifiedPath = _unqualifiedPath;209 result._flags = VariablePathFlags.Local | VariablePathFlags.Variable;210 return result;211 }212 213 #endregion Constructor214 215 #region data accessors216 217 /// <summary>218 /// Gets the full path including any possibly specified scope and/or drive name.219 /// </summary>220 public string UserPath { get { return _userPath; } }221 222 /// <summary>223 /// Returns true if the path explicitly specifies 'global:'.224 /// </summary>225 public bool IsGlobal { get { return (_flags & VariablePathFlags.Global) != 0; } }226 227 /// <summary>228 /// Returns true if the path explicitly specifies 'local:'.229 /// </summary>230 public bool IsLocal { get { return (_flags & VariablePathFlags.Local) != 0; } }231 232 /// <summary>233 /// Returns true if the path explicitly specifies 'private:'.234 /// </summary>235 public bool IsPrivate { get { return (_flags & VariablePathFlags.Private) != 0; } }236 237 /// <summary>238 /// Returns true if the path explicitly specifies 'script:'.239 /// </summary>240 public bool IsScript { get { return (_flags & VariablePathFlags.Script) != 0; } }241 242 /// <summary>243 /// Returns true if the path specifies no drive or scope qualifiers.244 /// </summary>245 public bool IsUnqualified { get { return (_flags & VariablePathFlags.Unqualified) != 0; } }246 247 /// <summary>248 /// Returns true if the path specifies a variable path with no scope qualifiers.249 /// </summary>250 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unscoped")]251 public bool IsUnscopedVariable { get { return ((_flags & VariablePathFlags.UnscopedVariableMask) == 0); } }252 253 /// <summary>254 /// Returns true if the path defines a variable.255 /// </summary>256 public bool IsVariable { get { return (_flags & VariablePathFlags.Variable) != 0; } }257 258 /// <summary>259 /// Returns true if the path defines a function.260 /// </summary>261 internal bool IsFunction { get { return (_flags & VariablePathFlags.Function) != 0; } }262 263 /// <summary>264 /// Returns true if the path specifies a drive other than the variable drive.265 /// </summary>266 public bool IsDriveQualified { get { return (_flags & VariablePathFlags.DriveQualified) != 0; } }267 268 /// <summary>269 /// The drive name, or null if the path is for a variable.270 /// It may also be null for some functions (specifically if this is a FunctionScopedItemLookupPath.)271 /// </summary>272 public string DriveName273 {274 get275 {276 if (!IsDriveQualified)277 {278 return null;279 }280 281 // The drive name is asked for infrequently. Lots of VariablePath282 // objects are created, so rather than allocate an extra string that will283 // always be null, just compute the drive name on demand.284 return _userPath.Substring(0, _userPath.IndexOf(':'));285 }286 }287 288 /// <summary>289 /// Gets the namespace specific string.290 /// </summary>291 internal string UnqualifiedPath292 {293 get { return _unqualifiedPath; }294 }295 296 /// <summary>297 /// Return the drive qualified name, if any drive specified, otherwise the simple variable name.298 /// </summary>299 internal string QualifiedName300 {301 get { return IsDriveQualified ? _userPath : _unqualifiedPath; }302 }303 304 #endregion data accessors305 306 /// <summary>307 /// Helpful for debugging.308 /// </summary>309 public override string ToString()310 {311 return _userPath;312 }313 }314 315 internal class FunctionLookupPath : VariablePath316 {317 internal FunctionLookupPath(string path)318 : base(path, VariablePathFlags.Function | VariablePathFlags.Unqualified)319 {320 }321 }322}323 