reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

path.cpp (5981B)


      1 /* ReaPack: Package manager for REAPER
      2  * Copyright (C) 2015-2025  Christian Fillion
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU Lesser General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #include "path.hpp"
     19 
     20 #include <algorithm>
     21 #include <boost/range/adaptor/reversed.hpp>
     22 #include <vector>
     23 
     24 static constexpr char UNIX_SEPARATOR = '/';
     25 
     26 #ifndef _WIN32
     27 static constexpr char NATIVE_SEPARATOR = UNIX_SEPARATOR;
     28 #else
     29 #include <windows.h> // MAX_PATH
     30 static constexpr char NATIVE_SEPARATOR = '\\';
     31 #endif
     32 
     33 static constexpr const char *DOT = ".";
     34 static constexpr const char *DOTDOT = "..";
     35 
     36 const Path Path::DATA("ReaPack");
     37 const Path Path::CACHE = Path::DATA + "cache";
     38 const Path Path::CONFIG("reapack.ini");
     39 const Path Path::REGISTRY = Path::DATA + "registry.db";
     40 
     41 Path Path::s_root;
     42 
     43 static std::vector<std::string> Split(const std::string &input, int *attributes)
     44 {
     45   std::vector<std::string> list;
     46   *attributes = 0;
     47 
     48   size_t last = 0;
     49 
     50   while(last < input.size()) {
     51     const size_t pos = input.find_first_of("\\/", last);
     52 
     53     std::string part;
     54 
     55     if(pos == std::string::npos)
     56       part = input.substr(last);
     57     else if(last + pos == 0) {
     58 #ifndef _WIN32
     59       *attributes |= Path::Absolute;
     60 #endif
     61       last++;
     62       continue;
     63     }
     64     else if(last == pos) {
     65 #ifdef _WIN32
     66       if(pos == 1)
     67         *attributes |= Path::UNC | Path::Absolute;
     68 #endif
     69       last++;
     70       continue;
     71     }
     72     else
     73       part = input.substr(last, pos - last);
     74 
     75 #ifdef _WIN32
     76     if(list.empty() && part.size() == 2 && part[1] == ':' && isalpha(part[0]))
     77       *attributes |= Path::Absolute;
     78 #endif
     79 
     80     if(part != DOT)
     81       list.push_back(part);
     82 
     83     last += part.size() + 1;
     84   }
     85 
     86   return list;
     87 }
     88 
     89 Path::Path(const std::string &path) : m_attributes{}
     90 {
     91   append(path);
     92 }
     93 
     94 void Path::append(const std::string &input, const bool traversal)
     95 {
     96   if(input.empty())
     97     return;
     98 
     99   int attributes;
    100   const auto &parts = Split(input, &attributes);
    101 
    102   if(m_parts.empty() && attributes)
    103     m_attributes = attributes;
    104 
    105   for(const std::string &part : parts) {
    106     if(part == DOTDOT) {
    107       if(traversal)
    108         removeLast();
    109     }
    110     else
    111       m_parts.push_back(part);
    112   }
    113 }
    114 
    115 void Path::append(const Path &o)
    116 {
    117   if(m_parts.empty())
    118     m_attributes = o.attributes();
    119 
    120   m_parts.insert(m_parts.end(), o.m_parts.begin(), o.m_parts.end());
    121 }
    122 
    123 void Path::clear()
    124 {
    125   m_parts.clear();
    126 }
    127 
    128 void Path::remove(const size_t pos, size_t count)
    129 {
    130   if(pos > size())
    131     return;
    132   else if(pos + count > size())
    133     count = size() - pos;
    134 
    135   auto begin = m_parts.begin();
    136   std::advance(begin, pos);
    137 
    138   auto end = begin;
    139   std::advance(end, count);
    140 
    141   m_parts.erase(begin, end);
    142 
    143   if(!pos)
    144     m_attributes = 0;
    145 }
    146 
    147 void Path::removeLast()
    148 {
    149   if(!empty())
    150     m_parts.pop_back();
    151 }
    152 
    153 std::string Path::front() const
    154 {
    155   if(empty())
    156     return {};
    157 
    158   return m_parts.front();
    159 }
    160 
    161 std::string Path::basename() const
    162 {
    163   if(empty())
    164     return {};
    165 
    166   return m_parts.back();
    167 }
    168 
    169 Path Path::dirname() const
    170 {
    171   if(empty())
    172     return {};
    173 
    174   Path dir(*this);
    175   dir.removeLast();
    176   return dir;
    177 }
    178 
    179 std::string Path::join(const bool nativeSeparator) const
    180 {
    181   const char sep = nativeSeparator ? NATIVE_SEPARATOR : UNIX_SEPARATOR;
    182 
    183   std::string path;
    184 
    185 #ifndef _WIN32
    186   if(test(Absolute))
    187     path += sep;
    188 #endif
    189 
    190   for(const std::string &part : m_parts) {
    191 #ifdef _WIN32
    192     if(!path.empty())
    193 #else
    194     if(path.size() > test(Absolute))
    195 #endif
    196       path += sep;
    197 
    198     path += part;
    199   }
    200 
    201 #ifdef _WIN32
    202   if(test(Absolute) && path.size() >= MAX_PATH - (8+1+3)) {
    203     path.insert(0, "\\\\?\\");
    204 
    205     if(test(UNC))
    206       path.insert(4, "UNC\\");
    207   }
    208   else if(test(UNC))
    209     path.insert(0, "\\\\");
    210 #endif
    211 
    212   return path;
    213 }
    214 
    215 bool Path::startsWith(const Path &o) const
    216 {
    217   if(m_parts.size() < o.size() || m_attributes != o.attributes())
    218     return false;
    219 
    220   for(size_t i = 0; i < o.size(); i++) {
    221     if(o[i] != at(i))
    222       return false;
    223   }
    224 
    225   return true;
    226 }
    227 
    228 Path Path::prependRoot() const
    229 {
    230   return m_attributes & Absolute ? *this : s_root + *this;
    231 }
    232 
    233 Path Path::removeRoot() const
    234 {
    235   Path copy(*this);
    236 
    237   if(startsWith(s_root))
    238     copy.remove(0, s_root.size());
    239 
    240   return copy;
    241 }
    242 
    243 bool Path::operator==(const Path &o) const
    244 {
    245   return m_attributes == o.attributes() && m_parts == o.m_parts;
    246 }
    247 
    248 bool Path::operator!=(const Path &o) const
    249 {
    250   return !(*this == o);
    251 }
    252 
    253 bool Path::operator<(const Path &o) const
    254 {
    255   return m_parts < o.m_parts;
    256 }
    257 
    258 Path Path::operator+(const std::string &part) const
    259 {
    260   Path path(*this);
    261   path.append(part);
    262 
    263   return path;
    264 }
    265 
    266 Path Path::operator+(const Path &o) const
    267 {
    268   Path path(*this);
    269   path.append(o);
    270 
    271   return path;
    272 }
    273 
    274 const Path &Path::operator+=(const std::string &parts)
    275 {
    276   append(parts);
    277   return *this;
    278 }
    279 
    280 const Path &Path::operator+=(const Path &o)
    281 {
    282   append(o);
    283   return *this;
    284 }
    285 
    286 const std::string &Path::at(const size_t index) const
    287 {
    288   auto it = m_parts.begin();
    289   advance(it, index);
    290 
    291   return *it;
    292 }
    293 
    294 std::string &Path::operator[](const size_t index)
    295 {
    296   return const_cast<std::string &>(at(index));
    297 }
    298 
    299 const std::string &Path::operator[](const size_t index) const
    300 {
    301   return at(index);
    302 }
    303 
    304 UseRootPath::UseRootPath(const Path &path)
    305   : m_backup(std::move(Path::s_root))
    306 {
    307   Path::s_root = path;
    308 }
    309 
    310 UseRootPath::~UseRootPath()
    311 {
    312   Path::s_root = std::move(m_backup);
    313 }
    314 
    315 TempPath::TempPath(const Path &target)
    316   : m_target(target), m_temp(target)
    317 {
    318   m_temp[m_temp.size() - 1] += ".part";
    319 }