PathInfo.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <iostream>
00014 #include <fstream>
00015 #include <iomanip>
00016 
00017 #include "zypp/base/Logger.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/IOStream.h"
00020 
00021 #include "zypp/ExternalProgram.h"
00022 #include "zypp/PathInfo.h"
00023 #include "zypp/Digest.h"
00024 
00025 #include <sys/types.h> // for ::minor, ::major macros
00026 
00027 using std::string;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace filesystem
00034   { 
00035 
00036     /******************************************************************
00037      **
00038      ** FUNCTION NAME : operator<<
00039      ** FUNCTION TYPE : std::ostream &
00040     */
00041     std::ostream & operator<<( std::ostream & str, FileType obj )
00042     {
00043       switch ( obj ) {
00044 #define EMUMOUT(T) case T: return str << #T; break
00045         EMUMOUT( FT_NOT_AVAIL );
00046         EMUMOUT( FT_NOT_EXIST );
00047         EMUMOUT( FT_FILE );
00048         EMUMOUT( FT_DIR );
00049         EMUMOUT( FT_CHARDEV );
00050         EMUMOUT( FT_BLOCKDEV );
00051         EMUMOUT( FT_FIFO );
00052         EMUMOUT( FT_LINK );
00053         EMUMOUT( FT_SOCKET );
00054 #undef EMUMOUT
00055       }
00056       return str;
00057     }
00058 
00060     //
00061     //  METHOD NAME : StatMode::fileType
00062     //  METHOD TYPE : FileType
00063     //
00064     FileType StatMode::fileType() const
00065     {
00066       if ( isFile() )
00067         return FT_FILE;
00068       if ( isDir() )
00069         return FT_DIR;
00070       if ( isLink() )
00071         return FT_LINK;
00072       if ( isChr() )
00073         return FT_CHARDEV;
00074       if ( isBlk() )
00075         return FT_BLOCKDEV;
00076       if ( isFifo() )
00077         return FT_FIFO;
00078       if ( isSock() )
00079         return FT_SOCKET ;
00080 
00081       return FT_NOT_AVAIL;
00082     }
00083 
00084     /******************************************************************
00085      **
00086      ** FUNCTION NAME : operator<<
00087      ** FUNCTION TYPE : std::ostream &
00088     */
00089     std::ostream & operator<<( std::ostream & str, const StatMode & obj )
00090     {
00091       iostr::IosFmtFlagsSaver autoResoreState( str );
00092 
00093       char t = '?';
00094       if ( obj.isFile() )
00095         t = '-';
00096       else if ( obj.isDir() )
00097         t = 'd';
00098       else if ( obj.isLink() )
00099         t = 'l';
00100       else if ( obj.isChr() )
00101         t = 'c';
00102       else if ( obj.isBlk() )
00103         t = 'b';
00104       else if ( obj.isFifo() )
00105         t = 'p';
00106       else if ( obj.isSock() )
00107         t = 's';
00108 
00109       str << t << " " << std::setfill( '0' ) << std::setw( 4 ) << std::oct << obj.perm();
00110       return str;
00111     }
00112 
00114     //
00115     //  Class : PathInfo
00116     //
00118 
00120     //
00121     //  METHOD NAME : PathInfo::PathInfo
00122     //  METHOD TYPE : Constructor
00123     //
00124     PathInfo::PathInfo()
00125     : mode_e( STAT )
00126     , error_i( -1 )
00127     {}
00128 
00130     //
00131     //  METHOD NAME : PathInfo::PathInfo
00132     //  METHOD TYPE : Constructor
00133     //
00134     PathInfo::PathInfo( const Pathname & path, Mode initial )
00135     : path_t( path )
00136     , mode_e( initial )
00137     , error_i( -1 )
00138     {
00139       operator()();
00140     }
00141 
00143     //
00144     //  METHOD NAME : PathInfo::PathInfo
00145     //  METHOD TYPE : Constructor
00146     //
00147     PathInfo::PathInfo( const std::string & path, Mode initial )
00148     : path_t( path )
00149     , mode_e( initial )
00150     , error_i( -1 )
00151     {
00152       operator()();
00153     }
00154 
00156     //
00157     //  METHOD NAME : PathInfo::PathInfo
00158     //  METHOD TYPE : Constructor
00159     //
00160     PathInfo::PathInfo( const char * path, Mode initial )
00161     : path_t( path )
00162     , mode_e( initial )
00163     , error_i( -1 )
00164     {
00165       operator()();
00166     }
00167 
00169     //
00170     //  METHOD NAME : PathInfo::~PathInfo
00171     //  METHOD TYPE : Destructor
00172     //
00173     PathInfo::~PathInfo()
00174     {
00175     }
00176 
00178     //
00179     //  METHOD NAME : PathInfo::operator()
00180     //  METHOD TYPE : bool
00181     //
00182     bool PathInfo::operator()()
00183     {
00184       if ( path_t.empty() ) {
00185         error_i = -1;
00186       } else {
00187         switch ( mode_e ) {
00188         case STAT:
00189           error_i = ::stat( path_t.asString().c_str(), &statbuf_C );
00190           break;
00191         case LSTAT:
00192           error_i = ::lstat( path_t.asString().c_str(), &statbuf_C );
00193           break;
00194         }
00195         if ( error_i == -1 )
00196           error_i = errno;
00197       }
00198       return !error_i;
00199     }
00200 
00202     //
00203     //  METHOD NAME : PathInfo::fileType
00204     //  METHOD TYPE : File_type
00205     //
00206     FileType PathInfo::fileType() const
00207     {
00208       if ( isExist() )
00209         return asStatMode().fileType();
00210       return FT_NOT_EXIST;
00211     }
00212 
00214     //
00215     //  METHOD NAME : PathInfo::userMay
00216     //  METHOD TYPE : mode_t
00217     //
00218     mode_t PathInfo::userMay() const
00219     {
00220       if ( !isExist() )
00221         return 0;
00222       if ( owner() == getuid() ) {
00223         return( uperm()/0100 );
00224       } else if ( group() == getgid() ) {
00225         return( gperm()/010 );
00226       }
00227       return operm();
00228     }
00229 
00230     /******************************************************************
00231      **
00232      ** FUNCTION NAME : PathInfo::major
00233      ** FUNCTION TYPE : unsigned int
00234      */
00235     unsigned int PathInfo::major() const
00236     {
00237       return isBlk() || isChr() ? ::major(statbuf_C.st_rdev) : 0;
00238     }
00239 
00240     /******************************************************************
00241      **
00242      ** FUNCTION NAME : PathInfo::minor
00243      ** FUNCTION TYPE : unsigned int
00244      */
00245     unsigned int PathInfo::minor() const
00246     {
00247       return isBlk() || isChr() ? ::minor(statbuf_C.st_rdev) : 0;
00248     }
00249 
00250     /******************************************************************
00251      **
00252      ** FUNCTION NAME : operator<<
00253      ** FUNCTION TYPE :  std::ostream &
00254     */
00255     std::ostream & operator<<( std::ostream & str, const PathInfo & obj )
00256     {
00257       iostr::IosFmtFlagsSaver autoResoreState( str );
00258 
00259       str << obj.asString() << "{";
00260       if ( !obj.isExist() ) {
00261         str << "does not exist}";
00262       } else {
00263         str << obj.asStatMode() << " " << std::dec << obj.owner() << "/" << obj.group();
00264 
00265         if ( obj.isFile() )
00266           str << " size " << obj.size();
00267 
00268         str << "}";
00269       }
00270 
00271       return str;
00272     }
00273 
00275     //
00276     //  filesystem utilities
00277     //
00279 
00280     /******************************************************************
00281      **
00282      ** FUNCTION NAME : _Log_Result
00283      ** FUNCTION TYPE : int
00284      **
00285      ** DESCRIPTION : Helper function to log return values.
00286     */
00287     inline int _Log_Result( const int res, const char * rclass = "errno" )
00288     {
00289       if ( res )
00290         DBG << " FAILED: " << rclass << " " << res;
00291       DBG << std::endl;
00292       return res;
00293     }
00294 
00296     //
00297     //  METHOD NAME : PathInfo::mkdir
00298     //  METHOD TYPE : int
00299     //
00300     int mkdir( const Pathname & path, unsigned mode )
00301     {
00302       DBG << "mkdir " << path << ' ' << str::octstring( mode );
00303       if ( ::mkdir( path.asString().c_str(), mode ) == -1 ) {
00304         return _Log_Result( errno );
00305       }
00306       return _Log_Result( 0 );
00307     }
00308 
00310     //
00311     //  METHOD NAME : assert_dir()
00312     //  METHOD TYPE : int
00313     //
00314     int assert_dir( const Pathname & path, unsigned mode )
00315     {
00316       string::size_type pos, lastpos = 0;
00317       string spath = path.asString()+"/";
00318       int ret = 0;
00319 
00320       if(path.empty())
00321         return ENOENT;
00322 
00323       // skip ./
00324       if(path.relative())
00325         lastpos=2;
00326       // skip /
00327       else
00328         lastpos=1;
00329 
00330       //    DBG << "about to create " << spath << endl;
00331       while((pos = spath.find('/',lastpos)) != string::npos )
00332         {
00333           string dir = spath.substr(0,pos);
00334           ret = ::mkdir(dir.c_str(), mode);
00335           if(ret == -1)
00336             {
00337               // ignore errors about already existing directorys
00338               if(errno == EEXIST)
00339                 ret=0;
00340               else
00341                 ret=errno;
00342             }
00343           //    DBG << "creating directory " << dir << (ret?" failed":" succeeded") << endl;
00344           lastpos = pos+1;
00345         }
00346       return ret;
00347     }
00348 
00350     //
00351     //  METHOD NAME : rmdir
00352     //  METHOD TYPE : int
00353     //
00354     int rmdir( const Pathname & path )
00355     {
00356       DBG << "rmdir " << path;
00357       if ( ::rmdir( path.asString().c_str() ) == -1 ) {
00358         return _Log_Result( errno );
00359       }
00360       return _Log_Result( 0 );
00361     }
00362 
00364     //
00365     //  METHOD NAME : recursive_rmdir
00366     //  METHOD TYPE : int
00367     //
00368     int recursive_rmdir( const Pathname & path )
00369     {
00370       DBG << "recursive_rmdir " << path << ' ';
00371       PathInfo p( path );
00372 
00373       if ( !p.isExist() ) {
00374         return _Log_Result( 0 );
00375       }
00376 
00377       if ( !p.isDir() ) {
00378         return _Log_Result( ENOTDIR );
00379       }
00380 
00381       const char *const argv[] = {
00382         "/bin/rm",
00383         "-rf",
00384         "--preserve-root",
00385         "--",
00386         path.asString().c_str(),
00387         NULL
00388       };
00389 
00390       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00391       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00392         DBG << "  " << output;
00393       }
00394       int ret = prog.close();
00395       return _Log_Result( ret, "returned" );
00396     }
00397 
00399     //
00400     //  METHOD NAME : clean_dir
00401     //  METHOD TYPE : int
00402     //
00403     int clean_dir( const Pathname & path )
00404     {
00405       DBG << "clean_dir " << path << ' ';
00406       PathInfo p( path );
00407 
00408       if ( !p.isExist() ) {
00409         return _Log_Result( 0 );
00410       }
00411 
00412       if ( !p.isDir() ) {
00413         return _Log_Result( ENOTDIR );
00414       }
00415 
00416       string cmd( str::form( "cd '%s' && rm -rf --preserve-root -- *", path.asString().c_str() ) );
00417       ExternalProgram prog( cmd, ExternalProgram::Stderr_To_Stdout );
00418       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00419         DBG << "  " << output;
00420       }
00421       int ret = prog.close();
00422       return _Log_Result( ret, "returned" );
00423     }
00424 
00426     //
00427     //  METHOD NAME : copy_dir
00428     //  METHOD TYPE : int
00429     //
00430     int copy_dir( const Pathname & srcpath, const Pathname & destpath )
00431     {
00432       DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
00433 
00434       PathInfo sp( srcpath );
00435       if ( !sp.isDir() ) {
00436         return _Log_Result( ENOTDIR );
00437       }
00438 
00439       PathInfo dp( destpath );
00440       if ( !dp.isDir() ) {
00441         return _Log_Result( ENOTDIR );
00442       }
00443 
00444       PathInfo tp( destpath + srcpath.basename() );
00445       if ( tp.isExist() ) {
00446         return _Log_Result( EEXIST );
00447       }
00448 
00449 
00450       const char *const argv[] = {
00451         "/bin/cp",
00452         "-dR",
00453         "--",
00454         srcpath.asString().c_str(),
00455         destpath.asString().c_str(),
00456         NULL
00457       };
00458       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00459       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00460         DBG << "  " << output;
00461       }
00462       int ret = prog.close();
00463       return _Log_Result( ret, "returned" );
00464     }
00465 
00467     //
00468     //  METHOD NAME : copy_dir_content
00469     //  METHOD TYPE : int
00470     //
00471     int copy_dir_content(const Pathname & srcpath, const Pathname & destpath)
00472     {
00473       DBG << "copy_dir " << srcpath << " -> " << destpath << ' ';
00474 
00475       PathInfo sp( srcpath );
00476       if ( !sp.isDir() ) {
00477         return _Log_Result( ENOTDIR );
00478       }
00479 
00480       PathInfo dp( destpath );
00481       if ( !dp.isDir() ) {
00482         return _Log_Result( ENOTDIR );
00483       }
00484 
00485       if ( srcpath == destpath ) {
00486         return _Log_Result( EEXIST );
00487       }
00488 
00489       std::string src( srcpath.asString());
00490       src += "/.";
00491       const char *const argv[] = {
00492         "/bin/cp",
00493         "-dR",
00494         "--",
00495         src.c_str(),
00496         destpath.asString().c_str(),
00497         NULL
00498       };
00499       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00500       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00501         DBG << "  " << output;
00502       }
00503       int ret = prog.close();
00504       return _Log_Result( ret, "returned" );
00505     }
00506 
00508     //
00509     //  METHOD NAME : readdir
00510     //  METHOD TYPE : int
00511     //
00512     int readdir( std::list<std::string> & retlist,
00513                  const Pathname & path, bool dots )
00514     {
00515       retlist.clear();
00516 
00517       DBG << "readdir " << path << ' ';
00518 
00519       DIR * dir = ::opendir( path.asString().c_str() );
00520       if ( ! dir ) {
00521         return _Log_Result( errno );
00522       }
00523 
00524       struct dirent *entry;
00525       while ( (entry = ::readdir( dir )) != 0 ) {
00526 
00527         if ( entry->d_name[0] == '.' ) {
00528           if ( !dots )
00529             continue;
00530           if ( entry->d_name[1] == '\0'
00531                || (    entry->d_name[1] == '.'
00532                     && entry->d_name[2] == '\0' ) )
00533             continue;
00534         }
00535         retlist.push_back( entry->d_name );
00536       }
00537 
00538       ::closedir( dir );
00539 
00540       return _Log_Result( 0 );
00541     }
00542 
00543 
00545     //
00546     //  METHOD NAME : readdir
00547     //  METHOD TYPE : int
00548     //
00549     int readdir( std::list<Pathname> & retlist,
00550                  const Pathname & path, bool dots )
00551     {
00552       retlist.clear();
00553 
00554       std::list<string> content;
00555       int res = readdir( content, path, dots );
00556 
00557       if ( !res ) {
00558         for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
00559           retlist.push_back( path + *it );
00560         }
00561       }
00562 
00563       return res;
00564     }
00565 
00567     //
00568     //  METHOD NAME : readdir
00569     //  METHOD TYPE : int
00570     //
00571     int readdir( DirContent & retlist, const Pathname & path,
00572                  bool dots, PathInfo::Mode statmode )
00573     {
00574       retlist.clear();
00575 
00576       std::list<string> content;
00577       int res = readdir( content, path, dots );
00578 
00579       if ( !res ) {
00580         for ( std::list<string>::const_iterator it = content.begin(); it != content.end(); ++it ) {
00581           PathInfo p( path + *it, statmode );
00582           retlist.push_back( DirEntry( *it, p.fileType() ) );
00583         }
00584       }
00585 
00586       return res;
00587     }
00588 
00590     //
00591     //  METHOD NAME : is_empty_dir
00592     //  METHOD TYPE : int
00593     //
00594     int is_empty_dir(const Pathname & path)
00595     {
00596       DIR * dir = ::opendir( path.asString().c_str() );
00597       if ( ! dir ) {
00598         return _Log_Result( errno );
00599       }
00600 
00601       struct dirent *entry;
00602       while ( (entry = ::readdir( dir )) != NULL )
00603       {
00604         std::string name(entry->d_name);
00605 
00606         if ( name == "." || name == "..")
00607           continue;
00608 
00609         break;
00610       }
00611       ::closedir( dir );
00612 
00613       return entry != NULL ? -1 : 0;
00614     }
00615 
00617     //
00618     //  METHOD NAME : unlink
00619     //  METHOD TYPE : int
00620     //
00621     int unlink( const Pathname & path )
00622     {
00623       DBG << "unlink " << path;
00624       if ( ::unlink( path.asString().c_str() ) == -1 ) {
00625         return _Log_Result( errno );
00626       }
00627       return _Log_Result( 0 );
00628     }
00629 
00631     //
00632     //  METHOD NAME : rename
00633     //  METHOD TYPE : int
00634     //
00635     int rename( const Pathname & oldpath, const Pathname & newpath )
00636     {
00637       DBG << "rename " << oldpath << " -> " << newpath;
00638       if ( ::rename( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00639         return _Log_Result( errno );
00640       }
00641       return _Log_Result( 0 );
00642     }
00643 
00645     //
00646     //  METHOD NAME : copy
00647     //  METHOD TYPE : int
00648     //
00649     int copy( const Pathname & file, const Pathname & dest )
00650     {
00651       DBG << "copy " << file << " -> " << dest << ' ';
00652 
00653       PathInfo sp( file );
00654       if ( !sp.isFile() ) {
00655         return _Log_Result( EINVAL );
00656       }
00657 
00658       PathInfo dp( dest );
00659       if ( dp.isDir() ) {
00660         return _Log_Result( EISDIR );
00661       }
00662 
00663       const char *const argv[] = {
00664         "/bin/cp",
00665         "--",
00666         file.asString().c_str(),
00667         dest.asString().c_str(),
00668         NULL
00669       };
00670       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00671       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00672         DBG << "  " << output;
00673       }
00674       int ret = prog.close();
00675       return _Log_Result( ret, "returned" );
00676     }
00677 
00679     //
00680     //  METHOD NAME : symlink
00681     //  METHOD TYPE : int
00682     //
00683     int symlink( const Pathname & oldpath, const Pathname & newpath )
00684     {
00685       DBG << "symlink " << newpath << " -> " << oldpath;
00686       if ( ::symlink( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00687         return _Log_Result( errno );
00688       }
00689       return _Log_Result( 0 );
00690     }
00691 
00693     //
00694     //  METHOD NAME : hardlink
00695     //  METHOD TYPE : int
00696     //
00697     int hardlink( const Pathname & oldpath, const Pathname & newpath )
00698     {
00699       DBG << "hardlink " << newpath << " -> " << oldpath;
00700       if ( ::link( oldpath.asString().c_str(), newpath.asString().c_str() ) == -1 ) {
00701         return _Log_Result( errno );
00702       }
00703       return _Log_Result( 0 );
00704     }
00705 
00707     //
00708     //  METHOD NAME : copy_file2dir
00709     //  METHOD TYPE : int
00710     //
00711     int copy_file2dir( const Pathname & file, const Pathname & dest )
00712     {
00713       DBG << "copy_file2dir " << file << " -> " << dest << ' ';
00714 
00715       PathInfo sp( file );
00716       if ( !sp.isFile() ) {
00717         return _Log_Result( EINVAL );
00718       }
00719 
00720       PathInfo dp( dest );
00721       if ( !dp.isDir() ) {
00722         return _Log_Result( ENOTDIR );
00723       }
00724 
00725       const char *const argv[] = {
00726         "/bin/cp",
00727         "--",
00728         file.asString().c_str(),
00729         dest.asString().c_str(),
00730         NULL
00731       };
00732       ExternalProgram prog( argv, ExternalProgram::Stderr_To_Stdout );
00733       for ( string output( prog.receiveLine() ); output.length(); output = prog.receiveLine() ) {
00734         DBG << "  " << output;
00735       }
00736       int ret = prog.close();
00737       return _Log_Result( ret, "returned" );
00738     }
00739 
00741     //
00742     //  METHOD NAME : md5sum
00743     //  METHOD TYPE : std::string
00744     //
00745     std::string md5sum( const Pathname & file )
00746     {
00747       if ( ! PathInfo( file ).isFile() ) {
00748         return string();
00749       }
00750       std::ifstream istr( file.asString().c_str() );
00751       if ( ! istr ) {
00752         return string();
00753       }
00754       return Digest::digest( "MD5", istr );
00755     }
00756 
00758     //
00759     //  METHOD NAME : sha1sum
00760     //  METHOD TYPE : std::string
00761     //
00762     std::string sha1sum( const Pathname & file )
00763     {
00764       if ( ! PathInfo( file ).isFile() ) {
00765         return string();
00766       }
00767       std::ifstream istr( file.asString().c_str() );
00768       if ( ! istr ) {
00769         return string();
00770       }
00771       return Digest::digest( "SHA1", istr );
00772     }
00773 
00775     //
00776     //  METHOD NAME : erase
00777     //  METHOD TYPE : int
00778     //
00779     int erase( const Pathname & path )
00780     {
00781       int res = 0;
00782       PathInfo p( path, PathInfo::LSTAT );
00783       if ( p.isExist() )
00784         {
00785           if ( p.isDir() )
00786             res = recursive_rmdir( path );
00787           else
00788             res = unlink( path );
00789         }
00790       return res;
00791     }
00792 
00794     //
00795     //  METHOD NAME : chmod
00796     //  METHOD TYPE : int
00797     //
00798     int chmod( const Pathname & path, mode_t mode )
00799     {
00800       DBG << "chmod " << path << ' ' << str::octstring( mode );
00801       if ( ::chmod( path.asString().c_str(), mode ) == -1 ) {
00802         return _Log_Result( errno );
00803       }
00804       return _Log_Result( 0 );
00805     }
00806 
00808     //
00809     //  METHOD NAME : zipType
00810     //  METHOD TYPE : ZIP_TYPE
00811     //
00812     ZIP_TYPE zipType( const Pathname & file )
00813     {
00814       ZIP_TYPE ret = ZT_NONE;
00815 
00816       int fd = open( file.asString().c_str(), O_RDONLY );
00817 
00818       if ( fd != -1 ) {
00819         const int magicSize = 3;
00820         unsigned char magic[magicSize];
00821         memset( magic, 0, magicSize );
00822         if ( read( fd, magic, magicSize ) == magicSize ) {
00823           if ( magic[0] == 0037 && magic[1] == 0213 ) {
00824             ret = ZT_GZ;
00825           } else if ( magic[0] == 'B' && magic[1] == 'Z' && magic[2] == 'h' ) {
00826             ret = ZT_BZ2;
00827           }
00828         }
00829         close( fd );
00830       }
00831 
00832       return ret;
00833     }
00834 
00836   } // namespace filesystem
00839 } // namespace zypp

Generated on Mon Jun 5 19:10:34 2006 for zypp by  doxygen 1.4.6