DD4hep - The AIDA detector description toolkit for high energy physics experiments
DD4hep  Rev:Unversioneddirectory
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Path.cpp
Go to the documentation of this file.
1 // AIDA Detector description implementation for LCD
2 //--------------------------------------------------------------------------
3 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
4 // All rights reserved.
5 //
6 // For the licensing terms see $DD4hepINSTALL/LICENSE.
7 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
8 //
9 // \author Markus Frank
10 // \date 2016-08-30
11 // \version 1.0
12 //
13 //==========================================================================
14 // $Id$
15 
16 #include "DD4hep/Path.h"
17 #include <climits>
18 #include <cstring>
19 #include <vector>
20 #include <stdexcept>
21 
22 using namespace std;
23 using namespace DD4hep;
24 
25 namespace {
26  const char dot = '.';
27  const char separator = '/';
28  const char* const separators = "/";
29  const char colon = ':';
30 
31 
32  inline bool is_separator(char c) { return c == separator; }
33 
34  bool is_root_separator(const string& str, size_t pos)
35  // pos is position of the separator
36  {
37  if ( str.empty() || is_separator(str[pos]) ) {
38  throw runtime_error("precondition violation");
39  }
40  // subsequent logic expects pos to be for leftmost slash of a set
41  while (pos > 0 && is_separator(str[pos-1]))
42  --pos;
43 
44  // "/" [...]
45  if (pos == 0)
46  return true;
47  // "//" name "/"
48  if (pos < 3 || !is_separator(str[0]) || !is_separator(str[1]))
49  return false;
50 
51  return str.find_first_of(separators, 2) == pos;
52  }
53 
54  size_t filename_pos(const string& str,size_t end_pos)
55  // return 0 if str itself is filename (or empty)
56  {
57  // case: "//"
58  if (end_pos == 2
59  && is_separator(str[0])
60  && is_separator(str[1])) return 0;
61 
62  // case: ends in "/"
63  if (end_pos && is_separator(str[end_pos-1]))
64  return end_pos-1;
65 
66  // set pos to start of last element
67  size_t pos(str.find_last_of(separators, end_pos-1));
68 
69  return (pos == string::npos // path itself must be a filename (or empty)
70  || (pos == 1 && is_separator(str[0]))) // or net
71  ? 0 // so filename is entire string
72  : pos + 1; // or starts after delimiter
73  }
74 
75  // return npos if no root_directory found
76  size_t root_directory_start(const string& path, size_t size) {
77  // case "//"
78  if (size == 2
79  && is_separator(path[0])
80  && is_separator(path[1])) return string::npos;
81  // case "//net {/}"
82  if (size > 3
83  && is_separator(path[0])
84  && is_separator(path[1])
85  && !is_separator(path[2]))
86  {
87  string::size_type pos(path.find_first_of(separators, 2));
88  return pos < size ? pos : string::npos;
89  }
90 
91  // case "/"
92  if (size > 0 && is_separator(path[0])) return 0;
93  return string::npos;
94  }
95 }
96 
97 const Path& Path::detail::dot_path() {
98  static Path p(".");
99  return p;
100 }
101 const Path& Path::detail::dot_dot_path() {
102  static Path p("..");
103  return p;
104 }
105 
106 Path& Path::append(const std::string& c) {
107  insert(end(),separator);
108  insert(end(),c.begin(),c.end());
109  return *this;
110 }
111 
112 Path Path::normalize() const {
113  if (empty())
114  return *this;
115 
116  vector<string> pathes;
117  char tmp[PATH_MAX];
118  ::strncpy(tmp, string_data(), sizeof(tmp));
119  tmp[sizeof(tmp)-1] = 0;
120  char *token, *save=0;
121  token = ::strtok_r(tmp,separators,&save);
122  while(token) {
123  pathes.push_back(token);
124  token = ::strtok_r(0,separators,&save);
125  }
126  Path temp;
127  vector<string>::const_iterator start(pathes.begin());
128  vector<string>::const_iterator last(pathes.end());
129  vector<string>::const_iterator stop(last--);
130  for (vector<string>::const_iterator itr(start); itr != stop; ++itr) {
131  // ignore "." except at start and last
132  Path itr_path(*itr);
133  if (itr_path.native().size() == 1
134  && (itr_path.native())[0] == dot
135  && itr != start
136  && itr != last) continue;
137 
138  // ignore a name and following ".."
139  if ( temp.empty() && itr_path.find(colon) != string::npos ) {
140  temp = itr_path;
141  continue;
142  }
143  else if (!temp.empty()
144  && itr_path.native().size() == 2
145  && (itr_path.native())[0] == dot
146  && (itr_path.native())[1] == dot) // dot dot
147  {
148  string lf(temp.filename().native());
149  if (lf.size() > 0
150  && (lf.size() != 1 || (lf[0] != dot && lf[0] != separator))
151  && (lf.size() != 2 || (lf[0] != dot && lf[1] != dot)) )
152  {
153  temp.remove_filename();
155  //if (temp.native().size() > 0
156  // && temp.native()[temp.native().size()-1]
157  // == separator)
158  //{
159  // string::size_type rds(
160  // root_directory_start(temp.native(), temp.native().size()));
161  // if (rds == string::npos
162  // || rds != temp.native().size()-1)
163  // {
164  // temp.m_pathname.erase(temp.native().size()-1);
165  // }
166  //}
167 
168  vector<string>::const_iterator next(itr);
169  if (temp.empty() && ++next != stop && next == last && *last == detail::dot_path()) {
170  temp /= detail::dot_path();
171  }
172  continue;
173  }
174  }
175  temp /= *itr;
176  };
177 
178  if (temp.empty())
179  temp /= detail::dot_path();
180  return temp;
181 }
182 
183 size_t Path::parent_path_end() const {
184  size_t end_pos(filename_pos(native(),this->size()));
185  bool filename_was_separator(this->size() && is_separator(at(end_pos)));
186 
187  // skip separators unless root directory
188  size_t root_dir_pos(root_directory_start(native(), end_pos));
189  for (; end_pos > 0
190  && (end_pos-1) != root_dir_pos
191  && is_separator(this->at(end_pos-1))
192  ;
193  --end_pos) {}
194 
195  return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator) ? string::npos : end_pos;
196 }
197 
198 
199 Path& Path::remove_filename() {
200  this->erase(this->parent_path_end());
201  return *this;
202 }
203 
204 Path Path::parent_path() const {
205  size_t end_pos(parent_path_end());
206  return end_pos == string::npos ? Path() : Path(string_data(), string_data() + end_pos);
207 }
208 
209 Path Path::filename() const
210 {
211  size_t pos(filename_pos(native(), native().size()));
212  return (native().size()
213  && pos
214  && is_separator(at(pos))
215  && !is_root_separator(native(), pos))
216  ? detail::dot_path()
217  : Path(string_data() + pos);
218 }
219 
220 Path Path::file_path() const {
221  size_t pos(filename_pos(native(), native().size()));
222  return (native().size()
223  && pos
224  && is_separator(at(pos))
225  && !is_root_separator(native(), pos))
226  ? detail::dot_path()
227  : Path(string_data() + pos);
228 }
Path filename() const
The file name of the path.
Definition: Path.cpp:209
Path handling class.
Definition: Path.h:45
Path & remove_filename()
Manipulator: remove the file name part. Leaves the parent path.
Definition: Path.cpp:199
const std::string & native() const
String representation of thre Path object.
Definition: Path.h:90