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