A pathname is an symbolic identifier that locates a file in a filesystem (e.g., foo/bar/baz.txt). This module provides predicates to manipulate pathnames, encoded as atoms. No file system access is required for pathname manipulation.
X is a pathname (encoded as an atom)
Path is a basename (empty directory part) (equivalent to path_split(Path, ”, _)
Path is a root directory (normalized into / or //) (equivalent to + Path = ”, path_split(Path, Path, ”)
Concatenate pathnames PathA and PathB in a new path Path, adding a / separator if needed. If PathB is ”, then Path is a / ended path. If PathB is an absolute pathname, Path is PathB. No pathname normalization is performed in any case.
Given a pathname Path, Base is the last component of the path and Dir is the rest of the path. The following rules must hold:
path_split(A,B,C), path_concat(B,C,D), path_norm(A,An), path_norm(D,Dn), An = Dn.
Split Path into the directory part Dir and the basename part Base.
NormPath is the normalized pathname version of Path. Normalization removes redundant separators (// into /), and collapses references to the parent (..) and current (.) level. The parent of a root path (/ or //) is itself. Empty paths (”) or relative paths where all parent references are collapsed are normalized as '.'.
For compatibility, leading double-slashes are preserved in normalization (the POSIX.2 standard states that "a pathname that begins with two successive slashes may be interpreted in an implementation-defined manner, although more than two leading slashes shall be treated as a single slash."). Some systems (like Linux) ignore double-slashes while others (like Cygwin for //hostname/path SMB network drives) do not.
Note that path_norm/2 does not access the filesystem, which may affect the semantics when symbolic links are used (and no path normalization is involved). E.g., the following query obtain different values for S1 and S2:
?- P = '/usr/donotexists/..', path_norm(P, N), process_call(path(test), ['-e', P], [status(S1)]), process_call(path(test), ['-e', N], [status(S2)]). N = '/usr', P = '/usr/donotexists/..', S1 = 1, S2 = 0 ? ?- use_module(library(process)). ?- copy_file('/usr', 'u', [symlink]), P = 'u/../u', path_norm(P, N), process_call(path(test), ['-e', P], [status(S1)]), process_call(path(test), ['-e', N], [status(S2)]), delete_file('u'). N = u, P = 'u/../u', S1 = 1, S2 = 0 ? yes
NormPath is the normalized pathname version of Path.
The extension Ext is the shortest suffix that begins with '.' of Path. The rest of the pathname is NoExt, which cannot be empty (”). The extension is ” if the pathname has no extension.
In this example, all the following goals succeed:
path_splitext('a/foo.', 'a/foo', '.') path_splitext('a/foo.c', 'a/foo', '.c') path_splitext('a/foo.c.d', 'a/foo.c', '.d') path_splitext('a/.foo.', 'a/.foo', '.') path_splitext('a/.foo.c', 'a/.foo', '.c') path_splitext('a/.foo.c.d', 'a/.foo.c', '.d')
Split Path into its extension Ext and the rest of the pathname NoExt.
Compose Path by concatenating the extension Ext to NoExt pathname.
Base is the basename corresponding to the Path (equivalent to path_split(Path,_,Base)).
Dir is the directory part corresponding to the Path (equivalent to path_split(Path,Dir,_)).
Replace FromDir prefix by DestDir in FromDir to generate ToDir
Obtain path RelPath such that path_concat(BaseDir, RelPath, Path) RelPath will not contain any trailing '/'
Split Path into its components Bases, calling path_split/3 recursively.
Concatenate all components in Bases a new path Path, calling path_concat/3 recursively.
Reversible path operations can be implemented by decomposing paths in list of names (using path_split/2 recursively), manipulating the lists, and composing back the paths (using path_concat/2 recursively).