ID: $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $
[NOTE! This FAQ is being overhauled. Please send comments about it directly to ttn@gnu.org.]
Guile is an implementation of the Scheme programming language built to
be used as an extension language. The interesting thing about this
Scheme implementation is that it is the official extension language of
the GNU project, which means that it is likely that guile
will be
used in an increasing number of GNU programs.
This document aims to help the programmer who is trying to get started
with guile. It is not necessary to know a lot about Scheme or
guile
in particular, however it is assumed that the reader knows
a bit about writing and building C programs. Note that this document
does not pretend to be a definitive reference document for guile; use
the guile reference manual for that. Instead it is supposed to be a
pointer to more detailed information about guile
, a cookbook of
common idioms for using guile
, and a list of common problems with
guile
and their resolution.
The discussion focuses around the 1.3 [fixme] release of guile
. The
examples in this document should all compile and run correctly in this
version of guile
. You may use the example programs in any way
you wish (see Copying).
Copyright (C) 2000 Free Software Foundation
This document is free documentation; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
As a special exception, the programs contained in this document are in the public domain. There are no restrictions on how you may use these programs. This exception applies only to the machine executable programs contained in the body of the document.
This document and any included programs in the document are distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
This document is far from an exhaustive listing of information about
guile. This is not an exhaustive list of guile
links, but instead an
attempt to provide a number of useful starting points for the interested
programmer to find more information.
guile
home page. One can find some introductory material
about guile
here, along with lots of pointers to more information.
guile
mailing list archive, which goes up to August 1998.
guile
mailing list, which has messages up to the present
(hopefully).
guile
projects page. This page has a list of
all known publicly available guile
related projects, applications, tools,
add-ons, you name it.
guile
internals. These are incomplete,
but very useful if you want to know how guile
works.
guile
developer's ftp site. You can pick up some contributed
software as well as guile
development snapshots here.
One of the uses for guile
is as an extension language to C and C++
programs. In order to do this, one needs to know how to link guile
into
your program (exhaustive documentation of this is included in the guile
reference manual), write new primitive procedures in C, convert data
between Scheme and C, and manage the control flow between Scheme and C.
This information is covered exhaustively in the guile
reference manual,
however there are some common gotcha's.
Snarfing is the process of automatically grabbing primitive
procedure definitions from C source, and registering those procedures
with the run time. This is helpful because defining a primitive from C
is a two step process; first the C function that implements the
primitive must be written, and then this C function must be registered
by name with the Scheme runtime. Without guile-snarf
, this
registration would happen at a place in the source physically distant
from the place where the C function is itself defined, which makes
adding or changing primitive definitions awkward and error prone.
guile-snarf is a utility program that gets installed into the same
directory as guile
itself when you build and install the
guile
package. It is used to make the maintenance of C source
files simpler, in the specific case when the user is defining new
guile
primitives (there are some other uses for the program, but
for now let's stick to this).
Please note that using guile-snarf
is completely optional; the
guile
sources themselves use it, but that doesn't mean that you
have to do so. Many people seem to think that it's simpler to use the
gh_
functions (FIXME: add more stuff about gh functions for
adding primitives).
guile-snarf
uses some C pre-processor trickery to allow the
primitive registration to remain physically close to the primitive
definition. The C preprocessor marches through C source files looking
for macro invocations of SCM_PROC
, each of which expands into
code that registers the new primitive procedure. The expanded code is
stored away into another file, conventionally a file with the same name
as the source file, with a .x
extension. Then the file
containing the expanded code is re-introduced into the source file at
the appropriate place using a C preprocessor #include
directive.
An example is in order.
/* $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ */ #include <guile/gh.h> SCM_PROC(s_remove_if_not, "remove-if-not", 1, 0, 1, scm_remove_if_not); static SCM scm_remove_if_not(SCM predicate, SCM args) { SCM return_list = SCM_EOL; SCM_ASSERT(gh_procedure_p(predicate), predicate, SCM_ARG1, s_remove_if_not); for (; args != SCM_EOL; args = gh_cdr(args)) { if (gh_call1(predicate, gh_car(args)) != SCM_BOOL_F) { return_list = gh_cons(gh_car(args), return_list); } } return gh_reverse(return_list); } void main_prog(int argc, char *argv[]) { # include "snarf.x" scm_shell(argc, argv); } int main(int argc, char *argv[]) { gh_enter(argc, argv, (void(*)())main_prog); return(0); }
Let's examine the SCM_PROC
line in detail, using the primitive
remove-if-not
as an example. It says that there is a new
primitive function with a Scheme name remove-if-not
(argument 2),
whose C implementation is the function scm_remove_if_not
(argument 6). You can identify the C function in error messages with
the constant string s_remove_if_not
(argument 1).
The numeric argument in position three represents the number of required
parameters. The signature of scm_remove_if_not
should start with
this many parameters of type SCM
. In this case, there is one
required parameter, named predicate
. These parameters will
always have valid Scheme data when the runtime calls your function.
The numeric argument in position four represents the number of optional
parameters. The signature of scm_remove_if_not
should contain,
in addition to and following the parameters described previously, this
many parameters. Each of these parameters may have the special value
SCM_UNDEFINED, depending on whether the user supplied the parameter. In
the case of remove-if-not
, there are no optional parameters.
The numeric argument in position five represents a C boolean expression
that specifies whether the function accepts a 'rest' list, which
corresponds to the dot notation in a lambda list. The
remove-if-not
implementation above demonstrates this
functionality. If the parameter is true (!= 0
in C parlance),
then the signature for scm_remove_if_not
should contain an
additional parameter, appearing at the end of the parameter list. This
final parameter will contain the user supplied list of additional
arguments to the C primitive, or SCM_EOL if no list was supplied. In
this case the parameter is called args
.
guile> (remove-if-not odd? 1 2 3 4 5 6 7) (1 3 5 7)
The following Makefile.in
bits are useful for generating the
guile-snarf
files from C source files. (FIXME: this needs to
be expanded with an explanation of what is really happening here)
GUILE_SNARF = @GUILE_SNARF@ .SUFFIXES: .x .c.x: $(GUILE_SNARF) $(CPPFLAGS) $< > $@
You can find out the required C preprocessor arguments for compiling C
files that use guile functions into object files using a utility program
named guile-config
that comes with guile
, and should be
installed in the same directory as guile
. Here is an example
usage:
[nytrdc058.eq.gs.com:~/src/lam/guile/doc ]% guile-config compile -I/opt/guile/include
Complete documentation for guile-config
comes with the
guile
reference manual, and I'd also recommend using
See autoconf, to make this easier.
You can find out the required libraries for linking guile into your
program by running a utility program named guile-config
that
comes with guile
, and should be installed in the same directory
as guile
. Here is an example usage:
[nytrdc058.eq.gs.com:~/src/lam/guile/doc ]% guile-config link -L/opt/guile/lib -lguile -lqthreads -ldl -ltermcap -lsocket -lnsl -lm
Complete documentation for guile-config
comes with the
guile
reference manual, and I'd also recommend using
See autoconf, to make this easier.
If you're not using autoconf (see Top) when building your programs, you can skip this section, and you have my condolences. For the rest of you, this section will hopefully make your life a bit easier.
The first thing you need when using autoconf is configure.in
, a
file which directs autoconf
how to construct configure
.
When using guile
with autoconf
, there are some special bits
that you want to add to your configure.in
:
GUILE_FLAGS AC_PATH_PROG(GUILE_SNARF, guile-snarf)
The definition of the GUILE_FLAGS
m4
macro comes from the guile
distribution. To grab this macro definition, and put it in your
project's aclocal.m4
file, run aclocal
. If you've got
guile
installed somewhere other than the default place, you may need to
specify a path to aclocal, like this.
aclocal --acdir=/opt/guile/share/aclocal
The GUILE_FLAGS
defines two configure
variables,
GUILE_LDFLAGS
and GUILE_CFLAGS
, which will be of use in
your Makefile.in
.
guile
provides facilities to split up your Scheme program into
reusable components. Each component is called a module.
Conventionally, a single file of Scheme code will define the contents of
a particular module.
There are fuzzy plans to update guile's module system, however this has been the case for two years, so I will take some time to try to describe the current module system, since it might be around for a while yet.
guile
allows the programmer to divide code into modules. A
module is a special environment for resolving variable bindings.
At any given time, one module is considered the current module,
and this module can be retreived using the procedure
current-module
. You can get the name of a module using
module-name
.
It is possible to write guile
modules completely in C. This
is useful if you're exposing a lot of code to Scheme, and you want to
manage the visibility of various parts of the program.
/* $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ */ /* this code creates a new dynamically linkable module called (silly hack). there is precisely one primitive defined in this module, '2+', which adds 2 to it's argument */ #include <guile/gh.h> /* add new primitives here */ SCM_PROC(s_2_plus, "2+", 1, 0, 0, scm_2_plus); static SCM scm_2_plus(SCM x) { SCM_ASSERT(gh_number_p(x), x, SCM_ARG1, s_2_plus); return(scm_sum(x, gh_int2scm(2))); } /* the init function */ void scm_init_hack(void) { # include "hack.x" return; } /* the pre-init function */ void scm_init_silly_hack_module() { scm_register_module_xxx("silly hack", (void*)scm_init_hack); }
One of the most useful ways to use guile
is to bolt it onto an
existing C or C++ application, and then drop into the interpreter when
some sort of dynamic behavior is required. In this case, the user would
create a list of arguments, and then call a single Scheme function from
C with this list of arguments to compute a result. This is called a
callout into the Scheme interpreter.
The module system makes it non-trivial to make a callout to a procedure
defined somewhere other than the the-root-module
. So I often
use the following utility function from C:
/* $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ */ /* it is possible to make a version of this that is much faster, i.e. that only does the gh_eval_str once. */ static SCM make_callout(char *callout, SCM ls) { SCM proc; char buf[512]; sprintf(buf, "(module-ref (resolve-module '(guile-user)) '%s)", callout); proc = gh_eval_str(buf); if (proc == SCM_UNDEFINED) { printf("callout error: lookup failed for '%s'\n", callout); return SCM_UNDEFINED; } else { return scm_apply(proc, ls, SCM_EOL); } } /* example of how to use make_callout. first create a list of arguments using scm_listify. note the SCM_UNDEFINED at the end of the argument list to scm_listify. */ void query_popup_callout(long tag, int isOk) { make_callout("fte:query-popup", scm_listify(SCM_MAKINUM(tag), (isOk? SCM_BOOL_T : SCM_BOOL_F), SCM_UNDEFINED)); }
guile
supports an optional threaded programming model. By
default guile
does not include this thread support, but you can
turn it on at configure time by specifying the --with-threads
configure option.
guile
includes a user level threads library called qthreads. At
this time, guile does not support OS level threads. It is possible to
use guile in a multi-threaded program, as long as you restrict all
access to guile functions to a single thread. I don't think that it's
possible to use guile from multiple threads, even if you wrap all uses
of guile with a single mutex, because some data structures internal to
guile could be left in an inconsistent state on a thread switch (I'm not
sure about this part, someone please correct me if I'm wrong).
There is some work going on to make guile function nicely with OS level threads. Niibe Yutaka has done most of the work so far; a link to the patch and status information can be found on the temporary projects page http://home.thezone.net/~gharvey/guile/guile-projects.html.
If you want to use guile
's user level threads library, don't
forget to run configure
with --with-threads
. The
following example programs should be helpful to illustrate what you can
do with this threads library.
This simple program starts a new thread, which simply goes into a loop of sleeping for one second, and then printing a message to the current output port. The original thread in the program does the same, and the two threads use a mutex variable to make sure that the output is not munged.
#!/opt/guile/bin/guile -s !# (define-module (guile-user)) ;;; end-header (define output (let ((output-mutex (make-mutex))) (lambda args (with-mutex output-mutex (for-each (lambda (arg) (write arg) (display " ")) args) (newline) (flush-all-ports))))) (define (make-looper message) (lambda () (let loop () (select () () () 1) (output message) (loop)))) (let ((background (make-looper "background"))) (begin-thread (background))) (let ((foreground (make-looper "foreground"))) (foreground))
Garbage collection is a programming technique that provides the user with automatic storage management. The user does not need to figure out when a particular piece of memory is no longer used; the garbage collector provides this service. FIXME: links to GC sites should go here.
guile
has a built-in garbage collector, which is used to
implement the interpreter itself, but is also useful in the context of
C
or C++
programs that use guile
.
guile
manages memory.
A conservative garbage collector is one that, instead of knowing the
exact location of each object, discovers the set of live objects by
scanning a region of memory, looking for areas that may be objects. The
possible objects found may or may not actually be objects, but we are
insured that all live objects referred to from that particular area are
found by the garbage collector. Conservative collectors are most useful
in 'hostile environments' (those where very little information on the
types and locations of objects are provided); guile
's merging of
Scheme
with C
is a perfect example.
guile
's method of collection is mostly precise. That is, most of
the objects can be definitely traced by the GC, with some areas (the C
stack & the stack of continuations) being scanned conservatively. This
has some obvious benefits to C
programmers, in that the
programming style of interfacing with the Scheme
facilities of
guile
is very similar to the style of using any other library.
The benefits of a conservative GC:
guile
currently doesn't have
any sharp, moving objects).
The drawbacks of a conservative GC:
In the worst case of the conservative collector, the program fails due to a resource exhausting number of dead objects being retained by incorrect pointers.
This worst case scenario, like many worst case scenarios, is unlikely
for typical programs. Heavy recursion is the most likely candidate for
causing things to go horribly wrong; for the most part, this is
purposely avoided in languages like C
for performance reasons. A
more insidious candidate for failure is the use of the stack for keeping
large amounts of static program state; this also doesn't generally
happen (given that alloca is non-standard, and not always well
implemented). Regardless of their unlikeliness, though, these both
suggest suggest that programmers must at least be mindful of the
existence and limitations of the conservative garbage collector, in
order to notice areas where problems could occur.
A way to get around the uncertainty of the conservative garbage collector is to introduce a system whereby the programmer explicitly registers and De-registers GC-able objects with the garbage collector. This allows us to be 100% certain that no dead objects are falsely considered live due to non-pointers looking like pointers, as well as allowing various other improvements, including the movement of stack traced objects.
The biggest drawback of explicit marking is the amount of manual bookkeeping the programmer has to do. Although easy in theory, in real programs, bugs tend to gravitate towards the bits where you have to do a lot of repetitive manual calculations (off by one arrays, malloc/free memory leaks, etc...). While compilers and other automatic tools can provide diagnostics for most of these problems, the fact remains that large, non-trivial programs tend to do non-trivial things, and programming tools can't find all of the areas that programs can go wrong.
There is also the issue of what to do in the presence of constructs
like longjmp; in many programs, this is often not a worry; in Guile,
however, many of the constructs are rolled around this, and it's hard
to see a nice way of insuring that objects are handled correctly in
their presence (or to see how the author of a Scheme
program can do
things correctly without having to know how the details of how
everything in guile works).
Explicit marking insures that no garbage is falsely retained. It also brings us close enough to the malloc/free situation, that we might as well just say screw it and use explicit allocation. Unless a way can be shown to have explicit marking without the bookkeeping being placed on the heads of programmers, I'll continue to take the slightest possibilities of failing programs over the much higher probability of failing programmers.
This section attempts to present a number of small, but useful examples
of how to use guile
to solve common problems. At least one of
the programs contained here is actually used to prepare this document,
in fact.
The following code shows how to read and process lines one at a time
from the file foo
. guile
's IO performance is not very
fast at the moment, so if you have to process large files, you may want
to use a different model than the code below.
(with-input-from-file "foo" (lambda () (while (not (eof-object? (peek-char))) (display (read-line)) (newline))))
There is a portable library of Scheme functions, called slib, that
is very useful when writing non-trivial programs. Aubrey Jaffer put
together slib
in conjunction with SCM
, a Scheme
implementation which is a precursor to guile
(many people still
prefer SCM, actually (doh!)).
Before you can use slib
with guile, you need to grab the tarball
from http://www-swiss.ai.mit.edu:80/~jaffer/SLIB.html and install
it. I recommend installing slib
in the
$prefix/share/guile/site
directory, so that when you upgrade
guile
, you don't have to reinstall slib
. Installing
slib
should be a simple matter of unpacking the files, but read
the installation notes in the package to be sure.
Once slib is installed, to use slib
within a module definition,
put something like the following in the module definition:
(define-module (silly hack) :use-module (ice-9 slib)) (require 'format)
To use slib within an arbitrary piece of scheme code, precede the code with:
(use-modules (ice-9 slib)) (require 'format)
It's not difficult to use guile two write Unix style daemon processes.
This demonstration program is thanks to Gary Houston. If you get
ambitious, extend this little program to use guile
's threading
capability, and send me the result.
;;; ;;; From: Gary Houston <ghouston@actrix.gen.nz> ;;; Subject: Re: Socket programming ;;; To: szi@aibon.ping.de ;;; Cc: guile@cygnus.com ;;; Date: 30 Sep 1997 23:17:27 -0000 ;;; ;;; | Date: Tue, 30 Sep 1997 21:34:27 +0100 ;;; | From: Sascha Ziemann <szi@aibon.ping.de> ;;; | ;;; | Hi, ;;; | ;;; | the Perl book contains a example program that shows how to write a ;;; | simple daemon. Does such an example exist for Guile too? ;;; | ;;; ;;; Here's a complicated way to write a simple daemon. talk to it by ;;; telnetting to port 20004: (let ((port (socket AF_INET SOCK_STREAM 0)) (inet-port 20004)) ; Some unused port. (bind port AF_INET INADDR_ANY inet-port) (listen port 10) ; Queue up to 10 requests. (let loop () (let ((p (accept port))) (display "Incoming connection from ") (display (inet-ntoa (sockaddr:addr (cdr p)))) (display " port ") (display (sockaddr:port (cdr p))) (newline) (let next-line () (let ((line (read-line (car p)))) (cond ((eof-object? line) (display "EOF\n")) (else (display line) (newline) (display "you sent:\n" (car p)) (display line (car p)) (newline (car p)) (next-line))))) (close-port (car p)) (loop))))
This program is used in the preparation of the guile FAQ. The program
accepts a filename as an argument, and prints to standard output the
contents of the file, with texinfo
special characters prefixed
with @
.
This program is probably a one liner in perl
(doh!). Of course,
if I rewrote it using the scsh
awk
macro, I'm sure it
would be much shorter. substitute-global
type-functionality
should definitely be included somewhere, for certain.
#! /home/ttn/local/bin/guile -s !# (define-module (guile-user) :use-module (ice-9 regex)) ;;; end-header (define (map-filename filename) (string-append filename "-txt")) (define (process-file filename) (with-output-to-file (map-filename filename) (lambda () (with-input-from-file filename (lambda () (while (not (eof-object? (peek-char))) (regexp-substitute/global (current-output-port) "[{}@]" (read-line) 'pre "@" (lambda (m) (match:substring m 0)) 'post) (newline))))))) (for-each process-file (cdr (command-line)))
Here's a way to get a C string containing the printed representation of
an object of type SCM. (Thanks to Westley Sherman). The user of the
function is responsible for freeing the returned string. As an
optimization, the stringify function could be eval'ed just once, stored
away, and protected with scm_permanent_object
.
char * scm2cstring(SCM object, int *length_p) { SCM stringify; char * string; stringify = gh_eval_str("(lambda(object)" " (with-output-to-string" " (lambda() (write object))))"); string = gh_scm2newstr(gh_call1(stringify, object), length_p); return string; }
It is often useful to display errors to the user, and the quality of the
error message is very important. Applications may want to display error
messages in a window, or in some other application specific way, so the
user must have some way or writing a custom error handler. Fortunately
guile
supports this, and we've included some example code below.
This code is more useful than is should be, though, because
guile
's error handling our of the box works well only when you're
running. When the C world is in control, guile tends to generate terse
error messages, which are hard to make sense out of. Using the code
below, you can get at the full richness of guile
's error handling
facilities, including stack traces.
Thanks to Eric Ludlam for contributing the guts of this code.
File catch.c
:
// $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ // Author: Russ McManus // guile includes #include <guile/gh.h> #include <gfec.h> static void prompt() { gh_eval_str("(display \"catch> \")" "(force-output)"); } static void error_handler(const char *err_str) { printf("----------------\n"); printf("%s\n", err_str); printf("----------------\n"); } static void read_eval_print() { SCM thunk = gh_eval_str("(lambda ()" " (display (eval (read)))" " (newline))"); prompt(); while (1) { gfec_apply(thunk, SCM_EOL, error_handler); prompt(); } return; } void main_prog(int argc, char *argv[]) { read_eval_print(); } int main(int argc, char *argv[]) { gh_enter(argc, argv, (void(*)())main_prog); return(0); }
File gfec.c
:
/* $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ * Authors: Eric M. Ludlam <zappo@ultranet.com> * Russ McManus <russell.mcmanus@gs.com> * * gfec stands for 'guile fancy error catching'. This code is in the * public domain. */ #include <gfec.h> #include <string.h> #ifdef __cplusplus extern "C" { #endif #include <libguile/fluids.h> #ifdef __cplusplus } #endif /* we assume that data is actually a char**. the way we return results from this function is to malloc a fresh string, and store it in this pointer. it is the caller's responsibility to do something smart with this freshly allocated storage. the caller can determine whether there was an error by initializing the char* passed in to NULL. if there is an error, the char string will not be NULL on return.*/ static SCM gfec_catcher(void *data, SCM tag, SCM throw_args) { SCM the_stack; /* create string port into which we write the error message and stack. */ SCM port = scm_mkstrport(SCM_INUM0, scm_make_string(SCM_MAKINUM(200), SCM_UNDEFINED), SCM_OPN | SCM_WRTNG, "error-handler"); /* throw args seem to be: (FN FORMAT ARGS #f). split the pieces into local vars. */ if (gh_list_p(throw_args) && gh_length(throw_args) >= 4) { SCM fn = gh_car(throw_args); SCM format = gh_cadr(throw_args); SCM args = gh_caddr(throw_args); SCM other_data = gh_car(gh_cdddr(throw_args)); if (fn != SCM_BOOL_F) { /* display the function name and tag */ scm_puts("Function: ", port); scm_display(fn, port); scm_puts(", ", port); scm_display(tag, port); scm_newline(port); } if (gh_string_p(format)) { /* conditionally display the error message using format */ scm_puts("Error: ", port); scm_display_error_message(format, args, port); } if (other_data != SCM_BOOL_F) { scm_puts("Other Data: ", port); scm_display(other_data, port); scm_newline(port); scm_newline(port); } } /* find the stack, and conditionally display it */ the_stack = scm_fluid_ref(SCM_CDR(scm_the_last_stack_fluid)); if (the_stack != SCM_BOOL_F) { scm_display_backtrace(the_stack, port, SCM_UNDEFINED, SCM_UNDEFINED); } SCM_DEFER_INTS; /* apparently the car of the stream object is the length of the string, and the cdr is the string itself. */ *(char**)data = strdup(SCM_CHARS(SCM_CDR(SCM_STREAM(port)))); SCM_ALLOW_INTS; return gh_int2scm(1); } /* the arguments to scm_internal_stack_catch: ------------------------------------------ SCM tag : this should be SCM_BOOL_T to catch all errors. scm_catch_body_t body : the function to run. void *body_data : a pointer to pass to body scm_catch_handler_t handler : the hander function void *handler_data : a pointer to pass to the handler */ /* what is the return value of a catch function used for? */ void gfec_eval_file(const char *file, gfec_error_handler error_handler) { char *err_msg = NULL; scm_internal_stack_catch(SCM_BOOL_T, (scm_catch_body_t)gh_eval_file, (void*)file, (scm_catch_handler_t)gfec_catcher, (void*)&err_msg); if (err_msg != NULL) { error_handler(err_msg); free(err_msg); } return; } void gfec_eval_string(const char *str, gfec_error_handler error_handler) { char *err_msg = NULL; scm_internal_stack_catch(SCM_BOOL_T, (scm_catch_body_t)gh_eval_str, (void*)str, (scm_catch_handler_t)gfec_catcher, (void*)&err_msg); if (err_msg != NULL) { error_handler(err_msg); free(err_msg); } return; } typedef struct gfec_apply_rec { SCM proc; SCM arglist; }; static void gfec_apply_helper(void *data) { struct gfec_apply_rec *apply_rec = (struct gfec_apply_rec *)data; gh_apply(apply_rec->proc, apply_rec->arglist); } void gfec_apply(SCM proc, SCM arglist, gfec_error_handler error_handler) { char *err_msg = NULL; struct gfec_apply_rec apply_rec; apply_rec.proc = proc; apply_rec.arglist = arglist; scm_internal_stack_catch(SCM_BOOL_T, (scm_catch_body_t)gfec_apply_helper, (void*)&apply_rec, (scm_catch_handler_t)gfec_catcher, (void*)&err_msg); if (err_msg != NULL) { error_handler(err_msg); free(err_msg); } return; }
File gfec.h
:
// $Id: OLD-guile-faq.html,v 1.1 2000/07/25 19:17:37 ttn Exp $ // Author: Russ McManus #ifndef GFEC_H #define GFEC_H #include <guile/gh.h> typedef void (*gfec_error_handler)(const char *error_message); void gfec_eval_file(const char *file, gfec_error_handler error_handler); void gfec_eval_string(const char *str, gfec_error_handler error_handler); void gfec_apply(SCM proc, SCM arglist, gfec_error_handler error_handler); #endif
Stuff about common problems goes here.
guile
with autoconf
: autoconf