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/source_dir.h"
      6 
      7 #include "base/logging.h"
      8 #include "tools/gn/filesystem_utils.h"
      9 #include "tools/gn/source_file.h"
     10 
     11 namespace {
     12 
     13 void AssertValueSourceDirString(const std::string& s) {
     14   if (!s.empty()) {
     15     DCHECK(s[0] == '/');
     16     DCHECK(EndsWithSlash(s));
     17   }
     18 }
     19 
     20 }  // namespace
     21 
     22 SourceDir::SourceDir() {
     23 }
     24 
     25 SourceDir::SourceDir(const base::StringPiece& p)
     26     : value_(p.data(), p.size()) {
     27   if (!EndsWithSlash(value_))
     28     value_.push_back('/');
     29   AssertValueSourceDirString(value_);
     30 }
     31 
     32 SourceDir::SourceDir(SwapIn, std::string* s) {
     33   value_.swap(*s);
     34   if (!EndsWithSlash(value_))
     35     value_.push_back('/');
     36   AssertValueSourceDirString(value_);
     37 }
     38 
     39 SourceDir::~SourceDir() {
     40 }
     41 
     42 SourceFile SourceDir::ResolveRelativeFile(
     43     const base::StringPiece& p,
     44     const base::StringPiece& source_root) const {
     45   SourceFile ret;
     46 
     47   // It's an error to resolve an empty string or one that is a directory
     48   // (indicated by a trailing slash) because this is the function that expects
     49   // to return a file.
     50   if (p.empty() || (p.size() > 0 && p[p.size() - 1] == '/'))
     51     return SourceFile();
     52   if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
     53     // Source-relative.
     54     ret.value_.assign(p.data(), p.size());
     55     NormalizePath(&ret.value_);
     56     return ret;
     57   } else if (IsPathAbsolute(p)) {
     58     if (source_root.empty() ||
     59         !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_)) {
     60 #if defined(OS_WIN)
     61       // On Windows we'll accept "C:\foo" as an absolute path, which we want
     62       // to convert to "/C:..." here.
     63       if (p[0] != '/')
     64         ret.value_ = "/";
     65 #endif
     66       ret.value_.append(p.data(), p.size());
     67     }
     68     NormalizePath(&ret.value_);
     69     return ret;
     70   }
     71 
     72   ret.value_.reserve(value_.size() + p.size());
     73   ret.value_.assign(value_);
     74   ret.value_.append(p.data(), p.size());
     75 
     76   NormalizePath(&ret.value_);
     77   return ret;
     78 }
     79 
     80 SourceDir SourceDir::ResolveRelativeDir(
     81     const base::StringPiece& p,
     82     const base::StringPiece& source_root) const {
     83   SourceDir ret;
     84 
     85   if (p.empty())
     86     return ret;
     87   if (p.size() >= 2 && p[0] == '/' && p[1] == '/') {
     88     // Source-relative.
     89     ret.value_.assign(p.data(), p.size());
     90     if (!EndsWithSlash(ret.value_))
     91       ret.value_.push_back('/');
     92     NormalizePath(&ret.value_);
     93     return ret;
     94   } else if (IsPathAbsolute(p)) {
     95     if (source_root.empty() ||
     96         !MakeAbsolutePathRelativeIfPossible(source_root, p, &ret.value_)) {
     97 #if defined(OS_WIN)
     98       if (p[0] != '/')  // See the file case for why we do this check.
     99         ret.value_ = "/";
    100 #endif
    101       ret.value_.append(p.data(), p.size());
    102     }
    103     NormalizePath(&ret.value_);
    104     if (!EndsWithSlash(ret.value_))
    105       ret.value_.push_back('/');
    106     return ret;
    107   }
    108 
    109   ret.value_.reserve(value_.size() + p.size());
    110   ret.value_.assign(value_);
    111   ret.value_.append(p.data(), p.size());
    112 
    113   NormalizePath(&ret.value_);
    114   if (!EndsWithSlash(ret.value_))
    115     ret.value_.push_back('/');
    116   AssertValueSourceDirString(ret.value_);
    117 
    118   return ret;
    119 }
    120 
    121 base::FilePath SourceDir::Resolve(const base::FilePath& source_root) const {
    122   if (is_null())
    123     return base::FilePath();
    124 
    125   std::string converted;
    126   if (is_system_absolute()) {
    127     if (value_.size() > 2 && value_[2] == ':') {
    128       // Windows path, strip the leading slash.
    129       converted.assign(&value_[1], value_.size() - 1);
    130     } else {
    131       converted.assign(value_);
    132     }
    133     return base::FilePath(UTF8ToFilePath(converted));
    134   }
    135 
    136   // String the double-leading slash for source-relative paths.
    137   converted.assign(&value_[2], value_.size() - 2);
    138   return source_root.Append(UTF8ToFilePath(converted))
    139       .NormalizePathSeparatorsTo('/');
    140 }
    141 
    142 void SourceDir::SwapValue(std::string* v) {
    143   value_.swap(*v);
    144   AssertValueSourceDirString(value_);
    145 }
    146