Program Listing for File path_util.cpp

Return to documentation for file (src/common/path_util.cpp)

/*
  Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain
  Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany

  This software was partially supported by the
  EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).

  This software was partially supported by the
  ADA-FS project under the SPPEXA project funded by the DFG.

  This file is part of GekkoFS.

  GekkoFS is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  GekkoFS is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with GekkoFS.  If not, see <https://www.gnu.org/licenses/>.

  SPDX-License-Identifier: GPL-3.0-or-later
*/

#include <common/path_util.hpp>

#include <system_error>
#include <cstring>
#include <cassert>

using namespace std;

namespace gkfs::path {

bool
is_relative(const string& path) {
    return (!path.empty()) && (path.front() != separator);
}

bool
is_absolute(const string& path) {
    return (!path.empty()) && (path.front() == separator);
}

bool
has_trailing_slash(const string& path) {
    return (!path.empty()) && (path.back() == separator);
}

string
prepend_path(const string& prefix_path, const char* raw_path) {
    assert(!has_trailing_slash(prefix_path));
    ::size_t raw_len = ::strlen(raw_path);
    string res;
    res.reserve(prefix_path.size() + 1 + raw_len);
    res.append(prefix_path);
    res.push_back(separator);
    res.append(raw_path, raw_len);
    return res;
}

::vector<string>
split_path(const string& path) {
    ::vector<string> tokens;
    size_t start = string::npos;
    size_t end = (path.front() != separator) ? 0 : 1;
    while(end != string::npos && end < path.size()) {
        start = end;
        end = path.find(separator, start);
        tokens.push_back(path.substr(start, end - start));
        if(end != string::npos) {
            ++end;
        }
    }
    return tokens;
}


string
absolute_to_relative(const string& root_path, const string& absolute_path) {
    assert(is_absolute(root_path));
    assert(is_absolute(absolute_path));
    assert(!has_trailing_slash(root_path));

    auto diff_its = ::mismatch(absolute_path.cbegin(), absolute_path.cend(),
                               root_path.cbegin());
    if(diff_its.second != root_path.cend()) {
        // complete path doesn't start with root_path
        return {};
    }

    // iterator to the starting char of the relative portion of the
    // @absolute_path
    auto rel_it_begin = diff_its.first;
    // iterator to the end of the relative portion of the @absolute_path
    auto rel_it_end = absolute_path.cend();

    // relative path start exactly after the root_path prefix
    assert((size_t) (rel_it_begin - absolute_path.cbegin()) ==
           root_path.size());

    if(rel_it_begin == rel_it_end) {
        // relative path is empty, @absolute_path was equal to @root_path
        return {'/'};
    }

    // remove the trailing slash from relative path
    if(has_trailing_slash(absolute_path) &&
       rel_it_begin !=
               rel_it_end -
                       1) { // the relative path is longer then 1 char ('/')
        --rel_it_end;
    }

    return {rel_it_begin, rel_it_end};
}

string
dirname(const string& path) {
    assert(path.size() > 1 || path.front() == separator);
    assert(path.size() == 1 || !has_trailing_slash(path));

    auto parent_path_size = path.find_last_of(separator);
    assert(parent_path_size != string::npos);
    if(parent_path_size == 0) {
        // parent is '/'
        parent_path_size = 1;
    }
    return path.substr(0, parent_path_size);
}

} // namespace gkfs::path