summaryrefslogtreecommitdiff
path: root/src/includes_normalize-win32.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/includes_normalize-win32.cc')
-rw-r--r--src/includes_normalize-win32.cc128
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;
}