691 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			HTML
		
	
	
	
			
		
		
	
	
			691 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			HTML
		
	
	
	
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
 | |
| <HTML>
 | |
| <!-- HTML file produced from file: external.tex --
 | |
|  -- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
 | |
|  -- on Emacs 19.34.1, Tue Feb 23 18:21:44 1999 -->
 | |
| <HEAD>
 | |
| <TITLE>Mixing Scheme 48 and C</TITLE>
 | |
| 
 | |
| </HEAD><BODY>
 | |
| 
 | |
| 
 | |
|     <H1 ALIGN=CENTER>Using C code with Scheme 48</H1>
 | |
|     <H2 ALIGN=CENTER>Mike Sperber<BR><TT><FONT SIZE=-1>sperber@informatik.uni-tuebingen.de</FONT></TT><BR>Richard Kelsey<BR><TT><FONT SIZE=-1>kelsey@research.nj.nec.com</FONT></TT>
 | |
|   </H2>
 | |
|     <H3 ALIGN=CENTER>February 23, 1999</H3>
 | |
|     <H3 ALIGN=CENTER>Abstract</H3>
 | |
|   <BLOCKQUOTE>
 | |
| This document describes an interface for calling C functions
 | |
|  from Scheme, calling Scheme functions from C, and allocating
 | |
|  storage in the Scheme heap.
 | |
| These facilities are designed to link
 | |
|  existing C libraries into Scheme 48 in order to use them from Scheme.
 | |
| To this end, Scheme 48 manages stub functions in C that
 | |
|  negotiate between the calling conventions of Scheme and C and the
 | |
|  memory allocation policies of both worlds.
 | |
| No stub generator is available yet, but writing them is a straightforward task.
 | |
| </BLOCKQUOTE>
 | |
| <H1><A NAME="1">Available Facilities</A></H1>
 | |
| 
 | |
| <P>The following facilities are available for interfacing between
 | |
|  Scheme 48 and C:
 | |
| <UL><LI>Scheme code can call C functions.
 | |
| <LI>The external interface provides full introspection for all
 | |
|   Scheme objects.  External code may inspect, modify, and allocate
 | |
|   Scheme objects arbitrarily.
 | |
| <LI>External code may raise exceptions back to Scheme 48 to
 | |
|   signal errors.
 | |
| <LI>External code may call back into Scheme.  Scheme 48
 | |
|   correctly unrolls the process stack on non-local exits.
 | |
| <LI>External modules may register bindings of names to values with a 
 | |
|   central registry accessible from
 | |
|   Scheme.  Conversely, Scheme code can register shared
 | |
|   bindings for access by C code.
 | |
| </UL>
 | |
| This document has three parts: the first describes how bindings are
 | |
|  moved from Scheme to C and vice versa, the second tells how to call
 | |
|  C functions from Scheme, and the third covers the C interface
 | |
|  to Scheme objects, including calling Scheme procedures, using the
 | |
|  Scheme heap, and so forth.
 | |
| <H2><A NAME="2">Scheme structures</A></H2>
 | |
| <P>The structure <CODE>external-calls</CODE> has 
 | |
|  most of the Scheme functions described here.
 | |
| The others are in 
 | |
|  <CODE>dynamic-externals</CODE>, which has the functions for dynamic loading and
 | |
|  name lookup from
 | |
| 
 | |
| the section on <A HREF="#dynamic-externals">Dynamic Loading</A>,
 | |
|  and <CODE>shared-bindings</CODE>, which has the additional shared-binding functions
 | |
|  described in
 | |
| 
 | |
| the section on the <A HREF="#more-shared-bindings">complete shared-binding interface</A>.
 | |
| <H2><A NAME="3">C naming conventions</A></H2>
 | |
| <P>The names of all of Scheme 48's visible C bindings begin 
 | |
|  with `<CODE>s48_</CODE>' (for procedures and variables) or 
 | |
|  `<CODE>S48_</CODE>' (for macros).
 | |
| Whenever a C name is derived from a Scheme identifier, we
 | |
|  replace `<CODE>-</CODE>' with `<CODE>_</CODE>' and convert letters to lowercase
 | |
|  for procedures and uppercase for macros.
 | |
| A final `<CODE>?</CODE>'  converted to `<CODE>_p</CODE>' (`<CODE>_P</CODE>' in C macro names).
 | |
| A final `<CODE>!</CODE>' is dropped.
 | |
| Thus the C macro for Scheme's <CODE>pair?</CODE> is <CODE>S48_PAIR_P</CODE> and
 | |
|  the one for <CODE>set-car!</CODE> is <CODE>S48_SET_CAR</CODE>.
 | |
| Procedures and macros that do not check the types of their arguments
 | |
|  have `<CODE>unsafe</CODE>' in their names.
 | |
| <P>All of the C functions and macros described have prototypes or definitions
 | |
|  in the file <CODE>c/scheme48.h</CODE>.
 | |
| The C type for Scheme values is defined there to be <CODE>s48_value</CODE>.
 | |
| <H1><A NAME="4">Shared bindings</A></H1>
 | |
| 
 | |
| <P>Shared bindings are the means by which named values are shared between Scheme
 | |
|  code and C code.
 | |
| There are two separate tables of shared bindings, one for values defined in
 | |
|  Scheme and accessed from C and the other for values going the other way.
 | |
| Shared bindings actually bind names to cells, to allow a name to be looked
 | |
|  up before it has been assigned.
 | |
| This is necessary because C initialization code may be run before or after
 | |
|  the corresponding Scheme code, depending on whether the Scheme code is in
 | |
