Next: , Previous: Allocating memory, Up: Operations


6.2.10 Embedding SCM

The file scmmain.c contains the definition of main(). When SCM is compiled as a library scmmain.c is not included in the library; a copy of scmmain.c can be modified to use SCM as an embedded library module.

— Function: int main (int argc, char **argv)

This is the top level C routine. The value of the argc argument is the number of command line arguments. The argv argument is a vector of C strings; its elements are the individual command line argument strings. A null pointer always follows the last element: argv[argc] is this null pointer.

— Variable: char *execpath

This string is the pathname of the executable file being run. This variable can be examined and set from Scheme (see Internal State). execpath must be set to executable's path in order to use DUMP (see Dump) or DLD.

Rename main() and arrange your code to call it with an argv which sets up SCM as you want it.

If you need more control than is possible through argv, here are descriptions of the functions which main() calls.

— Function: void init_sbrk (void)

Call this before SCM calls malloc(). Value returned from sbrk() is used to gauge how much storage SCM uses.

— Function: char * scm_find_execpath (int argc, char **argv, char *script_arg)

argc and argv are as described in main(). script_arg is the pathname of the SCSH-style script (see Scripting) being invoked; 0 otherwise. scm_find_execpath returns the pathname of the executable being run; if scm_find_execpath cannot determine the pathname, then it returns 0.

scm_find_implpath is defined in scmmain.c. Preceeding this are definitions ofGENERIC_NAME and INIT_GETENV. These, along with IMPLINIT and dirsep control scm_find_implpath()'s operation.

If your application has an easier way to locate initialization code for SCM, then you can replace scm_find_implpath.

— Function: char * scm_find_implpath (char *execpath)

Returns the full pathname of the Scheme initialization file or 0 if it cannot find it.

The string value of the preprocessor variable INIT_GETENV names an environment variable (default ‘"SCM_INIT_PATH"’). If this environment variable is defined, its value will be returned from scm_find_implpath. Otherwise find_impl_file() is called with the arguments execpath, GENERIC_NAME (default "scm"), INIT_FILE_NAME (default "Init5e7_scm"), and the directory separator string dirsep. If find_impl_file() returns 0 and IMPLINIT is defined, then a copy of the string IMPLINIT is returned.

— Function: int init_buf0 (FILE *inport)

Tries to determine whether inport (usually stdin) is an interactive input port which should be used in an unbuffered mode. If so, inport is set to unbuffered and non-zero is returned. Otherwise, 0 is returned.

init_buf0 should be called before any input is read from inport. Its value can be used as the last argument to scm_init_from_argv().

— Function: void scm_init_from_argv (int argc, char **argv, char *script_arg, int iverbose, int buf0stdin)

Initializes SCM storage and creates a list of the argument strings program-arguments from argv. argc and argv must already be processed to accomodate Scheme Scripts (if desired). The scheme variable *script* is set to the string script_arg, or #f if script_arg is 0. iverbose is the initial prolixity level. If buf0stdin is non-zero, stdin is treated as an unbuffered port.

Call init_signals and restore_signals only if you want SCM to handle interrupts and signals.

— Function: void init_signals (void)

Initializes handlers for SIGINT and SIGALRM if they are supported by the C implementation. All of the signal handlers immediately reestablish themselves by a call to signal().

— Function: void restore_signals (void)

Restores the handlers in effect when init_signals was called.

— Function: SCM scm_top_level (char *initpath, SCM (*toplvl_fun)())

This is SCM's top-level. Errors longjmp here. toplvl_fun is a callback function of zero arguments that is called by scm_top_level to do useful work – if zero, then repl, which implements a read-eval-print loop, is called.

If toplvl_fun returns, then scm_top_level will return as well. If the return value of toplvl_fun is an immediate integer then it will be used as the return value of scm_top_level. In the main function supplied with SCM, this return value is the exit status of the process.

If the first character of string initpath is ‘;’, ‘(’ or whitespace, then scm_ldstr() is called with initpath to initialize SCM; otherwise initpath names a file of Scheme code to be loaded to initialize SCM.

When a Scheme error is signaled; control will pass into scm_top_level by longjmp, error messages will be printed to current-error-port, and then toplvl_fun will be called again. toplvl_fun must maintain enough state to prevent errors from being resignalled. If toplvl_fun can not recover from an error situation it may simply return.

— Function: void final_scm (int freeall)

Calls all finalization routines registered with add_final(). If freeall is non-zero, then all memory which SCM allocated with malloc() will be freed.

You can call indivdual Scheme procedures from C code in the toplvl_fun argument passed to scm_top_level(), or from module subrs (registered by an init_ function, see Changing Scm).

Use apply to call Scheme procedures from your C code. For example:

     /* If this apply fails, SCM will catch the error */
     apply(CDR(intern("srv:startup",sizeof("srv:startup")-1)),
           mksproc(srvproc),
           listofnull);
     
     func = CDR(intern(rpcname,strlen(rpcname)));
     retval = apply(func, cons(mksproc(srvproc), args), EOL);

Functions for loading Scheme files and evaluating Scheme code given as C strings are described in the next section, (see Callbacks).

Here is a minimal embedding program libtest.c:

     /* gcc -o libtest libtest.c libscm.a -ldl -lm -lc */
     #include "scm.h"
     /* include patchlvl.h for SCM's INIT_FILE_NAME. */
     #include "patchlvl.h"
     
     void libtest_init_user_scm()
     {
       fputs("This is libtest_init_user_scm\n", stderr); fflush(stderr);
       sysintern("*the-string*", makfrom0str("hello world\n"));
     }
     
     SCM user_main()
     {
       static int done = 0;
       if (done++) return MAKINUM(EXIT_FAILURE);
       scm_ldstr("(display *the-string*)");
       return MAKINUM(EXIT_SUCCESS);
     }
     
     int main(argc, argv)
          int argc;
          const char **argv;
     {
       SCM retval;
       char *implpath, *execpath;
     
       init_user_scm = libtest_init_user_scm;
       execpath = dld_find_executable(argv[0]);
       fprintf(stderr, "dld_find_executable(%s): %s\n", argv[0], execpath);
       implpath = find_impl_file(execpath, "scm", INIT_FILE_NAME, dirsep);
       fprintf(stderr, "implpath: %s\n", implpath);
       scm_init_from_argv(argc, argv, 0L, 0, 0);
     
       retval = scm_top_level(implpath, user_main);
     
       final_scm(!0);
       return (int)INUM(retval);
     }
     
     -|
     dld_find_executable(./libtest): /home/jaffer/scm/libtest
     implpath: /home/jaffer/scm/Init5e7.scm
     This is libtest_init_user_scm
     hello world