Home | History | Annotate | Download | only in gn
      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