Common Lisp the Language, 2nd Edition

Next: Structured Directories Up: File Names Previous: Pathnames

## 23.1.2. Case Conventions

Issues of alphabetic case in pathnames are a major source of problems. In some file systems, the customary case is lowercase, in some uppercase, in some mixed. Some file systems are case-sensitive (that is, they treat `FOO` and `foo` as different file names) and others are not.

There are two kinds of pathname case portability problems: moving programs from one Common Lisp to another, and moving pathname component values from one file system to another. The solution to the first problem is the requirement that all Common Lisp implementations that support a particular file system must use compatible representations for pathname component values. The solution to the second problem is the use of a common representation for the least-common-denominator pathname component values that exist on all interesting file systems.

Requiring a common representation directly conflicts with the desire among programmers that use only one file system to work with the local conventions and to ignore issues of porting to other file systems. The common representation cannot be the same as local (varying) conventions.

X3J13 voted in June 1989 (PATHNAME-COMPONENT-CASE) to add a keyword argument `:case` to each of the functions `make-pathname`, `pathname-host`, `pathname-device`, `pathname-directory`, `pathname-name`, and `pathname-type`. The possible values for the argument are `:common` and `:local`. The default is `:local`.

The value `:local` means that strings given to `make-pathname` or returned by any of the pathname component accessors follow the local file system's conventions for alphabetic case. Strings given to `make-pathname` will be used exactly as written if the file system supports both cases. If the file system supports only one case, the strings will be translated to that case.

The value `:common` means that strings given to `make-pathname` or returned by any of the pathname component accessors follow this common convention:

- All uppercase means that a file system's customary case will be used.
- All lowercase means that the opposite of the customary case will be used.
- Mixed case represents itself.

Uppercase is used as the common case for no better reason than consistency with Lisp symbols. The second and third points allow translation from local representation to common and back to be information-preserving. (Note that translation from common to local representation and back may or may not be information-preserving, depending on the nature of the local representation.)

Namestrings always use `:local` file system case conventions.

Finally, `merge-pathnames` and `translate-pathname` map customary case in the input pathnames into customary case in the output pathname.

Examples of possible use of this convention:

- TOPS-20 is case-sensitive and prefers uppercase, translating lowercase to uppercase unless escaped with `^V`; for a TOPS-20-based file system, a Common Lisp implementation should use identical representations for common and local.

- UNIX is case-sensitive and prefers lowercase; for a UNIX-based file system, a Common Lisp implementation should translate between common and local representations by inverting the case of non-mixed-case strings.

- VAX/VMS is uppercase-only (that is, the file system translates all file name arguments to uppercase); for a VAX/VMS-based file system, a Common Lisp implementation should translate common representation to local by converting to uppercase and should translate local representation to common with no change.

- The Macintosh operating system is case-insensitive and prefers lowercase, but remembers the cases of letters actually used to name a file; for a Macintosh-based file system, a Common Lisp implementation should translate between common and local representations by inverting the case of non-mixed-case strings and should ignore case when determining whether two pathnames are `equal`.

Here are some examples of this behavior. Assume that the host `T` runs TOPS-20, `U` runs UNIX, `V` runs VAX/VMS, and `M` runs the Macintosh operating system.

    ;;; Returns two values: the PATHNAME-NAME from a namestring
    ;;; in :COMMON and :LOCAL representations (in that order).
    (defun pathname-example (name)
      (let ((path (parse-namestring name))))
        (values (pathname-name path :case :common)
                (pathname-name path :case :local))))

                                               => "FOO" and ¯"FOO"                                               ;Common		Local
    (pathname-example "T:<ME>FOO.LISP")        => "FOO" and "FOO"
    (pathname-example "T:<ME>foo.LISP")        => "FOO" and "FOO"
    (pathname-example "T:<ME>^Vf^Vo^Vo.LISP")  => "foo" and "foo"
    (pathname-example "T:<ME>TeX.LISP")        => "TEX" and "TEX"
    (pathname-example "T:<ME>T^VeX.LISP")      => "TeX" and "TeX"
    (pathname-example "U:/me/FOO.lisp")        => "foo" and "FOO"
    (pathname-example "U:/me/foo.lisp")        => "FOO" and "foo"
    (pathname-example "U:/me/TeX.lisp")        => "TeX" and "TeX"
    (pathname-example "V:[me]FOO.LISP")        => "FOO" and "FOO"
    (pathname-example "V:[me]foo.LISP")        => "FOO" and "FOO"
    (pathname-example "V:[me]TeX.LISP")        => "TEX" and "TEX"
    (pathname-example "M:FOO.LISP")            => "foo" and "FOO"
    (pathname-example "M:foo.LISP")            => "FOO" and "foo"
    (pathname-example "M:TeX.LISP")            => "TeX" and "TeX"

The following example illustrates the creation of new pathnames. The name is converted from common representation to local because namestrings always use local conventions.

    (defun make-pathname-example (h n)
      (namestring (make-pathname :host h :name n :case :common))

    (make-pathname-example "T" "FOO") => "T:FOO"
    (make-pathname-example "T" "foo") => "T:^Vf^Vo^Vo"
    (make-pathname-example "T" "TeX") => "T:T^VeX"
    (make-pathname-example "U" "FOO") => "U:foo"
    (make-pathname-example "U" "foo") => "U:FOO"
    (make-pathname-example "U" "TeX") => "U:TeX"
    (make-pathname-example "V" "FOO") => "V:FOO"
    (make-pathname-example "V" "foo") => "V:FOO"
    (make-pathname-example "V" "TeX") => "V:TeX"
    (make-pathname-example "M" "FOO") => "M:foo"
    (make-pathname-example "M" "foo") => "M:FOO"
    (make-pathname-example "M" "TeX") => "M:TeX"

A big advantage of this set of conventions is that one can, for example, call `make-pathname` with `:type "LISP"` and `:case :common`, and the result will appear in a namestring as `.LISP` or `.lisp`, whichever is appropriate.

Next: Structured Directories Up: File Names Previous: Pathnames