| // Copyright 2018 The Bazel Authors. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | #include "src/main/cpp/util/path_platform.h" | 
 |  | 
 | #include <limits.h>  // PATH_MAX | 
 |  | 
 | #include <stdlib.h>  // getenv | 
 | #include <string.h>  // strncmp | 
 | #include <unistd.h>  // access, open, close, fsync | 
 | #include "src/main/cpp/util/errors.h" | 
 | #include "src/main/cpp/util/exit_code.h" | 
 | #include "src/main/cpp/util/file_platform.h" | 
 | #include "src/main/cpp/util/logging.h" | 
 | #include "src/main/cpp/util/path.h" | 
 |  | 
 | namespace blaze_util { | 
 |  | 
 | std::string ConvertPath(const std::string &path) { return path; } | 
 |  | 
 | std::string PathAsJvmFlag(const std::string &path) { return path; } | 
 |  | 
 | bool CompareAbsolutePaths(const std::string &a, const std::string &b) { | 
 |   return a == b; | 
 | } | 
 |  | 
 | std::pair<std::string, std::string> SplitPath(const std::string &path) { | 
 |   size_t pos = path.rfind('/'); | 
 |  | 
 |   // Handle the case with no '/' in 'path'. | 
 |   if (pos == std::string::npos) return std::make_pair("", path); | 
 |  | 
 |   // Handle the case with a single leading '/' in 'path'. | 
 |   if (pos == 0) | 
 |     return std::make_pair(std::string(path, 0, 1), std::string(path, 1)); | 
 |  | 
 |   return std::make_pair(std::string(path, 0, pos), std::string(path, pos + 1)); | 
 | } | 
 |  | 
 | bool IsDevNull(const char *path) { | 
 |   return path != nullptr && *path != 0 && strncmp("/dev/null\0", path, 10) == 0; | 
 | } | 
 |  | 
 | bool IsRootDirectory(const std::string &path) { | 
 |   return path.size() == 1 && path[0] == '/'; | 
 | } | 
 |  | 
 | bool IsRootDirectory(const Path &path) { | 
 |   return IsRootDirectory(path.AsNativePath()); | 
 | } | 
 |  | 
 | bool IsAbsolute(const std::string &path) { | 
 |   return !path.empty() && path[0] == '/'; | 
 | } | 
 |  | 
 | std::string MakeAbsolute(const std::string &path) { | 
 |   if (blaze_util::IsAbsolute(path) || path.empty()) { | 
 |     return path; | 
 |   } | 
 |  | 
 |   return JoinPath(blaze_util::GetCwd(), path); | 
 | } | 
 |  | 
 | std::string ResolveEnvvars(const std::string &path) { | 
 |   std::string result = path; | 
 |   size_t start = 0; | 
 |   while ((start = result.find("${", start)) != std::string::npos) { | 
 |     // Just match to the next } | 
 |     size_t end = result.find('}', start + 1); | 
 |     if (end == std::string::npos) { | 
 |       BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) | 
 |           << "ResolveEnvvars(" << path << "): incomplete variable at position " | 
 |           << start; | 
 |     } | 
 |     // Extract the variable name | 
 |     const std::string name = result.substr(start + 2, end - start - 2); | 
 |     // Get the value from the environment | 
 |     const char *c_value = getenv(name.c_str()); | 
 |     const std::string value = std::string(c_value ? c_value : ""); | 
 |     result.replace(start, end - start + 1, value); | 
 |     start += value.length(); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | std::string MakeAbsoluteAndResolveEnvvars(const std::string &path) { | 
 |   return MakeAbsolute(ResolveEnvvars(path)); | 
 | } | 
 |  | 
 | static std::string NormalizeAbsPath(const std::string &p) { | 
 |   if (p.empty() || p[0] != '/') { | 
 |     return ""; | 
 |   } | 
 |   typedef std::string::size_type index; | 
 |   std::vector<std::pair<index, index> > segments; | 
 |   for (index s = 0; s < p.size();) { | 
 |     index e = p.find_first_of('/', s); | 
 |     if (e == std::string::npos) { | 
 |       e = p.size(); | 
 |     } | 
 |     if (e > s) { | 
 |       if (p.compare(s, e - s, "..") == 0) { | 
 |         if (!segments.empty()) { | 
 |           segments.pop_back(); | 
 |         } | 
 |       } else if (p.compare(s, e - s, ".") != 0) { | 
 |         segments.push_back(std::make_pair(s, e - s)); | 
 |       } | 
 |     } | 
 |     s = e + 1; | 
 |   } | 
 |   if (segments.empty()) { | 
 |     return "/"; | 
 |   } else { | 
 |     std::stringstream r; | 
 |     for (const auto &s : segments) { | 
 |       r << "/" << p.substr(s.first, s.second); | 
 |     } | 
 |     if (p[p.size() - 1] == '/') { | 
 |       r << "/"; | 
 |     } | 
 |     return r.str(); | 
 |   } | 
 | } | 
 |  | 
 | std::string TestOnly_NormalizeAbsPath(const std::string &s) { | 
 |   return NormalizeAbsPath(s); | 
 | } | 
 |  | 
 | Path::Path(const std::string &path) | 
 |     : path_(NormalizeAbsPath(MakeAbsolute(path))) {} | 
 |  | 
 | Path::Path(const std::string &path, std::string *errorText) | 
 |     : path_(NormalizeAbsPath(MakeAbsolute(path))) {} | 
 |  | 
 | bool Path::IsNull() const { return path_ == "/dev/null"; } | 
 |  | 
 | bool Path::Contains(const char c) const { | 
 |   return path_.find_first_of(c) != std::string::npos; | 
 | } | 
 |  | 
 | bool Path::Contains(const std::string &s) const { | 
 |   return path_.find(s) != std::string::npos; | 
 | } | 
 |  | 
 | Path Path::GetRelative(const std::string &r) const { | 
 |   return Path(JoinPath(path_, r)); | 
 | } | 
 |  | 
 | Path Path::Canonicalize() const { return Path(MakeCanonical(path_.c_str())); } | 
 |  | 
 | Path Path::GetParent() const { return Path(SplitPath(path_).first); } | 
 |  | 
 | std::string Path::AsPrintablePath() const { return path_; } | 
 |  | 
 | std::string Path::AsJvmArgument() const { return path_; } | 
 |  | 
 | std::string Path::AsCommandLineArgument() const { return path_; } | 
 |  | 
 | }  // namespace blaze_util |