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