Previous Section Next Section Table of Contents Glossary Index

Chapter 13. The Foreign-Function Interface

13.8. Case-sensitivity of foreign names in CCL

13.8.1. Overview

As of release 0.11, CCL addresses the fact that foreign type, constant, record, field, and function nams are case-sensitive and provides mechanisms to refer to these names via lisp symbols.

Previous versions of CCL have tried to ignore that fact, under the belief that case conflicts were rare and that many users (and implementors) would prefer not to deal with case-related issues. The fact that some information in the interface databases was incomplete or inaccessible because of this policy made it clearer that the policy was untenable. I can't claim that the approach described here is aesthetically pleasing, but I can honestly say that it's less unpleasant than other approaches that I'd thought of. I'd be interested to hear alternate proposals.

The issues described here have to do with how lisp symbols are used to denote foreign functions, constants, types, records, and fields. It doesn't affect how other lisp objects are sometimes used to denote foreign objects. For instance, the first argument to the EXTERNAL-CALL macros is now and has always been a case-sensitive string.

13.8.2. Foreign constant and function names

The primary way of referring to foreign constant and function names in CCL is via the #$ and #_ reader macros. These reader macro functions each read a symbol into the "OS" package, look up its constant or function definition in the interface database, and assign the value of the constant to the symbol or install a macroexpansion function on the symbol.

In order to observe case-sensitivity, the reader-macros now read the symbol with (READTABLE-CASE :PRESERVE) in effect.

This means that it's necessary to type the foreign constant or function name in correct case, but it isn't necessary to use any special escaping constructs when writing the variable name. For instance:

        (#_read fd buf n) ; refers to foreign symbol "read"
        (#_READ fd buf n) ; refers to foreign symbol "READ", which may
        ; not exist ...
        #$o_rdonly ; Probably doesn't exist
        #$O_RDONLY ; Exists on most platforms

13.8.3. Foreign type, record, and field names

Constructs like RLET expect a foreign type or record name to be denoted by a symbol (typically a keyword); RREF (and PREF) expect an "accessor" form, typically a keyword formed by concatenating a foreign type or record name with a sequence of one or more foreign field names, separated by dots. These names are interned by the reader as other lisp symbols are, with an arbitrary value of READTABLE-CASE in effect (typically :UPCASE.) It seems like it would be very tedious to force users to manually escape (via vertical bar or backslash syntax) all lowercase characters in symbols used to specify foreign type, record, and field names (especially given that many traditional POSIX structure, type, and field names are entirely lowercase.)

The approach taken by CCL is to allow the symbols (keywords) used to denote foreign type, record, and field names to contain angle brackets (< and >). Such symbols are translated to foreign names via the following set of conventions:

  • All instances of < and > in the symbol's pname are balanced and don't nest.

  • Any alphabetic characters in the symbol's pname that aren't enclosed in angle brackets are treated as lower-case,regardless of the value of READTABLE-CASE and regardless of the case in which they were written.

  • Alphabetic characters that appear within angle brackets are mapped to upper-case, again regardless of how they were written or interned.

There may be many ways of "escaping" (with angle brackets) sequences of upper-case and non-lower-case characters in a symbol used to denote a foreign name. When translating in the other direction, CCL always escapes the longest sequence that starts with an upper-case character and doesn't contain a lower-case character.

It's often preferable to use this canonical form of a foreign type name.

The accessor forms used by PREF/RREF should be viewed as a series of foreign type/record and field names; upper-case sequences in the component names should be escaped with angle brackets, but those sequences shouldn't span components. (More simply, the separating dots shouldn't be enclosed, even if both surrounding characters need to be.)

Older POSIX code tends to use lower-case exclusively for type, record, and field names; there are only a few cases in the CCL sources where mixed-case names need to be escaped.

13.8.4. Examples

        ;;; Allocate a record of type "window".
        (rlet ((w :window)) ...)
        ;;; Allocate a record of type "Window", which is probably a
        ;;;  different type
        (rlet ((w :<w>indow)) ...)
        ;;; This is equivalent to the last example
        (rlet ((w :<w>INDOW)))

Previous Section Next Section Table of Contents Glossary Index