Ninja
includes_normalize-win32.cc
Go to the documentation of this file.
00001 // Copyright 2012 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "includes_normalize.h"
00016 
00017 #include "string_piece.h"
00018 #include "util.h"
00019 
00020 #include <algorithm>
00021 #include <iterator>
00022 #include <sstream>
00023 
00024 #include <windows.h>
00025 
00026 namespace {
00027 
00028 /// Return true if paths a and b are on the same Windows drive.
00029 bool SameDrive(StringPiece a, StringPiece b)  {
00030   char a_absolute[_MAX_PATH];
00031   char b_absolute[_MAX_PATH];
00032   GetFullPathName(a.AsString().c_str(), sizeof(a_absolute), a_absolute, NULL);
00033   GetFullPathName(b.AsString().c_str(), sizeof(b_absolute), b_absolute, NULL);
00034   char a_drive[_MAX_DIR];
00035   char b_drive[_MAX_DIR];
00036   _splitpath(a_absolute, a_drive, NULL, NULL, NULL);
00037   _splitpath(b_absolute, b_drive, NULL, NULL, NULL);
00038   return _stricmp(a_drive, b_drive) == 0;
00039 }
00040 
00041 }  // anonymous namespace
00042 
00043 string IncludesNormalize::Join(const vector<string>& list, char sep) {
00044   string ret;
00045   for (size_t i = 0; i < list.size(); ++i) {
00046     ret += list[i];
00047     if (i != list.size() - 1)
00048       ret += sep;
00049   }
00050   return ret;
00051 }
00052 
00053 vector<string> IncludesNormalize::Split(const string& input, char sep) {
00054   vector<string> elems;
00055   stringstream ss(input);
00056   string item;
00057   while (getline(ss, item, sep))
00058     elems.push_back(item);
00059   return elems;
00060 }
00061 
00062 string IncludesNormalize::ToLower(const string& s) {
00063   string ret;
00064   transform(s.begin(), s.end(), back_inserter(ret), ::tolower);
00065   return ret;
00066 }
00067 
00068 string IncludesNormalize::AbsPath(StringPiece s) {
00069   char result[_MAX_PATH];
00070   GetFullPathName(s.AsString().c_str(), sizeof(result), result, NULL);
00071   return result;
00072 }
00073 
00074 string IncludesNormalize::Relativize(StringPiece path, const string& start) {
00075   vector<string> start_list = Split(AbsPath(start), '\\');
00076   vector<string> path_list = Split(AbsPath(path), '\\');
00077   int i;
00078   for (i = 0; i < static_cast<int>(min(start_list.size(), path_list.size()));
00079        ++i) {
00080     if (ToLower(start_list[i]) != ToLower(path_list[i]))
00081       break;
00082   }
00083 
00084   vector<string> rel_list;
00085   for (int j = 0; j < static_cast<int>(start_list.size() - i); ++j)
00086     rel_list.push_back("..");
00087   for (int j = i; j < static_cast<int>(path_list.size()); ++j)
00088     rel_list.push_back(path_list[j]);
00089   if (rel_list.size() == 0)
00090     return ".";
00091   return Join(rel_list, '\\');
00092 }
00093 
00094 string IncludesNormalize::Normalize(const string& input,
00095                                     const char* relative_to) {
00096   char copy[_MAX_PATH];
00097   size_t len = input.size();
00098   strncpy(copy, input.c_str(), input.size() + 1);
00099   for (size_t j = 0; j < len; ++j)
00100     if (copy[j] == '/')
00101       copy[j] = '\\';
00102   string err;
00103   if (!CanonicalizePath(copy, &len, &err)) {
00104     Warning("couldn't canonicalize '%s: %s\n", input.c_str(), err.c_str());
00105   }
00106   string curdir;
00107   if (!relative_to) {
00108     curdir = AbsPath(".");
00109     relative_to = curdir.c_str();
00110   }
00111   StringPiece partially_fixed(copy, len);
00112   if (!SameDrive(partially_fixed, relative_to))
00113     return partially_fixed.AsString();
00114   return Relativize(partially_fixed, relative_to);
00115 }