libzypp 8.13.6

Pathname.cc

Go to the documentation of this file.
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 
00032       //
00033       //        CLASS NAME : DirStack
00034       //
00037       class DirStack {
00038 
00039         struct Dir {
00040 
00041           Dir *  up;
00042           Dir *  dn;
00043           string name;
00044 
00045           Dir( const string & n = "" ) {
00046             name = n;
00047             up = dn = 0;
00048           }
00049 
00050           ~Dir() {
00051             if ( up )
00052               up->dn = dn;
00053             if ( dn )
00054               dn->up = up;
00055           }
00056         };
00057 
00058         Dir *  top;
00059         Dir *  bot;
00060 
00061         void Pop() {
00062           if ( !top )
00063             return;
00064           top = top->dn;
00065           if ( top )
00066             delete top->up;
00067           else {
00068             delete bot;
00069             bot = 0;
00070           }
00071         }
00072 
00073       public:
00074 
00075         DirStack() { top = bot = 0; }
00076         ~DirStack() {
00077           while ( bot )
00078             Pop();
00079         }
00080 
00081         void Push( const string & n ) {
00082           if ( n.empty() || n == "." ) { // '.' or '/' only for bot
00083             if ( bot )
00084               return;
00085           } else if ( n == ".." && top ) {
00086             if ( top->name == "" )          // "/.."        ==> "/"
00087               return;
00088 
00089             if ( top->name != "." && top->name != ".." ) {      // "somedir/.." ==> ""
00090               Pop();
00091               return;
00092             }
00093             // "../.." "./.." stays
00094           }
00095 
00096           Dir * d = new Dir( n );
00097           if ( !top )
00098             top = bot = d;
00099           else {
00100             top->up = d;
00101             d->dn = top;
00102             d->up = 0;
00103             top = d;
00104           }
00105         }
00106 
00107         string str() {
00108           if ( !bot )
00109             return "";
00110           string ret;
00111           for ( Dir * d = bot; d; d = d->up ) {
00112             if ( d != bot )
00113               ret += "/";
00114             ret += d->name;
00115           }
00116           if ( ret.empty() )
00117             return "/";
00118           return ret;
00119         }
00120       };
00121 
00123     } // namespace
00125 
00127     //
00128     //  METHOD NAME : Pathname::_assign
00129     //  METHOD TYPE : void
00130     //
00131     void Pathname::_assign( const string & name_tv )
00132     {
00133       prfx_i = 0;
00134       name_t = name_tv;
00135 
00136       if ( name_t.empty() )
00137         return;
00138 
00139       string   Tprfx;
00140       DirStack Stack_Ci;
00141 
00142       char *       Buf_aci    = new char[name_tv.length() + 1];
00143       char *       W_pci      = Buf_aci;
00144       const char * R_pci      = name_tv.c_str();
00145 
00146       // check for prefix
00147       if (    name_t.length() >= 2
00148            && name_t[1] == ':'
00149            && (    ( 'a' <= name_t[0] && name_t[0] <= 'z' )
00150                 || ( 'A' <= name_t[0] && name_t[0] <= 'Z' ) ) ) {
00151         Tprfx  = name_t.substr( 0, 2 );
00152         prfx_i = 2;
00153         R_pci += 2;
00154       }
00155 
00156       // rel or abs path
00157       if ( *R_pci == '/' ) {
00158         Stack_Ci.Push( "" );
00159         ++R_pci;
00160       } else {
00161         Stack_Ci.Push( "." );
00162       }
00163 
00164       do {
00165         switch ( *R_pci ) {
00166         case '/':
00167         case '\0':
00168           if ( W_pci != Buf_aci ) {
00169             *W_pci = '\0';
00170             W_pci = Buf_aci;
00171             Stack_Ci.Push( Buf_aci );
00172           }
00173           break;
00174 
00175         default:
00176           *W_pci++ = *R_pci;
00177           break;
00178         }
00179       } while( *R_pci++ );
00180 
00181       delete[] Buf_aci;
00182       name_t = Tprfx + Stack_Ci.str();
00183     }
00184 
00186     //
00187     //  METHOD NAME : Pathname::dirname
00188     //  METHOD TYPE : Pathname
00189     //
00190     Pathname Pathname::dirname( const Pathname & name_tv )
00191     {
00192       if ( name_tv.empty() )
00193         return "";
00194 
00195       Pathname ret_t( name_tv );
00196       string::size_type idx = ret_t.name_t.find_last_of( '/' );
00197 
00198       if ( idx == string::npos ) {
00199         ret_t.name_t.erase( ret_t.prfx_i );
00200         ret_t.name_t += ".";
00201       } else if ( idx == ret_t.prfx_i ) {
00202         ret_t.name_t.erase( ret_t.prfx_i );
00203         ret_t.name_t += "/";
00204       } else {
00205         ret_t.name_t.erase( idx );
00206       }
00207 
00208       return ret_t;
00209     }
00210 
00212     //
00213     //  METHOD NAME : Pathname::basename
00214     //  METHOD TYPE : string
00215     //
00216     string Pathname::basename( const Pathname & name_tv )
00217     {
00218       if ( name_tv.empty() )
00219         return string();
00220 
00221       string ret_t( name_tv.asString() );
00222       ret_t.erase( 0, name_tv.prfx_i );
00223       string::size_type idx = ret_t.find_last_of( '/' );
00224       if ( idx != string::npos ) {
00225         ret_t.erase( 0, idx+1 );
00226       }
00227 
00228       return ret_t;
00229     }
00230 
00232     //
00233     //  METHOD NAME : Pathname::asUrl
00234     //  METHOD TYPE : Url
00235     //
00236     Url Pathname::asUrl() const
00237     {
00238       Url ret( "dir:///" );
00239       ret.setPathName( asString() );
00240       return ret;
00241     }
00242 
00243     std::string Pathname::showRoot( const Pathname & root_r, const Pathname & path_r )
00244     {
00245       return str::Str() << "(" << root_r << ")" << path_r;
00246     }
00247 
00248     std::string Pathname::showRootIf( const Pathname & root_r, const Pathname & path_r )
00249     {
00250       if ( root_r.empty() || root_r == "/" )
00251         return path_r.asString();
00252       return showRoot( root_r, path_r );
00253     }
00254 
00256     //
00257     //  METHOD NAME : Pathname::extension
00258     //  METHOD TYPE : string
00259     //
00260     string Pathname::extension( const Pathname & name_tv )
00261     {
00262       if ( name_tv.empty() )
00263         return string();
00264 
00265       string base( basename( name_tv ) );
00266       string::size_type pos = base.rfind( '.' );
00267       if ( pos == string::npos )
00268         return string();
00269       return base.substr( pos );
00270     }
00271 
00273     //
00274     //  METHOD NAME : Pathname::assertprefix
00275     //  METHOD TYPE : Pathname
00276     //
00277     Pathname Pathname::assertprefix( const Pathname & root_r, const Pathname & path_r )
00278     {
00279       if ( root_r.empty()
00280            || path_r == root_r
00281            || str::hasPrefix( path_r.asString(), root_r.asString() ) )
00282         return path_r;
00283       return root_r / path_r;
00284     }
00285 
00287     //
00288     //  METHOD NAME : Pathname::cat
00289     //  METHOD TYPE : Pathname
00290     //
00291     Pathname Pathname::cat( const Pathname & name_tv, const Pathname & add_tv )
00292     {
00293       if ( add_tv.empty() )
00294         return name_tv;
00295       if ( name_tv.empty() )
00296         return add_tv;
00297 
00298       string ret_ti( add_tv.asString() );
00299       ret_ti.replace( 0, add_tv.prfx_i, "/" );
00300 
00301       return name_tv.asString() + ret_ti;
00302     }
00303 
00305     //
00306     //  METHOD NAME : Pathname::Extend
00307     //  METHOD TYPE : Pathname
00308     //
00309     Pathname Pathname::extend( const Pathname & l, const string & r )
00310     {
00311       return l.asString() + r;
00312     }
00313 
00315   } // namespace filesystem
00318 } // namespace zypp