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
,
86 ret
.value_
= absolute
;
90 // With no source_root_, there's nothing we can do about
91 // e.g. p=../../../path/to/file and value_=//source and we'll
92 // errornously return //file.
93 ret
.value_
.reserve(value_
.size() + p
.size());
94 ret
.value_
.assign(value_
);
95 ret
.value_
.append(p
.data(), p
.size());
97 NormalizePath(&ret
.value_
);
101 SourceDir
SourceDir::ResolveRelativeDir(
102 const base::StringPiece
& p
,
103 const base::StringPiece
& source_root
) const {
106 DCHECK(source_root
.empty() || !source_root
.ends_with("/"));
110 if (p
.size() >= 2 && p
[0] == '/' && p
[1] == '/') {
112 ret
.value_
.assign(p
.data(), p
.size());
113 if (!EndsWithSlash(ret
.value_
))
114 ret
.value_
.push_back('/');
115 NormalizePath(&ret
.value_
);
117 } else if (IsPathAbsolute(p
)) {
118 if (source_root
.empty() ||
119 !MakeAbsolutePathRelativeIfPossible(source_root
, p
, &ret
.value_
)) {
121 if (p
[0] != '/') // See the file case for why we do this check.
124 ret
.value_
.append(p
.data(), p
.size());
126 NormalizePath(&ret
.value_
);
127 if (!EndsWithSlash(ret
.value_
))
128 ret
.value_
.push_back('/');
132 if (!source_root
.empty()) {
133 std::string absolute
=
134 FilePathToUTF8(Resolve(UTF8ToFilePath(source_root
)).AppendASCII(
135 p
.as_string()).value());
136 NormalizePath(&absolute
);
137 if (!MakeAbsolutePathRelativeIfPossible(source_root
, absolute
, &ret
.value_
))
138 ret
.value_
= absolute
;
139 if (!EndsWithSlash(ret
.value_
))
140 ret
.value_
.push_back('/');
144 ret
.value_
.reserve(value_
.size() + p
.size());
145 ret
.value_
.assign(value_
);
146 ret
.value_
.append(p
.data(), p
.size());
148 NormalizePath(&ret
.value_
);
149 if (!EndsWithSlash(ret
.value_
))
150 ret
.value_
.push_back('/');
151 AssertValueSourceDirString(ret
.value_
);
156 base::FilePath
SourceDir::Resolve(const base::FilePath
& source_root
) const {
158 return base::FilePath();
160 std::string converted
;
161 if (is_system_absolute()) {
162 if (value_
.size() > 2 && value_
[2] == ':') {
163 // Windows path, strip the leading slash.
164 converted
.assign(&value_
[1], value_
.size() - 1);
166 converted
.assign(value_
);
168 return base::FilePath(UTF8ToFilePath(converted
));
171 // String the double-leading slash for source-relative paths.
172 converted
.assign(&value_
[2], value_
.size() - 2);
173 return source_root
.Append(UTF8ToFilePath(converted
))
174 .NormalizePathSeparatorsTo('/');
177 void SourceDir::SwapValue(std::string
* v
) {
179 AssertValueSourceDirString(value_
);