// -*- C++ -*- (c) 2015 Jiří Weiser // (c) 2014 Vladimír Štill /* * This file contains couple of (sometimes a little bit modified) * functions from bricks/brick-fs.h. */ #include "fs-utils.h" #ifndef _FS_PATH_H_ #define _FS_PATH_H_ namespace divine { namespace fs { namespace path { #if defined( __unix ) const char pathSeparators[] = { '/' }; #elif defined( _WIN32 ) const char pathSeparators[] = { '\\', '/' }; #endif inline bool isPathSeparator( char c ) { for ( auto sep : pathSeparators ) if ( sep == c ) return true; return false; } inline std::pair< utils::String, utils::String > absolutePrefix( utils::String path ) { #ifdef _WIN32 /* this must go before general case, because \ is prefix of \\ */ if ( path.size() >= 3 && path[ 1 ] == ':' && isPathSeparator( path[ 2 ] ) ) return std::make_pair( path.substr( 0, 3 ), path.substr( 3 ) ); if ( path.size() >= 2 && isPathSeparator( path[ 0 ] ) && isPathSeparator( path[ 1 ] ) ) return std::make_pair( path.substr( 0, 2 ), path.substr( 2 ) ); #endif // this is absolute path in both windows and unix if ( path.size() >= 1 && isPathSeparator( path[ 0 ] ) ) return std::make_pair( path.substr( 0, 1 ), path.substr( 1 ) ); return std::make_pair( utils::String(), path ); } inline bool isAbsolute( utils::String path ) { return absolutePrefix( std::move( path ) ).first.size() != 0; } inline bool isRelative( utils::String path ) { return !isAbsolute( std::move( path ) ); } inline std::pair< utils::String, utils::String > splitFileName( utils::String path ) { auto begin = path.rbegin(); while ( isPathSeparator( *begin ) ) ++begin; auto length = &*begin - &path.front() + 1; auto pos = std::find_if( begin, path.rend(), &isPathSeparator ); if ( pos == path.rend() ) return std::make_pair( utils::String(), path.substr( 0, length ) ); auto count = &*pos - &path.front(); length -= count + 1; return std::make_pair( path.substr( 0, count ), path.substr( count + 1, length ) ); } inline utils::String joinPath( utils::Vector< utils::String > paths, bool normalize = false ) { if ( paths.empty() ) return ""; auto it = ++paths.begin(); utils::String out = paths[0]; for ( ; it != paths.end(); ++it ) { if ( isAbsolute( *it ) || out.empty() ) out = *it; else if ( !out.empty() && isPathSeparator( out.back() ) ) out += *it; else out += pathSeparators[0] + *it; } return out; } template< typename... FilePaths > inline utils::String joinPath( FilePaths &&...paths ) { return joinPath( utils::Vector< utils::String >{ std::forward< FilePaths >( paths )... } ); } template< typename Result = utils::Vector< utils::String > > inline Result splitPath( const utils::String &path, bool normalize = false ) { Result out; auto last = path.begin(); while ( true ) { auto next = std::find_if( last, path.end(), &isPathSeparator ); if ( next == path.end() ) { utils::String s( last, next ); if ( normalize && s == "." ); else if ( normalize && s == ".." ) { if ( !out.empty() && out.back() != ".." ) out.pop_back(); else out.emplace_back( std::move( s ) ); } else out.emplace_back( std::move( s ) ); return out; } if ( last != next ) { utils::String s( last, next ); if ( normalize && s == "." ); else if ( normalize && s == ".." ) { if ( !out.empty() && out.back() != ".." ) out.pop_back(); else out.emplace_back( std::move( s ) ); } else out.emplace_back( std::move( s ) ); } last = ++next; } } inline utils::String normalize( utils::String path ) { auto abs = absolutePrefix( path ); return joinPath( abs.first, joinPath( splitPath( abs.second, true ) ) ); } } // namespace path } // namespace fs } // namespace divine #endif