1 // Copyright 2012 Google Inc. All Rights Reserved.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "includes_normalize.h"
17 #include "string_piece.h"
28 /// Return true if paths a and b are on the same Windows drive.
29 bool SameDrive(StringPiece a, StringPiece b) {
30 char a_absolute[_MAX_PATH];
31 char b_absolute[_MAX_PATH];
32 GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL);
33 GetFullPathName(b.AsString().c_str(), sizeof(b_absolute), b_absolute, NULL);
34 char a_drive[_MAX_DIR];
35 char b_drive[_MAX_DIR];
36 _splitpath(a_absolute, a_drive, NULL, NULL, NULL);
37 _splitpath(b_absolute, b_drive, NULL, NULL, NULL);
38 return _stricmp(a_drive, b_drive) == 0;
41 } // anonymous namespace
43 string IncludesNormalize::Join(const vector<string>& list, char sep) {
45 for (size_t i = 0; i < list.size(); ++i) {
47 if (i != list.size() - 1)
53 vector<string> IncludesNormalize::Split(const string& input, char sep) {
55 stringstream ss(input);
57 while (getline(ss, item, sep))
58 elems.push_back(item);
62 string IncludesNormalize::ToLower(const string& s) {
64 transform(s.begin(), s.end(), back_inserter(ret), ::tolower);
68 string IncludesNormalize::AbsPath(StringPiece s) {
69 char result[_MAX_PATH];
70 GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL);
71 for (char* c = result; *c; ++c)
77 string IncludesNormalize::Relativize(StringPiece path, const string& start) {
78 vector<string> start_list = Split(AbsPath(start), '/');
79 vector<string> path_list = Split(AbsPath(path), '/');
81 for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size()));
83 if (ToLower(start_list[i]) != ToLower(path_list[i]))
87 vector<string> rel_list;
88 for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j)
89 rel_list.push_back("..");
90 for (int j = i; j < static_cast<int>(path_list.size()); ++j)
91 rel_list.push_back(path_list[j]);
92 if (rel_list.size() == 0)
94 return Join(rel_list, '/');
97 string IncludesNormalize::Normalize(const string& input,
98 const char* relative_to) {
99 char copy[_MAX_PATH + 1];
100 size_t len = input.size();
101 if (len > _MAX_PATH) {
102 Warning("path too long '%s'\n", input.c_str());
105 strncpy(copy, input.c_str(), input.size() + 1);
107 unsigned int slash_bits;
108 if (!CanonicalizePath(copy, &len, &slash_bits, &err))
109 Warning("couldn't canonicalize '%s': %s\n", input.c_str(), err.c_str());
110 StringPiece partially_fixed(copy, len);
114 curdir = AbsPath(".");
115 relative_to = curdir.c_str();
117 if (!SameDrive(partially_fixed, relative_to))
118 return partially_fixed.AsString();
119 return Relativize(partially_fixed, relative_to);