File indexing completed on 2025-01-18 09:13:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <DD4hep/Path.h>
0018
0019
0020 #include <climits>
0021 #include <cstring>
0022 #include <vector>
0023 #include <stdexcept>
0024
0025 namespace {
0026 const char dot = '.';
0027 const char separator = '/';
0028 const char* const separators = "/";
0029 const char colon = ':';
0030
0031
0032 inline bool is_separator(char c) { return c == separator; }
0033
0034 bool is_root_separator(const std::string& str, size_t pos)
0035
0036 {
0037 if ( str.empty() || is_separator(str[pos]) ) {
0038 throw std::runtime_error("precondition violation");
0039 }
0040
0041 while (pos > 0 && is_separator(str[pos-1]))
0042 --pos;
0043
0044
0045 if (pos == 0)
0046 return true;
0047
0048 if (pos < 3 || !is_separator(str[0]) || !is_separator(str[1]))
0049 return false;
0050
0051 return str.find_first_of(separators, 2) == pos;
0052 }
0053
0054 size_t filename_pos(const std::string& str,size_t end_pos)
0055
0056 {
0057
0058 if (end_pos == 2
0059 && is_separator(str[0])
0060 && is_separator(str[1])) return 0;
0061
0062
0063 if (end_pos && is_separator(str[end_pos-1]))
0064 return end_pos-1;
0065
0066
0067 size_t pos(str.find_last_of(separators, end_pos-1));
0068
0069 return (pos == std::string::npos
0070 || (pos == 1 && is_separator(str[0])))
0071 ? 0
0072 : pos + 1;
0073 }
0074
0075
0076 size_t root_directory_start(const std::string& path, size_t size) {
0077
0078 if (size == 2
0079 && is_separator(path[0])
0080 && is_separator(path[1])) return std::string::npos;
0081
0082 if (size > 3
0083 && is_separator(path[0])
0084 && is_separator(path[1])
0085 && !is_separator(path[2]))
0086 {
0087 std::string::size_type pos(path.find_first_of(separators, 2));
0088 return pos < size ? pos : std::string::npos;
0089 }
0090
0091
0092 if (size > 0 && is_separator(path[0])) return 0;
0093 return std::string::npos;
0094 }
0095 }
0096
0097 using Path = dd4hep::Path;
0098
0099 const Path& Path::detail::dot_path() {
0100 static Path p(".");
0101 return p;
0102 }
0103 const Path& Path::detail::dot_dot_path() {
0104 static Path p("..");
0105 return p;
0106 }
0107
0108 Path& Path::append(const std::string& c) {
0109 insert(end(),separator);
0110 insert(end(),c.begin(),c.end());
0111 return *this;
0112 }
0113
0114 Path Path::normalize() const {
0115 if (empty())
0116 return *this;
0117
0118 std::vector<std::string> pathes;
0119 char tmp[PATH_MAX];
0120 ::strncpy(tmp, string_data(), sizeof(tmp));
0121 tmp[sizeof(tmp)-1] = 0;
0122 char *token, *save=0;
0123 token = ::strtok_r(tmp,separators,&save);
0124 while(token) {
0125 pathes.emplace_back(token);
0126 token = ::strtok_r(0,separators,&save);
0127 }
0128 Path temp;
0129 std::vector<std::string>::const_iterator start(pathes.begin());
0130 std::vector<std::string>::const_iterator last(pathes.end());
0131 std::vector<std::string>::const_iterator stop(last--);
0132 for (std::vector<std::string>::const_iterator itr(start); itr != stop; ++itr) {
0133
0134 Path itr_path(*itr);
0135 if (itr_path.native().size() == 1
0136 && (itr_path.native())[0] == dot
0137 && itr != start
0138 && itr != last) continue;
0139
0140
0141 if ( temp.empty() && itr_path.find(colon) != std::string::npos ) {
0142 temp = std::move(itr_path);
0143 continue;
0144 }
0145 else if (!temp.empty()
0146 && itr_path.native().size() == 2
0147 && (itr_path.native())[0] == dot
0148 && (itr_path.native())[1] == dot)
0149 {
0150 std::string lf(temp.filename().native());
0151 if (lf.size() > 0
0152 && (lf.size() != 1 || (lf[0] != dot && lf[0] != separator))
0153 && (lf.size() != 2 || (lf[0] != dot && lf[1] != dot)) )
0154 {
0155 temp.remove_filename();
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170 std::vector<std::string>::const_iterator next(itr);
0171 if (temp.empty() && ++next != stop && next == last && *last == detail::dot_path()) {
0172 temp /= detail::dot_path();
0173 }
0174 continue;
0175 }
0176 }
0177 temp /= *itr;
0178 };
0179
0180 if (temp.empty())
0181 temp /= detail::dot_path();
0182 return temp;
0183 }
0184
0185 size_t Path::parent_path_end() const {
0186 size_t end_pos(filename_pos(native(),this->size()));
0187 bool filename_was_separator(this->size() && is_separator(at(end_pos)));
0188
0189
0190 size_t root_dir_pos(root_directory_start(native(), end_pos));
0191 for (; end_pos > 0
0192 && (end_pos-1) != root_dir_pos
0193 && is_separator(this->at(end_pos-1))
0194 ;
0195 --end_pos) {}
0196
0197 return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator) ? std::string::npos : end_pos;
0198 }
0199
0200
0201 Path& Path::remove_filename() {
0202 this->erase(this->parent_path_end());
0203 return *this;
0204 }
0205
0206 Path Path::parent_path() const {
0207 size_t end_pos(parent_path_end());
0208 return end_pos == std::string::npos ? Path() : Path(string_data(), string_data() + end_pos);
0209 }
0210
0211 Path Path::filename() const
0212 {
0213 size_t pos(filename_pos(native(), native().size()));
0214 return (native().size()
0215 && pos
0216 && is_separator(at(pos))
0217 && !is_root_separator(native(), pos))
0218 ? detail::dot_path()
0219 : Path(string_data() + pos);
0220 }
0221
0222 Path Path::file_path() const {
0223 size_t pos(filename_pos(native(), native().size()));
0224 return (native().size()
0225 && pos
0226 && is_separator(at(pos))
0227 && !is_root_separator(native(), pos))
0228 ? detail::dot_path()
0229 : Path(string_data() + pos);
0230 }