text: // Copyright 2010 The Goma Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  
  #include "path.h"
  
  #include <stddef.h>
  
  #include "glog/logging.h"
  
  namespace {
  
  // Appends |path2| to |path1|.
  // Assuming |path1| and |path2| are not empty.
  void AppendPath(std::string* path1, absl::string_view path2) {
    DCHECK(!path1->empty());
    DCHECK(!path2.empty());
  
  #ifndef _WIN32
    if (path2[0] == '/') {
      path2.remove_prefix(1);
    }
    if (path1->back() != '/') {
      path1->push_back('/');
    }
  #else
    if (path2[0] == '\\' || path2[0] == '/') {
      path2.remove_prefix(1);
    }
    if (path1->back() != '\\' && path1->back() != '/') {
      path1->push_back('\\');
    }
  #endif
  
    path1->append(path2.begin(), path2.end());
  }
  
  }  // anonymous namespace
  
  namespace file {
  
  namespace internal {
  
  std::string JoinPathIterators(const absl::string_view* begin,
                                const absl::string_view* end,
                                size_t cap) {
    std::string result;
    result.reserve(cap);
  
    while (begin != end) {
      const absl::string_view path = *begin++;
  
      if (path.empty()) {
        continue;
      }
      if (result.empty()) {
        result.append(path.begin(), path.end());
        continue;
      }
      AppendPath(&result, path);
    }
  
    return result;
  }
  
  std::string JoinPathImpl(std::initializer_list<absl::string_view> paths) {
    size_t cap = 0;
    for (const auto& path : paths) {
      cap += path.size() + 1;
    }
  
    return JoinPathIterators(paths.begin(), paths.end(), cap);
  }
  
  std::string JoinPathRespectAbsoluteImpl(
      std::initializer_list<absl::string_view> paths) {
    size_t cap = 0;
    auto start_iter = paths.end();
    for (; start_iter != paths.begin();) {
      --start_iter;
      const auto& path = *start_iter;
      cap += path.size() + 1;
      if (IsAbsolutePath(path)) {
        break;
      }
    }
  
    return JoinPathIterators(start_iter, paths.end(), cap);
  }
  
  }  // namespace internal
  
  absl::string_view Basename(absl::string_view fname) {
  #ifndef _WIN32
    absl::string_view::size_type pos = fname.find_last_of('/');
    // Handle the case with no '/' in |fname|.
    if (pos == absl::string_view::npos)
      return fname;
    return fname.substr(pos + 1);
  #else
    // TODO: support UNC path.
    char name[_MAX_FNAME] = {0};
    char ext[_MAX_EXT] = {0};
    CHECK_EQ(_splitpath_s(std::string(fname).c_str(), nullptr, 0, nullptr, 0,
                          name, sizeof name, ext, sizeof ext),
             0);
    size_t basename_length = strlen(name);
    if (ext[0] == '.')
      basename_length += strlen(ext);
    fname.remove_prefix(fname.length() - basename_length);
    return fname;
  #endif
  }
  
  absl::string_view Dirname(absl::string_view fname) {
  #ifndef _WIN32
    absl::string_view::size_type pos = fname.find_last_of('/');
  
    // Handle the case with no '/' in 'path'.
    if (pos == absl::string_view::npos)
      return fname.substr(0, 0);
  
    // Handle the case with a single leading '/' in 'path'.
    if (pos == 0)
      return fname.substr(0, 1);
  
    return fname.substr(0, pos);
  #else
    // TODO: support UNC path.
    char drive[_MAX_DRIVE] = {0};
    char dir[_MAX_DIR] = {0};
    _splitpath_s(std::string(fname).c_str(), drive, sizeof drive, dir, sizeof dir,
                 nullptr, 0, nullptr, 0);
    const size_t dir_length = strlen(dir);
    size_t dirname_length = strlen(drive) + dir_length;
    // Cut off last '\\' or '/' if dir is not single '\\' or '/'.
    if (dir_length > 1) {
      dirname_length--;
    }
    return fname.substr(0, dirname_length);
  #endif
  }
  
  absl::string_view Stem(absl::string_view fname) {
    absl::string_view path = Basename(fname);
    absl::string_view::size_type pos = path.find_last_of('.');
    if (pos == absl::string_view::npos)
      return path;
    return path.substr(0, pos);
  }
  
  absl::string_view Extension(absl::string_view fname) {
    absl::string_view path = Basename(fname);
    absl::string_view::size_type pos = path.find_last_of('.');
    if (pos == absl::string_view::npos)
      return fname.substr(fname.size());
    return path.substr(pos + 1);
  }
  
  bool IsAbsolutePath(absl::string_view path) {
  #ifndef _WIN32
    return !path.empty() && path[0] == '/';
  #else
    return (!path.empty() && path[0] == '\\') ||
        (!path.empty() && path[0] == '/') ||
        (path.size() > 1 && path[1] == ':');
  #endif
  }
  
  }  // namespace file
  