Accessing Scheme data from C
============================

The C header file scheme48.h provides access to Scheme48 data structures.  The type s48_value is used for Scheme values.  When the type of a value is known, such as the integer returned by the Scheme procedure vector-length or the boolean returned by pair, the corresponding C function returns a C value of the appropriate type, not an s48_value.  Predicates return 1 for true and 0 for false.

 -- C macro: s48_value S48_FALSE
 -- C macro: s48_value S48_TRUE
 -- C macro: s48_value S48_NULL
 -- C macro: s48_value S48_UNSPECIFIC
 -- C macro: s48_value S48_EOF
 -- C macro: long S48_MAX_FIXNUM_VALUE
 -- C macro: long S48_MIN_FIXNUM_VALUE
     These C macros denote various Scheme constants.  S48_FALSE is the boolean false value, written in Scheme as #f. S48_TRUE is the boolean true value, or #t. S48_NULL is the empty list ().  S48_UNSPECIFIC is a miscellaneous value returned by procedures that have no meaningful return value (accessed in Scheme48 by the nullary procedure unspecific in the util structure).  S48_EOF is the end-of-file object (which the Scheme procedure eof-object? answers true for).  S48_MAX_FIXNUM_VALUE is the maximum integer as a long that can be represented in a Scheme48 fixnum. S48_MIN_FIXNUM_VALUE is similar, but the minimum integer.

 -- C macro: int S48_EXTRACT_BOOLEAN (s48_value BOOLEAN)
 -- C function: unsigned char s48_extract_char (s48_value CHAR)
 -- C function: char * s48_extract_string (s48_value STRING)
 -- C function: char * s48_extract_byte_vector (s48_value BYTEV)
 -- C function: long s48_extract_integer (s48_value INTEGER)
 -- C function: double s48_extract_double (s48_value DOUBLE)
 -- C macro: s48_value S48_ENTER_BOOLEAN (int BOOLEAN)
 -- C function: s48_value s48_enter_char (unsigned char CHAR)
 -- C function: s48_value s48_enter_string (char *STRING)
 -- C function: s48_value s48_enter_byte_vector (char *BYTEV, long LENGTH)
 -- C function: s48_value s48_enter_integer (long INTEGER)
 -- C function: s48_value s48_enter_double (double DOUBLE)
     These functions & macros convert values between their respective Scheme & C representations.

     S48_EXTRACT_BOOLEAN returns 0 if BOOLEAN is #f and 1 otherwise.  S48_ENTER_BOOLEAN returns the Scheme value #f if its argument is zero and #t otherwise.

     s48_extract_char & s48_enter_char convert between Scheme characters and C chars.

     s48_extract_string & s48_extract_byte_vector return pointers to the actual storage used by STRING or BYTEV. These pointers are valid only until the next garbage collection, however; see Interacting with the Scheme heap in C. s48_enter_string & s48_enter_byte_vector allocate space on the Scheme48 heap for the given strings or byte vectors. s48_enter_string copies the data starting from the pointer it is given up to the first ASCII NUL character, whereas s48_enter_byte_vector is given the number of bytes to copy into the Scheme heap.

     s48_extract_integer returns a C long that represents the Scheme integer as input.  If the Scheme integer is too large to be represented in a long, an exception is signalled.  (The Scheme integer may be a fixnum or a bignum.)  s48_enter_integer converts back to Scheme integers, and it will never signal an exception.

     s48_extract_double & s48_enter_double convert between Scheme & C double-precision floating point representations.

     Of these, s48_enter_string, s48_enter_byte_vector, s48_enter_integer, & s48_enter_double may cause the garbage collector to be invoked: the former two copy the string or byte vector onto the Scheme heap first, s48_enter_integer may need to allocate a bignum (since C longs are wider than Scheme48 fixnums), and floats are heap-allocated in Scheme48.

 -- C macro: int S48_TRUE_P (s48_value OBJECT)
 -- C macro: int S48_FALSE_P (s48_value OBJECT)
     S48_TRUE_P returns true if OBJECT is the true constant S48_TRUE and false if otherwise.  S48_FALSE_P returns true if its argument is the false constant S48_FALSE and false if otherwise.

 -- C macro: int S48_FIXNUM_P (s48_value OBJECT)
 -- C function: long s48_extract_fixnum (s48_value FIXNUM)
 -- C function: s48_value s48_enter_fixnum (long INTEGER)
     S48_FIXNUM_P is the C predicate for Scheme48 fixnums, delimited in range by S48_MIN_FIXNUM_VALUE & S48_MAX_FIXNUM_VALUE. s48_extract_fixnum returns the C long representation of the Scheme fixnum, and s48_enter_fixnum returns the Scheme fixnum representation of the C long.  These are identical to s48_extract_integer & s48_enter_integer, except that s48_extract_fixnum will never raise a range exception, but s48_enter_fixnum may, and s48_enter_fixnum will never return a bignum; this is due to the fact that C longs have a wider range than Scheme48 fixnums.

 -- C macro: int S48_EQ_P (s48_value A, s48_value B)
 -- C macro: int S48_CHAR_P (s48_value OBJECT)
 -- C macro: int S48_PAIR_P (s48_value OBJECT)
 -- C macro: int S48_VECTOR_P (s48_value OBJECT)
 -- C macro: int S48_STRING_P (s48_value OBJECT)
 -- C macro: int S48_SYMBOL_P (s48_value OBJECT)
 -- C macro: int S48_BYTE_VECTOR_P (s48_value OBJECT)
 -- C macro: s48_value S48_CAR (s48_value PAIR)
 -- C macro: s48_value S48_CDR (s48_value PAIR)
 -- C macro: void S48_SET_CAR (s48_value PAIR, s48_value OBJECT)
 -- C macro: void S48_SET_CDR (s48_value PAIR, s48_value OBJECT)
 -- C function (may GC): s48_value s48_cons (s48_value CAR, s48_value CDR)
 -- C function: s48_value s48_length (s48_value LIST)
 -- C macro: long S48_VECTOR_LENGTH (s48_value VECTOR)
 -- C macro: s48_value S48_VECTOR_REF (s48_value VECTOR, long INDEX)
 -- C macro: void S48_VECTOR_SET (s48_value VECTOR, long INDEX, s48_value OBJECT)
 -- C function (may GC): s48_value s48_make_vector (long LENGTH, s48_value FILL)
 -- C macro: long S48_STRING_LENGTH (s48_value STRING)
 -- C macro: char S48_STRING_REF (s48_value STRING, long INDEX)
 -- C macro: void S48_STRING_SET (s48_value STRING, long INDEX, char CHAR)
 -- C function (may GC): s48_value s48_make_string (long LENGTH, char FILL)
 -- C macro: s48_value S48_SYMBOL_TO_STRING (s48_value SYMBOL)
 -- C macro: long S48_BYTE_VECTOR_LENGTH (s48_value BYTEV)
 -- C macro: char S48_BYTE_VECTOR_REF (s48_value BYTEV, long INDEX)
 -- C macro: void S48_BYTE_VECTOR_SET (s48_value BYTEV, long INDEX, char BYTE)
 -- C function (may GC): s48_value s48_make_byte_vector (long LENGTH)
     C versions of miscellaneous Scheme procedures.  The names were derived from their Scheme counterparts by replacing hyphens with underscores, ? suffixes with _P, and dropping ! suffixes.

