1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "includes_normalize.h"
#include "string_piece.h"
#include "util.h"
#include <algorithm>
#include <iterator>
#include <sstream>
#include <windows.h>
namespace {
/// Return true if paths a and b are on the same Windows drive.
bool SameDrive(StringPiece a, StringPiece b) {
char a_absolute[_MAX_PATH];
char b_absolute[_MAX_PATH];
GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL);
GetFullPathName(b.AsString().c_str(), sizeof(b_absolute), b_absolute, NULL);
char a_drive[_MAX_DIR];
char b_drive[_MAX_DIR];
_splitpath(a_absolute, a_drive, NULL, NULL, NULL);
_splitpath(b_absolute, b_drive, NULL, NULL, NULL);
return _stricmp(a_drive, b_drive) == 0;
}
} // anonymous namespace
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;
}
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;
}
string IncludesNormalize::ToLower(const string& s) {
string ret;
transform(s.begin(), s.end(), back_inserter(ret), ::tolower);
return ret;
}
string IncludesNormalize::AbsPath(StringPiece s) {
char result[_MAX_PATH];
GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL);
for (char* c = result; *c; ++c)
if (*c == '\\')
*c = '/';
return result;
}
string IncludesNormalize::Relativize(StringPiece path, const string& start) {
vector<string> start_list = Split(AbsPath(start), '/');
vector<string> path_list = Split(AbsPath(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]))
break;
}
vector<string> rel_list;
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, '/');
}
string IncludesNormalize::Normalize(const string& input,
const char* relative_to) {
char copy[_MAX_PATH];
size_t len = input.size();
strncpy(copy, input.c_str(), input.size() + 1);
string err;
if (!CanonicalizePath(copy, &len, &err))
Warning("couldn't canonicalize '%s': %s\n", input.c_str(), err.c_str());
StringPiece partially_fixed(copy, len);
string curdir;
if (!relative_to) {
curdir = AbsPath(".");
relative_to = curdir.c_str();
}
if (!SameDrive(partially_fixed, relative_to))
return partially_fixed.AsString();
return Relativize(partially_fixed, relative_to);
}
|