5 // Ankit Jain (jankit@novell.com)
7 // Copyright (c) 2009 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
34 using System.Runtime.InteropServices;
36 namespace Mono.XBuild.Utilities {
37 internal static class MSBuildUtils {
39 public readonly static bool RunningOnMac;
40 public readonly static bool RunningOnWindows;
41 static Hashtable charsToEscape;
43 static MSBuildUtils ()
45 RunningOnWindows = Path.DirectorySeparatorChar == '\\';
46 RunningOnMac = !RunningOnWindows && IsRunningOnMac ();
48 charsToEscape = new Hashtable ();
50 charsToEscape.Add ('$', null);
51 charsToEscape.Add ('%', null);
52 charsToEscape.Add ('\'', null);
53 charsToEscape.Add ('(', null);
54 charsToEscape.Add (')', null);
55 charsToEscape.Add ('*', null);
56 charsToEscape.Add (';', null);
57 charsToEscape.Add ('?', null);
58 charsToEscape.Add ('@', null);
61 public static string Escape (string unescapedExpression)
63 StringBuilder sb = new StringBuilder ();
65 foreach (char c in unescapedExpression) {
66 if (charsToEscape.Contains (c))
67 sb.AppendFormat ("%{0:x2}", (int) c);
72 return sb.ToString ();
75 // FIXME: add tests for this
76 internal static string Unescape (string escapedExpression)
78 StringBuilder sb = new StringBuilder ();
81 while (i < escapedExpression.Length) {
82 sb.Append (Uri.HexUnescape (escapedExpression, ref i));
85 return sb.ToString ();
88 internal static string UnescapeFromXml (string text)
90 StringBuilder sb = new StringBuilder ();
91 for (int i = 0; i < text.Length; i++) {
94 int end = text.IndexOf (';', i);
96 throw new FormatException ("Unterminated XML entity.");
97 string entity = text.Substring (i+1, end - i - 1);
115 throw new FormatException ("Unrecogised XML entity '&" + entity + ";'.");
121 return sb.ToString ();
125 static extern int uname (IntPtr buf);
127 //From Managed.Windows.Forms/XplatUI
128 static bool IsRunningOnMac ()
130 IntPtr buf = IntPtr.Zero;
132 buf = System.Runtime.InteropServices.Marshal.AllocHGlobal (8192);
133 // This is a hacktastic way of getting sysname from uname ()
134 if (uname (buf) == 0) {
135 string os = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (buf);
141 if (buf != IntPtr.Zero)
142 System.Runtime.InteropServices.Marshal.FreeHGlobal (buf);
147 internal static string FromMSBuildPath (string relPath)
149 string result = null;
150 FromMSBuildPath (String.Empty, relPath, out result);
154 internal static bool FromMSBuildPath (string basePath, string relPath, out string resultPath)
156 resultPath = relPath;
158 if (string.IsNullOrEmpty (relPath))
161 string path = relPath;
162 if (!RunningOnWindows)
163 path = path.Replace ("\\", "/");
165 path = Unescape (path);
167 if (char.IsLetter (path [0]) && path.Length > 1 && path[1] == ':') {
168 if (RunningOnWindows) {
169 resultPath = path; // Return the escaped value
175 if (basePath != null)
176 path = Path.Combine (basePath, path);
178 if (System.IO.File.Exists (path) || System.IO.Directory.Exists (path)){
179 resultPath = Path.GetFullPath (path);
183 if (Path.IsPathRooted (path) && !RunningOnWindows) {
185 // Windows paths are case-insensitive. When mapping an absolute path
186 // we can try to find the correct case for the path.
188 string[] names = path.Substring (1).Split ('/');
191 for (int n=0; n<names.Length; n++) {
194 if (names [n] == ".."){
196 return false; // Can go further back. It's not an existing file
197 part = Path.GetFullPath (part + "/..");
201 entries = Directory.GetFileSystemEntries (part);
204 foreach (string e in entries) {
205 if (string.Compare (Path.GetFileName (e), names[n], true) == 0) {
211 // Part of the path does not exist. Can't do any more checking.
212 part = Path.GetFullPath (part);
213 for (; n < names.Length; n++)
214 part += "/" + names[n];
221 resultPath = Path.GetFullPath (part);
223 resultPath = Path.GetFullPath (path);