Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: tools/gn/filesystem_utils.cc

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/filesystem_utils.h ('k') | tools/gn/filesystem_utils_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/filesystem_utils.h"
6
7 #include "base/logging.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "build/build_config.h"
10 #include "tools/gn/location.h"
11 #include "tools/gn/source_dir.h"
12
13 namespace {
14
15 enum DotDisposition {
16 // The given dot is just part of a filename and is not special.
17 NOT_A_DIRECTORY,
18
19 // The given dot is the current directory.
20 DIRECTORY_CUR,
21
22 // The given dot is the first of a double dot that should take us up one.
23 DIRECTORY_UP
24 };
25
26 // When we find a dot, this function is called with the character following
27 // that dot to see what it is. The return value indicates what type this dot is
28 // (see above). This code handles the case where the dot is at the end of the
29 // input.
30 //
31 // |*consumed_len| will contain the number of characters in the input that
32 // express what we found.
33 DotDisposition ClassifyAfterDot(const std::string& path,
34 size_t after_dot,
35 size_t* consumed_len) {
36 if (after_dot == path.size()) {
37 // Single dot at the end.
38 *consumed_len = 1;
39 return DIRECTORY_CUR;
40 }
41 if (path[after_dot] == '/') {
42 // Single dot followed by a slash.
43 *consumed_len = 2; // Consume the slash
44 return DIRECTORY_CUR;
45 }
46
47 if (path[after_dot] == '.') {
48 // Two dots.
49 if (after_dot + 1 == path.size()) {
50 // Double dot at the end.
51 *consumed_len = 2;
52 return DIRECTORY_UP;
53 }
54 if (path[after_dot + 1] == '/') {
55 // Double dot folowed by a slash.
56 *consumed_len = 3;
57 return DIRECTORY_UP;
58 }
59 }
60
61 // The dots are followed by something else, not a directory.
62 *consumed_len = 1;
63 return NOT_A_DIRECTORY;
64 }
65
66 } // namesapce
67
68 SourceFileType GetSourceFileType(const SourceFile& file,
69 Settings::TargetOS os) {
70 base::StringPiece extension = FindExtension(&file.value());
71 if (extension == "cc" || extension == "cpp" || extension == "cxx")
72 return SOURCE_CC;
73 if (extension == "h")
74 return SOURCE_H;
75 if (extension == "c")
76 return SOURCE_C;
77
78 switch (os) {
79 case Settings::MAC:
80 if (extension == "m")
81 return SOURCE_M;
82 if (extension == "mm")
83 return SOURCE_MM;
84 break;
85
86 case Settings::WIN:
87 if (extension == "rc")
88 return SOURCE_RC;
89 break;
90
91 default:
92 break;
93 }
94
95 // TODO(brettw) asm files.
96 // TODO(brettw) weird thing with .S on non-Windows platforms.
97 return SOURCE_UNKNOWN;
98 }
99
100 const char* GetExtensionForOutputType(Target::OutputType type,
101 Settings::TargetOS os) {
102 switch (os) {
103 case Settings::WIN:
104 switch (type) {
105 case Target::NONE:
106 NOTREACHED();
107 return "";
108 case Target::EXECUTABLE:
109 return "exe";
110 case Target::SHARED_LIBRARY:
111 return "dll.lib"; // Extension of import library.
112 case Target::STATIC_LIBRARY:
113 return "lib";
114 case Target::LOADABLE_MODULE:
115 return "dll"; // TODO(brettw) what's this?
116 default:
117 NOTREACHED();
118 }
119 break;
120
121 default:
122 NOTREACHED();
123 }
124 return "";
125 }
126
127 std::string FilePathToUTF8(const base::FilePath& path) {
128 #if defined(OS_WIN)
129 return WideToUTF8(path.value());
130 #else
131 return path.value();
132 #endif
133 }
134
135 base::FilePath UTF8ToFilePath(const base::StringPiece& sp) {
136 #if defined(OS_WIN)
137 return base::FilePath(UTF8ToWide(sp));
138 #else
139 return base::FilePath(sp.as_string());
140 #endif
141 }
142
143 size_t FindExtensionOffset(const std::string& path) {
144 for (int i = static_cast<int>(path.size()); i >= 0; i--) {
145 if (path[i] == '/')
146 break;
147 if (path[i] == '.')
148 return i + 1;
149 }
150 return std::string::npos;
151 }
152
153 base::StringPiece FindExtension(const std::string* path) {
154 size_t extension_offset = FindExtensionOffset(*path);
155 if (extension_offset == std::string::npos)
156 return base::StringPiece();
157 return base::StringPiece(&path->data()[extension_offset],
158 path->size() - extension_offset);
159 }
160
161 size_t FindFilenameOffset(const std::string& path) {
162 for (int i = static_cast<int>(path.size()) - 1; i >= 0; i--) {
163 if (path[i] == '/')
164 return i + 1;
165 }
166 return 0; // No filename found means everything was the filename.
167 }
168
169 base::StringPiece FindFilename(const std::string* path) {
170 size_t filename_offset = FindFilenameOffset(*path);
171 if (filename_offset == 0)
172 return base::StringPiece(*path); // Everything is the file name.
173 return base::StringPiece(&(*path).data()[filename_offset],
174 path->size() - filename_offset);
175 }
176
177 base::StringPiece FindFilenameNoExtension(const std::string* path) {
178 if (path->empty())
179 return base::StringPiece();
180 size_t filename_offset = FindFilenameOffset(*path);
181 size_t extension_offset = FindExtensionOffset(*path);
182
183 size_t name_len;
184 if (extension_offset == std::string::npos)
185 name_len = path->size() - filename_offset;
186 else
187 name_len = extension_offset - filename_offset - 1;
188
189 return base::StringPiece(&(*path).data()[filename_offset], name_len);
190 }
191
192 void RemoveFilename(std::string* path) {
193 path->resize(FindFilenameOffset(*path));
194 }
195
196 bool EndsWithSlash(const std::string& s) {
197 return !s.empty() && s[s.size() - 1] == '/';
198 }
199
200 base::StringPiece FindDir(const std::string* path) {
201 size_t filename_offset = FindFilenameOffset(*path);
202 if (filename_offset == 0u)
203 return base::StringPiece();
204 return base::StringPiece(path->data(), filename_offset);
205 }
206
207 bool EnsureStringIsInOutputDir(const SourceDir& dir,
208 const std::string& str,
209 const Value& originating,
210 Err* err) {
211 // The last char of the dir will be a slash. We don't care if the input ends
212 // in a slash or not, so just compare up until there.
213 //
214 // This check will be wrong for all proper prefixes "e.g. "/output" will
215 // match "/out" but we don't really care since this is just a sanity check.
216 const std::string& dir_str = dir.value();
217 if (str.compare(0, dir_str.length() - 1, dir_str, 0, dir_str.length() - 1)
218 != 0) {
219 *err = Err(originating, "File not inside output directory.",
220 "The given file should be in the output directory. Normally you would "
221 "specify\n\"$target_output_dir/foo\" or "
222 "\"$target_gen_dir/foo\". I interpreted this as\n\""
223 + str + "\".");
224 return false;
225 }
226 return true;
227 }
228
229 std::string InvertDir(const SourceDir& path) {
230 const std::string value = path.value();
231 if (value.empty())
232 return std::string();
233
234 DCHECK(value[0] == '/');
235 size_t begin_index = 1;
236
237 // If the input begins with two slashes, skip over both (this is a
238 // source-relative dir).
239 if (value.size() > 1 && value[1] == '/')
240 begin_index = 2;
241
242 std::string ret;
243 for (size_t i = begin_index; i < value.size(); i++) {
244 if (value[i] == '/')
245 ret.append("../");
246 }
247 return ret;
248 }
249
250 void NormalizePath(std::string* path) {
251 char* pathbuf = path->empty() ? NULL : &(*path)[0];
252
253 // top_index is the first character we can modify in the path. Anything
254 // before this indicates where the path is relative to.
255 size_t top_index = 0;
256 bool is_relative = true;
257 if (!path->empty() && pathbuf[0] == '/') {
258 is_relative = false;
259
260 if (path->size() > 1 && pathbuf[1] == '/') {
261 // Two leading slashes, this is a path into the source dir.
262 top_index = 2;
263 } else {
264 // One leading slash, this is a system-absolute path.
265 top_index = 1;
266 }
267 }
268
269 size_t dest_i = top_index;
270 for (size_t src_i = top_index; src_i < path->size(); /* nothing */) {
271 if (pathbuf[src_i] == '.') {
272 if (src_i == 0 || pathbuf[src_i - 1] == '/') {
273 // Slash followed by a dot, see if it's something special.
274 size_t consumed_len;
275 switch (ClassifyAfterDot(*path, src_i + 1, &consumed_len)) {
276 case NOT_A_DIRECTORY:
277 // Copy the dot to the output, it means nothing special.
278 pathbuf[dest_i++] = pathbuf[src_i++];
279 break;
280 case DIRECTORY_CUR:
281 // Current directory, just skip the input.
282 src_i += consumed_len;
283 break;
284 case DIRECTORY_UP:
285 // Back up over previous directory component. If we're already
286 // at the top, preserve the "..".
287 if (dest_i > top_index) {
288 // The previous char was a slash, remove it.
289 dest_i--;
290 }
291
292 if (dest_i == top_index) {
293 if (is_relative) {
294 // We're already at the beginning of a relative input, copy the
295 // ".." and continue. We need the trailing slash if there was
296 // one before (otherwise we're at the end of the input).
297 pathbuf[dest_i++] = '.';
298 pathbuf[dest_i++] = '.';
299 if (consumed_len == 3)
300 pathbuf[dest_i++] = '/';
301
302 // This also makes a new "root" that we can't delete by going
303 // up more levels. Otherwise "../.." would collapse to
304 // nothing.
305 top_index = dest_i;
306 }
307 // Otherwise we're at the beginning of an absolute path. Don't
308 // allow ".." to go up another level and just eat it.
309 } else {
310 // Just find the previous slash or the beginning of input.
311 while (dest_i > 0 && pathbuf[dest_i - 1] != '/')
312 dest_i--;
313 }
314 src_i += consumed_len;
315 }
316 } else {
317 // Dot not preceeded by a slash, copy it literally.
318 pathbuf[dest_i++] = pathbuf[src_i++];
319 }
320 } else if (pathbuf[src_i] == '/') {
321 if (src_i > 0 && pathbuf[src_i - 1] == '/') {
322 // Two slashes in a row, skip over it.
323 src_i++;
324 } else {
325 // Just one slash, copy it.
326 pathbuf[dest_i++] = pathbuf[src_i++];
327 }
328 } else {
329 // Input nothing special, just copy it.
330 pathbuf[dest_i++] = pathbuf[src_i++];
331 }
332 }
333 path->resize(dest_i);
334 }
335
336 void ConvertPathToSystem(std::string* path) {
337 #if defined(OS_WIN)
338 for (size_t i = 0; i < path->size(); i++) {
339 if ((*path)[i] == '/')
340 (*path)[i] = '\\';
341 }
342 #endif
343 }
344
345 std::string PathToSystem(const std::string& path) {
346 std::string ret(path);
347 ConvertPathToSystem(&ret);
348 return ret;
349 }
350
OLDNEW
« no previous file with comments | « tools/gn/filesystem_utils.h ('k') | tools/gn/filesystem_utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698