6.3  Entry points

To simplify embedding compiled Scheme code into arbitrary programs, one can define so called ``entry points'', which provide a uniform interface and parameter conversion facilities.

[syntax] (define-entry-point INDEX ((VAR1 TYPE1) ...) (RTYPE1 ...) EXP1 EXP2 ...)
Defines a new entry-point with index INDEX which should evaluate to an exact integer. During execution of the body EXP1 EXP2 ... the variables VAR1 ... are bound to the parameters passed from the host program to the invoked entry point. The parameters passed are converted according to the foreign type specifiers TYPE1 .... The expressions should return as many values as foreign type specifiers are given in RTYPE1 .... The results are then transformed into values that can be used in the host program.

Note: if one or more of the result types RTYPE ... specify the type c-string, then the parameter types at the same positions in TYPE1 ... have to be c-strings as well, because the result strings are copied into the same area in memory. You should also take care that the passed buffer is long enough to hold the result string or unpredictable things will happen.

If entry points were defined then the program will not terminate after execution of the last toplevel expression, but instead it will enter a loop that waits for the host to invoke one of the defined entry points.

The following C functions and data types are provided:

[C function] void CHICKEN_parse_command_line(int argc, char *argv[], int *heap, int *stack int *symbols)
Parse the programs command-line contained in argc and argv and return the heap-, stack- and symbol table limits given by runtime options of the form -:..., or choose default limits. The library procedure argv can access the command-line only if this function has been called by the containing application.

[C function] int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel)
Initializes the Scheme execution context and memory. heap holds the number of bytes that are to be allocated for the secondary heap. stack holds the number of bytes for the primary heap. symbols contains the size of the symbol table. Passing 0 to one or more of these parameters will select a default size. toplevel should be a pointer to the toplevel entry point procedure. You should pass C_toplevel here. In any subsequent call to CHICKEN_run or CHICKEN_invoke you can simply pass NULL. Calling this function more than once has no effect. If enough memory is available and initialization was successful, then 1 is returned, otherwise this function returns 0.

[C function] void CHICKEN_run(void **data, int *bytes, int *maxlen, void *toplevel)
Starts the Scheme program. data, bytes and maxlen contain invocation parameters in raw form. Pass NULL here. Call this function once to execute all toplevel expressions in your compiled Scheme program. If the runtime system was not initialized before, then CHICKEN_initialize is called with default sizes. toplevel is the toplevel entry-point procedure.

[C function] void CHICKEN_invoke(int index, C_parameter *params, int count, void *toplevel)
Invoke the entry point with index index. count should contain the number of parameters passed. params is a pointer to parameter data:

typedef union
{
  C_word x;           /* parameter type scheme-object */
  long i;             /* parameter type bool, [unsigned] int/short/long */
  long c;             /* parameter type [unsigned] char */
  double f;           /* parameter type float/double */
  void *p;            /* any pointer parameter type and C strings */
} C_parameter;

This function calls CHICKEN_run if it was not called at least once before.

Here is a simple example (assuming a UNIX-like environment):

% cat foo.c
#include <stdio.h>
#include "chicken.h"

int main(void)
{
  C_parameter p[ 3 ];
  char str[ 32 ] = "hello!";  /* We need some space for the result string! */

  memset(p, 0, sizeof(p));
  p[ 0 ].i = -99;
  p[ 1 ].p = str;
  p[ 2 ].f = 3.14;
  CHICKEN_invoke(1, p, 3, C_toplevel);
  printf("->\n%d\n%s\n", p[ 0 ].i, p[ 1 ].p);
  return 0;
}

% cat bar.scm
(define-entry-point 1
    ((a integer) (b c-string) (c double))
    (int c-string)
  (print (list a b c))
  (values 123 "good bye!") )

% chicken bar.scm -quiet
% gcc foo.c bar.c -o foo `chicken-config -cflags -embedded`
% foo
(-99 "hello!" 3.14)
->
123
good bye!

Note the use of -embedded. We have to compile with additional compiler options, because the host program provides the main function.