## 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-string`s 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.