Filesystem abstraction prototype - Partial path implementation
Initialisation, assignment, comparison, conversion to string, hashing
This commit is contained in:
parent
0ae69daf05
commit
81a8390606
3 changed files with 340 additions and 4 deletions
2
Makefile
2
Makefile
|
@ -43,6 +43,8 @@ COMMON = \
|
||||||
c-sync.cc \
|
c-sync.cc \
|
||||||
c-syncedit.cc \
|
c-syncedit.cc \
|
||||||
c-syncoverrides.cc \
|
c-syncoverrides.cc \
|
||||||
|
\
|
||||||
|
p-filesystem.cc \
|
||||||
# END COMMON
|
# END COMMON
|
||||||
|
|
||||||
TOOL = \
|
TOOL = \
|
||||||
|
|
182
p-filesystem.cc
Normal file
182
p-filesystem.cc
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/******************************************************************************/
|
||||||
|
/* FILESYSTEM ABSTRACTION *****************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <p-filesystem.hh>
|
||||||
|
using namespace ebcl;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define M_PATHSEP_ '\\'
|
||||||
|
#else
|
||||||
|
# define M_PATHSEP_ '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_FSPath =================================================================*/
|
||||||
|
|
||||||
|
bool T_FSPath::IsValidRoot(
|
||||||
|
T_String const& str ) noexcept
|
||||||
|
{
|
||||||
|
if ( !str ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// TODO: support for network names (\\server\path)
|
||||||
|
if ( str.length( ) == 3 && ( str.endsWith( ":\\" )
|
||||||
|
|| str.endsWith( ":/" ) ) ) {
|
||||||
|
return str[ 0 ].isAlpha( );
|
||||||
|
} else {
|
||||||
|
return ( str == "/" || str == "\\" );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return ( str == "/" || str == "\\" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool T_FSPath::IsValidComponent(
|
||||||
|
T_String const& str ) noexcept
|
||||||
|
{
|
||||||
|
if ( !str ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
T_StringIterator it{ str };
|
||||||
|
while ( !it.atEnd( ) ) {
|
||||||
|
const auto c{ it.character( ) };
|
||||||
|
it.next( );
|
||||||
|
if ( c.isControl( ) || c == '\\' || c == '/' || c == '"'
|
||||||
|
|| c == '<' || c == '>' || c == '|' || c == ':'
|
||||||
|
|| c == '*' || c == '?' ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
T_FSPath::T_FSPath(
|
||||||
|
T_String const& path ) noexcept
|
||||||
|
{
|
||||||
|
if ( !path ) {
|
||||||
|
valid_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find sequences of (back)slashes in the string. For each sequence
|
||||||
|
// we will store the positions of the first and last (back)slash.
|
||||||
|
T_AutoArray< uint32_t , 64 > slashPos;
|
||||||
|
T_StringIterator it{ path };
|
||||||
|
while ( !it.atEnd( ) ) {
|
||||||
|
const auto c{ it.character( ) };
|
||||||
|
const auto p{ it.index( ) };
|
||||||
|
it.next( );
|
||||||
|
|
||||||
|
if ( c != '/' && c != '\\' ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ps{ slashPos.size( ) };
|
||||||
|
if ( ps == 0 || slashPos[ ps - 1 ] != p - 1 ) {
|
||||||
|
slashPos.add( p );
|
||||||
|
slashPos.add( p );
|
||||||
|
} else {
|
||||||
|
slashPos[ ps - 1 ] ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No (back)slashes, this is a relative path
|
||||||
|
const auto sps{ slashPos.size( ) };
|
||||||
|
if ( sps == 0 ) {
|
||||||
|
components_.add( path );
|
||||||
|
valid_ = IsValidComponent( path );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect the first item, with the first (back)slash included,
|
||||||
|
// check if it's a root
|
||||||
|
const auto firstSlashPos{ slashPos[ 0 ] };
|
||||||
|
T_String firstItem{ path.substr( 0 , 1 + firstSlashPos ) };
|
||||||
|
valid_ = true;
|
||||||
|
if ( IsValidRoot( firstItem ) ) {
|
||||||
|
root_ = std::move( firstItem );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and check the components
|
||||||
|
uint32_t pos{ root_ ? 2u : 0u };
|
||||||
|
while ( pos <= sps ) {
|
||||||
|
T_String item{ path.range(
|
||||||
|
pos ? ( 1 + slashPos[ pos - 1 ] ) : 0 ,
|
||||||
|
pos == sps ? path.length( ) : ( slashPos[ pos ] - 1 ) )
|
||||||
|
};
|
||||||
|
assert( item || pos == sps );
|
||||||
|
if ( item ) {
|
||||||
|
valid_ = valid_ && IsValidComponent( item );
|
||||||
|
components_.add( std::move( item ) );
|
||||||
|
}
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
uint32_t T_FSPath::computeHash( ) const noexcept
|
||||||
|
{
|
||||||
|
uint32_t h{ ComputeHash( root_ ) };
|
||||||
|
const auto cs{ components_.size( ) };
|
||||||
|
h = ( ( h << 27 ) | ( h >> 5 ) ) ^ cs;
|
||||||
|
for ( auto i = 0u ; i < cs ; i ++ ) {
|
||||||
|
h = ( ( h << 27 ) | ( h >> 5 ) ) ^ ComputeHash( components_[ i ] );
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void T_FSPath::appendTo(
|
||||||
|
T_StringBuilder& sb ) const noexcept
|
||||||
|
{
|
||||||
|
const auto cs{ components_.size( ) };
|
||||||
|
if ( !( root_ || cs ) ) {
|
||||||
|
sb << '.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto i = 0u ; i < cs ; i ++ ) {
|
||||||
|
if ( i == 0 ) {
|
||||||
|
sb << root_;
|
||||||
|
} else {
|
||||||
|
sb << M_PATHSEP_;
|
||||||
|
}
|
||||||
|
sb << components_[ i ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define M_CMPSTR_(A,B) (A).compareIgnoreCase( B )
|
||||||
|
#else
|
||||||
|
# define M_CMPSTR_(A,B) (A).compare( B )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32_t T_FSPath::compareTo(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
if ( &other == this ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t cmp{ M_CMPSTR_( root_ , other.root_ ) };
|
||||||
|
if ( cmp == 0 ) {
|
||||||
|
const auto nca{ components_.size( ) } ,
|
||||||
|
ncb{ other.components_.size( ) } ,
|
||||||
|
nc{ std::min( nca , ncb ) };
|
||||||
|
for ( auto i = 0u ; i < nc && cmp == 0 ; i ++ ) {
|
||||||
|
cmp = M_CMPSTR_( components_[ i ] , other.components_[ i ] );
|
||||||
|
}
|
||||||
|
if ( cmp == 0 ) {
|
||||||
|
cmp = T_Comparator< uint32_t >::compare( nca , ncb );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmp;
|
||||||
|
}
|
160
p-filesystem.hh
160
p-filesystem.hh
|
@ -54,7 +54,6 @@ class T_FSPath
|
||||||
|
|
||||||
T_String const& root( ) const noexcept;
|
T_String const& root( ) const noexcept;
|
||||||
T_Components const& components( ) const noexcept;
|
T_Components const& components( ) const noexcept;
|
||||||
// FIXME: provide iterators for the components
|
|
||||||
|
|
||||||
bool isRelative( ) const noexcept;
|
bool isRelative( ) const noexcept;
|
||||||
bool isAbsolute( ) const noexcept;
|
bool isAbsolute( ) const noexcept;
|
||||||
|
@ -68,10 +67,14 @@ class T_FSPath
|
||||||
// Append to a string builder
|
// Append to a string builder
|
||||||
void appendTo( T_StringBuilder& sb ) const noexcept;
|
void appendTo( T_StringBuilder& sb ) const noexcept;
|
||||||
|
|
||||||
// Equality operators. On Windows the comparison will be
|
// Comparisons. On Windows the comparison will be case-insensitive.
|
||||||
// case-insensitive.
|
int32_t compareTo( T_FSPath const& other ) const noexcept;
|
||||||
bool operator ==( T_FSPath const& other ) const noexcept;
|
bool operator ==( T_FSPath const& other ) const noexcept;
|
||||||
bool operator !=( T_FSPath const& other ) const noexcept;
|
bool operator !=( T_FSPath const& other ) const noexcept;
|
||||||
|
bool operator <( T_FSPath const& other ) const noexcept;
|
||||||
|
bool operator <=( T_FSPath const& other ) const noexcept;
|
||||||
|
bool operator >( T_FSPath const& other ) const noexcept;
|
||||||
|
bool operator >=( T_FSPath const& other ) const noexcept;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -108,13 +111,162 @@ class T_FSPath
|
||||||
};
|
};
|
||||||
M_DECLARE_SWAP( T_FSPath );
|
M_DECLARE_SWAP( T_FSPath );
|
||||||
M_DECLARE_HASH( T_FSPath );
|
M_DECLARE_HASH( T_FSPath );
|
||||||
M_LSHIFT_OP( T_StringBuilder , T_FSPath );
|
M_LSHIFT_OP( T_StringBuilder , T_FSPath const& );
|
||||||
|
|
||||||
|
|
||||||
|
/*= FILESYSTEM ===============================================================*/
|
||||||
|
|
||||||
|
class T_Filesystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Return the absolute path to the current directory
|
||||||
|
static T_FSPath currentDirectory( ) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*= T_FSPath =================================================================*/
|
/*= T_FSPath =================================================================*/
|
||||||
// FIXME: inline stuff should be moved
|
// FIXME: inline stuff should be moved
|
||||||
|
|
||||||
|
inline T_FSPath::T_FSPath( ) noexcept
|
||||||
|
: root_{ } , components_{ } , valid_{ true }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline T_FSPath::T_FSPath(
|
||||||
|
T_FSPath const& other ) noexcept
|
||||||
|
: root_{ other.root_ } , components_{ other.components_ } ,
|
||||||
|
valid_{ other.valid_ }
|
||||||
|
{ }
|
||||||
|
|
||||||
|
inline T_FSPath& T_FSPath::operator =(
|
||||||
|
T_FSPath const& other ) noexcept
|
||||||
|
{
|
||||||
|
root_ = other.root_;
|
||||||
|
components_ = other.components_;
|
||||||
|
valid_ = other.valid_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline T_FSPath::T_FSPath( T_FSPath&& other ) noexcept
|
||||||
|
: T_FSPath{ }
|
||||||
|
{
|
||||||
|
swap( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T_FSPath& T_FSPath::operator =(
|
||||||
|
T_FSPath&& other ) noexcept
|
||||||
|
{
|
||||||
|
root_ = T_String{ };
|
||||||
|
components_.free( );
|
||||||
|
valid_ = true;
|
||||||
|
return swap( other );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline T_FSPath& T_FSPath::swap(
|
||||||
|
T_FSPath& other ) noexcept
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap( root_ , other.root_ );
|
||||||
|
swap( components_ , other.components_ );
|
||||||
|
swap( valid_ , other.valid_ );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline M_DEFINE_SWAP( T_FSPath )
|
||||||
|
{
|
||||||
|
lhs.swap( rhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline bool T_FSPath::isValid( ) const noexcept
|
||||||
|
{
|
||||||
|
return valid_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T_String const& T_FSPath::root( ) const noexcept
|
||||||
|
{
|
||||||
|
return root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T_FSPath::T_Components const& T_FSPath::components( ) const noexcept
|
||||||
|
{
|
||||||
|
return components_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::isRelative( ) const noexcept
|
||||||
|
{
|
||||||
|
return !root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::isAbsolute( ) const noexcept
|
||||||
|
{
|
||||||
|
return bool( root_ );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline T_String T_FSPath::toString( ) const noexcept
|
||||||
|
{
|
||||||
|
T_StringBuilder sb;
|
||||||
|
appendTo( sb );
|
||||||
|
return T_String{ std::move( sb ) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline M_DEFINE_HASH( T_FSPath )
|
||||||
|
{
|
||||||
|
return item.computeHash( );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline M_LSHIFT_OP( T_StringBuilder , T_FSPath const& )
|
||||||
|
{
|
||||||
|
value.appendTo( obj );
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator ==(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator !=(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator <(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator <=(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator >(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool T_FSPath::operator >=(
|
||||||
|
T_FSPath const& other ) const noexcept
|
||||||
|
{
|
||||||
|
return compareTo( other ) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ebcl
|
} // namespace ebcl
|
||||||
|
|
Loading…
Reference in a new issue