Calling Scheme procedures from C
================================

 -- C function: s48_value s48_call_scheme (s48_value PROC, long NARGS, ...)
     Calls the Scheme procedure PROC on NARGS arguments, which are passed as additional arguments to s48_call_scheme.  There may be at most twelve arguments.  The value returned by the Scheme procedure is returned to the C procedure.  Calling any Scheme procedure may potentially cause a garbage collection.

There are some complications that arise when mixing calls from C to Scheme with continuations & threads.  C supports only downward continuations (via longjmp()).  Scheme continuations that capture a portion of the C stack have to follow the same restriction. For example, suppose Scheme procedure s0 captures continuation a and then calls C function c0, which in turn calls Scheme procedure s1.  S1 can safely call the continuation a, because that is a downward use.  When a is called, Scheme48 will remove the portion of the C stack used by the call to c0.  On the other hand, if s1 captures a continuation, that continuation cannot be used from s0, because, by the time control returns to s0, the C stack used by s0 will no longer be valid.  An attempt to invoke an upward continuation that is closed over a portion of the C stack will raise an exception.

In Scheme48, threads are implemented using continuations, so the downward restriction applies to them as well.  An attempt to return from Scheme to C at a time when the appropriate C frame is not on the top of the C stack will cause the current thread to block until the frame is available.  For example, suppose thread t0 calls a C function that calls back to Scheme, at which point control switches to thread t1, which also calls C & then back to Scheme.  At this point, both t0 & t1 have active calls to C on the C stack, with t1's C frame above t0's.  If t0 attempts to return from Scheme to C, it will block, because the frame is not yet accessible.  Once t1 has returned to C and from there back to Scheme, t0 will be able to resume.  The return to Scheme is required because context switches can occur only while Scheme code is running.  T0 will also be able to resume if t1 uses a continuation to throw past its call out to C.