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
)) << 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(
50 const base::StringPiece
& source_root
) const {
52 if (!p
.VerifyTypeIs(Value::STRING
, err
))
55 // It's an error to resolve an empty string or one that is a directory
56 // (indicated by a trailing slash) because this is the function that expects
58 const std::string
& str
= p
.string_value();
60 *err
= Err(p
, "Empty file path.",
61 "You can't use empty strings as file paths. That's just wrong.");
63 } else if (str
[str
.size() - 1] == '/') {
64 *err
= Err(p
, "File path ends in a slash.",
65 "You specified the path\n " + str
+ "\n"
66 "and it ends in a slash, indicating you think it's a directory."
67 "\nBut here you're supposed to be listing a file.");
71 if (str
.size() >= 2 && str
[0] == '/' && str
[1] == '/') {
73 ret
.value_
.assign(str
.data(), str
.size());
74 NormalizePath(&ret
.value_
);
76 } else if (IsPathAbsolute(str
)) {
77 if (source_root
.empty() ||
78 !MakeAbsolutePathRelativeIfPossible(source_root
, str
, &ret
.value_
)) {
80 // On Windows we'll accept "C:\foo" as an absolute path, which we want
81 // to convert to "/C:..." here.
85 ret
.value_
.append(str
.data(), str
.size());
87 NormalizePath(&ret
.value_
);
91 if (!source_root
.empty()) {
92 std::string absolute
=
93 FilePathToUTF8(Resolve(UTF8ToFilePath(source_root
)).AppendASCII(
95 NormalizePath(&absolute
);
96 if (!MakeAbsolutePathRelativeIfPossible(source_root
, absolute
,
99 // On Windows we'll accept "C:\foo" as an absolute path, which we want
100 // to convert to "/C:..." here.
101 if (absolute
[0] != '/')
104 ret
.value_
.append(absolute
.data(), absolute
.size());
109 // With no source_root_, there's nothing we can do about
110 // e.g. p=../../../path/to/file and value_=//source and we'll
111 // errornously return //file.
112 ret
.value_
.reserve(value_
.size() + str
.size());
113 ret
.value_
.assign(value_
);
114 ret
.value_
.append(str
.data(), str
.size());
116 NormalizePath(&ret
.value_
);
120 SourceDir
SourceDir::ResolveRelativeDir(
123 const base::StringPiece
& source_root
) const {
124 if (!p
.VerifyTypeIs(Value::STRING
, err
))
126 return ResolveRelativeDir(p
, p
.string_value(), err
, source_root
);
129 SourceDir
SourceDir::ResolveRelativeDir(
130 const Value
& blame_but_dont_use
,
131 const base::StringPiece
& str
,
133 const base::StringPiece
& source_root
) const {
137 *err
= Err(blame_but_dont_use
, "Empty directory path.",
138 "You can't use empty strings as directories. "
139 "That's just wrong.");
143 if (str
.size() >= 2 && str
[0] == '/' && str
[1] == '/') {
145 ret
.value_
.assign(str
.data(), str
.size());
146 if (!EndsWithSlash(ret
.value_
))
147 ret
.value_
.push_back('/');
148 NormalizePath(&ret
.value_
);
150 } else if (IsPathAbsolute(str
)) {
151 if (source_root
.empty() ||
152 !MakeAbsolutePathRelativeIfPossible(source_root
, str
, &ret
.value_
)) {
154 if (str
[0] != '/') // See the file case for why we do this check.
157 ret
.value_
.append(str
.data(), str
.size());
159 NormalizePath(&ret
.value_
);
160 if (!EndsWithSlash(ret
.value_
))
161 ret
.value_
.push_back('/');
165 if (!source_root
.empty()) {
166 std::string absolute
=
167 FilePathToUTF8(Resolve(UTF8ToFilePath(source_root
)).AppendASCII(
168 str
.as_string()).value());
169 NormalizePath(&absolute
);
170 if (!MakeAbsolutePathRelativeIfPossible(source_root
, absolute
,
173 if (absolute
[0] != '/') // See the file case for why we do this check.
176 ret
.value_
.append(absolute
.data(), absolute
.size());
178 if (!EndsWithSlash(ret
.value_
))
179 ret
.value_
.push_back('/');
183 ret
.value_
.reserve(value_
.size() + str
.size());
184 ret
.value_
.assign(value_
);
185 ret
.value_
.append(str
.data(), str
.size());
187 NormalizePath(&ret
.value_
);
188 if (!EndsWithSlash(ret
.value_
))
189 ret
.value_
.push_back('/');
190 AssertValueSourceDirString(ret
.value_
);
195 base::FilePath
SourceDir::Resolve(const base::FilePath
& source_root
) const {
197 return base::FilePath();
199 std::string converted
;
200 if (is_system_absolute()) {
201 if (value_
.size() > 2 && value_
[2] == ':') {
202 // Windows path, strip the leading slash.
203 converted
.assign(&value_
[1], value_
.size() - 1);
205 converted
.assign(value_
);
207 return base::FilePath(UTF8ToFilePath(converted
));
210 // String the double-leading slash for source-relative paths.
211 converted
.assign(&value_
[2], value_
.size() - 2);
212 return source_root
.Append(UTF8ToFilePath(converted
))
213 .NormalizePathSeparatorsTo('/');
216 void SourceDir::SwapValue(std::string
* v
) {
218 AssertValueSourceDirString(value_
);