1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "tools/gn/source_dir.h" 6 7 #include "base/logging.h" 8 #include "tools/gn/filesystem_utils.h" 9 #include "tools/gn/source_file.h" 10 11 namespace { 12 13 void AssertValueSourceDirString(const std::string& s) { 14 if (!s.empty()) { 15 DCHECK(s[0] == '/'); 16 DCHECK(EndsWithSlash(s)); 17 } 18 } 19 20 } // namespace 21 22 SourceDir::SourceDir() { 23 } 24 25 SourceDir::SourceDir(const base::StringPiece& p) 26 : value_(p.data(), p.size()) { 27 if (!EndsWithSlash(value_)) 28 value_.push_back('/'); 29 AssertValueSourceDirString(value_); 30 } 31 32 SourceDir::SourceDir(SwapIn, std::string* s) { 33 value_.swap(*s); 34 if (!EndsWithSlash(value_)) 35 value_.push_back('/'); 36 AssertValueSourceDirString(value_); 37 } 38 39 SourceDir::~SourceDir() { 40 } 41 42 SourceFile SourceDir::ResolveRelativeFile( 43 const base::StringPiece& p, 44 const base::StringPiece& source_root) const { 45 SourceFile ret; 46 47 // It's an error to resolve an empty string or one that is a directory 48 // (indicated by a trailing slash) because this is the function that expects 49 // to return a file. 50 if (p.empty() || (p.size() > 0 && p[p.size() - 1] == '/')) 51 return SourceFile(); 52 if (p.size() >= 2 && p[0] == '/' && p[1] == '/') { 53 // Source-relative. 54 ret.value_.assign(p.data(), p.size()); 55 NormalizePath(&ret.value_); 56 return ret; 57 } else if (IsPathAbsolute(p)) { 58 if (source_root.empty() || 59 !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_)) { 60 #if defined(OS_WIN) 61 // On Windows we'll accept "C:\foo" as an absolute path, which we want 62 // to convert to "/C:..." here. 63 if (p[0] != '/') 64 ret.value_ = "/"; 65 #endif 66 ret.value_.append(p.data(), p.size()); 67 } 68 NormalizePath(&ret.value_); 69 return ret; 70 } 71 72 ret.value_.reserve(value_.size() + p.size()); 73 ret.value_.assign(value_); 74 ret.value_.append(p.data(), p.size()); 75 76 NormalizePath(&ret.value_); 77 return ret; 78 } 79 80 SourceDir SourceDir::ResolveRelativeDir( 81 const base::StringPiece& p, 82 const base::StringPiece& source_root) const { 83 SourceDir ret; 84 85 if (p.empty()) 86 return ret; 87 if (p.size() >= 2 && p[0] == '/' && p[1] == '/') { 88 // Source-relative. 89 ret.value_.assign(p.data(), p.size()); 90 if (!EndsWithSlash(ret.value_)) 91 ret.value_.push_back('/'); 92 NormalizePath(&ret.value_); 93 return ret; 94 } else if (IsPathAbsolute(p)) { 95 if (source_root.empty() || 96 !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_)) { 97 #if defined(OS_WIN) 98 if (p[0] != '/') // See the file case for why we do this check. 99 ret.value_ = "/"; 100 #endif 101 ret.value_.append(p.data(), p.size()); 102 } 103 NormalizePath(&ret.value_); 104 if (!EndsWithSlash(ret.value_)) 105 ret.value_.push_back('/'); 106 return ret; 107 } 108 109 ret.value_.reserve(value_.size() + p.size()); 110 ret.value_.assign(value_); 111 ret.value_.append(p.data(), p.size()); 112 113 NormalizePath(&ret.value_); 114 if (!EndsWithSlash(ret.value_)) 115 ret.value_.push_back('/'); 116 AssertValueSourceDirString(ret.value_); 117 118 return ret; 119 } 120 121 base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const { 122 if (is_null()) 123 return base::FilePath(); 124 125 std::string converted; 126 if (is_system_absolute()) { 127 if (value_.size() > 2 && value_[2] == ':') { 128 // Windows path, strip the leading slash. 129 converted.assign(&value_[1], value_.size() - 1); 130 } else { 131 converted.assign(value_); 132 } 133 ConvertPathToSystem(&converted); 134 return base::FilePath(UTF8ToFilePath(converted)); 135 } 136 137 // String the double-leading slash for source-relative paths. 138 converted.assign(&value_[2], value_.size() - 2); 139 ConvertPathToSystem(&converted); 140 return source_root.Append(UTF8ToFilePath(converted)); 141 } 142 143 void SourceDir::SwapValue(std::string* v) { 144 value_.swap(*v); 145 AssertValueSourceDirString(value_); 146 } 147