X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=zypp%2FPathname.cc;h=61b08afb01d2ca898a5b2910416e4899758f9cf7;hb=HEAD;hp=9d4b081d23f5cf5a4271bbd54024ce082e3d5b24;hpb=1f37ea0151d021b542cfa62e0614a599c4975a45;p=platform%2Fupstream%2Flibzypp.git diff --git a/zypp/Pathname.cc b/zypp/Pathname.cc index 9d4b081..d81a472 100644 --- a/zypp/Pathname.cc +++ b/zypp/Pathname.cc @@ -11,8 +11,9 @@ */ #include -#include "zypp/Pathname.h" -#include "zypp/Url.h" +#include +#include +#include using std::string; @@ -24,162 +25,99 @@ namespace zypp { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - namespace - { ///////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // - // CLASS NAME : DirStack - // - /** silly helper to build Pathnames. - */ - class DirStack { - - struct Dir { - - Dir * up; - Dir * dn; - string name; - - Dir( const string & n = "" ) { - name = n; - up = dn = 0; - } - - ~Dir() { - if ( up ) - up->dn = dn; - if ( dn ) - dn->up = up; - } - }; - - Dir * top; - Dir * bot; - - void Pop() { - if ( !top ) - return; - top = top->dn; - if ( top ) - delete top->up; - else { - delete bot; - bot = 0; - } - } - - public: - - DirStack() { top = bot = 0; } - ~DirStack() { - while ( bot ) - Pop(); - } - - void Push( const string & n ) { - if ( n.empty() || n == "." ) { // '.' or '/' only for bot - if ( bot ) - return; - } else if ( n == ".." && top ) { - if ( top->name == "" ) // "/.." ==> "/" - return; - - if ( top->name != "." && top->name != ".." ) { // "somedir/.." ==> "" - Pop(); - return; - } - // "../.." "./.." stays - } - - Dir * d = new Dir( n ); - if ( !top ) - top = bot = d; - else { - top->up = d; - d->dn = top; - d->up = 0; - top = d; - } - } - - string str() { - if ( !bot ) - return ""; - string ret; - for ( Dir * d = bot; d; d = d->up ) { - if ( d != bot ) - ret += "/"; - ret += d->name; - } - if ( ret.empty() ) - return "/"; - return ret; - } - }; - - ///////////////////////////////////////////////////////////////// - } // namespace - /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// // // METHOD NAME : Pathname::_assign // METHOD TYPE : void // - void Pathname::_assign( const string & name_tv ) + void Pathname::_assign( const string & name_r ) { - prfx_i = 0; - name_t = name_tv; - - if ( name_t.empty() ) + _name.clear(); + if ( name_r.empty() ) return; - - string Tprfx; - DirStack Stack_Ci; - - char * Buf_aci = new char[name_tv.length() + 1]; - char * W_pci = Buf_aci; - const char * R_pci = name_tv.c_str(); - - // check for prefix - if ( name_t.length() >= 2 - && name_t[1] == ':' - && ( ( 'a' <= name_t[0] && name_t[0] <= 'z' ) - || ( 'A' <= name_t[0] && name_t[0] <= 'Z' ) ) ) { - Tprfx = name_t.substr( 0, 2 ); - prfx_i = 2; - R_pci += 2; + _name.reserve( name_r.size() ); + + // Collect up to "/.." + enum Pending { + P_none = 0, // "" + P_slash = 1, // "/" + P_dot1 = 2, // "/." + P_dot2 = 3 // "/.." + } pending = P_none; + + // Assert relative path starting with "./" + // We rely on this below! + if ( name_r[0] != '/' ) + { + _name += '.'; + pending = P_slash; } - // rel or abs path - if ( *R_pci == '/' || *R_pci == '\\' ) { - Stack_Ci.Push( "" ); - ++R_pci; - } else { - Stack_Ci.Push( "." ); + // Lambda handling the "/.." case: + // [] + "/.." ==> [] + // [.] + "/.." ==> [./..] + // [foo] is always [./foo] due to init above + // [*/..] + "/.." ==> [*/../..] + // [*/foo] + "/.." ==> [*] + auto goParent_f = [&](){ + if ( _name.empty() ) + /*NOOP*/; + else if ( _name.size() == 1 ) // content is '.' + _name += "/.."; + else + { + std::string::size_type pos = _name.rfind( "/" ); + if ( pos == _name.size() - 3 && _name[pos+1] == '.' && _name[pos+2] == '.' ) + _name += "/.."; + else + _name.erase( pos ); + } + }; + + for ( char ch : name_r ) + { + switch ( ch ) + { + case '/': + switch ( pending ) + { + case P_none: pending = P_slash; break; + case P_slash: break; + case P_dot1: pending = P_slash; break; + case P_dot2: goParent_f(); pending = P_slash; break; + } + break; + + case '.': + switch ( pending ) + { + case P_none: _name += '.'; break; + case P_slash: pending = P_dot1; break; + case P_dot1: pending = P_dot2; break; + case P_dot2: _name += "/..."; pending = P_none; break; + } + break; + + default: + switch ( pending ) + { + case P_none: break; + case P_slash: _name += '/'; pending = P_none; break; + case P_dot1: _name += "/."; pending = P_none; break; + case P_dot2: _name += "/.."; pending = P_none; break; + } + _name += ch; + break; + } } - do { - switch ( *R_pci ) { - case '/': - case '\\': - case '\0': - if ( W_pci != Buf_aci ) { - *W_pci = '\0'; - W_pci = Buf_aci; - Stack_Ci.Push( Buf_aci ); - } - break; - - default: - *W_pci++ = *R_pci; - break; - } - } while( *R_pci++ ); - - delete[] Buf_aci; - name_t = Tprfx + Stack_Ci.str(); + switch ( pending ) + { + case P_none: break; + case P_slash: if ( _name.empty() ) _name = "/"; break; + case P_dot1: if ( _name.empty() ) _name = "/"; break; + case P_dot2: goParent_f(); if ( _name.empty() ) _name = "/"; break; + } + return; } /////////////////////////////////////////////////////////////////// @@ -187,22 +125,20 @@ namespace zypp // METHOD NAME : Pathname::dirname // METHOD TYPE : Pathname // - Pathname Pathname::dirname( const Pathname & name_tv ) + Pathname Pathname::dirname( const Pathname & name_r ) { - if ( name_tv.empty() ) - return ""; - - Pathname ret_t( name_tv ); - string::size_type idx = ret_t.name_t.find_last_of( '/' ); - - if ( idx == string::npos ) { - ret_t.name_t.erase( ret_t.prfx_i ); - ret_t.name_t += "."; - } else if ( idx == ret_t.prfx_i ) { - ret_t.name_t.erase( ret_t.prfx_i ); - ret_t.name_t += "/"; + if ( name_r.empty() ) + return Pathname(); + + Pathname ret_t( name_r ); + std::string::size_type idx = ret_t._name.find_last_of( '/' ); + + if ( idx == std::string::npos ) { + ret_t._name = "."; + } else if ( idx == 0 ) { + ret_t._name = "/"; } else { - ret_t.name_t.erase( idx ); + ret_t._name.erase( idx ); } return ret_t; @@ -213,15 +149,14 @@ namespace zypp // METHOD NAME : Pathname::basename // METHOD TYPE : string // - string Pathname::basename( const Pathname & name_tv ) + string Pathname::basename( const Pathname & name_r ) { - if ( name_tv.empty() ) + if ( name_r.empty() ) return string(); - string ret_t( name_tv.asString() ); - ret_t.erase( 0, name_tv.prfx_i ); - string::size_type idx = ret_t.find_last_of( '/' ); - if ( idx != string::npos ) { + string ret_t( name_r.asString() ); + std::string::size_type idx = ret_t.find_last_of( '/' ); + if ( idx != std::string::npos && ( idx != 0 || ret_t.size() != 1 ) ) { ret_t.erase( 0, idx+1 ); } @@ -233,46 +168,107 @@ namespace zypp // METHOD NAME : Pathname::asUrl // METHOD TYPE : Url // - Url Pathname::asUrl() const + Url Pathname::asUrl( const std::string & scheme_r ) const { - Url ret( "dir:///" ); + Url ret; ret.setPathName( asString() ); + ret.setScheme( scheme_r ); return ret; } + Url Pathname::asUrl() const + { return asUrl( "dir" ); } + + Url Pathname::asDirUrl() const + { return asUrl( "dir" ); } + + Url Pathname::asFileUrl() const + { return asUrl( "file" ); } + + + std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r ) + { + return str::Str() << "(" << root_r << ")" << path_r; + } + + std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r ) + { + if ( root_r.empty() || root_r == "/" ) + return path_r.asString(); + return showRoot( root_r, path_r ); + } + /////////////////////////////////////////////////////////////////// // // METHOD NAME : Pathname::extension // METHOD TYPE : string // - string Pathname::extension( const Pathname & name_tv ) + string Pathname::extension( const Pathname & name_r ) { - if ( name_tv.empty() ) + if ( name_r.empty() ) return string(); - string base( basename( name_tv ) ); - string::size_type pos = base.rfind( '.' ); - if ( pos == string::npos ) - return string(); + string base( basename( name_r ) ); + std::string::size_type pos = base.rfind( '.' ); + switch ( pos ) + { + case 0: + if ( base.size() == 1 ) // . + return string(); + break; + case 1: + if ( base.size() == 2 && base[0] == '.' ) // .. + return string(); + break; + case std::string::npos: + return string(); + break; + } return base.substr( pos ); } /////////////////////////////////////////////////////////////////// // + // METHOD NAME : Pathname::assertprefix + // METHOD TYPE : Pathname + // + Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r ) + { + if ( root_r.empty() + || path_r == root_r + || str::hasPrefix( path_r.asString(), root_r.asString() ) ) + return path_r; + return root_r / path_r; + } + + Pathname Pathname::stripprefix( const Pathname & root_r, const Pathname & path_r ) + { + if ( root_r.emptyOrRoot() ) + return path_r; + if ( root_r == path_r ) + return "/"; + std::string rest( str::stripPrefix( path_r.asString(), root_r.asString() ) ); + if ( rest[0] == '/' ) // needs to be a dir prefix! + return rest; + return path_r; + } + + /////////////////////////////////////////////////////////////////// + // // METHOD NAME : Pathname::cat // METHOD TYPE : Pathname // - Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv ) + Pathname Pathname::cat( const Pathname & name_r, const Pathname & add_tv ) { if ( add_tv.empty() ) - return name_tv; - if ( name_tv.empty() ) + return name_r; + if ( name_r.empty() ) return add_tv; - string ret_ti( add_tv.asString() ); - ret_ti.replace( 0, add_tv.prfx_i, "/" ); - - return name_tv.asString() + ret_ti; + string ret_ti( name_r._name ); + if( add_tv._name[0] != '/' ) + ret_ti += '/'; + return ret_ti + add_tv._name; } ///////////////////////////////////////////////////////////////////