- add sources.
[platform/framework/web/crosswalk.git] / src / tools / gn / path_output.cc
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
12 PathOutput::PathOutput(const SourceDir& current_dir,
13                        EscapingMode escaping,
14                        bool convert_slashes)
15     : current_dir_(current_dir) {
16   CHECK(current_dir.is_source_absolute())
17       << "Currently this only supports writing to output directories inside "
18          "the source root. There needs to be some tweaks to PathOutput to make "
19          "doing this work correctly.";
20   inverse_current_dir_ = InvertDir(current_dir_);
21
22   options_.mode = escaping;
23   options_.convert_slashes = convert_slashes;
24   options_.inhibit_quoting = false;
25
26   if (convert_slashes)
27     ConvertPathToSystem(&inverse_current_dir_);
28 }
29
30 PathOutput::~PathOutput() {
31 }
32
33 void PathOutput::WriteFile(std::ostream& out, const SourceFile& file) const {
34   WritePathStr(out, file.value());
35 }
36
37 void PathOutput::WriteDir(std::ostream& out,
38                           const SourceDir& dir,
39                           DirSlashEnding slash_ending) const {
40   if (dir.value() == "/") {
41     // Writing system root is always a slash (this will normally only come up
42     // on Posix systems).
43     if (slash_ending == DIR_NO_LAST_SLASH)
44       out << "/.";
45     else
46       out << "/";
47   } else if (dir.value() == "//") {
48     // Writing out the source root.
49     if (slash_ending == DIR_NO_LAST_SLASH) {
50       // The inverse_current_dir_ will contain a [back]slash at the end, so we
51       // can't just write it out.
52       if (inverse_current_dir_.empty()) {
53         out << ".";
54       } else {
55         out.write(inverse_current_dir_.c_str(),
56                   inverse_current_dir_.size() - 1);
57       }
58     } else {
59       if (inverse_current_dir_.empty())
60         out << "./";
61       else
62         out << inverse_current_dir_;
63     }
64   } else if (dir == current_dir_) {
65     // Writing the same directory. This needs special handling here since
66     // we need to output something else other than the input.
67     if (slash_ending == DIR_INCLUDE_LAST_SLASH)
68       out << "./";
69     else
70       out << ".";
71   } else if (slash_ending == DIR_INCLUDE_LAST_SLASH) {
72     WritePathStr(out, dir.value());
73   } else {
74     // DIR_NO_LAST_SLASH mode, just trim the last char.
75     WritePathStr(out, base::StringPiece(dir.value().data(),
76                                         dir.value().size() - 1));
77   }
78 }
79
80 void PathOutput::WriteFile(std::ostream& out, const OutputFile& file) const {
81   // Here we assume that the path is already preprocessed.
82   EscapeStringToStream(out, file.value(), options_);
83 }
84
85 void PathOutput::WriteFile(std::ostream& out,
86                            const base::FilePath& file) const {
87   // Assume native file paths are always absolute.
88   EscapeStringToStream(out, FilePathToUTF8(file), options_);
89 }
90
91 void PathOutput::WriteSourceRelativeString(
92     std::ostream& out,
93     const base::StringPiece& str) const {
94   if (options_.mode == ESCAPE_SHELL) {
95     // Shell escaping needs an intermediate string since it may end up
96     // quoting the whole thing. On Windows, the slashes may already be
97     // converted to backslashes in inverse_current_dir_, but we assume that on
98     // Windows the escaper won't try to then escape the preconverted
99     // backslashes and will just pass them, so this is fine.
100     std::string intermediate;
101     intermediate.reserve(inverse_current_dir_.size() + str.size());
102     intermediate.assign(inverse_current_dir_.c_str(),
103                         inverse_current_dir_.size());
104     intermediate.append(str.data(), str.size());
105
106     EscapeStringToStream(out,
107         base::StringPiece(intermediate.c_str(), intermediate.size()),
108         options_);
109   } else {
110     // Ninja (and none) escaping can avoid the intermediate string and
111     // reprocessing of the inverse_current_dir_.
112     out << inverse_current_dir_;
113     EscapeStringToStream(out, str, options_);
114   }
115 }
116
117 void PathOutput::WritePathStr(std::ostream& out,
118                               const base::StringPiece& str) const {
119   DCHECK(str.size() > 0 && str[0] == '/');
120
121   if (str.substr(0, current_dir_.value().size()) ==
122       base::StringPiece(current_dir_.value())) {
123     // The current dir is a prefix of the output file, so we can strip the
124     // prefix and write out the result.
125     EscapeStringToStream(out, str.substr(current_dir_.value().size()),
126                          options_);
127   } else if (str.size() >= 2 && str[1] == '/') {
128     WriteSourceRelativeString(out, str.substr(2));
129   } else {
130     // Input begins with one slash, don't write the current directory since
131     // it's system-absolute.
132 #if defined(OS_WIN)
133     // On Windows, trim the leading slash, since the input for absolute
134     // paths will look like "/C:/foo/bar.txt".
135     EscapeStringToStream(out, str.substr(1), options_);
136 #else
137     EscapeStringToStream(out, str, options_);
138 #endif
139   }
140 }