Manipulating Paths
Plywood provides the WindowsPath
and PosixPath
classes for manipulating filesystem paths. All member functions are static and accept StringView
arguments:
PosixPath::join("path/to", "file"); // "path/to/file"
WindowsPath::split("path\\to\\file"); // {"path\\to", "file"}
Plywood also provides NativePath
, a type alias for either WindowsPath
or PosixPath
depending on the target platform:
NativePath::join(PLY_WORKSPACE_FOLDER, "repos/plywood/docs");
You'll likely use NativePath
most often, but there's nothing to stop you from using WindowsPath
on POSIX or PosixPath
on Windows.
The WindowsPath
class recognizes both forward and backslash characters as path separators. Its join()
, normalize()
and makeRelative()
functions normalize all path separators to backslashes.
The PosixPath
class only treats forward slashes as path separators.
Neither of these classes interact with the filesystem in any way. These path manipulation functions operate purely on strings.
You can also manipulate paths indirectly using a PathFormat
object, which can be obtained by calling format()
. All WindowsPath
and PosixPath
member functions are static, and all PathFormat
member functions are non-static.
Normalized Paths
The join()
, normalize()
and makeRelative()
member functions all return normalized paths. A normalized path is one in which redundant path separators are collapsed, references to the current directory "."
are discarded unless it is the only component, and references to the parent directory ".."
collapse the parent directory if there is one. A normalized WindowsPath
contains no forward slashes and uses only backslashes as path separators. An empty string is normalized to "."
. Normalized paths may or may not include a trailing path separator; see each function for further details.
Unicode Support
UTF-8 is the preferred character encoding for paths, but for practical purposes, the only characters treated specially are / \ . :
and ASCII letters. Therefore, these path functions work just as well with ISO 8859-1, Windows-1252 and pure ASCII strings.
The FileSystem
functions, on the other hand, do expect UTF-8 strings.
See Unicode Support for more information.
Header File
#include <ply-runtime/filesystem/Path.h>
Also included from <ply-runtime/Base.h>
.
Member Functions
static const char& sepByte()
-
WindowsPath
returns a backslash.PosixPath
returns a forward slash. static bool isSepByte(char c)
-
WindowsPath
returnstrue
ifc
is a forward or backslash.PosixPath
returnstrue
ifc
is a forward slash. static bool endsWithSep(StringView path)
-
WindowsPath
returnstrue
ifpath
ends with a forward or backslash.PosixPath
returnstrue
ifpath
ends with a forward slash. static bool hasDriveLetter(StringView path)
-
WindowsPath
returnstrue
ifpath
begins with a drive letter prefix such as"C:"
.PosixPath
always returnsfalse
. static StringView getDriveLetter(StringView path)
-
If
path
begins with a drive letter such as"C:"
,WindowsPath
returns the drive letter including the colon.PosixPath
always returns an empty string. static bool isAbsolute(StringView path)
-
WindowsPath
returnstrue
ifpath
begins with a drive letter and path separator.PosixPath
returnstrue
ifpath
begins with'/'
.WindowsPath::isAbsolute("C:\\"); // true WindowsPath::isAbsolute("d:/my/path"); // true WindowsPath::isAbsolute("C:file"); // false WindowsPath::isAbsolute("\\my\\path"); // false PosixPath::isAbsolute("/my/path"); // true
An empty string satisfies neither
isAbsolute()
norisRelative()
. ForWindowsPath
, a path that begin with a drive letter or path separator only (such as"C:file"
and"\\my\\path"
) satisfies neitherisAbsolute()
norisRelative()
.You can make a path absolute using
FileSystem::getAbsolutePath()
. static bool isRelative(StringView path)
-
Returns
true
ifpath
is non-empty and does not begin with a drive letter or path separator.WindowsPath::isRelative("file"); // true WindowsPath::isRelative("my\\path"); // true WindowsPath::isRelative("C:file"); // false WindowsPath::isRelative("\\my\\path"); // false PosixPath::isRelative("my/path"); // true
An empty string satisfies neither
isAbsolute()
norisRelative()
. ForWindowsPath
, a path that begin with a drive letter or path separator only (such as"C:file"
and"\\my\\path"
) satisfies neitherisAbsolute()
norisRelative()
. static Tuple<StringView, StringView> split(StringView path)
-
Splits
path
into aTuple
wheresecond
is the last path component andfirst
is everything leading up to that. Similar toos.path.split()
in Python.second
will never contain a path separator; ifpath
ends with a path separator,second
will be empty. If there is no path separator inpath
,first
will be empty. Trailing slashes are stripped fromfirst
unless it is the root.WindowsPath::split()
does not convert forward slashes to backslashes.PosixPath::split("path/to/file"); // {"path/to", "file"} PosixPath::split("path/to/folder/"); // {"path/to/folder", ""} PosixPath::split("/file_in_root"); // {"/", "file_in_root"} PosixPath::split("file"); // {"", "file"} WindowsPath::split("path\\to\\file"); // {"path\\to", "file"} WindowsPath::split("path/to/file"); // {"path/to", "file"}
static Array<StringView> splitFull(StringView path)
-
Splits
path
into an array of items where each item contains a single path component. WhenWindowsPath
is given an absolute path, it returns the drive letter and first path separator as the first component. WhenPosixPath
is given an absolute path, it returns"/"
as the first component. None of the other components contain a path separator. Ifpath
ends with a path separator, the last component is an empty string.PosixPath::splitFull("path/to/file"); // {"path", "to", "file"} PosixPath::splitFull("path/to/folder/"); // {"path", "to", "folder", ""} PosixPath::splitFull("/file_in_root"); // {"/", "file_in_root"} WindowsPath::splitFull("path\\to/file"); // {"path", "to", "file"} WindowsPath::splitFull("C:\\file_in_root"); // {"C:\\", "file_in_root"}
static Tuple<StringView, StringView> splitExt(StringView path)
-
Splits
path
into aTuple
such thatfirst + second == path
, andsecond
is empty or begins with a period and contains at most one period. Similar toos.path.splitext()
in Python. Leading periods on the basename, as in".gitignore"
, are ignored.PosixPath::splitExt("file.txt"); // {"file", ".txt"} PosixPath::splitExt("file"); // {"file"} PosixPath::splitExt("file.tar.gz"); // {"file.tar", ".gz"} PosixPath::splitExt("path/to/file.txt"); // {"path/to/file", ".txt"} PosixPath::splitExt("folder.tmp/"); // {"folder.tmp/", ""} PosixPath::splitExt("folder.tmp/file"); // {"folder.tmp/file", ""} PosixPath::splitExt(".gitignore"); // {".gitignore", ""} PosixPath::splitExt("path/to/.gitignore"); // {"path/to/.gitignore", ""}
static String join(components...)
-
Joins one or more path components together and normalizes the result. Note that this function is not the same as
os.path.join()
in Python. It's closer (but not identical) toos.path.normpath(os.path.join())
in Python.The returned path has a trailing slash if and only if the last component has a trailing slash or is an empty string. If any argument is an absolute path, all previous arguments are thrown away except for any drive letter that was encountered. For
WindowsPath
, if any argument contains a drive letter, all previous arguments are thrown away.PosixPath::join("path/to", "file"); // "path/to/file" PosixPath::join("path/to", "folder/"); // "path/to/folder/" PosixPath::join("path/to", "folder", ""); // "path/to/folder/" PosixPath::join("path/to", "./file"); // "path/to/file" PosixPath::join("path/to/file", "../other"); // "path/to/other" WindowsPath::join("C:\\", "bad/slash"); // "C:\\bad\\slash"
static String normalize(components...)
-
Equivalent to
join()
. static bool isNormalized(StringView path)
-
Equivalent to
path == normalize(path)
. static String makeRelative(StringView ancestor, StringView descendant)
-
Returns a new path
relative
such thatjoin(ancestor, relative)
is equivalent todescendant
. Ifancestor
is an absolute path,descendant
must also be an absolute path, and ifancestor
is a relative path,descendant
must also be a relative path. The returned path is normalized. The returned path has a trailing slash if and only ifdescendant
has a trailing slash.PosixPath::makeRelative("/path/to", "/path/to/file"); // "file" PosixPath::makeRelative("/path/to/", "/path/to/file"); // "file" PosixPath::makeRelative("/path/to", "/path/to/a/b"); // "a/b" PosixPath::makeRelative("/path/to/file", "/path/to/other"); // "../other" PosixPath::makeRelative("/path/to/file", "/path/to/other/"); // "../other/" PosixPath::makeRelative("path/to", "path/to"); // "." PosixPath::makeRelative("path/to/", "path/to"); // "." PosixPath::makeRelative("path/to", "path/to/"); // "./"
static PathFormat format()
-
Returns a
PathFormat
object that exposes the same functionality asWindowsPath
orPosixPath
, but using non-static member functions instead of static member functions. You can pass thePathFormat
object to other functions to perform platform-specific path manipulation indirectly. static HybridString from<SrcFormat>(StringView path)
-
Converts the path separators in
path
.PosixPath::from<WindowsPath>()
converts all backslashes to forward slashes.WindowsPath::from<PosixPath>()
andWindowsPath::from<WindowsPath>()
convert all forward slashes to backslashes. Otherwise the returned string is identical.// Returns "path\\to\\file": WindowsPath::from<PosixPath>("path/to/file"); // Returns "C:/path/to/file": PosixPath::from<WindowsPath>("C:\\path\\to\\file");
static HybridString from(const PathFormat& srcFormat, StringView path)
-
Same as the previous function, but the source format is determined by function argument instead of template argument.
// Returns "path\\to\\file": WindowsPath::from(PosixPath::format(), "path/to/file"); // Returns "C:/path/to/file": PosixPath::from(WindowsPath::format(), "C:\\path\\to\\file");