diff options
author | Nico Weber <nicolasweber@gmx.de> | 2017-09-04 02:15:13 (GMT) |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2017-09-04 02:15:13 (GMT) |
commit | 0c671527322d15016bb9ff5c3cf436f68e6ddbde (patch) | |
tree | cf9625c31e7ad023606c3881c6c759c8572c45c9 /src/includes_normalize-win32.cc | |
parent | 256bf897b85e35bc90294090ad39b5214eb141fb (diff) | |
parent | b98941a605d3cc47966d8407ace6e454d781af9b (diff) | |
download | Ninja-0c671527322d15016bb9ff5c3cf436f68e6ddbde.zip Ninja-0c671527322d15016bb9ff5c3cf436f68e6ddbde.tar.gz Ninja-0c671527322d15016bb9ff5c3cf436f68e6ddbde.tar.bz2 |
v1.8.0v1.8.0
Diffstat (limited to 'src/includes_normalize-win32.cc')
-rw-r--r-- | src/includes_normalize-win32.cc | 128 |
1 files changed, 91 insertions, 37 deletions
diff --git a/src/includes_normalize-win32.cc b/src/includes_normalize-win32.cc index ca35012..459329b 100644 --- a/src/includes_normalize-win32.cc +++ b/src/includes_normalize-win32.cc @@ -15,6 +15,7 @@ #include "includes_normalize.h" #include "string_piece.h" +#include "string_piece_util.h" #include "util.h" #include <algorithm> @@ -25,8 +26,39 @@ namespace { -/// Return true if paths a and b are on the same Windows drive. +bool IsPathSeparator(char c) { + return c == '/' || c == '\\'; +} + +// Return true if paths a and b are on the same windows drive. +// Return false if this funcation cannot check +// whether or not on the same windows drive. +bool SameDriveFast(StringPiece a, StringPiece b) { + if (a.size() < 3 || b.size() < 3) { + return false; + } + + if (!islatinalpha(a[0]) || !islatinalpha(b[0])) { + return false; + } + + if (ToLowerASCII(a[0]) != ToLowerASCII(b[0])) { + return false; + } + + if (a[1] != ':' || b[1] != ':') { + return false; + } + + return IsPathSeparator(a[2]) && IsPathSeparator(b[2]); +} + +// Return true if paths a and b are on the same Windows drive. bool SameDrive(StringPiece a, StringPiece b) { + if (SameDriveFast(a, b)) { + return true; + } + char a_absolute[_MAX_PATH]; char b_absolute[_MAX_PATH]; GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL); @@ -38,34 +70,57 @@ bool SameDrive(StringPiece a, StringPiece b) { return _stricmp(a_drive, b_drive) == 0; } -} // anonymous namespace +// Check path |s| is FullPath style returned by GetFullPathName. +// This ignores difference of path separator. +// This is used not to call very slow GetFullPathName API. +bool IsFullPathName(StringPiece s) { + if (s.size() < 3 || + !islatinalpha(s[0]) || + s[1] != ':' || + !IsPathSeparator(s[2])) { + return false; + } + + // Check "." or ".." is contained in path. + for (size_t i = 2; i < s.size(); ++i) { + if (!IsPathSeparator(s[i])) { + continue; + } + + // Check ".". + if (i + 1 < s.size() && s[i+1] == '.' && + (i + 2 >= s.size() || IsPathSeparator(s[i+2]))) { + return false; + } -string IncludesNormalize::Join(const vector<string>& list, char sep) { - string ret; - for (size_t i = 0; i < list.size(); ++i) { - ret += list[i]; - if (i != list.size() - 1) - ret += sep; + // Check "..". + if (i + 2 < s.size() && s[i+1] == '.' && s[i+2] == '.' && + (i + 3 >= s.size() || IsPathSeparator(s[i+3]))) { + return false; + } } - return ret; -} -vector<string> IncludesNormalize::Split(const string& input, char sep) { - vector<string> elems; - stringstream ss(input); - string item; - while (getline(ss, item, sep)) - elems.push_back(item); - return elems; + return true; } -string IncludesNormalize::ToLower(const string& s) { - string ret; - transform(s.begin(), s.end(), back_inserter(ret), ::tolower); - return ret; +} // anonymous namespace + +IncludesNormalize::IncludesNormalize(const string& relative_to) { + relative_to_ = AbsPath(relative_to); + split_relative_to_ = SplitStringPiece(relative_to_, '/'); } string IncludesNormalize::AbsPath(StringPiece s) { + if (IsFullPathName(s)) { + string result = s.AsString(); + for (size_t i = 0; i < result.size(); ++i) { + if (result[i] == '\\') { + result[i] = '/'; + } + } + return result; + } + char result[_MAX_PATH]; GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL); for (char* c = result; *c; ++c) @@ -74,28 +129,31 @@ string IncludesNormalize::AbsPath(StringPiece s) { return result; } -string IncludesNormalize::Relativize(StringPiece path, const string& start) { - vector<string> start_list = Split(AbsPath(start), '/'); - vector<string> path_list = Split(AbsPath(path), '/'); +string IncludesNormalize::Relativize( + StringPiece path, const vector<StringPiece>& start_list) { + string abs_path = AbsPath(path); + vector<StringPiece> path_list = SplitStringPiece(abs_path, '/'); int i; for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size())); ++i) { - if (ToLower(start_list[i]) != ToLower(path_list[i])) + if (!EqualsCaseInsensitiveASCII(start_list[i], path_list[i])) { break; + } } - vector<string> rel_list; + vector<StringPiece> rel_list; + rel_list.reserve(start_list.size() - i + path_list.size() - i); for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j) rel_list.push_back(".."); for (int j = i; j < static_cast<int>(path_list.size()); ++j) rel_list.push_back(path_list[j]); if (rel_list.size() == 0) return "."; - return Join(rel_list, '/'); + return JoinStringPiece(rel_list, '/'); } -bool IncludesNormalize::Normalize(const string& input, const char* relative_to, - string* result, string* err) { +bool IncludesNormalize::Normalize(const string& input, + string* result, string* err) const { char copy[_MAX_PATH + 1]; size_t len = input.size(); if (len > _MAX_PATH) { @@ -103,20 +161,16 @@ bool IncludesNormalize::Normalize(const string& input, const char* relative_to, return false; } strncpy(copy, input.c_str(), input.size() + 1); - unsigned int slash_bits; + uint64_t slash_bits; if (!CanonicalizePath(copy, &len, &slash_bits, err)) return false; StringPiece partially_fixed(copy, len); + string abs_input = AbsPath(partially_fixed); - string curdir; - if (!relative_to) { - curdir = AbsPath("."); - relative_to = curdir.c_str(); - } - if (!SameDrive(partially_fixed, relative_to)) { + if (!SameDrive(abs_input, relative_to_)) { *result = partially_fixed.AsString(); return true; } - *result = Relativize(partially_fixed, relative_to); + *result = Relativize(abs_input, split_relative_to_); return true; } |