libzypp  10.5.0
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     //
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