filesystem_utils.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file.
4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/filesystem_utils.h"
6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <algorithm>
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/file_util.h"
10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/logging.h"
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_util.h"
12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/utf_string_conversions.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "build/build_config.h"
14d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/location.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/settings.h"
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/source_dir.h"
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochenum DotDisposition {
21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is just part of a filename and is not special.
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  NOT_A_DIRECTORY,
23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
24d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is the current directory.
25d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DIRECTORY_CUR,
26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is the first of a double dot that should take us up one.
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DIRECTORY_UP
29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch};
30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// When we find a dot, this function is called with the character following
32d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// that dot to see what it is. The return value indicates what type this dot is
33d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// (see above). This code handles the case where the dot is at the end of the
34d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// input.
35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch//
36d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// |*consumed_len| will contain the number of characters in the input that
37d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// express what we found.
38d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochDotDisposition ClassifyAfterDot(const std::string& path,
39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                size_t after_dot,
40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                size_t* consumed_len) {
41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (after_dot == path.size()) {
42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Single dot at the end.
43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *consumed_len = 1;
44d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return DIRECTORY_CUR;
45d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsSlash(path[after_dot])) {
47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Single dot followed by a slash.
48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *consumed_len = 2;  // Consume the slash
49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return DIRECTORY_CUR;
50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (path[after_dot] == '.') {
53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Two dots.
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (after_dot + 1 == path.size()) {
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Double dot at the end.
56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      *consumed_len = 2;
57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return DIRECTORY_UP;
58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(path[after_dot + 1])) {
60d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Double dot folowed by a slash.
61d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      *consumed_len = 3;
62d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return DIRECTORY_UP;
63d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
64d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
66d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The dots are followed by something else, not a directory.
67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  *consumed_len = 1;
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return NOT_A_DIRECTORY;
69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
70d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_WIN)
72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)inline char NormalizeWindowsPathChar(char c) {
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (c == '/')
74424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return '\\';
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return base::ToLowerASCII(c);
76424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Attempts to do a case and slash-insensitive comparison of two 8-bit Windows
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// paths.
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool AreAbsoluteWindowsPathsEqual(const base::StringPiece& a,
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                  const base::StringPiece& b) {
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (a.size() != b.size())
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // For now, just do a case-insensitive ASCII comparison. We could convert to
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // UTF-16 and use ICU if necessary. Or maybe base::strcasecmp is good enough?
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  for (size_t i = 0; i < a.size(); i++) {
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (NormalizeWindowsPathChar(a[i]) != NormalizeWindowsPathChar(b[i]))
89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool DoesBeginWindowsDriveLetter(const base::StringPiece& path) {
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (path.size() < 3)
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check colon first, this will generally fail fastest.
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (path[1] != ':')
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Check drive letter.
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!IsAsciiAlpha(path[0]))
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsSlash(path[2]))
107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A wrapper around FilePath.GetComponents that works the way we need. This is
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// not super efficient since it does some O(n) transformations on the path. If
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// this is called a lot, we might want to optimize.
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::vector<base::FilePath::StringType> GetPathComponents(
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::FilePath& path) {
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath::StringType> result;
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  path.GetComponents(&result);
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result.empty())
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return result;
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // GetComponents will preserve the "/" at the beginning, which confuses us.
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // We don't expect to have relative paths in this function.
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Don't use IsSeparator since we always want to allow backslashes.
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result[0] == FILE_PATH_LITERAL("/") ||
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      result[0] == FILE_PATH_LITERAL("\\"))
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result.erase(result.begin());
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // On Windows, GetComponents will give us [ "C:", "/", "foo" ], and we
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // don't want the slash in there. This doesn't support input like "C:foo"
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // which means foo relative to the current directory of the C drive but
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // that's basically legacy DOS behavior we don't need to support.
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (result.size() >= 2 && result[1].size() == 1 && IsSlash(result[1][0]))
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result.erase(result.begin() + 1);
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return result;
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Provides the equivalent of == for filesystem strings, trying to do
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// approximately the right thing with case.
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool FilesystemStringsEqual(const base::FilePath::StringType& a,
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            const base::FilePath::StringType& b) {
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_WIN)
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Assume case-insensitive filesystems on Windows. We use the CompareString
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // function to do a case-insensitive comparison based on the current locale
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // (we don't want GN to depend on ICU which is large and requires data
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // files). This isn't perfect, but getting this perfectly right is very
151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // difficult and requires I/O, and this comparison should cover 99.9999% of
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // all cases.
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Note: The documentation for CompareString says it runs fastest on
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // null-terminated strings with -1 passed for the length, so we do that here.
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // There should not be embedded nulls in filesystem strings.
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return ::CompareString(LOCALE_USER_DEFAULT, LINGUISTIC_IGNORECASE,
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         a.c_str(), -1, b.c_str(), -1) == CSTR_EQUAL;
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#else
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Assume case-sensitive filesystems on non-Windows.
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return a == b;
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSourceFileType GetSourceFileType(const SourceFile& file) {
168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  base::StringPiece extension = FindExtension(&file.value());
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "cc" || extension == "cpp" || extension == "cxx")
170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_CC;
171d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "h")
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_H;
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "c")
174d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_C;
175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (extension == "m")
176c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return SOURCE_M;
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (extension == "mm")
178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return SOURCE_MM;
179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (extension == "rc")
180c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return SOURCE_RC;
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (extension == "S" || extension == "s")
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return SOURCE_S;
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (extension == "o" || extension == "obj")
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return SOURCE_O;
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return SOURCE_UNKNOWN;
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst char* GetExtensionForOutputType(Target::OutputType type,
190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                      Settings::TargetOS os) {
191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (os) {
1922385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    case Settings::MAC:
1932385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      switch (type) {
1942385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::EXECUTABLE:
1952385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "";
1962385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::SHARED_LIBRARY:
1972385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "dylib";
1982385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::STATIC_LIBRARY:
1992385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "a";
2002385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        default:
2012385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          NOTREACHED();
2022385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      }
2032385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      break;
2042385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Settings::WIN:
206d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (type) {
207d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::EXECUTABLE:
208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "exe";
209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::SHARED_LIBRARY:
210d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "dll.lib";  // Extension of import library.
211d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::STATIC_LIBRARY:
212d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "lib";
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        default:
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          NOTREACHED();
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case Settings::LINUX:
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      switch (type) {
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::EXECUTABLE:
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "";
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::SHARED_LIBRARY:
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "so";
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::STATIC_LIBRARY:
2253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "a";
226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          NOTREACHED();
228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
229d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      NOTREACHED();
233d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
234d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return "";
235d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
236d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
23768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string FilePathToUTF8(const base::FilePath::StringType& str) {
238d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::WideToUTF8(str);
240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#else
24168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return str;
242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
245d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::FilePath UTF8ToFilePath(const base::StringPiece& sp) {
246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return base::FilePath(base::UTF8ToWide(sp));
248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#else
249d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::FilePath(sp.as_string());
250d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
251d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
252d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
253d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochsize_t FindExtensionOffset(const std::string& path) {
254d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (int i = static_cast<int>(path.size()); i >= 0; i--) {
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(path[i]))
256d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
257d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path[i] == '.')
258d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return i + 1;
259d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
260d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return std::string::npos;
261d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
262d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
263d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindExtension(const std::string* path) {
264d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t extension_offset = FindExtensionOffset(*path);
265d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension_offset == std::string::npos)
266d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
267d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&path->data()[extension_offset],
268d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           path->size() - extension_offset);
269d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
270d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
271d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochsize_t FindFilenameOffset(const std::string& path) {
272d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (int i = static_cast<int>(path.size()) - 1; i >= 0; i--) {
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(path[i]))
274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return i + 1;
275d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
276d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return 0;  // No filename found means everything was the filename.
277d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
278d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
279d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindFilename(const std::string* path) {
280d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
281d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (filename_offset == 0)
282d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece(*path);  // Everything is the file name.
283d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&(*path).data()[filename_offset],
284d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           path->size() - filename_offset);
285d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
286d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
287d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindFilenameNoExtension(const std::string* path) {
288d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (path->empty())
289d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
290d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
291d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t extension_offset = FindExtensionOffset(*path);
292d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
293d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t name_len;
294d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension_offset == std::string::npos)
295d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    name_len = path->size() - filename_offset;
296d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  else
297d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    name_len = extension_offset - filename_offset - 1;
298d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
299d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&(*path).data()[filename_offset], name_len);
300d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
301d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
302d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid RemoveFilename(std::string* path) {
303d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path->resize(FindFilenameOffset(*path));
304d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
305d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
306d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool EndsWithSlash(const std::string& s) {
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return !s.empty() && IsSlash(s[s.size() - 1]);
308d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
309d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
310d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindDir(const std::string* path) {
311d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
312d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (filename_offset == 0u)
313d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
314d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(path->data(), filename_offset);
315d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
316d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
3175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubase::StringPiece FindLastDirComponent(const SourceDir& dir) {
3185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const std::string& dir_string = dir.value();
3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (dir_string.empty())
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return base::StringPiece();
3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int cur = static_cast<int>(dir_string.size()) - 1;
3235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DCHECK(dir_string[cur] == '/');
3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int end = cur;
3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  cur--;  // Skip before the last slash.
3265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (; cur >= 0; cur--) {
3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (dir_string[cur] == '/')
3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return base::StringPiece(&dir_string[cur + 1], end - cur - 1);
3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return base::StringPiece(&dir_string[0], end);
3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
334d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool EnsureStringIsInOutputDir(const SourceDir& dir,
335d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               const std::string& str,
336d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               const Value& originating,
337d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               Err* err) {
338d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The last char of the dir will be a slash. We don't care if the input ends
339d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // in a slash or not, so just compare up until there.
340d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  //
341d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // This check will be wrong for all proper prefixes "e.g. "/output" will
342d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // match "/out" but we don't really care since this is just a sanity check.
343d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string& dir_str = dir.value();
344d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (str.compare(0, dir_str.length() - 1, dir_str, 0, dir_str.length() - 1)
345d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      != 0) {
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *err = Err(originating, "File is not inside output directory.",
347d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "The given file should be in the output directory. Normally you would "
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "specify\n\"$target_out_dir/foo\" or "
349d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "\"$target_gen_dir/foo\". I interpreted this as\n\""
350d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        + str + "\".");
351d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return false;
352d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
353d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return true;
354d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
355d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool IsPathAbsolute(const base::StringPiece& path) {
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.empty())
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsSlash(path[0])) {
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_WIN)
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Check for Windows system paths like "C:\foo".
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (path.size() > 2 && path[1] == ':' && IsSlash(path[2]))
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return true;
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
3663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;  // Doesn't begin with a slash, is relative.
3673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Double forward slash at the beginning means source-relative (we don't
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // allow backslashes for denoting this).
3713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.size() > 1 && path[1] == '/')
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
3783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        const base::StringPiece& path,
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        std::string* dest) {
3803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(IsPathAbsolute(source_root));
3813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(IsPathAbsolute(path));
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dest->clear();
3843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (source_root.size() > path.size())
3863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;  // The source root is longer: the path can never be inside.
3873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_WIN)
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Source root should be canonical on Windows. Note that the initial slash
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // must be forward slash, but that the other ones can be either forward or
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // backward.
3923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(source_root.size() > 2 && source_root[0] != '/' &&
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         source_root[1] == ':' && IsSlash(source_root[2]));
394424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  size_t after_common_index = std::string::npos;
396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (DoesBeginWindowsDriveLetter(path)) {
397424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Handle "C:\foo"
398424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (AreAbsoluteWindowsPathsEqual(source_root,
399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                     path.substr(0, source_root.size())))
400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      after_common_index = source_root.size();
401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
403424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else if (path[0] == '/' && source_root.size() <= path.size() - 1 &&
404424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)             DoesBeginWindowsDriveLetter(path.substr(1))) {
405424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Handle "/C:/foo"
406424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (AreAbsoluteWindowsPathsEqual(source_root,
407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                     path.substr(1, source_root.size())))
408424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      after_common_index = source_root.size() + 1;
409424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
410424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
411424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
412424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
413424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
414424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
415424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If we get here, there's a match and after_common_index identifies the
416424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // part after it.
417424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
418424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // The base may or may not have a trailing slash, so skip all slashes from
419424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // the path after our prefix match.
420424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  size_t first_after_slash = after_common_index;
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  while (first_after_slash < path.size() && IsSlash(path[first_after_slash]))
422424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    first_after_slash++;
423424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
424424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dest->assign("//");  // Result is source root relative.
425424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dest->append(&path.data()[first_after_slash],
426424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)               path.size() - first_after_slash);
427424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
428424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#else
430424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // On non-Windows this is easy. Since we know both are absolute, just do a
4323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // prefix check.
4333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.substr(0, source_root.size()) == source_root) {
4343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The base may or may not have a trailing slash, so skip all slashes from
4353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // the path after our prefix match.
4363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t first_after_slash = source_root.size();
437a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    while (first_after_slash < path.size() && IsSlash(path[first_after_slash]))
4383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      first_after_slash++;
4393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
440424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    dest->assign("//");  // Result is source root relative.
4413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dest->append(&path.data()[first_after_slash],
4423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 path.size() - first_after_slash);
4433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
4443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return false;
446424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
4473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
449d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstd::string InvertDir(const SourceDir& path) {
450d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string value = path.value();
451d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (value.empty())
452d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return std::string();
453d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
454d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DCHECK(value[0] == '/');
455d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t begin_index = 1;
456d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
457d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // If the input begins with two slashes, skip over both (this is a
458a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // source-relative dir). These must be forward slashes only.
459d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (value.size() > 1 && value[1] == '/')
460d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    begin_index = 2;
461d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
462d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string ret;
463d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = begin_index; i < value.size(); i++) {
464a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(value[i]))
465d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      ret.append("../");
466d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
467d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
468d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
469d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
470d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NormalizePath(std::string* path) {
471d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  char* pathbuf = path->empty() ? NULL : &(*path)[0];
472d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
473d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // top_index is the first character we can modify in the path. Anything
474d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // before this indicates where the path is relative to.
475d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t top_index = 0;
476d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  bool is_relative = true;
477d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!path->empty() && pathbuf[0] == '/') {
478d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    is_relative = false;
479d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
480d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path->size() > 1 && pathbuf[1] == '/') {
481d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Two leading slashes, this is a path into the source dir.
482d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      top_index = 2;
483d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else {
484d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // One leading slash, this is a system-absolute path.
485d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      top_index = 1;
486d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
487d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
488d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
489d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t dest_i = top_index;
490d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t src_i = top_index; src_i < path->size(); /* nothing */) {
491d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (pathbuf[src_i] == '.') {
492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (src_i == 0 || IsSlash(pathbuf[src_i - 1])) {
493d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Slash followed by a dot, see if it's something special.
494d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        size_t consumed_len;
495d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switch (ClassifyAfterDot(*path, src_i + 1, &consumed_len)) {
496d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case NOT_A_DIRECTORY:
497d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Copy the dot to the output, it means nothing special.
498d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            pathbuf[dest_i++] = pathbuf[src_i++];
499d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            break;
500d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case DIRECTORY_CUR:
501d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Current directory, just skip the input.
502d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            src_i += consumed_len;
503d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            break;
504d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case DIRECTORY_UP:
505d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Back up over previous directory component. If we're already
506d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // at the top, preserve the "..".
507d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            if (dest_i > top_index) {
508d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // The previous char was a slash, remove it.
509d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              dest_i--;
510d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            }
511d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
512d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            if (dest_i == top_index) {
513d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              if (is_relative) {
514d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // We're already at the beginning of a relative input, copy the
515d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // ".." and continue. We need the trailing slash if there was
516d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // one before (otherwise we're at the end of the input).
517d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                pathbuf[dest_i++] = '.';
518d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                pathbuf[dest_i++] = '.';
519d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                if (consumed_len == 3)
520d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  pathbuf[dest_i++] = '/';
521d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
522d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // This also makes a new "root" that we can't delete by going
523d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // up more levels.  Otherwise "../.." would collapse to
524d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // nothing.
525d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                top_index = dest_i;
526d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              }
527d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // Otherwise we're at the beginning of an absolute path. Don't
528d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // allow ".." to go up another level and just eat it.
529d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            } else {
530d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // Just find the previous slash or the beginning of input.
531a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)              while (dest_i > 0 && !IsSlash(pathbuf[dest_i - 1]))
532d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                dest_i--;
533d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            }
534d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            src_i += consumed_len;
535d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        }
536d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      } else {
537d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Dot not preceeded by a slash, copy it literally.
538d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        pathbuf[dest_i++] = pathbuf[src_i++];
539d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
540a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else if (IsSlash(pathbuf[src_i])) {
541a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (src_i > 0 && IsSlash(pathbuf[src_i - 1])) {
542d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Two slashes in a row, skip over it.
543d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        src_i++;
544d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      } else {
545a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        // Just one slash, copy it, normalizing to foward slash.
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        pathbuf[dest_i] = '/';
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        dest_i++;
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        src_i++;
549d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
550d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else {
551d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Input nothing special, just copy it.
552d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      pathbuf[dest_i++] = pathbuf[src_i++];
553d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
554d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
555d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path->resize(dest_i);
556d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
557d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
558d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid ConvertPathToSystem(std::string* path) {
559d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
560d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < path->size(); i++) {
561d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if ((*path)[i] == '/')
562d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      (*path)[i] = '\\';
563d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
564d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
565d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
566d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
56768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string RebaseSourceAbsolutePath(const std::string& input,
56868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                     const SourceDir& dest_dir) {
56968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(input.size() >= 2 && input[0] == '/' && input[1] == '/')
57068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      << "Input to rebase isn't source-absolute: " << input;
57168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(dest_dir.is_source_absolute())
57268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      << "Dir to rebase to isn't source-absolute: " << dest_dir.value();
57368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
57468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string& dest = dest_dir.value();
57568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
57668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Skip the common prefixes of the source and dest as long as they end in
57768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // a [back]slash.
57868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t common_prefix_len = 2;  // The beginning two "//" are always the same.
57968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t max_common_length = std::min(input.size(), dest.size());
58068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (size_t i = common_prefix_len; i < max_common_length; i++) {
581a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(input[i]) && IsSlash(dest[i]))
58268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      common_prefix_len = i + 1;
58368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    else if (input[i] != dest[i])
58468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      break;
58568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
58668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
58768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Invert the dest dir starting from the end of the common prefix.
58868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string ret;
58968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (size_t i = common_prefix_len; i < dest.size(); i++) {
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsSlash(dest[i]))
59168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ret.append("../");
59268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
59368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
59468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Append any remaining unique input.
59568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ret.append(&input[common_prefix_len], input.size() - common_prefix_len);
59668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
59768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If the result is still empty, the paths are the same.
59868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (ret.empty())
59968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ret.push_back('.');
60068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
60168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return ret;
60268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string DirectoryWithNoLastSlash(const SourceDir& dir) {
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (dir.value().empty()) {
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Just keep input the same.
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (dir.value() == "/") {
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign("/.");
611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (dir.value() == "//") {
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign("//.");
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign(dir.value());
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.resize(ret.size() - 1);
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ret;
618f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SourceDir SourceDirForPath(const base::FilePath& source_root,
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           const base::FilePath& path) {
622a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath::StringType> source_comp =
623a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      GetPathComponents(source_root);
624a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<base::FilePath::StringType> path_comp =
625a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      GetPathComponents(path);
626a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
627a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // See if path is inside the source root by looking for each of source root's
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // components at the beginning of path.
629a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_inside_source;
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (path_comp.size() < source_comp.size()) {
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Too small to fit.
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    is_inside_source = false;
633a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
634a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    is_inside_source = true;
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < source_comp.size(); i++) {
636a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (!FilesystemStringsEqual(source_comp[i], path_comp[i])) {
637a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        is_inside_source = false;
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        break;
639a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
640a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
641a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
642a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
643a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string result_str;
644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  size_t initial_path_comp_to_use;
645a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (is_inside_source) {
646a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Construct a source-relative path beginning in // and skip all of the
647a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // shared directories.
648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result_str = "//";
649a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    initial_path_comp_to_use = source_comp.size();
650a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
651a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Not inside source code, construct a system-absolute path.
652a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result_str = "/";
653a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    initial_path_comp_to_use = 0;
654a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
655a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
656a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = initial_path_comp_to_use; i < path_comp.size(); i++) {
657a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result_str.append(FilePathToUTF8(path_comp[i]));
658a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result_str.push_back('/');
659a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
660a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return SourceDir(result_str);
661a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
662a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
663a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root) {
664a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::FilePath cd;
665a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::GetCurrentDirectory(&cd);
666a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return SourceDirForPath(source_root, cd);
667a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
668a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
669cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default) {
670cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // The default toolchain has no subdir.
671cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (is_default)
672cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return std::string();
673cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
674cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // For now just assume the toolchain name is always a valid dir name. We may
675cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // want to clean up the in the future.
676cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return toolchain_label.name() + "/";
677cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
678cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
679f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetToolchainOutputDir(const Settings* settings) {
680f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
681f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
682f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string result = settings->build_settings()->build_dir().value();
683f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!toolchain_subdir.value().empty())
684f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    result.append(toolchain_subdir.value());
685f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
688f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
689cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SourceDir GetToolchainOutputDir(const BuildSettings* build_settings,
690cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                const Label& toolchain_label, bool is_default) {
691cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string result = build_settings->build_dir().value();
692cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  result.append(GetOutputSubdirName(toolchain_label, is_default));
693cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
694cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
695cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
696f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetToolchainGenDir(const Settings* settings) {
697f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
698f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
699f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string result = settings->build_settings()->build_dir().value();
700f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!toolchain_subdir.value().empty())
701f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    result.append(toolchain_subdir.value());
702f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
703f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  result.append("gen/");
704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
705f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
706f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
707cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SourceDir GetToolchainGenDir(const BuildSettings* build_settings,
708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             const Label& toolchain_label, bool is_default) {
709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string result = GetToolchainOutputDir(
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      build_settings, toolchain_label, is_default).value();
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  result.append("gen/");
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
715f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetOutputDirForSourceDir(const Settings* settings,
716f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                   const SourceDir& source_dir) {
717f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SourceDir toolchain = GetToolchainOutputDir(settings);
718f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
719f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
720f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  toolchain.SwapValue(&ret);
721f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ret.append("obj/");
722f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (source_dir.is_source_absolute()) {
7246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // The source dir is source-absolute, so we trim off the two leading
7256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // slashes to append to the toolchain object directory.
7266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ret.append(&source_dir.value()[2], source_dir.value().size() - 2);
7276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
7286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // (Put system-absolute stuff in the root obj directory.)
729f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
730f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &ret);
731f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
732f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
733f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetGenDirForSourceDir(const Settings* settings,
734f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                const SourceDir& source_dir) {
735f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SourceDir toolchain = GetToolchainGenDir(settings);
736f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
737f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
738f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  toolchain.SwapValue(&ret);
739f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
7406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (source_dir.is_source_absolute()) {
7416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // The source dir should be source-absolute, so we trim off the two leading
7426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    // slashes to append to the toolchain object directory.
7436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    DCHECK(source_dir.is_source_absolute());
7446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ret.append(&source_dir.value()[2], source_dir.value().size() - 2);
7456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
7466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // (Put system-absolute stuff in the root gen directory.)
747f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
748f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &ret);
749f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
750f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
751f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetTargetOutputDir(const Target* target) {
752f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetOutputDirForSourceDir(target->settings(), target->label().dir());
753f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
754f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
755f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetTargetGenDir(const Target* target) {
756f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetGenDirForSourceDir(target->settings(), target->label().dir());
757f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
758f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
759f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetCurrentOutputDir(const Scope* scope) {
760f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetOutputDirForSourceDir(scope->settings(), scope->GetSourceDir());
761f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
762f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
763f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetCurrentGenDir(const Scope* scope) {
764f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetGenDirForSourceDir(scope->settings(), scope->GetSourceDir());
765f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
766