mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2025-06-07 00:51:41 +00:00
254 lines
7.1 KiB
C++
254 lines
7.1 KiB
C++
/* Copyright 2015, 2016, Michele Santullo
|
|
* This file is part of "dindexer".
|
|
*
|
|
* "dindexer" 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.
|
|
*
|
|
* "dindexer" 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 "dindexer". If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "pathname.hpp"
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <ciso646>
|
|
#include <iostream>
|
|
#include <cassert>
|
|
|
|
namespace mchlib {
|
|
const std::string PathName::m_empty_str("");
|
|
|
|
namespace {
|
|
std::string get_joint_atoms ( const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight=0 );
|
|
std::size_t calc_join_size ( const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight=0 );
|
|
std::size_t get_adjusted_atom_count ( const StringPool<char>& parPool, std::size_t parSkipRight );
|
|
|
|
std::size_t get_adjusted_atom_count (const StringPool<char>& parPool, std::size_t parSkipRight) {
|
|
const auto orig_atom_count = parPool.size();
|
|
const auto atom_count = (parSkipRight >= orig_atom_count ? 0 : orig_atom_count - parSkipRight);
|
|
return atom_count;
|
|
}
|
|
|
|
std::size_t calc_join_size (const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight) {
|
|
const auto atom_count = get_adjusted_atom_count(parPool, parSkipRight);
|
|
if (not atom_count) {
|
|
if (parPool.empty() and parAbs) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
std::size_t reserve = (parAbs ? 1 : 0);
|
|
for (std::size_t z = 0; z < atom_count; ++z) {
|
|
reserve += parPool[z].size();
|
|
}
|
|
reserve += atom_count - 1;
|
|
return reserve;
|
|
}
|
|
|
|
std::size_t count_grouped (boost::string_view parIn, char parDelim) {
|
|
std::size_t retval = 0;
|
|
char prev = '\0';
|
|
for (auto c : parIn) {
|
|
retval += (parDelim == c and prev != parDelim ? 1 : 0);
|
|
prev = c;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
void split_path (std::vector<boost::string_view>* parOut, boost::string_view parPath) {
|
|
auto from = parPath.begin();
|
|
boost::string_view::const_iterator next;
|
|
const auto end = parPath.end();
|
|
const auto beg = parPath.begin();
|
|
while (end != (next = std::find(from, end, '/'))) {
|
|
if (next != from) {
|
|
parOut->push_back(parPath.substr(from - beg, next - from));
|
|
from = next;
|
|
}
|
|
++from;
|
|
}
|
|
if (next != from) {
|
|
parOut->push_back(parPath.substr(from - beg, next - from));
|
|
}
|
|
}
|
|
|
|
std::string get_joint_atoms (const StringPool<char>& parPool, bool parAbs, std::size_t parSkipRight) {
|
|
const auto reserve = calc_join_size(parPool, parAbs, parSkipRight);
|
|
switch (reserve) {
|
|
case 0:
|
|
//reserve 0 means the resulting string is empty
|
|
return std::string("");
|
|
case 1:
|
|
//when reserve is 1 and we're talking about an absolute path,
|
|
//the resulting string can only be "/"
|
|
if (parAbs) {
|
|
return std::string("/");
|
|
}
|
|
};
|
|
|
|
std::string out;
|
|
out.reserve(reserve);
|
|
const char* slash = (parAbs ? "/" : "");
|
|
const auto atom_count = get_adjusted_atom_count(parPool, parSkipRight);
|
|
for (std::size_t z = 0; z < atom_count; ++z) {
|
|
out += slash;
|
|
const auto& curr_itm = parPool[z];
|
|
out.insert(out.end(), curr_itm.begin(), curr_itm.end());
|
|
slash = "/";
|
|
}
|
|
assert(reserve == out.size());
|
|
return out;
|
|
}
|
|
} //unnamed namespace
|
|
|
|
PathName::PathName (boost::string_view parPath) {
|
|
if (not parPath.empty()) {
|
|
m_absolute = ('/' == parPath.front());
|
|
std::string path(parPath.begin(), parPath.end());
|
|
|
|
const auto count = count_grouped(path, '/');
|
|
const std::size_t trailing = (path.back() == '/' ? 1 : 0);
|
|
const std::size_t absolute = (m_absolute ? 1 : 0);
|
|
const auto res = count + 1 - trailing - absolute;
|
|
std::vector<boost::string_view> atoms;
|
|
atoms.reserve(res);
|
|
split_path(&atoms, path);
|
|
m_pool.insert(atoms, &path);
|
|
}
|
|
else {
|
|
m_original_path = nullptr;
|
|
m_absolute = false;
|
|
}
|
|
}
|
|
|
|
std::string PathName::path() const {
|
|
return get_joint_atoms(m_pool, m_absolute);
|
|
}
|
|
|
|
void PathName::join (const PathName& parOther) {
|
|
m_pool.update(parOther.m_pool);
|
|
}
|
|
|
|
const boost::string_view PathName::operator[] (std::size_t parIndex) const {
|
|
return *(m_pool.begin() + parIndex);
|
|
}
|
|
|
|
std::size_t PathName::atom_count ( void ) const {
|
|
return m_pool.size();
|
|
}
|
|
|
|
void PathName::join (const char* parOther) {
|
|
const std::string src(parOther);
|
|
const boost::string_view ref(src);
|
|
m_pool.insert(ref, &src);
|
|
}
|
|
|
|
void PathName::join (boost::string_view parOther, const std::string* parSource) {
|
|
m_pool.insert(parOther, parSource);
|
|
}
|
|
|
|
PathName make_relative_path (const PathName& parBasePath, const PathName& parOtherPath) {
|
|
if (not parBasePath.is_absolute() and parOtherPath.is_absolute()) {
|
|
return parOtherPath;
|
|
}
|
|
|
|
std::size_t common_atoms = 0;
|
|
{
|
|
const std::size_t shortest = std::min(parOtherPath.atom_count(), parBasePath.atom_count());
|
|
for (std::size_t z = 0; z < shortest; ++z) {
|
|
if (parOtherPath[z] == parBasePath[z]) {
|
|
++common_atoms;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
PathName retval("");
|
|
const auto ellipses_count = parBasePath.atom_count() - common_atoms;
|
|
for (std::size_t z = 0; z < ellipses_count; ++z) {
|
|
retval.join("..");
|
|
}
|
|
|
|
const auto remaining_atoms = parOtherPath.atom_count() - common_atoms;
|
|
for (std::size_t z = 0; z < remaining_atoms; ++z) {
|
|
retval.join(parOtherPath[z + common_atoms], parOtherPath.get_stringref_source(z + common_atoms));
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
const std::string* PathName::get_stringref_source (std::size_t parIndex) const {
|
|
return m_pool.get_stringref_source(parIndex);
|
|
}
|
|
|
|
std::string PathName::dirname() const {
|
|
if (this->atom_count() == 0)
|
|
return std::string();
|
|
|
|
return get_joint_atoms(m_pool, m_absolute, 1);
|
|
}
|
|
|
|
std::ostream& operator<< (std::ostream& parStream, const PathName& parPath) {
|
|
parStream << parPath.path();
|
|
return parStream;
|
|
}
|
|
|
|
const boost::string_view basename (const PathName& parPath) {
|
|
static const char* const empty = "";
|
|
const auto sz = parPath.atom_count();
|
|
if (not sz) {
|
|
return boost::string_view(empty);
|
|
}
|
|
|
|
assert(sz > 0);
|
|
return parPath[sz - 1];
|
|
}
|
|
|
|
PathName& PathName::pop_right() {
|
|
m_pool.pop();
|
|
return *this;
|
|
}
|
|
|
|
bool PathName::operator!= (const PathName& parOther) const {
|
|
const auto count = atom_count();
|
|
if (count != parOther.atom_count()) {
|
|
return true;
|
|
}
|
|
|
|
for (std::size_t z = 0; z < count; ++z) {
|
|
if ((*this)[z] != parOther[z]) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool PathName::operator== (const PathName& parOther) const {
|
|
const auto count = atom_count();
|
|
if (count != parOther.atom_count()) {
|
|
return false;
|
|
}
|
|
|
|
for (std::size_t z = 0; z < count; ++z) {
|
|
if ((*this)[z] != parOther[z]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::size_t PathName::str_path_size() const {
|
|
return calc_join_size(m_pool, is_absolute());
|
|
}
|
|
} //namespace mchlib
|