- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gpath.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 Graeme Walker <graeme_walker@users.sourceforge.net>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gpath.cpp
19 //
20
21 #include "gdef.h"
22 #include "gpath.h"
23 #include "gfs.h"
24 #include "gstr.h"
25 #include "gdebug.h"
26 #include "glog.h"
27 #include "gassert.h"
28 #include <cstring>
29
30 G::Path::Path() :
31 m_dot(std::string::npos)
32 {
33 }
34
35 G::Path::~Path()
36 {
37 }
38
39 G::Path::Path( const std::string & path )
40 {
41 set( path ) ;
42 }
43
44 G::Path::Path( const char * path )
45 {
46 G_ASSERT( path != NULL ) ;
47 set( std::string(path) ) ;
48 }
49
50 G::Path::Path( const Path & path , const std::string & tail )
51 {
52 set( path.str() ) ;
53 pathAppend( tail ) ;
54 }
55
56 G::Path::Path( const Path & path , const std::string & tail_1 , const std::string & tail_2 )
57 {
58 set( path.str() ) ;
59 pathAppend( tail_1 ) ;
60 pathAppend( tail_2 ) ;
61 }
62
63 G::Path::Path( const Path & other )
64 {
65 set( other.str() ) ;
66 }
67
68 void G::Path::set( const std::string & path )
69 {
70 clear() ;
71 m_str = path ;
72 normalise() ;
73 }
74
75 void G::Path::clear()
76 {
77 m_extension.erase() ;
78 m_str.erase() ;
79 m_dot = std::string::npos ;
80 }
81
82 void G::Path::normalise()
83 {
84 char ns[2] ; char s[2] ; char ss[3] ;
85 s[0] = ss[0] = ss[1] = FileSystem::slash() ;
86 ns[0] = FileSystem::nonSlash() ;
87 ns[1] = s[1] = ss[2] = '\0' ;
88
89 // normalise spaces
90 if( !FileSystem::allowsSpaces() )
91 Str::replaceAll( m_str , " " , "" ) ;
92
93 // normalise alternate (non) slash characters
94 Str::replaceAll( m_str , ns , s ) ;
95
96 // save leading double-slashes
97 bool has_leading_double_slash = FileSystem::leadingDoubleSlash() && m_str.find( ss ) == 0U ;
98
99 // normalise double slashes
100 Str::replaceAll( m_str , ss , s ) ;
101
102 // normalise funny characters
103 Str::removeAll( m_str , '\t' ) ;
104 Str::removeAll( m_str , '\n' ) ;
105 Str::removeAll( m_str , '\r' ) ;
106
107 // remove trailing slashes where appropriate
108 while( (
109 m_str.size() > 1U &&
110 m_str.at(m_str.size()-1) == FileSystem::slash() &&
111 !( FileSystem::usesDriveLetters() &&
112 m_str.size() == 3U &&
113 m_str.at(1) == ':' ) ) )
114 {
115 m_str.resize( m_str.size()-1U ) ;
116 }
117
118 // restore leading double slash
119 if( has_leading_double_slash )
120 m_str = s + m_str ;
121
122 // prepare a pointer to the extension
123 std::string::size_type slash = m_str.rfind( FileSystem::slash() ) ;
124 m_dot = m_str.rfind( '.' ) ;
125 if( m_dot != std::string::npos && slash != std::string::npos && m_dot < slash ) // ie. if "foo.bar/bletch"
126 m_dot = std::string::npos ;
127
128 // make a copy of the extension
129 if( m_dot != std::string::npos )
130 {
131 m_extension = (m_dot+1U) == m_str.length() ? std::string() : m_str.substr(m_dot+1U) ;
132 }
133 }
134
135 std::string G::Path::str() const
136 {
137 return m_str ;
138 }
139
140 bool G::Path::simple() const
141 {
142 return dirnameImp().empty() ;
143 }
144
145 bool G::Path::isRelative() const
146 {
147 return !isAbsolute() ;
148 }
149
150 bool G::Path::isAbsolute() const
151 {
152 if( hasNetworkDrive() )
153 return true ;
154
155 std::string str(m_str) ;
156 if( hasDriveLetter() )
157 str.erase( 0U , driveString().length() ) ;
158
159 return str.length() > 0U && str.at(0U) == FileSystem::slash() ;
160 }
161
162 std::string G::Path::basename() const
163 {
164 // for consistency compare m_str with dirname() and return the
165 // difference, excluding any leading slash
166
167 std::string head( dirnameImp() ) ;
168 if( head.length() == 0 )
169 {
170 return m_str ;
171 }
172 else
173 {
174 std::string result( m_str ) ;
175 result.erase( 0U , head.length() ) ;
176 if( result.at(0) == FileSystem::slash() )
177 result.erase( 0U , 1U ) ;
178 return result ;
179 }
180 }
181
182 G::Path G::Path::dirname() const
183 {
184 return Path( dirnameImp() ) ;
185 }
186
187 std::string G::Path::dirnameImp() const
188 {
189 std::string result ;
190 if( FileSystem::usesDriveLetters() && m_str.size() >= 2 && m_str.at(1) == ':' )
191 {
192 if( hasNoSlash() )
193 {
194 result = m_str.size() > 2 ? driveString() : std::string() ;
195 }
196 else
197 {
198 if( m_str.rfind(FileSystem::slash()) == 2U )
199 {
200 if( m_str.size() == 3U )
201 {
202 result = "" ;
203 }
204 else
205 {
206 result = withoutTail() ;
207 if( result.length() == 2 )
208 result.append( slashString() ) ;
209 }
210 }
211 else
212 {
213 result = withoutTail() ;
214 }
215 }
216 }
217 else if( FileSystem::leadingDoubleSlash() && m_str.size() >= 2U && m_str.substr(0U,2U) == doubleSlashString() )
218 {
219 size_t slash_count = 0U ;
220 for( std::string::const_iterator p = m_str.begin() ; p != m_str.end() ; ++p )
221 if( *p == FileSystem::slash() )
222 slash_count++ ;
223
224 result = slash_count > 3U ? withoutTail() : std::string() ;
225 }
226 else if( hasNoSlash() || m_str.size() == 1U )
227 {
228 ;
229 }
230 else
231 {
232 result = withoutTail() ;
233 if( result.length() == 0U )
234 result = slashString() ;
235 }
236 return result ;
237 }
238
239 std::string G::Path::withoutTail() const
240 {
241 G_ASSERT( !hasNoSlash() ) ;
242 return m_str.substr( 0U , m_str.rfind(FileSystem::slash()) ) ;
243 }
244
245 bool G::Path::hasNoSlash() const
246 {
247 return m_str.find(FileSystem::slash()) == std::string::npos ;
248 }
249
250 std::string::size_type G::Path::slashAt() const
251 {
252 std::string::size_type position = m_str.find( FileSystem::slash() ) ;
253 G_ASSERT( position != std::string::npos ) ;
254 return position ;
255 }
256
257 std::string G::Path::slashString()
258 {
259 return std::string( 1U , FileSystem::slash() ) ;
260 }
261
262 std::string G::Path::doubleSlashString()
263 {
264 return std::string ( 2U , FileSystem::slash() ) ;
265 }
266
267 bool G::Path::hasDriveLetter() const
268 {
269 return
270 FileSystem::usesDriveLetters() &&
271 m_str.size() >= 2U &&
272 m_str.at(1U) == ':' ;
273 }
274
275 bool G::Path::hasNetworkDrive() const
276 {
277 return
278 FileSystem::leadingDoubleSlash() &&
279 m_str.size() > 2U&&
280 m_str.at(0U) == FileSystem::slash() &&
281 m_str.at(1U) == FileSystem::slash() ;
282 }
283
284 std::string G::Path::driveString() const
285 {
286 G_ASSERT( m_str.at(1U) == ':' ) ;
287 G_ASSERT( FileSystem::usesDriveLetters() ) ;
288 return std::string( 1U , m_str.at(0U) ) + std::string(":") ;
289 }
290
291 void G::Path::removeExtension()
292 {
293 if( m_dot != std::string::npos )
294 {
295 m_str.resize( m_dot ) ;
296 m_dot = std::string::npos ;
297 normalise() ; // in case of dir/foo.bar.bletch
298 }
299 }
300
301 void G::Path::pathAppend( const std::string & tail )
302 {
303 if( !tail.empty() )
304 {
305 // if empty or root or just a drive letter...
306 if( m_str.size() == 0U || m_str == slashString() ||
307 ( hasDriveLetter() && m_str == driveString() ) )
308 {
309 ; // no-op
310 }
311 else
312 {
313 m_str.append( slashString() ) ;
314 }
315 m_str.append( tail ) ;
316 normalise() ;
317 }
318 }
319
320 std::string G::Path::extension() const
321 {
322 return m_extension ;
323 }
324
325 G::Path G::Path::join( const G::Path & p1 , const G::Path & p2 )
326 {
327 if( p1 == Path() )
328 {
329 return p2 ;
330 }
331 else if( p2 == Path() )
332 {
333 return p1 ;
334 }
335 else
336 {
337 G::Path result( p1 ) ;
338 Strings list = p2.split() ;
339 for( Strings::iterator p = list.begin() ; p != list.end() ; ++p )
340 result.pathAppend( *p ) ;
341 return result ;
342 }
343 }
344
345 G::Strings G::Path::split( bool no_dot ) const
346 {
347 Path path( *this ) ;
348 Strings list ;
349 for( unsigned int part = 0U ;; part++ )
350 {
351 std::string front = path.dirnameImp() ;
352 std::string back = path.basename() ;
353
354 // if a dot in the middle or end of the path...
355 if( back == std::string(".") && no_dot && front.length() != 0U )
356 ; // ...ignore it
357 else
358 list.push_front( back ) ;
359
360 if( front.length() == 0U )
361 break ;
362
363 path = Path(front) ;
364 }
365 return list ;
366 }
367
368 bool G::Path::operator==( const Path & other ) const
369 {
370 return
371 ( m_str.empty() && other.m_str.empty() ) ||
372 ( m_str == other.m_str ) ;
373 }
374
375 bool G::Path::operator!=( const Path & other ) const
376 {
377 return m_str != other.m_str ;
378 }
379
380 G::Path & G::Path::operator=( const Path & other )
381 {
382 if( &other != this )
383 set( other.str() ) ;
384 return *this ;
385 }
386
G::Path::str
std::string str() const
Returns the path string.
Definition: gpath.cpp:135
G::Path::operator=
Path & operator=(const Path &other)
Assignment operator.
Definition: gpath.cpp:380
G::Path::Path
Path()
Default constructor.
Definition: gpath.cpp:30
glog.h
G::Path::basename
std::string basename() const
Returns the path, excluding drive/directory parts.
Definition: gpath.cpp:162
G::Path::split
Strings split(bool no_dot=true) const
Spits the path into a list of component parts.
Definition: gpath.cpp:345
G::Strings
std::list< std::string > Strings
A std::list of std::strings.
Definition: gstrings.h:39
G::Path::operator!=
bool operator!=(const Path &path) const
Comparison operator.
Definition: gpath.cpp:375
md5::size_type
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
G::Path::hasDriveLetter
bool hasDriveLetter() const
Returns true if the path has a leading drive letter (and the operating system uses drive letters)...
Definition: gpath.cpp:267
G::Path::extension
std::string extension() const
Returns the path's filename extension.
Definition: gpath.cpp:320
G::FileSystem::usesDriveLetters
static bool usesDriveLetters()
Definition: gfs_unix.cpp:49
G::Path::simple
bool simple() const
Returns true if the path is just a file/directory name without any separators.
Definition: gpath.cpp:140
G::FileSystem::slash
static char slash()
Definition: gfs_unix.cpp:29
G::Path::isRelative
bool isRelative() const
Returns true if the path is a relative path.
Definition: gpath.cpp:145
gfs.h
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
gstr.h
gassert.h
G::Str::replaceAll
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurences of sub-string 'from' with 'to'...
Definition: gstr.cpp:78
G::FileSystem::allowsSpaces
static bool allowsSpaces()
Definition: gfs_unix.cpp:39
G::Path::isAbsolute
bool isAbsolute() const
Returns !isRelative().
Definition: gpath.cpp:150
G::Path::operator==
bool operator==(const Path &path) const
Comparison operator.
Definition: gpath.cpp:368
G::Path::dirname
Path dirname() const
Returns the drive/directory parts of the path.
Definition: gpath.cpp:182
gpath.h
G::Path::pathAppend
void pathAppend(const std::string &tail)
Appends a filename to the path.
Definition: gpath.cpp:301
G::Str::removeAll
static void removeAll(std::string &, char)
Removes all occurrences of the character from the string.
Definition: gstr.cpp:105
G::FileSystem::leadingDoubleSlash
static bool leadingDoubleSlash()
Definition: gfs_unix.cpp:54
G::Path
A Path object represents a file system path.
Definition: gpath.h:44
G::Path::removeExtension
void removeExtension()
Modifies the path by removing any extension.
Definition: gpath.cpp:291
G::Path::join
static G::Path join(const G::Path &p1, const G::Path &p2)
Joins two paths together.
Definition: gpath.cpp:325
G::Path::~Path
~Path()
Destructor.
Definition: gpath.cpp:35
G::FileSystem::nonSlash
static char nonSlash()
Definition: gfs_unix.cpp:34
gdebug.h