|  the resumed image or is run in the current session.
 | |
| <H2><A NAME="5">Exporting Scheme values to C</A></H2>
 | |
| <UL><LI><CODE>(define-exported-binding<I> name value</I>) -> <I>shared-binding</I></CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>s48_value s48_get_imported_binding(char *name)</CODE>
 | |
| <LI><CODE>s48_value S48_SHARED_BINDING_REF(s48_value shared_binding)</CODE>
 | |
| </UL>
 | |
| <P><CODE>Define-exported-binding</CODE> makes <CODE><I>value</I></CODE> available to C code
 | |
|  under as <CODE><I>name</I></CODE> which must be a <CODE><I>string</I></CODE>, creating a new shared
 | |
|  binding if necessary.
 | |
| The C function <CODE>s48_get_imported_binding</CODE> returns the shared binding
 | |
|  defined for <CODE>name</CODE>, again creating it if necessary.
 | |
| The C macro <CODE>S48_SHARED_BINDING_REF</CODE> dereferences a shared binding,
 | |
|  returning its current value.
 | |
| <H2><A NAME="6">Exporting C values to Scheme</A></H2>
 | |
| <UL><LI><CODE>void s48_define_exported_binding(char *name, s48_value value)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>(lookup-imported-binding<I> string</I>) -> <I>shared-binding</I></CODE>
 | |
| <LI><CODE>(shared-binding-ref<I> shared-binding</I>) -> <I>value</I></CODE>
 | |
| </UL>
 | |
| <P>These are used to define shared bindings from C and to access them
 | |
|  from Scheme.
 | |
| Again, if a name is looked up before it has been defined, a new binding is
 | |
|  created for it.
 | |
| <P>The common case of exporting a C function to Scheme can be done using
 | |
|  the macro <CODE>S48_EXPORT_FUNCTION(<EM>name</EM>)</CODE>.
 | |
| This expands into
 | |
| <P><CODE>s48_define_exported_binding("<CODE><I>name</I></CODE>", s48_enter_pointer(<CODE><I>name</I></CODE>))</CODE>
 | |
| <P>which boxes the function into a Scheme byte vector and then
 | |
|  exports it.
 | |
| Note that <CODE>s48_enter_pointer</CODE> allocates space in the Scheme heap
 | |
|  and might trigger a 
 | |
|  <A HREF="#gc">garbage collection</A>.
 | |
