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