Remove obsolete ResStatus bits.
[platform/upstream/libzypp.git] / zypp / Pathname.cc
1 /*---------------------------------------------------------------------\
2  |                          ____ _   __ __ ___                          |
3  |                         |__  / \ / / . \ . \                         |
4  |                           / / \ V /|  _/  _/                         |
5  |                          / /__ | | | | | |                           |
6  |                         /_____||_| |_| |_|                           |
7  |                                                                      |
8  \---------------------------------------------------------------------*/
9 /** \file       zypp/Pathname.cc
10  *
11 */
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
20 ///////////////////////////////////////////////////////////////////
21 namespace zypp
22 { /////////////////////////////////////////////////////////////////
23   ///////////////////////////////////////////////////////////////////
24   namespace filesystem
25   { /////////////////////////////////////////////////////////////////
26
27     ///////////////////////////////////////////////////////////////////
28     namespace
29     { /////////////////////////////////////////////////////////////////
30
31       ///////////////////////////////////////////////////////////////////
32       //
33       //        CLASS NAME : DirStack
34       //
35       /** silly helper to build Pathnames.
36       */
37       class DirStack {
38
39         struct Dir {
40
41           Dir *  up;
42           Dir *  dn;
43           string name;
44
45           Dir( const string & n = "" ) {
46             name = n;
47             up = dn = 0;
48           }
49
50           ~Dir() {
51             if ( up )
52               up->dn = dn;
53             if ( dn )
54               dn->up = up;
55           }
56         };
57
58         Dir *  top;
59         Dir *  bot;
60
61         void Pop() {
62           if ( !top )
63             return;
64           top = top->dn;
65           if ( top )
66             delete top->up;
67           else {
68             delete bot;
69             bot = 0;
70           }
71         }
72
73       public:
74
75         DirStack() { top = bot = 0; }
76         ~DirStack() {
77           while ( bot )
78             Pop();
79         }
80
81         void Push( const string & n ) {
82           if ( n.empty() || n == "." ) { // '.' or '/' only for bot
83             if ( bot )
84               return;
85           } else if ( n == ".." && top ) {
86             if ( top->name == "" )          // "/.."        ==> "/"
87               return;
88
89             if ( top->name != "." && top->name != ".." ) {      // "somedir/.." ==> ""
90               Pop();
91               return;
92             }
93             // "../.." "./.." stays
94           }
95
96           Dir * d = new Dir( n );
97           if ( !top )
98             top = bot = d;
99           else {
100             top->up = d;
101             d->dn = top;
102             d->up = 0;
103             top = d;
104           }
105         }
106
107         string str() {
108           if ( !bot )
109             return "";
110           string ret;
111           for ( Dir * d = bot; d; d = d->up ) {
112             if ( d != bot )
113               ret += "/";
114             ret += d->name;
115           }
116           if ( ret.empty() )
117             return "/";
118           return ret;
119         }
120       };
121
122       /////////////////////////////////////////////////////////////////
123     } // namespace
124     ///////////////////////////////////////////////////////////////////
125
126     ///////////////////////////////////////////////////////////////////
127     //
128     //  METHOD NAME : Pathname::_assign
129     //  METHOD TYPE : void
130     //
131     void Pathname::_assign( const string & name_tv )
132     {
133       prfx_i = 0;
134       name_t = name_tv;
135
136       if ( name_t.empty() )
137         return;
138
139       string   Tprfx;
140       DirStack Stack_Ci;
141
142       char *       Buf_aci    = new char[name_tv.length() + 1];
143       char *       W_pci      = Buf_aci;
144       const char * R_pci      = name_tv.c_str();
145
146       // check for prefix
147       if (    name_t.length() >= 2
148            && name_t[1] == ':'
149            && (    ( 'a' <= name_t[0] && name_t[0] <= 'z' )
150                 || ( 'A' <= name_t[0] && name_t[0] <= 'Z' ) ) ) {
151         Tprfx  = name_t.substr( 0, 2 );
152         prfx_i = 2;
153         R_pci += 2;
154       }
155
156       // rel or abs path
157       if ( *R_pci == '/' || *R_pci == '\\' ) {
158         Stack_Ci.Push( "" );
159         ++R_pci;
160       } else {
161         Stack_Ci.Push( "." );
162       }
163
164       do {
165         switch ( *R_pci ) {
166         case '/':
167         case '\\':
168         case '\0':
169           if ( W_pci != Buf_aci ) {
170             *W_pci = '\0';
171             W_pci = Buf_aci;
172             Stack_Ci.Push( Buf_aci );
173           }
174           break;
175
176         default:
177           *W_pci++ = *R_pci;
178           break;
179         }
180       } while( *R_pci++ );
181
182       delete[] Buf_aci;
183       name_t = Tprfx + Stack_Ci.str();
184     }
185
186     ///////////////////////////////////////////////////////////////////
187     //
188     //  METHOD NAME : Pathname::dirname
189     //  METHOD TYPE : Pathname
190     //
191     Pathname Pathname::dirname( const Pathname & name_tv )
192     {
193       if ( name_tv.empty() )
194         return "";
195
196       Pathname ret_t( name_tv );
197       string::size_type idx = ret_t.name_t.find_last_of( '/' );
198
199       if ( idx == string::npos ) {
200         ret_t.name_t.erase( ret_t.prfx_i );
201         ret_t.name_t += ".";
202       } else if ( idx == ret_t.prfx_i ) {
203         ret_t.name_t.erase( ret_t.prfx_i );
204         ret_t.name_t += "/";
205       } else {
206         ret_t.name_t.erase( idx );
207       }
208
209       return ret_t;
210     }
211
212     ///////////////////////////////////////////////////////////////////
213     //
214     //  METHOD NAME : Pathname::basename
215     //  METHOD TYPE : string
216     //
217     string Pathname::basename( const Pathname & name_tv )
218     {
219       if ( name_tv.empty() )
220         return string();
221
222       string ret_t( name_tv.asString() );
223       ret_t.erase( 0, name_tv.prfx_i );
224       string::size_type idx = ret_t.find_last_of( '/' );
225       if ( idx != string::npos ) {
226         ret_t.erase( 0, idx+1 );
227       }
228
229       return ret_t;
230     }
231
232     ///////////////////////////////////////////////////////////////////
233     //
234     //  METHOD NAME : Pathname::asUrl
235     //  METHOD TYPE : Url
236     //
237     Url Pathname::asUrl() const
238     {
239       Url ret( "dir:///" );
240       ret.setPathName( asString() );
241       return ret;
242     }
243
244     std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
245     {
246       return str::Str() << "(" << root_r << ")" << path_r;
247     }
248
249     std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
250     {
251       if ( root_r.empty() || root_r == "/" )
252         return path_r.asString();
253       return showRoot( root_r, path_r );
254     }
255
256     ///////////////////////////////////////////////////////////////////
257     //
258     //  METHOD NAME : Pathname::extension
259     //  METHOD TYPE : string
260     //
261     string Pathname::extension( const Pathname & name_tv )
262     {
263       if ( name_tv.empty() )
264         return string();
265
266       string base( basename( name_tv ) );
267       string::size_type pos = base.rfind( '.' );
268       if ( pos == string::npos )
269         return string();
270       return base.substr( pos );
271     }
272
273     ///////////////////////////////////////////////////////////////////
274     //
275     //  METHOD NAME : Pathname::assertprefix
276     //  METHOD TYPE : Pathname
277     //
278     Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
279     {
280       if ( root_r.empty()
281            || path_r == root_r
282            || str::hasPrefix( path_r.asString(), root_r.asString() ) )
283         return path_r;
284       return root_r / path_r;
285     }
286
287     ///////////////////////////////////////////////////////////////////
288     //
289     //  METHOD NAME : Pathname::cat
290     //  METHOD TYPE : Pathname
291     //
292     Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv )
293     {
294       if ( add_tv.empty() )
295         return name_tv;
296       if ( name_tv.empty() )
297         return add_tv;
298
299       string ret_ti( add_tv.asString() );
300       ret_ti.replace( 0, add_tv.prfx_i, "/" );
301
302       return name_tv.asString() + ret_ti;
303     }
304
305     ///////////////////////////////////////////////////////////////////
306     //
307     //  METHOD NAME : Pathname::Extend
308     //  METHOD TYPE : Pathname
309     //
310     Pathname Pathname::extend( const Pathname & l, const string & r )
311     {
312       return l.asString() + r;
313     }
314
315     /////////////////////////////////////////////////////////////////
316   } // namespace filesystem
317   ///////////////////////////////////////////////////////////////////
318   /////////////////////////////////////////////////////////////////
319 } // namespace zypp
320 ///////////////////////////////////////////////////////////////////