| <UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>(import-definition <CODE><I>name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>(import-definition <CODE><I>name c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
 | |
| </UL>
 | |
| These macros simplify importing definitions from C to Scheme.
 | |
| They expand into
 | |
| <P><CODE>(define <CODE><I>name</I></CODE> (lookup-imported-binding <CODE><I>c-name</I></CODE>))</CODE>
 | |
| <P>where <CODE><I>c-name</I></CODE> is as supplied for the second form.
 | |
| For the first form <CODE><I>c-name</I></CODE> is derived from <CODE><I>name</I></CODE> by
 | |
|  replacing `<CODE>-</CODE>' with `<CODE>_</CODE>' and converting letters to lowercase.
 | |
| For example, <CODE>(import-definition my-foo)</CODE> expands into
 | |
| <P><CODE>(define my-foo (lookup-imported-binding "my_foo"))</CODE>
 | |
| <H2><A NAME="more-shared-bindings">Complete shared binding interface</A></H2>
 | |
| 
 | |
| <P>There are a number of other Scheme functions related to shared bindings;
 | |
|  these are in the structure <CODE>shared-bindings</CODE>.
 | |
| <UL><LI><CODE>(shared-binding?<I> x</I>) -> <I>boolean</I></CODE>
 | |
| <LI><CODE>(shared-binding-name<I> shared-binding</I>) -> <I>string</I></CODE>
 | |
| <LI><CODE>(shared-binding-is-import?<I> shared-binding</I>) -> <I>boolean</I></CODE>
 | |
| <LI><CODE>(shared-binding-set!<I> shared-binding value</I>)</CODE>
 | |
| <LI><CODE>(define-imported-binding<I> string value</I>)</CODE>
 | |
| <LI><CODE>(lookup-exported-binding<I> string</I>)</CODE>
 | |
| <LI><CODE>(undefine-imported-binding<I> string</I>)</CODE>
 | |
| <LI><CODE>(undefine-exported-binding<I> string</I>)</CODE>
 | |
| </UL>
 | |
| <P><CODE>Shared-binding?</CODE> is the predicate for shared-bindings.
 | |
| <CODE>Shared-binding-name</CODE> returns the name of a binding.
 | |
| <CODE>Shared-binding-is-import?</CODE> is true if the binding was defined from C.
 | |
| <CODE>Shared-binding-set!</CODE> changes the value of a binding.
 | |
| <CODE>Define-imported-binding</CODE> and <CODE>lookup-exported-binding</CODE> are
 | |
|  Scheme versions of <CODE>s48_define_exported_binding</CODE>
 | |
|  and <CODE>s48_lookup_imported_binding</CODE>.
 | |
| The two <CODE>undefine-</CODE> procedures remove bindings from the two tables.
 | |
| They do nothing if the name is not found in the table.
 | |
| <P>The following C macros correspond to the Scheme functions above.
 | |
| <UL><LI><CODE>int       S48_SHARED_BINDING_P(x)</CODE>
 | |
| <LI><CODE>int       S48_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
 | |
| <LI><CODE>s48_value S48_SHARED_BINDING_NAME(s48_value s_b)</CODE>
 | |
| <LI><CODE>void      S48_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
 | |
| </UL>
 | |
| <H1><A NAME="8">Calling C Functions from Scheme</A></H1>
 | |
| 
 | |
| <P>There are three different ways to call C functions from Scheme, depending on
 | |
|  how the C function was obtained.
 | |
| <UL><LI><CODE>(call-imported-binding<I> binding arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
 | |
| <LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
 | |
| <LI><CODE>(call-external-value<I> value name arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
 | |
| </UL>
 | |
| Each of these applies its first argument, a C function, to the rest of
 | |
|  the arguments.
 | |
| For <CODE>call-imported-binding</CODE> the function argument must be an
 | |
|  imported binding.
 | |
| For <CODE>call-external</CODE> the function argument must be an external
 | |
|  bound in the current process
 | |
|  (see
 | |
| 
 | |
| the section on <A HREF="#dynamic-externals">Dynamic Loading</A>).
 | |
| For <CODE>call-external-value</CODE> <CODE><I>value</I></CODE> must be a byte vector
 | |
|  whose contents is a pointer to a C function and <CODE><I>name</I></CODE> should be
 | |
|  a string naming the function.
 | |
| The <CODE><I>name</I></CODE> argument is used only for printing error messages.
 | |
| <P>For all of these, the C function is passed the <CODE><I>arg<I><sub>i</sub></I></I></CODE> values
 | |
|  and the value returned is that returned by C procedure.
 | |
| Up to twelve arguments may be passed.
 | |
| There is no method supplied for returning multiple values to
 | |
|  Scheme from C (or vice versa) (mainly because C does not have multiple return
 | |
|  values).
 | |
| <P>Keyboard interrupts that occur during a call to a C function are ignored
 | |
|  until the function returns to Scheme (this is clearly a
 | |
|  problem; we are working on a solution).
 | |
| <UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...))</CODE></td> <td align=right>syntax</td></tr></table>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...) <CODE><I>c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
 | |
| </UL>
 | |
| These macros simplify importing functions from C.
 | |
| They define <CODE><I>name</I></CODE> to be a function with the given formals that
 | |
|  applies those formals to the corresponding C binding.
 | |
| <CODE><I>C-name</I></CODE>, if supplied, should be a string.
 | |
| These expand into
 | |
| <BLOCKQUOTE><PRE>
 | |
| (define temp (lookup-imported-binding <CODE><I>c-name</I></CODE>))
 | |
| (define <CODE><I>name</I></CODE>
 | |
|   (lambda (<CODE><I>formal</I></CODE> ...)
 | |
|     (external-apply temp <CODE><I>formal</I></CODE> ...)))
 | |
| </PRE></BLOCKQUOTE>
 | |
| <P>
 | |
| If <CODE><I>c-name</I></CODE> is not supplied, it is derived from <CODE><I>name</I></CODE> by converting
 | |
|  all letters to lowercase and replacing `<CODE>-</CODE>' with `<CODE>_</CODE>'.
 | |
| <H1><A NAME="9">Adding external modules to the <CODE>Makefile</CODE></A></H1>
 | |
| 
 | |
| <P>Getting access to C bindings from Scheme requires that the C code be
 | |
|  compiled an linked in with the Scheme 48 virtual machine and that the
 | |
|  relevent shared-bindings be created.
 | |
| The Scheme 48 makefile has rules for compiling and linking external code
 | |
|  and for specifying initialization functions that should be called on
 | |
|  startup.
 | |
| There are three Makefile variables that control which external modules are
 | |
|  included in the executable for the virutal machine (<CODE>scheme48vm</CODE>).
 | |
| <CODE>EXTERNAL_OBJECTS</CODE> lists the object files to be included in
 | |
|  <CODE>scheme48vm</CODE>,
 | |
| <CODE>EXTERNAL_FLAGS</CODE> is a list of <CODE>ld</CODE> flags to be used when
 | |
|  creating <CODE>scheme48vm</CODE>, and
 | |
|  <CODE>EXTERNAL_INITIALIZERS</CODE> is a list of C procedures to be called
 | |
|  on startup.
 | |
| The procedures listed in <CODE>EXTERNAL_INITIALIZERS</CODE> should take no
 | |
|  arguments and have a return type of <CODE>void</CODE>.
 | |
| After changing the definitions of any of these variables you should
 | |
|  do <CODE>make scheme48vm</CODE> to rebuild the virtual machine.
 | |
| <H1><A NAME="dynamic-externals">Dynamic Loading</A></H1>
 | |
| 
 | |
| <P>External code can be loaded into a running Scheme 48 process
 | |
|  and C object-file bindings can be dereferenced at runtime and
 | |
|  their values called
 | |
|  (although not all versions of Unix support all of this).
 | |
| The required Scheme functions are in the structure <CODE>dynamic-externals</CODE>.
 | |
| <UL><LI><CODE>(dynamic-load<I> string</I>)</CODE>
 | |
| </UL>
 | |
| <CODE>Dynamic-load</CODE> loads the named file into the current
 | |
|  process, raising an exception if the file cannot be found or if dynamic
 | |
|  loading is not supported by the operating system.
 | |
| The file must have been compiled and linked appropriately.
 | |
| For Linux, the following commands compile <CODE>foo.c</CODE> into a
 | |
|  file <CODE>foo.so</CODE> that can be loaded dynamically.
 | |
| <BLOCKQUOTE><PRE>
 | |
| % gcc -c -o foo.o foo.c
 | |
| % ld -shared -o foo.so foo.o
 | |
| </PRE></BLOCKQUOTE>
 | |
| <UL><LI><CODE>(get-external<I> string</I>) -> <I>external</I></CODE>
 | |
| <LI><CODE>(external?<I> x</I>) -> <I>boolean</I></CODE>
 | |
| <LI><CODE>(external-name<I> external</I>) -> <I>string</I></CODE>
 | |
| <LI><CODE>(external-value<I> external</I>) -> <I>byte-vector</I></CODE>
 | |
| </UL>
 | |
| These functions give access to values bound in the current process, and
 | |
|  are used for retrieving values from dynamically-loaded files.
 | |
| <CODE>Get-external</CODE> returns an <I>external</I> object that contains the
 | |
|  value of <CODE><I>name</I></CODE>, raising an exception if there is no such
 | |
|  value in the current process.
 | |
| <CODE>External?</CODE> is the predicate for externals, and
 | |
| <CODE>external-name</CODE> and <CODE>external-value</CODE> return the name and
 | |
|  value of an external.
 | |
| The value is returned as byte vector of length four (on 32-bit
 | |
|  architectures).
 | |
| The value is that which was extant when <CODE>get-external</CODE> was
 | |
|  called.
 | |
| The following two functions can be used to update the values of
 | |
|  externals.
 | |
| <UL><LI><CODE>(lookup-external<I> external</I>) -> <I>boolean</I></CODE>
 | |
| <LI><CODE>(lookup-all-externals<I></I>) -> <I>boolean</I></CODE>
 | |
| </UL>
 | |
| <CODE>Lookup-external</CODE> updates the value of <CODE><I>external</I></CODE> by looking its
 | |
|  name in the current process, returning <CODE>#t</CODE> if it is bound and <CODE>#f</CODE>
 | |
|  if it is not.
 | |
| <CODE>Lookup-all-externals</CODE> calls <CODE>lookup-external</CODE> on all extant
 | |
|  externals, returning <CODE>#f</CODE> any are unbound.
 | |
| <UL><LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
 | |
| </UL>
 | |
| An external whose value is a C procedure can be called using
 | |
|  <CODE>call-external</CODE>.
 | |
| See
 | |
| 
 | |
| the section on <A HREF="#8">calling C functions from Scheme</A>
 | |
| for more information.
 | |
| <P>In some versions of Unix retrieving a value from the current
 | |
|  process may require a non-trivial amount of computation.
 | |
| We recommend that a dynamically-loaded file contain a single initialization
 | |
|  procedure that creates shared bindings for the values exported by the file.
 | |
| <H1><A NAME="11">Compatibility</A></H1>
 | |
| <P>Scheme 48's old <CODE>external-call</CODE> function is still available in the structure
 | |
|  <CODE>externals</CODE>, which now also includes <CODE>external-name</CODE> and
 | |
|  <CODE>external-value</CODE>.
 | |
| The old <CODE>scheme48.h</CODE> file has been renamed <CODE>old-scheme48.h</CODE>.
 | |
| <H1><A NAME="12">Accessing Scheme data from C</A></H1>
 | |
| 
 | |
| <P>The C header file <CODE>scheme48.h</CODE> provides
 | |
|  access to Scheme 48 data structures
 | |
|  (for compatibility, the old <CODE>scheme48.h</CODE> file is available
 | |
|  as <CODE>old-scheme48.h</CODE>).
 | |
| The type <CODE>s48_value</CODE> is used for Scheme values.
 | |
| When the type of a value is known, such as the integer returned
 | |
|  by <CODE>vector-length</CODE> or the boolean returned by <CODE>pair?</CODE>,
 | |
|  the corresponding C procedure returns a C value of the appropriate
 | |
|  type, and not a <CODE>s48_value</CODE>.
 | |
| Predicates return <CODE>1</CODE> for true and <CODE>0</CODE> for false.
 | |
| <H2><A NAME="13">Constants</A></H2>
 | |
| 
 | |
| <P>The following macros denote Scheme constants:
 | |
| <DL><DT><B><CODE>S48_FALSE</CODE></B><DD> is <CODE>#f</CODE>.
 | |
| <DT><B><CODE>S48_TRUE</CODE></B><DD> is <CODE>#t</CODE>.
 | |
| <DT><B><CODE>S48_NULL</CODE></B><DD> is the empty list.
 | |
| <DT><B><CODE>S48_UNSPECIFIC</CODE></B><DD> is a value used for functions which have no
 | |
|   meaningful return value
 | |
|  (in Scheme this value returned by the nullary procedure <CODE>unspecific</CODE>
 | |
|  in the structure <CODE>util</CODE>).
 | |
| <DT><B><CODE>S48_EOF</CODE></B><DD> is the end-of-file object
 | |
|  (in Scheme this value is returned by the nullary procedure <CODE>eof-object</CODE>
 | |
|  in the structure <CODE>i/o-internal</CODE>).
 | |
| </DL>
 | |
| <H2><A NAME="14">Converting values</A></H2>
 | |
| <P>The following functions convert values between Scheme and C
 | |
|  representations.
 | |
| The `extract' ones convert from Scheme to C and the `enter's go the other
 | |
|  way.
 | |
| <UL><LI><CODE>unsigned char s48_extract_char(s48_value)</CODE>
 | |
| <LI><CODE>char *    s48_extract_string(s48_value)</CODE>
 | |
| <LI><CODE>long      s48_extract_integer(s48_value)</CODE>
 | |
| <LI><CODE>double    s48_extract_double(s48_value)</CODE>
 | |
| <LI><CODE>s48_value s48_enter_char(unsigned char)</CODE>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_enter_string(char *)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_enter_integer(long)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_enter_double(double)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| </UL>
 | |
| <P>The value returned by <CODE>s48_extract_string</CODE> points to the actual
 | |
|  storage used by the string; it is valid only until the next
 | |
|  <A HREF="#gc">garbage collection</A>.
 | |
| <P><CODE>s48_enter_integer()</CODE> needs to allocate storage when
 | |
|  its argument is too large to fit in a Scheme 48 fixnum.
 | |
| In cases where the number is known to fit within a fixnum (currently 30 bits
 | |
|  including the sign), the following procedures can be used.
 | |
| These have the disadvantage of only having a limited range, but
 | |
|  the advantage of never causing a garbage collection.
 | |
| <UL><LI><CODE>long      s48_extract_fixnum(s48_value)</CODE>
 | |
| <LI><CODE>s48_value s48_enter_fixnum(long)</CODE>
 | |
| <LI><CODE>long      S48_MAX_FIXNUM_VALUE</CODE>
 | |
| <LI><CODE>long      S48_MIN_FIXNUM_VALUE</CODE>
 | |
| </UL>
 | |
| <P>An error is signalled if <CODE>s48_extract_fixnum</CODE>'s argument
 | |
|  is not a fixnum or if the argument to <CODE>s48_enter_fixnum</CODE> is less than
 | |
|  <CODE>S48_MIN_FIXNUM_VALUE</CODE> or greater than <CODE>S48_MAX_FIXNUM_VALUE</CODE>
 | |
|  (<I>-2<sup>29</sup></I> and <I>2<sup>29</sup>-1</I> in the current system).
 | |
| <H2><A NAME="15">C versions of Scheme procedures</A></H2>
 | |
| <P>The following macros and procedures are C versions of Scheme procedures.
 | |
| The names were derived by replacing `<CODE>-</CODE>' with `<CODE>_</CODE>',
 | |
|  `<CODE>?</CODE>' with `<CODE>p</CODE>', and dropping `<CODE>!</CODE>.
 | |
| <UL><LI><CODE>int       S48_EQ_P(s48_value)</CODE>
 | |
| <LI><CODE>int       S48_CHAR_P(s48_value)</CODE>
 | |
| <LI><CODE>int       S48_INTEGER_P(s48_value)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>int       S48_PAIR_P(s48_value)</CODE>
 | |
| <LI><CODE>s48_value S48_CAR(s48_value)</CODE>
 | |
| <LI><CODE>s48_value S48_CDR(s48_value)</CODE>
 | |
| <LI><CODE>void      S48_SET_CAR(s48_value, s48_value)</CODE>
 | |
| <LI><CODE>void      S48_SET_CDR(s48_value, s48_value)</CODE>
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_cons(s48_value, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| <LI><CODE>long      s48_length(s48_value)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>int       S48_VECTOR_P(s48_value)</CODE> 
 | |
| <LI><CODE>long      S48_VECTOR_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value S48_VECTOR_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_VECTOR_SET(s48_value, long, s48_value)</CODE> 
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_make_vector(long, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| </UL>
 | |
| <UL><LI><CODE>int       S48_STRING_P(s48_value)</CODE> 
 | |
| <LI><CODE>long      S48_STRING_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>char      S48_STRING_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_STRING_SET(s48_value, long, char)</CODE> 
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_make_string(long, char)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| </UL>
 | |
| <UL><LI><CODE>int       S48_SYMBOL_P(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value s48_SYMBOL_TO_STRING(s48_value)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>int       S48_BYTE_VECTOR_P(s48_value)</CODE> 
 | |
| <LI><CODE>long      S48_BYTE_VECTOR_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>char      S48_BYTE_VECTOR_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_BYTE_VECTOR_SET(s48_value, long, int)</CODE> 
 | |
| <LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value s48_make_byte_vector(long, int)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| </UL>
 | |
| <H1><A NAME="16">Calling Scheme functions from C</A></H1>
 | |
| 
 | |
| <P>External code that has been called from Scheme can call back to Scheme
 | |
|  procedures using the following function.
 | |
| <UL><LI><CODE>scheme_value s48_call_scheme(s48_value proc, long nargs, ...)</CODE>
 | |
| </UL>
 | |
| This calls the Scheme procedure <CODE>proc</CODE> on <CODE>nargs</CODE>
 | |
|  arguments, which are passed as additional arguments to <CODE>s48_call_scheme</CODE>.
 | |
| There may be at most ten arguments.
 | |
| The value returned by the Scheme procedure is returned by the C procedure.
 | |
| Invoking any Scheme procedure may potentially cause a garbage collection.
 | |
| <P>There are some complications that occur when mixing calls from C to Scheme
 | |
|  with continuations and threads.
 | |
| C only supports downward continuations (via <CODE>longjmp()</CODE>).
 | |
| Scheme continuations that capture a portion of the C stack have to follow the
 | |
|  same restriction.
 | |
| For example, suppose Scheme procedure <CODE>s0</CODE> captures continuation <CODE>a</CODE>
 | |
|  and then calls C procedure <CODE>c0</CODE>, which in turn calls Scheme procedure
 | |
|  <CODE>s1</CODE>.
 | |
| Procedure <CODE>s1</CODE> can safely call the continuation <CODE>a</CODE>, because that
 | |
|  is a downward use.
 | |
| When <CODE>a</CODE> is called Scheme 48 will remove the portion of the C stack used
 | |
|  by the call to <CODE>c0</CODE>.
 | |
| On the other hand, if <CODE>s1</CODE> captures a continuation, that continuation
 | |
|  cannot be used from <CODE>s0</CODE>, because by the time control returns to
 | |
|  <CODE>s0</CODE> the C stack used by <CODE>c0</CODE> 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.
 | |
| <P>In Scheme 48 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 top of the C stack will cause the current thread to
 | |
|  block until the frame is available.
 | |
| For example, suppose thread <CODE>t0</CODE> calls a C procedure which calls back
 | |
|  to Scheme, at which point control switches to thread <CODE>t1</CODE>, which also
 | |
|  calls C and then back to Scheme.
 | |
| At this point both <CODE>t0</CODE> and <CODE>t1</CODE> have active calls to C on the
 | |
|  C stack, with <CODE>t1</CODE>'s C frame above <CODE>t0</CODE>'s.
 | |
| If thread <CODE>t0</CODE> attempts to return from Scheme to C it will block,
 | |
|  as its frame is not accessable.
 | |
| Once <CODE>t1</CODE> has returned to C and from there to Scheme, <CODE>t0</CODE> will
 | |
|  be able to resume.
 | |
| The return to Scheme is required because context switches can only occur while
 | |
|  C code is running.
 | |
| <CODE>T0</CODE> will also be able to resume if <CODE>t1</CODE> uses a continuation to
 | |
|  throw past its call to C.
 | |
| <H1><A NAME="gc">Interacting with the Scheme Heap</A></H1>
 | |
| 
 | |
| 
 | |
| <P>Scheme 48 uses a copying, precise garbage collector.
 | |
| Any procedure that allocates objects within the Scheme 48 heap may trigger
 | |
|  a garbage collection.
 | |
| Variables bound to values in the Scheme 48 heap need to be registered with
 | |
|  the garbage collector so that the value will be retained and so that the
 | |
|  variables will be updated if the garbage collector moves the object.
 | |
| The garbage collector has no facility for updating pointers to the interiors
 | |
|  of objects, so such pointers, for example the ones returned by
 | |
|  <CODE>EXTRACT_STRING</CODE>, will likely become invalid when a garbage collection
 | |
|  occurs.
 | |
| <H2><A NAME="18">Registering Objects with the GC</A></H2>
 | |
| 
 | |
| <P>A set of macros are used to manage the registration of local variables with the
 | |
|  garbage collector.
 | |
| <UL><LI><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
 | |
| <LI><CODE>void S48_GC_PROTECT_<I>n</I>(s48_value<I><sub>1</sub></I>, <I>...</I>, s48_value<I><sub>n</sub></I>)</CODE>
 | |
| <LI><CODE>void S48_GC_UNPROTECT()</CODE>
 | |
| </UL>
 | |
| <P><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>, where  <I>1 <= n <= 9</I>, allocates
 | |
|  storage for registering <I>n</I> variables.
 | |
| At most one use of <CODE>S48_DECLARE_GC_PROTECT</CODE> may occur in a block.
 | |
| <CODE>S48_GC_PROTECT_<I>n</I>(<I>v<sub>1</sub></I>, <I>...</I>, <I>v<sub>n</sub></I>)</CODE> registers the
 | |
|  <I>n</I> variables (l-values) with the garbage collector.
 | |
| It must be within scope of a <CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
 | |
|  and be before any code which can cause a GC.
 | |
| <CODE>S48_GC_UNPROTECT</CODE> removes the block's protected variables from
 | |
|  the garbage collectors list.
 | |
| It must be called at the end of the block after 
 | |
|   any code which may cause a garbage collection.
 | |
| Omitting any of the three may cause serious and
 | |
|  hard-to-debug problems.
 | |
| Notably, the garbage collector may relocate an object and
 | |
|  invalidate <CODE>s48_value</CODE> variables which are not protected.
 | |
| <P>A <CODE>gc-protection-mismatch</CODE> exception is raised if, when a C
 | |
|  procedure returns to Scheme, the calls
 | |
|  to <CODE>S48_GC_PROTECT()</CODE> have not been matched by an equal number of
 | |
|  calls to <CODE>S48_GC_UNPROTECT()</CODE>.
 | |
| <P>Global variables may also be registered with the garbage collector.
 | |
| <UL><LI><CODE>void S48_GC_PROTECT_GLOBAL(<CODE><I>value</I></CODE>)</CODE>
 | |
| </UL>
 | |
| <P><CODE>S48_GC_PROTECT_GLOBAL</CODE> permanently registers the
 | |
|   variable <CODE><I>value</I></CODE> (an l-value) with the garbage collector.
 | |
| There is no way to unregister the variable.
 | |
| <H2><A NAME="19">Keeping C data structures in the Scheme heap</A></H2>
 | |
| 
 | |
| <P>C data structures can be kept in the Scheme heap by embedding them
 | |
|  inside byte vectors.
 | |
| The following macros can be used to create and access embedded C objects.
 | |
| <UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value S48_MAKE_VALUE(type)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| <LI><CODE>type      S48_EXTRACT_VALUE(s48_value, type)</CODE>
 | |
| <LI><CODE>type *    S48_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
 | |
| <LI><CODE>void      S48_SET_VALUE(s48_value, type, value)</CODE>
 | |
| </UL>
 | |
| <P><CODE>S48_MAKE_VALUE</CODE> makes a byte vector large enough to hold an object
 | |
|  whose type is <CODE><I>type</I></CODE>.
 | |
| <CODE>S48_EXTRACT_VALUE</CODE> returns the contents of a byte vector cast to
 | |
|  <CODE><I>type</I></CODE>, and <CODE>S48_EXTRACT_VALUE_POINTER</CODE> returns a pointer
 | |
|  to the contents of the byte vector.
 | |
| The value returned by <CODE>S48_EXTRACT_VALUE_POINTER</CODE> is valid only until
 | |
|  the next <A HREF="#gc">garbage collection</A>.
 | |
| <P><CODE>S48_SET_VALUE</CODE> stores <CODE>value</CODE> into the byte vector.
 | |
| <H2><A NAME="20">C code and heap images</A></H2>
 | |
| 
 | |
| <P>Scheme 48 uses dumped heap images to restore a previous system state.
 | |
| The Scheme 48 heap is written into a file in a machine-independent and
 | |
|  operating-system-independent format.
 | |
| The procedures described above may be used to create objects in the
 | |
|  Scheme heap that contain information specific to the current
 | |
|  machine, operating system, or process.
 | |
| A heap image containing such objects may not work correctly on
 | |
|  when resumed.
 | |
| <P>To address this problem, a record type may be given a `resumer'
 | |
|  procedure.
 | |
| On startup, the resumer procedure for a type is applied to each record of
 | |
|  that type in the image being restarted.
 | |
| This procedure can update the record in a manner appropriate to
 | |
|  the machine, operating system, or process used to resume the
 | |
|  image.
 | |
| <UL><LI><CODE>(define-record-resumer<I> record-type procedure</I>)</CODE>
 | |
| </UL>
 | |
| <P><CODE>Define-record-resumer</CODE> defines <CODE><I>procedure</I></CODE>,
 | |
|  which should accept one argument, to be the resumer for
 | |
|  <I>record-type</I>.
 | |
| The order in which resumer procedures are called is not specified.
 | |
| <P>The <CODE><I>procedure</I></CODE> argument to <CODE>define-record-resumer</CODE> may
 | |
|  be <CODE>#f</CODE>, in which case records of the given type are
 | |
|  not written out in heap images.
 | |
| When writing a heap image any reference to such a record is replaced by
 | |
|  the value of the record's first field, and an exception is raised
 | |
|  after the image is written.
 | |
| <H1><A NAME="21">Using Scheme records in C code</A></H1>
 | |
| <P>External modules can create records and access their slots
 | |
|  positionally.
 | |
| <UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
 | |
| <tr> <td><CODE>s48_value S48_MAKE_RECORD(s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
 | |
| <LI><CODE>int       S48_RECORD_P(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value S48_RECORD_TYPE(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value S48_RECORD_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_RECORD_SET(s48_value, long, s48_value)</CODE> 
 | |
| </UL>
 | |
| The argument to <CODE>S48_MAKE_RECORD</CODE> should be a shared binding
 | |
|  whose value is a record type.
 | |
| In C the fields of Scheme records are only accessible via offsets,
 | |
|  with the first field having offset zero, the second offset one, and
 | |
|  so forth.
 | |
| If the order of the fields is changed in the Scheme definition of the
 | |
|  record type the C code must be updated as well.
 | |
| <P>For example, given the following record-type definition
 | |
| <BLOCKQUOTE><PRE>
 | |
| (define-record-type thing :thing
 | |
|   (make-thing a b)
 | |
|   thing?
 | |
|   (a thing-a)
 | |
|   (b thing-b))
 | |
| </PRE></BLOCKQUOTE>
 | |
| the identifier <CODE>:thing</CODE> is bound to the record type and can
 | |
|  be exported to C:
 | |
| <BLOCKQUOTE><PRE>
 | |
| (define-exported-binding "thing-record-type" :thing)
 | |
| </PRE></BLOCKQUOTE>
 | |
| <CODE>Thing</CODE> records can then be made in C:
 | |
| <BLOCKQUOTE><PRE>
 | |
| static scheme_value thing_record_type_binding = SCHFALSE;
 | |
| 
 | |
| void initialize_things(void)
 | |
| {
 | |
|   S48_GC_PROTECT_GLOBAL(thing_record_type_binding);
 | |
|   thing_record_type_binding =
 | |
|      s48_get_imported_binding("thing-record-type");
 | |
| }
 | |
| 
 | |
| scheme_value make_thing(scheme_value a, scheme_value b)
 | |
| {
 | |
|   s48_value thing;
 | |
|   s48_DECLARE_GC_PROTECT(2);
 | |
| 
 | |
|   S48_GC_PROTECT_2(a, b);
 | |
| 
 | |
|   thing = s48_make_record(thing_record_type_binding);
 | |
|   S48_RECORD_SET(thing, 0, a);
 | |
|   S48_RECORD_SET(thing, 1, b);
 | |
| 
 | |
|   S48_GC_UNPROTECT();
 | |
| 
 | |
|   return thing;
 | |
| }
 | |
| </PRE></BLOCKQUOTE>
 | |
| Note that the variables <CODE>a</CODE> and <CODE>b</CODE> must be protected
 | |
|  against the possibility of a garbage collection occuring during
 | |
|  the call to <CODE>s48_make_record()</CODE>.
 | |
| <H1><A NAME="22">Raising exceptions from external code</A></H1>
 | |
| 
 | |
| <P>The following macros explicitly raise certain errors, immediately
 | |
|  returning to Scheme 48.
 | |
| Raising an exception performs all
 | |
|  necessary clean-up actions to properly return to Scheme 48, including
 | |
|  adjusting the stack of protected variables.
 | |
| <UL><LI><CODE>s48_raise_scheme_exception(int type, int nargs, ...)</CODE>
 | |
| </UL>
 | |
| <P><CODE>s48_raise_scheme_exception</CODE> is the base procedure for
 | |
|  raising exceptions.
 | |
| <CODE>type</CODE> is the type of exception, and should be one of the
 | |
|  <CODE>S48_EXCEPTION_</CODE>...constants defined in <CODE>scheme48arch.h</CODE>.
 | |
| <CODE>nargs</CODE> is the number of additional values to be included in the
 | |
|  exception; these follow the <CODE>nargs</CODE> argument and should all have
 | |
|  type <CODE>s48_value</CODE>.
 | |
| <CODE>s48_raise_scheme_exception</CODE> never returns.
 | |
| <P>The following procedures are available for raising particular
 | |
|  types of exceptions.
 | |
| Like <CODE>s48_raise_scheme_exception</CODE> these never return.
 | |
| <UL><LI><CODE>s48_raise_argument_type_error(scheme_value)</CODE>
 | |
| <LI><CODE>s48_raise_argument_number_error(int nargs, int min, int max)</CODE>
 | |
| <LI><CODE>s48_raise_index_range_error(long value, long min, long max)</CODE>
 | |
| <LI><CODE>s48_raise_closed_channel_error()</CODE>
 | |
| <LI><CODE>s48_raise_os_error(int errno)</CODE>
 | |
| <LI><CODE>s48_raise_out_of_memory_error()</CODE>
 | |
| </UL>
 | |
| <P>An argument type error indicates that the given value is of the wrong
 | |
|  type.
 | |
| An argument number error is raised when the number of arguments, <CODE>nargs</CODE>,
 | |
|  should be, but isn't, between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
 | |
| Similarly, and index range error is raised when <CODE>value</CODE> is not between
 | |
|  between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
 | |
| <P>The following macros raise argument type errors if their argument does not
 | |
|  have the required type.
 | |
| <UL><LI><CODE>void S48_CHECK_SYMBOL(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_PAIR(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_STRING(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_INTEGER(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_CHANNEL(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_BYTE_VECTOR(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_RECORD(s48_value)</CODE>
 | |
| <LI><CODE>void S48_CHECK_SHARED_BINDING(s48_value)</CODE>
 | |
| </UL>
 | |
| <H1><A NAME="23">Unsafe functions and macros</A></H1>
 | |
| <P>All of the C procedures and macros described above check that their
 | |
|  arguments have the appropriate types and that indexes are in range.
 | |
| The following procedures and macros are identical to those described
 | |
|  above, except that they do not perform type and range checks.
 | |
| They are provided for the purpose of writing more efficient code;
 | |
|  their general use is not recommended.
 | |
| <UL><LI><CODE>char      S48_UNSAFE_EXTRACT_CHAR(s48_value)</CODE>
 | |
| <LI><CODE>char *    S48_UNSAFE_EXTRACT_STRING(s48_value)</CODE>
 | |
| <LI><CODE>long      S48_UNSAFE_EXTRACT_INTEGER(s48_value)</CODE>
 | |
| <LI><CODE>long      S48_UNSAFE_EXTRACT_DOUBLE(s48_value)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>long      S48_UNSAFE_EXTRACT_FIXNUM(s48_value)</CODE>
 | |
| <LI><CODE>s48_value S48_UNSAFE_ENTER_FIXNUM(long)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>s48_value S48_UNSAFE_CAR(s48_value)</CODE>
 | |
| <LI><CODE>s48_value S48_UNSAFE_CDR(s48_value)</CODE>
 | |
| <LI><CODE>void      S48_UNSAFE_SET_CAR(s48_value, s48_value)</CODE>
 | |
| <LI><CODE>void      S48_UNSAFE_SET_CDR(s48_value, s48_value)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>long      S48_UNSAFE_VECTOR_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value S48_UNSAFE_VECTOR_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_UNSAFE_VECTOR_SET(s48_value, long, s48_value)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>long      S48_UNSAFE_STRING_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>char      S48_UNSAFE_STRING_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_UNSAFE_STRING_SET(s48_value, long, char)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>s48_value S48_UNSAFE_SYMBOL_TO_STRING(s48_value)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>long      S48_UNSAFE_BYTE_VECTOR_LENGTH(s48_value)</CODE> 
 | |
| <LI><CODE>char      S48_UNSAFE_BYTE_VECTOR_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_UNSAFE_BYTE_VECTOR_SET(s48_value, long, int)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_REF(s48_value s_b)</CODE>
 | |
| <LI><CODE>int       S48_UNSAFE_SHARED_BINDING_P(x)</CODE>
 | |
| <LI><CODE>int       S48_UNSAFE_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
 | |
| <LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_NAME(s48_value s_b)</CODE>
 | |
| <LI><CODE>void      S48_UNSAFE_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
 | |
| </UL>
 | |
| <UL><LI><CODE>s48_value S48_UNSAFE_RECORD_TYPE(s48_value)</CODE> 
 | |
| <LI><CODE>s48_value S48_UNSAFE_RECORD_REF(s48_value, long)</CODE> 
 | |
| <LI><CODE>void      S48_UNSAFE_RECORD_SET(s48_value, long, s48_value)</CODE> 
 | |
| </UL>
 | |
| <UL><LI><CODE>type      S48_UNSAFE_EXTRACT_VALUE(s48_value, type)</CODE>
 | |
| <LI><CODE>type *    S48_UNSAFE_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
 | |
| <LI><CODE>void      S48_UNSAFE_SET_VALUE(s48_value, type, value)</CODE>
 | |
| </UL>
 | |
| <HR ><ADDRESS><a href="http://www-pu.informatik.uni-tuebingen.de/users/sperber/">Mike
 | |
|   Sperber</a>, <a href="http://www.neci.nj.nec.com/homepages/kelsey/">Richard Kelsey</a></ADDRESS><BR>
 | |
| </BODY></HTML>
 |