Ninja
|
00001 // Copyright 2012 Google Inc. All Rights Reserved. 00002 // 00003 // Licensed under the Apache License, Version 2.0 (the "License"); 00004 // you may not use this file except in compliance with the License. 00005 // You may obtain a copy of the License at 00006 // 00007 // http://www.apache.org/licenses/LICENSE-2.0 00008 // 00009 // Unless required by applicable law or agreed to in writing, software 00010 // distributed under the License is distributed on an "AS IS" BASIS, 00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00012 // See the License for the specific language governing permissions and 00013 // limitations under the License. 00014 00015 #include "includes_normalize.h" 00016 00017 #include "string_piece.h" 00018 #include "util.h" 00019 00020 #include <algorithm> 00021 #include <iterator> 00022 #include <sstream> 00023 00024 #include <windows.h> 00025 00026 namespace { 00027 00028 /// Return true if paths a and b are on the same Windows drive. 00029 bool SameDrive(StringPiece a, StringPiece b) { 00030 char a_absolute[_MAX_PATH]; 00031 char b_absolute[_MAX_PATH]; 00032 GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL); 00033 GetFullPathName(b.AsString().c_str(), sizeof(b_absolute), b_absolute, NULL); 00034 char a_drive[_MAX_DIR]; 00035 char b_drive[_MAX_DIR]; 00036 _splitpath(a_absolute, a_drive, NULL, NULL, NULL); 00037 _splitpath(b_absolute, b_drive, NULL, NULL, NULL); 00038 return _stricmp(a_drive, b_drive) == 0; 00039 } 00040 00041 } // anonymous namespace 00042 00043 string IncludesNormalize::Join(const vector<string>& list, char sep) { 00044 string ret; 00045 for (size_t i = 0; i < list.size(); ++i) { 00046 ret += list[i]; 00047 if (i != list.size() - 1) 00048 ret += sep; 00049 } 00050 return ret; 00051 } 00052 00053 vector<string> IncludesNormalize::Split(const string& input, char sep) { 00054 vector<string> elems; 00055 stringstream ss(input); 00056 string item; 00057 while (getline(ss, item, sep)) 00058 elems.push_back(item); 00059 return elems; 00060 } 00061 00062 string IncludesNormalize::ToLower(const string& s) { 00063 string ret; 00064 transform(s.begin(), s.end(), back_inserter(ret), ::tolower); 00065 return ret; 00066 } 00067 00068 string IncludesNormalize::AbsPath(StringPiece s) { 00069 char result[_MAX_PATH]; 00070 GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL); 00071 return result; 00072 } 00073 00074 string IncludesNormalize::Relativize(StringPiece path, const string& start) { 00075 vector<string> start_list = Split(AbsPath(start), '\\'); 00076 vector<string> path_list = Split(AbsPath(path), '\\'); 00077 int i; 00078 for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size())); 00079 ++i) { 00080 if (ToLower(start_list[i]) != ToLower(path_list[i])) 00081 break; 00082 } 00083 00084 vector<string> rel_list; 00085 for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j) 00086 rel_list.push_back(".."); 00087 for (int j = i; j < static_cast<int>(path_list.size()); ++j) 00088 rel_list.push_back(path_list[j]); 00089 if (rel_list.size() == 0) 00090 return "."; 00091 return Join(rel_list, '\\'); 00092 } 00093 00094 string IncludesNormalize::Normalize(const string& input, 00095 const char* relative_to) { 00096 char copy[_MAX_PATH]; 00097 size_t len = input.size(); 00098 strncpy(copy, input.c_str(), input.size() + 1); 00099 for (size_t j = 0; j < len; ++j) 00100 if (copy[j] == '/') 00101 copy[j] = '\\'; 00102 string err; 00103 if (!CanonicalizePath(copy, &len, &err)) { 00104 Warning("couldn't canonicalize '%s: %s\n", input.c_str(), err.c_str()); 00105 } 00106 string curdir; 00107 if (!relative_to) { 00108 curdir = AbsPath("."); 00109 relative_to = curdir.c_str(); 00110 } 00111 StringPiece partially_fixed(copy, len); 00112 if (!SameDrive(partially_fixed, relative_to)) 00113 return partially_fixed.AsString(); 00114 return Relativize(partially_fixed, relative_to); 00115 }