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