Relationship between Scheme and C functions
*******************************************

Scheme procedures marked "primitive functions" have a regular interface when calling from C, reflected in two areas: the name of a C function, and the convention for passing non-required arguments to this function.

Transforming Scheme name to C name
==================================

Normally, the name of a C function can be derived given its Scheme name, using some simple textual transformations:

  * Replace - (hyphen) with _ (underscore).

  * Replace ? (question mark) with "_p".

  * Replace ! (exclamation point) with "_x".

  * Replace internal -> with "_to_".

  * Replace <= (less than or equal) with "_leq".

  * Replace >= (greater than or equal) with "_geq".

  * Replace < (less than) with "_less".

  * Replace > (greater than) with "_gr".

  * Replace @ with "at". [Omit?]

  * Prefix with "gh_" (or "scm_" if you are ignoring the gh interface).

  * [Anything else?  --ttn, 2000/01/16 15:17:28]

Here is an Emacs Lisp command that prompts for a Scheme function name and inserts the corresponding C function name into the buffer.

     (defun insert-scheme-to-C (name &optional use-gh)
       "Transforms Scheme NAME, a string, to its C counterpart, and inserts it.
     Prefix arg non-nil means use \"gh_\" prefix, otherwise use \"scm_\" prefix."
       (interactive "sScheme name: \nP")
       (let ((transforms '(("-"  . "_")
                           ("?"  . "_p")
                           ("!"  . "_x")
                           ("->" . "_to_")
                           ("<=" . "_leq")
                           (">=" . "_geq")
                           ("<"  . "_less")
                           (">"  . "_gr")
                           ("  . "at"))))
         (while transforms
           (let ((trigger (concat "\\(.*\\)"
                                  (regexp-quote (caar transforms))
                                  "\\(.*\\)"))
                 (sub (cdar transforms))
                 (m nil))
             (while (setq m (string-match trigger name))
               (setq name (concat (match-string 1 name)
                                  sub
                                  (match-string 2 name)))))
           (setq transforms (cdr transforms))))
       (insert (if use-gh "gh_" "scm_") name))

Structuring argument lists for C functions
==========================================

The C function's arguments will be all of the Scheme procedure's argumements, both required and optional; if the Scheme procedure takes a ``rest'' argument, that will be a final argument to the C function.  The C function's arguments, as well as its return type, will be SCM.

Using and Extending Ports in C
******************************

C Port Interface
================

This section describes how to use Scheme ports from C.

Port basics
-----------

There are two main data structures.  A port type object (ptob) is of type scm_ptob_descriptor.  A port instance is of type scm_port.  Given an SCM variable which points to a port, the corresponding C port object can be obtained using the SCM_PTAB_ENTRY macro.  The ptob can be obtained by using SCM_PTOBNUM to give an index into the scm_ptobs global array.

Port buffers
------------

An input port always has a read buffer and an output port always has a write buffer.  However the size of these buffers is not guaranteed to be more than one byte (e.g., the shortbuf field in scm_port which is used when no other buffer is allocated).  The way in which the buffers are allocated depends on the implementation of the ptob.  For example in the case of an fport, buffers may be allocated with malloc when the port is created, but in the case of an strport the underlying string is used as the buffer.

The rw_random flag
------------------

Special treatment is required for ports which can be seeked at random. Before various operations, such as seeking the port or changing from input to output on a bidirectional port or vice versa, the port implemention must be given a chance to update its state.  The write buffer is updated by calling the flush ptob procedure and the input buffer is updated by calling the end_input ptob procedure. In the case of an fport, flush causes buffered output to be written to the file descriptor, while end_input causes the descriptor position to be adjusted to account for buffered input which was never read.

The special treatment must be performed if the rw_random flag in the port is non-zero.

The rw_active variable
----------------------

The rw_active variable in the port is only used if rw_random is set.  It's defined as an enum with the following values:

SCM_PORT_READ
     the read buffer may have unread data.

SCM_PORT_WRITE
     the write buffer may have unwritten data.

SCM_PORT_NEITHER
     neither the write nor the read buffer has data.

Reading from a port.
--------------------

To read from a port, it's possible to either call existing libguile procedures such as scm_getc and scm_read_line or to read data from the read buffer directly.  Reading from the buffer involves the following steps:

 1. Flush output on the port, if rw_active is SCM_PORT_WRITE.

 2. Fill the read buffer, if it's empty, using scm_fill_input.

 3. Read the data from the buffer and update the read position in the buffer.  Steps 2) and 3) may be repeated as many times as required.

 4. Set rw_active to SCM_PORT_READ if rw_random is set.

 5. update the port's line and column counts.

Writing to a port.
------------------

To write data to a port, calling scm_lfwrite should be sufficient for most purposes.  This takes care of the following steps:

 1. End input on the port, if rw_active is SCM_PORT_READ.

 2. Pass the data to the ptob implementation using the write ptob procedure.  The advantage of using the ptob write instead of manipulating the write buffer directly is that it allows the data to be written in one operation even if the port is using the single-byte shortbuf.

 3. Set rw_active to SCM_PORT_WRITE if rw_random is set.

Port Implementation
===================

This section describes how to implement a new port type in C.

As described in the previous section, a port type object (ptob) is a structure of type scm_ptob_descriptor.  A ptob is created by calling scm_make_port_type.

All of the elements of the ptob, apart from name, are procedures which collectively implement the port behaviour.  Creating a new port type mostly involves writing these procedures.

scm_make_port_type initialises three elements of the structure (name, fill_input and write) from its arguments. The remaining elements are initialised with default values and can be set later if required.

name
     A pointer to a NUL terminated string: the name of the port type.  This is the only element of scm_ptob_descriptor which is not a procedure.  Set via the first argument to scm_make_port_type.

mark
     Called during garbage collection to mark any SCM objects that a port object may contain.  It doesn't need to be set unless the port has SCM components.  Set using scm_set_port_mark.

free
     Called when the port is collected during gc.  It should free any resources used by the port. Set using scm_set_port_free.

print
     Called when write is called on the port object, to print a port description.  e.g., for an fport it may produce something like: #<input: /etc/passwd 3>.   Set using scm_set_port_print.

equalp
     Not used at present.  Set using scm_set_port_equalp.

close
     Called when the port is closed, unless it was collected during gc.  It should free any resources used by the port. Set using scm_set_port_close.

write
     Accept data which is to be written using the port.  The port implementation may choose to buffer the data instead of processing it directly. Set via the third argument to scm_make_port_type.

flush
     Complete the processing of buffered output data.  Reset the value of rw_active to SCM_PORT_NEITHER. Set using scm_set_port_flush.

end_input
     Perform any synchronisation required when switching from input to output on the port.  Reset the value of rw_active to SCM_PORT_NEITHER. Set using scm_set_port_end_input.

fill_input
     Read new data into the read buffer and return the first character.  It can be assumed that the read buffer is empty when this procedure is called. Set via the second argument to scm_make_port_type.

input_waiting
     Return a lower bound on the number of bytes that could be read from the port without blocking.  It can be assumed that the current state of rw_active is SCM_PORT_NEITHER. Set using scm_set_port_input_waiting.

seek
     Set the current position of the port.  The procedure can not make any assumptions about the value of rw_active when it's called.  It can reset the buffers first if desired by using something like:

                if (pt->rw_active == SCM_PORT_READ)
          	scm_end_input (object);
                else if (pt->rw_active == SCM_PORT_WRITE)
          	ptob->flush (object);

     However note that this will have the side effect of discarding any data in the unread-char buffer, in addition to any side effects from the end_input and flush ptob procedures.  This is undesirable when seek is called to measure the current position of the port, i.e., (seek p 0 SEEK_CUR).  The libguile fport and string port implementations take care to avoid this problem.

     The procedure is set using scm_set_port_seek.

truncate
     Truncate the port data to be specified length.  It can be assumed that the current state of rw_active is SCM_PORT_NEITHER. Set using scm_set_port_truncate.

How to Handle Errors in C Code
******************************

Error handling is based on catch and throw.  Errors are always thrown with a key and four arguments:

  * key: a symbol which indicates the type of error.  The symbols used by libguile are listed below.

  * subr: the name of the procedure from which the error is thrown, or #f.

  * message: a string (possibly language and system dependent) describing the error.  The tokens %s and %S can be embedded within the message: they will be replaced with members of the args list when the message is printed.  %s indicates an argument printed using "display", while %S indicates an argument printed using "write".  message can also be #f, to allow it to be derived from the key by the error handler (may be useful if the key is to be thrown from both C and Scheme).

  * args: a list of arguments to be used to expand %s and %S tokens in message. Can also be #f if no arguments are required.

  * rest: a list of any additional objects required. e.g., when the key is 'system-error, this contains the C errno value.  Can also be #f if no additional objects are required.

In addition to catch and throw, the following Scheme facilities are available:

  * (scm-error key subr message args rest): throw an error, with arguments as described above.

  * (error msg arg ...)  Throw an error using the key 'misc-error.  The error message is created by displaying msg and writing the args.

The following are the error keys defined by libguile and the situations in which they are used:

  * error-signal: thrown after receiving an unhandled fatal signal such as SIGSEV, SIGBUS, SIGFPE etc.  The "rest" argument in the throw contains the coded signal number (at present this is not the same as the usual Unix signal number).

  * system-error: thrown after the operating system indicates an error condition.  The "rest" argument in the throw contains the errno value.

  * numerical-overflow: numerical overflow.

  * out-of-range: the arguments to a procedure do not fall within the accepted domain.

  * wrong-type-arg: an argument to a procedure has the wrong thpe.

  * wrong-number-of-args: a procedure was called with the wrong number of arguments.

  * memory-allocation-error: memory allocation error.

  * stack-overflow: stack overflow error.

  * regex-error: errors generated by the regular expression library.

  * misc-error: other errors.

C Support
=========

SCM scm_error (SCM key, char *subr, char *message, SCM args, SCM rest)

Throws an error, after converting the char * arguments to Scheme strings. subr is the Scheme name of the procedure, NULL is converted to #f. Likewise a NULL message is converted to #f.

The following procedures invoke scm_error with various error keys and arguments.  The first three call scm_error with the system-error key and automatically supply errno in the "rest" argument:  scm_syserror generates messages using strerror,  scm_sysmissing is used when facilities are not available.  Care should be taken that the errno value is not reset (e.g. due to an interrupt).

  * void scm_syserror (char *subr);

  * void scm_syserror_msg (char *subr, char *message, SCM args);

  * void scm_sysmissing (char *subr);

  * void scm_num_overflow (char *subr);

  * void scm_out_of_range (char *subr, SCM bad_value);

  * void scm_wrong_num_args (SCM proc);

  * void scm_wrong_type_arg (char *subr, int pos, SCM bad_value);

  * void scm_memory_error (char *subr);

  * static void scm_regex_error (char *subr, int code); (only used in rgx.c).

Exception handlers can also be installed from C, using scm_internal_catch, scm_lazy_catch, or scm_stack_catch from libguile/throw.c.  These have not yet been documented, however the source contains some useful comments.