libzypp  17.1.1
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/base/String.h"
15 #include "zypp/Pathname.h"
16 #include "zypp/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  string::size_type idx = ret_t._name.find_last_of( '/' );
135 
136  if ( idx == 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  string::size_type idx = ret_t.find_last_of( '/' );
159  if ( idx != 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  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 string::npos:
224  return string();
225  break;
226  }
227  return base.substr( pos );
228  }
229 
231  //
232  // METHOD NAME : Pathname::assertprefix
233  // METHOD TYPE : Pathname
234  //
235  Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
236  {
237  if ( root_r.empty()
238  || path_r == root_r
239  || str::hasPrefix( path_r.asString(), root_r.asString() ) )
240  return path_r;
241  return root_r / path_r;
242  }
243 
245  //
246  // METHOD NAME : Pathname::cat
247  // METHOD TYPE : Pathname
248  //
249  Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv )
250  {
251  if ( add_tv.empty() )
252  return name_r;
253  if ( name_r.empty() )
254  return add_tv;
255 
256  string ret_ti( name_r._name );
257  if( add_tv._name[0] != '/' )
258  ret_ti += '/';
259  return ret_ti + add_tv._name;
260  }
261 
263  //
264  // METHOD NAME : Pathname::Extend
265  // METHOD TYPE : Pathname
266  //
267  Pathname Pathname::extend( const Pathname & l, const string & r )
268  {
269  return l.asString() + r;
270  }
271 
273  } // namespace filesystem
276 } // namespace zypp
Pathname extend(const std::string &r) const
Append string r to the last component of the path.
Definition: Pathname.h:166
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:127
bool empty() const
Test for an empty path.
Definition: Pathname.h:113
void setPathName(const std::string &path, EEncoding eflag=zypp::url::E_DECODED)
Set the path name.
Definition: Url.cc:758
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:210
void setScheme(const std::string &scheme)
Set the scheme name in the URL.
Definition: Url.cc:662
const std::string & asString() const
String representation.
Definition: Pathname.h:90
Pathname dirname() const
Return all but the last component od this path.
Definition: Pathname.h:123
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:235
Pathname()
Default ctor: an empty path.
Definition: Pathname.h:47
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:1028
Pathname cat(const Pathname &r) const
Concatenation of pathnames.
Definition: Pathname.h:158
Url manipulation class.
Definition: Url.h:87
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:134