Menu

Diff of /src/glib/gpath.h [000000] .. [r1]  Maximize  Restore

Switch to side-by-side view

--- a
+++ b/src/glib/gpath.h
@@ -0,0 +1,223 @@
+//
+// Copyright (C) 2017 Graeme Walker
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// ===
+///
+/// \file gpath.h
+///
+
+#ifndef G_PATH_H
+#define G_PATH_H
+
+#include "gdef.h"
+#include "gstrings.h"
+#include <string>
+#include <iostream>
+
+namespace G
+{
+	class Path ;
+	class PathImp ;
+}
+
+/// \class G::Path
+/// A Path object represents a file system path. The class is concerned with
+/// path syntax, not file system i/o.
+/// 
+/// A full path is made up of a root, a set of directories, and a filename. The 
+/// posix root is just a forward slash, but on Windows the root can be complex, 
+/// possibly including non-splitting separator characters. The filename may have 
+/// an extension part, which is to the right of the right-most dot.
+/// 
+/// The path separator is used between directories and filename, but only 
+/// between the root and the first directory if the root does not itself end in 
+/// a separator character.
+/// 
+/// A windows drive-letter root may end with a separator character or not; if 
+/// there is no separator character at the end of the drive-letter root then 
+/// the path is relative to the drive's current working directory.
+/// 
+/// Path components of "." are ignored by simple(), basename(), and dirname().
+/// Path components of ".." are retained but can be eliminated if they are 
+/// collapsed(). Path components of "." are eliminated by split(), except
+/// in the degenerate case.
+/// 
+/// This class is agnostic on the choice of utf8 or eight-bit characters since 
+/// the delimiters are all seven-bit ascii. On Windows it might make sense to 
+/// obtain paths from the win32 api as multi-byte and convert immediately to 
+/// utf8 before wrapping in G::Path.
+/// 
+/// Both posix and windows behaviours are available at run-time; the default 
+/// behaviour is the native behaviour, but this can be overridden, typically 
+/// for testing purposes.
+/// 
+/// The posix path separator character is the forward-slash; on Windows it is a 
+/// back-slash, but with all forward-slashes converted to back-slashes 
+/// immediately on input.
+/// 
+/// \see G::File, G::Directory
+/// 
+class G::Path
+{
+public:
+	Path() ;
+		///< Default constructor for a zero-length path.
+		///< Postcondition: str().empty()
+
+	Path( const std::string & path ) ;
+		///< Implicit constructor from a string.
+
+	Path( const char * path ) ;
+		///< Implicit constructor from a c-style string.
+
+	Path( const Path & path , const std::string & tail ) ;
+		///< Constructor with an implicit pathAppend().
+
+	Path( const Path & path , const std::string & tail_1 , const std::string & tail_2 ) ;
+		///< Constructor with two implicit pathAppend()s.
+
+	Path( const Path & other ) ;
+		///< Copy constructor.
+
+	~Path() ;
+		///< Destructor.
+
+	std::string str() const ;
+		///< Returns the path string.
+
+	bool simple() const ;
+		///< Returns true if the path has a single component (ignoring "." parts), 
+		///< ie. the dirname() is empty.
+
+	std::string basename() const ;
+		///< Returns the rightmost part of the path, ignoring "." parts.
+		///< For a directory path this may be "..", but see also collapsed().
+
+	Path dirname() const ;
+		///< Returns the path without the rightmost part, ignoring "." parts.
+		///< For simple() paths the empty path is returned.
+
+	std::string extension() const ;
+		///< Returns the path's basename extension, ie. anything
+		///< after the rightmost dot. Returns the zero-length 
+		///< string if there is none.
+
+	Path withExtension( const std::string & ext ) const ;
+		///< Returns the path with the new basename extension.
+		///< Any previous extension is replaced. The extension 
+		///< should not normally have a leading dot and it 
+		///< should not be the empty string.
+
+	Path withoutExtension() const ;
+		///< Returns a path without the basename extension, if any.
+		///< As a special case, a basename() that starts with a dot
+		///< is replaced by a single dot. Prefer withExtension()
+		///< where appropriate to avoid this.
+
+	bool isAbsolute() const ;
+		///< Returns !isRelative().
+
+	bool isRelative() const ;
+		///< Returns true if the path is a relative path.
+
+	void pathAppend( const std::string & tail ) ;
+		///< Appends a filename or a relative path to this path.
+
+	StringArray split() const ;
+		///< Spits the path into a list of component parts (ignoring "." parts
+		///< unless the whole path is ".").
+
+	static Path join( const StringArray & parts ) ;
+		///< Builds a path from a set of parts. Note that part boundaries
+		///< are not necessarily preserved once they have been join()ed
+		///< into a path.
+
+	static Path join( const Path & p1 , const Path & p2 ) ;
+		///< Joins two paths together. The second should be a relative path.
+
+	static Path difference( const Path & p1 , const Path & p2 ) ;
+		///< Returns the relative path from p1 to p2. Returns the empty
+		///< path if p2 is not under p1. Returns "." if p1 and p2 are the
+		///< same. Input paths are collapsed(). Empty input paths are 
+		///< treated as ".".
+
+	Path collapsed() const ;
+		///< Returns the path with "foo/.." and "." parts removed, so far
+		///< as is possible without changing the meaning of the path.
+		///< Parts like "../foo" at the beginning of the path, or immediately
+		///< following the root, are not removed.
+
+	static Path nullDevice() ;
+		///< Returns the path of the "/dev/null" special file, or equivalent.
+
+	void swap( Path & other ) ;
+		///< Swaps this with other.
+
+	Path & operator=( const Path & other ) ;
+		///< Assignment operator.
+
+	bool operator==( const Path & path ) const ;
+		///< Comparison operator.
+
+	bool operator!=( const Path & path ) const ;
+		///< Comparison operator.
+
+	static void setPosixStyle() ;
+		///< Sets posix mode for testing purposes.
+
+	static void setWindowsStyle() ;
+		///< Sets windows mode for testing purposes.
+
+	static bool less( const Path & a , const Path & b ) ;
+		///< Compares two paths, with simple eight-bit lexicographical 
+		///< comparisons of each path component. This is slightly different 
+		///< from a lexicographical comparison of the compete strings
+		///< (eg. "a/b" compared to "a./b"), and it is not suitable for 
+		///< utf8 paths.
+
+private:
+	friend class G::PathImp ;
+	std::string m_str ;
+} ;
+
+namespace G
+{
+	inline
+	std::ostream & operator<<( std::ostream & stream , const Path & path )
+	{
+		return stream << path.str() ;
+	}
+
+	inline
+	Path & operator+=( Path & p , const std::string & str )
+	{
+		p.pathAppend( str ) ;
+		return p ;
+	}
+
+	inline
+	Path operator+( const Path & p , const std::string & str )
+	{
+		return Path( p , str ) ;
+	}
+
+	inline
+	void swap( Path & p1 , Path & p2 )
+	{
+		p1.swap( p2 ) ;
+	}
+}
+
+#endif