@c -*-texinfo-*-
@node Foreign Interface, Tracer, Mailboxes, Top
@comment  node-name,  next,  previous,  up
@chapter Foreign Language Interface 

ICP offers an interface to functions written in the programming language 
`C' --- Brian W. Kerninghan and Dennis M. Ritchie, @cite{The C Programming
Language}, Prentice-Hall, inc. Currently the calling of `C' functions from
prolog is 
supported but `C' can not call prolog. In later versions this support will 
be provided. Dynamic loading is achieved through the unix @file{ld} 
command.

The arguments of predicates corresponding to `C' functions are restricted 
to non complex terms - integers, floats or atoms. The type of each 
argument must be specified together with whether it is an input or output 
argument. Input arguments must be ground when called, while output arguments may
also be variables. The interface provides the transformation to and from the 
internal Prolog representation of the primitive types and the 
corresponding `C' representation.

@menu
* ForeignPredicates::           Foreign Language Predicates 
@end menu

@node ForeignPredicates,  ,  , Foreign Interface
@comment  node-name,  next,  previous,  up
@section Foreign Language Predicates 

@table @code
@item load_foreign_files(@var{+FileList})
@findex load_foreign_files/1
This is used to load foreign functions into the running prolog system. 
@var{FileList} is a list of object files (compiled `C' files). The 
`@file{tt .o}' extension may be ommited. A single atom (file name) is also 
allowed as a value of @var{FileList}. The files are searched for in the 
current search path.

@item load_foreign_files(@var{+FileList}, @var{+LinkerArgs})
@findex load_foreign_files/2
Same as above with the additional parameter @var{LinkerArgs} specifying
a list of arguments to be passed to the unix @file{ld} command.
This is typically used when additional system libraries are required.

The user defined predicates @code{foreign_file/2} and 
@code{foreign/3} are used to specify the prolog predicates and 
corresponding `C' functions.

@item foreign_file(@var{-File}, @var{-Functions})
@upindex foreign_file/2
@var{File} is an object (compiled `C') file while @var{Functions} is 
a list of the `C' function names defined in this file which are to be
interfaced.

@item foreign(@var{+Cfunction}, @var{+Language}, @var{+PredicateSpecification})
@upindex foreign/3
@var{Cfunction} is the name of a `C' function and @var{Language} is the 
atom @code{c} (In future languages other than `C' may be supported). 
@var{PredicateSpecification} describes the form of the prolog predicate 
to be used to access the foreign function. This is a term of the form @*
PrologName(@var{ArgSpec1}, ..., @var{ArgSpecN}) @*
Each argument is of one of the following forms

@itemize @bullet
@item
+@var{integer} The Prolog argument is an integer. The corresponding 
`C' argument type is @kbd{long int}.
@item
-@var{integer} The Prolog argument is an integer or a variable. 
The corresponding `C' argument type is @kbd{long int *}.
@item
@code{[-@var{integer}]} The Prolog argument is an integer or a 
variable. The corresponding `C' function type is @kbd{long int *}.
@item
+@var{float} The Prolog argument is a floating point number. 
The corresponding `C' argument type is @kbd{double}.
@item
-@var{float} The Prolog argument is a floating point number or a variable. 
The corresponding `C' argument type is @kbd{double *}.
@item
@code{[-@var{float}]} The Prolog argument is a floating 
point number or a variable. The corresponding `C' function type is 
@kbd{long int *}.
@item
+@var{atom} The Prolog argument is an atom. The corresponding 
`C' argument type is @kbd{char *}.
@item
-@var{atom} The Prolog argument is an atom or a variable. 
The corresponding `C' argument type is @kbd{char **}.
@item
@code{[-@var{atom}]} The Prolog argument is an atom or a 
variable. The corresponding `C' function type is @kbd{char *}.
@item
+@var{string} Synonym for +@var{atom}.
@item
-@var{string} Synonym for -@var{atom}.
@item
@code{[-@var{string}]} Synonym for @code{[-@var{atom}]}.
@end itemize

The `C' function must include the file @file{ICprolog.h}.
There should be no more than one argument corresponding to a `C' 
function return type. If there is no such argument, the return type of the 
`C' function should be specified as @kbd{bool}, and it should return one
of the following values

@table @code
@item FAIL
The prolog call will fail.
@item SUCCEED
The prolog call will succeed.
@item SUSPEND
If a primitive returns @code{SUSPEND}, then that thread is taken out of
the run queue.  This means that another thread will have to explicitly
`resume' @xref{Threads}, it before it can run again.
@item REQUEUE
@code{REQUEUE} means the primitive should be tried again later. This
can result in a busy wait if nothing happens in between to change the status.
@end table
@end table

@menu
* ForeignComp::                 
@end menu

@node ForeignComp,  ,  , ForeignPredicates
@comment  node-name,  next,  previous,  up
@subsection Compilation and Example

When compiling the @kbd{-I} option should be given to the `C' compiler to
specify the directory where the @file{ICprolog.h} file is located. For example
@example
cc -w -O -I$ICP_INSTALLDIR/include -c myfuncs.c
@end example

With the following code for @file{myfuncs.c}
@example
#include "ICprolog.h"

char *malloc();

/* foreign(twice, c, ptwice(+float, [-float])). */
double twice(a)
double a;
@{
        return(2 * a);
@}

/* foreign(concat, c, pconcat(+atom, +atom, -atom)). */
bool concat(a, b, c)
char *a, *b, **c;
@{
        int len;
        static int last_len = 0;
        static char *ret = NULL;
        char *pt;

        len = strlen(a) + strlen(b) + 1;
        if (!ret) @{
                last_len = len;
                ret = malloc(len);
        @} else if (len > last_len) @{
                free(ret);
                ret = malloc(len);
                last_len = len;
        @}
        pt = ret;
        while (*pt = *a++)
                pt++;
        while (*pt = *b++)
                pt++;
        *c = ret;
        return(SUCCESS);
@}

/* foreign(foo, c, pfoo(+integer,-integer,+atom,-atom,+float,-float)). */
bool foo(int1, int2, atom1, atom2, float1, float2)
int int1, *int2;
char *atom1, **atom2;
double float1, *float2;
@{
        *int2 = int1;
        *atom2 = atom1;
        *float2 = float1;
        return(SUCCESS);
@}
@end example

and the following prolog declarations

@example
foreign_file('test.o', [twice, concat, foo]).

foreign(twice, c, ptwice(+float, [-float])).
foreign(concat, c, pconcat(+atom, +atom, -atom)).
foreign(foo, c, pfoo(+integer, -integer, +atom, -atom, +float, -float)).
@end example

will give the results:
@example
@cartouche
| ?- [test], listing([foreign_file, foreign]).
foreign_file('test.o',[twice,concat,foo]).

foreign(twice,c,ptwice(+ float,[- float])).
foreign(concat,c,pconcat(+ atom,+ atom,- atom)).
foreign(foo,c,pfoo(+ integer,- integer,+ atom,- atom,+ float,- float)).

yes
| ?- load_foreign_files('test.o').
@{loading foreign from ./test_interface.o ./test.o @}

yes
| ?- ptwice(1.1, T).

T = 2.2 

| ?- pconcat(ab, cd, E).

E = abcd 

| ?- pfoo(4, I, hello, A, 1.3, F).

I = 4
A = hello
F = 1.3 
@end cartouche
@end example

