
\chapter{Foreign-function Interface}


The interface between T3 and the local operating system is the
{\mbox {\tt define-foreign}} special form:

{\tt \begin{tabbing}
(DEFINE-FOREIGN \= {\it T-name\/} \+ \\
                ({\it foreign-name parameters\/}) \\
                {\it return-type\/})
\end{tabbing}}

{\mbox {\tt DEFINE-FOREIGN}} defines a {\it foreign procedure\/},
i.e. a {\bf T} procedure which will call a procedure defined
by the operating system or in another language.

\begin{inset}{}
\item[{{\it T-name\/}}] is the name of the {\bf T} procedure being defined.

\item[{{\it foreign-name\/}}] is the name of the foreign procedure
to which the {\it T-name\/} corresponds.

\item[{{\it parameters\/}}] specifies the representation of the parameters
to the foreign procedure or function.

\item[{{\it return-type\/}}] indicates the representation of the value 
returned by the foreign procedure.
\end{inset}

\begin{codexenv}
    \begin{tabular}{lll}
parameter      &$\Longrightarrow$\ & (parameter-type foreign-type [parameter-name]) \\

parameter-type &$\Longrightarrow$\ & \{ in $|$ out $|$ in/out $|$ var $|$ ignore \} \\

foreign-type   &$\Longrightarrow$\ & \{ rep/integer        $|$ \\
                      &&rep/integer-8-s    $|$ \\
                      &&rep/integer-8-u    $|$ \\
                      &&rep/integer-16-s   $|$ \\
                      &&rep/integer-16-u   $|$ \\
                      &&rep/value          $|$ \\
                      &&rep/extend         $|$ \\
                      &&rep/extend-pointer $|$ \\
                      &&rep/string         $|$ \\
                      &&rep/string-pointer  \} \\

parameter-name &$\Longrightarrow$\ & symbol used for identification \\

return-type    &$\Longrightarrow$\ & Aegis: \{ foreign-type $|$ ignore $|$ rep/address \} \\
                    && Unix:  \{ foreign-type $|$ ignore \} \\
\end{tabular}
    \end{codexenv}

For example, on the Apollo a procedure to do block reads from a stream
would be defined as follows:

{\tt \begin{tabbing}
(DEFINE-FOREIGN \= aegis-read \+  \\
    (stream\_\$get\_buf \= (in     rep/integer-16-u   stream-id) \+ \\
                     (in     rep/string         bufptr) \\
                     (in     rep/integer        buflen) \\
                     (ignore rep/integer        retptr) \\
                     (out    rep/integer        retlen) \\
                     (ignore rep/extend         seek-key) \\
                     (out    rep/integer        status)) \- \\
          ignore)
\end{tabbing}}

The following code will use {\mbox {\tt AEGIS-READ}} to read in a string
from standard input:

{\tt \begin{tabbing}
  (let \= (\= (stream 0) \+  \\
        (buf    (make-string 128))) \-  \\
    (receive \= (5 status) (aegis-read stream buf 128 nil nil nil nil) \+  \\
      (cond \= (\= (= 0 status) \+ \+  \\
             (set (string-length buf) 5) \\
             5) \-  \\
            (error \ldots\ ))))
\end{tabbing}}

On a Unix machine a similar procedure would be defined as,

{\tt \begin{tabbing}
  (define-foreign \= unix-read-extend (read \= (in rep/integer) \+ \+  \\
                                         (in rep/string) \\
                                         (in rep/integer)) \-  \\
                  rep/integer)
\end{tabbing}}

To read a string from standard input on Unix the {\bf T} code would
look something like:

{\tt \begin{tabbing}
  (let \= ((buf (make-string 128))) \+  \\
    (receive \= (5 status) (unix-read 0 buf 128) \+  \\
      (cond \= (\= ($>$ 0 status ) \+ \+  \\
             (set (string-length buf) 5) \\
             5) \-  \\
            (error \ldots\ ))))
\end{tabbing}}

\section{Foreign Type Specification}


The {\it foreign-type\/} tells the compiler how to interpret a {\bf T}
data type in order to pass it to the foreign call.  The general
categories of Pascal data types are numeric, string, record,
enumerated, set of.

\begin{tabular}{llll}

              &  Pascal Type   &  T3 Type   &  Foreign Type Spec   \\
