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