Next: , Previous: Filenames and Pathnames, Up: Pathnames


15.1.2 Components of Pathnames

A pathname object 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 Scheme implementation.

host
The name of the file system on which the file resides. In the current implementation, this component is always a host object that is filled in automatically by the runtime system. When specifying the host component, use either #f or the value of the variable local-host.
device
Corresponds to the “device” or “file structure” concept in many host file systems: the name of a (logical or physical) device containing files. This component is the drive letter for PC file systems, and is unused for unix file systems.
directory
Corresponds to the “directory” concept in many host file systems: the name of a group of related files (typically those belonging to a single user or project). This component is always used for all file systems.
name
The name of a group of files that can be thought of as conceptually the “same” file. This component is always used for all file systems.
type
Corresponds to the “filetype” or “extension” concept in many host file systems. This says what kind of file this is. Files with the same name but different type are usually related in some specific way, such as one being a source file, another the compiled form of that source, and a third the listing of error messages from the compiler. This component is currently used for all file systems, and is formed by taking the characters that follow the last dot in the namestring.
version
Corresponds to the “version number” concept in many host file systems. Typically this is a number that is incremented every time the file is modified. This component is currently unused for all file systems.

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-input-file.

Two important operations involving pathnames are parsing and merging. Parsing is the conversion of a filename (which might be something supplied interactively by the users when asked to supply the name of a file) into a pathname object. This operation is implementation-dependent, because the format of filenames is implementation-dependent. Merging takes a pathname with missing components and supplies values for those components from a source of default values.

Not all of the components of a pathname need to be specified. If a component of a pathname is missing, its value is #f. 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. Pathnames with missing components are used internally for various purposes; in particular, parsing a namestring that does not specify certain components will result in a pathname with missing components.

Any component of a pathname may be the symbol unspecific, meaning that the component simply does not exist, for file systems in which such a value makes no sense. For example, unix and Windows file systems usually do not support version numbers, so the version component for such a host might be unspecific.1

In addition to #f and unspecific, the components of a pathname may take on the following meaningful values:

host
An implementation-defined type which may be tested for using the host? predicate.
device
On systems that support this component (Windows), it may be specified as a string containing a single alphabetic character, for which the alphabetic case is ignored.
directory
A non-empty list, which represents a directory path: a sequence of directories, each of which has a name in the previous directory, the last of which is the directory specified by the entire path. Each element in such a path specifies the name of the directory relative to the directory specified by the elements to its left. The first element of the list is either the symbol absolute or the symbol relative. If the first element in the list is the symbol absolute, then the directory component (and subsequently the pathname) is absolute; the first component in the sequence is to be found at the “root” of the file system. If the directory is relative then the first component is to be found in some as yet unspecified directory; typically this is later specified to be the current working directory. Aside from absolute and relative, which may only appear as the first element of the list, each subsequent element in the list is either: a string, which is a literal component; the symbol wild, meaningful only when used in conjunction with the directory reader; or the symbol up, meaning the next directory is the “parent” of the previous one. up corresponds to the file .. in unix and PC file systems.

(The following note does not refer to any file system currently supported by MIT/GNU Scheme, but is included for completeness.) In file systems that do not have “hierarchical” structure, a specified directory component will always be a list whose first element is absolute. If the system does not support directories other than a single global directory, the list will have no other elements. If the system supports “flat” directories, i.e. a global set of directories with no subdirectories, then the list will contain a second element, which is either a string or wild. In other words, a non-hierarchical file system is treated as if it were hierarchical, but the hierarchical features are unused. This representation is somewhat inconvenient for such file systems, but it discourages programmers from making code depend on the lack of a file hierarchy.

name
A string, which is a literal component; or the symbol wild, meaningful only when used in conjunction with the directory reader.
type
A string, which is a literal component; or the symbol wild, meaningful only when used in conjunction with the directory reader.
version
An exact positive integer, which is a literal component; the symbol newest, which means to choose the largest available version number for that file; the symbol oldest, which means to choose the smallest version number; or the symbol wild, meaningful only when used in conjunction with the directory reader. In the future some other possible values may be added, e.g. installed. Note that currently no file systems support version numbers; thus this component is not used and should be specified as #f.
— procedure: make-pathname host device directory name type version

Returns a pathname object whose components are the respective arguments. Each argument must satisfy the restrictions for the corresponding component, which were outlined above.

          (make-pathname #f
                         #f
                         '(absolute "usr" "morris")
                         "foo"
                         "scm"
                         #f)
               =>  #[pathname 67 "/usr/morris/foo.scm"]
     
— procedure: pathname-host pathname
— procedure: pathname-device pathname
— procedure: pathname-directory pathname
— procedure: pathname-name pathname
— procedure: pathname-type pathname
— procedure: pathname-version pathname

Returns a particular component of pathname.

          (define x (->pathname "/usr/morris/foo.scm"))
          (pathname-host x)       =>  #[host 1]
          (pathname-device x)     =>  unspecific
          (pathname-directory x)  =>  (absolute "usr" "morris")
          (pathname-name x)       =>  "foo"
          (pathname-type x)       =>  "scm"
          (pathname-version x)    =>  unspecific
     
— procedure: pathname-new-device pathname device
— procedure: pathname-new-directory pathname directory
— procedure: pathname-new-name pathname name
— procedure: pathname-new-type pathname type
— procedure: pathname-new-version pathname version

Returns a new copy of pathname with the respective component replaced by the second argument. Pathname is unchanged. Portable programs should not explicitly replace a component with unspecific because this might not be permitted in some situations.

          (define p (->pathname "/usr/blisp/rel15"))
          p
               =>  #[pathname 71 "/usr/blisp/rel15"]
          (pathname-new-name p "rel100")
               =>  #[pathname 72 "/usr/blisp/rel100"]
          (pathname-new-directory p '(relative "test" "morris"))
               =>  #[pathname 73 "test/morris/rel15"]
          p
               =>  #[pathname 71 "/usr/blisp/rel15"]
     
— procedure: pathname-default-device pathname device
— procedure: pathname-default-directory pathname directory
— procedure: pathname-default-name pathname name
— procedure: pathname-default-type pathname type
— procedure: pathname-default-version pathname version

These operations are similar to the pathname-new-component operations, except that they only change the specified component if it has the value #f in pathname.


Footnotes

[1] This description is adapted from Common Lisp, The Language, second edition, section 23.1.1.