Numeric       &                &            &                      \\
              &  integer8      &  fixnum    &  rep/integer-8-s     \\
              &  binteger      &  fixnum    &  rep/integer-8-u     \\
              &  integer16     &  fixnum    &  rep/integer-16-s    \\
              &  pinteger      &  fixnum    &  rep/integer-16-u    \\
              &  integer       &  fixnum    &  rep/integer         \\
              &  linteger      &  fixnum    &  rep/integer         \\
              &  real          &            &  unimplemented       \\
              &  double        &  flonum    &  rep/extend          \\
String        &                &            &                      \\
              &  string        &  string    &  rep/string          \\
              &  string        &  text      &  rep/extend          \\
              &  univ\_pointer &  string    &  rep/string-pointer  \\
              &  univ\_pointer &  text      &  rep/extend-pointer  \\
Record        &                &            &                      \\
              &  record        &  extend    &  rep/extend          \\
Miscellaneous &                &            &                      \\
              &  char          &  char      &  rep/char            \\
              &  boolean       &  boolean   &  rep/integer-8-s

\end{tabular}

Beware that if a {\bf T} string is being used as an out parameter
the offset field of the string must be 0 (the string must never
have been {\mbox {\tt chdr!}}'ed).

Record structures are represented by byte-vectors of the
appropriate size.

\section{Pascal (Apollo) Enumerated Types}


Pascal enumerated types are defined using the {\mbox {\tt DEFINE-ENUMERATED}}
special form:

\index{DEFINE-ENUMERATED@{\tt DEFINE-ENUMERATED}}
{\mbox {\tt (DEFINE-ENUMERATED {\it type-name\/} \{{\it element\/}\}$^*$\ ) $\longrightarrow$\  {\it undefined}}}
\hfill Special form


\begin{inset}{}
Here {\it type-name\/} is just for identification, and the {\it element\/}s
are the enumerated types.  For example,

{\tt \begin{tabbing}
  (define-enumerated \= ios\_\$create\_mode\_t \+ \\
                     ios\_\$no\_pre\_exist\_mode \\
                     ios\_\$preserve\_mode \\
                     ios\_\$recreate\_mode \\
                     ios\_\$truncate\_mode \\
                     ios\_\$make\_backup\_mode \\
                     ios\_\$loc\_name\_only\_mode \\
                     )
\end{tabbing}}

The foreign procedure is called with the enumerated type name just as in Pascal.
\end{inset}

\section{Pascal Sets (Apollo)}


The Pascal type {\bf set-of} is defined using the {\mbox {\tt DEFINE-SET-OF}}
special form:

\index{DEFINE-SET-OF@{\tt DEFINE-SET-OF}}
{\mbox {\tt (DEFINE-SET-OF {\it type-name\/} \{{\it element\/}\}$^*$\ ) $\longrightarrow$\  {\it undefined}}}
\hfill Special form


There, again, {\it type-name} is just for identification, and
the {\it element}s are the names of the set members.  For
example,

{\tt \begin{tabbing}
  (define-set-of \= ios\_\$put\_get\_opts\_t \+ \\
                 ios\_\$cond\_opt \\
                 ios\_\$preview\_opt \\
                 ios\_\$partial\_record\_opt \\
                 ios\_\$no\_rec\_bndry\_opt \\
                 )
\end{tabbing}}

\section{Returned Values and Out Parameters}


For languages which have output parameters, e.g. Pascal, multiple
values are returned.  The first value is the return-value of
the foreign procedure, unless it is of {\it return-type}
{\mbox {\tt ignore}}, followed by the out parameters.  Thus a call
to the {\bf T} procedure {\mbox {\tt AEGIS-READ}}, defined above, would
return two values: {\it retlen} and {\it status}.  For a
Pascal procedure the return spec will always be {\mbox {\tt ignore}}.
The argument to a foreign procedure should usually be of type
{\mbox {\tt ignore}} if it is an out parameter to the foreign
procedure that is bigger than a longword.  Also, the value of
any out parameters which are not needed can be specified as
{\mbox {\tt ignore}}.

Pascal functions which return addresses {\bf must} have
{\it return-type} of type {\it rep/address}.  If this value is passed
to another foreign call it should be with {\it rep/integer}.

{\mbox {\tt DEFINE-FOREIGN}} does not allocate storage for out
parameters.  This means that you must allocate your own object
and pass it to the foreign procedure even if it is only an out
parameter.  If it is an out parameter which is other than an
integer then its {\it foreign-type} should be {\mbox {\tt ignore}}
and the variable passed in should be used to reference the
parameter.
