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.
29 using System.Collections;
32 using System.Runtime.InteropServices;
34 namespace Mono.XBuild.Utilities {
35 internal static class MSBuildUtils {
37 public readonly static bool RunningOnMac;
38 public readonly static bool RunningOnWindows;
39 static Hashtable charsToEscape;
41 static MSBuildUtils ()
43 RunningOnWindows = Path.DirectorySeparatorChar == '\\';
44 RunningOnMac = !RunningOnWindows && IsRunningOnMac ();
46 charsToEscape = new Hashtable ();
48 charsToEscape.Add ('$', null);
49 charsToEscape.Add ('%', null);
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);
59 public static string Escape (string unescapedExpression)
61 StringBuilder sb = new StringBuilder ();
63 foreach (char c in unescapedExpression) {
64 if (charsToEscape.Contains (c))
65 sb.AppendFormat ("%{0:x2}", (int) c);
70 return sb.ToString ();
73 // FIXME: add tests for this
74 internal static string Unescape (string escapedExpression)
76 StringBuilder sb = new StringBuilder ();
79 while (i < escapedExpression.Length) {
80 sb.Append (Uri.HexUnescape (escapedExpression, ref i));
83 return sb.ToString ();
86 internal static string UnescapeFromXml (string text)
88 StringBuilder sb = new StringBuilder ();
89 for (int i = 0; i < text.Length; i++) {
92 int end = text.IndexOf (';', i);
94 throw new FormatException ("Unterminated XML entity.");
95 string entity = text.Substring (i+1, end - i - 1);
113 throw new FormatException ("Unrecognized XML entity '&" + entity + ";'.");
119 return sb.ToString ();
123 static extern int uname (IntPtr buf);
125 //From Managed.Windows.Forms/XplatUI
126 static bool IsRunningOnMac ()
128 IntPtr buf = IntPtr.Zero;
130 buf = System.Runtime.InteropServices.Marshal.AllocHGlobal (8192);
131 // This is a hacktastic way of getting sysname from uname ()
132 if (uname (buf) == 0) {
133 string os = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (buf);
139 if (buf != IntPtr.Zero)
140 System.Runtime.InteropServices.Marshal.FreeHGlobal (buf);
145 internal static string FromMSBuildPath (string relPath)
147 string result = null;
148 FromMSBuildPath (String.Empty, relPath, out result);
152 internal static bool FromMSBuildPath (string basePath, string relPath, out string resultPath)
154 resultPath = relPath;
156 if (string.IsNullOrEmpty (relPath))
159 string path = relPath;
160 if (!RunningOnWindows)
161 path = path.Replace ("\\", "/");
163 path = Unescape (path);
165 if (char.IsLetter (path [0]) && path.Length > 1 && path[1] == ':') {
166 if (RunningOnWindows) {
167 resultPath = path; // Return the escaped value
173 if (basePath != null)
174 path = Path.Combine (basePath, path);
176 if (System.IO.File.Exists (path) || System.IO.Directory.Exists (path)){
177 resultPath = Path.GetFullPath (path);
181 if (Path.IsPathRooted (path) && !RunningOnWindows) {
183 // Windows paths are case-insensitive. When mapping an absolute path
184 // we can try to find the correct case for the path.
186 string[] names = path.Substring (1).Split ('/');
189 for (int n=0; n<names.Length; n++) {
192 if (names [n] == ".."){
194 return false; // Can go further back. It's not an existing file
195 part = Path.GetFullPath (part + "/..");
199 entries = Directory.GetFileSystemEntries (part);
202 foreach (string e in entries) {
203 if (string.Compare (Path.GetFileName (e), names[n], true) == 0) {
209 // Part of the path does not exist. Can't do any more checking.
210 part = Path.GetFullPath (part);
211 for (; n < names.Length; n++)
212 part += "/" + names[n];
219 resultPath = Path.GetFullPath (part);
221 resultPath = Path.GetFullPath (path);