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 inverse_current_dir_ = InvertDir(current_dir_); 17 18 options_.mode = escaping; 19 options_.convert_slashes = convert_slashes; 20 options_.inhibit_quoting = false; 21 22 if (convert_slashes) 23 ConvertPathToSystem(&inverse_current_dir_); 24 } 25 26 PathOutput::~PathOutput() { 27 } 28 29 void PathOutput::WriteFile(std::ostream& out, const SourceFile& file) const { 30 WritePathStr(out, file.value()); 31 } 32 33 void PathOutput::WriteDir(std::ostream& out, 34 const SourceDir& dir, 35 DirSlashEnding slash_ending) const { 36 if (dir.value() == "/") { 37 // Writing system root is always a slash (this will normally only come up 38 // on Posix systems). 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 (slash_ending == DIR_INCLUDE_LAST_SLASH) { 58 WritePathStr(out, dir.value()); 59 } else { 60 // DIR_NO_LAST_SLASH mode, just trim the last char. 61 WritePathStr(out, base::StringPiece(dir.value().data(), 62 dir.value().size() - 1)); 63 } 64 } 65 66 void PathOutput::WriteFile(std::ostream& out, const OutputFile& file) const { 67 // Here we assume that the path is already preprocessed. 68 EscapeStringToStream(out, file.value(), options_); 69 } 70 71 void PathOutput::WriteSourceRelativeString( 72 std::ostream& out, 73 const base::StringPiece& str) const { 74 // Input begins with two slashes, is relative to source root. Strip off 75 // the two slashes when cat-ing it. 76 if (options_.mode == ESCAPE_SHELL) { 77 // Shell escaping needs an intermediate string since it may end up 78 // quoting the whole thing. On Windows, the slashes may already be 79 // converted to backslashes in inverse_current_dir_, but we assume that on 80 // Windows the escaper won't try to then escape the preconverted 81 // backslashes and will just pass them, so this is fine. 82 std::string intermediate; 83 intermediate.reserve(inverse_current_dir_.size() + str.size()); 84 intermediate.assign(inverse_current_dir_.c_str(), 85 inverse_current_dir_.size()); 86 intermediate.append(str.data(), str.size()); 87 88 EscapeStringToStream(out, 89 base::StringPiece(intermediate.c_str(), intermediate.size()), 90 options_); 91 } else { 92 // Ninja (and none) escaping can avoid the intermediate string and 93 // reprocessing of the inverse_current_dir_. 94 out << inverse_current_dir_; 95 EscapeStringToStream(out, str, options_); 96 } 97 } 98 99 void PathOutput::WritePathStr(std::ostream& out, 100 const base::StringPiece& str) const { 101 DCHECK(str.size() > 0 && str[0] == '/'); 102 103 if (str.size() >= 2 && str[1] == '/') { 104 WriteSourceRelativeString(out, str.substr(2)); 105 } else { 106 // Input begins with one slash, don't write the current directory since 107 // it's system-absolute. 108 #if defined(OS_WIN) 109 // On Windows, trim the leading slash, since the input for absolute 110 // paths will look like "/C:/foo/bar.txt". 111 EscapeStringToStream(out, str.substr(1), options_); 112 #else 113 EscapeStringToStream(out, str, options_); 114 #endif 115 } 116 } 117