libzypp 9.41.1
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00012 #include <iostream> 00013 00014 #include "zypp/base/String.h" 00015 #include "zypp/Pathname.h" 00016 #include "zypp/Url.h" 00017 00018 using std::string; 00019 00021 namespace zypp 00022 { 00023 00024 namespace filesystem 00025 { 00026 00028 namespace 00029 { 00030 // Lambda handling the "/.." case: 00031 // [] + "/.." ==> [] 00032 // [.] + "/.." ==> [./..] 00033 // [foo] is always [./foo] due to init above 00034 // [*/..] + "/.." ==> [*/../..] 00035 // [*/foo] + "/.." ==> [*] 00036 inline void goParent_fnc( string & name_t ) 00037 { 00038 if ( name_t.empty() ) 00039 /*NOOP*/; 00040 else if ( name_t.size() == 1 ) // content is '.' 00041 name_t += "/.."; 00042 else 00043 { 00044 std::string::size_type pos = name_t.rfind( "/" ); 00045 if ( pos == name_t.size() - 3 && name_t[pos+1] == '.' && name_t[pos+2] == '.' ) 00046 name_t += "/.."; 00047 else 00048 name_t.erase( pos ); 00049 } 00050 }; 00051 00052 } // namespace 00054 00055 00057 // 00058 // METHOD NAME : Pathname::_assign 00059 // METHOD TYPE : void 00060 // 00061 void Pathname::_assign( const string & name_tv ) 00062 { 00063 prfx_i = 0; 00064 name_t.clear(); 00065 if ( name_tv.empty() ) 00066 return; 00067 name_t.reserve( name_tv.size() ); 00068 00069 // Collect up to "/.." 00070 enum Pending { 00071 P_none = 0, // "" 00072 P_slash = 1, // "/" 00073 P_dot1 = 2, // "/." 00074 P_dot2 = 3 // "/.." 00075 } pending = P_none; 00076 00077 // Assert relative path starting with "./" 00078 // We rely on this below! 00079 if ( name_tv[0] != '/' ) 00080 { 00081 name_t += '.'; 00082 pending = P_slash; 00083 } 00084 00085 // Lambda handling the "/.." case: 00086 // [] + "/.." ==> [] 00087 // [.] + "/.." ==> [./..] 00088 // [foo] is always [./foo] due to init above 00089 // [*/..] + "/.." ==> [*/../..] 00090 // [*/foo] + "/.." ==> [*] 00091 #define goParent_f() goParent_fnc( name_t ) 00092 00093 for_each_( it, name_tv ) 00094 { 00095 const char ch( *it ); 00096 00097 switch ( ch ) 00098 { 00099 case '/': 00100 switch ( pending ) 00101 { 00102 case P_none: pending = P_slash; break; 00103 case P_slash: break; 00104 case P_dot1: pending = P_slash; break; 00105 case P_dot2: goParent_f(); pending = P_slash; break; 00106 } 00107 break; 00108 00109 case '.': 00110 switch ( pending ) 00111 { 00112 case P_none: name_t += '.'; break; 00113 case P_slash: pending = P_dot1; break; 00114 case P_dot1: pending = P_dot2; break; 00115 case P_dot2: name_t += "/..."; pending = P_none; break; 00116 } 00117 break; 00118 00119 default: 00120 switch ( pending ) 00121 { 00122 case P_none: break; 00123 case P_slash: name_t += '/'; pending = P_none; break; 00124 case P_dot1: name_t += "/."; pending = P_none; break; 00125 case P_dot2: name_t += "/.."; pending = P_none; break; 00126 } 00127 name_t += ch; 00128 break; 00129 } 00130 } 00131 00132 switch ( pending ) 00133 { 00134 case P_none: break; 00135 case P_slash: if ( name_t.empty() ) name_t = "/"; break; 00136 case P_dot1: if ( name_t.empty() ) name_t = "/"; break; 00137 case P_dot2: goParent_f(); if ( name_t.empty() ) name_t = "/"; break; 00138 } 00139 return; 00140 } 00141 00143 // 00144 // METHOD NAME : Pathname::dirname 00145 // METHOD TYPE : Pathname 00146 // 00147 Pathname Pathname::dirname( const Pathname & name_tv ) 00148 { 00149 if ( name_tv.empty() ) 00150 return Pathname(); 00151 00152 Pathname ret_t( name_tv ); 00153 string::size_type idx = ret_t.name_t.find_last_of( '/' ); 00154 00155 if ( idx == string::npos ) { 00156 ret_t.name_t = "."; 00157 } else if ( idx == 0 ) { 00158 ret_t.name_t = "/"; 00159 } else { 00160 ret_t.name_t.erase( idx ); 00161 } 00162 00163 return ret_t; 00164 } 00165 00167 // 00168 // METHOD NAME : Pathname::basename 00169 // METHOD TYPE : string 00170 // 00171 string Pathname::basename( const Pathname & name_tv ) 00172 { 00173 if ( name_tv.empty() ) 00174 return string(); 00175 00176 string ret_t( name_tv.asString() ); 00177 string::size_type idx = ret_t.find_last_of( '/' ); 00178 if ( idx != string::npos && ( idx != 0 || ret_t.size() != 1 ) ) { 00179 ret_t.erase( 0, idx+1 ); 00180 } 00181 00182 return ret_t; 00183 } 00184 00186 // 00187 // METHOD NAME : Pathname::asUrl 00188 // METHOD TYPE : Url 00189 // 00190 Url Pathname::asUrl() const 00191 { 00192 Url ret( "dir:///" ); 00193 ret.setPathName( asString() ); 00194 return ret; 00195 } 00196 00197 std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r ) 00198 { 00199 return str::Str() << "(" << root_r << ")" << path_r; 00200 } 00201 00202 std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r ) 00203 { 00204 if ( root_r.empty() || root_r == "/" ) 00205 return path_r.asString(); 00206 return showRoot( root_r, path_r ); 00207 } 00208 00210 // 00211 // METHOD NAME : Pathname::extension 00212 // METHOD TYPE : string 00213 // 00214 string Pathname::extension( const Pathname & name_tv ) 00215 { 00216 if ( name_tv.empty() ) 00217 return string(); 00218 00219 string base( basename( name_tv ) ); 00220 string::size_type pos = base.rfind( '.' ); 00221 switch ( pos ) 00222 { 00223 case 0: 00224 if ( base.size() == 1 ) // . 00225 return string(); 00226 break; 00227 case 1: 00228 if ( base.size() == 2 && base[0] == '.' ) // .. 00229 return string(); 00230 break; 00231 case string::npos: 00232 return string(); 00233 break; 00234 } 00235 return base.substr( pos ); 00236 } 00237 00239 // 00240 // METHOD NAME : Pathname::assertprefix 00241 // METHOD TYPE : Pathname 00242 // 00243 Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r ) 00244 { 00245 if ( root_r.empty() 00246 || path_r == root_r 00247 || str::hasPrefix( path_r.asString(), root_r.asString() ) ) 00248 return path_r; 00249 return root_r / path_r; 00250 } 00251 00253 // 00254 // METHOD NAME : Pathname::cat 00255 // METHOD TYPE : Pathname 00256 // 00257 Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv ) 00258 { 00259 if ( add_tv.empty() ) 00260 return name_tv; 00261 if ( name_tv.empty() ) 00262 return add_tv; 00263 00264 string ret_ti( name_tv.name_t ); 00265 if( add_tv.name_t[0] != '/' ) 00266 ret_ti += '/'; 00267 return ret_ti + add_tv.name_t; 00268 } 00269 00271 // 00272 // METHOD NAME : Pathname::Extend 00273 // METHOD TYPE : Pathname 00274 // 00275 Pathname Pathname::extend( const Pathname & l, const string & r ) 00276 { 00277 return l.asString() + r; 00278 } 00279 00281 } // namespace filesystem 00284 } // namespace zypp