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.
5 #include "tools/gn/source_dir.h"
7 #include "base/logging.h"
8 #include "tools/gn/filesystem_utils.h"
9 #include "tools/gn/source_file.h"
13 void AssertValueSourceDirString(const std::string
& s
) {
17 (s
.size() > 2 && s
[0] != '/' && s
[1] == ':' && IsSlash(s
[2])));
21 DCHECK(EndsWithSlash(s
));
27 SourceDir::SourceDir() {
30 SourceDir::SourceDir(const base::StringPiece
& p
)
31 : value_(p
.data(), p
.size()) {
32 if (!EndsWithSlash(value_
))
33 value_
.push_back('/');
34 AssertValueSourceDirString(value_
);
37 SourceDir::SourceDir(SwapIn
, std::string
* s
) {
39 if (!EndsWithSlash(value_
))
40 value_
.push_back('/');
41 AssertValueSourceDirString(value_
);
44 SourceDir::~SourceDir() {
47 SourceFile
SourceDir::ResolveRelativeFile(
48 const base::StringPiece
& p
,
49 const base::StringPiece
& source_root
) const {
52 DCHECK(source_root
.empty() || !source_root
.ends_with("/"));
54 // It's an error to resolve an empty string or one that is a directory
55 // (indicated by a trailing slash) because this is the function that expects
57 if (p
.empty() || (p
.size() > 0 && p
[p
.size() - 1] == '/'))
59 if (p
.size() >= 2 && p
[0] == '/' && p
[1] == '/') {
61 ret
.value_
.assign(p
.data(), p
.size());
62 NormalizePath(&ret
.value_
);
64 } else if (IsPathAbsolute(p
)) {
65 if (source_root
.empty() ||
66 !MakeAbsolutePathRelativeIfPossible(source_root
, p
, &ret
.value_
)) {
68 // On Windows we'll accept "C:\foo" as an absolute path, which we want
69 // to convert to "/C:..." here.
73 ret
.value_
.append(p
.data(), p
.size());
75 NormalizePath(&ret
.value_
);
79 if (!source_root
.empty()) {
80 std::string absolute
=
81 FilePathToUTF8(Resolve(UTF8ToFilePath(source_root
)).AppendASCII(
82 p
.as_string()).value());
83 NormalizePath(&absolute
);
84 if (!MakeAbsolutePathRelativeIfPossible(source_root
, absolute
,
87 // On Windows we'll accept "C:\foo" as an absolute path, which we want
88 // to convert to "/C:..." here.
89 if (absolute
[0] != '/')
92 ret
.value_
.append(absolute
.data(), absolute
.size());
97 // With no source_root_, there's nothing we can do about
98 // e.g. p=../../../path/to/file and value_=//source and we'll
99 // errornously return //file.
100 ret
.value_
.reserve(value_
.size() + p
.size());
101 ret
.value_
.assign(value_
);
102 ret
.value_
.append(p
.data(), p
.size());
104 NormalizePath(&ret
.value_
);
108 SourceDir
SourceDir::ResolveRelativeDir(
109 const base::StringPiece
& p
,
110 const base::StringPiece
& source_root
) const {
113 DCHECK(source_root
.empty() || !source_root
.ends_with("/"));
117 if (p
.size() >= 2 && p
[0] == '/' && p
[1] == '/') {
119 ret
.value_
.assign(p
.data(), p
.size());
120 if (!EndsWithSlash(ret
.value_
))
121 ret
.value_
.push_back('/');
122 NormalizePath(&ret
.value_
);
124 } else if (IsPathAbsolute(p
)) {
125 if (source_root
.empty() ||
126 !MakeAbsolutePathRelativeIfPossible(source_root
, p
, &ret
.value_
)) {
128 if (p
[0] != '/') // See the file case for why we do this check.
131 ret
.value_
.append(p
.data(), p
.size());
133 NormalizePath(&ret
.value_
);
134 if (!EndsWithSlash(ret
.value_
))
135 ret
.value_
.push_back('/');
139 if (!source_root
.empty()) {
140 std::string absolute
=
141 FilePathToUTF8(Resolve(UTF8ToFilePath(source_root
)).AppendASCII(
142 p
.as_string()).value());
143 NormalizePath(&absolute
);
144 if (!MakeAbsolutePathRelativeIfPossible(source_root
, absolute
,
147 if (absolute
[0] != '/') // See the file case for why we do this check.
150 ret
.value_
.append(absolute
.data(), absolute
.size());
152 if (!EndsWithSlash(ret
.value_
))
153 ret
.value_
.push_back('/');
157 ret
.value_
.reserve(value_
.size() + p
.size());
158 ret
.value_
.assign(value_
);
159 ret
.value_
.append(p
.data(), p
.size());
161 NormalizePath(&ret
.value_
);
162 if (!EndsWithSlash(ret
.value_
))
163 ret
.value_
.push_back('/');
164 AssertValueSourceDirString(ret
.value_
);
169 base::FilePath
SourceDir::Resolve(const base::FilePath
& source_root
) const {
171 return base::FilePath();
173 std::string converted
;
174 if (is_system_absolute()) {
175 if (value_
.size() > 2 && value_
[2] == ':') {
176 // Windows path, strip the leading slash.
177 converted
.assign(&value_
[1], value_
.size() - 1);
179 converted
.assign(value_
);
181 return base::FilePath(UTF8ToFilePath(converted
));
184 // String the double-leading slash for source-relative paths.
185 converted
.assign(&value_
[2], value_
.size() - 2);
186 return source_root
.Append(UTF8ToFilePath(converted
))
187 .NormalizePathSeparatorsTo('/');
190 void SourceDir::SwapValue(std::string
* v
) {
192 AssertValueSourceDirString(value_
);