Common Lisp the Language, 2nd Edition
All file systems dealt with by Common Lisp are forced into a common framework, in which files are named by a Lisp data object of type pathname.
A pathname always has six components, described below. These components are the common interface that allows programs to work the same way with different file systems; the mapping of the pathname components into the concepts peculiar to each file system is taken care of by the Common Lisp implementation.
Note that a pathname is not necessarily the name of a specific file. Rather, it is a specification (possibly only a partial specification) of how to access a file. A pathname need not correspond to any file that actually exists, and more than one pathname can refer to the same file. For example, the pathname with a version of ``newest'' may refer to the same file as a pathname with the same components except a certain number as the version. Indeed, a pathname with version ``newest'' may refer to different files as time passes, because the meaning of such a pathname depends on the state of the file system. In file systems with such facilities as ``links,'' multiple file names, logical devices, and so on, two pathnames that look quite different may turn out to address the same file. To access a file given a pathname, one must do a file system operation such as open.
Two important operations involving pathnames are parsing and merging. Parsing is the conversion of a namestring (which might be something supplied interactively by the user when asked to supply the name of a file) into a pathname object. This operation is implementation-dependent, because the format of namestrings is implementation-dependent. Merging takes a pathname with missing components and supplies values for those components from a source of defaults.
Not all of the components of a pathname need to be specified. If a component of a pathname is missing, its value is nil. Before the file system interface can do anything interesting with a file, such as opening the file, all the missing components of a pathname must be filled in (typically from a set of defaults). Pathnames with missing components may be used internally for various purposes; in particular, parsing a namestring that does not specify certain components will result in a pathname with missing components.
X3J13 voted in January 1989 (PATHNAME-UNSPECIFIC-COMPONENT) to permit any component of a pathname to have the value :unspecific, meaning that the component simply does not exist, for file systems in which such a value makes sense. (For example, a UNIX file system usually does not support version numbers, so the version component of a pathname for a UNIX host might be :unspecific. Similarly, the file type is usually regarded in a UNIX file system as the part of a name after a period, but some file names contain no periods and therefore have no file types.)
When a pathname is converted to a namestring, the values nil and :unspecific have the same effect: they are treated as if the component were empty (that is, they each cause the component not to appear in the namestring). When merging, however, only a nil value for a component will be replaced with the default for that component; the value :unspecific will be left alone as if the field were filled.
The results are undefined if :unspecific is supplied to a file system in a component for which :unspecific does not make sense for that file system.
portable programs should be prepared to handle the value :unspecific in the device,
directory, type, or version field in some implementations.
Portable programs should not explicitly place :unspecific in any
field because it might not be permitted in some situations,
but portable programs may sometimes do so implicitly (by copying
such a value from another pathname, for example).
A component of a pathname can also be the keyword :wild. This is only useful when the pathname is being used with a directory-manipulating operation, where it means that the pathname component matches anything. The printed representation of a pathname typically designates :wild by an asterisk; however, this is host-dependent.
See section 23.1.4 for a discussion of new wildcard pathname facilities.
What values are allowed for components of a pathname depends, in general, on the pathname's host. However, in order for pathnames to be usable in a system-independent way, certain global conventions are adhered to. These conventions are stronger for the type and version than for the other components, since the type and version are explicitly manipulated by many programs, while the other components are usually treated as something supplied by the user that just needs to be remembered and copied from place to place.
The type is always a string or nil or :wild. It is expected that most programs that deal with files will supply a default type for each file.
The version is either a positive integer or a special symbol. The meanings of nil and :wild have been explained above. The keyword :newest refers to the largest version number that already exists in the file system when reading a file, or to a version number greater than any already existing in the file system when writing a new file. Some Common Lisp implementors may choose to define other special version symbols. Some semi-standard names, suggested but not required to be supported by every Common Lisp implementation, are :oldest, to refer to the smallest version number that exists in the file system; :previous, to refer to the version previous to the newest version; and :installed, to refer to a version that is officially installed for users (as opposed to a working or development version). Some Common Lisp implementors may also choose to attach a meaning to non-positive version numbers (a typical convention is that 0 is synonymous with :newest and -1 with :previous), but such interpretations are implementation-dependent.
The host may be a string, indicating a file system, or a list of strings, of which the first names the file system and the rest may be used for such a purpose as inter-network routing.
The device, directory, and name can each be a string (with host-dependent rules on allowed characters and length) or possibly some other Common Lisp data structure (in which case such a component is said to be structured and has an implementation-dependent format). Structured components may be used to handle such file system features as hierarchical directories. Common Lisp programs do not need to know about structured components unless they do host-dependent operations. Specifying a string as a pathname component for a host that requires a structured component will cause conversion of the string to the appropriate form.
X3J13 voted in June 1989 (PATHNAME-SUBDIRECTORY-LIST) to define a specific format for structured directories (see section 23.1.3).
X3J13 voted in June 1989 (PATHNAME-COMPONENT-VALUE) to approve the following clarifications and specifications of precisely what are valid values for the various components of a pathname.
Pathname component value strings never contain the punctuation characters that are used to separate fields in a namestring (for example, slashes and periods as used in UNIX file systems). Punctuation characters appear only in namestrings. Characters used as punctuation can appear in pathname component values with a non-punctuation meaning if the file system allows it (for example, UNIX file systems allow a file name to begin with a period).
When examining pathname components, conforming programs must be prepared to encounter any of the following siutations:
When examining wildcard components of a wildcard pathname, conforming programs must be prepared to encounter any of the following additional values in any component or any element of a list that is the directory component:
When constructing a pathname from components, conforming programs must follow these rules:
The best way to compare two pathnames for equality is with equal, not eql. (On pathnames, eql is simply the same as eq.) Two pathname objects are equal if and only if all the corresponding components (host, device, and so on) are equivalent. (Whether or not uppercase and lowercase letters are considered equivalent in strings appearing in components depends on the file name conventions of the file system.) Pathnames that are equal should be functionally equivalent.
Some host file systems have features that do not fit into this pathname model. For instance, directories might be accessible as files; there might be complicated structure in the directories or names; or there might be a way to specify a directory relative to a ``current'' directory, such as the < syntax in MULTICS or the special ``..'' file name of UNIX. Such features are not allowed for by the standard Common Lisp file system interface. An implementation is free to accommodate such features in its pathname representation and provide a parser that can process such specifications in namestrings; such features are then likely to work within that single implementation. However, note that once a program depends explicitly on any such features, it will not be portable.
X3J13 voted in June 1989 (PATHNAME-SUBDIRECTORY-LIST) to define a specific format for structured directories (see section 23.1.3), so some of the specific examples in the previous paragraph no longer apply, but the principle is still correct.