private static IEnumerable <string> /*!*/ GetAbsolutePaths(PlatformAdaptationLayer /*!*/ pal, string /*!*/ path) { if (pal.IsAbsolutePath(path)) { yield return(path); } else { yield return(pal.GetFullPath(path)); string var = pal.GetEnvironmentVariable("PATH"); if (!String.IsNullOrEmpty(var)) { foreach (var prefix in var.Split(Path.PathSeparator)) { if (prefix.Length > 0) { yield return(Path.Combine(prefix, path)); } } } var = Environment.GetFolderPath(Environment.SpecialFolder.System); if (!String.IsNullOrEmpty(var)) { yield return(Path.Combine(var, path)); } var = pal.GetEnvironmentVariable("SystemRoot"); if (!String.IsNullOrEmpty(var)) { yield return(Path.Combine(var, path)); } } }
// Expand directory path - these cases exist: // // 1. Empty string or nil means return current directory // 2. ~ with non-existent HOME directory throws exception // 3. ~, ~/ or ~\ which expands to HOME // 4. ~foo is left unexpanded // 5. Expand to full path if path is a relative path // // No attempt is made to determine whether the path is valid or not // Returned path is always canonicalized to forward slashes private static MutableString /*!*/ ExpandPath(RubyContext /*!*/ context, MutableString /*!*/ path) { PlatformAdaptationLayer pal = context.DomainManager.Platform; int length = path.Length; try { if (path == null || length == 0) { return(Glob.CanonicalizePath(MutableString.Create(Directory.GetCurrentDirectory()))); } if (length == 1 && path.GetChar(0) == '~') { return(Glob.CanonicalizePath(MutableString.Create(Path.GetFullPath(pal.GetEnvironmentVariable("HOME"))))); } if (path.GetChar(0) == '~' && (path.GetChar(1) == Path.DirectorySeparatorChar || path.GetChar(1) == Path.AltDirectorySeparatorChar)) { string homeDirectory = pal.GetEnvironmentVariable("HOME"); return(Glob.CanonicalizePath(length < 3 ? MutableString.Create(homeDirectory) : MutableString.Create(Path.Combine(homeDirectory, path.GetSlice(2).ConvertToString())))); } else { return(Glob.CanonicalizePath(MutableString.Create(Path.GetFullPath(path.ConvertToString())))); } } catch (Exception e) { // Re-throw exception as a reasonable Ruby exception throw new Errno.InvalidError(path.ConvertToString(), e); } }
public static MutableString GetVariable(RubyContext /*!*/ context, object /*!*/ self, [DefaultProtocol, NotNull] MutableString /*!*/ name) { PlatformAdaptationLayer pal = context.DomainManager.Platform; string value = pal.GetEnvironmentVariable(name.ConvertToString()); return((value != null) ? FrozenString(context, value) : null); }
// Algorithm to find HOME equivalents under Windows. This is equivalent to Ruby 1.9 behavior: // // 1. Try get HOME // 2. Try to generate HOME equivalent using HOMEDRIVE + HOMEPATH // 3. Try to generate HOME equivalent from USERPROFILE // 4. Try to generate HOME equivalent from Personal special folder internal static string /*!*/ GetHomeDirectory(RubyContext /*!*/ context) { PlatformAdaptationLayer pal = context.DomainManager.Platform; string result = pal.GetEnvironmentVariable("HOME"); if (result == null) { string homeDrive = pal.GetEnvironmentVariable("HOMEDRIVE"); string homePath = pal.GetEnvironmentVariable("HOMEPATH"); if (homeDrive == null && homePath == null) { string userEnvironment = pal.GetEnvironmentVariable("USERPROFILE"); if (userEnvironment == null) { // This will always succeed with a non-null string, but it can fail // if the Personal folder was renamed or deleted. In this case it returns // an empty string. result = Environment.GetFolderPath(Environment.SpecialFolder.Personal); } else { result = userEnvironment; } } else if (homeDrive == null) { result = homePath; } else if (homePath == null) { result = homeDrive; } else { result = Path.Combine(homeDrive, homePath); } } return(result); }
private static void GetExecutable(PlatformAdaptationLayer /*!*/ pal, string /*!*/ command, out string executable, out string arguments) { command = command.Trim(' '); if (command.Length == 0) { throw RubyExceptions.CreateEINVAL(command); } // This seems to be quite complicated: // 1) If the first part of the command is a shell command (DIR, ECHO, ...) or // if the command contains unquoted <, > or | then // it uses ENV['COMSPEC'] to execute the command: %COMSPEC% /c "COMMAND" // 2) It looks for the shortest prefix of command that is separated by space from the rest of the command that is either // a) An absolute path to an executable file. // b) Try prepend paths from ENV['PATH'] // c) Try Environment.SpecialFolder.System. // d) Try SHGetFolderPath(CSIDL_WINDOWS) - we can't get this from Environment.SpecialFolder, so we need to use // ENV["SystemRoot"] environment variable. // In each step it tries to append ".exe" or ".com" extension if the path doesn't exist. // // For example, if the command is `x/a b/x` and the directory structure is // x\a b\x.exe // x\a.exe // it executes a.exe. // // MRI probably calls CreateProcess Win32 API with lpApplicationName it resolves as described above and // lpCommandLine == command. System.Diagnostics.Process also uses this API with lpApplicationName == NULL and // lpCommandLine == '"{ProcessStartInfo.FileName}" {ProcessStartInfo.Arguments}'. // // Although CreateProcess does all the searching for an executable if passed no lpApplicationName, // we need to do it ourselves because it is slightly different in MRI (is that a bug?) and also because System.Diagnostics.Process // quotes the FileName :( // string comspec = pal.GetEnvironmentVariable("COMSPEC"); if (!pal.FileExists(comspec)) { comspec = null; } if (comspec != null && IndexOfUnquotedSpecialCharacter(command) >= 0) { executable = comspec; arguments = "/c \"" + command + "\""; return; } int start = 0; while (true) { int next = command.IndexOf(' ', start); executable = (next >= 0) ? command.Substring(0, next) : command; arguments = (next >= 0) ? command.Substring(next + 1) : ""; if (start == 0 && comspec != null && IsShellCommand(executable)) { executable = comspec; arguments = "/c \"" + command + "\""; return; } try { foreach (var path in GetExecutableFiles(pal, executable)) { if (pal.FileExists(path)) { // We need to set the path we found as executable. Althought makes command line of the target process // different from when called by MRI it will execute the right process. If we passed the original executable name // CreateProcess might resolve it to a different executable. executable = path; return; } } } catch (Exception e) { if (next < 0) { throw RubyExceptions.CreateENOENT(command, e); } } if (next < 0) { throw RubyExceptions.CreateENOENT(command); } start = next + 1; while (start < command.Length && command[start] == ' ') { start++; } } }
public static bool HasKey(RubyContext /*!*/ context, object /*!*/ self, [DefaultProtocol, NotNull] MutableString /*!*/ key) { PlatformAdaptationLayer pal = context.DomainManager.Platform; return(pal.GetEnvironmentVariable(key.ConvertToString()) != null); }