• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "tools/gn/path_output.h"
6 
7 #include "build/build_config.h"
8 #include "tools/gn/filesystem_utils.h"
9 #include "tools/gn/output_file.h"
10 #include "tools/gn/string_utils.h"
11 
PathOutput(const SourceDir & current_dir,EscapingMode escaping)12 PathOutput::PathOutput(const SourceDir& current_dir, EscapingMode escaping)
13     : current_dir_(current_dir) {
14   CHECK(current_dir.is_source_absolute())
15       << "Currently this only supports writing to output directories inside "
16          "the source root. There needs to be some tweaks to PathOutput to make "
17          "doing this work correctly.";
18   inverse_current_dir_ = InvertDir(current_dir_);
19 
20   options_.mode = escaping;
21 }
22 
~PathOutput()23 PathOutput::~PathOutput() {
24 }
25 
WriteFile(std::ostream & out,const SourceFile & file) const26 void PathOutput::WriteFile(std::ostream& out, const SourceFile& file) const {
27   WritePathStr(out, file.value());
28 }
29 
WriteDir(std::ostream & out,const SourceDir & dir,DirSlashEnding slash_ending) const30 void PathOutput::WriteDir(std::ostream& out,
31                           const SourceDir& dir,
32                           DirSlashEnding slash_ending) const {
33   if (dir.value() == "/") {
34     // Writing system root is always a slash (this will normally only come up
35     // on Posix systems).
36     if (slash_ending == DIR_NO_LAST_SLASH)
37       out << "/.";
38     else
39       out << "/";
40   } else if (dir.value() == "//") {
41     // Writing out the source root.
42     if (slash_ending == DIR_NO_LAST_SLASH) {
43       // The inverse_current_dir_ will contain a [back]slash at the end, so we
44       // can't just write it out.
45       if (inverse_current_dir_.empty()) {
46         out << ".";
47       } else {
48         out.write(inverse_current_dir_.c_str(),
49                   inverse_current_dir_.size() - 1);
50       }
51     } else {
52       if (inverse_current_dir_.empty())
53         out << "./";
54       else
55         out << inverse_current_dir_;
56     }
57   } else if (dir == current_dir_) {
58     // Writing the same directory. This needs special handling here since
59     // we need to output something else other than the input.
60     if (slash_ending == DIR_INCLUDE_LAST_SLASH)
61       out << "./";
62     else
63       out << ".";
64   } else if (slash_ending == DIR_INCLUDE_LAST_SLASH) {
65     WritePathStr(out, dir.value());
66   } else {
67     // DIR_NO_LAST_SLASH mode, just trim the last char.
68     WritePathStr(out, base::StringPiece(dir.value().data(),
69                                         dir.value().size() - 1));
70   }
71 }
72 
WriteFile(std::ostream & out,const OutputFile & file) const73 void PathOutput::WriteFile(std::ostream& out, const OutputFile& file) const {
74   // Here we assume that the path is already preprocessed.
75   EscapeStringToStream(out, file.value(), options_);
76 }
77 
WriteFile(std::ostream & out,const base::FilePath & file) const78 void PathOutput::WriteFile(std::ostream& out,
79                            const base::FilePath& file) const {
80   // Assume native file paths are always absolute.
81   EscapeStringToStream(out, FilePathToUTF8(file), options_);
82 }
83 
WriteSourceRelativeString(std::ostream & out,const base::StringPiece & str) const84 void PathOutput::WriteSourceRelativeString(
85     std::ostream& out,
86     const base::StringPiece& str) const {
87   if (options_.mode == ESCAPE_NINJA_COMMAND) {
88     // Shell escaping needs an intermediate string since it may end up
89     // quoting the whole thing.
90     std::string intermediate;
91     intermediate.reserve(inverse_current_dir_.size() + str.size());
92     intermediate.assign(inverse_current_dir_.c_str(),
93                         inverse_current_dir_.size());
94     intermediate.append(str.data(), str.size());
95 
96     EscapeStringToStream(out,
97         base::StringPiece(intermediate.c_str(), intermediate.size()),
98         options_);
99   } else {
100     // Ninja (and none) escaping can avoid the intermediate string and
101     // reprocessing of the inverse_current_dir_.
102     out << inverse_current_dir_;
103     EscapeStringToStream(out, str, options_);
104   }
105 }
106 
WritePathStr(std::ostream & out,const base::StringPiece & str) const107 void PathOutput::WritePathStr(std::ostream& out,
108                               const base::StringPiece& str) const {
109   DCHECK(str.size() > 0 && str[0] == '/');
110 
111   if (str.substr(0, current_dir_.value().size()) ==
112       base::StringPiece(current_dir_.value())) {
113     // The current dir is a prefix of the output file, so we can strip the
114     // prefix and write out the result.
115     EscapeStringToStream(out, str.substr(current_dir_.value().size()),
116                          options_);
117   } else if (str.size() >= 2 && str[1] == '/') {
118     WriteSourceRelativeString(out, str.substr(2));
119   } else {
120     // Input begins with one slash, don't write the current directory since
121     // it's system-absolute.
122 #if defined(OS_WIN)
123     // On Windows, trim the leading slash, since the input for absolute
124     // paths will look like "/C:/foo/bar.txt".
125     EscapeStringToStream(out, str.substr(1), options_);
126 #else
127     EscapeStringToStream(out, str, options_);
128 #endif
129   }
130 }
131