libzypp  11.13.5
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 
24  namespace filesystem
25  {
26 
28  //
29  // METHOD NAME : Pathname::_assign
30  // METHOD TYPE : void
31  //
32  void Pathname::_assign( const string & name_tv )
33  {
34  prfx_i = 0;
35  name_t.clear();
36  if ( name_tv.empty() )
37  return;
38  name_t.reserve( name_tv.size() );
39 
40  // Collect up to "/.."
41  enum Pending {
42  P_none = 0, // ""
43  P_slash = 1, // "/"
44  P_dot1 = 2, // "/."
45  P_dot2 = 3 // "/.."
46  } pending = P_none;
47 
48  // Assert relative path starting with "./"
49  // We rely on this below!
50  if ( name_tv[0] != '/' )
51  {
52  name_t += '.';
53  pending = P_slash;
54  }
55 
56  // Lambda handling the "/.." case:
57  // [] + "/.." ==> []
58  // [.] + "/.." ==> [./..]
59  // [foo] is always [./foo] due to init above
60  // [*/..] + "/.." ==> [*/../..]
61  // [*/foo] + "/.." ==> [*]
62  auto goParent_f = [&](){
63  if ( name_t.empty() )
64  /*NOOP*/;
65  else if ( name_t.size() == 1 ) // content is '.'
66  name_t += "/..";
67  else
68  {
69  std::string::size_type pos = name_t.rfind( "/" );
70  if ( pos == name_t.size() - 3 && name_t[pos+1] == '.' && name_t[pos+2] == '.' )
71  name_t += "/..";
72  else
73  name_t.erase( pos );
74  }
75  };
76 
77  for ( auto ch : name_tv )
78  {
79  switch ( ch )
80  {
81  case '/':
82  switch ( pending )
83  {
84  case P_none: pending = P_slash; break;
85  case P_slash: break;
86  case P_dot1: pending = P_slash; break;
87  case P_dot2: goParent_f(); pending = P_slash; break;
88  }
89  break;
90 
91  case '.':
92  switch ( pending )
93  {
94  case P_none: name_t += '.'; break;
95  case P_slash: pending = P_dot1; break;
96  case P_dot1: pending = P_dot2; break;
97  case P_dot2: name_t += "/..."; pending = P_none; break;
98  }
99  break;
100 
101  default:
102  switch ( pending )
103  {
104  case P_none: break;
105  case P_slash: name_t += '/'; pending = P_none; break;
106  case P_dot1: name_t += "/."; pending = P_none; break;
107  case P_dot2: name_t += "/.."; pending = P_none; break;
108  }
109  name_t += ch;
110  break;
111  }
112  }
113 
114  switch ( pending )
115  {
116  case P_none: break;
117  case P_slash: if ( name_t.empty() ) name_t = "/"; break;
118  case P_dot1: if ( name_t.empty() ) name_t = "/"; break;
119  case P_dot2: goParent_f(); if ( name_t.empty() ) name_t = "/"; break;
120  }
121  return;
122  }
123 
125  //
126  // METHOD NAME : Pathname::dirname
127  // METHOD TYPE : Pathname
128  //
130  {
131  if ( name_tv.empty() )
132  return Pathname();
133 
134  Pathname ret_t( name_tv );
135  string::size_type idx = ret_t.name_t.find_last_of( '/' );
136 
137  if ( idx == string::npos ) {
138  ret_t.name_t = ".";
139  } else if ( idx == 0 ) {
140  ret_t.name_t = "/";
141  } else {
142  ret_t.name_t.erase( idx );
143  }
144 
145  return ret_t;
146  }
147 
149  //
150  // METHOD NAME : Pathname::basename
151  // METHOD TYPE : string
152  //
153  string Pathname::basename( const Pathname & name_tv )
154  {
155  if ( name_tv.empty() )
156  return string();
157 
158  string ret_t( name_tv.asString() );
159  string::size_type idx = ret_t.find_last_of( '/' );
160  if ( idx != string::npos && ( idx != 0 || ret_t.size() != 1 ) ) {
161  ret_t.erase( 0, idx+1 );
162  }
163 
164  return ret_t;
165  }
166 
168  //
169  // METHOD NAME : Pathname::asUrl
170  // METHOD TYPE : Url
171  //
173  {
174  Url ret( "dir:///" );
175  ret.setPathName( asString() );
176  return ret;
177  }
178 
179  std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
180  {
181  return str::Str() << "(" << root_r << ")" << path_r;
182  }
183 
184  std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
185  {
186  if ( root_r.empty() || root_r == "/" )
187  return path_r.asString();
188  return showRoot( root_r, path_r );
189  }
190 
192  //
193  // METHOD NAME : Pathname::extension
194  // METHOD TYPE : string
195  //
196  string Pathname::extension( const Pathname & name_tv )
197  {
198  if ( name_tv.empty() )
199  return string();
200 
201  string base( basename( name_tv ) );
202  string::size_type pos = base.rfind( '.' );
203  switch ( pos )
204  {
205  case 0:
206  if ( base.size() == 1 ) // .
207  return string();
208  break;
209  case 1:
210  if ( base.size() == 2 && base[0] == '.' ) // ..
211  return string();
212  break;
213  case string::npos:
214  return string();
215  break;
216  }
217  return base.substr( pos );
218  }
219 
221  //
222  // METHOD NAME : Pathname::assertprefix
223  // METHOD TYPE : Pathname
224  //
225  Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
226  {
227  if ( root_r.empty()
228  || path_r == root_r
229  || str::hasPrefix( path_r.asString(), root_r.asString() ) )
230  return path_r;
231  return root_r / path_r;
232  }
233 
235  //
236  // METHOD NAME : Pathname::cat
237  // METHOD TYPE : Pathname
238  //
239  Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv )
240  {
241  if ( add_tv.empty() )
242  return name_tv;
243  if ( name_tv.empty() )
244  return add_tv;
245 
246  string ret_ti( name_tv.name_t );
247  if( add_tv.name_t[0] != '/' )
248  ret_ti += '/';
249  return ret_ti + add_tv.name_t;
250  }
251 
253  //
254  // METHOD NAME : Pathname::Extend
255  // METHOD TYPE : Pathname
256  //
257  Pathname Pathname::extend( const Pathname & l, const string & r )
258  {
259  return l.asString() + r;
260  }
261 
263  } // namespace filesystem
266 } // namespace zypp