39 static bool use_posix ;
40 typedef std::string::size_type pos_t ;
42 static std::string windows_sep()
46 static pos_t windows_slashpos(
const std::string & s )
48 return s.rfind(
'\\') ;
50 static bool windows_simple(
const std::string & s )
52 return s.find(
'/') == std::string::npos && s.find(
'\\') == std::string::npos ;
54 static bool windows_absolute(
const std::string & s )
57 ( s.length() >= 3U && s.at(1U) ==
':' && s.at(2U) ==
'\\' ) ||
58 ( s.length() >= 1U && s.at(0U) ==
'\\' ) ;
60 static pos_t windows_rootsize(
const std::string & s ,
size_t chars ,
size_t parts )
62 G_ASSERT( s.length() >= chars ) ;
63 G_ASSERT( parts == 1U || parts == 2U ) ;
64 pos_t pos = s.find(
'\\' , chars ) ;
65 if( parts == 2U && pos != std::string::npos )
66 pos = s.find(
'\\' , pos+1U ) ;
67 return pos == std::string::npos ? s.length() : pos ;
69 static pos_t windows_rootsize(
const std::string & s )
71 if( s.empty() )
return 0U ;
72 if( s.length() >= 3U && s.at(1U) ==
':' && s.at(2U) ==
'\\' )
return 3U ;
73 if( s.length() >= 2U && s.at(1U) ==
':' )
return 2U ;
74 if( s.find(
"\\\\?\\UNC\\") == 0U )
return windows_rootsize(s,8U,2U) ;
75 if( s.find(
"\\\\?\\") == 0U && s.size() > 5U && s.at(5U) ==
':' )
return windows_rootsize(s,4U,1U) ;
76 if( s.find(
"\\\\?\\") == 0U )
return windows_rootsize(s,4U,2U) ;
77 if( s.find(
"\\\\.\\") == 0U )
return windows_rootsize(s,4U,1U) ;
78 if( s.find(
"\\\\") == 0U )
return windows_rootsize(s,2U,2U) ;
79 if( s.find(
"\\") == 0U )
return 1U ;
82 static void windows_normalise( std::string & s )
85 bool special = s.find(
"\\\\") == 0U ;
87 if( special ) s =
"\\" + s ;
89 while( s.length() > 1U )
91 pos_t pos = s.rfind(
'\\') ;
92 if( pos == std::string::npos ) break ;
93 if( (pos+1U) != s.length() )
break ;
94 if( pos < windows_rootsize(s) )
break ;
98 static std::string windows_null()
103 static std::string posix_sep()
107 static pos_t posix_slashpos(
const std::string & s )
109 return s.rfind(
'/') ;
111 static bool posix_simple(
const std::string & s )
113 return s.find(
'/') == std::string::npos ;
115 static void posix_normalise( std::string & s )
118 while( s.length() > 1U && s.at(s.length()-1U) ==
'/' ) s.resize(s.length()-1U) ;
120 static bool posix_absolute(
const std::string & s )
122 return !s.empty() && s.at(0U) ==
'/' ;
124 static pos_t posix_rootsize(
const std::string & s )
126 return s.empty() || s.at(0U) !=
'/' ? 0U : 1U ;
128 static std::string posix_null()
133 static std::string sep()
135 return use_posix ? posix_sep() : windows_sep() ;
137 static void normalise( std::string & s )
139 use_posix ? posix_normalise(s) : windows_normalise(s) ;
141 static bool simple(
const std::string & s )
143 return use_posix ? posix_simple(s) : windows_simple(s) ;
145 static bool absolute(
const std::string & s )
147 return use_posix ? posix_absolute(s) : windows_absolute(s) ;
149 static std::string null()
151 return use_posix ? posix_null() : windows_null() ;
153 static pos_t rootsize(
const std::string & s )
155 return use_posix ? posix_rootsize(s) : windows_rootsize(s) ;
157 static pos_t slashpos(
const std::string & s )
159 return use_posix ? posix_slashpos(s) : windows_slashpos(s) ;
161 static pos_t dotpos(
const std::string & s )
163 const pos_t npos = std::string::npos ;
164 const pos_t sp = slashpos( s ) ;
165 const pos_t dp = s.rfind(
'.' ) ;
168 else if( sp == npos )
176 static void splitInto(
const std::string & str ,
StringArray & a )
178 pos_t rs = rootsize(str) ;
184 std::string root = str.substr( 0U , rs ) ;
186 a.insert( a.begin() , root ) ;
196 const std::string dot( 1U ,
'.' ) ;
197 a.erase( std::remove( a.begin() , a.end() , std::string() ) , a.end() ) ;
198 size_t n = a.size() ;
199 a.erase( std::remove( a.begin() , a.end() , dot ) , a.end() ) ;
200 const bool all_dots = a.empty() && n != 0U ;
204 static std::string join( StringArray::const_iterator p , StringArray::const_iterator end )
208 for( ; p != end ; ++p , i++ )
210 bool drive = !use_posix && str.length() == 2U && str.at(1U) ==
':' ;
211 bool last_is_slash = !str.empty() && ( str.at(str.length()-1U) ==
'/' || str.at(str.length()-1U) ==
'\\' ) ;
212 if( i == 1 && (drive || last_is_slash) )
215 str.append( sep() ) ;
223 return join( a.begin() , a.end() ) ;
228 bool G::PathImp::use_posix = false ;
230 bool G::PathImp::use_posix = true ;
237 G::PathImp::use_posix = true ;
242 G::PathImp::use_posix = false ;
256 PathImp::normalise( m_str ) ;
262 PathImp::normalise( m_str ) ;
269 PathImp::normalise( m_str ) ;
277 PathImp::normalise( m_str ) ;
287 return Path(PathImp::null()) ;
297 return dirname() ==
Path() ;
302 return PathImp::absolute( m_str ) ;
307 return !isAbsolute() ;
313 PathImp::splitInto( m_str , a ) ;
314 PathImp::purge( a ) ;
315 return a.empty() ? std::string() : a.at(a.size()-1U) ;
321 PathImp::splitInto( m_str , a ) ;
322 PathImp::purge( a ) ;
323 if( a.empty() )
return Path() ;
330 std::string::size_type sp = PathImp::slashpos(m_str) ;
331 std::string::size_type dp = PathImp::dotpos(m_str) ;
332 if( dp != std::string::npos )
334 std::string result = m_str ;
335 result.resize( dp ) ;
336 if( (sp == std::string::npos && dp == 0U) || ((sp+1U) == dp) )
338 return Path( result ) ;
348 std::string result = m_str ;
349 std::string::size_type dp = PathImp::dotpos(m_str) ;
350 if( dp != std::string::npos )
351 result.resize( dp ) ;
352 result.append( 1U ,
'.' ) ;
353 result.append( ext ) ;
354 return Path( result ) ;
362 else if( PathImp::simple(tail) )
364 m_str.append( PathImp::sep() + tail ) ;
368 Path result = join( *
this , tail ) ;
369 result.
swap( *
this ) ;
375 std::string::size_type pos = PathImp::dotpos(m_str) ;
377 pos == std::string::npos || (pos+1U) == m_str.length() ?
379 m_str.substr( pos+1U ) ;
385 PathImp::splitInto( m_str , a ) ;
386 if( PathImp::purge(a) ) a.push_back(
"." ) ;
392 if( a.empty() )
return Path() ;
393 return Path( PathImp::join(a) ) ;
402 else if( p2 ==
Path() )
410 a2.insert( a2.begin() , a1.begin() , a1.end() ) ;
417 typedef StringArray::iterator Ptr ;
418 const std::string dots =
".." ;
421 Ptr start = a.begin() ;
423 if( start != end && isAbsolute() )
426 while( start != end )
428 while( start != end && *start == dots )
431 Ptr p_dots = std::find( start , end , dots ) ;
435 G_ASSERT( p_dots != a.begin() ) ;
436 G_ASSERT( a.size() >= 2U ) ;
438 a.erase( a.erase(--p_dots) ) ;
447 return m_str == other.m_str ;
452 return m_str != other.m_str ;
458 swap( m_str , other.m_str ) ;
468 static bool string_less(
const std::string & a ,
const std::string & b )
470 return a.compare(b) < 0 ;
477 return std::lexicographical_compare(
478 a_parts.begin() , a_parts.end() ,
479 b_parts.begin() , b_parts.end() ,
489 if( root_parts.size() == 1U && root_parts.at(0U) ==
"." ) root_parts.clear() ;
490 if( path_parts.size() == 1U && path_parts.at(0U) ==
"." ) path_parts.clear() ;
492 if( path_parts.size() < root_parts.size() )
495 typedef std::pair<StringArray::iterator,StringArray::iterator> Pair ;
496 Pair p = std::mismatch( root_parts.begin() , root_parts.end() , path_parts.begin() ) ;
498 if( p.first == root_parts.end() && p.second == path_parts.end() )
500 else if( p.first != root_parts.end() )
503 return Path( PathImp::join(p.second,path_parts.end()) ) ;
std::string str() const
Returns the path string.
Path & operator=(const Path &other)
Assignment operator.
void swap(Path &other)
Swaps this with other.
A private implementation class used by G::Path providing a set of static methods. ...
Path()
Default constructor for a zero-length path.
Path withoutExtension() const
Returns a path without the basename extension, if any.
std::string basename() const
Returns the rightmost part of the path, ignoring "." parts.
bool operator!=(const Path &path) const
Comparison operator.
std::vector< std::string > StringArray
A std::vector of std::strings.
static void splitIntoTokens(const std::string &in, StringArray &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
std::string extension() const
Returns the path's basename extension, ie.
static std::string tail(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
bool simple() const
Returns true if the path has a single component (ignoring "." parts), ie.
bool isRelative() const
Returns true if the path is a relative path.
static Path difference(const Path &p1, const Path &p2)
Returns the relative path from p1 to p2.
static bool less(const Path &a, const Path &b)
Compares two paths, with simple eight-bit lexicographical comparisons of each path component...
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurances of sub-string 'from' with 'to'...
bool isAbsolute() const
Returns !isRelative().
bool operator==(const Path &path) const
Comparison operator.
Path dirname() const
Returns the path without the rightmost part, ignoring "." parts.
StringArray split() const
Spits the path into a list of component parts (ignoring "." parts unless the whole path is "...
Path collapsed() const
Returns the path with "foo/.." and "." parts removed, so far as is possible without changing the mean...
void pathAppend(const std::string &tail)
Appends a filename or a relative path to this path.
static void setWindowsStyle()
Sets windows mode for testing purposes.
static void setPosixStyle()
Sets posix mode for testing purposes.
A Path object represents a file system path.
static Path join(const StringArray &parts)
Builds a path from a set of parts.
static Path nullDevice()
Returns the path of the "/dev/null" special file, or equivalent.
Path withExtension(const std::string &ext) const
Returns the path with the new basename extension.