libzypp  17.31.0
Pathname.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2  | ____ _ __ __ ___ |
3  | |__ / \ / / . \ . \ |
4  | / / \ V /| _/ _/ |
5  | / /__ | | | | | | |
6  | /_____||_| |_| |_| |
7  | |
8  \---------------------------------------------------------------------*/
12 #include <iostream>
13 
14 #include <zypp-core/base/String.h>
15 #include <zypp-core/Pathname.h>
16 #include <zypp-core/Url.h>
17 
18 using std::string;
19 
21 namespace zypp
22 {
23  namespace filesystem
25  {
26 
28  //
29  // METHOD NAME : Pathname::_assign
30  // METHOD TYPE : void
31  //
32  void Pathname::_assign( const string & name_r )
33  {
34  _name.clear();
35  if ( name_r.empty() )
36  return;
37  _name.reserve( name_r.size() );
38 
39  // Collect up to "/.."
40  enum Pending {
41  P_none = 0, // ""
42  P_slash = 1, // "/"
43  P_dot1 = 2, // "/."
44  P_dot2 = 3 // "/.."
45  } pending = P_none;
46 
47  // Assert relative path starting with "./"
48  // We rely on this below!
49  if ( name_r[0] != '/' )
50  {
51  _name += '.';
52  pending = P_slash;
53  }
54 
55  // Lambda handling the "/.." case:
56  // [] + "/.." ==> []
57  // [.] + "/.." ==> [./..]
58  // [foo] is always [./foo] due to init above
59  // [*/..] + "/.." ==> [*/../..]
60  // [*/foo] + "/.." ==> [*]
61  auto goParent_f = [&](){
62  if ( _name.empty() )
63  /*NOOP*/;
64  else if ( _name.size() == 1 ) // content is '.'
65  _name += "/..";
66  else
67  {
68  std::string::size_type pos = _name.rfind( "/" );
69  if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' )
70  _name += "/..";
71  else
72  _name.erase( pos );
73  }
74  };
75 
76  for ( char ch : name_r )
77  {
78  switch ( ch )
79  {
80  case '/':
81  switch ( pending )
82  {
83  case P_none: pending = P_slash; break;
84  case P_slash: break;
85  case P_dot1: pending = P_slash; break;
86  case P_dot2: goParent_f(); pending = P_slash; break;
87  }
88  break;
89 
90  case '.':
91  switch ( pending )
92  {
93  case P_none: _name += '.'; break;
94  case P_slash: pending = P_dot1; break;
95  case P_dot1: pending = P_dot2; break;
96  case P_dot2: _name += "/..."; pending = P_none; break;
97  }
98  break;
99 
100  default:
101  switch ( pending )
102  {
103  case P_none: break;
104  case P_slash: _name += '/'; pending = P_none; break;
105  case P_dot1: _name += "/."; pending = P_none; break;
106  case P_dot2: _name += "/.."; pending = P_none; break;
107  }
108  _name += ch;
109  break;
110  }
111  }
112 
113  switch ( pending )
114  {
115  case P_none: break;
116  case P_slash: if ( _name.empty() ) _name = "/"; break;
117  case P_dot1: if ( _name.empty() ) _name = "/"; break;
118  case P_dot2: goParent_f(); if ( _name.empty() ) _name = "/"; break;
119  }
120  return;
121  }
122 
124  //
125  // METHOD NAME : Pathname::dirname
126  // METHOD TYPE : Pathname
127  //
129  {
130  if ( name_r.empty() )
131  return Pathname();
132 
133  Pathname ret_t( name_r );
134  std::string::size_type idx = ret_t._name.find_last_of( '/' );
135 
136  if ( idx == std::string::npos ) {
137  ret_t._name = ".";
138  } else if ( idx == 0 ) {
139  ret_t._name = "/";
140  } else {
141  ret_t._name.erase( idx );
142  }
143 
144  return ret_t;
145  }
146 
148  //
149  // METHOD NAME : Pathname::basename
150  // METHOD TYPE : string
151  //
152  string Pathname::basename( const Pathname & name_r )
153  {
154  if ( name_r.empty() )
155  return string();
156 
157  string ret_t( name_r.asString() );
158  std::string::size_type idx = ret_t.find_last_of( '/' );
159  if ( idx != std::string::npos && ( idx != 0 || ret_t.size() != 1 ) ) {
160  ret_t.erase( 0, idx+1 );
161  }
162 
163  return ret_t;
164  }
165 
167  //
168  // METHOD NAME : Pathname::asUrl
169  // METHOD TYPE : Url
170  //
171  Url Pathname::asUrl( const std::string & scheme_r ) const
172  {
173  Url ret;
174  ret.setPathName( asString() );
175  ret.setScheme( scheme_r );
176  return ret;
177  }
178 
180  { return asUrl( "dir" ); }
181 
183  { return asUrl( "dir" ); }
184 
186  { return asUrl( "file" ); }
187 
188 
189  std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
190  {
191  return str::Str() << "(" << root_r << ")" << path_r;
192  }
193 
194  std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
195  {
196  if ( root_r.empty() || root_r == "/" )
197  return path_r.asString();
198  return showRoot( root_r, path_r );
199  }
200 
202  //
203  // METHOD NAME : Pathname::extension
204  // METHOD TYPE : string
205  //
206  string Pathname::extension( const Pathname & name_r )
207  {
208  if ( name_r.empty() )
209  return string();
210 
211  string base( basename( name_r ) );
212  std::string::size_type pos = base.rfind( '.' );
213  switch ( pos )
214  {
215  case 0:
216  if ( base.size() == 1 ) // .
217  return string();
218  break;
219  case 1:
220  if ( base.size() == 2 && base[0] == '.' ) // ..
221  return string();
222  break;
223  case std::string::npos:
224  return string();
225  break;
226  }
227  return base.substr( pos );
228  }
229 
231  {
232  std::string real;
233  if( !empty())
234  {
235  #if __GNUC__ > 2
236 
237  char *ptr = ::realpath(_name.c_str(), NULL);
238  if( ptr != NULL)
239  {
240  real = ptr;
241  free( ptr);
242  }
243  else
245  if( EINVAL == errno)
246  {
247  char buff[PATH_MAX + 2];
248  memset(buff, '\0', sizeof(buff));
249  if( ::realpath(_name.c_str(), buff) != NULL)
250  {
251  real = buff;
252  }
253  }
254  #else
255  char buff[PATH_MAX + 2];
256  memset(buff, '\0', sizeof(buff));
257  if( ::realpath(_name.c_str(), buff) != NULL)
258  {
259  real = buff;
260  }
261  #endif
262  }
263  return zypp::Pathname(real);
264  }
265 
267  //
268  // METHOD NAME : Pathname::assertprefix
269  // METHOD TYPE : Pathname
270  //
271  Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
272  {
273  if ( root_r.empty()
274  || path_r == root_r
275  || str::hasPrefix( path_r.asString(), root_r.asString() ) )
276  return path_r;
277  return root_r / path_r;
278  }
279 
280  Pathname Pathname::stripprefix( const Pathname & root_r, const Pathname & path_r )
281  {
282  if ( root_r.emptyOrRoot() )
283  return path_r;
284  if ( root_r == path_r )
285  return "/";
286  std::string rest( str::stripPrefix( path_r.asString(), root_r.asString() ) );
287  if ( rest[0] == '/' ) // needs to be a dir prefix!
288  return rest;
289  return path_r;
290  }
291 
293  //
294  // METHOD NAME : Pathname::cat
295  // METHOD TYPE : Pathname
296  //
297  Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv )
298  {
299  if ( add_tv.empty() )
300  return name_r;
301  if ( name_r.empty() )
302  return add_tv;
303 
304  string ret_ti( name_r._name );
305  if( add_tv._name[0] != '/' )
306  ret_ti += '/';
307  return ret_ti + add_tv._name;
308  }
309 
311  //
312  // METHOD NAME : Pathname::Extend
313  // METHOD TYPE : Pathname
314  //
315  Pathname Pathname::extend( const Pathname & l, const string & r )
316  {
317  return l.asString() + r;
318  }
319 
321  } // namespace filesystem
324 } // namespace zypp
Pathname realpath() const
Returns this path as the absolute canonical pathname.
Definition: Pathname.cc:230
std::string stripPrefix(const C_Str &str_r, const C_Str &prefix_r)
Strip a prefix_r from str_r and return the resulting string.
Definition: String.h:1034
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:173
static std::string showRootIf(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path", unless root is "/" or empty.
Definition: Pathname.cc:194
std::string basename() const
Return the last component of this path.
Definition: Pathname.h:128
bool emptyOrRoot() const
Test for "" or "/".
Definition: Pathname.h:121
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:764
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition: Url.cc:668
const std::string & asString() const
String representation.
Definition: Pathname.h:91
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:124
static Pathname assertprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r prefixed with root_r, unless it is already prefixed.
Definition: Pathname.cc:271
Pathname()
Default ctor: an empty path.
Definition: Pathname.h:48
static std::string showRoot(const Pathname &root_r, const Pathname &path_r)
String representation as "(root)/path".
Definition: Pathname.cc:189
SolvableIdType size_type
Definition: PoolMember.h:126
void _assign(const std::string &name_r)
Definition: Pathname.cc:32
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:1
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1027
Pathname cat(const Pathname &r) const
Concatenation of pathnames.
Definition: Pathname.h:165
static Pathname stripprefix(const Pathname &root_r, const Pathname &path_r)
Return path_r with any root_r dir prefix striped.
Definition: Pathname.cc:280
Url manipulation class.
Definition: Url.h:91
std::string extension() const
Return all of the characters in name after and including the last dot in the last element of name...
Definition: Pathname.h:135