Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / includes_normalize-win32.cc
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include "includes_normalize.h"
16
17 #include "string_piece.h"
18 #include "util.h"
19
20 #include <algorithm>
21 #include <iterator>
22 #include <sstream>
23
24 #include <windows.h>
25
26 namespace {
27
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;
39 }
40
41 }  // anonymous namespace
42
43 string IncludesNormalize::Join(const vector<string>& list, char sep) {
44   string ret;
45   for (size_t i = 0; i < list.size(); ++i) {
46     ret += list[i];
47     if (i != list.size() - 1)
48       ret += sep;
49   }
50   return ret;
51 }
52
53 vector<string> IncludesNormalize::Split(const string& input, char sep) {
54   vector<string> elems;
55   stringstream ss(input);
56   string item;
57   while (getline(ss, item, sep))
58     elems.push_back(item);
59   return elems;
60 }
61
62 string IncludesNormalize::ToLower(const string& s) {
63   string ret;
64   transform(s.begin(), s.end(), back_inserter(ret), ::tolower);
65   return ret;
66 }
67
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)
72     if (*c == '\\')
73       *c = '/';
74   return result;
75 }
76
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), '/');
80   int i;
81   for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size()));
82        ++i) {
83     if (ToLower(start_list[i]) != ToLower(path_list[i]))
84       break;
85   }
86
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)
93     return ".";
94   return Join(rel_list, '/');
95 }
96
97 bool IncludesNormalize::Normalize(const string& input, const char* relative_to,
98                                   string* result, string* err) {
99   char copy[_MAX_PATH + 1];
100   size_t len = input.size();
101   if (len > _MAX_PATH) {
102     *err = "path too long";
103     return false;
104   }
105   strncpy(copy, input.c_str(), input.size() + 1);
106   unsigned int slash_bits;
107   if (!CanonicalizePath(copy, &len, &slash_bits, err))
108     return false;
109   StringPiece partially_fixed(copy, len);
110
111   string curdir;
112   if (!relative_to) {
113     curdir = AbsPath(".");
114     relative_to = curdir.c_str();
115   }
116   if (!SameDrive(partially_fixed, relative_to)) {
117     *result = partially_fixed.AsString();
118     return true;
119   }
120   *result = Relativize(partially_fixed, relative_to);
121   return true;
122 }