Common Lisp the Language, 2nd Edition
X3J13
voted in June 1989 (PATHNAME-SUBDIRECTORY-LIST)
to define a specific pathname component format for structured directories.
The value of a pathname's directory component may be a list. The car of the list should be a keyword, either :absolute or :relative. Each remaining element of the list should be a string or a symbol (see below). Each string names a single level of directory structure and should consist of only the directory name without any punctuation characters.
A list whose car is the symbol :absolute represents a directory path starting from the root directory. For example, the list (:absolute) represents the root directory itself; the list (:absolute "foo" "bar" "baz") represents the directory that in a UNIX file system would be called /foo/bar/baz.
A list whose car is the symbol :relative represents a directory path starting from a default directory. The list (:relative) has the same meaning as nil and hence normally is not used. The list (:relative "foo" "bar") represents the directory named bar in the directory named foo in the default directory.
In place of a string, at any point in the list, a symbol may occur to indicate a special file notation. The following symbols have standard meanings.
Implementations are permitted to add additional objects of any non-string type if necessary to represent features of their file systems that cannot be represented with the standard strings and symbols. Supplying any non-string, including any of the symbols listed below, to a file system for which it does not make sense signals an error of type file-error. For example, most implementations of the UNIX file system do not support :wild-inferiors. Any directory list in which :absolute or :wild-inferiors is immediately followed by :up or :back is illegal and when processed causes an error to be signaled.
The keyword :back has a ``syntactic'' meaning that depends only on the pathname and not on the contents of the file system. The keyword :up has a ``semantic'' meaning that depends on the contents of the file system; to resolve a pathname containing :up to a pathname whose directory component contains only :absolute and strings requires a search of the file system. Note that use of :up instead of :back can result in designating a different actual directory only in file systems that support multiple names for directories, perhaps via symbolic links. For example, suppose that there is a directory link such that
(:absolute "X" "Y") is linked to (:absolute "A" "B")
and there also exist directories
(:absolute "A" "Q") and (:absolute "X" "Q")
Then
(:absolute "X" "Y" :up "Q") designates (:absolute "A" "Q")
but
(:absolute "X" "Y" :back "Q") designates (:absolute "X" "Q")
If a string is used as the value of the :directory argument to make-pathname, it should be the name of a top-level directory and should not contain any punctuation characters. Specifying a string s is equivalent to specifying the list (:absolute s). Specifying the symbol :wild is equivalent to specifying the list (:absolute :wild-inferiors) (or (:absolute :wild) in a file system that does not support :wild-inferiors).
The function pathname-directory always returns nil, :unspecific, or a list-never a string, never :wild. If a list is returned, it is not guaranteed to be freshly consed; the consequences of modifying this list are undefined.
In non-hierarchical file systems, the only valid list values for the directory component of a pathname are (:absolute s) (where s is a string) and (:absolute :wild). The keywords :relative, :wild-inferiors, :up, and :back are not used in non-hierarchical file systems.
Pathname merging treats a relative directory specially. Let pathname and defaults be the first two arguments to merge-pathnames. If (pathname-directory pathname) is a list whose car is :relative, and (pathname-directory defaults) is a list, then the merged directory is the value of
(append (pathname-directory defaults) (cdr ;Remove :relative from the front (pathname-directory pathname)))
except that if the resulting list contains a string or :wild immediately followed by :back, both of them are removed. This removal of redundant occurrences of :back is repeated as many times as possible. If (pathname-directory defaults) is not a list or (pathname-directory pathname) is not a list whose car is :relative, the merged directory is the value of
(or (pathname-directory pathname) (pathname-directory defaults))
A relative directory in the pathname argument to a function such as open is merged with the value of *default-pathname-defaults* before the file system is accessed.
Here are some examples of the use of structured directories. Suppose that host L supports a Symbolics Lisp Machine file system, host U supports a UNIX file system, and host V supports a VAX/VMS file system.
(pathname-directory (parse-namestring "V:[FOO.BAR]BAZ.LSP")) => (:ABSOLUTE "FOO" "BAR")
(pathname-directory (parse-namestring "U:/foo/bar/baz.lisp")) => (:ABSOLUTE "foo" "bar")
(pathname-directory (parse-namestring "U:../baz.lisp")) => (:RELATIVE :UP)
(pathname-directory (parse-namestring "U:/foo/bar/../mum/baz")) => (:ABSOLUTE "foo" "bar" :UP "mum")
(pathname-directory (parse-namestring "U:bar/../../ztesch/zip")) => (:RELATIVE "bar" :UP :UP "ztesch")
(pathname-directory (parse-namestring "L:>foo>**>bar>baz.lisp")) => (:ABSOLUTE "FOO" :WILD-INFERIORS "BAR")
(pathname-directory (parse-namestring "L:>foo>*>bar>baz.lisp")) => (:ABSOLUTE "FOO" :WILD "BAR")