All Manuals > LispWorks® User Guide and Reference Manual > 27 LispWorks' Operating Environment

27.18 Physical pathnames in LispWorks

This section describes the implementation-dependent details of physical (non-logical) pathnames in LispWorks.

27.18.1 Parsing physical namestrings in LispWorks

In LispWorks, namestrings of non-logical pathnames have the following parts:

<host>:<device>:<directory><name>.<type>

All the components are optional.

<directory> is made of directory elements separated by directory separators. On non-Windows platforms, the directory separator is forward slash (#\/). On Windows, it can be either forward slash or backslash (#\\).

On Windows, a pathname may also be an UNC pathname, representing a Windows UNC (Universal Name Convention) path. See 27.18.5 Windows UNC pathnames (Windows only) below. Namestrings representing UNC pathnames have the following parts:

\\<host>\<directory><name>.<type>

When reading a namestring on Windows, forward slashes can be used instead of backslashes. Note that, when such a namestring is printed as a Lisp value, Common Lisp will escape each backslash so they will appear to be doubled.

In general, the namestring syntax matches the syntax used by the utilities of the operating system, at least for pathnames that do not contain wild components.

LispWorks does not parse the pathname version component from a namestring. The <device> part of a namestring is not normally useful. The <host> part of a namestring is useful for Windows drive letters and is not valid otherwise.

On non-Windows platforms, a backslash (#\\) can be used as an escape character, which means that it and the next character (which is "escaped") are read as part of the current component, even if the character would normally be interpreted in a special way. When the pathname is used in an operating system interface function such as open, the escape characters are removed. The backslash can be used to escape itself, but it cannot be used to escape the directory separator (forward slash).

On Windows, there is no way to escape special characters.

27.18.1.1 Detailed description of the parsing of namestrings

The parsing of a physical pathname namestring starts with a new empty pathname, where all components are nil, and proceeds as follows:

Initial state

Initially the parse point is at the first charactrer of the string. "The string" refers to the string that is being parsed, which, when parse-namestring is used with :start or :end, is the part between the start and the end.

UNC pathnames (Windows only)

On Windows only, when the first and second character at the parse-point are directory separators and are the same character (that is both forward slashes or both backslashes), and that character also appears a third time later in the string, then the namestring is parsed as an UNC pathname. The resulting pathname is made an UNC pathname, the characters following the pair of separators up to the third separator are read into the pathname host component, and the parse point is moved to the third separator. There must be at least one character between the pair of separators and the third separator, otherwise an error is signaled.

Note that, as a result, the third separator is parsed as the first character of the <directory> part of the namestring by the following steps.

When LispWorks uses an UNC pathname, the pathname host component specifies the server of the path and the first string in the pathname directory component is the name of the shared directory. The rest of the pathname directory component and the pathname name and type components specify the path relative to the shared directory.

Host

If there is an unescaped colon (#\:) after the parse point before any directory separator, and the colon is not the first character in the string, then the characters until this colon are read into the pathname host component of the pathname and the parse point is moved to the character following the colon.

Device

If there is an unescaped colon after the parse point and before any directory separator, then the string between the parse point and this colon is read into the pathname device component of the pathname and the parse point is moved after the colon.

Note that because both the <host> and the <device> parts of the namestring are marked by a colon, you cannot have a device without a host. That means that normally the drive letter of a pathname on Windows will be in the pathname host component of the pathname.

Directory

If the string contains a directory separator, then the <directory> part of the namestring starts at the parse point and ends at last directory separator, and the parse point is moved to the first character after the last directory separator. Otherwise, the pathname directory component is nil.

If the <directory> part starts with a directory separator, then the directory is absolute. otherwise it is relative, and the string from the directory part start up to the first directory separator is the first element of the <directory> part. Each string between two directory separators is another element of the <directory> part.

If any of the elements of the <directory> part is "*" (a 1 character string containing #\*), it is replaced by :wild. If any of the elements is "**", it replaced by :wild-inferiors. If any of the elements is ".", it is discarded. If any of the elements is "..", it is replaced by :up.

The elements of the <directory> part are not allowed to be empty, that is if a directory separator is followed immediately by another directory separator then an error is signaled.

The pathane directory component of the pathname is set to a list where the first element is either :absolute for an absolute pathname or :relative for a relative pathname followed by the elements of the <directory> part of the namestring.

Name and type

If there is a any unescaped dot character (#\.) at or after the parse point, and the last unescaped dot is followed by some characters, then the pathname name component is read from the parse point until the last unescaped dot and the pathname type component is read from the first character after the last unescaped dot until the end of the string.

Otherwise, if the parse point is not at the end of the string, then the pathname name component is read from the parse point to the end of the string and the pathname type component is nil.

Otherwise, both the pathname name and type components are nil.

If either <name> or the <type> parts is "*", then it is parsed as :wild.

27.18.2 Namestrings of pathnames

The namestring for a pathame (the result of calling namestring) is created in a way that reverses the parsing of a namestring that is described above. On Windows, the backslash is used as the directory separator. The steps in creating the namestring are:

  1. For an UNC pathname, two directory separators are output followed by the pathname host component.
  2. For a non-UNC pathname, if the pathname host component is a string then it is output followed by a colon.

    If the pathname host component is not a string, but the pathname device component is a string, then a colon is output. Note that such a pathname cannot be created by parsing a namestring, and parsing the resulting namestring will produce a different pathname.

  3. For a non-UNC pathname, if the pathname device components is a string, then it is output followed by a colon.
  4. If the pathname directory component is non-nil, then it must be a list starting with either :relative or :absolute. If it starts with :absolute then a directory separator is output. The remaining elements in the list are then output, each one followed by a directory separator. If any of the elements is one of the symbols :wild, :wild-inferiors, :back or :up, then a corresponding string is output: "*" for :wild, "**" for :wild-inferiors, and ".." for :back and :up". Otherwise, the element must be a string which is output as it is.
  5. If the pathname name component is a string then it is output, otherwise if it is the symbol :wild then the string "*" is output.
  6. If the pathname type component is a string or :wild, a dot is output followed by the pathname type component, where :wild is output as "*".
  7. The pathname version component is ignored.

27.18.3 Creating pathnames with make-pathname

On Windows only, if the <host> argument to make-pathname is a string with more than one character, or <defaults> is an UNC pathname, then make-pathname returns an UNC pathname.

make-pathname can return pathnames that cannot be created by parsing a namestring, for example a pathname where the pathname name component is nil and pathname type component is a string. The namestring for these pathnames is output in the same way, so if you parse it back you will get a different pathname. These pathnames should be avoided, because it is easy to get confused when using them.

27.18.4 Backslashes in pathnames on non-Windows platforms

As described above, when parsing on non-Windows platforms, the backslash character is used as an escape character, causing the following character to be interpreted as a plain character. The backslash character itself is included in the component string, which means that making a namestring from the pathname will include the backslash too. When the pathname is passed to an operating system interface function (such as open), the backslashes are removed before using it.

For pathnames made by make-pathname, you don't need the escape characters, unless you want to parse namestrings that are produced from the pathname. The backslash characters itself is an exception: if the name of the file, any element of the directory component or the type in contain a backslash in the filesystem, then you have the escape it to make 2 consecutive backslashes.

27.18.5 Windows UNC pathnames (Windows only)

On Windows, a pathname may be an UNC pathname, representing a Windows UNC (Universal Name Convention) path. UNC pathnames allow you to access directories that are shared by other machines on the local network. An UNC pathname is an instance of a subclass of pathname, which is used somewhat differently when passed to the OS and when producing a namestring, but otherwise behaves the same as ordinary pathnames.

A Windows UNC pathname has this form:

\\<server>\<shared-directory-name>\<relative-path>

When LispWorks uses an UNC pathname, the pathname host component specifies the <server> of the path and the first string component (the second element) of the pathname directory component is the <shared-directory-name>. The rest of the pathname directory component and the pathname name and type components specify the <relative-path>.

An UNC pathname can be made by parsing a namestring starting with two directory separators, as described in 27.18.1 Parsing physical namestrings in LispWorks above.

When merge-pathnames is given an UNC pathname as its first argument, or the pathname host component of the first argument is nil and the second argument is an UNC pathname, then it returns an UNC pathname.

When make-pathname is given a host that is a string with more than one character (so cannot be a drive letter), or defaults is an UNC pathname, then it returns an UNC pathname.

27.18.6 Wildcards in pathname components

If the pathname directory, name or type components are strings containing any unescaped asterisk (#\*) characters then the pathname is considered to be a wildcard pathname (see Restrictions on Wildcard Pathnames). An asterisk can be escaped by preceding it with a backslash, making it a normal character.

When used for matching, the asterisk matches any number of characters in the corresponding component of a pathname. For example, #P"/dir/a*b.txt" matches any pathname whose directory component is (:absolute "dir") and whose name component start with #\a and ends with #\b and whose type component is "txt". Multiple asterisks are allowed. If the pathname directory component contains :wild-inferiors (represented as two asterisks in the pathname namestring) then it matches any number of directories.

27.18.7 Pathname comparison

Comparing pathnames using equal and equalp is case-sensitive on non-Windows platforms and case-insensitive on Windows. This matches the usual case conventions for filesystems.

27.18.7.1 Pathname comparison on macOS

Because equal and equalp use case-sensitive comparison on the Macintosh, this can lead to occasional unexpected mismatch of pathnames, because the HFS+ filesystem is usually case-insensitive (some Macintosh file systems are case-sensitive).


LispWorks® User Guide and Reference Manual - 01 Dec 2021 19:30:24