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

doxygen