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 "gn/source_dir.h"
6
7 #include <string>
8
9 #include "base/logging.h"
10 #include "gn/filesystem_utils.h"
11 #include "gn/source_file.h"
12 #include "util/build_config.h"
13
14 namespace {
15
AssertValueSourceDirString(const std::string & s)16 void AssertValueSourceDirString(const std::string& s) {
17 if (!s.empty()) {
18 #if defined(OS_WIN)
19 DCHECK(s[0] == '/' ||
20 (s.size() > 2 && s[0] != '/' && s[1] == ':' && IsSlash(s[2])));
21 #else
22 DCHECK(s[0] == '/');
23 #endif
24 DCHECK(EndsWithSlash(s)) << s;
25 }
26 }
27
28 // Validates input value (input_value) and sets proper error message.
29 // Note: Parameter blame_input is used only for generating error message.
30 template <typename StringType>
ValidateResolveInput(bool as_file,const Value & blame_input_value,const StringType & input_value,Err * err)31 bool ValidateResolveInput(bool as_file,
32 const Value& blame_input_value,
33 const StringType& input_value,
34 Err* err) {
35 if (as_file) {
36 // It's an error to resolve an empty string or one that is a directory
37 // (indicated by a trailing slash) because this is the function that expects
38 // to return a file.
39 if (input_value.empty()) {
40 *err = Err(blame_input_value, "Empty file path.",
41 "You can't use empty strings as file paths.");
42 return false;
43 } else if (input_value[input_value.size() - 1] == '/') {
44 std::string help = "You specified the path\n ";
45 help.append(std::string(input_value));
46 help.append(
47 "\nand it ends in a slash, indicating you think it's a directory."
48 "\nBut here you're supposed to be listing a file.");
49 *err = Err(blame_input_value, "File path ends in a slash.", help);
50 return false;
51 }
52 } else if (input_value.empty()) {
53 *err = Err(blame_input_value, "Empty directory path.",
54 "You can't use empty strings as directories.");
55 return false;
56 }
57 return true;
58 }
59
60 } // namespace
61
SourceDir(const std::string & s)62 SourceDir::SourceDir(const std::string& s) : value_(s) {
63 if (!EndsWithSlash(value_))
64 value_.push_back('/');
65 AssertValueSourceDirString(value_);
66 }
67
SourceDir(std::string && s)68 SourceDir::SourceDir(std::string&& s) : value_(std::move(s)) {
69 if (!EndsWithSlash(value_))
70 value_.push_back('/');
71 AssertValueSourceDirString(value_);
72 }
73
74 template <typename StringType>
ResolveRelativeAs(bool as_file,const Value & blame_input_value,const StringType & input_value,Err * err,const std::string_view & source_root) const75 std::string SourceDir::ResolveRelativeAs(
76 bool as_file,
77 const Value& blame_input_value,
78 const StringType& input_value,
79 Err* err,
80 const std::string_view& source_root) const {
81 if (!ValidateResolveInput<StringType>(as_file, blame_input_value, input_value,
82 err)) {
83 return std::string();
84 }
85 return ResolveRelative(input_value, value_, as_file, source_root);
86 }
87
ResolveRelativeFile(const Value & p,Err * err,const std::string_view & source_root) const88 SourceFile SourceDir::ResolveRelativeFile(
89 const Value& p,
90 Err* err,
91 const std::string_view& source_root) const {
92 SourceFile ret;
93
94 if (!p.VerifyTypeIs(Value::STRING, err))
95 return ret;
96
97 const std::string& input_string = p.string_value();
98 if (!ValidateResolveInput<std::string>(true, p, input_string, err))
99 return ret;
100
101 ret.SetValue(ResolveRelative(input_string, value_, true, source_root));
102 return ret;
103 }
104
ResolveRelativeAs(bool as_file,const Value & v,Err * err,const std::string_view & source_root,const std::string * v_value) const105 std::string SourceDir::ResolveRelativeAs(bool as_file,
106 const Value& v,
107 Err* err,
108 const std::string_view& source_root,
109 const std::string* v_value) const {
110 if (!v.VerifyTypeIs(Value::STRING, err))
111 return std::string();
112
113 if (!v_value) {
114 v_value = &v.string_value();
115 }
116 std::string result =
117 ResolveRelativeAs(as_file, v, *v_value, err, source_root);
118 if (!as_file)
119 AssertValueSourceDirString(result);
120 return result;
121 }
122
ResolveRelativeDir(const Value & v,Err * err,const std::string_view & source_root) const123 SourceDir SourceDir::ResolveRelativeDir(
124 const Value& v,
125 Err* err,
126 const std::string_view& source_root) const {
127 if (!v.VerifyTypeIs(Value::STRING, err))
128 return SourceDir();
129
130 return ResolveRelativeDir<std::string>(v, v.string_value(), err, source_root);
131 }
132
Resolve(const base::FilePath & source_root) const133 base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const {
134 return ResolvePath(value_, false, source_root);
135 }
136
137 // Explicit template instantiation
138 template std::string SourceDir::ResolveRelativeAs(
139 bool as_file,
140 const Value& blame_input_value,
141 const std::string& input_value,
142 Err* err,
143 const std::string_view& source_root) const;
144
145 template std::string SourceDir::ResolveRelativeAs(
146 bool as_file,
147 const Value& blame_input_value,
148 const std::string_view& input_value,
149 Err* err,
150 const std::string_view& source_root) const;
151