filesystem_utils.cc revision f2477e01787aa58f445919b809d89e252beef54f
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)
9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/logging.h"
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/strings/string_util.h"
11d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/utf_string_conversions.h"
12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "build/build_config.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/location.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/settings.h"
15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/source_dir.h"
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochenum DotDisposition {
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is just part of a filename and is not special.
21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  NOT_A_DIRECTORY,
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is the current directory.
24d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DIRECTORY_CUR,
25d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The given dot is the first of a double dot that should take us up one.
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DIRECTORY_UP
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch};
29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// When we find a dot, this function is called with the character following
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// that dot to see what it is. The return value indicates what type this dot is
32d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// (see above). This code handles the case where the dot is at the end of the
33d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// input.
34d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch//
35d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// |*consumed_len| will contain the number of characters in the input that
36d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// express what we found.
37d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochDotDisposition ClassifyAfterDot(const std::string& path,
38d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                size_t after_dot,
39d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                size_t* consumed_len) {
40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (after_dot == path.size()) {
41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Single dot at the end.
42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *consumed_len = 1;
43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return DIRECTORY_CUR;
44d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
45d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (path[after_dot] == '/') {
46d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Single dot followed by a slash.
47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *consumed_len = 2;  // Consume the slash
48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return DIRECTORY_CUR;
49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (path[after_dot] == '.') {
52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Two dots.
53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (after_dot + 1 == path.size()) {
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Double dot at the end.
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      *consumed_len = 2;
56d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return DIRECTORY_UP;
57d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
58d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path[after_dot + 1] == '/') {
59d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Double dot folowed by a slash.
60d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      *consumed_len = 3;
61d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return DIRECTORY_UP;
62d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
63d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
64d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
65d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The dots are followed by something else, not a directory.
66d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  *consumed_len = 1;
67d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return NOT_A_DIRECTORY;
68d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
69d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_WIN)
71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)inline char NormalizeWindowsPathChar(char c) {
72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (c == '/')
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return '\\';
74424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return base::ToLowerASCII(c);
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
76424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Attempts to do a case and slash-insensitive comparison of two 8-bit Windows
78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// paths.
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool AreAbsoluteWindowsPathsEqual(const base::StringPiece& a,
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                  const base::StringPiece& b) {
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (a.size() != b.size())
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // For now, just do a case-insensitive ASCII comparison. We could convert to
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // UTF-16 and use ICU if necessary. Or maybe base::strcasecmp is good enough?
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  for (size_t i = 0; i < a.size(); i++) {
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (NormalizeWindowsPathChar(a[i]) != NormalizeWindowsPathChar(b[i]))
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool DoesBeginWindowsDriveLetter(const base::StringPiece& path) {
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (path.size() < 3)
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check colon first, this will generally fail fastest.
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (path[1] != ':')
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Check drive letter
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!((path[0] >= 'A' && path[0] <= 'Z') ||
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)         path[0] >= 'a' && path[0] <= 'z'))
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (path[2] != '/' && path[2] != '\\')
107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace
113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
114d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochSourceFileType GetSourceFileType(const SourceFile& file,
115d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                 Settings::TargetOS os) {
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  base::StringPiece extension = FindExtension(&file.value());
117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "cc" || extension == "cpp" || extension == "cxx")
118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_CC;
119d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "h")
120d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_H;
121d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension == "c")
122d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return SOURCE_C;
123d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
124d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (os) {
125d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Settings::MAC:
126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (extension == "m")
127d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        return SOURCE_M;
128d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (extension == "mm")
129d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        return SOURCE_MM;
130d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
131d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
132d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Settings::WIN:
133d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (extension == "rc")
134d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        return SOURCE_RC;
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // TODO(brettw) asm files.
136d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
137d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
138d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
139d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
141d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (os != Settings::WIN) {
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (extension == "S")
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return SOURCE_S;
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
147d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return SOURCE_UNKNOWN;
148d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
149d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst char* GetExtensionForOutputType(Target::OutputType type,
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                      Settings::TargetOS os) {
152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (os) {
1532385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    case Settings::MAC:
1542385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      switch (type) {
1552385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::EXECUTABLE:
1562385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "";
1572385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::SHARED_LIBRARY:
1582385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "dylib";
1592385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        case Target::STATIC_LIBRARY:
1602385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          return "a";
1612385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch        default:
1622385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          NOTREACHED();
1632385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      }
1642385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      break;
1652385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Settings::WIN:
167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (type) {
168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::EXECUTABLE:
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "exe";
170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::SHARED_LIBRARY:
171d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "dll.lib";  // Extension of import library.
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Target::STATIC_LIBRARY:
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return "lib";
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        default:
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          NOTREACHED();
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case Settings::LINUX:
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      switch (type) {
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::EXECUTABLE:
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "";
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::SHARED_LIBRARY:
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "so";
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        case Target::STATIC_LIBRARY:
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          return "a";
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          NOTREACHED();
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
192d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
193d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      NOTREACHED();
194d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
195d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return "";
196d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
197d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
19868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string FilePathToUTF8(const base::FilePath::StringType& str) {
199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
20068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return WideToUTF8(str);
201d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#else
20268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return str;
203d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
204d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
206d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::FilePath UTF8ToFilePath(const base::StringPiece& sp) {
207d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::FilePath(UTF8ToWide(sp));
209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#else
210d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::FilePath(sp.as_string());
211d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
212d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
213d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochsize_t FindExtensionOffset(const std::string& path) {
215d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (int i = static_cast<int>(path.size()); i >= 0; i--) {
216d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path[i] == '/')
217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
218d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path[i] == '.')
219d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return i + 1;
220d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
221d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return std::string::npos;
222d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
223d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
224d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindExtension(const std::string* path) {
225d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t extension_offset = FindExtensionOffset(*path);
226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension_offset == std::string::npos)
227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&path->data()[extension_offset],
229d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           path->size() - extension_offset);
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochsize_t FindFilenameOffset(const std::string& path) {
233d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (int i = static_cast<int>(path.size()) - 1; i >= 0; i--) {
234d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path[i] == '/')
235d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return i + 1;
236d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
237d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return 0;  // No filename found means everything was the filename.
238d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
239d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindFilename(const std::string* path) {
241d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (filename_offset == 0)
243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece(*path);  // Everything is the file name.
244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&(*path).data()[filename_offset],
245d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           path->size() - filename_offset);
246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
247d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindFilenameNoExtension(const std::string* path) {
249d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (path->empty())
250d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
251d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
252d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t extension_offset = FindExtensionOffset(*path);
253d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
254d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t name_len;
255d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (extension_offset == std::string::npos)
256d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    name_len = path->size() - filename_offset;
257d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  else
258d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    name_len = extension_offset - filename_offset - 1;
259d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
260d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(&(*path).data()[filename_offset], name_len);
261d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
262d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
263d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid RemoveFilename(std::string* path) {
264d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path->resize(FindFilenameOffset(*path));
265d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
266d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
267d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool EndsWithSlash(const std::string& s) {
268d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return !s.empty() && s[s.size() - 1] == '/';
269d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
270d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
271d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbase::StringPiece FindDir(const std::string* path) {
272d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t filename_offset = FindFilenameOffset(*path);
273d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (filename_offset == 0u)
274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return base::StringPiece();
275d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return base::StringPiece(path->data(), filename_offset);
276d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
277d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
278d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool EnsureStringIsInOutputDir(const SourceDir& dir,
279d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               const std::string& str,
280d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               const Value& originating,
281d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                               Err* err) {
282d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // The last char of the dir will be a slash. We don't care if the input ends
283d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // in a slash or not, so just compare up until there.
284d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  //
285d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // This check will be wrong for all proper prefixes "e.g. "/output" will
286d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // match "/out" but we don't really care since this is just a sanity check.
287d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string& dir_str = dir.value();
288d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (str.compare(0, dir_str.length() - 1, dir_str, 0, dir_str.length() - 1)
289d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      != 0) {
290d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *err = Err(originating, "File not inside output directory.",
291d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "The given file should be in the output directory. Normally you would "
292d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "specify\n\"$target_output_dir/foo\" or "
293d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "\"$target_gen_dir/foo\". I interpreted this as\n\""
294d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        + str + "\".");
295d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return false;
296d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
297d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return true;
298d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
299d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
3003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool IsPathAbsolute(const base::StringPiece& path) {
3013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.empty())
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path[0] != '/') {
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_WIN)
3063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Check for Windows system paths like "C:\foo".
3073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (path.size() > 2 &&
3083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        path[1] == ':' && (path[2] == '/' || path[2] == '\\'))
3093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return true;
3103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;  // Doesn't begin with a slash, is relative.
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.size() > 1 && path[1] == '/')
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;  // Double slash at the beginning means source-relative.
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool MakeAbsolutePathRelativeIfPossible(const base::StringPiece& source_root,
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        const base::StringPiece& path,
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                        std::string* dest) {
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(IsPathAbsolute(source_root));
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(IsPathAbsolute(path));
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dest->clear();
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (source_root.size() > path.size())
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;  // The source root is longer: the path can never be inside.
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_WIN)
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Source root should be canonical on Windows.
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(source_root.size() > 2 && source_root[0] != '/' &&
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         source_root[1] == ':' && source_root[2] =='\\');
335424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
336424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  size_t after_common_index = std::string::npos;
337424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (DoesBeginWindowsDriveLetter(path)) {
338424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Handle "C:\foo"
339424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (AreAbsoluteWindowsPathsEqual(source_root,
340424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                     path.substr(0, source_root.size())))
341424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      after_common_index = source_root.size();
342424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
343424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
344424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else if (path[0] == '/' && source_root.size() <= path.size() - 1 &&
345424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)             DoesBeginWindowsDriveLetter(path.substr(1))) {
346424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Handle "/C:/foo"
347424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (AreAbsoluteWindowsPathsEqual(source_root,
348424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                     path.substr(1, source_root.size())))
349424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      after_common_index = source_root.size() + 1;
350424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
351424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return false;
352424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
353424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
354424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
355424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
356424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // If we get here, there's a match and after_common_index identifies the
357424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // part after it.
358424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
359424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // The base may or may not have a trailing slash, so skip all slashes from
360424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // the path after our prefix match.
361424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  size_t first_after_slash = after_common_index;
362424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  while (first_after_slash < path.size() &&
363424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)         (path[first_after_slash] == '/' || path[first_after_slash] == '\\'))
364424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    first_after_slash++;
365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
366424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dest->assign("//");  // Result is source root relative.
367424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  dest->append(&path.data()[first_after_slash],
368424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)               path.size() - first_after_slash);
369424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return true;
370424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#else
372424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // On non-Windows this is easy. Since we know both are absolute, just do a
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // prefix check.
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (path.substr(0, source_root.size()) == source_root) {
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The base may or may not have a trailing slash, so skip all slashes from
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // the path after our prefix match.
3783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    size_t first_after_slash = source_root.size();
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    while (first_after_slash < path.size() && path[first_after_slash] == '/')
3803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      first_after_slash++;
3813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
382424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    dest->assign("//");  // Result is source root relative.
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    dest->append(&path.data()[first_after_slash],
3843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 path.size() - first_after_slash);
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
3863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return false;
388424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
3893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
391d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstd::string InvertDir(const SourceDir& path) {
392d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const std::string value = path.value();
393d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (value.empty())
394d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return std::string();
395d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
396d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DCHECK(value[0] == '/');
397d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t begin_index = 1;
398d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
399d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // If the input begins with two slashes, skip over both (this is a
400d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // source-relative dir).
401d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (value.size() > 1 && value[1] == '/')
402d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    begin_index = 2;
403d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
404d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string ret;
405d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = begin_index; i < value.size(); i++) {
406d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (value[i] == '/')
407d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      ret.append("../");
408d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
409d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
410d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
411d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
412d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid NormalizePath(std::string* path) {
413d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  char* pathbuf = path->empty() ? NULL : &(*path)[0];
414d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
415d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // top_index is the first character we can modify in the path. Anything
416d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // before this indicates where the path is relative to.
417d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t top_index = 0;
418d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  bool is_relative = true;
419d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!path->empty() && pathbuf[0] == '/') {
420d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    is_relative = false;
421d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
422d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (path->size() > 1 && pathbuf[1] == '/') {
423d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Two leading slashes, this is a path into the source dir.
424d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      top_index = 2;
425d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else {
426d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // One leading slash, this is a system-absolute path.
427d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      top_index = 1;
428d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
429d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
430d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
431d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  size_t dest_i = top_index;
432d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t src_i = top_index; src_i < path->size(); /* nothing */) {
433d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (pathbuf[src_i] == '.') {
434d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (src_i == 0 || pathbuf[src_i - 1] == '/') {
435d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Slash followed by a dot, see if it's something special.
436d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        size_t consumed_len;
437d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switch (ClassifyAfterDot(*path, src_i + 1, &consumed_len)) {
438d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case NOT_A_DIRECTORY:
439d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Copy the dot to the output, it means nothing special.
440d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            pathbuf[dest_i++] = pathbuf[src_i++];
441d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            break;
442d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case DIRECTORY_CUR:
443d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Current directory, just skip the input.
444d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            src_i += consumed_len;
445d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            break;
446d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          case DIRECTORY_UP:
447d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Back up over previous directory component. If we're already
448d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // at the top, preserve the "..".
449d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            if (dest_i > top_index) {
450d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // The previous char was a slash, remove it.
451d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              dest_i--;
452d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            }
453d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
454d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            if (dest_i == top_index) {
455d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              if (is_relative) {
456d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // We're already at the beginning of a relative input, copy the
457d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // ".." and continue. We need the trailing slash if there was
458d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // one before (otherwise we're at the end of the input).
459d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                pathbuf[dest_i++] = '.';
460d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                pathbuf[dest_i++] = '.';
461d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                if (consumed_len == 3)
462d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  pathbuf[dest_i++] = '/';
463d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
464d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // This also makes a new "root" that we can't delete by going
465d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // up more levels.  Otherwise "../.." would collapse to
466d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                // nothing.
467d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                top_index = dest_i;
468d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              }
469d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // Otherwise we're at the beginning of an absolute path. Don't
470d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // allow ".." to go up another level and just eat it.
471d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            } else {
472d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              // Just find the previous slash or the beginning of input.
473d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              while (dest_i > 0 && pathbuf[dest_i - 1] != '/')
474d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                dest_i--;
475d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            }
476d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            src_i += consumed_len;
477d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        }
478d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      } else {
479d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Dot not preceeded by a slash, copy it literally.
480d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        pathbuf[dest_i++] = pathbuf[src_i++];
481d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
482d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else if (pathbuf[src_i] == '/') {
483d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (src_i > 0 && pathbuf[src_i - 1] == '/') {
484d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Two slashes in a row, skip over it.
485d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        src_i++;
486d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      } else {
487d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // Just one slash, copy it.
488d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        pathbuf[dest_i++] = pathbuf[src_i++];
489d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
490d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    } else {
491d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Input nothing special, just copy it.
492d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      pathbuf[dest_i++] = pathbuf[src_i++];
493d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
494d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
495d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  path->resize(dest_i);
496d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
497d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
498d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid ConvertPathToSystem(std::string* path) {
499d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#if defined(OS_WIN)
500d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < path->size(); i++) {
501d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if ((*path)[i] == '/')
502d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      (*path)[i] = '\\';
503d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
504d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#endif
505d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
506d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
507d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochstd::string PathToSystem(const std::string& path) {
508d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::string ret(path);
509d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ConvertPathToSystem(&ret);
510d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
511d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
512d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string RebaseSourceAbsolutePath(const std::string& input,
51468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                     const SourceDir& dest_dir) {
51568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(input.size() >= 2 && input[0] == '/' && input[1] == '/')
51668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      << "Input to rebase isn't source-absolute: " << input;
51768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  CHECK(dest_dir.is_source_absolute())
51868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      << "Dir to rebase to isn't source-absolute: " << dest_dir.value();
51968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
52068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const std::string& dest = dest_dir.value();
52168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
52268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Skip the common prefixes of the source and dest as long as they end in
52368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // a [back]slash.
52468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t common_prefix_len = 2;  // The beginning two "//" are always the same.
52568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t max_common_length = std::min(input.size(), dest.size());
52668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (size_t i = common_prefix_len; i < max_common_length; i++) {
52768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if ((input[i] == '/' || input[i] == '\\') &&
52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        (dest[i] == '/' || dest[i] == '\\'))
52968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      common_prefix_len = i + 1;
53068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    else if (input[i] != dest[i])
53168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      break;
53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Invert the dest dir starting from the end of the common prefix.
53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string ret;
53668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (size_t i = common_prefix_len; i < dest.size(); i++) {
53768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (dest[i] == '/' || dest[i] == '\\')
53868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      ret.append("../");
53968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
54068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
54168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Append any remaining unique input.
54268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ret.append(&input[common_prefix_len], input.size() - common_prefix_len);
54368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
54468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If the result is still empty, the paths are the same.
54568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (ret.empty())
54668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ret.push_back('.');
54768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
54868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return ret;
54968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string DirectoryWithNoLastSlash(const SourceDir& dir) {
552f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
553f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
554f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (dir.value().empty()) {
555f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Just keep input the same.
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (dir.value() == "/") {
557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign("/.");
558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else if (dir.value() == "//") {
559f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign("//.");
560f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  } else {
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.assign(dir.value());
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ret.resize(ret.size() - 1);
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return ret;
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetToolchainOutputDir(const Settings* settings) {
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string result = settings->build_settings()->build_dir().value();
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!toolchain_subdir.value().empty())
572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    result.append(toolchain_subdir.value());
573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetToolchainGenDir(const Settings* settings) {
578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const OutputFile& toolchain_subdir = settings->toolchain_output_subdir();
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string result = settings->build_settings()->build_dir().value();
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!toolchain_subdir.value().empty())
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    result.append(toolchain_subdir.value());
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  result.append("gen/");
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &result);
586f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
587f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
588f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetOutputDirForSourceDir(const Settings* settings,
589f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                   const SourceDir& source_dir) {
590f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SourceDir toolchain = GetToolchainOutputDir(settings);
591f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
592f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
593f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  toolchain.SwapValue(&ret);
594f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ret.append("obj/");
595f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
596f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The source dir should be source-absolute, so we trim off the two leading
597f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // slashes to append to the toolchain object directory.
598f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(source_dir.is_source_absolute());
599f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ret.append(&source_dir.value()[2], source_dir.value().size() - 2);
600f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
601f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &ret);
602f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
603f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetGenDirForSourceDir(const Settings* settings,
605f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                const SourceDir& source_dir) {
606f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  SourceDir toolchain = GetToolchainGenDir(settings);
607f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string ret;
609f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  toolchain.SwapValue(&ret);
610f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
611f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The source dir should be source-absolute, so we trim off the two leading
612f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // slashes to append to the toolchain object directory.
613f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(source_dir.is_source_absolute());
614f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ret.append(&source_dir.value()[2], source_dir.value().size() - 2);
615f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
616f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return SourceDir(SourceDir::SWAP_IN, &ret);
617f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
618f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
619f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetTargetOutputDir(const Target* target) {
620f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetOutputDirForSourceDir(target->settings(), target->label().dir());
621f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
623f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetTargetGenDir(const Target* target) {
624f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetGenDirForSourceDir(target->settings(), target->label().dir());
625f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
626f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
627f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetCurrentOutputDir(const Scope* scope) {
628f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetOutputDirForSourceDir(scope->settings(), scope->GetSourceDir());
629f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
630f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
631f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SourceDir GetCurrentGenDir(const Scope* scope) {
632f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return GetGenDirForSourceDir(scope->settings(), scope->GetSourceDir());
633f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
634