Scribble insidemz
svn: r7931
This commit is contained in:
parent
0e6e742ec7
commit
b7583984d8
28
collects/scribblings/inside/contmarks.scrbl
Normal file
28
collects/scribblings/inside/contmarks.scrbl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "contmarks"]{Continuation Marks}
|
||||||
|
|
||||||
|
A mark can be attached to the current continuation frame using
|
||||||
|
@cppi{scheme_set_cont_mark}. To force the creation of a new frame
|
||||||
|
(e.g., during a nested function call within your function), use
|
||||||
|
@cppi{scheme_push_continuation_frame}, and then remove the frame with
|
||||||
|
@cppi{scheme_pop_continuation_frame}.
|
||||||
|
|
||||||
|
@function[(void scheme_set_cont_mark
|
||||||
|
[Scheme_Object* key]
|
||||||
|
[Scheme_Object* val])]{
|
||||||
|
|
||||||
|
Add/sets a continuation mark in the current continuation.}
|
||||||
|
|
||||||
|
@function[(void scheme_push_continuation_frame
|
||||||
|
[Scheme_Cont_Frame_Data* data])]{
|
||||||
|
|
||||||
|
Creates a new continuation frame. The @var{data} record need not be
|
||||||
|
initialized, and it can be allocated on the C stack. Supply @var{data} to
|
||||||
|
@cpp{scheme_pop_continuation_frame} to remove the continuation frame.}
|
||||||
|
|
||||||
|
@function[(void scheme_pop_continuation_frame
|
||||||
|
[Scheme_Cont_Frame_Data* data])]{
|
||||||
|
|
||||||
|
Removes a continuation frame created by @cpp{scheme_pop_continuation_frame}.}
|
97
collects/scribblings/inside/custodians.scrbl
Normal file
97
collects/scribblings/inside/custodians.scrbl
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Custodians}
|
||||||
|
|
||||||
|
When an extension allocates resources that must be explicitly freed
|
||||||
|
(in the same way that a port must be explicitly closed), a Scheme
|
||||||
|
object associated with the resource should be placed into the
|
||||||
|
management of the current custodian with @cppi{scheme_add_managed}.
|
||||||
|
|
||||||
|
Before allocating the resource, call
|
||||||
|
@cppi{scheme_custodian_check_available} to ensure that the relevant
|
||||||
|
custodian is not already shut down. If it is,
|
||||||
|
@cpp{scheme_custodian_check_available} will raise an exception. If
|
||||||
|
the custodian is shut down when @cpp{scheme_add_managed} is called,
|
||||||
|
the close function provided to @cpp{scheme_add_managed} will be called
|
||||||
|
immediately, and no exception will be reported.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@function[(Scheme_Custodian* scheme_make_custodian
|
||||||
|
[Scheme_Custodian* m])]{
|
||||||
|
|
||||||
|
Creates a new custodian as a subordinate of @var{m}. If @var{m} is
|
||||||
|
@cpp{NULL}, then the main custodian is used as the new custodian's
|
||||||
|
supervisor. Do not use @cpp{NULL} for @var{m} unless you intend to
|
||||||
|
create an especially privileged custodian.}
|
||||||
|
|
||||||
|
@function[(Scheme_Custodian_Reference* scheme_add_managed
|
||||||
|
[Scheme_Custodian* m]
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[Scheme_Close_Custodian_Client* f]
|
||||||
|
[void* data]
|
||||||
|
[int strong])]{
|
||||||
|
|
||||||
|
Places the value @var{o} into the management of the custodian
|
||||||
|
@var{m}. If @var{m} is @cpp{NULL}, the current custodian is used.
|
||||||
|
|
||||||
|
|
||||||
|
The @var{f} function is called by the custodian if it is ever asked to
|
||||||
|
``shutdown'' its values; @var{o} and @var{data} are passed on to
|
||||||
|
@var{f}, which has the type
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef void (*Scheme_Close_Custodian_Client)(Scheme_Object *o,
|
||||||
|
void *data);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
If @var{strong} is non-zero, then the newly managed value will
|
||||||
|
be remembered until either the custodian shuts it down or
|
||||||
|
@cpp{scheme_remove_managed} is called. If @var{strong} is
|
||||||
|
zero, the value is allowed to be garbaged collected (and automatically
|
||||||
|
removed from the custodian).
|
||||||
|
|
||||||
|
The return value from @cpp{scheme_add_managed} can be used to refer
|
||||||
|
to the value's custodian later in a call to
|
||||||
|
@cpp{scheme_remove_managed}. A value can be registered with at
|
||||||
|
most one custodian.
|
||||||
|
|
||||||
|
If @var{m} (or the current custodian if @var{m} is @cpp{NULL})is shut
|
||||||
|
down, then @var{f} is called immediately, and the result is
|
||||||
|
@cpp{NULL}.}
|
||||||
|
|
||||||
|
@function[(void scheme_custodian_check_available
|
||||||
|
[Scheme_Custodian* m]
|
||||||
|
[const-char* name]
|
||||||
|
[const-char* resname]
|
||||||
|
[Scheme_Custodian_Reference* mref]
|
||||||
|
[Scheme_Object* o])]{
|
||||||
|
|
||||||
|
Removes @var{o} from the management of its custodian. The @var{mref}
|
||||||
|
argument must be a value returned by @cpp{scheme_add_managed} or
|
||||||
|
@cpp{NULL}.}
|
||||||
|
|
||||||
|
@function[(void scheme_close_managed
|
||||||
|
[Scheme_Custodian* m])]{
|
||||||
|
|
||||||
|
Instructs the custodian @var{m} to shutdown all of its managed values.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_atexit_closer
|
||||||
|
[Scheme_Exit_Closer_Func f])]{
|
||||||
|
|
||||||
|
Installs a function to be called on each custodian-registered item and
|
||||||
|
its closer when MzScheme is about to exit. The registered function
|
||||||
|
has the type
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef
|
||||||
|
void (*Scheme_Exit_Closer_Func)(Scheme_Object *o,
|
||||||
|
Scheme_Close_Custodian_Client *f,
|
||||||
|
void *d);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
where @var{d} is the second argument for @var{f}.}
|
||||||
|
|
288
collects/scribblings/inside/eval.scrbl
Normal file
288
collects/scribblings/inside/eval.scrbl
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Evaluation}
|
||||||
|
|
||||||
|
A Scheme S-expression is evaluated by calling @cppi{scheme_eval}.
|
||||||
|
This function takes an S-expression (as a @cpp{Scheme_Object*}) and a
|
||||||
|
namespace and returns the value of the expression in that namespace.
|
||||||
|
|
||||||
|
The function @cppi{scheme_apply} takes a @cpp{Scheme_Object*} that is
|
||||||
|
a procedure, the number of arguments to pass to the procedure, and an
|
||||||
|
array of @cpp{Scheme_Object *} arguments. The return value is the
|
||||||
|
result of the application. There is also a function
|
||||||
|
@cppi{scheme_apply_to_list}, which takes a procedure and a list
|
||||||
|
(constructed with @cppi{scheme_make_pair}) and performs the Scheme
|
||||||
|
@scheme[apply] operation.
|
||||||
|
|
||||||
|
The @cppi{scheme_eval} function actually calls @cppi{scheme_compile}
|
||||||
|
followed by @cppi{scheme_eval_compiled}.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "topleveleval"]{Top-level Evaluation Functions}
|
||||||
|
|
||||||
|
The functions @cpp{scheme_eval}, @cpp{scheme_apply}, etc., are
|
||||||
|
@defterm{top-level evaluation functions}. Continuation invocations are
|
||||||
|
confined to jumps within a top-level evaluation.
|
||||||
|
|
||||||
|
The functions @cppi{_scheme_eval_compiled}, @cppi{_scheme_apply},
|
||||||
|
etc. (with a leading underscore) provide the same functionality
|
||||||
|
without starting a new top-level evaluation; these functions should
|
||||||
|
only be used within new primitive procedures. Since these functions
|
||||||
|
allow full continuation hops, calls to non-top-level evaluation
|
||||||
|
functions can return zero or multiple times.
|
||||||
|
|
||||||
|
Currently, escape continuations and primitive error escapes can jump
|
||||||
|
out of all evaluation and application functions. For more information,
|
||||||
|
see @secref["exceptions"].
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Tail Evaluation}
|
||||||
|
|
||||||
|
@section-index{tail recursion}
|
||||||
|
|
||||||
|
All of Scheme's built-in functions and syntax support proper
|
||||||
|
tail-recursion. When a new primitive procedure or syntax is added to
|
||||||
|
Scheme, special care must be taken to ensure that tail recursion is
|
||||||
|
handled properly. Specifically, when the final return value of a
|
||||||
|
function is the result of an application, then
|
||||||
|
@cppi{scheme_tail_apply} should be used instead of
|
||||||
|
@cppi{scheme_apply}. When @cppi{scheme_tail_apply} is called, it
|
||||||
|
postpones the procedure application until control returns to the
|
||||||
|
Scheme evaluation loop.
|
||||||
|
|
||||||
|
For example, consider the following implementation of a
|
||||||
|
@scheme[thunk-or] primitive, which takes any number of thunks and
|
||||||
|
performs @scheme[or] on the results of the thunks, evaluating only as
|
||||||
|
many thunks as necessary.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
static Scheme_Object *
|
||||||
|
thunk_or (int argc, Scheme_Object **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Scheme_Object *v;
|
||||||
|
|
||||||
|
if (!argc)
|
||||||
|
return scheme_false;
|
||||||
|
|
||||||
|
for (i = 0; i < argc - 1; i++)
|
||||||
|
if (SCHEME_FALSEP((v = _scheme_apply(argv[i], 0, NULL))))
|
||||||
|
return v;
|
||||||
|
|
||||||
|
return scheme_tail_apply(argv[argc - 1], 0, NULL);
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
This @scheme[thunk-or] properly implements tail-recursion: if the
|
||||||
|
final thunk is applied, then the result of @scheme[thunk-or] is the
|
||||||
|
result of that application, so @cppi{scheme_tail_apply} is used for
|
||||||
|
the final application.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "multiple"]{Multiple Values}
|
||||||
|
|
||||||
|
A primitive procedure can return multiple values by returning the
|
||||||
|
result of calling @cppi{scheme_values}. The functions
|
||||||
|
@cppi{scheme_eval_compiled_multi}, @cppi{scheme_apply_multi},
|
||||||
|
@cppi{_scheme_eval_compiled_multi}, and @cppi{_scheme_apply_multi}
|
||||||
|
potentially return multiple values; all other evaluation and
|
||||||
|
applications procedures return a single value or raise an exception.
|
||||||
|
|
||||||
|
Multiple return values are represented by the
|
||||||
|
@cppi{scheme_multiple_values} ``value''. This quasi-value has the type
|
||||||
|
@cpp{Scheme_Object *}, but it is not a pointer or a fixnum. When the
|
||||||
|
result of an evaluation or application is
|
||||||
|
@cppi{scheme_multiple_values}, the number of actual values can be
|
||||||
|
obtained as @cppi{scheme_multiple_count} and the array of
|
||||||
|
@cpp{Scheme_Object*} values as @cppi{scheme_multiple_array}. If any
|
||||||
|
application or evaluation procedure is called, the
|
||||||
|
@cpp{scheme_multiple_count} and @cpp{scheme_multiple_array} variables
|
||||||
|
may be modified, but the array previously referenced by
|
||||||
|
@cpp{scheme_multiple_array} is never re-used and should never be
|
||||||
|
modified.
|
||||||
|
|
||||||
|
The @cpp{scheme_multiple_count} and @cpp{scheme_multiple_array}
|
||||||
|
variables only contain meaningful values when
|
||||||
|
@cpp{scheme_multiple_values} is returned.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Evaluation Functions}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval
|
||||||
|
[Scheme_Object* expr]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Evaluates the (uncompiled) S-expression @var{expr} in the namespace
|
||||||
|
@var{env}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval_compiled
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Evaluates the compiled expression @var{obj}, which was previously
|
||||||
|
returned from @cpp{scheme_compile}, first linking to the namespace @var{env}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval_compiled_multi
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Evaluates the compiled expression @var{obj}, possibly
|
||||||
|
returning multiple values (see @secref["multiple"]).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* _scheme_eval_compiled
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Non-top-level version of @cpp{scheme_eval_compiled}. (See @secref["topleveleval"].)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* _scheme_eval_compiled_multi
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Non-top-level version of @cpp{scheme_eval_compiled_multi}. (See @secref["topleveleval"].)}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Env* scheme_basic_env)]{
|
||||||
|
|
||||||
|
Creates the main namespace for an embedded PLT Scheme. This procedure
|
||||||
|
must be called before other Scheme library function (except
|
||||||
|
@cpp{scheme_make_param}). Extensions to Scheme cannot call this
|
||||||
|
function.
|
||||||
|
|
||||||
|
If it is called more than once, this function resets all threads
|
||||||
|
(replacing the main thread), parameters, ports, namespaces, and
|
||||||
|
finalizations.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_namespace
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Creates and returns a new namespace. This values can be cast to
|
||||||
|
@scheme[Scheme\_Env *]. It can also be installed in
|
||||||
|
a parameterization using @cppi{scheme_set_param} with
|
||||||
|
@cppi{MZCONFIG_ENV}.
|
||||||
|
|
||||||
|
When PLT Scheme is embedded in an application, create the initial
|
||||||
|
namespace with @cppi{scheme_basic_env} before calling this procedure
|
||||||
|
to create new namespaces.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_apply
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Applies the procedure @var{f} to the given arguments.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_apply_multi
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Applies the procedure @var{f} to the given arguments, possibly
|
||||||
|
returning multiple values (see @secref["multiple"]).}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Object* _scheme_apply
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Non-top-level version of @cpp{scheme_apply}. (See @secref["topleveleval"].)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* _scheme_apply_multi
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Non-top-level version of @cpp{scheme_apply_multi}. (See @secref["topleveleval"].)}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_apply_to_list
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[Scheme_Object* args])]{
|
||||||
|
|
||||||
|
Applies the procedure @var{f} to the list of arguments in @var{args}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval_string
|
||||||
|
[char* str]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Reads a single S-expression from @var{str} and evaluates it in the given
|
||||||
|
namespace; the expression must return a single value, otherwise an
|
||||||
|
exception is raised. The @var{str} argument is parsed as a
|
||||||
|
UTF-8-encoded string of Unicode characters (so plain ASCII is fine).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval_string_multi
|
||||||
|
[char* str]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_eval_string}, but returns
|
||||||
|
@cpp{scheme_multiple_values} when the expression returns multiple
|
||||||
|
values.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_eval_string_all
|
||||||
|
[char* str]
|
||||||
|
[Scheme_Env* env]
|
||||||
|
[int all])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_eval_string}, but if @var{all} is not @cpp{0}, then
|
||||||
|
expressions are read and evaluated from @var{str} until the end of
|
||||||
|
the string is reached.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_tail_apply
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int n]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Applies the procedure as a tail-call. Actually, this function just
|
||||||
|
registers the given application to be invoked when control returns to
|
||||||
|
the evaluation loop. (Hence, this function is only useful within a
|
||||||
|
primitive procedure that is returning to its caller.)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_tail_apply_no_copy
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[int n]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_tail_apply}, but the array @var{args} is not
|
||||||
|
copied. Use this only when @var{args} has infinite extent and will not
|
||||||
|
be used again, or when @var{args} will certainly not be used again
|
||||||
|
until the called procedure has returned.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_tail_apply_to_list
|
||||||
|
[Scheme_Object* f]
|
||||||
|
[Scheme_Object* l])]{
|
||||||
|
|
||||||
|
Applies the procedure as a tail-call.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_compile
|
||||||
|
[Scheme_Object* form]
|
||||||
|
[Scheme_Env* env]
|
||||||
|
[int writable])]{
|
||||||
|
|
||||||
|
Compiles the S-expression @var{form} in the given namespace. The
|
||||||
|
returned value can be used with @cpp{scheme_eval_compiled} et al.
|
||||||
|
Provide a non-zero value fo @var{writable} if the resulting compiled
|
||||||
|
object will be marshalled via @scheme[write] instead of evaluated.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_expand
|
||||||
|
[Scheme_Object* form]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Expands all macros in the S-expression @var{form} using the given
|
||||||
|
namespace.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_values
|
||||||
|
[int n]
|
||||||
|
[Scheme_Object** args])]{
|
||||||
|
|
||||||
|
Returns the given values together as multiple return values. Unless
|
||||||
|
@var{n} is @cpp{1}, the result will always be
|
||||||
|
@cpp{scheme_multiple_values}.}
|
467
collects/scribblings/inside/exns.scrbl
Normal file
467
collects/scribblings/inside/exns.scrbl
Normal file
|
@ -0,0 +1,467 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "exceptions"]{Exceptions and Escape Continuations}
|
||||||
|
|
||||||
|
When Scheme encounters an error, it raises an exception. The default
|
||||||
|
exception handler invokes the error display handler and then the error
|
||||||
|
escape handler. The default error escape handler escapes via a
|
||||||
|
@defterm{primitive error escape}, which is implemented by calling
|
||||||
|
@cpp{scheme_longjmp(*scheme_current_thread->error_buf)}.
|
||||||
|
|
||||||
|
An embedding program should install a fresh buffer into
|
||||||
|
@cpp{scheme_current_thread->error_buf} and call
|
||||||
|
@cpp{scheme_setjmp(*scheme_current_thread->error_buf)} before any
|
||||||
|
top-level entry into Scheme evaluation to catch primitive error
|
||||||
|
escapes. When the new buffer goes out of scope, restore the original
|
||||||
|
in @cpp{scheme_current_thread->error_buf}. The macro
|
||||||
|
@cppi{scheme_error_buf} is a shorthand for
|
||||||
|
@cpp{*scheme_current_thread->error_buf}.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
mz_jmp_buf * volatile save, fresh;
|
||||||
|
...
|
||||||
|
save = scheme_current_thread->error_buf;
|
||||||
|
scheme_current_thread->error_buf = &fresh;
|
||||||
|
if (scheme_setjmp(scheme_error_buf)) {
|
||||||
|
/* There was an error */
|
||||||
|
...
|
||||||
|
} else {
|
||||||
|
v = scheme_eval_string(s, env);
|
||||||
|
}
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
...
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
3m: when @cpp{scheme_setjmp} is used, the enclosing context must
|
||||||
|
provide a local-variable registration record via @cpp{MZ_GC_DECL_REG}.
|
||||||
|
Use @cpp{MZ_GC_DECL_REG(0)} if the context has no local variables to
|
||||||
|
register. Unfortunately, when using @DFlag{xform} with @|mzc| instead
|
||||||
|
of @cpp{MZ_GC_DECL_REG}, etc., you may need to declare a dummy pointer
|
||||||
|
and use it after @cpp{scheme_setjmp} to ensure that a local-variable
|
||||||
|
registration is generated.
|
||||||
|
|
||||||
|
New primitive procedures can raise a generic exception by calling
|
||||||
|
@cppi{scheme_signal_error}. The arguments for
|
||||||
|
@cpp{scheme_signal_error} are roughly the same as for the standard C
|
||||||
|
function @cpp{printf}. A specific primitive exception can be raised by
|
||||||
|
calling @cppi{scheme_raise_exn}.
|
||||||
|
|
||||||
|
Full @as-index{continuations} are implemented in Scheme by copying
|
||||||
|
the C stack and using @cppi{scheme_setjmp} and @cppi{scheme_longjmp}.
|
||||||
|
As long a C/C++ application invokes Scheme evaluation through the
|
||||||
|
top-level evaluation functions (@cpp{scheme_eval}, @cpp{scheme_apply},
|
||||||
|
etc., as opposed to @cpp{_scheme_apply}, @cpp{_scheme_eval_compiled},
|
||||||
|
etc.), the code is protected against any unusual behavior from Scheme
|
||||||
|
evaluations (such as returning twice from a function) because
|
||||||
|
continuation invocations are confined to jumps within a single
|
||||||
|
top-level evaluation. However, escape continuation jumps are still
|
||||||
|
allowed; as explained in the following sub-section, special care must
|
||||||
|
be taken in extension that is sensitive to escapes.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "imz:tempcatch"]{Temporarily Catching Error Escapes}
|
||||||
|
|
||||||
|
When implementing new primitive procedure, it is sometimes useful to
|
||||||
|
catch and handle errors that occur in evaluating subexpressions. One
|
||||||
|
way to do this is the following: save
|
||||||
|
@cppi{scheme_current_thread->error_buf} to a temporary variable, set
|
||||||
|
@cppi{scheme_current_thread->error_buf} to the address of a
|
||||||
|
stack-allocated @cpp{mz_jmp_buf}, invoke
|
||||||
|
@cpp{scheme_setjmp(scheme_error_buf)}, perform the function's work,
|
||||||
|
and then restore @cpp{scheme_current_thread->error_buf} before
|
||||||
|
returning a value. (3m: A stack-allocated @cpp{mz_jmp_buf} instance
|
||||||
|
need not be registered with the garbage collector, and a
|
||||||
|
heap-allocated @cpp{mz_jmp_buf} should be alloctaed as atomic.)
|
||||||
|
|
||||||
|
However, beware that a prompt abort or the invocation of an escaping
|
||||||
|
continuation looks like a primitive error escape. In that case, the
|
||||||
|
special indicator flag @cppi{scheme_jumping_to_continuation} is
|
||||||
|
non-zero (instead of its normal zero value); this situation is only
|
||||||
|
visible when implementing a new primitive procedure. When
|
||||||
|
@cppi{scheme_jumping_to_continuation} is non-zero, honor the escape
|
||||||
|
request by chaining to the previously saved error buffer; otherwise,
|
||||||
|
call @cppi{scheme_clear_escape}.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
mz_jmp_buf * volatile save, fresh;
|
||||||
|
save = scheme_current_thread->error_buf;
|
||||||
|
scheme_current_thread->error_buf = &fresh;
|
||||||
|
if (scheme_setjmp(scheme_error_buf)) {
|
||||||
|
/* There was an error or continuation invocation */
|
||||||
|
if (scheme_jumping_to_continuation) {
|
||||||
|
/* It was a continuation jump */
|
||||||
|
scheme_longjmp(*save, 1);
|
||||||
|
/* To block the jump, instead: scheme_clear_escape(); */
|
||||||
|
} else {
|
||||||
|
/* It was a primitive error escape */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scheme_eval_string("x", scheme_env);
|
||||||
|
}
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
This solution works fine as long as the procedure implementation only
|
||||||
|
calls top-level evaluation functions (@cpp{scheme_eval},
|
||||||
|
@cpp{scheme_apply}, etc., as opposed to @cpp{_scheme_apply},
|
||||||
|
@cpp{_scheme_eval_compiled}, etc.). Otherwise, use
|
||||||
|
@cppi{scheme_dynamic_wind} to protect your code against full
|
||||||
|
continuation jumps in the same way that @scheme[dynamic-wind] is used
|
||||||
|
in Scheme.
|
||||||
|
|
||||||
|
The above solution simply traps the escape; it doesn't report the
|
||||||
|
reason that the escape occurred. To catch exceptions and obtain
|
||||||
|
information about the exception, the simplest route is to mix Scheme
|
||||||
|
code with C-implemented thunks. The code below can be used to catch
|
||||||
|
exceptions in a variety of situations. It implements the function
|
||||||
|
@cpp{_apply_catch_exceptions}, which catches exceptions during the
|
||||||
|
application of a thunk. (This code is in
|
||||||
|
@filepath{collects/mzscheme/examples/catch.c} in the distribution.)
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
static Scheme_Object *exn_catching_apply, *exn_p, *exn_message;
|
||||||
|
|
||||||
|
static void init_exn_catching_apply()
|
||||||
|
{
|
||||||
|
if (!exn_catching_apply) {
|
||||||
|
char *e =
|
||||||
|
"(lambda (thunk) "
|
||||||
|
"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
|
||||||
|
"(cons #t (thunk))))";
|
||||||
|
/* make sure we have a namespace with the standard bindings: */
|
||||||
|
Scheme_Env *env = (Scheme_Env *)scheme_make_namespace(0, NULL);
|
||||||
|
|
||||||
|
scheme_register_extension_global(&exn_catching_apply,
|
||||||
|
sizeof(Scheme_Object *));
|
||||||
|
scheme_register_extension_global(&exn_p,
|
||||||
|
sizeof(Scheme_Object *));
|
||||||
|
scheme_register_extension_global(&exn_message,
|
||||||
|
sizeof(Scheme_Object *));
|
||||||
|
|
||||||
|
exn_catching_apply = scheme_eval_string(e, env);
|
||||||
|
exn_p = scheme_lookup_global(scheme_intern_symbol("exn?"), env);
|
||||||
|
exn_message
|
||||||
|
= scheme_lookup_global(scheme_intern_symbol("exn-message"),
|
||||||
|
env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function applies a thunk, returning the Scheme value if
|
||||||
|
there's no exception, otherwise returning NULL and setting *exn
|
||||||
|
to the raised value (usually an exn structure). */
|
||||||
|
Scheme_Object *_apply_thunk_catch_exceptions(Scheme_Object *f,
|
||||||
|
Scheme_Object **exn)
|
||||||
|
{
|
||||||
|
Scheme_Object *v;
|
||||||
|
|
||||||
|
init_exn_catching_apply();
|
||||||
|
|
||||||
|
v = _scheme_apply(exn_catching_apply, 1, &f);
|
||||||
|
/* v is a pair: (cons #t value) or (cons #f exn) */
|
||||||
|
|
||||||
|
if (SCHEME_TRUEP(SCHEME_CAR(v)))
|
||||||
|
return SCHEME_CDR(v);
|
||||||
|
else {
|
||||||
|
*exn = SCHEME_CDR(v);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scheme_Object *extract_exn_message(Scheme_Object *v)
|
||||||
|
{
|
||||||
|
init_exn_catching_apply();
|
||||||
|
|
||||||
|
if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
|
||||||
|
return _scheme_apply(exn_message, 1, &v);
|
||||||
|
else
|
||||||
|
return NULL; /* Not an exn structure */
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
In the following example, the above code is used to catch exceptions
|
||||||
|
that occur during while evaluating source code from a string.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
static Scheme_Object *do_eval(void *s, int noargc, Scheme_Object **noargv)
|
||||||
|
{
|
||||||
|
return scheme_eval_string((char *)s, scheme_get_env(scheme_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Scheme_Object *eval_string_or_get_exn_message(char *s)
|
||||||
|
{
|
||||||
|
Scheme_Object *v, *exn;
|
||||||
|
|
||||||
|
v = scheme_make_closed_prim(do_eval, s);
|
||||||
|
v = _apply_thunk_catch_exceptions(v, &exn);
|
||||||
|
/* Got a value? */
|
||||||
|
if (v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
v = extract_exn_message(exn);
|
||||||
|
/* Got an exn? */
|
||||||
|
if (v)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
/* `raise' was called on some arbitrary value */
|
||||||
|
return exn;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Enabling and Disabling Breaks}
|
||||||
|
|
||||||
|
When embedding PLT Scheme, asynchronous break exceptions are disabled by
|
||||||
|
default. Call @cpp{scheme_set_can_break} (which is the same as calling
|
||||||
|
the Scheme funciton @scheme[break-enabled]) to enable or disable
|
||||||
|
breaks. To enable or disable breaks during the dynamic extent of
|
||||||
|
another evaluation (where you would use
|
||||||
|
@scheme[with-break-parameterization] in Scheme), use
|
||||||
|
@cppi{scheme_push_break_enable} before and
|
||||||
|
@cppi{scheme_pop_break_enable} after, instead.
|
||||||
|
|
||||||
|
@section{Exception Functions}
|
||||||
|
|
||||||
|
@function[(void scheme_signal_error
|
||||||
|
[char* msg]
|
||||||
|
[... ...])]{
|
||||||
|
|
||||||
|
Raises a generic primitive exception. The parameters are roughly as
|
||||||
|
for @cpp{printf}, but with the following format directives:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@FormatD{c} : a Unicode character (of type @cpp{mzchar})}
|
||||||
|
|
||||||
|
@item{@FormatD{d} : an integer}
|
||||||
|
|
||||||
|
@item{@FormatD{ld} : a @cpp{long} integer}
|
||||||
|
|
||||||
|
@item{@FormatD{f} : a floating-point @cpp{double}}
|
||||||
|
|
||||||
|
@item{@FormatD{s} : a nul-terminated @cpp{char} string}
|
||||||
|
|
||||||
|
@item{@FormatD{5} : a nul-terminated @cpp{mzchar} string}
|
||||||
|
|
||||||
|
@item{@FormatD{S} : a Scheme symbol (a @cpp{Scheme_Object*})}
|
||||||
|
|
||||||
|
@item{@FormatD{t} : a @cpp{char} string with a @cpp{long} size (two
|
||||||
|
arguments), possibly containing a non-terminating nul byte, and
|
||||||
|
possibly without a nul-terminator}
|
||||||
|
|
||||||
|
@item{@FormatD{u} : a @cpp{mzchar} string with a @cpp{long} size (two
|
||||||
|
arguments), possibly containing a non-terminating nul character, and
|
||||||
|
possibly without a nul-terminator}
|
||||||
|
|
||||||
|
@item{@FormatD{T} : a Scheme string (a @cpp{Scheme_Object*})}
|
||||||
|
|
||||||
|
@item{@FormatD{q} : a string, truncated to 253 characters, with ellipses
|
||||||
|
printed if the string is truncated}
|
||||||
|
|
||||||
|
@item{@FormatD{Q} : a Scheme string (a @cpp{Scheme_Object*}),
|
||||||
|
truncated to 253 characters, with ellipses printed if the string is
|
||||||
|
truncated}
|
||||||
|
|
||||||
|
@item{@FormatD{V} : a Scheme value (a @cpp{Scheme_Object*}),
|
||||||
|
truncated according to the current error print width.}
|
||||||
|
|
||||||
|
@item{@FormatD{e} : an @cpp{errno} value, to be printed as a text
|
||||||
|
message.}
|
||||||
|
|
||||||
|
@item{@FormatD{E} : a platform-specific error value, to be printed as a
|
||||||
|
text message.}
|
||||||
|
|
||||||
|
@item{@FormatD{Z} : a potential platform-specific error value and a
|
||||||
|
@cpp{char} string; if the string is non-@cpp{NULL}, then the error
|
||||||
|
value is ignored, otherwise the error value is used as for \Format{E}.}
|
||||||
|
|
||||||
|
@item{@FormatD{%} : a percent sign}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
The arguments following the format string must include no more than 25
|
||||||
|
strings and Scheme values, 25 integers, and 25 floating-point
|
||||||
|
numbers. (This restriction simplifies the implementation with precise
|
||||||
|
garbage collection.)}
|
||||||
|
|
||||||
|
@function[(void scheme_raise_exn
|
||||||
|
[int exnid]
|
||||||
|
[... ...])]{
|
||||||
|
|
||||||
|
Raises a specific primitive exception. The @var{exnid} argument
|
||||||
|
specifies the exception to be raised. If an instance of that exception
|
||||||
|
has @math{n} fields, then the next @math{n-2} arguments are values for
|
||||||
|
those fields (skipping the @scheme[message] and @scheme[debug-info]
|
||||||
|
fields). The remaining arguments start with an error string and
|
||||||
|
proceed roughly as for @cpp{printf}; see @cpp{scheme_signal_error}
|
||||||
|
above for more details.
|
||||||
|
|
||||||
|
Exception ids are @cpp{#define}d using the same names as in Scheme,
|
||||||
|
but prefixed with ``MZ'', all letters are capitalized, and all ``:'s',
|
||||||
|
``-''s, and ``/''s are replaced with underscores. For example,
|
||||||
|
@cpp{MZEXN_FAIL_FILESYSTEM} is the exception id for a filesystem
|
||||||
|
exception.}
|
||||||
|
|
||||||
|
@function[(void scheme_warning
|
||||||
|
[char* msg]
|
||||||
|
[... ...])]{
|
||||||
|
|
||||||
|
Signals a warning. The parameters are roughly as for @cpp{printf}; see
|
||||||
|
@cpp{scheme_signal_error} above for more details.}
|
||||||
|
|
||||||
|
@function[(void scheme_wrong_count
|
||||||
|
[char* name]
|
||||||
|
[int minc]
|
||||||
|
[int maxc]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
This function is automatically invoked when the wrong number of
|
||||||
|
arguments are given to a primitive procedure. It signals that the
|
||||||
|
wrong number of parameters was received and escapes (like
|
||||||
|
@cpp{scheme_signal_error}). The @var{name} argument is the name of
|
||||||
|
the procedure that was given the wrong number of arguments; @var{minc}
|
||||||
|
is the minimum number of expected arguments; @var{maxc} is the maximum
|
||||||
|
number of expected arguments, or -1 if there is no maximum; @var{argc}
|
||||||
|
and @var{argv} contain all of the received arguments.}
|
||||||
|
|
||||||
|
@function[(void scheme_wrong_type
|
||||||
|
[char* name]
|
||||||
|
[char* expected]
|
||||||
|
[int which]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Signals that an argument of the wrong type was received, and escapes
|
||||||
|
(like @cpp{scheme_signal_error}). The @var{name} argument is the name
|
||||||
|
of the procedure that was given the wrong type of argument;
|
||||||
|
@var{expected} is the name of the expected type; @var{which} is the
|
||||||
|
offending argument in the @var{argv} array; @var{argc} and @var{argv}
|
||||||
|
contain all of the received arguments. If the original @var{argc} and
|
||||||
|
@var{argv} are not available, provide -1 for @var{which} and a pointer
|
||||||
|
to the bad value in @var{argv}; @var{argc} is ignored in this case.}
|
||||||
|
|
||||||
|
@function[(void scheme_wrong_return_arity
|
||||||
|
[char* name]
|
||||||
|
[int expected]
|
||||||
|
[int got]
|
||||||
|
[Scheme_Object** argv]
|
||||||
|
[const-char* detail])]{
|
||||||
|
|
||||||
|
Signals that the wrong number of values were returned to a
|
||||||
|
multiple-values context. The @var{expected} argument indicates how
|
||||||
|
many values were expected, @var{got} indicates the number received,
|
||||||
|
and @var{argv} are the received values. The @var{detail} string can be
|
||||||
|
@cpp{NULL} or it can contain a @cpp{printf}-style string (with
|
||||||
|
additional arguments) to describe the context of the error; see
|
||||||
|
@cpp{scheme_signal_error} above for more details about the
|
||||||
|
@cpp{printf}-style string.}
|
||||||
|
|
||||||
|
@function[(void scheme_unbound_global
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Signals an unbound-variable error, where @var{name} is the name of the
|
||||||
|
variable.}
|
||||||
|
|
||||||
|
@function[(char* scheme_make_provided_string
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[int count]
|
||||||
|
[int* len])]{
|
||||||
|
|
||||||
|
Converts a Scheme value into a string for the purposes of reporting an
|
||||||
|
error message. The @var{count} argument specifies how many Scheme
|
||||||
|
values total will appear in the error message (so the string for this
|
||||||
|
value can be scaled appropriately). If @var{len} is not @cpp{NULL}, it
|
||||||
|
is filled with the length of the returned string.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(char* scheme_make_args_string
|
||||||
|
[char* s]
|
||||||
|
[int which]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv]
|
||||||
|
[long* len])]{
|
||||||
|
|
||||||
|
Converts an array of Scheme values into a byte string, skipping the
|
||||||
|
array element indicated by @var{which}. This function is used to
|
||||||
|
specify the ``other'' arguments to a function when one argument is bad
|
||||||
|
(thus giving the user more information about the state of the program
|
||||||
|
when the error occurred). If @var{len} is not @cpp{NULL}, it is
|
||||||
|
filled with the length of the returned string.}
|
||||||
|
|
||||||
|
@function[(void scheme_check_proc_arity
|
||||||
|
[char* where]
|
||||||
|
[int a]
|
||||||
|
[int which]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Checks the @var{which}th argument in @var{argv} to make sure it is a
|
||||||
|
procedure that can take @var{a} arguments. If there is an error, the
|
||||||
|
@var{where}, @var{which}, @var{argc}, and @var{argv} arguments are
|
||||||
|
passed on to @cpp{scheme_wrong_type}. As in @cpp{scheme_wrong_type},
|
||||||
|
@var{which} can be -1, in which case @cpp{*}@var{argv} is checked.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_dynamic_wind
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Evaluates calls the function @var{action} to get a value for the
|
||||||
|
@cpp{scheme_dynamic_wind} call. The functions @var{pre} and
|
||||||
|
@var{post} are invoked when jumping into and out of @var{action},
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
The function @var{jmp_handler} is called when an error is signaled (or
|
||||||
|
an escaping continuation is invoked) during the call to @var{action};
|
||||||
|
if @var{jmp_handler} returns @cpp{NULL}, then the error is passed on
|
||||||
|
to the next error handler, otherwise the return value is used as the
|
||||||
|
return value for the @cpp{scheme_dynamic_wind} call.
|
||||||
|
|
||||||
|
The pointer @var{data} can be anything; it is passed along in calls to
|
||||||
|
@var{action}, @var{pre}, @var{post}, and @var{jmp_handler}.}
|
||||||
|
|
||||||
|
@function[(void scheme_clear_escape)]{
|
||||||
|
|
||||||
|
Clears the ``jumping to escape continuation'' flag associated with a
|
||||||
|
thread. Call this function when blocking escape continuation hops (see
|
||||||
|
the first example in @secref["imz:tempcatch"]).}
|
||||||
|
|
||||||
|
@function[(void scheme_set_can_break
|
||||||
|
[int on])]{
|
||||||
|
|
||||||
|
Enables or disables breaks in the same way as
|
||||||
|
calling @scheme[break-enabled].}
|
||||||
|
|
||||||
|
@function[(void scheme_push_break_enable
|
||||||
|
[Scheme_Cont_Frame_Data* cframe]
|
||||||
|
[int on]
|
||||||
|
[int pre_check])]{
|
||||||
|
|
||||||
|
Use this function with @cpp{scheme_pop_break_enable} to enable or
|
||||||
|
disable breaks in the same way as
|
||||||
|
@scheme[with-break-parameterization]; this function writes to
|
||||||
|
@var{cframe} to initialize it, and @cpp{scheme_pop_break_enable} reads
|
||||||
|
from @var{cframe}. If @var{pre_check} is non-zero and breaks are
|
||||||
|
currently enabled, any pending break exception is raised.}
|
||||||
|
|
||||||
|
@function[(void scheme_pop_break_enable
|
||||||
|
[Scheme_Cont_Frame_Data* cframe]
|
||||||
|
[int post_check])]{
|
||||||
|
|
||||||
|
Use this function with @cpp{scheme_push_break_enable}. If
|
||||||
|
@var{post_check} is non-zero and breaks are enabled after restoring
|
||||||
|
the previous state, then any pending break exception is raised.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_current_continuation_marks
|
||||||
|
[Scheme_Object* prompt_tag])]{
|
||||||
|
|
||||||
|
Like @scheme[current-continuation-marks]. Passing @cpp{NULL} as
|
||||||
|
@var{prompt_tag} is the same as providing the default continuation
|
||||||
|
prompt tag.}
|
||||||
|
|
||||||
|
|
51
collects/scribblings/inside/hooks.scrbl
Normal file
51
collects/scribblings/inside/hooks.scrbl
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Flags and Hooks}
|
||||||
|
|
||||||
|
The following flags and hooks are available when PLT Scheme is
|
||||||
|
embedded:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_exit} --- This pointer can be set to a function
|
||||||
|
that takes an integer argument and returns @cpp{void}; the function
|
||||||
|
will be used as the default exit handler. The default is @cpp{NULL}.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_make_stdin}, @cppdef{scheme_make_stdout},
|
||||||
|
@cppdef{scheme_make_stderr}, --- These pointers can be set to a
|
||||||
|
function that takes no arguments and returns a Scheme port
|
||||||
|
@cpp{Scheme_Object *} to be used as the starting standard input,
|
||||||
|
output, and/or error port. The defaults are @cpp{NULL}. Setting the
|
||||||
|
initial error port is particularly important for seeing unexpected
|
||||||
|
error messages if @cpp{stderr} output goes nowhere.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_console_output} --- This pointer can be set to a
|
||||||
|
function that takes a string and a @cpp{long} string length; the
|
||||||
|
function will be called to display internal MzScheme warnings and
|
||||||
|
messages that possibly contain non-terminating nuls. The default is
|
||||||
|
@var{NULL}.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_check_for_break} --- \index{user breaks} This
|
||||||
|
points to a function of no arguments that returns an integer. It is
|
||||||
|
used as the default user-break polling procedure in the main
|
||||||
|
thread. A non-zero return value indicates a user break, and each time
|
||||||
|
the function returns a non-zero value, it counts as a new break
|
||||||
|
signal (though the break signal may be ignored if a previous signal
|
||||||
|
is still pending). The default is @cpp{NULL}.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_case_sensitive} --- If this flag is set to a
|
||||||
|
non-zero value before @cppi{scheme_basic_env} is called, then
|
||||||
|
MzScheme will not ignore capitalization for symbols and global
|
||||||
|
variable names. The value of this flag should not change once it is
|
||||||
|
set. The default is zero.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_allow_set_undefined} --- This flag determines
|
||||||
|
the initial value of \scmi{compile-allow-set!-undefined}. The default
|
||||||
|
is zero.}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_console_printf} --- This function pointer was
|
||||||
|
left for backward compatibility. The default builds a string and
|
||||||
|
calls @cppi{scheme_console_output}.}
|
||||||
|
|
||||||
|
}
|
3
collects/scribblings/inside/info.ss
Normal file
3
collects/scribblings/inside/info.ss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
(module info setup/infotab
|
||||||
|
(define name "Scribblings: Inside PLT Scheme")
|
||||||
|
(define scribblings '(("inside.scrbl" (multi-page main-doc)))))
|
41
collects/scribblings/inside/inside.scrbl
Normal file
41
collects/scribblings/inside/inside.scrbl
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag-prefix '(lib "scribblings/inside/inside.scrbl")
|
||||||
|
#:tag "top"]{Inside PLT Scheme}
|
||||||
|
|
||||||
|
This manual describes PLT Scheme's C interface, which allows the
|
||||||
|
interpreter to be extended by a dynamically-loaded library, or
|
||||||
|
embedded within an arbitrary C/C++ program. The manual assumes
|
||||||
|
familiarity with PLT Scheme as described in @|MzScheme|.
|
||||||
|
|
||||||
|
For an alternative way of dealing with foreign code, see ..., which
|
||||||
|
describes the @schememodname[scheme/foreign] module for manipulating
|
||||||
|
low-level libraries and structures purely through Scheme code.
|
||||||
|
|
||||||
|
@table-of-contents[]
|
||||||
|
|
||||||
|
@; ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@include-section["overview.scrbl"]
|
||||||
|
@include-section["values.scrbl"]
|
||||||
|
@include-section["memory.scrbl"]
|
||||||
|
@include-section["namespaces.scrbl"]
|
||||||
|
@include-section["procedures.scrbl"]
|
||||||
|
@include-section["eval.scrbl"]
|
||||||
|
@include-section["exns.scrbl"]
|
||||||
|
@include-section["threads.scrbl"]
|
||||||
|
@include-section["params.scrbl"]
|
||||||
|
@include-section["contmarks.scrbl"]
|
||||||
|
@include-section["strings.scrbl"]
|
||||||
|
@include-section["numbers.scrbl"]
|
||||||
|
@include-section["ports.scrbl"]
|
||||||
|
@include-section["structures.scrbl"]
|
||||||
|
@include-section["security.scrbl"]
|
||||||
|
@include-section["custodians.scrbl"]
|
||||||
|
@include-section["misc.scrbl"]
|
||||||
|
@include-section["hooks.scrbl"]
|
||||||
|
|
||||||
|
@; ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@index-section[]
|
923
collects/scribblings/inside/memory.scrbl
Normal file
923
collects/scribblings/inside/memory.scrbl
Normal file
|
@ -0,0 +1,923 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "im:memoryalloc"]{Memory Allocation}
|
||||||
|
|
||||||
|
@section-index{memory}
|
||||||
|
@section-index{garbage collection}
|
||||||
|
|
||||||
|
PLT Scheme uses both @cppi{malloc} and allocation functions provided
|
||||||
|
by a garbage collector. Embedding/extension C/C++ code may use either
|
||||||
|
allocation method, keeping in mind that pointers to
|
||||||
|
garbage-collectable blocks in @cpp{malloc}ed memory are invisible
|
||||||
|
(i.e., such pointers will not prevent the block from being
|
||||||
|
garbage-collected).
|
||||||
|
|
||||||
|
PLT Scheme CGC uses a conservative garbage collector. This garbage
|
||||||
|
collector normally only recognizes pointers to the beginning of
|
||||||
|
allocated objects. Thus, a pointer into the middle of a GC-allocated
|
||||||
|
string will normally not keep the string from being collected. The
|
||||||
|
exception to this rule is that pointers saved on the stack or in
|
||||||
|
registers may point to the middle of a collectable object. Thus, it
|
||||||
|
is safe to loop over an array by incrementing a local pointer
|
||||||
|
variable.
|
||||||
|
|
||||||
|
PLT Scheme 3m uses a precise garbage collector that moves objects
|
||||||
|
during collection, in which case the C code must be instrumented to
|
||||||
|
expose local pointer bindings to the collector, and to provide tracing
|
||||||
|
procedures for (tagged) records containing pointers. This
|
||||||
|
instrumentation is described further in @secref["im:3m"].
|
||||||
|
|
||||||
|
The basic collector allocation functions are:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc} --- Allocates collectable memory that may
|
||||||
|
contain pointers to collectable objects; for 3m, the memory must be
|
||||||
|
an array of pointers (though not necessarily to collectable
|
||||||
|
objects). The newly allocated memory is initially zeroed.}
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc_atomic} --- Allocates collectable memory
|
||||||
|
that does not contain pointers to collectable objects. If the memory
|
||||||
|
does contain pointers, they are invisible to the collector and will
|
||||||
|
not prevent an object from being collected. Newly allocated atomic
|
||||||
|
memory is not necessary zeroed.
|
||||||
|
|
||||||
|
Atomic memory is used for strings or other blocks of memory which do
|
||||||
|
not contain pointers. Atomic memory can also be used to store
|
||||||
|
intentionally-hidden pointers.}
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc_tagged} --- Allocates collectable memory
|
||||||
|
that contains a mixture of pointers and atomic data. With the
|
||||||
|
conservative collector, this function is the same
|
||||||
|
as @cppi{scheme_malloc}, but under 3m, the type tag stored at the
|
||||||
|
start of the block is used to determine the size and shape of the
|
||||||
|
object for future garbage collection (as described
|
||||||
|
in @secref["im:3m"]).}
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc_allow_interior} --- Allocates a large
|
||||||
|
array of pointers such that references are allowed into the middle of
|
||||||
|
the block under 3m, and such pointers prevent the block from being
|
||||||
|
collected. This procedure is the same as @cppi{scheme_malloc} with
|
||||||
|
the conservative collector, but in the that case, having @italic{only}
|
||||||
|
a pointer into the interior will not prevent the array from being
|
||||||
|
collected.}
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc_atomic_allow_interior} --- Like
|
||||||
|
@cpp{scheme_malloc_allow_interior} for memory that does not
|
||||||
|
contain pointers.}
|
||||||
|
|
||||||
|
@item{@cppi{scheme_malloc_uncollectable} --- Allocates
|
||||||
|
uncollectable memory that may contain pointers to collectable
|
||||||
|
objects. There is no way to free the memory. The newly allocated
|
||||||
|
memory is initially zeroed. This function is not available in 3m.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@index['("globals" "in extension code")]{If} a PLT Scheme extension
|
||||||
|
stores Scheme pointers in a global or static variable, then that
|
||||||
|
variable must be registered with
|
||||||
|
@cppi{scheme_register_extension_global}; this makes the pointer
|
||||||
|
visible to the garbage collector. Registered variables need not
|
||||||
|
contain a collectable pointer at all times (even with 3m, but the
|
||||||
|
variable must contain some pointer, possibly uncollectable, at all
|
||||||
|
times).
|
||||||
|
|
||||||
|
With conservative collection, no registration is needed for the global
|
||||||
|
or static variables of an embedding program, unless it calls
|
||||||
|
@cppi{scheme_set_stack_base} with a non-zero second argument. (Under
|
||||||
|
Mac OS X or with 3m, @cpp{scheme_set_stack_base} must be called
|
||||||
|
always.) In that case, global and static variables containing
|
||||||
|
collectable pointers must be registered with
|
||||||
|
@cppi{scheme_register_static}. The @cppi{MZ_REGISTER_STATIC} macro
|
||||||
|
takes any variable name and registers it with
|
||||||
|
@cppi{scheme_register_static}. The @cppi{scheme_register_static}
|
||||||
|
function can be safely called even when it's not needed, but it must
|
||||||
|
not be called multiple times for a single memory address.
|
||||||
|
|
||||||
|
Collectable memory can be temporarily locked from collection by using
|
||||||
|
the reference-counting function @cppi{scheme_dont_gc_ptr}. Under 3m,
|
||||||
|
such locking does not prevent the object from being moved.
|
||||||
|
|
||||||
|
Garbage collection can occur during any call into Scheme or its
|
||||||
|
allocator, on anytime that Scheme has control, except during functions
|
||||||
|
that are documented otherwise. The predicate and accessor macros
|
||||||
|
listed in @secref["im:stdtypes"] never trigger a collection.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "im:3m"]{Cooperating with 3m}
|
||||||
|
|
||||||
|
To allow 3m's precise collector to detect and update pointers during
|
||||||
|
garbage collection, all pointer values must be registered with the
|
||||||
|
collector, at least during the times that a collection may occur. The
|
||||||
|
content of a word registered as a pointer must contain either
|
||||||
|
@cpp{NULL}, a pointer to the start of a collectable object, a pointer
|
||||||
|
into an object allocated by @cpp{scheme_malloc_allow_interior}, a
|
||||||
|
pointer to an object currently allocated by another memory manager
|
||||||
|
(and therefore not into a block that is currently managed by the
|
||||||
|
collector), or a pointer to an odd-numbered address (e.g., a Scheme
|
||||||
|
fixnum).
|
||||||
|
|
||||||
|
Pointers are registered in three different ways:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{Pointers in static variables should be registered with
|
||||||
|
@cppi{scheme_register_static} or @cpp{MZ_REGISTER_STATIC}.}
|
||||||
|
|
||||||
|
@item{Pointers in allocated memory are registered automatically when
|
||||||
|
they are in an array allocated with @cpp{scheme_malloc}, etc. When a
|
||||||
|
pointer resides in an object allocated with
|
||||||
|
@cpp{scheme_malloc_tagged}, etc.~the tag at the start of the object
|
||||||
|
identifiers the object's size and shape. Handling of tags is
|
||||||
|
described in @secref["im:3m:tagged"].}
|
||||||
|
|
||||||
|
@item{Local pointers (i.e., pointers on the stack or in registers)
|
||||||
|
must be registered through the @cpp{MZ_GC_DECL_REG}, @|etc| macros
|
||||||
|
that are described in @secref["im:3m:stack"].}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
A pointer must never refer to the interior of an allocated object
|
||||||
|
(when a garbage collection is possible), unless the object was
|
||||||
|
allocated with {@cppi{scheme_malloc_allow_interior}}. For this reason,
|
||||||
|
pointer arithmetic must usually be avoided, unless the variable
|
||||||
|
holding the generated pointer is @cpp{NULL}ed before a collection.
|
||||||
|
|
||||||
|
@bold{IMPORTANT:} The @cppi{SCHEME_SYM_VAL},
|
||||||
|
@cppi{SCHEME_KEYWORD_VAL}, @cppi{SCHEME_VEC_ELS}, and
|
||||||
|
@cppi{SCHEME_PRIM_CLOSURE_ELS} macros produce pointers into the middle
|
||||||
|
of their respective objects, so the results of these macros must not
|
||||||
|
be held during the time that a collection can occur. Incorrectly
|
||||||
|
retaining such a pointer can lead to a crash.
|
||||||
|
|
||||||
|
@; - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
@subsection[#:tag "im:3m:tagged"]{Tagged Objects}
|
||||||
|
|
||||||
|
As explained in @secref["im:values+types"], the @cpp{scheme_make_type}
|
||||||
|
function can be used to obtain a new tag for a new type of object.
|
||||||
|
These new types are in relatively short supply for 3m; the maximum tag
|
||||||
|
is 255, and Scheme itself uses nearly 200.
|
||||||
|
|
||||||
|
After allocating a new tag in 3m (and before creating instances of the
|
||||||
|
tag), a @defterm{size procedure}, a @defterm{mark procedure}, and a
|
||||||
|
@defterm{fixup procedure} must be installed for the tag using
|
||||||
|
@cppi{GC_register_traversers}.
|
||||||
|
|
||||||
|
A size procedure simply takes a pointer to an object with the tag and
|
||||||
|
returns its size in words (not bytes). The @cppi{gcBYTES_TO_WORDS}
|
||||||
|
macro converts a byte count to a word count.
|
||||||
|
|
||||||
|
A mark procedure is used to trace references among objects without
|
||||||
|
moving any objects. The procedure takes a pointer to an object, and it
|
||||||
|
should apply the @cppi{gcMARK} macro to every pointer within the
|
||||||
|
object. The mark procedure should return the same result as the size
|
||||||
|
procedure.
|
||||||
|
|
||||||
|
A fixup procedure is used to update references to objects after or
|
||||||
|
while they are moved. The procedure takes a pointer to an object, and
|
||||||
|
it should apply the @cppi{gcFIXUP} macro to every pointer within the
|
||||||
|
object; the expansion of this macro takes the address of its
|
||||||
|
argument. The fixup procedure should return the same result as the
|
||||||
|
size procedure.
|
||||||
|
|
||||||
|
Depending on the collector's implementation, the mark or fixup
|
||||||
|
procedure might not be used. For example, the collector may only use
|
||||||
|
the mark procedure and not actually move the object. Or it may use the
|
||||||
|
fixup procedure to mark and move objects at the same time. To
|
||||||
|
dereference an object pointer during a fixup procedure, use
|
||||||
|
@cppi{GC_fixup_self} to convert the address passed to the procedure to
|
||||||
|
refer to the potentially moved object, and use @cppi{GC_resolve} to
|
||||||
|
convert an address that is not yet fixed up to determine the object's
|
||||||
|
current location.
|
||||||
|
|
||||||
|
When allocating a tagged object in 3m, the tag must be installed
|
||||||
|
immediately after the object is allocated---or, at least, before the
|
||||||
|
next possible collection.
|
||||||
|
|
||||||
|
@; - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
@subsection[#:tag "im:3m:stack"]{Local Pointers}
|
||||||
|
|
||||||
|
The 3m collector needs to know the address of every local or temporary
|
||||||
|
pointer within a function call at any point when a collection can be
|
||||||
|
triggered. Beware that nested function calls can hide temporary
|
||||||
|
pointers; for example, in
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
scheme_make_pair(scheme_make_pair(scheme_true, scheme_false),
|
||||||
|
scheme_make_pair(scheme_false, scheme_true))
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
the result from one @cpp{scheme_make_pair} call is on the stack or in
|
||||||
|
a register during the other call to @cpp{scheme_make_pair}; this
|
||||||
|
pointer must be exposed to the garbage collection and made subject to
|
||||||
|
update. Simply changing the code to
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
tmp = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
scheme_make_pair(tmp,
|
||||||
|
scheme_make_pair(scheme_false, scheme_true))
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
does not expose all pointers, since @cpp{tmp} must be evaluated before
|
||||||
|
the second call to @cpp{scheme_make_pair}. In general, the above code
|
||||||
|
must be converted to the form
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
tmp1 = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
tmp2 = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
scheme_make_pair(tmp1, tmp2);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
and this is converted form must be instrumented to register @cpp{tmp1}
|
||||||
|
and @cpp{tmp2}. The final result might be
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
Scheme_Object *tmp1 = NULL, *tmp2 = NULL, *result;
|
||||||
|
MZ_GC_DECL_REG(2);
|
||||||
|
|
||||||
|
MZ_GC_VAR_IN_REG(0, tmp1);
|
||||||
|
MZ_GC_VAR_IN_REG(1, tmp2);
|
||||||
|
MZ_GC_REG();
|
||||||
|
|
||||||
|
tmp1 = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
tmp2 = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
result = scheme_make_pair(tmp1, tmp2);
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Notice that @cpp{result} is not registered above. The
|
||||||
|
@cpp{MZ_GC_UNREG} macro cannot trigger a garbage collection, so the
|
||||||
|
@cpp{result} variable is never live during a potential
|
||||||
|
collection. Note also that @cpp{tmp1} and @cpp{tmp2} are initialized
|
||||||
|
with @cpp{NULL}, so that they always contain a pointer whenever a
|
||||||
|
collection is possible.
|
||||||
|
|
||||||
|
The @cppi{MZ_GC_DECL_REG} macro expands to a local-variable
|
||||||
|
declaration to hold information for the garbage collector. The
|
||||||
|
argument is the number of slots to provide for
|
||||||
|
registration. Registering a simple pointer requires a single slot,
|
||||||
|
whereas registering an array of pointers requires three slots. For
|
||||||
|
example, to register a pointer @cpp{tmp} and an array of 10
|
||||||
|
@cpp{char*}s:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
Scheme_Object *tmp1 = NULL;
|
||||||
|
char *a[10];
|
||||||
|
int i;
|
||||||
|
MZ_GC_DECL_REG(4);
|
||||||
|
|
||||||
|
MZ_GC_ARRAY_VAR_IN_REG(0, a, 10);
|
||||||
|
MZ_GC_VAR_IN_REG(3, tmp1);
|
||||||
|
/* Clear a before a potential GC: */
|
||||||
|
for (i = 0; i < 10; i++) a[i] = NULL;
|
||||||
|
...
|
||||||
|
f(a);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The @cppi{MZ_GC_ARRAY_VAR_IN_REG} macro registers a local array given
|
||||||
|
a starting slot, the array variable, and an array size. The
|
||||||
|
@cppi{MZ_GC_VAR_IN_REG} takes a slot and simple pointer variable. A
|
||||||
|
local variable or array must not be registered multiple times.
|
||||||
|
|
||||||
|
In the above example, the first argument to @cppi{MZ_GC_VAR_IN_REG} is
|
||||||
|
@cpp{3} because the information for @cpp{a} uses the first three
|
||||||
|
slots. Even if @cpp{a} is not used after the call to @cpp{f}, @cpp{a}
|
||||||
|
must be registered with the collector during the entire call to
|
||||||
|
@cpp{f}, because @cpp{f} presumably uses @cpp{a} until it returns.
|
||||||
|
|
||||||
|
The name used for a variable need not be immediate. Structure members
|
||||||
|
can be supplied as well:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
struct { void *s; int v; void *t; } x = {NULL, 0, NULL};
|
||||||
|
MZ_GC_DECL_REG(2);
|
||||||
|
|
||||||
|
MZ_GC_VAR_IN_REG(0, x.s);
|
||||||
|
MZ_GC_VAR_IN_REG(0, x.t);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
In general, the only constraint on the second argument to
|
||||||
|
@cppi{MZ_GC_VAR_IN_REG} or @cppi{MZ_GC_ARRAY_VAR_IN_REG} is that
|
||||||
|
@cpp{&} must produce the relevant address.
|
||||||
|
|
||||||
|
Pointer information is not actually registered with the collector
|
||||||
|
until the @cppi{MZ_GC_REG} macro is used. The @cppi{MZ_GC_UNREG} macro
|
||||||
|
de-registers the information. Each call to @cpp{MZ_GC_REG} must be
|
||||||
|
balanced by one call to @cpp{MZ_GC_UNREG}.
|
||||||
|
|
||||||
|
Pointer information need not be initialized with
|
||||||
|
@cppi{MZ_GC_VAR_IN_REG} and @cppi{MZ_GC_ARRAY_VAR_IN_REG} before
|
||||||
|
calling @cpp{MZ_GC_REG}, and the set of registered pointers can change
|
||||||
|
at any time---as long as all relevent pointers are registered when a
|
||||||
|
collection might occur. The following example recycles slots and
|
||||||
|
completely de-registers information when no pointers are relevant. The
|
||||||
|
example also illustrates how @cpp{MZ_GC_UNREG} is not needed when
|
||||||
|
control escapes from the function, such as when
|
||||||
|
@cpp{scheme_signal_error} escapes.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
Scheme_Object *tmp1 = NULL, *tmp2 = NULL;
|
||||||
|
mzchar *a, *b;
|
||||||
|
MZ_GC_DECL_REG(2);
|
||||||
|
|
||||||
|
MZ_GC_VAR_IN_REG(0, tmp1);
|
||||||
|
MZ_GC_VAR_IN_REG(1, tmp2);
|
||||||
|
|
||||||
|
tmp1 = scheme_make_utf8_string("foo");
|
||||||
|
MZ_GC_REG();
|
||||||
|
tmp2 = scheme_make_utf8_string("bar");
|
||||||
|
tmp1 = scheme_append_char_string(tmp1, tmp2);
|
||||||
|
|
||||||
|
if (SCHEME_FALSEP(tmp1))
|
||||||
|
scheme_signal_error("shouldn't happen!");
|
||||||
|
|
||||||
|
a = SCHEME_CHAR_VAL(tmp1);
|
||||||
|
|
||||||
|
MZ_GC_VAR_IN_REG(0, a);
|
||||||
|
|
||||||
|
tmp2 = scheme_make_pair(scheme_read_bignum(a, 0, 10), tmp2);
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
|
||||||
|
if (SCHEME_INTP(tmp2)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MZ_GC_REG();
|
||||||
|
tmp1 = scheme_make_pair(scheme_read_bignum(a, 0, 8), tmp2);
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
|
||||||
|
return tmp1;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
A @cpp{MZ_GC_DECL_REG} can be used in a nested block to hold
|
||||||
|
declarations for the block's variables. In that case, the nested
|
||||||
|
@cpp{MZ_GC_DECL_REG} must have its own @cpp{MZ_GC_REG} and
|
||||||
|
@cpp{MZ_GC_UNREG} calls.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
Scheme_Object *accum = NULL;
|
||||||
|
MZ_GC_DECL_REG(1);
|
||||||
|
MZ_GC_VAR_IN_REG(0, accum);
|
||||||
|
MZ_GC_REG();
|
||||||
|
|
||||||
|
accum = scheme_make_pair(scheme_true, scheme_null);
|
||||||
|
{
|
||||||
|
Scheme_Object *tmp = NULL;
|
||||||
|
MZ_GC_DECL_REG(1);
|
||||||
|
MZ_GC_VAR_IN_REG(0, tmp);
|
||||||
|
MZ_GC_REG();
|
||||||
|
|
||||||
|
tmp = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
accum = scheme_make_pair(tmp, accum);
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
}
|
||||||
|
accum = scheme_make_pair(scheme_true, accum);
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Variables declared in a local block can also be registered together
|
||||||
|
with variables from an enclosing block, but the local-block variable
|
||||||
|
must be unregistered before it goes out of scope. The
|
||||||
|
@cppi{MZ_GC_NO_VAR_IN_REG} macro can be used to unregister a variable
|
||||||
|
or to initialize a slot as having no variable.
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
{
|
||||||
|
Scheme_Object *accum = NULL;
|
||||||
|
MZ_GC_DECL_REG(2);
|
||||||
|
MZ_GC_VAR_IN_REG(0, accum);
|
||||||
|
MZ_GC_NO_VAR_IN_REG(1);
|
||||||
|
MZ_GC_REG();
|
||||||
|
|
||||||
|
accum = scheme_make_pair(scheme_true, scheme_null);
|
||||||
|
{
|
||||||
|
Scheme_Object *tmp = NULL;
|
||||||
|
MZ_GC_VAR_IN_REG(1, tmp);
|
||||||
|
|
||||||
|
tmp = scheme_make_pair(scheme_true, scheme_false);
|
||||||
|
accum = scheme_make_pair(tmp, accum);
|
||||||
|
|
||||||
|
MZ_GC_NO_VAR_IN_REG(1);
|
||||||
|
}
|
||||||
|
accum = scheme_make_pair(scheme_true, accum);
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The @cpp{MZ_GC_} macros all expand to nothing when @cpp{MZ_PRECISE_GC}
|
||||||
|
is not defined, so the macros can be placed into code to be compiled
|
||||||
|
for both conservative and precise collection.
|
||||||
|
|
||||||
|
The @cpp{MZ_GC_REG} and @cpp{MZ_GC_UNREG} macros must never be
|
||||||
|
used in an OS thread other than Scheme's thread.
|
||||||
|
|
||||||
|
@; - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
@subsection[#:tag "im:3m:mzc"]{Local Pointers and @|mzc| @DFlag{xform}}
|
||||||
|
|
||||||
|
When @|mzc| is run with the @DFlag{xform} flag and a source C program,
|
||||||
|
it produces a C program that is instrumented in the way described in
|
||||||
|
the previous section (but with a slightly different set of macros).
|
||||||
|
For each input file @filepath{@italic{name}.c}, the transformed output
|
||||||
|
is @filepath{@italic{name}.3m.c}.
|
||||||
|
|
||||||
|
The @DFlag{xform} mode for @|mzc| does not change allocation calls,
|
||||||
|
nor does it generate size, mark, or fixup predocures. It merely
|
||||||
|
converts the code to register local pointers.
|
||||||
|
|
||||||
|
Furthermore, the @DFlag{xform} mode for @|mzc| does not handle all of
|
||||||
|
C. It's ability to rearrange compound expressions is particularly
|
||||||
|
limited, because @DFlag{xform} merely converts expression text
|
||||||
|
heuristically instead of parsing C. A future version of the tool will
|
||||||
|
correct such problems. For now, @|mzc| in @DFlag{xform} mode attempts
|
||||||
|
to provide reasonable error messages when it is unable to convert a
|
||||||
|
program, but beware that it can miss cases. To an even more limited
|
||||||
|
degree, @DFlag{xform} can work on C++ code. Inspect the output of
|
||||||
|
@DFlag{xform} mode to ensure that your code is correctly instrumented.
|
||||||
|
|
||||||
|
Some specific limitations:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{The body of a @cpp{for}, @cpp{while}, or @cpp{do} loop must be
|
||||||
|
surrounded with curly braces. (A conversion error is normally
|
||||||
|
reported, otherwise.)}
|
||||||
|
|
||||||
|
@item{Function calls may not appear on the right-hand side of an
|
||||||
|
assignment within a declaration block. (A conversion error is
|
||||||
|
normally reported if such an assignment is discovered.)}
|
||||||
|
|
||||||
|
@item{Multiple function calls in @cpp{... ? ... : ...} cannot be
|
||||||
|
lifted. (A conversion error is normally reported, otherwise.)}
|
||||||
|
|
||||||
|
@item{In an assignment, the left-hand side must be a local or static
|
||||||
|
variable, not a field selection, pointer dereference, etc. (A
|
||||||
|
conversion error is normally reported, otherwise.)}
|
||||||
|
|
||||||
|
@item{The conversion assumes that all function calls use an immediate
|
||||||
|
name for a function, as opposed to a compound expression as
|
||||||
|
in @cpp{s->f()}. The function name need not be a top-level
|
||||||
|
function name, but it must be bound either as an argument or
|
||||||
|
local variable with the form @cpp{@var{type} @var{id}}; the
|
||||||
|
syntax @cpp{@var{ret_type} (*@var{id})(...)} is not
|
||||||
|
recgoinzed, so bind the function type to a simple name
|
||||||
|
with @cpp{typedef}, first: @cpp{typedef @var{ret_type}
|
||||||
|
(*@var{type})(...); .... @var{type} @var{id}}.}
|
||||||
|
|
||||||
|
@item{Arrays and structs must be passed by address, only.}
|
||||||
|
|
||||||
|
@item{GC-triggering code must not appear in system headers.}
|
||||||
|
|
||||||
|
@item{Pointer-comparison expressions are not handled correctly when
|
||||||
|
either of the compared expressions includes a function call.
|
||||||
|
For example, @cpp{a() == b()} is not converted correctly when
|
||||||
|
@cpp{a} and @cpp{b} produce pointer values.}
|
||||||
|
|
||||||
|
@item{Passing the address of a local pointer to a function works only
|
||||||
|
when the pointer variable remains live after the function call.}
|
||||||
|
|
||||||
|
@item{A @cpp{return;} form can get converted to @cpp["{ " @var{stmt}
|
||||||
|
"; return; };"], which can break an @cpp{if (...) return; else
|
||||||
|
...} pattern.}
|
||||||
|
|
||||||
|
@item{Local instances of union types are generally not supported.}
|
||||||
|
|
||||||
|
@item{Pointer arithmetic cannot be converted away, and is instead
|
||||||
|
reported as an error.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@; - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
@subsection[#:tag "im:3m:macros"]{Guiding @|mzc| @DFlag{xform}}
|
||||||
|
|
||||||
|
The following macros can be used (with care!) to navigate
|
||||||
|
@DFlag{xform} around code that it cannot handle:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_START_SKIP} and @cppi{XFORM_END_SKIP}: code
|
||||||
|
between these two statements is ignored by the transform tool,
|
||||||
|
except to tokenize it.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
int foo(int c, ...) {
|
||||||
|
int r = 0;
|
||||||
|
XFORM_START_SKIP;
|
||||||
|
{
|
||||||
|
/* va plays strange tricks that confuse xform */
|
||||||
|
va_list args;
|
||||||
|
va_start(args, c);
|
||||||
|
while (c--) {
|
||||||
|
r += va_arg(args, int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XFORM_END_SKIP;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
These macros can also be used at the top level, outside of any
|
||||||
|
function. Since they have to be terminated by a semi-colon, however,
|
||||||
|
top-level uses usually must be wrapped with @cpp{#ifdef
|
||||||
|
MZ_PRECISE_GC} and @cpp{#endif}; a semi-colon by itself at the
|
||||||
|
top level is not legal in C.}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_HIDE_EXPR}: a macro that takes wraps an expression to
|
||||||
|
disable processing of the expression.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
int foo(int c, ...) {
|
||||||
|
int r = 0;
|
||||||
|
{
|
||||||
|
/* va plays strange tricks that confuse xform */
|
||||||
|
XFORM_CAN_IGNORE va_list args; /* See below */
|
||||||
|
XFORM_HIDE_EXPR(va_start(args, c));
|
||||||
|
while (c--) {
|
||||||
|
r += XFORM_HIDE_EXPR(va_arg(args, int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_CAN_IGNORE}: a macro that acts like a type
|
||||||
|
modifier (must appear first) to indicate that a declared variable
|
||||||
|
can be treated as atomic. See above for an example.}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_START_SUSPEND} and @cppi{XFORM_END_SUSPEND}: for
|
||||||
|
use at the top level (outside of any function definition), and
|
||||||
|
similar to @cpp{XFORM_START_SKIP} and @cpp{XFORM_END_SKIP} in
|
||||||
|
that function and class bodies are not transformed. Type and
|
||||||
|
prototype information is still collected for use by later
|
||||||
|
transformations, however. These forms must be terminated by a
|
||||||
|
semi-colon.}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_START_TRUST_ARITH} and
|
||||||
|
@cppi{XFORM_END_TRUST_ARITH}: for use at the top level (outside
|
||||||
|
of any function definition) to disable warnings about pointer
|
||||||
|
arithmetic. Use only when you're absolutely certain that the garbage
|
||||||
|
collector cannot be pointers offset into the middle of a collectable
|
||||||
|
object. These forms must be terminated by a semi-colon.}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_TRUST_PLUS}: a replacement for @cpp{+} that does
|
||||||
|
not trigger pointer-arithmetic warnings. Use with care.}
|
||||||
|
|
||||||
|
@item{@cppi{XFORM_TRUST_MINUS}: a replacement for @cpp{-} that does
|
||||||
|
not trigger pointer-arithmetic warnings. Use with care.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@section{Memory Functions}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Allocates @var{n} bytes of collectable memory, initially filled with
|
||||||
|
zeros. In 3m, the allocated object is treated as an array of
|
||||||
|
pointers.}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_atomic
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Allocates @var{n} bytes of collectable memory containing no pointers
|
||||||
|
visible to the garbage collector. The object is @italic{not}
|
||||||
|
initialized to zeros.}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_uncollectable
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Non-3m, only. Allocates @var{n} bytes of uncollectable memory.}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_eternal
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Allocates uncollectable atomic memory. This function is equivalent to
|
||||||
|
@cpp{malloc}, except that the memory cannot be freed.}
|
||||||
|
|
||||||
|
@function[(void* scheme_calloc
|
||||||
|
[size_t num]
|
||||||
|
[size_t size])]{
|
||||||
|
|
||||||
|
Allocates @var{num} * @var{size} bytes of memory using @cpp{scheme_malloc}.}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_tagged
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_malloc}, but in 3m, the type tag determines how the
|
||||||
|
garbage collector traverses the object; see @secref["im:memoryalloc"].}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_allow_interior
|
||||||
|
[size_t n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_malloc}, but in 3m, pointers are allowed to
|
||||||
|
reference the middle of the object; see @secref["im:memoryalloc"].}
|
||||||
|
|
||||||
|
@function[(char* scheme_strdup
|
||||||
|
[char* str])]{
|
||||||
|
|
||||||
|
Copies the null-terminated string @var{str}; the copy is collectable.}
|
||||||
|
|
||||||
|
@function[(char* scheme_strdup_eternal
|
||||||
|
[char* str])]{
|
||||||
|
|
||||||
|
Copies the null-terminated string @var{str}; the copy will never be freed.}
|
||||||
|
|
||||||
|
@function[(void* scheme_malloc_fail_ok
|
||||||
|
[size_t size]
|
||||||
|
[size_t size])]{
|
||||||
|
|
||||||
|
Attempts to allocate @var{size} bytes using @var{mallocf}. If the
|
||||||
|
allocation fails, the @scheme[exn:misc:out-of-memory] exception is
|
||||||
|
raised.}
|
||||||
|
|
||||||
|
@function[(void** scheme_malloc_immobile_box
|
||||||
|
[void* p])]{
|
||||||
|
|
||||||
|
Allocates memory that is not garbage-collected and that does not move
|
||||||
|
(even with 3m), but whose first word contains a pointer to a
|
||||||
|
collectable object. The box is initialized with @var{p}, but the value
|
||||||
|
can be changed at any time. An immobile box must be explicitly freed
|
||||||
|
using @cpp{scheme_free_immobile_box}.}
|
||||||
|
|
||||||
|
@function[(void scheme_free_immobile_box
|
||||||
|
[void** b])]{
|
||||||
|
|
||||||
|
Frees an immobile box allocated with @cpp{scheme_malloc_immobile_box}.}
|
||||||
|
|
||||||
|
@function[(void scheme_register_extension_global
|
||||||
|
[void* ptr]
|
||||||
|
[long size])]{
|
||||||
|
|
||||||
|
Registers an extension's global variable that can contain Scheme
|
||||||
|
pointers. The address of the global is given in @var{ptr}, and its
|
||||||
|
size in bytes in @var{size}.In addition to global variables, this
|
||||||
|
function can be used to register any permanent memory that the
|
||||||
|
collector would otherwise treat as atomic. A garbage collection can
|
||||||
|
occur during the registration.}
|
||||||
|
|
||||||
|
@function[(void scheme_set_stack_base
|
||||||
|
[void* stack_addr]
|
||||||
|
[int no_auto_statics])]{
|
||||||
|
|
||||||
|
Overrides the GC's auto-determined stack base, and/or disables the
|
||||||
|
GC's automatic traversal of global and static variables. If
|
||||||
|
@var{stack_addr} is @cpp{NULL}, the stack base determined by the GC is
|
||||||
|
used. Otherwise, it should be the ``deepest'' memory address on the
|
||||||
|
stack where a collectable pointer might be stored. This function
|
||||||
|
should be called only once, and before any other @cpp{scheme_}
|
||||||
|
function is called. It never triggers a garbage collection.
|
||||||
|
|
||||||
|
The following example shows a typical use for setting the stack base:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int dummy;
|
||||||
|
scheme_set_stack_base(&dummy, 0);
|
||||||
|
real_main(argc, argv); /* calls scheme_basic_env(), etc. */
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]}
|
||||||
|
|
||||||
|
@function[(void scheme_set_stack_bounds
|
||||||
|
[void* stack_addr]
|
||||||
|
[void* stack_end]
|
||||||
|
[int no_auto_statics])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_set_stack_base}, except for the extra
|
||||||
|
@var{stack_end} argument. If @var{stack_end} is non-@cpp{NULL}, then
|
||||||
|
it corresponds to a point of C-stack growth after which Scheme
|
||||||
|
should attempt to handle stack overflow. The @var{stack_end} argument
|
||||||
|
should not correspond to the actual stack end, since detecting stack
|
||||||
|
overflow may take a few frames, and since handling stack overflow
|
||||||
|
requires a few frames.
|
||||||
|
|
||||||
|
If @var{stack_end} is @cpp{NULL}, then the stack end is computed
|
||||||
|
automatically: the stack size assumed to be the limit reported by
|
||||||
|
@cpp{getrlimit} under Unix and Mac OS X, or it is assumed to be 1 MB
|
||||||
|
under Windows; if this size is greater than 8 MB, then 8 MB is
|
||||||
|
assumed, instead; the size is decremented by 50000 bytes to cover a
|
||||||
|
large margin of error; finally, the size is subtracted from (for
|
||||||
|
stacks that grow down) or added to (for stacks that grow up) the stack
|
||||||
|
base in @var{stack_addr} or the auotmatically computed stack
|
||||||
|
base. Note that the 50000-byte margin of error is assumed to cover the
|
||||||
|
difference between the actual stack start and the reported stack base,
|
||||||
|
in addition to the margin needed for detecting and handling stack
|
||||||
|
overflow.}
|
||||||
|
|
||||||
|
@function[(void scheme_register_static
|
||||||
|
[void* ptr]
|
||||||
|
[long size])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_register_extension_global}, for use in embedding
|
||||||
|
applications in situations where the collector does not automatically
|
||||||
|
find static variables (i.e., when @cpp{scheme_set_stack_base} has
|
||||||
|
been called with a non-zero second argument).
|
||||||
|
|
||||||
|
The macro @cppi{MZ_REGISTER_STATIC} can be used directly on a static
|
||||||
|
variable. It expands to a comment if statics need not be registered,
|
||||||
|
and a call to @cpp{scheme_register_static} (with the address of the
|
||||||
|
static variable) otherwise.}
|
||||||
|
|
||||||
|
@function[(void scheme_weak_reference
|
||||||
|
[void** p])]{
|
||||||
|
|
||||||
|
Registers the pointer @var{*p} as a weak pointer; when no other
|
||||||
|
(non-weak) pointers reference the same memory as @var{*p} references,
|
||||||
|
then @var{*p} will be set to @cpp{NULL} by the garbage collector. The
|
||||||
|
value in @var{*p} may change, but the pointer remains weak with
|
||||||
|
respect to the value of @var{*p} at the time @var{p} was registered.}
|
||||||
|
|
||||||
|
@function[(void scheme_weak_reference_indirect
|
||||||
|
[void** p]
|
||||||
|
[void* v])]{
|
||||||
|
|
||||||
|
Like @cppi{scheme_weak_reference}, but @var{*p} is cleared
|
||||||
|
(regardless of its value) when there are no references to @var{v}.}
|
||||||
|
|
||||||
|
@function[(void scheme_register_finalizer
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data]
|
||||||
|
[fnl_proc* oldf]
|
||||||
|
[void** olddata])]{
|
||||||
|
|
||||||
|
Registers a callback function to be invoked when the memory @var{p}
|
||||||
|
would otherwise be garbage-collected, and when no ``will''-like
|
||||||
|
finalizers are registered for @var{p}.
|
||||||
|
|
||||||
|
The @cpp{fnl_proc} type is not actually defined, but it is equivalent
|
||||||
|
to
|
||||||
|
|
||||||
|
@verbatim[" typedef void (*fnl_proc)(void *p, void *data)"]
|
||||||
|
|
||||||
|
The @var{f} argument is the callback function; when it is called, it
|
||||||
|
will be passed the value @var{p} and the data pointer @var{data};
|
||||||
|
@var{data} can be anything --- it is only passed on to the callback
|
||||||
|
function. If @var{oldf} and @var{olddata} are not @cpp{NULL}, then
|
||||||
|
@var{*oldf} and @var{*olddata} are filled with the old callback
|
||||||
|
information (@var{f} and @var{data} will override this old callback).
|
||||||
|
|
||||||
|
To remove a registered finalizer, pass @cpp{NULL} for @var{f} and
|
||||||
|
@var{data}.
|
||||||
|
|
||||||
|
Note: registering a callback not only keeps @var{p} from collection
|
||||||
|
until the callback is invoked, but it also keeps @var{data} reachable
|
||||||
|
until the callback is invoked.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_finalizer
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Adds a finalizer to a chain of primitive finalizers. This chain is
|
||||||
|
separate from the single finalizer installed with
|
||||||
|
@cpp{scheme_register_finalizer}; all finalizers in the chain are
|
||||||
|
called immediately after a finalizer that is installed with
|
||||||
|
@cpp{scheme_register_finalizer}.
|
||||||
|
|
||||||
|
See @cpp{scheme_register_finalizer}, above, for information about
|
||||||
|
the arguments.
|
||||||
|
|
||||||
|
To remove an added finalizer, use @cpp{scheme_subtract_finalizer}.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_scheme_finalizer
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Installs a ``will''-like finalizer, similar to @scheme[will-register].
|
||||||
|
Scheme finalizers are called one at a time, requiring the collector
|
||||||
|
to prove that a value has become inaccessible again before calling
|
||||||
|
the next Scheme finalizer. Finalizers registered with
|
||||||
|
@cpp{scheme_register_finalizer} or @cpp{scheme_add_finalizer} are
|
||||||
|
not called until all Scheme finalizers have been exhausted.
|
||||||
|
|
||||||
|
See @cpp{scheme_register_finalizer}, above, for information about
|
||||||
|
the arguments.
|
||||||
|
|
||||||
|
There is currently no facility to remove a ``will''-like finalizer.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_finalizer_once
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_add_finalizer}, but if the combination @var{f} and
|
||||||
|
@var{data} is already registered as a (non-``will''-like) finalizer
|
||||||
|
for @var{p}, it is not added a second time.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_scheme_finalizer_once
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_add_scheme_finalizer}, but if the combination of
|
||||||
|
@var{f} and @var{data} is already registered as a ``will''-like
|
||||||
|
finalizer for @var{p}, it is not added a second time.}
|
||||||
|
|
||||||
|
@function[(void scheme_subtract_finalizer
|
||||||
|
[void* p]
|
||||||
|
[fnl_proc f]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Removes a finalizer that was installed with
|
||||||
|
@cpp{scheme_add_finalizer}.}
|
||||||
|
|
||||||
|
@function[(void scheme_remove_all_finalization
|
||||||
|
[void* p])]{
|
||||||
|
|
||||||
|
Removes all finalization (``will''-like or not) for @var{p}, including
|
||||||
|
wills added in Scheme with @scheme[will-register] and finalizers used
|
||||||
|
by custodians.}
|
||||||
|
|
||||||
|
@function[(void scheme_dont_gc_ptr
|
||||||
|
[void* p])]{
|
||||||
|
|
||||||
|
Keeps the collectable block @var{p} from garbage collection. Use this
|
||||||
|
procedure when a reference to @var{p} is be stored somewhere
|
||||||
|
inaccessible to the collector. Once the reference is no longer used
|
||||||
|
from the inaccessible region, de-register the lock with
|
||||||
|
@cpp{scheme_gc_ptr_ok}. A garbage collection can occur during the
|
||||||
|
registration.
|
||||||
|
|
||||||
|
This function keeps a reference count on the pointers it registers, so
|
||||||
|
two calls to @cppi{scheme_dont_gc_ptr} for the same @var{p} should
|
||||||
|
be balanced with two calls to @cpp{scheme_gc_ptr_ok}.}
|
||||||
|
|
||||||
|
@function[(void scheme_gc_ptr_ok
|
||||||
|
[void* p])]{
|
||||||
|
|
||||||
|
See @cpp{scheme_dont_gc_ptr}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_collect_garbage)]{
|
||||||
|
|
||||||
|
Forces an immediate garbage-collection.}
|
||||||
|
|
||||||
|
@function[(void GC_register_traversers
|
||||||
|
[short tag]
|
||||||
|
[Size_Proc s]
|
||||||
|
[Mark_Proc m]
|
||||||
|
[Fixup_Proc f]
|
||||||
|
[int is_const_size]
|
||||||
|
[int is_atomic])]{
|
||||||
|
|
||||||
|
3m only. Registers a size, mark, and fixup procedure for a given type
|
||||||
|
tag; see @secref["im:3m:tagged"] for more information.
|
||||||
|
|
||||||
|
Each of the three procedures takes a pointer and returns an integer:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef int (*Size_Proc)(void *obj);
|
||||||
|
typedef int (*Mark_Proc)(void *obj);
|
||||||
|
typedef int (*Fixup_Proc)(void *obj);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
If the result of the size procedure is a constant, then pass a
|
||||||
|
non-zero value for @var{is_const_size}. If the mark and fixup
|
||||||
|
procedures are no-ops, then pass a non-zero value
|
||||||
|
for @var{is_atomic}.
|
||||||
|
|
||||||
|
}
|
293
collects/scribblings/inside/misc.scrbl
Normal file
293
collects/scribblings/inside/misc.scrbl
Normal file
|
@ -0,0 +1,293 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Miscellaneous Utilities}
|
||||||
|
|
||||||
|
The @cppi{MZSCHEME_VERSION} preprocessor macro is defined as a string
|
||||||
|
describing the version of Scheme. The @cppi{MZSCHEME_VERSION_MAJOR}
|
||||||
|
and @cppi{MZSCHEME_VERSION_MINOR} macros are defined as the major and
|
||||||
|
minor version numbers, respectively.
|
||||||
|
|
||||||
|
@function[(int scheme_eq
|
||||||
|
[Scheme_Object* obj1]
|
||||||
|
[Scheme_Object* obj2])]{
|
||||||
|
|
||||||
|
Returns 1 if the Scheme values are @scheme[eq?].}
|
||||||
|
|
||||||
|
@function[(int scheme_eqv
|
||||||
|
[Scheme_Object* obj1]
|
||||||
|
[Scheme_Object* obj2])]{
|
||||||
|
|
||||||
|
Returns 1 if the Scheme values are @scheme[eqv?].}
|
||||||
|
|
||||||
|
@function[(int scheme_equal
|
||||||
|
[Scheme_Object* obj1]
|
||||||
|
[Scheme_Object* obj2])]{
|
||||||
|
|
||||||
|
Returns 1 if the Scheme values are @scheme[equal?].}
|
||||||
|
|
||||||
|
@function[(long scheme_equal_hash_key
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object** elems])]{
|
||||||
|
|
||||||
|
Creates and returns a list of length @var{c} with the elements
|
||||||
|
@var{elems}.}
|
||||||
|
|
||||||
|
@function[(int scheme_list_length
|
||||||
|
[Scheme_Object* list])]{
|
||||||
|
|
||||||
|
Returns the length of the list. If @var{list} is not a proper list,
|
||||||
|
then the last @scheme[cdr] counts as an item. If there is a cycle in
|
||||||
|
@var{list} (involving only @scheme[cdr]s), this procedure will not
|
||||||
|
terminate.}
|
||||||
|
|
||||||
|
@function[(int scheme_proper_list_length
|
||||||
|
[Scheme_Object* list])]{
|
||||||
|
|
||||||
|
Returns the length of the list, or -1 if it is not a proper list. If
|
||||||
|
there is a cycle in @var{list} (involving only @scheme[cdr]s), this
|
||||||
|
procedure returns -1.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_car
|
||||||
|
[Scheme_Object* pair])]{
|
||||||
|
|
||||||
|
Returns the @scheme[car] of the pair.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_cdr
|
||||||
|
[Scheme_Object* pair])]{
|
||||||
|
|
||||||
|
Returns the @scheme[cdr] of the pair.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_cadr
|
||||||
|
[Scheme_Object* pair])]{
|
||||||
|
|
||||||
|
Returns the @scheme[cadr] of the pair.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_caddr
|
||||||
|
[Scheme_Object* pair])]{
|
||||||
|
|
||||||
|
Returns the @scheme[caddr] of the pair.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_vector_to_list
|
||||||
|
[Scheme_Object* vec])]{
|
||||||
|
|
||||||
|
Creates a list with the same elements as the given vector.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_list_to_vector
|
||||||
|
[Scheme_Object* list])]{
|
||||||
|
|
||||||
|
Creates a vector with the same elements as the given list.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_append
|
||||||
|
[Scheme_Object* lstx]
|
||||||
|
[Scheme_Object* lsty])]{
|
||||||
|
|
||||||
|
Non-destructively appends the given lists.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_unbox
|
||||||
|
[Scheme_Object* obj])]{
|
||||||
|
|
||||||
|
Returns the contents of the given box.}
|
||||||
|
|
||||||
|
@function[(void scheme_set_box
|
||||||
|
[Scheme_Object* b]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Sets the contents of the given box.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_load
|
||||||
|
[char* file])]{
|
||||||
|
|
||||||
|
Loads the specified Scheme file, returning the value of the last
|
||||||
|
expression loaded, or @cpp{NULL} if the load fails.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_load_extension
|
||||||
|
[char* filename])]{
|
||||||
|
|
||||||
|
Loads the specified Scheme extension file, returning the value provided
|
||||||
|
by the extension's initialization function.}
|
||||||
|
|
||||||
|
@function[(Scheme_Hash_Table* scheme_make_hash_table
|
||||||
|
[int type])]{
|
||||||
|
|
||||||
|
Creates a hash table. The @var{type} argument must be either
|
||||||
|
@cppi{SCHEME_hash_ptr} or @cppi{SCHEME_hash_string}, which determines
|
||||||
|
how keys are compared (unless the hash and compare functions are
|
||||||
|
modified in the hash table record; see below). A @cpp{SCHEME_hash_ptr}
|
||||||
|
table hashes on a key's pointer address, while
|
||||||
|
@cpp{SCHEME_hash_string} uses a key as a @cpp{char*} and hashes on the
|
||||||
|
null-terminated string content. Since a hash table created with
|
||||||
|
@cpp{SCHEME_hash_string} (instead of @cpp{SCHEME_hash_ptr}) does not
|
||||||
|
use a key as a Scheme value, it cannot be used from Scheme code.
|
||||||
|
|
||||||
|
Although the hash table interface uses the type @cpp{Scheme_Object*}
|
||||||
|
for both keys and values, the table functions never inspect values,
|
||||||
|
and they inspect keys only for @cpp{SCHEME_hash_string} hashing. Thus,
|
||||||
|
the actual types of the values (and keys, for @cpp{SCHEME_hash_ptr}
|
||||||
|
tables) can be anything.
|
||||||
|
|
||||||
|
The public portion of the @cppi{Scheme_Hash_Table} type is defined
|
||||||
|
roughly as follows:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef struct Scheme_Hash_Table {
|
||||||
|
Scheme_Object so; /* so.type == scheme_hash_table_type */
|
||||||
|
/* ... */
|
||||||
|
int size; /* size of keys and vals arrays */
|
||||||
|
int count; /* number of mapped keys */
|
||||||
|
Scheme_Object **keys;
|
||||||
|
Scheme_Object **vals;
|
||||||
|
void (*make_hash_indices)(void *v, long *h1, long *h2);
|
||||||
|
int (*compare)(void *v1, void *v2);
|
||||||
|
/* ... */
|
||||||
|
} Scheme_Hash_Table;
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The @cpp{make_hash_indices} and @cpp{compare} function pointers can be
|
||||||
|
set to arbitrary hashing and comparison functions (before any mapping
|
||||||
|
is installed into the table). A hash function should fill @var{h1}
|
||||||
|
with a primary hash value and @var{h2} with a secondary hash value;
|
||||||
|
the values are for double-hashing, where the caller takes appropriate
|
||||||
|
modulos.
|
||||||
|
|
||||||
|
To traverse the hash table content, iterate over @var{keys} and
|
||||||
|
@var{vals} in parallel from @cpp{0} to @cpp{size-1}, and ignore
|
||||||
|
@var{keys} where the corresponding @var{vals} entry is @cpp{NULL}.
|
||||||
|
The @cpp{count} field indicates the number of non-@cpp{NULL} values
|
||||||
|
that will be encountered.}
|
||||||
|
|
||||||
|
@function[(Scheme_Hash_Table* scheme_make_hash_table_equal)]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_hash_table}, except that keys are treated as
|
||||||
|
Scheme values and hashed based on @scheme[equal?]\ instead of
|
||||||
|
@scheme[eq?].}
|
||||||
|
|
||||||
|
@function[(void scheme_hash_set
|
||||||
|
[Scheme_Hash_Table* table]
|
||||||
|
[Scheme_Object* key]
|
||||||
|
[Scheme_Object* val])]{
|
||||||
|
|
||||||
|
Sets the current value for @var{key} in @var{table} to @var{val}. If
|
||||||
|
@var{val} is @cpp{NULL}, the @var{key} is unmapped in @var{table}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_hash_get
|
||||||
|
[Scheme_Hash_Table* table]
|
||||||
|
[Scheme_Object* key])]{
|
||||||
|
|
||||||
|
Returns the current value for @var{key} in @var{table}, or @cpp{NULL}
|
||||||
|
if @var{key} has no value.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Bucket_Table* scheme_make_bucket_table
|
||||||
|
[int size_hint]
|
||||||
|
[int type])]{
|
||||||
|
|
||||||
|
Like @cpp{make_hash_table}, but bucket tables are somewhat more
|
||||||
|
flexible, in that hash buckets are accessible and weak keys are
|
||||||
|
supported. (They also consume more space than hash tables.)
|
||||||
|
|
||||||
|
The @var{type} argument must be either @cppi{SCHEME_hash_ptr},
|
||||||
|
@cppi{SCHEME_hash_string}, or @cppi{SCHEME_hash_weak_ptr}. The first
|
||||||
|
two are the same as for hash tables. The last is like
|
||||||
|
@cpp{SCHEME_hash_ptr}, but the keys are weakly held.
|
||||||
|
|
||||||
|
The public portion of the @cppi{Scheme_Bucket_Table} type is defined
|
||||||
|
roughly as follows:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef struct Scheme_Bucket_Table {
|
||||||
|
Scheme_Object so; /* so.type == scheme_variable_type */
|
||||||
|
/* ... */
|
||||||
|
int size; /* size of buckets array */
|
||||||
|
int count; /* number of buckets, >= number of mapped keys */
|
||||||
|
Scheme_Bucket **buckets;
|
||||||
|
void (*make_hash_indices)(void *v, long *h1, long *h2);
|
||||||
|
int (*compare)(void *v1, void *v2);
|
||||||
|
/* ... */
|
||||||
|
} Scheme_Bucket_Table;
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The @cpp{make_hash_indices} and @cpp{compare} functions are used as
|
||||||
|
for hash tables. Note that @cppi{SCHEME_hash_weak_ptr} supplied as the
|
||||||
|
initial type makes keys weak even if the hash and comparison functions
|
||||||
|
are changed.
|
||||||
|
|
||||||
|
See @cpp{scheme_bucket_from_table} for information on buckets.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_to_table
|
||||||
|
[Scheme_Bucket_Table* table]
|
||||||
|
[const-char* key]
|
||||||
|
[void* val]
|
||||||
|
[int const])]{
|
||||||
|
|
||||||
|
Sets the current value for @var{key} in @var{table} to @var{val}. If
|
||||||
|
@var{const} is non-zero, the value for @var{key} must never be
|
||||||
|
changed.}
|
||||||
|
|
||||||
|
@function[(void scheme_change_in_table
|
||||||
|
[Scheme_Bucket_Table* table]
|
||||||
|
[const-char* key]
|
||||||
|
[void* val])]{
|
||||||
|
|
||||||
|
Sets the current value for @var{key} in @var{table} to @var{val}, but
|
||||||
|
only if @var{key} is already mapped in the table.}
|
||||||
|
|
||||||
|
@function[(void* scheme_lookup_in_table
|
||||||
|
[Scheme_Bucket_Table* table]
|
||||||
|
[const-char* key])]{
|
||||||
|
|
||||||
|
Returns the current value for @var{key} in @var{table}, or @cpp{NULL}
|
||||||
|
if @var{key} has no value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Bucket* scheme_bucket_from_table
|
||||||
|
[Scheme_Bucket_Table* table]
|
||||||
|
[const-char* key])]{
|
||||||
|
|
||||||
|
Returns the bucket for @var{key} in @var{table}. The
|
||||||
|
@cppi{Scheme_Bucket} structure is defined as:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef struct Scheme_Bucket {
|
||||||
|
Scheme_Object so; /* so.type == scheme_bucket_type */
|
||||||
|
/* ... */
|
||||||
|
void *key;
|
||||||
|
void *val;
|
||||||
|
} Scheme_Bucket;
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Setting @var{val} to @cpp{NULL} unmaps the bucket's key, and @var{key}
|
||||||
|
can be @cpp{NULL} in that case as well. If the table holds keys
|
||||||
|
weakly, then @var{key} points to a (weak) pointer to the actual key,
|
||||||
|
and the weak pointer's value can be @cpp{NULL}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(long scheme_double_to_int
|
||||||
|
[char* where]
|
||||||
|
[double d])]{
|
||||||
|
|
||||||
|
Returns a fixnum value for the given floating-point number @var{d}. If @var{d}
|
||||||
|
is not an integer or if it is too large, then an error message is
|
||||||
|
reported; @var{name} is used for error-reporting.}
|
||||||
|
|
||||||
|
@function[(long scheme_get_milliseconds)]{
|
||||||
|
|
||||||
|
Returns the current ``time'' in milliseconds, just like
|
||||||
|
@scheme[current-milliseconds].}
|
||||||
|
|
||||||
|
@function[(long scheme_get_process_milliseconds)]{
|
||||||
|
|
||||||
|
Returns the current process ``time'' in milliseconds, just like
|
||||||
|
@scheme[current-process-milliseconds].}
|
||||||
|
|
||||||
|
@function[(char* scheme_banner)]{
|
||||||
|
|
||||||
|
Returns the string that is used as the Scheme startup banner.}
|
||||||
|
|
||||||
|
@function[(char* scheme_version)]{
|
||||||
|
|
||||||
|
Returns a string for the executing version of Scheme.}
|
145
collects/scribblings/inside/namespaces.scrbl
Normal file
145
collects/scribblings/inside/namespaces.scrbl
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "im:env"]{Namespaces and Modules}
|
||||||
|
|
||||||
|
A Scheme namespace (a top-level environment) is represented by a value
|
||||||
|
of type @cppi{Scheme_Env*} --- which is also a Scheme value, castable
|
||||||
|
to @cpp{Scheme_Object*}. Calling @cppi{scheme_basic_env} returns a
|
||||||
|
namespace that includes all of Scheme's standard global procedures
|
||||||
|
and syntax.
|
||||||
|
|
||||||
|
The @cpp{scheme_basic_env} function must be called once by an
|
||||||
|
embedding program, before any other PLT Scheme function is called
|
||||||
|
(except @cpp{scheme_make_param}). The returned namespace is the
|
||||||
|
initial current namespace for the main Scheme thread. Scheme
|
||||||
|
extensions cannot call @cpp{scheme_basic_env}.
|
||||||
|
|
||||||
|
The current thread's current namespace is available from
|
||||||
|
@cppi{scheme_get_env}, given the current parameterization (see
|
||||||
|
@secref["config"]): @cpp{scheme_get_env(scheme_config)}.
|
||||||
|
|
||||||
|
New values can be added as @as-index{globals} in a namespace using
|
||||||
|
@cppi{scheme_add_global}. The @cppi{scheme_lookup_global} function
|
||||||
|
takes a Scheme symbol and returns the global value for that name, or
|
||||||
|
@cpp{NULL} if the symbol is undefined.
|
||||||
|
|
||||||
|
A @as-index{module}'s set of top-level bindings is implemented using
|
||||||
|
the same machinery as a namespace. Use @cppi{scheme_primitive_module}
|
||||||
|
to create a new @cpp{Scheme_Env*} that represents a primitive
|
||||||
|
module. The name provided to @cppi{scheme_primitive_module} is subject
|
||||||
|
to prefixing through the @scheme[current-module-name-prefix] parameter
|
||||||
|
(which is normally set by the module name resolver when auto-loading
|
||||||
|
module files). After installing variables into the module with
|
||||||
|
@cppi{scheme_add_global}, etc., call
|
||||||
|
@cppi{scheme_finish_primitive_module} on the @cpp{Scheme_Env*} value
|
||||||
|
to make the module declaration available. All defined variables are
|
||||||
|
exported from the primitive module.
|
||||||
|
|
||||||
|
The Scheme @indexed-scheme[#%variable-reference] form produces a value
|
||||||
|
that is opaque to Scheme code. Use @cpp{SCHEME_PTR_VAL} on the result
|
||||||
|
of @scheme[#%variable-reference] to obtain the same kind of value as
|
||||||
|
returned by @cpp{scheme_global_bucket} (i.e., a bucket containing the
|
||||||
|
variable's value, or @cpp{NULL} if the variable is not yet defined).
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@function[(void scheme_add_global
|
||||||
|
[char* name]
|
||||||
|
[Scheme_Object* val]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Adds a value to the table of globals for the namespace @var{env},
|
||||||
|
where @var{name} is a null-terminated string. (The string's case will
|
||||||
|
be normalized in the same way as for interning a symbol.)}
|
||||||
|
|
||||||
|
@function[(void scheme_add_global_symbol
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[Scheme_Object* val]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Adds a value to the table of globals by symbol name instead of string
|
||||||
|
name.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_lookup_global
|
||||||
|
[Scheme_Object* symbol]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Given a global variable name (as a symbol) in @var{sym}, returns the current
|
||||||
|
value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Bucket* scheme_global_bucket
|
||||||
|
[Scheme_Object* symbol]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Given a global variable name (as a symbol) in @var{sym}, returns the bucket
|
||||||
|
where the value is stored. When the value in this bucket is @cpp{NULL}, then
|
||||||
|
the global variable is undefined.
|
||||||
|
|
||||||
|
The @cppi{Scheme_Bucket} structure is defined as:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef struct Scheme_Bucket {
|
||||||
|
Scheme_Object so; /* so.type = scheme_variable_type */
|
||||||
|
void *key;
|
||||||
|
void *val;
|
||||||
|
} Scheme_Bucket;
|
||||||
|
EOS
|
||||||
|
]}
|
||||||
|
|
||||||
|
@function[(Scheme_Bucket* scheme_module_bucket
|
||||||
|
[Scheme_Object* mod]
|
||||||
|
[Scheme_Object* symbol]
|
||||||
|
[int pos]
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_global_bucket}, but finds a variable in a
|
||||||
|
module. The @var{mod} and @var{symbol} arguments are as for
|
||||||
|
@scheme[dynamic-require] in Scheme. The @var{pos} argument should be
|
||||||
|
@cpp{-1} always. The @var{env} argument represents the namespace in
|
||||||
|
which the module is declared.}
|
||||||
|
|
||||||
|
@function[(void scheme_set_global_bucket
|
||||||
|
[char* procname]
|
||||||
|
[Scheme_Bucket* var]
|
||||||
|
[Scheme_Object* val]
|
||||||
|
[int set_undef])]{
|
||||||
|
|
||||||
|
Changes the value of a global variable. The @var{procname} argument is
|
||||||
|
used to report errors (in case the global variable is constant, not
|
||||||
|
yet bound, or bound as syntax). If @var{set_undef} is not 1, then the
|
||||||
|
global variable must already have a binding. (For example,
|
||||||
|
@scheme[set!] cannot set unbound variables, while @scheme[define]
|
||||||
|
can.)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_builtin_value
|
||||||
|
[const-char* name])]{
|
||||||
|
|
||||||
|
Gets the binding of a name as it would be defined in the initial
|
||||||
|
namespace.}
|
||||||
|
|
||||||
|
@function[(Scheme_Env* scheme_get_env
|
||||||
|
[Scheme_Config* config])]{
|
||||||
|
|
||||||
|
Returns the current namespace for the given parameterization (see
|
||||||
|
@secref["config"]). The current thread's current parameterization is
|
||||||
|
available as @cppi{scheme_config}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Env* scheme_primitive_module
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[Scheme_Env* for_env])]{
|
||||||
|
|
||||||
|
Prepares a new primitive module whose name is the symbol @var{name} (plus any
|
||||||
|
prefix that is active via @scheme[current-module-name-prefix]). The
|
||||||
|
module will be declared within the namespace @var{for_env}. The
|
||||||
|
result is a @cpp{Scheme_Env *} value that can be used with
|
||||||
|
@cpp{scheme_add_global}, etc., but it represents a module instead
|
||||||
|
of a namespace. The module is not fully declared until
|
||||||
|
@cpp{scheme_finish_primitive_module} is called, at which point all
|
||||||
|
variables defined in the module become exported.}
|
||||||
|
|
||||||
|
@function[(void scheme_finish_primitive_module
|
||||||
|
[Scheme_Env* env])]{
|
||||||
|
|
||||||
|
Finalizes a primitive module and makes it available for use within the
|
||||||
|
module's namespace.}
|
165
collects/scribblings/inside/numbers.scrbl
Normal file
165
collects/scribblings/inside/numbers.scrbl
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Bignums, Rationals, and Complex Numbers}
|
||||||
|
|
||||||
|
Scheme supports integers of an arbitrary magnitude; when an integer
|
||||||
|
cannot be represented as a fixnum (i.e., 30 or 62 bits plus a sign
|
||||||
|
bit), then it is represented by the Scheme type
|
||||||
|
@cppi{scheme_bignum_type}. There is no overlap in integer values
|
||||||
|
represented by fixnums and bignums.
|
||||||
|
|
||||||
|
Rationals are implemented by the type @cppi{scheme_rational_type},
|
||||||
|
composed of a numerator and a denominator.
|
||||||
|
The numerator and denominator fixnums or bignums (possibly mixed).
|
||||||
|
|
||||||
|
Complex numbers are implemented by the types
|
||||||
|
@cppi{scheme_complex_type} and @cppi{scheme_complex_izi_type},
|
||||||
|
composed of a real and imaginary part. The real and imaginary parts
|
||||||
|
will either be both flonums, both exact numbers (fixnums, bignums, and
|
||||||
|
rationals can be mixed in any way), or one part will be exact 0 and
|
||||||
|
the other part will be a flonum. If the inexact part is inexact 0, the
|
||||||
|
type is @cpp{scheme_complex_izi_type}, otherwise the type is
|
||||||
|
@cppi{scheme_complex_type}; this distinction make it easy to test
|
||||||
|
whether a complex number should be treated as a real number.
|
||||||
|
|
||||||
|
|
||||||
|
@function[(int scheme_is_exact
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns @cpp{1} if @var{n} is an exact number, @scheme[0] otherwise
|
||||||
|
(@var{n} need not be a number).}
|
||||||
|
|
||||||
|
@function[(int scheme_is_inexact
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns @cpp{1} if @var{n} is an inexact number, @scheme[0] otherwise
|
||||||
|
(@var{n} need not be a number).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_bignum
|
||||||
|
[long v])]{
|
||||||
|
|
||||||
|
Creates a bignum representing the integer @var{v}. This can create a
|
||||||
|
bignum that otherwise fits into a fixnum. This must only be used to
|
||||||
|
create temporary values for use with the @cpp{bignum} functions. Final
|
||||||
|
results can be normalized with @cpp{scheme_bignum_normalize}. Only
|
||||||
|
normalized numbers can be used with procedures that are not specific
|
||||||
|
to bignums.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_bignum_from_unsigned
|
||||||
|
[unsigned-long v])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_bignum}, but works on unsigned integers.}
|
||||||
|
|
||||||
|
@function[(double scheme_bignum_to_double
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Converts a bignum to a floating-point number, with reasonable but
|
||||||
|
unspecified accuracy.}
|
||||||
|
|
||||||
|
@function[(float scheme_bignum_to_float
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
If PLT Scheme is not compiled with single-precision floats, this procedure
|
||||||
|
is actually a macro alias for @cpp{scheme_bignum_to_double}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_bignum_from_double
|
||||||
|
[double d])]{
|
||||||
|
|
||||||
|
Creates a bignum that is close in magnitude to the floating-point
|
||||||
|
number @var{d}. The conversion accuracy is reasonable but unspecified.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_bignum_from_float
|
||||||
|
[float f])]{
|
||||||
|
|
||||||
|
If PLT Scheme is not compiled with single-precision floats, this procedure
|
||||||
|
is actually a macro alias for @cpp{scheme_bignum_from_double}.}
|
||||||
|
|
||||||
|
@function[(char* scheme_bignum_to_string
|
||||||
|
[Scheme_Object* n]
|
||||||
|
[int radix])]{
|
||||||
|
|
||||||
|
Writes a bignum into a newly allocated byte string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_read_bignum
|
||||||
|
[mzchar* str]
|
||||||
|
[int offset]
|
||||||
|
[int radix])]{
|
||||||
|
|
||||||
|
Reads a bignum from a @cpp{mzchar} string, starting from position
|
||||||
|
@var{offset} in @var{str}. If the string does not represent an
|
||||||
|
integer, then @cpp{NULL} will be returned. If the string represents a
|
||||||
|
number that fits in 31 bits, then a @cpp{scheme_integer_type}
|
||||||
|
object will be returned.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_read_bignum_bytes
|
||||||
|
[char* str]
|
||||||
|
[int offset]
|
||||||
|
[int radix])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_read_bignum}, but from a UTF-8-encoding byte string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_bignum_normalize
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
If @var{n} fits in 31 bits, then a @cpp{scheme_integer_type} object
|
||||||
|
will be returned. Otherwise, @var{n} is returned.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_rational
|
||||||
|
[Scheme_Object* n]
|
||||||
|
[Scheme_Object* d])]{
|
||||||
|
|
||||||
|
Creates a rational from a numerator and denominator. The @var{n} and
|
||||||
|
@var{d} parameters must be fixnums or bignums (possibly mixed). The
|
||||||
|
resulting will be normalized (thus, a bignum or fixnum might be returned).}
|
||||||
|
|
||||||
|
@function[(double scheme_rational_to_double
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Converts the rational @var{n} to a @cpp{double}.}
|
||||||
|
|
||||||
|
@function[(float scheme_rational_to_float
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
If PLT Scheme is not compiled with single-precision floats, this procedure
|
||||||
|
is actually a macro alias for @cpp{scheme_rational_to_double}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_rational_numerator
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns the numerator of the rational @var{n}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_rational_denominator
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns the denominator of the rational @var{n}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_rational_from_double
|
||||||
|
[double d])]{
|
||||||
|
|
||||||
|
Converts the given @cpp{double} into a maximally-precise rational.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_rational_from_float
|
||||||
|
[float d])]{
|
||||||
|
|
||||||
|
If PLT Scheme is not compiled with single-precision floats, this procedure
|
||||||
|
is actually a macro alias for @cpp{scheme_rational_from_double}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_complex
|
||||||
|
[Scheme_Object* r]
|
||||||
|
[Scheme_Object* i])]{
|
||||||
|
|
||||||
|
Creates a complex number from real and imaginary parts. The @var{r}
|
||||||
|
and @var{i} arguments must be fixnums, bignums, flonums, or rationals
|
||||||
|
(possibly mixed). The resulting number will be normalized (thus, a real
|
||||||
|
number might be returned).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_complex_real_part
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns the real part of the complex number @var{n}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_complex_imaginary_part
|
||||||
|
[Scheme_Object* n])]{
|
||||||
|
|
||||||
|
Returns the imaginary part of the complex number @var{n}.}
|
556
collects/scribblings/inside/overview.scrbl
Normal file
556
collects/scribblings/inside/overview.scrbl
Normal file
|
@ -0,0 +1,556 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Overview}
|
||||||
|
|
||||||
|
@section{CGC versus 3m}
|
||||||
|
|
||||||
|
Before mixing any C code with MzScheme, first decide whether to use
|
||||||
|
the @bold{3m} variant of PLT Scheme, the @bold{CGC} variant of PLT
|
||||||
|
Scheme, or both:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@bold{@as-index{3m}} : the main variant of PLT Scheme, which
|
||||||
|
uses @defterm{precise} garbage collection instead of conservative
|
||||||
|
garbage collection, and it may move objects in memory during a
|
||||||
|
collection.}
|
||||||
|
|
||||||
|
@item{@bold{@as-index{CGC}} : the original variant of PLT Scheme,
|
||||||
|
where memory management depends on a @defterm{conservative} garbage
|
||||||
|
collector. The conservative garbage collector can automatically find
|
||||||
|
references to managed values from C local variables and (on some
|
||||||
|
platforms) static variables.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
At the C level, working with CGC can be much easier than working with
|
||||||
|
3m, but overall system performance is typically better with 3m.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Writing MzScheme Extensions}
|
||||||
|
|
||||||
|
@section-index["extending MzScheme"]
|
||||||
|
|
||||||
|
The process of creating an extension for 3m or CGC is essentially the
|
||||||
|
same, but the process for 3m is most easily understood as a variant of
|
||||||
|
the process for CGC.
|
||||||
|
|
||||||
|
@subsection{CGC Extensions}
|
||||||
|
|
||||||
|
|
||||||
|
To write a C/C++-based extension for PLT Scheme CGC, follow these
|
||||||
|
steps:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@index['("header files")]{For} each C/C++ file that uses PLT
|
||||||
|
Scheme library functions, @cpp{#include} the file
|
||||||
|
@as-index{@filepath{escheme.h}}.
|
||||||
|
|
||||||
|
This file is distributed with the PLT software in an
|
||||||
|
@filepath{include} directory, but if @|mzc| is used to compile, this
|
||||||
|
path is found automatically.}
|
||||||
|
|
||||||
|
|
||||||
|
@item{Define the C function @cppi{scheme_initialize}, which takes a
|
||||||
|
@cpp{Scheme_Env*} namespace (see @secref["im:env"]) and returns a
|
||||||
|
@cpp{Scheme_Object*} Scheme value.
|
||||||
|
|
||||||
|
This initialization function can install new global primitive
|
||||||
|
procedures or other values into the namespace, or it can simply
|
||||||
|
return a Scheme value. The initialization function is called when the
|
||||||
|
extension is loaded with @scheme[load-extension] (the first time);
|
||||||
|
the return value from @cpp{scheme_initialize} is used as the return
|
||||||
|
value for @scheme[load-extension]. The namespace provided to
|
||||||
|
@cpp{scheme_initialize} is the current namespace when
|
||||||
|
@scheme[load-extension] is called.}
|
||||||
|
|
||||||
|
|
||||||
|
@item{Define the C function @cppi{scheme_reload}, which has the same
|
||||||
|
arguments and return type as @cpp{scheme_initialize}.
|
||||||
|
|
||||||
|
This function is called if @scheme[load-extension] is called a second
|
||||||
|
time (or more times) for an extension. Like @cpp{scheme_initialize},
|
||||||
|
the return value from this function is the return value for
|
||||||
|
@scheme[load-extension].}
|
||||||
|
|
||||||
|
|
||||||
|
@item{Define the C function @cppi{scheme_module_name}, which takes
|
||||||
|
no arguments and returns a @cpp{Scheme_Object*} value, either a
|
||||||
|
symbol or @cpp{scheme_false}.
|
||||||
|
|
||||||
|
The function should return a symbol when the effect of calling
|
||||||
|
@cpp{scheme_initialize} and @cpp{scheme_reload} is only to declare
|
||||||
|
a module with the returned name. This function is called when the
|
||||||
|
extension is loaded to satisfy a @scheme[require] declaration.
|
||||||
|
|
||||||
|
The @cpp{scheme_module_name} function may be called before
|
||||||
|
@cpp{scheme_initialize} and @cpp{scheme_reload}, after those
|
||||||
|
functions, or both before and after, depending on how the extension
|
||||||
|
is loaded and re-loaded.}
|
||||||
|
|
||||||
|
|
||||||
|
@item{Compile the extension C/C++ files to create platform-specific
|
||||||
|
object files.
|
||||||
|
|
||||||
|
The @as-index{@|mzc|} compiler, which is distributed with PLT Scheme,
|
||||||
|
compiles plain C files when the @as-index{@DFlag{cc}} flag is
|
||||||
|
specified. More precisely, @|mzc| does not compile the files itself,
|
||||||
|
but it locates a C compiler on the system and launches it with the
|
||||||
|
appropriate compilation flags. If the platform is a relatively
|
||||||
|
standard Unix system, a Windows system with either Microsoft's C
|
||||||
|
compiler or @exec{gcc} in the path, or a Mac OS X system with Apple's
|
||||||
|
developer tools installed, then using @|mzc| is typically easier than
|
||||||
|
working with the C compiler directly. Use the @as-index{@DFlag{cgc}}
|
||||||
|
flag to indicate that the build is for use with PLT Scheme CGC.}
|
||||||
|
|
||||||
|
|
||||||
|
@item{Link the extension C/C++ files with
|
||||||
|
@as-index{@filepath{mzdyn.o}} (Unix, Mac OS X) or
|
||||||
|
@as-index{@filepath{mzdyn.obj}} (Windows) to create a shared object. The
|
||||||
|
resulting shared object should use the extension @filepath{.so} (Unix),
|
||||||
|
@filepath{.dll} (Windows), or @filepath{.dylib} (Mac OS X).
|
||||||
|
|
||||||
|
The @filepath{mzdyn} object file is distributed in the installation's
|
||||||
|
@filepath{lib} directory. For Windows, the object file is in a
|
||||||
|
compiler-specific sub-directory of @filepath{plt\lib}.
|
||||||
|
|
||||||
|
The @|mzc| compiler links object files into an extension when the
|
||||||
|
@as-index{@DFlag{ld}} flag is specified, automatically locating
|
||||||
|
@filepath{mzdyn}. Again, use the @DFlag{cgc} flag with @|mzc|.}
|
||||||
|
|
||||||
|
@item{Load the shared object within Scheme using
|
||||||
|
@scheme[(load-extension _path)], where @scheme[_path] is the name of
|
||||||
|
the extension file generated in the previous step.
|
||||||
|
|
||||||
|
Alternately, if the extension defines a module (i.e.,
|
||||||
|
@cpp{scheme_module_name} returns a symbol), then place the shared
|
||||||
|
object in a special directory so that it is detected by the module
|
||||||
|
loader when @scheme[require] is used. The special directory is a
|
||||||
|
platform-specific path that can be obtained by evaluating
|
||||||
|
@scheme[(build-path "compiled" "native" (system-library-subpath))];
|
||||||
|
see @scheme[load/use-compiled] for more information. For example, if
|
||||||
|
the shared object's name is @filepath{example.dll}, then
|
||||||
|
@scheme[(require "example.ss")] will be redirected to
|
||||||
|
@filepath{example.dll} if the latter is placed in the sub-directory
|
||||||
|
@scheme[(build-path "compiled" "native" (system-library-subpath))]
|
||||||
|
and if @filepath{example.ss} does not exist or has an earlier
|
||||||
|
timestamp.
|
||||||
|
|
||||||
|
Note that @scheme[(load-extension _path)] within a @scheme[module]
|
||||||
|
does @italic{not} introduce the extension's definitions into the
|
||||||
|
module, because @scheme[load-extension] is a run-time operation. To
|
||||||
|
introduce an extension's bindings into a module, make sure that the
|
||||||
|
extension defines a module, put the extension in the
|
||||||
|
platform-specific location as described above, and use
|
||||||
|
@scheme[require].}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@index['("allocation")]{@bold{IMPORTANT:}} With PLT Scheme CGC, Scheme
|
||||||
|
values are garbage collected using a conservative garbage collector,
|
||||||
|
so pointers to Scheme objects can be kept in registers, stack
|
||||||
|
variables, or structures allocated with @cppi{scheme_malloc}. However,
|
||||||
|
static variables that contain pointers to collectable memory must be
|
||||||
|
registered using @cppi{scheme_register_extension_global} (see
|
||||||
|
@secref["im:memoryalloc"]).
|
||||||
|
|
||||||
|
As an example, the following C code defines an extension that returns
|
||||||
|
@scheme["hello world"] when it is loaded:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
#include "escheme.h"
|
||||||
|
Scheme_Object *scheme_initialize(Scheme_Env *env) {
|
||||||
|
return scheme_make_utf8_string("hello world");
|
||||||
|
}
|
||||||
|
Scheme_Object *scheme_reload(Scheme_Env *env) {
|
||||||
|
return scheme_initialize(env); /* Nothing special for reload */
|
||||||
|
}
|
||||||
|
Scheme_Object *scheme_module_name() {
|
||||||
|
return scheme_false;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Assuming that this code is in the file @filepath{hw.c}, the extension
|
||||||
|
is compiled under Unix with the following two commands:
|
||||||
|
|
||||||
|
@commandline{mzc --cgc --cc hw.c}
|
||||||
|
@commandline{mzc --cgc --ld hw.so hw.o}
|
||||||
|
|
||||||
|
(Note that the @DFlag{cgc}, @DFlag{cc}, and @DFlag{ld} flags are each
|
||||||
|
prefixed by two dashes, not one.)
|
||||||
|
|
||||||
|
The @filepath{collects/mzscheme/examples} directory in the PLT
|
||||||
|
distribution contains additional examples.
|
||||||
|
|
||||||
|
@subsection{3m Extensions}
|
||||||
|
|
||||||
|
To build an extension to work with PLT Scheme 3m, the CGC instructions
|
||||||
|
must be extended as follows:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{Adjust code to cooperate with the garbage collector as
|
||||||
|
described in @secref["im:3m"]. Using @|mzc| with the
|
||||||
|
@as-index{@DFlag{xform}} might convert your code to implement part of
|
||||||
|
the conversion, as described in @secref["im:3m:mzc"].}
|
||||||
|
|
||||||
|
@item{In either your source in the in compiler command line,
|
||||||
|
@cpp{#define} @cpp{MZ_PRECISE_GC} before including
|
||||||
|
@filepath{escheme.h}. When using @|mzc| with the @DFlag{cc} and
|
||||||
|
@as-index{@DFlag{3m}} flags, @cpp{MZ_PRECISE_GC} is automatically
|
||||||
|
defined.}
|
||||||
|
|
||||||
|
@item{Link with @as-index{@filepath{mzdyn3m.o}} (Unix, Mac OS X) or
|
||||||
|
@as-index{@filepath{mzdyn3m.obj}} (Windows) to create a shared
|
||||||
|
object. When using @|mzc|, use the @DFlag{ld} and @DFlag{3m} flags
|
||||||
|
to link to these libraries.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
For a relatively simple extension @filepath{hw.c}, the extension is
|
||||||
|
compiled under Unix for 3m with the following three commands:
|
||||||
|
|
||||||
|
@commandline{mzc --xform --cc hw.c}
|
||||||
|
@commandline{mzc --3m --cc hw.3m.c}
|
||||||
|
@commandline{mzc --3m --ld hw.so hw.o}
|
||||||
|
|
||||||
|
Some examples in @filepath{collects/mzscheme/examples} work with
|
||||||
|
MzScheme3m in this way. A few examples are manually instrumented, in
|
||||||
|
which case the @DFlag{xform} step should be skipped.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Embedding MzScheme into a Program}
|
||||||
|
|
||||||
|
@section-index["embedding MzScheme"]
|
||||||
|
|
||||||
|
Like creating extensions, the embedding process for PLT Scheme CGC or
|
||||||
|
PLT Scheme 3m is essentially the same, but the process for PLT Scheme
|
||||||
|
3m is most easily understood as a variant of the process for
|
||||||
|
PLT Scheme CGC.
|
||||||
|
|
||||||
|
@subsection{CGC Embedding}
|
||||||
|
|
||||||
|
To embed PLT Scheme CGC in a program, follow these steps:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{Locate or build the PLT Scheme CGC libraries. Since the
|
||||||
|
standard distribution provides 3m libraries, only, you will most
|
||||||
|
likely have to build from source.
|
||||||
|
|
||||||
|
Under Unix, the libraries are @as-index{@filepath{libmzscheme.a}}
|
||||||
|
and @as-index{@filepath{libmzgc.a}} (or
|
||||||
|
@as-index{@filepath{libmzscheme.so}} and
|
||||||
|
@as-index{@filepath{libmzgc.so}} for a dynamic-library build, with
|
||||||
|
@as-index{@filepath{libmzscheme.la}} and
|
||||||
|
@as-index{@filepath{libmzgc.la}} files for use with
|
||||||
|
@exec{libtool}). Building from source and installing places the
|
||||||
|
libraries into the installation's @filepath{lib} directory. Be sure
|
||||||
|
to build the CGC variant, since the default is 3m.
|
||||||
|
|
||||||
|
Under Windows, stub libraries for use with Microsoft tools are
|
||||||
|
@filepath{libmzsch@italic{x}.lib} and
|
||||||
|
@filepath{libmzgc@italic{x}.lib} (where @italic{x} represents the
|
||||||
|
version number) are in a compiler-specific directory in
|
||||||
|
@filepath{plt\lib}. These libraries identify the bindings that are
|
||||||
|
provided by @filepath{libmzsch@italic{x}.dll} and
|
||||||
|
@filepath{libmzgc@italic{x}.dll} --- which are typically installed
|
||||||
|
in @filepath{plt\lib}. When linking with Cygwin, link to
|
||||||
|
@filepath{libmzsch@italic{x}.dll} and
|
||||||
|
@filepath{libmzgc@italic{x}.dll} directly. At run time, either
|
||||||
|
@filepath{libmzsch@italic{x}.dll} and
|
||||||
|
@filepath{libmzgc@italic{x}.dll} must be moved to a location in the
|
||||||
|
standard DLL search path, or your embedding application must
|
||||||
|
``delayload'' link the DLLs and explicitly load them before
|
||||||
|
use. (@filepath{MzScheme.exe} and @filepath{MrEd.exe} use the latter
|
||||||
|
strategy.)
|
||||||
|
|
||||||
|
Under Mac OS X, dynamic libraries are provided by the
|
||||||
|
@filepath{PLT_MzScheme} framework, which is typically installed in
|
||||||
|
@filepath{lib} sub-directory of the installation. Supply
|
||||||
|
@exec{-framework PLT_MzScheme} to @exec{gcc} when linking, along
|
||||||
|
with @exec{-F} and a path to the @filepath{lib} directory. Beware
|
||||||
|
that CGC and 3m libraries are installed as different versions within
|
||||||
|
a single framework, and installation marks one version or the other
|
||||||
|
as the default (by setting symbolic links); install only CGC to
|
||||||
|
simplify accessing the CGC version within the framework. At run
|
||||||
|
time, either @filepath{PLT_MzScheme.framework} must be moved to a
|
||||||
|
location in the standard framework search path, or your embedding
|
||||||
|
executable must provide a specific path to the framework (possibly
|
||||||
|
an executable-relative path using the Mach-O @tt["@executable_path"]
|
||||||
|
prefix).}
|
||||||
|
|
||||||
|
@item{For each C/C++ file that uses MzScheme library functions,
|
||||||
|
@cpp{#include} the file @as-index{@filepath{scheme.h}}.
|
||||||
|
|
||||||
|
The C preprocessor symbol @cppi{SCHEME_DIRECT_EMBEDDED} is defined
|
||||||
|
as @cpp{1} when @filepath{scheme.h} is @cpp{#include}d, or as
|
||||||
|
@cpp{0} when @filepath{escheme.h} is @cpp{#include}d.
|
||||||
|
|
||||||
|
The @filepath{scheme.h} file is distributed with the PLT software in
|
||||||
|
the installation's @filepath{include} directory. Building and
|
||||||
|
installing from source also places this file in the installation's
|
||||||
|
@filepath{include} directory.}
|
||||||
|
|
||||||
|
@item{In your main program, obtain a global MzScheme environment
|
||||||
|
@cpp{Scheme_Env*} by calling @cppi{scheme_basic_env}. This function
|
||||||
|
must be called before any other function in the MzScheme library
|
||||||
|
(except @cpp{scheme_make_param}).}
|
||||||
|
|
||||||
|
@item{Access MzScheme through @cppi{scheme_load},
|
||||||
|
@cppi{scheme_eval}, and/or other top-level MzScheme functions
|
||||||
|
described in this manual.}
|
||||||
|
|
||||||
|
@item{Compile the program and link it with the MzScheme libraries.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@index['("allocation")]{With} PLT Scheme CGC, Scheme values are
|
||||||
|
garbage collected using a conservative garbage collector, so pointers
|
||||||
|
to Scheme objects can be kept in registers, stack variables, or
|
||||||
|
structures allocated with @cppi{scheme_malloc}. In an embedding
|
||||||
|
application on some platforms, static variables are also automatically
|
||||||
|
registered as roots for garbage collection (but see notes below
|
||||||
|
specific to Mac OS X and Windows).
|
||||||
|
|
||||||
|
For example, the following is a simple embedding program which
|
||||||
|
evaluates all expressions provided on the command line and displays
|
||||||
|
the results, then runs a @scheme[read]-@scheme[eval]-@scheme[print]
|
||||||
|
loop:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
#include "scheme.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Scheme_Env *e;
|
||||||
|
Scheme_Object *curout;
|
||||||
|
int i;
|
||||||
|
mz_jmp_buf * volatile save, fresh;
|
||||||
|
|
||||||
|
scheme_set_stack_base(NULL, 1); /* required for OS X, only */
|
||||||
|
|
||||||
|
e = scheme_basic_env();
|
||||||
|
|
||||||
|
curout = scheme_get_param(scheme_current_config(),
|
||||||
|
MZCONFIG_OUTPUT_PORT);
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
save = scheme_current_thread->error_buf;
|
||||||
|
scheme_current_thread->error_buf = &fresh;
|
||||||
|
if (scheme_setjmp(scheme_error_buf)) {
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
return -1; /* There was an error */
|
||||||
|
} else {
|
||||||
|
Scheme_Object *v = scheme_eval_string(argv[i], e);
|
||||||
|
scheme_display(v, curout);
|
||||||
|
scheme_display(scheme_make_character('\n'), curout);
|
||||||
|
/* read-eval-print loop, uses initial Scheme_Env: */
|
||||||
|
scheme_apply(scheme_builtin_value("read-eval-print-loop"),
|
||||||
|
0, NULL);
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Under Mac OS X, or under Windows when MzScheme is compiled to a DLL
|
||||||
|
using Cygwin, the garbage collector cannot find static variables
|
||||||
|
automatically. In that case, @cppi{scheme_set_stack_base} must be
|
||||||
|
called with a non-zero second argument before calling any
|
||||||
|
@cpp{scheme_} function.
|
||||||
|
|
||||||
|
Under Windows (for any other build mode), the garbage collector finds
|
||||||
|
static variables in an embedding program by examining all memory
|
||||||
|
pages. This strategy fails if a program contains multiple Windows
|
||||||
|
threads; a page may get unmapped by a thread while the collector is
|
||||||
|
examining the page, causing the collector to crash. To avoid this
|
||||||
|
problem, call @cpp{scheme_set_stack_base} with a non-zero second
|
||||||
|
argument before calling any @cpp{scheme_} function.
|
||||||
|
|
||||||
|
When an embedding application calls @cpp{scheme_set_stack_base} with a
|
||||||
|
non-zero second argument, it must register each of its static
|
||||||
|
variables with @cppi{MZ_REGISTER_STATIC} if the variable can contain a
|
||||||
|
GCable pointer. For example, if @cpp{e} above is made @cpp{static},
|
||||||
|
then @cpp{MZ_REGISTER_STATIC(e)} should be inserted before the call to
|
||||||
|
@cpp{scheme_basic_env}.
|
||||||
|
|
||||||
|
When building an embedded MzSchemeCGC to use SenoraGC (SGC) instead of
|
||||||
|
the default collector, @cpp{scheme_set_stack_base} must be called both
|
||||||
|
with a non-zero second argument and with a stack-base pointer in the
|
||||||
|
first argument. See @secref["im:memoryalloc"] for more information.
|
||||||
|
|
||||||
|
|
||||||
|
@subsection{3m Embedding}
|
||||||
|
|
||||||
|
MzScheme3m can be embedded mostly the same as MzScheme, as long as the
|
||||||
|
embedding program cooperates with the precise garbage collector as
|
||||||
|
described in @secref["im:3m"].
|
||||||
|
|
||||||
|
In either your source in the in compiler command line, @cpp{#define}
|
||||||
|
@cpp{MZ_PRECISE_GC} before including @filepath{scheme.h}. When using
|
||||||
|
@|mzc| with the @DFlag{cc} and @DFlag{3m} flags, @cpp{MZ_PRECISE_GC}
|
||||||
|
is automatically defined.
|
||||||
|
|
||||||
|
In addition, some library details are different:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{Under Unix, the library is just
|
||||||
|
@as-index{@filepath{libmzscheme3m.a}} (or
|
||||||
|
@as-index{@filepath{libmzscheme3m.so}} for a dynamic-library build,
|
||||||
|
with @as-index{@filepath{libmzscheme3m.la}} for use with
|
||||||
|
@exec{libtool}). There is no separate library for 3m analogous to
|
||||||
|
CGC's @filepath{libmzgc.a}.}
|
||||||
|
|
||||||
|
@item{Under Windows, the stub library for use with Microsoft tools is
|
||||||
|
@filepath{libmzsch3m@italic{x}.lib} (where @italic{x} represents the
|
||||||
|
version number). This library identifies the bindings that are
|
||||||
|
provided by @filepath{libmzsch3m@italic{x}.dll}. There is no
|
||||||
|
separate library for 3m analogous to CGC's
|
||||||
|
@filepath{libmzgc@italic{x}.lib}.}
|
||||||
|
|
||||||
|
@item{Under Mac OS X, 3m dynamic libraries are provided by the
|
||||||
|
@filepath{PLT_MzScheme} framework, just as for CGC, but as a version
|
||||||
|
suffixed with @filepath{_3m}.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
For MzScheme3m, an embedding application must call
|
||||||
|
@cpp{scheme_set_stack_base} with non-zero arguments. Furthermore, the
|
||||||
|
first argument must be @cpp{&__gc_var_stack__}, where
|
||||||
|
@cpp{__gc_var_stack__} is bound by a @cpp{MZ_GC_DECL_REG}.
|
||||||
|
|
||||||
|
The simple embedding program from the previous section can be
|
||||||
|
extended to work with either CGC or 3m, dependong on whether
|
||||||
|
@cpp{MZ_PRECISE_GC} is specified on the compiler's command line:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
#include "scheme.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Scheme_Env *e = NULL;
|
||||||
|
Scheme_Object *curout = NULL, *v = NULL;
|
||||||
|
Scheme_Config *config = NULL;
|
||||||
|
int i;
|
||||||
|
mz_jmp_buf * volatile save = NULL, fresh;
|
||||||
|
|
||||||
|
MZ_GC_DECL_REG(5);
|
||||||
|
MZ_GC_VAR_IN_REG(0, e);
|
||||||
|
MZ_GC_VAR_IN_REG(1, curout);
|
||||||
|
MZ_GC_VAR_IN_REG(2, save);
|
||||||
|
MZ_GC_VAR_IN_REG(3, config);
|
||||||
|
MZ_GC_VAR_IN_REG(4, v);
|
||||||
|
|
||||||
|
# ifdef MZ_PRECISE_GC
|
||||||
|
# define STACK_BASE &__gc_var_stack__
|
||||||
|
# else
|
||||||
|
# define STACK_BASE NULL
|
||||||
|
# endif
|
||||||
|
|
||||||
|
scheme_set_stack_base(STACK_BASE, 1);
|
||||||
|
|
||||||
|
MZ_GC_REG();
|
||||||
|
|
||||||
|
e = scheme_basic_env();
|
||||||
|
|
||||||
|
config = scheme_current_config();
|
||||||
|
curout = scheme_get_param(config, MZCONFIG_OUTPUT_PORT);
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
save = scheme_current_thread->error_buf;
|
||||||
|
scheme_current_thread->error_buf = &fresh;
|
||||||
|
if (scheme_setjmp(scheme_error_buf)) {
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
return -1; /* There was an error */
|
||||||
|
} else {
|
||||||
|
v = scheme_eval_string(argv[i], e);
|
||||||
|
scheme_display(v, curout);
|
||||||
|
v = scheme_make_character('\n');
|
||||||
|
scheme_display(v, curout);
|
||||||
|
/* read-eval-print loop, uses initial Scheme_Env: */
|
||||||
|
v = scheme_builtin_value("read-eval-print-loop");
|
||||||
|
scheme_apply(v, 0, NULL);
|
||||||
|
scheme_current_thread->error_buf = save;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MZ_GC_UNREG();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Strictly speaking, the @cpp{config} and @cpp{v} variables above need not be
|
||||||
|
registered with the garbage collector, since their values are not needed
|
||||||
|
across function calls that allocate. That is, the original example could have
|
||||||
|
been left alone starting with the @cpp{scheme_base_env} call, except for the
|
||||||
|
addition of @cpp{MZ_GC_UNREG}. The code is much easier to maintain, however,
|
||||||
|
when all local variables are regsistered and when all temporary values are
|
||||||
|
put into variables.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{MzScheme and Threads}
|
||||||
|
|
||||||
|
MzScheme implements threads for Scheme programs without aid from the
|
||||||
|
operating system, so that MzScheme threads are cooperative from the
|
||||||
|
perspective of C code. Under Unix, stand-alone MzScheme uses a single
|
||||||
|
OS-implemented thread. Under Windows and Mac OS X, stand-alone
|
||||||
|
MzScheme uses a few private OS-implemented threads for background
|
||||||
|
tasks, but these OS-implemented threads are never exposed by the
|
||||||
|
MzScheme API.
|
||||||
|
|
||||||
|
In an embedding application, MzScheme can co-exist with additional
|
||||||
|
OS-implemented threads, but the additional OS threads must not call
|
||||||
|
any @cpp{scheme_} function. Only the OS thread that originally calls
|
||||||
|
@cpp{scheme_basic_env} can call @cpp{scheme_} functions. (This
|
||||||
|
restriction is stronger than saying all calls must be serialized
|
||||||
|
across threads. MzScheme relies on properties of specific threads to
|
||||||
|
avoid stack overflow and garbage collection.) When
|
||||||
|
@cpp{scheme_basic_env} is called a second time to reset the
|
||||||
|
interpreter, it can be called in an OS thread that is different from
|
||||||
|
the original call to @cpp{scheme_basic_env}. Thereafter, all calls to
|
||||||
|
@cpp{scheme_} functions must originate from the new thread.
|
||||||
|
|
||||||
|
See @secref["threads"] for more information about threads, including
|
||||||
|
the possible effects of MzScheme's thread implementation on extension
|
||||||
|
and embedding C code.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "im:unicode"]{MzScheme, Unicode, Characters, and Strings}
|
||||||
|
|
||||||
|
A character in MzScheme is a Unicode code point. In C, a character
|
||||||
|
value has type @cppi{mzchar}, which is an alias for @cpp{unsigned} ---
|
||||||
|
which is, in turn, 4 bytes for a properly compiled MzScheme. Thus, a
|
||||||
|
@cpp{mzchar*} string is effectively a UCS-4 string.
|
||||||
|
|
||||||
|
Only a few MzScheme functions use @cpp{mzchar*}. Instead, most
|
||||||
|
functions accept @cpp{char*} strings. When such byte strings are to be
|
||||||
|
used as a character strings, they are interpreted as UTF-8
|
||||||
|
encodings. A plain ASCII string is always acceptable in such cases,
|
||||||
|
since the UTF-8 encoding of an ASCII string is itself.
|
||||||
|
|
||||||
|
See also @secref["im:strings"] and @secref["im:encodings"].
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "im:intsize"]{Integers}
|
||||||
|
|
||||||
|
MzScheme expects to be compiled in a mode where @cppi{short} is a
|
||||||
|
16-bit integer, @cppi{int} is a 32-bit integer, and @cppi{long} has
|
||||||
|
the same number of bits as @cpp{void*}. The @cppi{mzlonglong} type has
|
||||||
|
64 bits for compilers that support a 64-bit integer type, otherwise it
|
||||||
|
is the same as @cpp{long}; thus, @cpp{mzlonglong} tends to match
|
||||||
|
@cpp{long long}. The @cppi{umzlonglong} type is the unsigned version
|
||||||
|
of @cpp{mzlonglong}.
|
209
collects/scribblings/inside/params.scrbl
Normal file
209
collects/scribblings/inside/params.scrbl
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "config"]{Parameterizations}
|
||||||
|
|
||||||
|
A @defterm{parameterization} is a set of parameter values. Each thread
|
||||||
|
has its own initial parameterization, which is extended functionally
|
||||||
|
and superseded by parameterizations that are attached to a particular
|
||||||
|
continuation mark.
|
||||||
|
|
||||||
|
Parameterization information is stored in a @cppi{Scheme_Config}
|
||||||
|
record. For the currently executing thread,
|
||||||
|
@cppi{scheme_current_config} returns the current parameterization.
|
||||||
|
|
||||||
|
To obtain parameter values, a @cpp{Scheme_Config} is combined with the
|
||||||
|
current threads @cpp{Scheme_Thread_Cell_Table}, as stored in the
|
||||||
|
thread record's @cpp{cell_values} field.
|
||||||
|
|
||||||
|
Parameter values for built-in parameters are obtained and modified
|
||||||
|
(for the current thread) using @cppi{scheme_get_param} and
|
||||||
|
@cppi{scheme_set_param}. Each parameter is stored as a
|
||||||
|
@cpp{Scheme_Object *} value, and the built-in parameters are accessed
|
||||||
|
through the following indices:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
@item{@cppi{MZCONFIG_ENV} --- @scheme[current-namespace] (use @cppi{scheme_get_env})}
|
||||||
|
@item{@cppi{MZCONFIG_INPUT_PORT} --- @scheme[current-input-port]}
|
||||||
|
@item{@cppi{MZCONFIG_OUTPUT_PORT} --- @scheme[current-output-port]}
|
||||||
|
@item{@cppi{MZCONFIG_ERROR_PORT} --- @scheme[current-error-port]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_ERROR_DISPLAY_HANDLER} --- @scheme[error-display-handler]}
|
||||||
|
@item{@cppi{MZCONFIG_ERROR_PRINT_VALUE_HANDLER} --- @scheme[error-value->string-handler]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_EXIT_HANDLER} --- @scheme[exit-handler]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_INIT_EXN_HANDLER} --- @scheme[uncaught-exception-handler]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_EVAL_HANDLER} --- @scheme[current-eval]}
|
||||||
|
@item{@cppi{MZCONFIG_LOAD_HANDLER} --- @scheme[current-load]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_PRINT_HANDLER} --- @scheme[current-print]}
|
||||||
|
@item{@cppi{MZCONFIG_PROMPT_READ_HANDLER} --- @scheme[current-prompt-read]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_CAN_READ_GRAPH} --- @scheme[read-accept-graph]}
|
||||||
|
@item{@cppi{MZCONFIG_CAN_READ_COMPILED} --- @scheme[read-accept-compiled]}
|
||||||
|
@item{@cppi{MZCONFIG_CAN_READ_BOX} --- @scheme[read-accept-box]}
|
||||||
|
@item{@cppi{MZCONFIG_CAN_READ_PIPE_QUOTE} --- @scheme[read-accept-bar-quote]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_PRINT_GRAPH} --- @scheme[print-graph]}
|
||||||
|
@item{@cppi{MZCONFIG_PRINT_STRUCT} --- @scheme[print-struct]}
|
||||||
|
@item{@cppi{MZCONFIG_PRINT_BOX} --- @scheme[print-box]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_CASE_SENS} --- @scheme[read-case-sensitive]}
|
||||||
|
@item{@cppi{MZCONFIG_SQUARE_BRACKETS_ARE_PARENS} --- @scheme[read-square-brackets-as-parens]}
|
||||||
|
@item{@cppi{MZCONFIG_CURLY_BRACES_ARE_PARENS} --- @scheme[read-curly-braces-as-parens]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_ERROR_PRINT_WIDTH} --- @scheme[error-print-width]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_ALLOW_SET_UNDEFINED} --- @scheme[allow-compile-set!-undefined]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_CUSTODIAN} --- @scheme[current-custodian]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_USE_COMPILED_KIND} --- @scheme[use-compiled-file-paths]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_LOAD_DIRECTORY} --- @scheme[current-load-relative-directory]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_COLLECTION_PATHS} --- @scheme[current-library-collection-paths]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_PORT_PRINT_HANDLER} --- @scheme[global-port-print-handler]}
|
||||||
|
|
||||||
|
@item{@cppi{MZCONFIG_LOAD_EXTENSION_HANDLER} --- @scheme[current-load-extension]}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
To get or set a parameter value for a thread other than the current
|
||||||
|
one, use @cppi{scheme_get_thread_param} and
|
||||||
|
@cppi{scheme_set_thread_param}, each of which takes a
|
||||||
|
@cpp{Scheme_Thread_Cell_Table} to use in resolving or setting a
|
||||||
|
parameter value.
|
||||||
|
|
||||||
|
When installing a new parameter with @cpp{scheme_set_param}, no check
|
||||||
|
is performed on the supplied value to ensure that it is a legal value
|
||||||
|
for the parameter; this is the responsibility of the caller of
|
||||||
|
@cpp{scheme_set_param}. Note that Boolean parameters should only be
|
||||||
|
set to the values @scheme[#t] and @scheme[#f].
|
||||||
|
|
||||||
|
New primitive parameter indices are created with
|
||||||
|
@cppi{scheme_new_param} and implemented with
|
||||||
|
@cppi{scheme_make_parameter} and @cppi{scheme_param_config}.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_get_param
|
||||||
|
[Scheme_Config* config]
|
||||||
|
[int param_id])]{
|
||||||
|
|
||||||
|
Gets the current value (for the current thread) of the parameter
|
||||||
|
specified by @var{param_id}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_set_param
|
||||||
|
[Scheme_Config* config]
|
||||||
|
[int param_id]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Sets the current value (for the current thread) of the parameter
|
||||||
|
specified by @var{param_id}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_get_thread_param
|
||||||
|
[Scheme_Config* config]
|
||||||
|
[Scheme_Thread_Cell_Table* cells]
|
||||||
|
[int param_id])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_get_param}, but using an arbitrary thread's
|
||||||
|
cell-value table.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_set_thread_param
|
||||||
|
[Scheme_Config* config]
|
||||||
|
[Scheme_Thread_Cell_Table* cells]
|
||||||
|
[int param_id]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_set_param}, but using an arbitrary thread's
|
||||||
|
cell-value table.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_extend_config
|
||||||
|
[Scheme_Config* base]
|
||||||
|
[int param_id]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Creates and returns a parameterization that extends @var{base} with a
|
||||||
|
new value @var{v} (in all threads) for the parameter
|
||||||
|
@var{param_id}. Use @cpp{scheme_install_config} to make this
|
||||||
|
configuration active in the current thread.}
|
||||||
|
|
||||||
|
@function[(void scheme_install_config
|
||||||
|
[Scheme_Config* config])]{
|
||||||
|
|
||||||
|
Adjusts the current thread's continuation marks to make @var{config}
|
||||||
|
the current parameterization. Typically, this function is called
|
||||||
|
after @cpp{scheme_push_continuation_frame} to establish a new
|
||||||
|
continuation frame, and then @cpp{scheme_pop_continuation_frame}
|
||||||
|
is called later to remove the frame (and thus the parameterization).}
|
||||||
|
|
||||||
|
@function[(Scheme_Thread_Cell_Table* scheme_inherit_cells
|
||||||
|
[Scheme_Thread_Cell_Table* cells])]{
|
||||||
|
|
||||||
|
Creates a new thread-cell-value table, copying values for preserved
|
||||||
|
thread cells from @var{cells}.}
|
||||||
|
|
||||||
|
@function[(int scheme_new_param)]{
|
||||||
|
|
||||||
|
Allocates a new primitive parameter index. This function must be
|
||||||
|
called @italic{before} @cppi{scheme_basic_env}, so it is only
|
||||||
|
available to embedding applications (i.e., not extensions).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_register_parameter
|
||||||
|
[Scheme_Prim* function]
|
||||||
|
[char* name]
|
||||||
|
[int exnid])]{
|
||||||
|
|
||||||
|
Use this function instead of the other primitive-constructing
|
||||||
|
functions, like @cpp{scheme_make_prim}, to create a primitive
|
||||||
|
parameter procedure. See also @cpp{scheme_param_config}, below.
|
||||||
|
This function is only available to embedding applications (i.e., not
|
||||||
|
extensions).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_param_config
|
||||||
|
[char* name]
|
||||||
|
[Scheme_Object* param]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv]
|
||||||
|
[int arity]
|
||||||
|
[Scheme_Prim* check]
|
||||||
|
[char* expected]
|
||||||
|
[int isbool])]{
|
||||||
|
|
||||||
|
Call this procedure in a primitive parameter procedure to implement
|
||||||
|
the work of getting or setting the parameter. The @var{name} argument
|
||||||
|
should be the parameter procedure name; it is used to report
|
||||||
|
errors. The @var{param} argument is a fixnum corresponding to the
|
||||||
|
primitive parameter index returned by @cpp{scheme_new_param}. The
|
||||||
|
@var{argc} and @var{argv} arguments should be the un-touched and
|
||||||
|
un-tested arguments that were passed to the primitive parameter.
|
||||||
|
Argument-checking is performed within @cpp{scheme_param_config}
|
||||||
|
using @var{arity}, @var{check}, @var{expected}, and @var{isbool}:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{If @var{arity} is non-negative, potential parameter values must
|
||||||
|
be able to accept the specified number of arguments. The @var{check}
|
||||||
|
and @var{expected} arguments should be @cpp{NULL}.}
|
||||||
|
|
||||||
|
@item{If @var{check} is not @cpp{NULL}, it is called to check a
|
||||||
|
potential parameter value. The arguments passed to @var{check} are
|
||||||
|
always @cpp{1} and an array that contains the potential parameter
|
||||||
|
value. If @var{isbool} is @cpp{0} and @var{check} returns
|
||||||
|
@cpp{scheme_false}, then a type error is reported using @var{name}
|
||||||
|
and @var{expected}. If @var{isbool} is @cpp{1}, then a type error is
|
||||||
|
reported only when @var{check} returns @cpp{NULL} and any
|
||||||
|
non-@cpp{NULL} return value is used as the actual value to be stored
|
||||||
|
for the parameter.}
|
||||||
|
|
||||||
|
@item{Otherwise, @var{isbool} should be 1. A potential procedure
|
||||||
|
argument is then treated as a Boolean value.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
This function is only available to embedding applications (i.e., not
|
||||||
|
extensions).}
|
918
collects/scribblings/inside/ports.scrbl
Normal file
918
collects/scribblings/inside/ports.scrbl
Normal file
|
@ -0,0 +1,918 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Ports and the Filesystem}
|
||||||
|
|
||||||
|
Ports are represented as Scheme values with the types
|
||||||
|
@cppi{scheme_input_port_type} and @cppi{scheme_output_port_type}. The
|
||||||
|
function @cppi{scheme_read} takes an input port value and returns the
|
||||||
|
next S-expression from the port. The function @cppi{scheme_write}
|
||||||
|
takes an output port and a value and writes the value to the
|
||||||
|
port. Other standard low-level port functions are also provided, such
|
||||||
|
as @cppi{scheme_getc}.
|
||||||
|
|
||||||
|
File ports are created with @cppi{scheme_make_file_input_port} and
|
||||||
|
@cppi{scheme_make_file_output_port}; these functions take a @cpp{FILE
|
||||||
|
*} file pointer and return a Scheme port. Strings are read or written
|
||||||
|
with @cppi{scheme_make_byte_string_input_port}, which takes a
|
||||||
|
nul-terminated byte string, and
|
||||||
|
@cppi{scheme_make_byte_string_output_port}, which takes no arguments.
|
||||||
|
The contents of a string output port are obtained with
|
||||||
|
@cppi{scheme_get_byte_string_output}.
|
||||||
|
|
||||||
|
Custom ports, with arbitrary read/write handlers, are created with
|
||||||
|
@cppi{scheme_make_input_port} and @cppi{scheme_make_output_port}.
|
||||||
|
|
||||||
|
When opening a file for any reason using a name provided from Scheme,
|
||||||
|
use @cppi{scheme_expand_filename} to normalize the filename and
|
||||||
|
resolve relative paths.
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_read
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
@scheme[read]s the next S-expression from the given input port.}
|
||||||
|
|
||||||
|
@function[(void scheme_write
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
@scheme[write]s the Scheme value @var{obj} to the given output port.}
|
||||||
|
|
||||||
|
@function[(void scheme_write_w_max
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[int n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_write}, but the printing is truncated to @var{n} bytes.
|
||||||
|
(If printing is truncated, the last bytes are printed as ``.''.)}
|
||||||
|
|
||||||
|
@function[(void scheme_display
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
@scheme[display]s the Scheme value @var{obj} to the given output
|
||||||
|
port.}
|
||||||
|
|
||||||
|
@function[(void scheme_display_w_max
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[int n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_display}, but the printing is truncated to @var{n} bytes.
|
||||||
|
(If printing is truncated, the last three bytes are printed as ``.''.)}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_write_byte_string
|
||||||
|
[char* str]
|
||||||
|
[long len]
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Writes @var{len} bytes of @var{str} to the given output port.}
|
||||||
|
|
||||||
|
@function[(void scheme_write_char_string
|
||||||
|
[mzchar* str]
|
||||||
|
[long len]
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Writes @var{len} characters of @var{str} to the given output port.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(long scheme_put_byte_string
|
||||||
|
[const-char* who]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[char* str]
|
||||||
|
[long d]
|
||||||
|
[long len]
|
||||||
|
[int rarely_block])]{
|
||||||
|
|
||||||
|
Writes @var{len} bytes of @var{str}, starting with the @var{d}th
|
||||||
|
character. Bytes are written to the given output port, and errors are
|
||||||
|
reported as from @var{who}.
|
||||||
|
|
||||||
|
If @var{rarely_block} is @cpp{0}, the write blocks until all @var{len}
|
||||||
|
bytes are written, possibly to an internal buffer. If
|
||||||
|
@var{rarely_block} is @cpp{2}, the write never blocks, and written
|
||||||
|
bytes are not buffered. If @var{rarely_block} is @cpp{1}, the write
|
||||||
|
blocks only until at least one byte is written (without buffering) or
|
||||||
|
until part of an internal buffer is flushed.
|
||||||
|
|
||||||
|
Supplying @cpp{0} for @var{len} corresponds to a buffer-flush
|
||||||
|
request. If @var{rarely_block} is @cpp{2}, the flush request is
|
||||||
|
non-blocking, and if @var{rarely_block} is @cpp{0}, it is blocking.
|
||||||
|
(A @var{rarely_block} of @cpp{1} is the same as @cpp{0} in this case.)
|
||||||
|
|
||||||
|
The result is @cpp{-1} if no bytes are written from @var{str} and
|
||||||
|
unflushed bytes remain in the internal buffer. Otherwise, the return
|
||||||
|
value is the number of written characters.}
|
||||||
|
|
||||||
|
@function[(long scheme_put_char_string
|
||||||
|
[const-char* who]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[char* str]
|
||||||
|
[long d]
|
||||||
|
[long len])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_put_byte_string}, but for a @cpp{mzchar} string, and
|
||||||
|
without the non-blocking option.}
|
||||||
|
|
||||||
|
@function[(char* scheme_write_to_string
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[long* len])]{
|
||||||
|
|
||||||
|
Prints the Scheme value @var{obj} using @scheme[write] to a newly
|
||||||
|
allocated string. If @var{len} is not @cpp{NULL}, @cpp{*@var{len}} is
|
||||||
|
set to the length of the bytes string.}
|
||||||
|
|
||||||
|
@function[(void scheme_write_to_string_w_max
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[long* len]
|
||||||
|
[int n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_write_to_string}, but the string is truncated to
|
||||||
|
@var{n} bytes. (If the string is truncated, the last three bytes are
|
||||||
|
``.''.)}
|
||||||
|
|
||||||
|
@function[(char* scheme_display_to_string
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[long* len])]{
|
||||||
|
|
||||||
|
Prints the Scheme value @var{obj} using @scheme[display] to a newly
|
||||||
|
allocated string. If @var{len} is not @cpp{NULL}, @cpp{*@var{len}} is
|
||||||
|
set to the length of the string.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_display_to_string_w_max
|
||||||
|
[Scheme_Object* obj]
|
||||||
|
[long* len]
|
||||||
|
[int n])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_display_to_string}, but the string is truncated to
|
||||||
|
@var{n} bytes. (If the string is truncated, the last three bytes are
|
||||||
|
``.''.)}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_debug_print
|
||||||
|
[Scheme_Object* obj])]{
|
||||||
|
|
||||||
|
Prints the Scheme value @var{obj} using @scheme[write] to the main
|
||||||
|
thread's output port.}
|
||||||
|
|
||||||
|
@function[(void scheme_flush_output
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
If @var{port} is a file port, a buffered data is written to the file.
|
||||||
|
Otherwise, there is no effect. @var{port} must be an output port.}
|
||||||
|
|
||||||
|
@function[(int scheme_get_byte
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Get the next byte from the given input port. The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
@function[(int scheme_getc
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Get the next character from the given input port (by decoding bytes as UTF-8).
|
||||||
|
The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
@function[(int scheme_peek_byte
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Peeks the next byte from the given input port. The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
@function[(int scheme_peekc
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Peeks the next character from the given input port (by decoding bytes as UTF-8).
|
||||||
|
The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
@function[(int scheme_peek_byte_skip
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[Scheme_Object* skip])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_peek_byte}, but with a skip count. The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
@function[(int scheme_peekc_skip
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[Scheme_Object* skip])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_peekc}, but with a skip count. The result can be @cpp{EOF}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(long scheme_get_byte_string
|
||||||
|
[const-char* who]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[char* buffer]
|
||||||
|
[int offset]
|
||||||
|
[long size]
|
||||||
|
[int only_avail]
|
||||||
|
[int peek]
|
||||||
|
[Scheme_Object* peek_skip])]{
|
||||||
|
|
||||||
|
Gets multiple bytes at once from a port, reporting errors with the
|
||||||
|
name @var{who}. The @var{size} argument indicates the number of
|
||||||
|
requested bytes, to be put into the @var{buffer} array starting at
|
||||||
|
@var{offset}. The return value is the number of bytes actually read,
|
||||||
|
or @cpp{EOF} if an end-of-file is encountered without reading any
|
||||||
|
bytes.
|
||||||
|
|
||||||
|
If @var{only_avail} is @cpp{0}, then the function blocks until
|
||||||
|
@var{size} bytes are read or an end-of-file is reached. If
|
||||||
|
@var{only_avail} is @cpp{1}, the function blocks only until at least
|
||||||
|
one byte is read. If @var{only_avail} is @cpp{2}, the function never
|
||||||
|
blocks. If @var{only_avail} is @cpp{-1}, the function blocks only
|
||||||
|
until at least one byte is read but also allows breaks (with the
|
||||||
|
guarantee that bytes are read or a break is raised, but not both).
|
||||||
|
|
||||||
|
If @var{peek} is non-zero, then the port is peeked instead of
|
||||||
|
read. The @var{peek_skip} argument indicates a portion of the input
|
||||||
|
stream to skip as a non-negative, exact integer (fixnum or bignum). In
|
||||||
|
this case, an @var{only_avail} value of @cpp{1} means to continue the
|
||||||
|
skip until at least one byte can be returned, even if it means
|
||||||
|
multiple blocking reads to skip bytes.
|
||||||
|
|
||||||
|
If @var{peek} is zero, then @var{peek_skip} should be either
|
||||||
|
@cpp{NULL} (which means zero) or the fixnum zero.}
|
||||||
|
|
||||||
|
@function[(long scheme_get_char_string
|
||||||
|
[const-char* who]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[char* buffer]
|
||||||
|
[int offset]
|
||||||
|
[long size]
|
||||||
|
[int peek]
|
||||||
|
[Scheme_Object* peek_skip])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_get_byte_string}, but for characters (by decoding
|
||||||
|
bytes as UTF-8), and without the non-blocking option.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(long scheme_get_bytes
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[long size]
|
||||||
|
[char* buffer]
|
||||||
|
[int offset])]{
|
||||||
|
|
||||||
|
For backward compatibility: calls @cpp{scheme_get_byte_string} in
|
||||||
|
essentially the obvious way with @var{only_avail} as @cpp{0}; if
|
||||||
|
@var{size} is negative, then it reads @var{-size} bytes with
|
||||||
|
@var{only_avail} as @cpp{1}.}
|
||||||
|
|
||||||
|
@function[(void scheme_ungetc
|
||||||
|
[int ch]
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Puts the byte @var{ch} back as the next character to be read from the
|
||||||
|
given input port. The character need not have been read from
|
||||||
|
@var{port}, and @cpp{scheme_ungetc} can be called to insert up to five
|
||||||
|
characters at the start of @var{port}.
|
||||||
|
|
||||||
|
Use @cpp{scheme_get_byte} followed by @cpp{scheme_ungetc} only when
|
||||||
|
your program will certainly call @cpp{scheme_get_byte} again to
|
||||||
|
consume the byte. Otherwise, use @cpp{scheme_peek_byte}, because some
|
||||||
|
a port may implement peeking and getting differently.}
|
||||||
|
|
||||||
|
@function[(int scheme_byte_ready
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns 1 if a call to @cpp{scheme_get_byte} is guaranteed not to
|
||||||
|
block for the given input port.}
|
||||||
|
|
||||||
|
@function[(int scheme_char_ready
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns 1 if a call to @cpp{scheme_getc} is guaranteed not to block
|
||||||
|
for the given input port.}
|
||||||
|
|
||||||
|
@function[(void scheme_need_wakeup
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[void* fds])]{
|
||||||
|
|
||||||
|
Requests that appropriate bits are set in @var{fds} to specify which
|
||||||
|
file descriptors(s) the given input port reads from. (@var{fds} is
|
||||||
|
sortof a pointer to an @cppi{fd_set} struct; see
|
||||||
|
@secref["blockednonmainel"].)}
|
||||||
|
|
||||||
|
@function[(long scheme_tell
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns the current read position of the given input port, or the
|
||||||
|
current file position of the given output port.}
|
||||||
|
|
||||||
|
@function[(long scheme_tell_line
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns the current read line of the given input port. If lines are
|
||||||
|
not counted, -1 is returned.}
|
||||||
|
|
||||||
|
@function[(void scheme_count_lines
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Turns on line-counting for the given input port. To get accurate line
|
||||||
|
counts, call this function immediately after creating a port.}
|
||||||
|
|
||||||
|
@function[(long scheme_set_file_position
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[long pos])]{
|
||||||
|
|
||||||
|
Sets the file position of the given input or output port (from the
|
||||||
|
start of the file). If the port does not support position setting, an
|
||||||
|
exception is raised.}
|
||||||
|
|
||||||
|
@function[(void scheme_close_input_port
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Closes the given input port.}
|
||||||
|
|
||||||
|
@function[(void scheme_close_output_port
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Closes the given output port.}
|
||||||
|
|
||||||
|
@function[(int scheme_get_port_file_descriptor
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[long* fd])]{
|
||||||
|
|
||||||
|
Fills @cpp{*@var{fd}} with a file-descriptor value for @var{port} if
|
||||||
|
one is available (i.e., the port is a file-stream port and it is not
|
||||||
|
closed). The result is non-zero if the file-descriptor value is
|
||||||
|
available, zero otherwise. Under Windows, a ``file dscriptor'' is a
|
||||||
|
file @cpp{HANDLE}.}
|
||||||
|
|
||||||
|
@function[(long scheme_get_port_fd
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[long* s])]{
|
||||||
|
|
||||||
|
Fills @cpp{*@var{s}} with a socket value for @var{port} if one is
|
||||||
|
available (i.e., the port is a TCP port and it is not closed). The
|
||||||
|
result is non-zero if the socket value is available, zero
|
||||||
|
otherwise. Under Windows, a socket value has type @cpp{SOCKET}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_port_type
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Creates a new port subtype.}
|
||||||
|
|
||||||
|
@function[(Scheme_Input_Port* scheme_make_input_port
|
||||||
|
[Scheme_Object* subtype]
|
||||||
|
[void* data]
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[Scheme_Get_String_Fun get_bytes_fun]
|
||||||
|
[Scheme_Peek_String_Fun peek_bytes_fun]
|
||||||
|
[Scheme_Progress_Evt_Fun progress_evt_fun]
|
||||||
|
[Scheme_Peeked_Read_Fun peeked_read_fun]
|
||||||
|
[Scheme_In_Ready_Fun char_ready_fun]
|
||||||
|
[Scheme_Close_Input_Fun close_fun]
|
||||||
|
[Scheme_Need_Wakeup_Input_Fun need_wakeup_fun]
|
||||||
|
[int must_close])]{
|
||||||
|
|
||||||
|
Creates a new input port with arbitrary control functions. The
|
||||||
|
@var{subtype} is an arbitrary value to distinguish the port's class.
|
||||||
|
The pointer @var{data} will be installed as the port's user data,
|
||||||
|
which can be extracted/set with the @cppi{SCHEME_INPORT_VAL} macro.
|
||||||
|
The @var{name} object is used as the port's name (for
|
||||||
|
@scheme[object-name] and as the default source name for
|
||||||
|
@scheme[read-syntax]).
|
||||||
|
|
||||||
|
If @var{must_close} is non-zero, the new port will be registered with
|
||||||
|
the current custodian, and @var{close_fun} is guaranteed to be called
|
||||||
|
before the port is garbage-collected.
|
||||||
|
|
||||||
|
Although the return type of @cpp{scheme_make_input_port} is
|
||||||
|
@cppi{Scheme_Input_Port*}, it can be cast into a @cpp{Scheme_Object*}.
|
||||||
|
|
||||||
|
The functions are as follows.
|
||||||
|
|
||||||
|
@subfunction[(long get_bytes_fun
|
||||||
|
[Scheme_Input_Port* port]
|
||||||
|
[char* buffer]
|
||||||
|
[long offset]
|
||||||
|
[long size]
|
||||||
|
[int nonblock]
|
||||||
|
[Scheme_Object* unless])]{
|
||||||
|
|
||||||
|
Reads bytes into @var{buffer}, starting from @var{offset}, up to
|
||||||
|
@var{size} bytes (i.e., @var{buffer} is at least
|
||||||
|
@var{offset} plus @var{size} long). If @var{nonblock} is @cpp{0},
|
||||||
|
then the function can block indefinitely, but it should return
|
||||||
|
when at least one byte of data is available. If @var{nonblock} is
|
||||||
|
@cpp{1}, the function should never block. If @var{nonblock} is
|
||||||
|
@cpp{2}, a port in unbuffered mode should return only bytes
|
||||||
|
previously forced to be buffered; other ports should treat a
|
||||||
|
@var{nonblock} of @cpp{2} like @cpp{1}. If @var{nonblock} is
|
||||||
|
@cpp{-1}, the function can block, but should enable breaks while
|
||||||
|
blocking. The function should return @cpp{0} if no bytes are ready
|
||||||
|
in non-blocking mode. It should return @cpp{EOF} if an end-of-file
|
||||||
|
is reached (and no bytes were read into @var{buffer}). Otherwise,
|
||||||
|
the function should return the number of read bytes. The function
|
||||||
|
can raise an exception to report an error.
|
||||||
|
|
||||||
|
The @var{unless} argument will be non-@cpp{NULL} only when
|
||||||
|
@var{nonblocking} is non-zero (except as noted below), and only if
|
||||||
|
the port supports progress events. If @var{unless} is
|
||||||
|
non-@cpp{NULL} and @cpp{SCHEME_CDR(@var{unless})} is
|
||||||
|
non-@cpp{NULL}, the latter is a progress event specific to the
|
||||||
|
port. The @var{get_bytes_fun} function should return
|
||||||
|
@cppi{SCHEME_UNLESS_READY} instead of reading bytes if the event
|
||||||
|
in @var{unless} becomes ready before bytes can be read. In
|
||||||
|
particular, @var{get_bytes_fun} should check the event in
|
||||||
|
@var{unless} before taking any action, and it should check the
|
||||||
|
event in @var{unless} after any operation that may allow Scheme
|
||||||
|
thread swaps. If the read must block, then it should unblock if
|
||||||
|
the event in @var{unless} becomes ready.
|
||||||
|
|
||||||
|
If @cpp{scheme_progress_evt_via_get} is used for
|
||||||
|
@var{progress_evt_fun}, then @var{unless} can be non-@cpp{NULL}
|
||||||
|
even when @var{nonblocking} is @cpp{0}. In all modes,
|
||||||
|
@var{get_bytes_fun} must call @cpp{scheme_unless_ready} to check
|
||||||
|
@var{unless_evt}. Furthermore, after any potentially
|
||||||
|
thread-swapping operation, @var{get_bytes_fun} must call
|
||||||
|
@cpp{scheme_wait_input_allowed}, because another thread may be
|
||||||
|
attempting to commit, and @var{unless_evt} must be checked after
|
||||||
|
@cpp{scheme_wait_input_allowed} returns. To block, the port should
|
||||||
|
use @cpp{scheme_block_until_unless} instead of
|
||||||
|
@cpp{scheme_block_until}. Finally, in blocking mode,
|
||||||
|
@var{get_bytes_fun} must return after immediately reading data,
|
||||||
|
without allowing a Scheme thread swap.}
|
||||||
|
|
||||||
|
@subfunction[(long peek_bytes_fun
|
||||||
|
[Scheme_Input_Port* port]
|
||||||
|
[char* buffer]
|
||||||
|
[long offset]
|
||||||
|
[long size]
|
||||||
|
[Scheme_Object* skip]
|
||||||
|
[int nonblock]
|
||||||
|
[Scheme_Object* unless_evt])]{
|
||||||
|
|
||||||
|
Can be @cpp{NULL} to use a default implementation of peeking that
|
||||||
|
uses @var{get_bytes_fun}. Otherwise, the protocol is the same as
|
||||||
|
for @var{get_bytes_fun}, except that an extra @var{skip} argument
|
||||||
|
indicates the number of input elements to skip (but @var{skip}
|
||||||
|
does not apply to @var{buffer}). The @var{skip} value will be a
|
||||||
|
non-negative exact integer, either a fixnum or a bignum.}
|
||||||
|
|
||||||
|
@subfunction[(Scheme_Object* progress_evt_fun
|
||||||
|
[Scheme_Input_Port* port])]{
|
||||||
|
|
||||||
|
Called to obtain a progress event for the port, such as for
|
||||||
|
@scheme[port-progress-evt]. This function can be @cpp{NULL} if the
|
||||||
|
port does not support progress events. Use
|
||||||
|
@cpp{progress_evt_via_get} to obtain a default implementation, in
|
||||||
|
which case @var{peeked_read_fun} should be
|
||||||
|
@cpp{peeked_read_via_get}, and @var{get_bytes_fun} and
|
||||||
|
@var{peek_bytes_fun} should handle @var{unless} as described
|
||||||
|
above.}
|
||||||
|
|
||||||
|
@subfunction[(int peeked_read_fun
|
||||||
|
[Scheme_Input_Port* port]
|
||||||
|
[long amount]
|
||||||
|
[Scheme_Object* unless_evt]
|
||||||
|
[Scheme_Object* target_ch])]{
|
||||||
|
|
||||||
|
Called to commit previously peeked bytes, just like the sixth
|
||||||
|
argument to @scheme[make-input-port]. Use
|
||||||
|
@cpp{peeked_read_via_get} for the default implementation of
|
||||||
|
commits when @var{progress_evt_fun} is
|
||||||
|
@cpp{progress_evt_via_get}.}
|
||||||
|
|
||||||
|
@subfunction[(int char_ready_fun
|
||||||
|
[Scheme_Input_Port* port])]{
|
||||||
|
|
||||||
|
Returns @cpp{1} when a non-blocking @var{get_bytes_fun} will
|
||||||
|
return bytes or an @cpp{EOF}.}
|
||||||
|
|
||||||
|
@subfunction[(void close_fun
|
||||||
|
[Scheme_Input_Port* port])]{
|
||||||
|
|
||||||
|
Called to close the port. The port is not considered closed until
|
||||||
|
the function returns.}
|
||||||
|
|
||||||
|
@subfunction[(void need_wakeup_fun
|
||||||
|
[Scheme_Input_Port* port]
|
||||||
|
[void* fds])]{
|
||||||
|
|
||||||
|
Called when the port is blocked on a read; @var{need_wakeup_fun}
|
||||||
|
should set appropriate bits in @var{fds} to specify which file
|
||||||
|
descriptor(s) it is blocked on. The @var{fds} argument is
|
||||||
|
conceptually an array of three @cppi{fd_set} structs (one for
|
||||||
|
read, one for write, one for exceptions), but manipulate this
|
||||||
|
array using @cppi{scheme_get_fdset} to get a particular element of
|
||||||
|
the array, and use @cppi{MZ_FD_XXX} instead of @cpp{FD_XXX} to
|
||||||
|
manipulate a single ``@cpp{fd_set}''. Under Windows, the first
|
||||||
|
``@cpp{fd_set}'' can also contain OS-level semaphores or other
|
||||||
|
handles via @cpp{scheme_add_fd_handle}.}
|
||||||
|
}
|
||||||
|
|
||||||
|
@function[(Scheme_Output_Port* scheme_make_output_port
|
||||||
|
[Scheme_Object* subtype]
|
||||||
|
[void* data]
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[Scheme_Write_String_Evt_Fun write_bytes_evt_fun]
|
||||||
|
[Scheme_Write_String_Fun write_bytes_fun]
|
||||||
|
[Scheme_Out_Ready_Fun char_ready_fun]
|
||||||
|
[Scheme_Close_Output_Fun close_fun]
|
||||||
|
[Scheme_Need_Wakeup_Output_Fun need_wakeup_fun]
|
||||||
|
[Scheme_Write_Special_Fun write_special_fun]
|
||||||
|
[Scheme_Write_Special_Evt_Fun write_special_evt_fun]
|
||||||
|
[Scheme_Write_Special_Fun write_special_fun]
|
||||||
|
[int must_close])]{
|
||||||
|
|
||||||
|
Creates a new output port with arbitrary control functions. The
|
||||||
|
@var{subtype} is an arbitrary value to distinguish the port's class.
|
||||||
|
The pointer @var{data} will be installed as the port's user data,
|
||||||
|
which can be extracted/set with the @cppi{SCHEME_OUTPORT_VAL}
|
||||||
|
macro. The @var{name} object is used as the port's name.
|
||||||
|
|
||||||
|
If @var{must_close} is non-zero, the new port will be registered with
|
||||||
|
the current custodian, and @var{close_fun} is guaranteed to be called
|
||||||
|
before the port is garbage-collected.
|
||||||
|
|
||||||
|
Although the return type of @cpp{scheme_make_output_port} is
|
||||||
|
@cppi{Scheme_Output_Port*}, it can be cast into a
|
||||||
|
@cpp{Scheme_Object*}.
|
||||||
|
|
||||||
|
The functions are as follows.
|
||||||
|
|
||||||
|
@subfunction[(long write_bytes_evt_fun
|
||||||
|
[Scheme_Output_Port* port]
|
||||||
|
[const-char* buffer]
|
||||||
|
[long offset]
|
||||||
|
[long size])]{
|
||||||
|
|
||||||
|
Returns an event that writes up to @var{size} bytes atomically
|
||||||
|
when event is chosen in a synchronization. Supply @cpp{NULL} if
|
||||||
|
bytes cannot be written atomically, or supply
|
||||||
|
@cppi{scheme_write_evt_via_write} to use the default
|
||||||
|
implementation in terms of @cpp{write_bytes_fun} (with
|
||||||
|
@var{rarely_block} as @cpp{2}).}
|
||||||
|
|
||||||
|
@subfunction[(long write_bytes_fun
|
||||||
|
[Scheme_Output_Port* port]
|
||||||
|
[const-char* buffer]
|
||||||
|
[long offset]
|
||||||
|
[long size]
|
||||||
|
[int rarely_block]
|
||||||
|
[int enable_break])]{
|
||||||
|
|
||||||
|
Write bytes from @var{buffer}, starting from @var{offset}, up to
|
||||||
|
@var{size} bytes (i.e., @var{buffer} is at least
|
||||||
|
@var{offset} plus @var{size} long). If @var{rarely_block} is @cpp{0},
|
||||||
|
then the function can block indefinitely, and it can buffer
|
||||||
|
output. If @var{rarely_block} is @cpp{2}, the function should
|
||||||
|
never block, and it should not buffer output. If
|
||||||
|
@var{rarely_block} is @cpp{1}, the function should not buffer
|
||||||
|
data, and it should block only until writing at least one byte,
|
||||||
|
either from @var{buffer} or an internal buffer. The function
|
||||||
|
should return the number of bytes from @var{buffer} that were
|
||||||
|
written; when @var{rarely_block} is non-zero and bytes remain in
|
||||||
|
an internal buffer, it should return @cpp{-1}. The @var{size}
|
||||||
|
argument can be @cpp{0} when @var{rarely_block} is @cpp{0} for a
|
||||||
|
blocking flush, and it can be @cpp{0} if @var{rarely_block} is
|
||||||
|
@cpp{2} for a non-blocking flush. If @var{enable_break} is true,
|
||||||
|
then it should enable breaks while blocking. The function can
|
||||||
|
raise an exception to report an error.}
|
||||||
|
|
||||||
|
@subfunction[(int char_ready_fun
|
||||||
|
[Scheme_Output_Port* port])]{
|
||||||
|
|
||||||
|
Returns @cpp{1} when a non-blocking @var{write_bytes_fun} will
|
||||||
|
write at least one byte or flush at least one byte from
|
||||||
|
the port's internal buffer.}
|
||||||
|
|
||||||
|
@subfunction[(void close_fun
|
||||||
|
[Scheme_Output_Port* port])]{
|
||||||
|
|
||||||
|
Called to close the port. The port is not considered closed until
|
||||||
|
the function returns. This function is allowed to block (usually
|
||||||
|
to flush a buffer) unless
|
||||||
|
@cpp{scheme_close_should_force_port_closed} returns a non-zero
|
||||||
|
result, in which case the function must return without blocking.}
|
||||||
|
|
||||||
|
@subfunction[(void need_wakeup_fun
|
||||||
|
[Scheme_Output_Port* port]
|
||||||
|
[void* fds])]{
|
||||||
|
|
||||||
|
Called when the port is blocked on a write; @var{need_wakeup_fun}
|
||||||
|
should set appropriate bits in @var{fds} to specify which file
|
||||||
|
descriptor(s) it is blocked on. The @var{fds} argument is
|
||||||
|
conceptually an array of three @cppi{fd_set} structs (one for
|
||||||
|
read, one for write, one for exceptions), but manipulate this
|
||||||
|
array using @cppi{scheme_get_fdset} to get a particular element of
|
||||||
|
the array, and use @cppi{MZ_FD_XXX} instead of @cpp{FD_XXX} to
|
||||||
|
manipulate a single ``@cpp{fd_set}''. Under Windows, the first
|
||||||
|
``@cpp{fd_set}'' can also contain OS-level semaphores or other
|
||||||
|
handles via @cpp{scheme_add_fd_handle}.}
|
||||||
|
|
||||||
|
@subfunction[(int write_special_evt_fun
|
||||||
|
[Scheme_Output_Port* port]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Returns an event that writes @var{v} atomically when event is
|
||||||
|
chosen in a synchronization. Supply @cpp{NULL} if specials cannot
|
||||||
|
be written atomically (or at all), or supply
|
||||||
|
@cppi{scheme_write_special_evt_via_write_special} to use the
|
||||||
|
default implementation in terms of @cpp{write_special_fun} (with
|
||||||
|
@var{non_block} as @cpp{1}).}
|
||||||
|
|
||||||
|
@subfunction[(int write_special_fun
|
||||||
|
[Scheme_Output_Port* port]
|
||||||
|
[Scheme_Object* v]
|
||||||
|
[int non_block])]{
|
||||||
|
|
||||||
|
Called to write the special value @var{v} for
|
||||||
|
@scheme[write-special] (when @var{non_block} is @cpp{0}) or
|
||||||
|
@scheme[write-special-avail*] (when @var{non_block} is
|
||||||
|
@cpp{1}). If @cpp{NULL} is supplied instead of a function pointer,
|
||||||
|
then @scheme[write-special] and @scheme[write-special-avail*]
|
||||||
|
produce an error for this port.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_file_input_port
|
||||||
|
[FILE* fp])]{
|
||||||
|
|
||||||
|
Creates a Scheme input file port from an ANSI C file pointer. The file
|
||||||
|
must never block on reads.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_open_input_file
|
||||||
|
[const-char* filename]
|
||||||
|
[const-char* who])]{
|
||||||
|
|
||||||
|
Opens @var{filename} for reading. In an exception is raised, the
|
||||||
|
exception message uses @var{who} as the name of procedure that raised
|
||||||
|
the exception.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_named_file_input_port
|
||||||
|
[FILE* fp]
|
||||||
|
[Scheme_Object* name])]{
|
||||||
|
|
||||||
|
Creates a Scheme input file port from an ANSI C file pointer. The file
|
||||||
|
must never block on reads. The @var{name} argument is used as the
|
||||||
|
port's name.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_open_output_file
|
||||||
|
[const-char* filename]
|
||||||
|
[const-char* who])]{
|
||||||
|
|
||||||
|
Opens @var{filename} for writing in @scheme['truncate/replace] mode. If
|
||||||
|
an exception is raised, the exception message uses @var{who} as the
|
||||||
|
name of procedure that raised the exception.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_file_output_port
|
||||||
|
[FILE* fp])]{
|
||||||
|
|
||||||
|
Creates a Scheme output file port from an ANSI C file pointer. The
|
||||||
|
file must never block on writes.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_fd_input_port
|
||||||
|
[int fd]
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[int regfile]
|
||||||
|
[int win_textmode]
|
||||||
|
[int fd]
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[int regfile]
|
||||||
|
[int win_textmode]
|
||||||
|
[int read_too]
|
||||||
|
[long s]
|
||||||
|
[const-char* name]
|
||||||
|
[int close]
|
||||||
|
[Scheme_Object** inp]
|
||||||
|
[Scheme_Object** outp]
|
||||||
|
[char* str])]{
|
||||||
|
|
||||||
|
Creates a Scheme input port from a byte string; successive
|
||||||
|
@scheme[read-char]s on the port return successive bytes in the
|
||||||
|
string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_byte_string_output_port)]{
|
||||||
|
|
||||||
|
Creates a Scheme output port; all writes to the port are kept in a byte string,
|
||||||
|
which can be obtained with @cpp{scheme_get_byte_string_output}.}
|
||||||
|
|
||||||
|
@function[(char* scheme_get_byte_string_output
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns (in a newly allocated byte string) all data that has been
|
||||||
|
written to the given string output port so far. (The returned string
|
||||||
|
is nul-terminated.)}
|
||||||
|
|
||||||
|
@function[(char* scheme_get_sized_byte_string_output
|
||||||
|
[Scheme_Object* port]
|
||||||
|
[long* len])]{
|
||||||
|
|
||||||
|
Returns (in a newly allocated byte string) all data that has been
|
||||||
|
written to the given string output port so far and fills in
|
||||||
|
@cpp{*len} with the length of the string in bytes (not including the
|
||||||
|
nul terminator).}
|
||||||
|
|
||||||
|
@function[(void scheme_pipe
|
||||||
|
[Scheme_Object** read]
|
||||||
|
[Scheme_Object** write])]{
|
||||||
|
|
||||||
|
Creates a pair of ports, setting @cpp{*@var{read}} and
|
||||||
|
@cpp{*@var{write}}; data written to @cpp{*@var{write}} can be read
|
||||||
|
back out of @cpp{*@var{read}}. The pipe can store arbitrarily many
|
||||||
|
unread characters,}
|
||||||
|
|
||||||
|
@function[(void scheme_pipe_with_limit
|
||||||
|
[Scheme_Object** read]
|
||||||
|
[Scheme_Object** write]
|
||||||
|
[int limit])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_pipe} is @var{limit} is @cpp{0}. If @var{limit} is
|
||||||
|
positive, creates a pipe that stores at most @var{limit} unread
|
||||||
|
characters, blocking writes when the pipe is full.}
|
||||||
|
|
||||||
|
@function[(Scheme_Input_Port* scheme_input_port_record
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns the input-port record for @var{port}, which may be either a
|
||||||
|
raw-port object with type @cpp{scheme_input_port_type} or a structure
|
||||||
|
with the @scheme[prop:input-port] property.}
|
||||||
|
|
||||||
|
@function[(Scheme_Output_Port* scheme_output_port_record
|
||||||
|
[Scheme_Object* port])]{
|
||||||
|
|
||||||
|
Returns the output-port record for @var{port}, which may be either a
|
||||||
|
raw-port object with type @cpp{scheme_output_port_type} or a structure
|
||||||
|
with the @scheme[prop:output-port] property.}
|
||||||
|
|
||||||
|
@function[(int scheme_file_exists
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Returns 1 if a file by the given name exists, 0 otherwise. If
|
||||||
|
@var{name} specifies a directory, FALSE is returned.
|
||||||
|
The @var{name} should be already expanded.}
|
||||||
|
|
||||||
|
@function[(int scheme_directory_exists
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Returns 1 if a directory by the given name exists, 0 otherwise. The
|
||||||
|
@var{name} should be already expanded.}
|
||||||
|
|
||||||
|
@function[(char* scheme_expand_filename
|
||||||
|
[const-char* name]
|
||||||
|
[int len]
|
||||||
|
[const-char* where]
|
||||||
|
[int* expanded]
|
||||||
|
[int checks])]{
|
||||||
|
|
||||||
|
Cleanses the pathname @var{name} (see @scheme[cleanse-path]) and
|
||||||
|
resolves relative paths with respect to the current directory
|
||||||
|
parameter. The @var{len} argument is the length of the input string;
|
||||||
|
if it is -1, the string is assumed to be null-terminated. The
|
||||||
|
@var{where} argument is used to raise an exception if there is an
|
||||||
|
error in the filename; if this is @cpp{NULL}, an error is not reported
|
||||||
|
and @cpp{NULL} is returned instead. If @var{expanded} is not
|
||||||
|
@cpp{NULL}, *@var{expanded} is set to 1 if some expansion takes place,
|
||||||
|
or 0 if the input name is simply returned.
|
||||||
|
|
||||||
|
If @var{guards} is not @cpp{0}, then @cpp{scheme_security_check_file}
|
||||||
|
(see @secref["security"]) is called with @var{name}, @var{where}, and
|
||||||
|
@var{checks} (which implies that @var{where} should never be
|
||||||
|
@cpp{NULL} unless @var{guards} is @cpp{0}). Normally, @var{guards}
|
||||||
|
should be @cpp{SCHEME_GUARD_FILE_EXISTS} at a minimum. Note that a
|
||||||
|
failed access check will result in an exception.}
|
||||||
|
|
||||||
|
@function[(char* scheme_expand_string_filename
|
||||||
|
[Scheme_Object* name]
|
||||||
|
[const-char* where]
|
||||||
|
[int* expanded]
|
||||||
|
[int checks])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_expand_string}, but given a @var{name} that can be a
|
||||||
|
character string or a path value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_char_string_to_path
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme character string into a Scheme path value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_path_to_char_string
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme path value into a Scheme character string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_path
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Makes a path value given a byte string. The @var{bytes} string is copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_path_without_copying
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_path}, but the string is not copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_path
|
||||||
|
[char* bytes]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Makes a path whose byte form has size @var{len}. A copy of @var{bytes}
|
||||||
|
is made if @var{copy} is not 0. The string @var{bytes} should contain
|
||||||
|
@var{len} bytes, and if @var{copy} is zero, @var{bytes} must have a
|
||||||
|
nul terminator in addition. If @var{len} is negative, then the
|
||||||
|
nul-terminated length of @var{bytes} is used for the length.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_path
|
||||||
|
[char* bytes]
|
||||||
|
[long d]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_sized_path}, except the @var{len} bytes start
|
||||||
|
from position @var{d} in @var{bytes}. If @var{d} is non-zero, then
|
||||||
|
@var{copy} must be non-zero.}
|
||||||
|
|
||||||
|
@function[(char* scheme_build_mac_filename
|
||||||
|
[FSSpec* spec]
|
||||||
|
[int isdir])]{
|
||||||
|
|
||||||
|
Mac OS X only: Converts an @cppi{FSSpec} record (defined by Mac OS X)
|
||||||
|
into a pathname string. If @var{spec} contains only directory
|
||||||
|
information (via the @cpp{vRefNum} and @cpp{parID} fields),
|
||||||
|
@var{isdir} should be @cpp{1}, otherwise it should be @cpp{0}.}
|
||||||
|
|
||||||
|
@function[(int scheme_mac_path_to_spec
|
||||||
|
[const-char* filename]
|
||||||
|
[FSSpec* spec]
|
||||||
|
[long* type])]{
|
||||||
|
|
||||||
|
Mac OS X only: Converts a pathname into an @cppi{FSSpec} record
|
||||||
|
(defined by Mac OS X), returning @cpp{1} if successful and @cpp{0}
|
||||||
|
otherwise. If @var{type} is not @cpp{NULL} and @var{filename} is a
|
||||||
|
file that exists, @var{type} is filled with the file's four-character
|
||||||
|
Mac OS X type. If @var{type} is not @cpp{NULL} and @var{filename} is
|
||||||
|
not a file that exists, @var{type} is filled with @cpp{0}.}
|
||||||
|
|
||||||
|
@function[(char* scheme_os_getcwd
|
||||||
|
[char* buf]
|
||||||
|
[int buflen]
|
||||||
|
[int* actlen]
|
||||||
|
[int noexn])]{
|
||||||
|
|
||||||
|
Gets the @as-index{current working directory} according to the
|
||||||
|
operating system. This is separate from MzScheme's current directory
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
The directory path is written into @var{buf}, of length @var{buflen},
|
||||||
|
if it fits. Otherwise, a new (collectable) string is allocated for the
|
||||||
|
directory path. If @var{actlen} is not @cpp{NULL}, *@var{actlen} is
|
||||||
|
set to the length of the current directory path. If @var{noexn} is
|
||||||
|
no 0, then an exception is raised if the operation fails.}
|
||||||
|
|
||||||
|
@function[(int scheme_os_setcwd
|
||||||
|
[char* buf]
|
||||||
|
[int noexn])]{
|
||||||
|
|
||||||
|
Sets the current working directory according to the operating system. This
|
||||||
|
is separate from MzScheme's current directory parameter.
|
||||||
|
|
||||||
|
If @var{noexn} is not 0, then an exception is raised if the operation
|
||||||
|
fails.}
|
||||||
|
|
||||||
|
@function[(char* scheme_format
|
||||||
|
[mzchar* format]
|
||||||
|
[int flen]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv]
|
||||||
|
[long* rlen])]{
|
||||||
|
|
||||||
|
Creates a string like MzScheme's @scheme[format] procedure, using the
|
||||||
|
format string @var{format} (of length @var{flen}) and the extra
|
||||||
|
arguments specified in @var{argc} and @var{argv}. If @var{rlen} is not
|
||||||
|
@cpp{NULL}, @cpp{*@var{rlen}} is filled with the length of the
|
||||||
|
resulting string.}
|
||||||
|
|
||||||
|
@function[(void scheme_printf
|
||||||
|
[char* format]
|
||||||
|
[int flen]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Writes to the current output port like MzScheme's @scheme[printf]
|
||||||
|
procedure, using the format string @var{format} (of length @var{flen})
|
||||||
|
and the extra arguments specified in @var{argc} and @var{argv}.}
|
||||||
|
|
||||||
|
@function[(char* scheme_format_utf8
|
||||||
|
[char* format]
|
||||||
|
[int flen]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv]
|
||||||
|
[long* rlen])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_format}, but takes a UTF-8-encoding byte string.}
|
||||||
|
|
||||||
|
@function[(void scheme_printf_utf8
|
||||||
|
[char* format]
|
||||||
|
[int flen]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_printf}, but takes a UTF-8-encoding byte string.}
|
||||||
|
|
||||||
|
@function[(int scheme_close_should_force_port_closed)]{
|
||||||
|
|
||||||
|
This function must be called by the close function for a port created
|
||||||
|
with @cpp{scheme_make_output_port}.}
|
134
collects/scribblings/inside/procedures.scrbl
Normal file
134
collects/scribblings/inside/procedures.scrbl
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Procedures}
|
||||||
|
|
||||||
|
A @defterm{primitive procedure} is a Scheme-callable procedure that is
|
||||||
|
implemented in C. Primitive procedures are created in Scheme with
|
||||||
|
the function @cppi{scheme_make_prim_w_arity}, which takes a C function
|
||||||
|
pointer, the name of the primitive, and information about the number
|
||||||
|
of Scheme arguments that it takes; it returns a Scheme procedure
|
||||||
|
value.
|
||||||
|
|
||||||
|
The C function implementing the procedure must take two arguments: an
|
||||||
|
integer that specifies the number of arguments passed to the
|
||||||
|
procedure, and an array of @cpp{Scheme_Object*} arguments. The number
|
||||||
|
of arguments passed to the function will be checked using the arity
|
||||||
|
information. (The arity information provided to
|
||||||
|
@cpp{scheme_make_prim_w_arity} is also used for the Scheme
|
||||||
|
@scheme[arity] procedure.) The procedure implementation is not allowed
|
||||||
|
to mutate the input array of arguments, although it may mutate the
|
||||||
|
arguments themselves when appropriate (e.g., a fill in a vector
|
||||||
|
argument).
|
||||||
|
|
||||||
|
The function @cppi{scheme_make_prim_closure_w_arity} is similar to
|
||||||
|
@cpp{scheme_make_prim_w_arity}, but it takes an additional count and
|
||||||
|
@cpp{Scheme_Object*} array that is copied into the created procedure;
|
||||||
|
the procedure is passed back to the C function when the closure is
|
||||||
|
invoked. In this way, closure-like data from the C world can be
|
||||||
|
associated with the primitive procedure.
|
||||||
|
|
||||||
|
The function @cppi{scheme_make_closed_prim_w_arity} is similar to
|
||||||
|
@cpp{scheme_make_prim_closure_w_arity}, but it uses an older calling
|
||||||
|
convention for passing closure data.
|
||||||
|
|
||||||
|
To work well with Scheme threads, a C function that performs
|
||||||
|
substantial or unbounded work should occasionally call
|
||||||
|
@cpp{SCHEME_USE_FUEL}; see @secref["usefuel"] for details.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_prim_w_arity
|
||||||
|
[Scheme_Prim* prim]
|
||||||
|
[char* name]
|
||||||
|
[int mina]
|
||||||
|
[int maxa])]{
|
||||||
|
|
||||||
|
Creates a primitive procedure value, given the C function pointer
|
||||||
|
@var{prim}. The form of @var{prim} is defined by:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef Scheme_Object *(Scheme_Prim)(int argc,
|
||||||
|
Scheme_Object **argv);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The value @var{mina} should be the minimum number of arguments that
|
||||||
|
must be supplied to the procedure. The value @var{maxa} should be the
|
||||||
|
maximum number of arguments that can be supplied to the procedure, or
|
||||||
|
-1 if the procedure can take arbitrarily many arguments. The
|
||||||
|
@var{mina} and @var{maxa} values are used for automatically checking
|
||||||
|
the argument count before the primitive is invoked, and also for the
|
||||||
|
Scheme @indexed-scheme[arity] procedure. The @var{name} argument is
|
||||||
|
used to report application arity errors at run-time.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_folding_prim
|
||||||
|
[Scheme_Prim* prim]
|
||||||
|
[char* name]
|
||||||
|
[int mina]
|
||||||
|
[int maxa]
|
||||||
|
[short folding])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_prim_w_arity}, but if @var{folding} is non-zero,
|
||||||
|
the compiler assumes that an application of the procedure to constant
|
||||||
|
values can be folded to a constant. For example, @scheme[+],
|
||||||
|
@scheme[zero?], and @scheme[string-length] are folding primitives, but
|
||||||
|
@scheme[display] and @scheme[cons] are not.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_prim
|
||||||
|
[Scheme_Prim* prim])]{
|
||||||
|
|
||||||
|
Same as @cppi{scheme_make_prim_w_arity}, but the arity (0, -1) and the
|
||||||
|
name ``UNKNOWN'' is assumed. This function is provided for backward
|
||||||
|
compatibility only.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_prim_closure_w_arity
|
||||||
|
[Scheme_Prim_Closure_Proc* prim]
|
||||||
|
[int c]
|
||||||
|
[Scheme_Object* vals]
|
||||||
|
[char* name]
|
||||||
|
[int mina]
|
||||||
|
[int maxa])]{
|
||||||
|
|
||||||
|
Creates a primitive procedure value that includes the @var{c} values
|
||||||
|
in @var{vals}; when the C function @var{prim} is invoked, the
|
||||||
|
generated primitive is passed as the last parameter. The form of
|
||||||
|
@var{prim} is defined by:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef
|
||||||
|
Scheme_Object *(Scheme_Prim_Closure_Proc)(int argc,
|
||||||
|
Scheme_Object **argv,
|
||||||
|
Scheme_Object *prim);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The macro @cppi{SCHEME_PRIM_CLOSURE_ELS} takes a primitive-closure
|
||||||
|
object and returns an array with the same length and content as
|
||||||
|
@var{vals}. (3m: see @secref["im:3m"] for a caution about
|
||||||
|
@cppi{SCHEME_PRIM_CLOSURE_ELS}.)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_closed_prim_w_arity
|
||||||
|
[Scheme_Closed_Prim* prim]
|
||||||
|
[void* data]
|
||||||
|
[char* name]
|
||||||
|
[int mina]
|
||||||
|
[int maxa])]{
|
||||||
|
|
||||||
|
Creates an old-style primitive procedure value; when the C function
|
||||||
|
@var{prim} is invoked, @var{data} is passed as the first parameter.
|
||||||
|
The form of @var{prim} is defined by:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef
|
||||||
|
Scheme_Object *(Scheme_Closed_Prim)(void *data, int argc,
|
||||||
|
Scheme_Object **argv);
|
||||||
|
EOS
|
||||||
|
]}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_closed_prim
|
||||||
|
[Scheme_Closed_Prim* prim]
|
||||||
|
[void* data])]{
|
||||||
|
|
||||||
|
Creates a closed primitive procedure value without arity information.
|
||||||
|
This function is provided for backward compatibility only.}
|
60
collects/scribblings/inside/security.scrbl
Normal file
60
collects/scribblings/inside/security.scrbl
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "security"]{Security Guards}
|
||||||
|
|
||||||
|
Before a primitive procedure accesses the filesystem or creates a
|
||||||
|
network connection, it should first consult the current security guard
|
||||||
|
to determine whether such access is allowed for the current thread.
|
||||||
|
|
||||||
|
File access is normally preceded by a call to
|
||||||
|
@cppi{scheme_expand_filename}, which accepts flags to indicate the
|
||||||
|
kind of filesystem access needed, so that the security guard is
|
||||||
|
consulted automatically.
|
||||||
|
|
||||||
|
An explicit filesystem-access check can be made by calling
|
||||||
|
@cpp{scheme_security_check_file}. Similarly, an explicit
|
||||||
|
network-access check is performed by calling
|
||||||
|
@cpp{scheme_security_check_network}.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_security_check_file
|
||||||
|
[const-char* who]
|
||||||
|
[char* filename]
|
||||||
|
[int guards])]{
|
||||||
|
|
||||||
|
Consults the current security manager to determine whether access is
|
||||||
|
allowed to @var{filename}. The @var{guards} argument should be a
|
||||||
|
bitwise combination of the following:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_GUARD_FILE_READ}}
|
||||||
|
@item{@cppi{SCHEME_GUARD_FILE_WRITE}}
|
||||||
|
@item{@cppi{SCHEME_GUARD_FILE_EXECUTE}}
|
||||||
|
@item{@cppi{SCHEME_GUARD_FILE_DELETE}}
|
||||||
|
@item{@cppi{SCHEME_GUARD_FILE_EXISTS} (do not combine with other values)}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
The @var{filename} argument can be @cpp{NULL} (in which case
|
||||||
|
@scheme[#f] is sent to the security manager's procedure), and
|
||||||
|
@var{guards} should be @cppi{SCHEME_GUARD_FILE_EXISTS} in that case.
|
||||||
|
|
||||||
|
If access is denied, an exception is raised.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_security_check_network
|
||||||
|
[const-char* who]
|
||||||
|
[char* host]
|
||||||
|
[int portno])]{
|
||||||
|
|
||||||
|
Consults the current security manager to determine whether access is
|
||||||
|
allowed for creating a client connection to @var{host} on port number
|
||||||
|
@var{portno}. If @var{host} is @cpp{NULL}, the security manager is
|
||||||
|
consulted for creating a server at port number @var{portno}.
|
||||||
|
|
||||||
|
If access is denied, an exception is raised.}
|
||||||
|
|
256
collects/scribblings/inside/strings.scrbl
Normal file
256
collects/scribblings/inside/strings.scrbl
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "im:encodings"]{String Encodings}
|
||||||
|
|
||||||
|
The @cpp{scheme_utf8_decode} function decodes a @cpp{char} array as
|
||||||
|
UTF-8 into either a UCS-4 @cpp{mzchar} array or a UTF-16 @cpp{short}
|
||||||
|
array. The @cpp{scheme_utf8_encode} function encodes either a UCS-4
|
||||||
|
@cpp{mzchar} array or a UTF-16 @cpp{short} array into a UTF-8
|
||||||
|
@cpp{char} array.
|
||||||
|
|
||||||
|
These functions can be used to check or measure an encoding or
|
||||||
|
decoding without actually producing the result decoding or encoding,
|
||||||
|
and variations of the function provide control over the handling of
|
||||||
|
decoding errors.
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_decode
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[mzchar* us]
|
||||||
|
[int dstart]
|
||||||
|
[int dend]
|
||||||
|
[long* ipos]
|
||||||
|
[char utf16]
|
||||||
|
[int permissive])]{
|
||||||
|
|
||||||
|
Decodes a byte array as UTF-8 to produce either Unicode code points
|
||||||
|
into @var{us} (when @var{utf16} is zero) or UTF-16 code units into
|
||||||
|
@var{us} cast to @cpp{short*} (when @var{utf16} is non-zero). No nul
|
||||||
|
terminator is added to @var{us}.
|
||||||
|
|
||||||
|
The result is non-negative when all of the given bytes are decoded,
|
||||||
|
and the result is the length of the decoding (in @cpp{mzchar}s or
|
||||||
|
@cpp{short}s). A @cpp{-2} result indicates an invalid encoding
|
||||||
|
sequence in the given bytes (possibly because the range to decode
|
||||||
|
ended mid-encoding), and a @cpp{-3} result indicates that decoding
|
||||||
|
stopped because not enough room was available in the result string.
|
||||||
|
|
||||||
|
The @var{start} and @var{end} arguments specify a range of @var{s} to
|
||||||
|
be decoded. If @var{end} is negative, @cpp{strlen(@var{s})} is used
|
||||||
|
as the end.
|
||||||
|
|
||||||
|
If @var{us} is @cpp{NULL}, then decoded bytes are not produced, but
|
||||||
|
the result is valid as if decoded bytes were written. The
|
||||||
|
@var{dstart} and @var{dend} arguments specify a target range in
|
||||||
|
@var{us} (in @cpp{mzchar} or @cpp{short} units) for the decoding; a
|
||||||
|
negative value for @var{dend} indicates that any number of bytes can
|
||||||
|
be written to @var{us}, which is normally sensible only when @var{us}
|
||||||
|
is @cpp{NULL} for measuring the length of the decoding.
|
||||||
|
|
||||||
|
If @var{ipos} is non-@cpp{NULL}, it is filled with the first undecoded
|
||||||
|
index within @var{s}. If the function result is non-negative, then
|
||||||
|
@cpp{*@var{ipos}} is set to the ending index (with is @var{end} if
|
||||||
|
non-negative, @cpp{strlen(@var{s})} otherwise). If the result is
|
||||||
|
@cpp{-1} or @cpp{-2}, then @cpp{*@var{ipos}} effectively indicates
|
||||||
|
how many bytes were decoded before decoding stopped.
|
||||||
|
|
||||||
|
If @var{permissive} is non-zero, it is used as the decoding of bytes
|
||||||
|
that are not part of a valid UTF-8 encoding. Thus, the function
|
||||||
|
result can be @cpp{-2} only if @var{permissive} is @cpp{0}.
|
||||||
|
|
||||||
|
This function does not allocate or trigger garbage collection.}
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_decode_as_prefix
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[mzchar* us]
|
||||||
|
[int dstart]
|
||||||
|
[int dend]
|
||||||
|
[long* ipos]
|
||||||
|
[char utf16]
|
||||||
|
[int permissive])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode}, but the result is always the number
|
||||||
|
of the decoded @cpp{mzchar}s or @cpp{short}s. If a decoding error is
|
||||||
|
encountered, the result is still the size of the decoding up until
|
||||||
|
the error.}
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_decode_all
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int len]
|
||||||
|
[mzchar* us]
|
||||||
|
[int permissive])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode}, but with fewer arguments. The
|
||||||
|
decoding produces UCS-4 @cpp{mzchar}s. If the buffer @var{us} is
|
||||||
|
non-@cpp{NULL}, it is assumed to be long enough to hold the decoding
|
||||||
|
(which cannot be longer than the length of the input, though it may
|
||||||
|
be shorter). If @var{len} is negative, @cpp{strlen(@var{s})} is used
|
||||||
|
as the input length.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_decode_prefix
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int len]
|
||||||
|
[mzchar* us]
|
||||||
|
[int permissive])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode}, but with fewer arguments. The
|
||||||
|
decoding produces UCS-4 @cpp{mzchar}s. If the buffer @var{us}
|
||||||
|
@bold{must} be non-@cpp{NULL}, and it is assumed to be long enough to hold the
|
||||||
|
decoding (which cannot be longer than the length of the input, though
|
||||||
|
it may be shorter). If @var{len} is negative, @cpp{strlen(@var{s})}
|
||||||
|
is used as the input length.
|
||||||
|
|
||||||
|
In addition to the result of @cpp{scheme_utf8_decode}, the result
|
||||||
|
can be @cpp{-1} to indicate that the input ended with a partial
|
||||||
|
(valid) encoding. A @cpp{-1} result is possible even when
|
||||||
|
@var{permissive} is non-zero.}
|
||||||
|
|
||||||
|
@function[(mzchar* scheme_utf8_decode_to_buffer
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int len]
|
||||||
|
[mzchar* buf]
|
||||||
|
[int blen])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode_all} with @var{permissive} as @cpp{0},
|
||||||
|
but if @var{buf} is not large enough (as indicated by @var{blen}) to
|
||||||
|
hold the result, a new buffer is allocated. Unlike other functions,
|
||||||
|
this one adds a nul terminator to the decoding result. The function
|
||||||
|
result is either @var{buf} (if it was big enough) or a buffer
|
||||||
|
allocated with @cpp{scheme_malloc_atomic}.}
|
||||||
|
|
||||||
|
@function[(mzchar* scheme_utf8_decode_to_buffer_len
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int len]
|
||||||
|
[mzchar* buf]
|
||||||
|
[int blen]
|
||||||
|
[long* ulen])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode_to_buffer}, but the length of the
|
||||||
|
result (not including the terminator) is placed into @var{ulen} if
|
||||||
|
@var{ulen} is non-@cpp{NULL}.}
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_decode_count
|
||||||
|
[const-unsigned-char* s]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[int* state]
|
||||||
|
[int might_continue]
|
||||||
|
[int permissive])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_decode}, but without producing the decoded
|
||||||
|
@cpp{mzchar}s, and always returning the number of decoded
|
||||||
|
@cpp{mzchar}s up until a decoding error (if any). If
|
||||||
|
@var{might_continue} is non-zero, the a partial valid encoding at
|
||||||
|
the end of the input is not decoded when @var{permissive} is also
|
||||||
|
non-zero.
|
||||||
|
|
||||||
|
If @var{state} is non-@cpp{NULL}, it holds information about partial
|
||||||
|
encodings; it should be set to zero for an initial call, and then
|
||||||
|
passed back to @cpp{scheme_utf8_decode} along with bytes that
|
||||||
|
extend the given input (i.e., without any unused partial
|
||||||
|
encodings). Typically, this mode makes sense only when
|
||||||
|
@var{might_continue} and @var{permissive} are non-zero.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_encode
|
||||||
|
[const-mzchar* us]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[unsigned-char* s]
|
||||||
|
[int dstart]
|
||||||
|
[char utf16])]{
|
||||||
|
|
||||||
|
Encodes the given UCS-4 array of @cpp{mzchar}s (if @var{utf16} is
|
||||||
|
zero) or UTF-16 array of @cpp{short}s (if @var{utf16} is non-zero)
|
||||||
|
into @var{s}. The @var{end} argument must be no less than
|
||||||
|
@var{start}.
|
||||||
|
|
||||||
|
The array @var{s} is assumed to be long enough to contain the
|
||||||
|
encoding, but no encoding is written if @var{s} is @cpp{NULL}. The
|
||||||
|
@var{dstart} argument indicates a starting place in @var{s} to hold
|
||||||
|
the encoding. No nul terminator is added to @var{s}.
|
||||||
|
|
||||||
|
The result is the number of bytes produced for the encoding (or that
|
||||||
|
would be produced if @var{s} was non-@cpp{NULL}). Encoding never
|
||||||
|
fails.
|
||||||
|
|
||||||
|
This function does not allocate or trigger garbage collection.}
|
||||||
|
|
||||||
|
@function[(int scheme_utf8_encode_all
|
||||||
|
[const-mzchar* us]
|
||||||
|
[int len]
|
||||||
|
[unsigned-char* s])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_encode} with @cpp{0} for @var{start},
|
||||||
|
@var{len} for @var{end}, @cpp{0} for @var{dstart} and @cpp{0} for
|
||||||
|
@var{utf16}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(char* scheme_utf8_encode_to_buffer
|
||||||
|
[const-mzchar* s]
|
||||||
|
[int len]
|
||||||
|
[char* buf]
|
||||||
|
[int blen])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_encode_all}, but the length of @var{buf} is
|
||||||
|
given, and if it is not long enough to hold the encoding, a buffer is
|
||||||
|
allocated. A nul terminator is added to the encoded array. The result
|
||||||
|
is either @var{buf} or an array allocated with
|
||||||
|
@cpp{scheme_malloc_atomic}.}
|
||||||
|
|
||||||
|
@function[(char* scheme_utf8_encode_to_buffer_len
|
||||||
|
[const-mzchar* s]
|
||||||
|
[int len]
|
||||||
|
[char* buf]
|
||||||
|
[int blen]
|
||||||
|
[long* rlen])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_utf8_encode_to_buffer}, but the length of the
|
||||||
|
resulting encoding (not including a nul terminator) is reported in
|
||||||
|
@var{rlen} if it is non-@cpp{NULL}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(unsigned-short* scheme_ucs4_to_utf16
|
||||||
|
[const-mzchar* text]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[unsigned-short* buf]
|
||||||
|
[int bufsize]
|
||||||
|
[long* ulen]
|
||||||
|
[int term_size])]{
|
||||||
|
|
||||||
|
Converts a UCS-4 encoding (the indicated range of @var{text}) to a
|
||||||
|
UTF-16 encoding. The @var{end} argument must be no less than
|
||||||
|
@var{start}.
|
||||||
|
|
||||||
|
A result buffer is allocated if @var{buf} is not long enough (as
|
||||||
|
indicated by @var{bufsize}). If @var{ulen} is non-@cpp{NULL}, it is
|
||||||
|
filled with the length of the UTF-16 encoding. The @var{term_size}
|
||||||
|
argument indicates a number of @cpp{short}s to reserve at the end of
|
||||||
|
the result buffer for a terminator (but no terminator is actually
|
||||||
|
written).}
|
||||||
|
|
||||||
|
@function[(mzchar* scheme_utf16_to_ucs4
|
||||||
|
[const-unsigned-short* text]
|
||||||
|
[int start]
|
||||||
|
[int end]
|
||||||
|
[mzchar* buf]
|
||||||
|
[int bufsize]
|
||||||
|
[long* ulen]
|
||||||
|
[int term_size])]{
|
||||||
|
|
||||||
|
Converts a UTF-16 encoding (the indicated range of @var{text}) to a
|
||||||
|
UCS-4 encoding. The @var{end} argument must be no less than
|
||||||
|
@var{start}.
|
||||||
|
|
||||||
|
A result buffer is allocated if @var{buf} is not long enough (as
|
||||||
|
indicated by @var{bufsize}). If @var{ulen} is non-@cpp{NULL}, it is
|
||||||
|
filled with the length of the UCS-4 encoding. The @var{term_size}
|
||||||
|
argument indicates a number of @cpp{mzchar}s to reserve at the end of
|
||||||
|
the result buffer for a terminator (but no terminator is actually
|
||||||
|
written).}
|
137
collects/scribblings/inside/structures.scrbl
Normal file
137
collects/scribblings/inside/structures.scrbl
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title{Structures}
|
||||||
|
|
||||||
|
A new Scheme structure type is created with
|
||||||
|
@cppi{scheme_make_struct_type}. This creates the structure type, but
|
||||||
|
does not generate the constructor, etc. procedures. The
|
||||||
|
@cppi{scheme_make_struct_values} function takes a structure type and
|
||||||
|
creates these procedures. The @cppi{scheme_make_struct_names} function
|
||||||
|
generates the standard structure procedures names given the structure
|
||||||
|
type's name. Instances of a structure type are created with
|
||||||
|
@cppi{scheme_make_struct_instance} and the function
|
||||||
|
@cppi{scheme_is_struct_instance} tests a structure's type. The
|
||||||
|
@cppi{scheme_struct_ref} and @cppi{scheme_struct_set} functions access
|
||||||
|
or modify a field of a structure.
|
||||||
|
|
||||||
|
The the structure procedure values and names generated by
|
||||||
|
@cpp{scheme_make_struct_values} and @cpp{scheme_make_struct_names} can
|
||||||
|
be restricted by passing any combination of these flags:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_NO_TYPE} --- the structure type
|
||||||
|
value/name is not returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_NO_CONSTR} --- the constructor procedure
|
||||||
|
value/name is not returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_NO_PRED}--- the predicate procedure
|
||||||
|
value/name is not returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_NO_GET} --- the selector procedure
|
||||||
|
values/names are not returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_NO_SET} --- the mutator procedure
|
||||||
|
values/names are not returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_GEN_GET} --- the field-independent
|
||||||
|
selector procedure value/name is returned.}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_STRUCT_GEN_SET} --- the field-independent
|
||||||
|
mutator procedure value/name is returned.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
When all values or names are returned, they are returned as an array
|
||||||
|
with the following order: structure type, constructor, predicate,
|
||||||
|
first selector, first mutator, second selector, etc.,
|
||||||
|
field-independent select, field-independent mutator. When particular
|
||||||
|
values/names are omitted, the array is compressed accordingly.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_struct_type
|
||||||
|
[Scheme_Object* base_name]
|
||||||
|
[Scheme_Object* super_type]
|
||||||
|
[Scheme_Object* inspector]
|
||||||
|
[int num_init_fields]
|
||||||
|
[int num_auto_fields]
|
||||||
|
[Scheme_Object* auto_val]
|
||||||
|
[Scheme_Object* properties]
|
||||||
|
[Scheme_Object* guard])]{
|
||||||
|
|
||||||
|
Creates and returns a new structure type. The @var{base_name}
|
||||||
|
argument is used as the name of the new structure type; it must be a
|
||||||
|
symbol. The @var{super_type} argument should be @cpp{NULL} or an
|
||||||
|
existing structure type to use as the super-type. The @var{inspector}
|
||||||
|
argument should be @cpp{NULL} or an inspector to manage the type.
|
||||||
|
The @var{num_init_fields} argument specifies the number of fields
|
||||||
|
for instances of this structure type that have corresponding
|
||||||
|
constructor arguments. (If a super-type is used, this is the number
|
||||||
|
of additional fields, rather than the total number.) The
|
||||||
|
@var{num_auto_fields} argument specifies the number of additional
|
||||||
|
fields that have no corresponding constructor arguments, and they are
|
||||||
|
initialized to @var{auto_val}. The @var{properties} argument is a
|
||||||
|
list of property-value pairs. The @var{guard} argument is either NULL
|
||||||
|
or a procedure to use as a constructor guard.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object** scheme_make_struct_names
|
||||||
|
[Scheme_Object* base_name]
|
||||||
|
[Scheme_Object* field_names]
|
||||||
|
[int flags]
|
||||||
|
[int* count_out])]{
|
||||||
|
|
||||||
|
Creates and returns an array of standard structure value name
|
||||||
|
symbols. The @var{base_name} argument is used as the name of the
|
||||||
|
structure type; it should be the same symbol passed to the associated
|
||||||
|
call to @cpp{scheme_make_struct_type}. The @var{field_names} argument
|
||||||
|
is a (Scheme) list of field name symbols. The @var{flags} argument
|
||||||
|
specifies which names should be generated, and if @var{count_out} is
|
||||||
|
not @cpp{NULL}, @var{count_out} is filled with the number of names
|
||||||
|
returned in the array.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object** scheme_make_struct_values
|
||||||
|
[Scheme_Object* struct_type]
|
||||||
|
[Scheme_Object** names]
|
||||||
|
[int count]
|
||||||
|
[int flags])]{
|
||||||
|
|
||||||
|
Creates and returns an array of the standard structure value and procedure values
|
||||||
|
for @var{struct_type}. The @var{struct_type} argument must be a structure type
|
||||||
|
value created by @cpp{scheme_make_struct_type}. The @var{names} procedure
|
||||||
|
must be an array of name symbols, generally the array returned by
|
||||||
|
@cpp{scheme_make_struct_names}. The @var{count} argument specifies the
|
||||||
|
length of the @var{names} array (and therefore the number of expected
|
||||||
|
return values) and the @var{flags} argument specifies which values
|
||||||
|
should be generated.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_struct_instance
|
||||||
|
[Scheme_Object* struct_type]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Creates an instance of the structure type @var{struct_type}. The
|
||||||
|
@var{argc} and @var{argv} arguments provide the field values for the
|
||||||
|
new instance.}
|
||||||
|
|
||||||
|
@function[(int scheme_is_struct_instance
|
||||||
|
[Scheme_Object* struct_type]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Returns 1 if @var{v} is an instance of @var{struct_type} or 0 otherwise.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_struct_ref
|
||||||
|
[Scheme_Object* s]
|
||||||
|
[int n])]{
|
||||||
|
|
||||||
|
Returns the @var{n}th field (counting from 0) in the structure @var{s}.}
|
||||||
|
|
||||||
|
@function[(void scheme_struct_set
|
||||||
|
[Scheme_Object* s]
|
||||||
|
[int n]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Sets the @var{n}th field (counting from 0) in the structure @var{s} to @var{v}.}
|
||||||
|
|
736
collects/scribblings/inside/threads.scrbl
Normal file
736
collects/scribblings/inside/threads.scrbl
Normal file
|
@ -0,0 +1,736 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss"
|
||||||
|
(for-label scheme/tcp))
|
||||||
|
|
||||||
|
@title[#:tag "threads"]{Threads}
|
||||||
|
|
||||||
|
The initializer function @cppi{scheme_basic_env} creates the main
|
||||||
|
Scheme thread; all other threads are created through calls to
|
||||||
|
@cppi{scheme_thread}.
|
||||||
|
|
||||||
|
Information about each internal Scheme thread is kept in a
|
||||||
|
@cppi{Scheme_Thread} structure. A pointer to the current thread's
|
||||||
|
structure is available as @cppi{scheme_current_thread}. A
|
||||||
|
@cpp{Scheme_Thread} structure includes the following fields:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{error_buf} --- the @cppi{mz_jmp_buf} value used to escape
|
||||||
|
from errors. The @cpp{error_buf} value of the current thread is
|
||||||
|
available as @cppi{scheme_error_buf}.}
|
||||||
|
|
||||||
|
@item{@cppi{cjs.jumping_to_continuation} --- a flag that
|
||||||
|
distinguishes escaping-continuation invocations from error
|
||||||
|
escapes. The @cpp{cjs.jumping_to_continuation} value of the current
|
||||||
|
thread is available as @cppi{scheme_jumping_to_continuation}.}
|
||||||
|
|
||||||
|
@item{@cppi{init_config} ---
|
||||||
|
the thread's initial parameterization. See also @secref["config"].}
|
||||||
|
|
||||||
|
@item{@cppi{cell_values} --- The thread's values for thread cells
|
||||||
|
(see also @secref["config"]).}
|
||||||
|
|
||||||
|
@item{@cppi{next} --- The next thread in the linked list of threads;
|
||||||
|
this is @cpp{NULL} for the main thread.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
The list of all scheduled threads is kept in a linked list;
|
||||||
|
@cppi{scheme_first_thread} points to the first thread in the list.
|
||||||
|
The last thread in the list is always the main thread.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Integration with Threads}
|
||||||
|
|
||||||
|
Scheme's threads can break external C code under two circumstances:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@italic{Pointers to stack-based values can be communicated
|
||||||
|
between threads.} For example, if thread A stores a pointer to a
|
||||||
|
stack-based variable in a global variable, if thread B uses the
|
||||||
|
pointer in the global variable, it may point to data that is not
|
||||||
|
currently on the stack.}
|
||||||
|
|
||||||
|
@item{@italic{C functions that can invoke Scheme (and also be invoked
|
||||||
|
by Scheme) depend on strict function-call nesting.} For example,
|
||||||
|
suppose a function F uses an internal stack, pushing items on to the
|
||||||
|
stack on entry and popping the same items on exit. Suppose also that
|
||||||
|
F invokes Scheme to evaluate an expression. If the evaluation of
|
||||||
|
this expression invokes F again in a new thread, but then returns to
|
||||||
|
the first thread before completing the second F, then F's internal
|
||||||
|
stack will be corrupted.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
If either of these circumstances occurs, Scheme will probably crash.
|
||||||
|
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "usefuel"]{Allowing Thread Switches}
|
||||||
|
|
||||||
|
C code that performs substantial or unbounded work should occasionally
|
||||||
|
call @cppi{SCHEME_USE_FUEL}---actually a macro---which allows Scheme
|
||||||
|
to swap in another Scheme thread to run, and to check for breaks on
|
||||||
|
the current thread. In particular, if breaks are enabled, then
|
||||||
|
@cpp{SCHEME_USE_FUEL} may trigger an exception.
|
||||||
|
|
||||||
|
The macro consumes an integer argument. On most platforms, where
|
||||||
|
thread scheduling is based on timer interrupts, the argument is
|
||||||
|
ignored. On some platforms, however, the integer represents the amount
|
||||||
|
of ``fuel'' that has been consumed since the last call to
|
||||||
|
@cpp{SCHEME_USE_FUEL}. For example, the implementation of
|
||||||
|
@scheme[vector->list] consumes a unit of fuel for each created cons
|
||||||
|
cell:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
Scheme_Object *scheme_vector_to_list(Scheme_Object *vec)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Scheme_Object *pair = scheme_null;
|
||||||
|
|
||||||
|
i = SCHEME_VEC_SIZE(vec);
|
||||||
|
|
||||||
|
for (; i--; ) {
|
||||||
|
SCHEME_USE_FUEL(1);
|
||||||
|
pair = scheme_make_pair(SCHEME_VEC_ELS(vec)[i], pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pair;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The @cpp{SCHEME_USE_FUEL} macro expands to a C block, not an
|
||||||
|
expression.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "threadblock"]{Blocking the Current Thread}
|
||||||
|
|
||||||
|
Embedding or extension code sometimes needs to block, but blocking
|
||||||
|
should allow other Scheme threads to execute. To allow other threads
|
||||||
|
to run, block using @cppi{scheme_block_until}. This procedure takes
|
||||||
|
two functions: a polling function that tests whether the blocking
|
||||||
|
operation can be completed, and a prepare-to-sleep function that sets
|
||||||
|
bits in @cpp{fd_set}s when Scheme decides to sleep (because all Scheme
|
||||||
|
threads are blocked). Under Windows, an ``@cpp{fd_set}'' can also
|
||||||
|
accommodate OS-level semaphores or other handles via
|
||||||
|
@cpp{scheme_add_fd_handle}.
|
||||||
|
|
||||||
|
Since the functions passed to @cppi{scheme_block_until} are called by
|
||||||
|
the Scheme thread scheduler, they must never raise exceptions, call
|
||||||
|
@cpp{scheme_apply}, or trigger the evaluation of Scheme code in any
|
||||||
|
way. The @cpp{scheme_block_until} function itself may call the current
|
||||||
|
exception handler, however, in reaction to a break (if breaks are
|
||||||
|
enabled).
|
||||||
|
|
||||||
|
When a blocking operation is associated with an object, then the
|
||||||
|
object might make sense as an argument to @indexed-scheme[sync]. To
|
||||||
|
extend the set of objects accepted by @scheme[sync], either register
|
||||||
|
polling and sleeping functions with @cppi{scheme_add_evt}, or register
|
||||||
|
a semaphore accessor with @cppi{scheme_add_evt_through_sema}.
|
||||||
|
|
||||||
|
The @cppi{scheme_signal_received} function can be called to wake up
|
||||||
|
Scheme when it is sleeping. In particular, calling
|
||||||
|
@cppi{scheme_signal_received} ensures that Scheme will poll all
|
||||||
|
blocking synchronizations soon afterward. Furthermore,
|
||||||
|
@cpp{scheme_signal_received} can be called from any OS-level thread.
|
||||||
|
Thus, when no adequate prepare-to-sleep function can be implemented
|
||||||
|
for @cpp{scheme_block_until} in terms of file descriptors or Windows
|
||||||
|
handles, calling @cpp{scheme_signal_received} when the poll result
|
||||||
|
changes will ensure that a poll is issued.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "threadtime"]{Threads in Embedded Scheme with Event Loops}
|
||||||
|
|
||||||
|
When Scheme is embedded in an application with an event-based model
|
||||||
|
(i.e., the execution of Scheme code in the main thread is repeatedly
|
||||||
|
triggered by external events until the application exits) special
|
||||||
|
hooks must be set to ensure that non-main threads execute
|
||||||
|
correctly. For example, during the execution in the main thread, a new
|
||||||
|
thread may be created; the new thread may still be running when the
|
||||||
|
main thread returns to the event loop, and it may be arbitrarily long
|
||||||
|
before the main thread continues from the event loop. Under such
|
||||||
|
circumstances, the embedding program must explicitly allow Scheme to
|
||||||
|
execute the non-main threads; this can be done by periodically calling
|
||||||
|
the function @cppi{scheme_check_threads}.
|
||||||
|
|
||||||
|
Thread-checking only needs to be performed when non-main threads exist
|
||||||
|
(or when there are active callback triggers). The embedding
|
||||||
|
application can set the global function pointer
|
||||||
|
@cppi{scheme_notify_multithread} to a function that takes an integer
|
||||||
|
parameter and returns @cpp{void}. This function is be called with 1
|
||||||
|
when thread-checking becomes necessary, and then with 0 when thread
|
||||||
|
checking is no longer necessary. An embedding program can use this
|
||||||
|
information to prevent unnecessary @cpp{scheme_check_threads} polling.
|
||||||
|
|
||||||
|
The below code illustrates how MrEd formerly set up
|
||||||
|
@cpp{scheme_check_threads} polling using the wxWindows @cpp{wxTimer}
|
||||||
|
class. (Any regular event-loop-based callback is appropriate.) The
|
||||||
|
@cpp{scheme_notify_multithread} pointer is set to
|
||||||
|
@cpp{MrEdInstallThreadTimer}. (MrEd no longer work this way, however.)
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
class MrEdThreadTimer : public wxTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Notify(void); /* callback when timer expires */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int threads_go;
|
||||||
|
static MrEdThreadTimer *theThreadTimer;
|
||||||
|
#define THREAD_WAIT_TIME 40
|
||||||
|
|
||||||
|
void MrEdThreadTimer::Notify()
|
||||||
|
{
|
||||||
|
if (threads_go)
|
||||||
|
Start(THREAD_WAIT_TIME, TRUE);
|
||||||
|
|
||||||
|
scheme_check_threads();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MrEdInstallThreadTimer(int on)
|
||||||
|
{
|
||||||
|
if (!theThreadTimer)
|
||||||
|
theThreadTimer = new MrEdThreadTimer;
|
||||||
|
|
||||||
|
if (on)
|
||||||
|
theThreadTimer->Start(THREAD_WAIT_TIME, TRUE);
|
||||||
|
else
|
||||||
|
theThreadTimer->Stop();
|
||||||
|
|
||||||
|
threads_go = on;
|
||||||
|
if (on)
|
||||||
|
do_this_time = 1;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
An alternate architecture, which MrEd now uses, is to send the main
|
||||||
|
thread into a loop, which blocks until an event is ready to handle.
|
||||||
|
Scheme automatically takes care of running all threads, and it does so
|
||||||
|
efficiently because the main thread blocks on a file descriptor, as
|
||||||
|
explained in @secref["threadblock"].
|
||||||
|
|
||||||
|
@subsection[#:tag "blockednonmainel"]{Callbacks for Blocked Threads}
|
||||||
|
|
||||||
|
Scheme threads are sometimes blocked on file descriptors, such as an
|
||||||
|
input file or the X event socket. Blocked non-main threads do not
|
||||||
|
block the main thread, and therefore do not affect the event loop, so
|
||||||
|
@cppi{scheme_check_threads} is sufficient to implement this case
|
||||||
|
correctly. However, it is wasteful to poll these descriptors with
|
||||||
|
@cpp{scheme_check_threads} when nothing else is happening in the
|
||||||
|
application and when a lower-level poll on the file descriptors can be
|
||||||
|
installed. If the global function pointer
|
||||||
|
@cppi{scheme_wakeup_on_input} is set, then this case is handled more
|
||||||
|
efficiently by turning off thread checking and issuing a ``wakeup''
|
||||||
|
request on the blocking file descriptors through
|
||||||
|
@cpp{scheme_wakeup_on_input}.
|
||||||
|
|
||||||
|
A @cpp{scheme_wakeup_on_input} procedure takes a pointer to an array
|
||||||
|
of three @cpp{fd_set}s (sortof\footnote{To ensure maximum portability,
|
||||||
|
use @cpp{MZ_FD_XXX} instead of @cpp{FD_XXX}.}) and returns
|
||||||
|
@cpp{void}. The @cpp{scheme_wakeup_on_input} does not sleep; it just
|
||||||
|
sets up callbacks on the specified file descriptors. When input is
|
||||||
|
ready on any of those file descriptors, the callbacks are removed and
|
||||||
|
@cpp{scheme_wake_up} is called.
|
||||||
|
|
||||||
|
For example, the X Windows version of MrEd formerly set
|
||||||
|
@cpp{scheme_wakeup_on_input} to this @cpp{MrEdNeedWakeup}:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
static XtInputId *scheme_cb_ids = NULL;
|
||||||
|
static int num_cbs;
|
||||||
|
|
||||||
|
static void MrEdNeedWakeup(void *fds)
|
||||||
|
{
|
||||||
|
int limit, count, i, p;
|
||||||
|
fd_set *rd, *wr, *ex;
|
||||||
|
|
||||||
|
rd = (fd_set *)fds;
|
||||||
|
wr = ((fd_set *)fds) + 1;
|
||||||
|
ex = ((fd_set *)fds) + 2;
|
||||||
|
|
||||||
|
limit = getdtablesize();
|
||||||
|
|
||||||
|
/* See if we need to do any work, really: */
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; i < limit; i++) {
|
||||||
|
if (MZ_FD_ISSET(i, rd))
|
||||||
|
count++;
|
||||||
|
if (MZ_FD_ISSET(i, wr))
|
||||||
|
count++;
|
||||||
|
if (MZ_FD_ISSET(i, ex))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Remove old callbacks: */
|
||||||
|
if (scheme_cb_ids)
|
||||||
|
for (i = 0; i < num_cbs; i++)
|
||||||
|
notify_set_input_func((Notify_client)NULL, (Notify_func)NULL,
|
||||||
|
scheme_cb_ids[i]);
|
||||||
|
|
||||||
|
num_cbs = count;
|
||||||
|
scheme_cb_ids = new int[num_cbs];
|
||||||
|
|
||||||
|
/* Install callbacks */
|
||||||
|
p = 0;
|
||||||
|
for (i = 0; i < limit; i++) {
|
||||||
|
if (MZ_FD_ISSET(i, rd))
|
||||||
|
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
|
||||||
|
(XtPointer *)XtInputReadMask,
|
||||||
|
(XtInputCallbackProc)MrEdWakeUp, NULL);
|
||||||
|
if (MZ_FD_ISSET(i, wr))
|
||||||
|
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
|
||||||
|
(XtPointer *)XtInputWriteMask,
|
||||||
|
(XtInputCallbackProc)MrEdWakeUp, NULL);
|
||||||
|
if (MZ_FD_ISSET(i, ex))
|
||||||
|
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
|
||||||
|
(XtPointer *)XtInputExceptMask,
|
||||||
|
(XtInputCallbackProc)MrEdWakeUp,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* callback function when input/exception is detected: */
|
||||||
|
Bool MrEdWakeUp(XtPointer, int *, XtInputId *)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (scheme_cb_ids) {
|
||||||
|
/* Remove all callbacks: */
|
||||||
|
for (i = 0; i < num_cbs; i++)
|
||||||
|
XtRemoveInput(scheme_cb_ids[i]);
|
||||||
|
|
||||||
|
scheme_cb_ids = NULL;
|
||||||
|
|
||||||
|
/* ``wake up'' */
|
||||||
|
scheme_wake_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "sleeping"]{Sleeping by Embedded Scheme}
|
||||||
|
|
||||||
|
When all Scheme threads are blocked, Scheme must ``sleep'' for a
|
||||||
|
certain number of seconds or until external input appears on some file
|
||||||
|
descriptor. Generally, sleeping should block the main event loop of
|
||||||
|
the entire application. However, the way in which sleeping is
|
||||||
|
performed may depend on the embedding application. The global function
|
||||||
|
pointer @cppi{scheme_sleep} can be set by an embedding application to
|
||||||
|
implement a blocking sleep, although Scheme implements this function
|
||||||
|
for you.
|
||||||
|
|
||||||
|
A @cpp{scheme_sleep} function takes two arguments: a @cpp{float} and a
|
||||||
|
@cpp{void*}. The latter is really points to an array of three
|
||||||
|
``@cpp{fd_set}'' records (one for read, one for write, and one for
|
||||||
|
exceptions); these records are described further below. If the
|
||||||
|
@cpp{float} argument is non-zero, then the @cpp{scheme_sleep} function
|
||||||
|
blocks for the specified number of seconds, at most. The
|
||||||
|
@cpp{scheme_sleep} function should block until there is input one of
|
||||||
|
the file descriptors specified in the ``@cpp{fd_set},'' indefinitely
|
||||||
|
if the @cpp{float} argument is zero.
|
||||||
|
|
||||||
|
The second argument to @cpp{scheme_sleep} is conceptually an array of
|
||||||
|
three @cpp{fd_set} records, but always use @cpp{scheme_get_fdset} to
|
||||||
|
get anything other than the zeroth element of this array, and
|
||||||
|
manipulate each ``@cpp{fd_set}'' with @cpp{MZ_FD_XXX} instead of
|
||||||
|
@cpp{FD_XXX}.
|
||||||
|
|
||||||
|
The following function @cpp{mzsleep} is an appropriate
|
||||||
|
@cpp{scheme_sleep} function for most any Unix or Windows application.
|
||||||
|
(This is approximately the built-in sleep used by Scheme.)
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
void mzsleep(float v, void *fds)
|
||||||
|
{
|
||||||
|
if (v) {
|
||||||
|
sleep(v);
|
||||||
|
} else {
|
||||||
|
int limit;
|
||||||
|
fd_set *rd, *wr, *ex;
|
||||||
|
|
||||||
|
# ifdef WIN32
|
||||||
|
limit = 0;
|
||||||
|
# else
|
||||||
|
limit = getdtablesize();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
rd = (fd_set *)fds;
|
||||||
|
wr = (fd_set *)scheme_get_fdset(fds, 1);
|
||||||
|
ex = (fd_set *)scheme_get_fdset(fds, 2);
|
||||||
|
|
||||||
|
select(limit, rd, wr, ex, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Thread Functions}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_thread
|
||||||
|
[Scheme_Object* thunk])]{
|
||||||
|
|
||||||
|
Creates a new thread, just like @scheme[thread].}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_thread_w_details
|
||||||
|
[Scheme_Object* thunk]
|
||||||
|
[Scheme_Config* config]
|
||||||
|
[Scheme_Thread_Cell_Table* cells]
|
||||||
|
[Scheme_Custodian* cust]
|
||||||
|
[int suspend_to_kill])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_thread}, except that the created thread belongs to
|
||||||
|
@var{cust} instead of the current custodian, it uses the given
|
||||||
|
@var{config} for its initial configuration, it uses @var{cells} for
|
||||||
|
its thread-cell table, and if @var{suspend_to_kill} is non-zero, then
|
||||||
|
the thread is merely suspended when it would otherwise be killed
|
||||||
|
(through either @scheme[kill-thread] or
|
||||||
|
@scheme[custodian-shutdown-all]).
|
||||||
|
|
||||||
|
The @var{config} argument is typically obtained through
|
||||||
|
@cpp{scheme_current_config} or @cpp{scheme_extend_config}. A
|
||||||
|
@var{config} is immutable, so different threads can safely use the
|
||||||
|
same value. The @var{cells} argument should be obtained from
|
||||||
|
@cpp{scheme_inherit_cells}; it is mutable, and a particular cell table
|
||||||
|
should be used by only one thread.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sema
|
||||||
|
[long v])]{
|
||||||
|
|
||||||
|
Creates a new semaphore.}
|
||||||
|
|
||||||
|
@function[(void scheme_post_sema
|
||||||
|
[Scheme_Object* sema])]{
|
||||||
|
|
||||||
|
Posts to @var{sema}.}
|
||||||
|
|
||||||
|
@function[(int scheme_wait_sema
|
||||||
|
[Scheme_Object* sema]
|
||||||
|
[int try])]{
|
||||||
|
|
||||||
|
Waits on @var{sema}. If @var{try} is not 0, the wait can fail and 0 is
|
||||||
|
returned for failure, otherwise 1 is returned.}
|
||||||
|
|
||||||
|
@function[(void scheme_thread_block
|
||||||
|
[float sleep_time])]{
|
||||||
|
|
||||||
|
Allows the current thread to be swapped out in favor of other
|
||||||
|
threads. If @var{sleep_time} positive, then the current thread will
|
||||||
|
sleep for at least @var{sleep_time} seconds.
|
||||||
|
|
||||||
|
After calling this function, a program should almost always call
|
||||||
|
@cppi{scheme_making_progress} next. The exception is when
|
||||||
|
@cpp{scheme_thread_block} is called in a polling loop that performs no
|
||||||
|
work that affects the progress of other threads. In that case,
|
||||||
|
@cpp{scheme_making_progress} should be called immediately after
|
||||||
|
exiting the loop.
|
||||||
|
|
||||||
|
See also @cpp{scheme_block_until}, and see also the
|
||||||
|
@cpp{SCHEME_USE_FUEL} macro in @secref["usefuel"].}
|
||||||
|
|
||||||
|
@function[(void scheme_thread_block_enable_break
|
||||||
|
[float sleep_time]
|
||||||
|
[int break_on])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_thread_block}, but breaks are enabled while blocking if
|
||||||
|
@var{break_on} is true.}
|
||||||
|
|
||||||
|
@function[(void scheme_swap_thread
|
||||||
|
[Scheme_Thread* thread])]{
|
||||||
|
|
||||||
|
Swaps out the current thread in favor of @var{thread}.}
|
||||||
|
|
||||||
|
@function[(void scheme_break_thread
|
||||||
|
[Scheme_Thread* thread])]{
|
||||||
|
|
||||||
|
Sends a break signal to the given thread.}
|
||||||
|
|
||||||
|
@function[(int scheme_break_waiting
|
||||||
|
[Scheme_Thread* thread])]{
|
||||||
|
|
||||||
|
Returns @cpp{1} if a break from @scheme[break-thread] or @cpp{scheme_break_thread}
|
||||||
|
has occurred in the specified thread but has not yet been handled.}
|
||||||
|
|
||||||
|
@function[(int scheme_block_until
|
||||||
|
[Scheme_Ready_Fun f]
|
||||||
|
[Scheme_Needs_Wakeup_Fun fdf]
|
||||||
|
[Scheme_Object* data]
|
||||||
|
[float sleep])]{
|
||||||
|
|
||||||
|
The @cpp{Scheme_Ready_Fun} and @cpp{Scheme_Needs_Wakeup_Fun}
|
||||||
|
types are defined as follows:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
|
||||||
|
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
|
||||||
|
void *fds);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Blocks the current thread until @var{f} with @var{data} returns a true
|
||||||
|
value. The @var{f} function is called periodically---at least once
|
||||||
|
per potential swap-in of the blocked thread---and it may be called
|
||||||
|
multiple times even after it returns a true value. If @var{f}
|
||||||
|
with @var{data} ever returns a true value, it must continue to return
|
||||||
|
a true value until @cpp{scheme_block_until} returns. The argument
|
||||||
|
to @var{f} is the same @var{data} as provided
|
||||||
|
to @cpp{scheme_block_until}, and @var{data} is ignored
|
||||||
|
otherwise. (The @var{data} argument is not actually required to be
|
||||||
|
a @cpp{Scheme_Object*} value, because it is only used by @var{f}
|
||||||
|
and @var{fdf}.)
|
||||||
|
|
||||||
|
If Scheme decides to sleep, then the @var{fdf} function is called to
|
||||||
|
sets bits in @var{fds}, conceptually an array of three
|
||||||
|
@cpp{fd_set}s: one or reading, one for writing, and one for
|
||||||
|
exceptions. Use @cpp{scheme_get_fdset} to get elements of this
|
||||||
|
array, and manipulate an ``@cpp{fd_set}'' with @cpp{MZ_FD_XXX}
|
||||||
|
instead of @cpp{FD_XXX}. Under Windows, an ``@cpp{fd_set}'' can
|
||||||
|
also accommodate OS-level semaphores or other handles via
|
||||||
|
@cpp{scheme_add_fd_handle}.
|
||||||
|
|
||||||
|
The @var{fdf} argument can be @cpp{NULL}, which implies that the thread
|
||||||
|
becomes unblocked (i.e., @var{ready} changes its result to true) only
|
||||||
|
through Scheme actions, and never through external processes (e.g.,
|
||||||
|
through a socket or OS-level semaphore)---with the exception that
|
||||||
|
@cpp{scheme_signal_received} may be called to indicate an external
|
||||||
|
change.
|
||||||
|
|
||||||
|
If @var{sleep} is a positive number, then @cpp{scheme_block_until}
|
||||||
|
polls @var{f} at least every @var{sleep} seconds, but
|
||||||
|
@cpp{scheme_block_until} does not return until @var{f} returns a
|
||||||
|
true value. The call to @cpp{scheme_block_until} can return before
|
||||||
|
@var{sleep} seconds if @var{f} returns a true value.
|
||||||
|
|
||||||
|
The return value from @cpp{scheme_block_until} is the return value
|
||||||
|
of its most recent call to @var{f}, which enables @var{f} to return
|
||||||
|
some information to the @cpp{scheme_block_until} caller.
|
||||||
|
|
||||||
|
See @secref["threadblock"] for information about restrictions on the
|
||||||
|
@var{f} and @var{fdf} functions.}
|
||||||
|
|
||||||
|
@function[(int scheme_block_until_enable_break
|
||||||
|
[Scheme_Ready_Fun f]
|
||||||
|
[Scheme_Needs_Wakeup_Fun fdf]
|
||||||
|
[Scheme_Object* data]
|
||||||
|
[float sleep]
|
||||||
|
[int break_on])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_block_until}, but breaks are enabled while blocking
|
||||||
|
if @var{break_on} is true.}
|
||||||
|
|
||||||
|
@function[(int scheme_block_until_unless
|
||||||
|
[Scheme_Ready_Fun f]
|
||||||
|
[Scheme_Needs_Wakeup_Fun fdf]
|
||||||
|
[Scheme_Object* data]
|
||||||
|
[float sleep]
|
||||||
|
[Scheme_Object* unless_evt]
|
||||||
|
[int break_on])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_block_until_enable_break}, but the function
|
||||||
|
returns if @var{unless_evt} becomes ready, where @var{unless_evt}
|
||||||
|
is a port progress event implemented by
|
||||||
|
@cpp{scheme_progress_evt_via_get}. See
|
||||||
|
@cpp{scheme_make_input_port} for more information.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_signal_received)]{
|
||||||
|
|
||||||
|
Indicates that an external event may have caused the result of a
|
||||||
|
synchronization poll to have a different result. Unlike most other
|
||||||
|
Scheme functions, this one can be called from any OS-level thread, and
|
||||||
|
it wakes up if the Scheme thread if it is sleeping.}
|
||||||
|
|
||||||
|
@function[(void scheme_check_threads)]{
|
||||||
|
|
||||||
|
This function is periodically called by the embedding program to give
|
||||||
|
background processes time to execute. See @secref["threadtime"]
|
||||||
|
for more information.}
|
||||||
|
|
||||||
|
@function[(void scheme_wake_up)]{
|
||||||
|
|
||||||
|
This function is called by the embedding program
|
||||||
|
when there is input on an external file descriptor. See
|
||||||
|
@secref["sleeping"] for more information.}
|
||||||
|
|
||||||
|
@function[(void* scheme_get_fdset
|
||||||
|
[void* fds]
|
||||||
|
[int pos])]{
|
||||||
|
|
||||||
|
Extracts an ``@cpp{fd_set}'' from an array passed to
|
||||||
|
@cpp{scheme_sleep}, a callback for @cpp{scheme_block_until}, or an
|
||||||
|
input port callback for @cpp{scheme_make_input_port}.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_fd_handle
|
||||||
|
[void* h]
|
||||||
|
[void* fds]
|
||||||
|
[int repost])]{
|
||||||
|
|
||||||
|
Adds an OS-level semaphore (Windows) or other waitable handle
|
||||||
|
(Windows) to the ``@cpp{fd_set}'' @var{fds}. When Scheme performs
|
||||||
|
a ``@cpp{select}'' to sleep on @var{fds}, it also waits on the given
|
||||||
|
semaphore or handle. This feature makes it possible for Scheme to
|
||||||
|
sleep until it is awakened by an external process.
|
||||||
|
|
||||||
|
Scheme does not attempt to deallocate the given semaphore or handle,
|
||||||
|
and the ``@cpp{select}'' call using @var{fds} may be unblocked due to
|
||||||
|
some other file descriptor or handle in @var{fds}. If @var{repost} is
|
||||||
|
a true value, then @var{h} must be an OS-level semaphore, and if the
|
||||||
|
``@cpp{select}'' unblocks due to a post on @var{h}, then @var{h} is
|
||||||
|
reposted; this allows clients to treat @var{fds}-installed semaphores
|
||||||
|
uniformly, whether or not a post on the semaphore was consumed by
|
||||||
|
``@cpp{select}''.
|
||||||
|
|
||||||
|
The @cpp{scheme_add_fd_handle} function is useful for implementing
|
||||||
|
the second procedure passed to @cpp{scheme_wait_until}, or for
|
||||||
|
implementing a custom input port.
|
||||||
|
|
||||||
|
Under Unix and Mac OS X, this function has no effect.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_add_fd_eventmask
|
||||||
|
[void* fds]
|
||||||
|
[int mask])]{
|
||||||
|
|
||||||
|
Adds an OS-level event type (Windows) to the set of types in the
|
||||||
|
``@cpp{fd_set}'' @var{fds}. When Scheme performs a
|
||||||
|
``@cpp{select}'' to sleep on @var{fds}, it also waits on events of
|
||||||
|
them specified type. This feature makes it possible for Scheme to
|
||||||
|
sleep until it is awakened by an external process.
|
||||||
|
|
||||||
|
The event mask is only used when some handle is installed with
|
||||||
|
@cpp{scheme_add_fd_handle}. This awkward restriction may force you
|
||||||
|
to create a dummy semaphore that is never posted.
|
||||||
|
|
||||||
|
Under Unix, and Mac OS X, this function has no effect.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_evt
|
||||||
|
[Scheme_Type type]
|
||||||
|
[Scheme_Ready_Fun ready]
|
||||||
|
[Scheme_Needs_Wakeup_Fun wakeup]
|
||||||
|
[Scheme_Wait_Filter_Fun filter]
|
||||||
|
[int can_redirect])]{
|
||||||
|
|
||||||
|
The argument types are defined as follows:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
|
||||||
|
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
|
||||||
|
void *fds);
|
||||||
|
typedef int (*Scheme_Wait_Filter_Fun)(Scheme_Object *data);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
Extends the set of waitable objects for @scheme[sync]
|
||||||
|
to those with the type tag @var{type}. If @var{filter} is
|
||||||
|
non-@cpp{NULL}, it constrains the new waitable set to those objects
|
||||||
|
for which @var{filter} returns a non-zero value.
|
||||||
|
|
||||||
|
The @var{ready} and @var{wakeup} functions are used in the same way
|
||||||
|
was the arguments to @cpp{scheme_block_until}.
|
||||||
|
|
||||||
|
The @var{can_redirect} argument should be @cpp{0}.}
|
||||||
|
|
||||||
|
@function[(void scheme_add_evt_through_sema
|
||||||
|
[Scheme_Type type]
|
||||||
|
[Scheme_Wait_Sema_Fun getsema]
|
||||||
|
[Scheme_Wait_Filter_Fun filter])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_add_evt}, but for objects where waiting is based
|
||||||
|
on a semaphore. Instead of @var{ready} and @var{wakeup} functions,
|
||||||
|
the @var{getsema} function extracts a semaphore for a given object:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef
|
||||||
|
Scheme_Object *(*Scheme_Wait_Sema_Fun)(Scheme_Object *data,
|
||||||
|
int *repost);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
If a successful wait should leave the semaphore waited, then
|
||||||
|
@var{getsema} should set @var{*repost} to @cpp{0}. Otherwise, the
|
||||||
|
given semaphore will be re-posted after a successful wait. A
|
||||||
|
@var{getsema} function should almost always set @var{*repost} to
|
||||||
|
@cpp{1}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(void scheme_making_progress)]{
|
||||||
|
|
||||||
|
Notifies the scheduler that the current thread is not simply calling
|
||||||
|
@cppi{scheme_thread_block} in a loop, but that it is actually
|
||||||
|
making progress.}
|
||||||
|
|
||||||
|
@function[(int scheme_tls_allocate)]{
|
||||||
|
|
||||||
|
Allocates a thread local storage index to be used with
|
||||||
|
@cpp{scheme_tls_set} and @cpp{scheme_tls_get}.}
|
||||||
|
|
||||||
|
@function[(void scheme_tls_set
|
||||||
|
[int index]
|
||||||
|
[void* v])]{
|
||||||
|
|
||||||
|
Stores a thread-specific value using an index allocated with
|
||||||
|
@cpp{scheme_tls_allocate}.}
|
||||||
|
|
||||||
|
@function[(void* scheme_tls_get
|
||||||
|
[int index])]{
|
||||||
|
|
||||||
|
Retrieves a thread-specific value installed with @cpp{scheme_tls_set}.
|
||||||
|
If no thread-specific value is available for the given index, @cpp{NULL} is
|
||||||
|
returned.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_call_enable_break
|
||||||
|
[Scheme_Prim* prim]
|
||||||
|
[int argc]
|
||||||
|
[Scheme_Object** argv])]{
|
||||||
|
|
||||||
|
Calls @var{prim} with the given @var{argc} and @var{argv} with breaks
|
||||||
|
enabled. The @var{prim} function can block, in which case it might be
|
||||||
|
interrupted by a break. The @var{prim} function should not block,
|
||||||
|
yield, or check for breaks after it succeeds, where ``succeeds''
|
||||||
|
depends on the operation. For example,
|
||||||
|
@scheme[tcp-accept/enable-break] is implemented by wrapping this
|
||||||
|
function around the implementation of @scheme[tcp-accept]; the
|
||||||
|
@scheme[tcp-accept] implementation does not block or yield after it
|
||||||
|
accepts a connection.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_thread_cell
|
||||||
|
[Scheme_Object* def_val]
|
||||||
|
[int preserved]
|
||||||
|
[Scheme_Object* cell]
|
||||||
|
[Scheme_Thread_Cell_Table* cells]
|
||||||
|
[Scheme_Object* cell]
|
||||||
|
[Scheme_Thread_Cell_Table* cells]
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Prevents Scheme thread swaps until @cpp{scheme_end_atomic} or
|
||||||
|
@cpp{scheme_end_atomic_no_swap} is called. Start-atomic and
|
||||||
|
end-atomic pairs can be nested.}
|
||||||
|
|
||||||
|
@function[(void scheme_end_atomic)]{
|
||||||
|
|
||||||
|
Ends an atomic region with respect to Scheme threads. The current
|
||||||
|
thread may be swapped out immediately (i.e., the call to
|
||||||
|
@cpp{scheme_end_atomic} is assumed to be a safe point for thread
|
||||||
|
swaps).}
|
||||||
|
|
||||||
|
@function[(void scheme_end_atomic_no_swap)]{
|
||||||
|
|
||||||
|
Ends an atomic region with respect to Scheme threads, and also
|
||||||
|
prevents an immediate thread swap. (In other words, no Scheme
|
||||||
|
thread swaps will occur until a future safe point.)}
|
142
collects/scribblings/inside/utils.ss
Normal file
142
collects/scribblings/inside/utils.ss
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#lang scheme/base
|
||||||
|
|
||||||
|
(require scribble/manual
|
||||||
|
scribble/struct
|
||||||
|
scribble/decode
|
||||||
|
(for-syntax scheme/base)
|
||||||
|
(for-label scheme/base))
|
||||||
|
|
||||||
|
(provide MzScheme
|
||||||
|
mzc cpp cppi cppdef (rename-out [*var var])
|
||||||
|
function subfunction
|
||||||
|
FormatD
|
||||||
|
(except-out (all-from-out scribble/manual) var)
|
||||||
|
(for-label (all-from-out scheme/base)))
|
||||||
|
|
||||||
|
(define-syntax (function stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ (ret name [type arg] ...) . body)
|
||||||
|
#'(*function (cpp/sym 'ret)
|
||||||
|
(as-index (cpp/sym 'name))
|
||||||
|
(list (type/sym 'type) ...)
|
||||||
|
(list (var/sym 'arg) ...)
|
||||||
|
(lambda ()
|
||||||
|
(list . body)))]))
|
||||||
|
|
||||||
|
(define-syntax (subfunction stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ (ret name [type arg] ...) . body)
|
||||||
|
#'(make-blockquote
|
||||||
|
"leftindent"
|
||||||
|
(flow-paragraphs
|
||||||
|
(decode-flow
|
||||||
|
(list
|
||||||
|
(*function (cpp/sym 'ret)
|
||||||
|
(var/sym 'name)
|
||||||
|
(list (type/sym 'type) ...)
|
||||||
|
(list (var/sym 'arg) ...)
|
||||||
|
(lambda ()
|
||||||
|
(list . body)))))))]))
|
||||||
|
|
||||||
|
(define (to-flow elem)
|
||||||
|
(make-flow (list (make-paragraph (list elem)))))
|
||||||
|
|
||||||
|
(define (*function ret name types args rest-thunk)
|
||||||
|
(let ([spacer (hspace 1)]
|
||||||
|
[pair-type (lambda (t v)
|
||||||
|
(make-element #f
|
||||||
|
(list
|
||||||
|
t
|
||||||
|
(hspace 1)
|
||||||
|
v)))]
|
||||||
|
[super-long? ((+ (element-width ret)
|
||||||
|
1
|
||||||
|
(element-width name)
|
||||||
|
1
|
||||||
|
(apply max 0 (map (lambda (t v)
|
||||||
|
(+ (element-width t)
|
||||||
|
1
|
||||||
|
(element-width v)))
|
||||||
|
types
|
||||||
|
args))
|
||||||
|
1)
|
||||||
|
. > .
|
||||||
|
65)])
|
||||||
|
(make-splice
|
||||||
|
(cons
|
||||||
|
(boxed
|
||||||
|
(make-table
|
||||||
|
#f
|
||||||
|
(append
|
||||||
|
(if super-long?
|
||||||
|
(list (list (to-flow ret) 'cont 'cont 'cont 'cont))
|
||||||
|
null)
|
||||||
|
(list
|
||||||
|
(append
|
||||||
|
(if super-long?
|
||||||
|
null
|
||||||
|
(list (to-flow ret)
|
||||||
|
(to-flow spacer)))
|
||||||
|
(list (to-flow name)
|
||||||
|
(to-flow (tt "("))
|
||||||
|
(if (null? types)
|
||||||
|
(to-flow (tt ")"))
|
||||||
|
(to-flow (make-element
|
||||||
|
#f
|
||||||
|
(cons (pair-type (car types) (car args))
|
||||||
|
(if (null? (cdr types))
|
||||||
|
(list (tt ")"))
|
||||||
|
(list (tt ","))))))))))
|
||||||
|
(if (null? types)
|
||||||
|
null
|
||||||
|
(let loop ([types (cdr types)]
|
||||||
|
[args (cdr args)])
|
||||||
|
(if (null? types)
|
||||||
|
null
|
||||||
|
(cons
|
||||||
|
(append
|
||||||
|
(if super-long?
|
||||||
|
null
|
||||||
|
(list (to-flow spacer)
|
||||||
|
(to-flow spacer)))
|
||||||
|
(list (to-flow spacer)
|
||||||
|
(to-flow spacer)
|
||||||
|
(to-flow (make-element
|
||||||
|
#f
|
||||||
|
(cons
|
||||||
|
(pair-type (car types) (car args))
|
||||||
|
(if (null? (cdr types))
|
||||||
|
(list (tt ")"))
|
||||||
|
(list (tt ","))))))))
|
||||||
|
(loop (cdr types) (cdr args)))))))))
|
||||||
|
(rest-thunk)))))
|
||||||
|
|
||||||
|
(define (boxed t)
|
||||||
|
(make-table
|
||||||
|
'boxed
|
||||||
|
(list (list (make-flow (list t))))))
|
||||||
|
|
||||||
|
(define (cpp/sym s)
|
||||||
|
(cpp (symbol->string s)))
|
||||||
|
|
||||||
|
(define (type/sym s)
|
||||||
|
(cpp (regexp-replace* #rx"-" (symbol->string s) " ")))
|
||||||
|
|
||||||
|
(define (var/sym s)
|
||||||
|
(*var (symbol->string s)))
|
||||||
|
|
||||||
|
(define cpp tt)
|
||||||
|
(define cppi tt)
|
||||||
|
(define cppdef (lambda (x) (as-index (tt x))))
|
||||||
|
(define *var italic)
|
||||||
|
|
||||||
|
(define mzc (exec "mzc"))
|
||||||
|
|
||||||
|
(define (refsecref s)
|
||||||
|
(secref #:doc '(lib "scribblings/reference/reference.scrbl") s))
|
||||||
|
|
||||||
|
(define MzScheme
|
||||||
|
(italic (refsecref "top")))
|
||||||
|
|
||||||
|
(define (FormatD s)
|
||||||
|
(litchar (string-append "%" s)))
|
747
collects/scribblings/inside/values.scrbl
Normal file
747
collects/scribblings/inside/values.scrbl
Normal file
|
@ -0,0 +1,747 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.ss")
|
||||||
|
|
||||||
|
@title[#:tag "im:values+types"]{Values and Types}
|
||||||
|
|
||||||
|
A Scheme value is represented by a pointer-sized value. The low bit is
|
||||||
|
a mark bit: a 1 in the low bit indicates an immediate integer, a 0
|
||||||
|
indicates a (word-aligned) pointer.
|
||||||
|
|
||||||
|
A pointer Scheme value references a structure that begins with a
|
||||||
|
@cppi{Scheme_Object} sub-structure, which in turn starts with a tag
|
||||||
|
that has the C type @cppi{Scheme_Type}. The rest of the structure,
|
||||||
|
following the @cppi{Scheme_Object} header, is type-dependent.
|
||||||
|
PLT Scheme's C interface gives Scheme values the type
|
||||||
|
@cpp{Scheme_Object*}. (The ``object'' here does not refer to objects
|
||||||
|
in the sense of the @schememodname[scheme/class] library.)
|
||||||
|
|
||||||
|
Examples of @cpp{Scheme_Type} values include @cpp{scheme_pair_type}
|
||||||
|
and @cpp{scheme_symbol_type}. Some of these are implemented as
|
||||||
|
instances of @cppi{Scheme_Simple_Object}, which is defined in
|
||||||
|
@filepath{scheme.h}, but extension or embedding code should never access
|
||||||
|
this structure directly. Instead, the code should use macros, such as
|
||||||
|
@cpp{SCHEME_CAR}, that provide access to the data of common Scheme
|
||||||
|
types.
|
||||||
|
|
||||||
|
For most Scheme types, a constructor is provided for creating values
|
||||||
|
of the type. For example, @cpp{scheme_make_pair} takes two
|
||||||
|
@cpp{Scheme_Object*} values and returns the @scheme[cons] of the
|
||||||
|
values.
|
||||||
|
|
||||||
|
The macro @cppi{SCHEME_TYPE} takes a @cpp{Scheme_Object *} and returns
|
||||||
|
the type of the object. This macro performs the tag-bit check, and
|
||||||
|
returns @cppi{scheme_integer_type} when the value is an immediate
|
||||||
|
integer; otherwise, @cpp{SCHEME_TYPE} follows the pointer to get the
|
||||||
|
type tag. Macros are provided to test for common Scheme types; for
|
||||||
|
example, @cpp{SCHEME_PAIRP} returns @cpp{1} if the value is a cons
|
||||||
|
cell, @cpp{0} otherwise.
|
||||||
|
|
||||||
|
In addition to providing constructors, PLT Scheme defines six global
|
||||||
|
constant Scheme values: @cppi{scheme_true}, @cppi{scheme_false},
|
||||||
|
@cppi{scheme_null}, @cppi{scheme_eof}, @cppi{scheme_void}, and
|
||||||
|
@cppi{scheme_undefined}. Each of these has a type tag, but each is
|
||||||
|
normally recognized via its constant address.
|
||||||
|
|
||||||
|
@index['("types" "creating")]{An} extension or embedding application
|
||||||
|
can create new a primitive data type by calling
|
||||||
|
@cppi{scheme_make_type}, which returns a fresh @cpp{Scheme_Type}
|
||||||
|
value. To create a collectable instance of this type, allocate memory
|
||||||
|
for the instance with @cpp{scheme_malloc}. From PLT Scheme's
|
||||||
|
perspective, the main constraint on the data format of such an
|
||||||
|
instance is that the first @cpp{sizeof(Scheme_Object)} bytes must
|
||||||
|
correspond to a @cpp{Scheme_Object} record; furthermore, the first
|
||||||
|
@cpp{sizeof(Scheme_Type)} bytes must contain the value returned by
|
||||||
|
@cpp{scheme_make_type}. Extensions with modest needs can use
|
||||||
|
@cppi{scheme_make_cptr}, instead of creating an entirely new type.
|
||||||
|
|
||||||
|
Scheme values should never be allocated on the stack, and they should
|
||||||
|
never contain pointers to values on the stack. Besides the problem of
|
||||||
|
restricting the value's lifetime to that of the stack frame,
|
||||||
|
allocating values on the stack creates problems for continuations and
|
||||||
|
threads, both of which copy into and out of the stack.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "im:stdtypes"]{Standard Types}
|
||||||
|
|
||||||
|
The following are the @cpp{Scheme_Type} values for the standard
|
||||||
|
types:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_bool_type} --- the constants
|
||||||
|
@cpp{scheme_true} and @cpp{scheme_false} are the only values of this
|
||||||
|
type; use @cpp{SCHEME_FALSEP} to recognize @cpp{scheme_false} and use
|
||||||
|
@cpp{SCHEME_TRUEP} to recognize anything except @cpp{scheme_false};
|
||||||
|
test for this type with @cppi{SCHEME_BOOLP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_char_type} --- @cppi{SCHEME_CHAR_VAL}
|
||||||
|
extracts the character (of type @cppi{mzchar}); test for this type
|
||||||
|
with @cppi{SCHEME_CHARP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_integer_type} --- fixnum integers, which are
|
||||||
|
identified via the tag bit rather than following a pointer to this
|
||||||
|
@cpp{Scheme_Type} value; @cppi{SCHEME_INT_VAL} extracts the integer;
|
||||||
|
test for this type with @cppi{SCHEME_INTP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_double_type} --- flonum inexact numbers;
|
||||||
|
@cppi{SCHEME_FLOAT_VAL} or @cppi{SCHEME_DBL_VAL} extracts the
|
||||||
|
floating-point value; test for this type with @cppi{SCHEME_DBLP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_float_type} --- single-precision flonum
|
||||||
|
inexact numbers, when specifically enabled when compiling PLT Scheme;
|
||||||
|
@cppi{SCHEME_FLOAT_VAL} or @cppi{SCHEME_FLT_VAL} extracts the
|
||||||
|
floating-point value; test for this type with @cppi{SCHEME_FLTP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_bignum_type} --- test for this type with
|
||||||
|
@cppi{SCHEME_BIGNUMP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_rational_type} --- test for this type with
|
||||||
|
@cppi{SCHEME_RATIONALP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_complex_type} --- test for this type or
|
||||||
|
@cpp{scheme_complex_izi_type} with @cppi{SCHEME_COMPLEXP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_complex_izi_type} --- complex number with an inexact
|
||||||
|
zero imaginary part (so it counts as a real number); test for this
|
||||||
|
type specifically with @cppi{SCHEME_COMPLEX_IZIP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_char_string_type} --- @index['("strings"
|
||||||
|
"conversion to C")]{@cppi{SCHEME_CHAR_STR_VAL}} extracts the string
|
||||||
|
as a @cpp{mzchar*}; the string is always nul-terminated, but may also
|
||||||
|
contain embedded nul characters, and the Scheme string is modified if
|
||||||
|
this string is modified; @cppi{SCHEME_CHAR_STRLEN_VAL} extracts the
|
||||||
|
string length (in characters, not counting the nul terminator); test
|
||||||
|
for this type with @cppi{SCHEME_CHAR_STRINGP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_byte_string_type} ---
|
||||||
|
@cppi{SCHEME_BYTE_STR_VAL} extracts the string as a @cpp{char*}; the
|
||||||
|
string is always nul-terminated, but may also contain embedded nul
|
||||||
|
characters, and the Scheme string is modified if this string is
|
||||||
|
modified; @cppi{SCHEME_BYTE_STRLEN_VAL} extracts the string length
|
||||||
|
(in bytes, not counting the nul terminator); test for this type with
|
||||||
|
@cppi{SCHEME_BYTE_STRINGP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_path_type} ---
|
||||||
|
@index['("strings" "conversion to C")] @cppi{SCHEME_PATH_VAL}
|
||||||
|
extracts the path as a @cpp{char*}; the string is always
|
||||||
|
nul-terminated; @cppi{SCHEME_PATH_LEN} extracts the path length (in
|
||||||
|
bytes, not counting the nul terminator); test for this type with
|
||||||
|
@cppi{SCHEME_PATHP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_symbol_type} --- @cppi{SCHEME_SYM_VAL}
|
||||||
|
extracts the symbol's string as a @cpp{char*} UTF-8 encoding (do not
|
||||||
|
modify this string); @cppi{SCHEME_SYM_LEN} extracts the number of
|
||||||
|
bytes in the symbol name (not counting the nul terminator); test for
|
||||||
|
this type with @cppi{SCHEME_SYMBOLP}; 3m: see @secref["im:3m"] for
|
||||||
|
a caution about @cppi{SCHEME_SYM_VAL}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_keyword_type} --- @cppi{SCHEME_KEYWORD_VAL}
|
||||||
|
extracts the keywors's string (without the leading hash colon) as a
|
||||||
|
@cpp{char*} UTF-8 encoding (do not modify this string);
|
||||||
|
@cppi{SCHEME_KEYWORD_LEN} extracts the number of bytes in the keyword
|
||||||
|
name (not counting the nul terminator); test for this type with
|
||||||
|
@cppi{SCHEME_KEYWORDP}; 3m: see @secref["im:3m"] for a caution
|
||||||
|
about @cppi{SCHEME_KEYWORD_VAL}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_box_type} --- @cppi{SCHEME_BOX_VAL}
|
||||||
|
extracts/sets the boxed value; test for this type with
|
||||||
|
@cppi{SCHEME_BOXP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_pair_type} --- @cppi{SCHEME_CAR} extracts/sets
|
||||||
|
the @scheme{car} and @cppi{SCHEME_CDR} extracts/sets the
|
||||||
|
@scheme{cdr}; test for this type with @cppi{SCHEME_PAIRP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_vector_type} --- @cppi{SCHEME_VEC_SIZE}
|
||||||
|
extracts the length and @cppi{SCHEME_VEC_ELS} extracts the array of
|
||||||
|
Scheme values (the Scheme vector is modified when this array is
|
||||||
|
modified); test for this type with @cppi{SCHEME_VECTORP}; 3m: see
|
||||||
|
@secref["im:3m"] for a caution about @cppi{SCHEME_VEC_ELS}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_structure_type} --- structure instances; test
|
||||||
|
for this type with @cppi{SCHEME_STRUCTP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_struct_type_type} --- structure types; test for
|
||||||
|
this type with @cppi{SCHEME_STRUCT_TYPEP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_struct_property_type} --- structure type
|
||||||
|
properties}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_input_port_type} --- @cppi{SCHEME_INPORT_VAL}
|
||||||
|
extracts/sets the user data pointer; test for just this type with
|
||||||
|
@cppi{SCHEME_INPORTP}, but use @cppi{SCHEME_INPUT_PORTP} to recognize
|
||||||
|
all input ports (including structures with the
|
||||||
|
@scheme[prop:input-port] property)}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_output_port_type} --- @cppi{SCHEME_OUTPORT_VAL}
|
||||||
|
extracts/sets the user data pointer; test for just this type with
|
||||||
|
@cppi{SCHEME_OUTPORTP}, but use @cppi{SCHEME_OUTPUT_PORTP} to
|
||||||
|
recognize all output ports (including structures with the
|
||||||
|
@scheme[prop:output-port] property)}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_thread_type} --- thread descriptors; test for
|
||||||
|
this type with @cppi{SCHEME_THREADP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_sema_type} --- semaphores; test for this type
|
||||||
|
with @cppi{SCHEME_SEMAP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_hash_table_type} --- test for this type with
|
||||||
|
@cppi{SCHEME_HASHTP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_bucket_table_type} --- test for this type with
|
||||||
|
@cppi{SCHEME_BUCKTP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_weak_box_type} --- test for this type with
|
||||||
|
@cppi{SCHEME_WEAKP}; @cppi{SCHEME_WEAK_PTR} extracts the contained
|
||||||
|
object, or @cpp{NULL} after the content is collected; do not set the
|
||||||
|
content of a weak box}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_namespace_type} --- namespaces; test for this
|
||||||
|
type with @cppi{SCHEME_NAMESPACEP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_cpointer_type} --- @|void-const| pointer with a
|
||||||
|
type-describing @cpp{Scheme_Object}; @cppi{SCHEME_CPTR_VAL} extracts
|
||||||
|
the pointer and @cppi{SCHEME_CPTR_TYPE} extracts the type tag object;
|
||||||
|
test for this type with @cppi{SCHEME_CPTRP}. The tag is used when
|
||||||
|
printing such objects when it's a symbol, a byte string, a string, or
|
||||||
|
a pair holding one of these in its car.}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
The following are the procedure types:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_prim_type} --- a primitive procedure,
|
||||||
|
possibly with data elements}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_closed_prim_type} --- an old-style primitive
|
||||||
|
procedure with a data pointer}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_compiled_closure_type} --- a Scheme
|
||||||
|
procedure}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_cont_type} --- a continuation}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_escaping_cont_type} --- an escape continuation}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_case_closure_type} --- a @scheme[case-lambda]
|
||||||
|
procedure}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_native_closure_type} --- a procedure with
|
||||||
|
native code generated by the just-in-time compiler}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
The predicate @cppi{SCHEME_PROCP} returns 1 for all procedure types
|
||||||
|
and 0 for anything else.
|
||||||
|
|
||||||
|
The following are additional number predicates:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_NUMBERP} --- all numerical types}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_REALP} --- all non-complex numerical types, plus
|
||||||
|
@cpp{scheme_complex_izi_type}}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_EXACT_INTEGERP} --- fixnums and bignums}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_EXACT_REALP} --- fixnums, bignums, and rationals}
|
||||||
|
|
||||||
|
@item{@cppi{SCHEME_FLOATP} --- both single-precision (when enabled)
|
||||||
|
and double-precision flonums}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Global Constants}
|
||||||
|
|
||||||
|
There are six global constants:
|
||||||
|
|
||||||
|
@itemize{
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_null} --- test for this value with
|
||||||
|
@cppi{SCHEME_NULLP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_eof} --- test for this value with
|
||||||
|
@cppi{SCHEME_EOFP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_true}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_false} --- test for this value with
|
||||||
|
@cppi{SCHEME_FALSEP}; test @italic{against} it with
|
||||||
|
@cppi{SCHEME_TRUEP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_void} --- test for this value with
|
||||||
|
@cppi{SCHEME_VOIDP}}
|
||||||
|
|
||||||
|
@item{@cppdef{scheme_undefined}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section[#:tag "im:strings"]{Strings}
|
||||||
|
|
||||||
|
As noted in @secref["im:unicode"], a Scheme character is a Unicode
|
||||||
|
code point represented by a @cpp{mzchar} value, and character strings
|
||||||
|
are @cpp{mzchar} arrays. PLT Scheme also supplies byte strings, which
|
||||||
|
are @cpp{char} arrays.
|
||||||
|
|
||||||
|
For a character string @var{s}, @cpp{SCHEME_CHAR_STR_VAL(@var{s})}
|
||||||
|
produces a pointer to @cpp{mzchar}s, not @cpp{char}s. Convert a
|
||||||
|
character string to its UTF-8 encoding as byte string with
|
||||||
|
@cpp{scheme_char_string_to_byte_string}. For a byte string
|
||||||
|
@var{bs}, @cpp{SCHEME_BYTE_STR_VAL(@var{bs})} produces a pointer
|
||||||
|
to @cpp{char}s. The function
|
||||||
|
@cpp{scheme_byte_string_to_char_string} decodes a byte string as
|
||||||
|
UTF-8 and produces a character string. The functions
|
||||||
|
@cpp{scheme_char_string_to_byte_string_locale} and
|
||||||
|
@cpp{scheme_byte_string_to_char_string_locale} are similar, but
|
||||||
|
they use the current locale's encoding instead of UTF-8.
|
||||||
|
|
||||||
|
For more fine-grained control over UTF-8 encoding, use the
|
||||||
|
@cpp{scheme_utf8_decode} and @cpp{scheme_utf8_encode} functions, which
|
||||||
|
are described in @secref["im:encodings"].
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Value Functions}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_char
|
||||||
|
[mzchar ch])]{
|
||||||
|
|
||||||
|
Returns the character value. The @var{ch} value must be a legal
|
||||||
|
Unicode code point (and not a surrogate, for example). The first 256
|
||||||
|
characters are represented by constant Scheme values, and others are
|
||||||
|
allocated.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_char_or_null
|
||||||
|
[mzchar ch])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_char}, but the result is @cpp{NULL} if @var{ch}
|
||||||
|
is not a legal Unicode code point.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_character
|
||||||
|
[mzchar ch])]{
|
||||||
|
|
||||||
|
Returns the character value. This is a macro that directly accesses
|
||||||
|
the array of constant characters when @var{ch} is less than 256.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_ascii_character
|
||||||
|
[mzchar ch])]{
|
||||||
|
|
||||||
|
Returns the character value, assuming that @var{ch} is less than 256. (This is a macro.)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer
|
||||||
|
[long i])]{
|
||||||
|
|
||||||
|
Returns the integer value; @var{i} must fit in a fixnum. (This is a macro.)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value
|
||||||
|
[long i])]{
|
||||||
|
|
||||||
|
Returns the integer value. If @var{i} does not fit in a fixnum,
|
||||||
|
a bignum is returned.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned
|
||||||
|
[unsigned-long i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_integer_value}, but for unsigned integers.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value_from_long_long
|
||||||
|
[mzlonglong i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_integer_value}, but for @cpp{mzlonglong}
|
||||||
|
values (see @secref["im:intsize"]).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned_long_long
|
||||||
|
[umzlonglong i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_integer_value_from_long_long}, but for unsigned integers.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value_from_long_halves
|
||||||
|
[unsigned-long hi]
|
||||||
|
[unsigned-long lo])]{
|
||||||
|
|
||||||
|
Creates an integer given the high and low @cpp{long}s of a signed
|
||||||
|
integer. Note that on 64-bit platforms where @cpp{long long} is the
|
||||||
|
same as @cpp{long}, the resulting integer has 128 bits. (See also
|
||||||
|
@secref["im:intsize"].)}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned_long_halves
|
||||||
|
[unsigned-long hi]
|
||||||
|
[unsigned-long lo])]{
|
||||||
|
|
||||||
|
Creates an integer given the high and low @cpp{long}s of an unsigned
|
||||||
|
integer. Note that on 64-bit platforms where @cpp{long long} is the
|
||||||
|
same as @cpp{long}, the resulting integer has 128 bits.}
|
||||||
|
|
||||||
|
@function[(int scheme_get_int_val
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[long* i])]{
|
||||||
|
|
||||||
|
Extracts the integer value. Unlike the @cppi{SCHEME_INT_VAL} macro,
|
||||||
|
this procedure will extract an integer that fits in a @cpp{long} from
|
||||||
|
a Scheme bignum. If @var{o} fits in a @cpp{long}, the extracted
|
||||||
|
integer is placed in @var{*i} and 1 is returned; otherwise, 0 is
|
||||||
|
returned and @var{*i} is unmodified.}
|
||||||
|
|
||||||
|
@function[(int scheme_get_unsigned_int_val
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[unsigned-long* i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_get_int_val}, but for unsigned integers.}
|
||||||
|
|
||||||
|
@function[(int scheme_get_long_long_val
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[mzlonglong* i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_get_int_val}, but for @cpp{mzlonglong} values (see
|
||||||
|
@secref["im:intsize"]).}
|
||||||
|
|
||||||
|
@function[(int scheme_get_unsigned_long_long_val
|
||||||
|
[Scheme_Object* o]
|
||||||
|
[umzlonglong* i])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_get_int_val}, but for unsigned @cpp{mzlonglong} values (see
|
||||||
|
@secref["im:intsize"]).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_double
|
||||||
|
[double d])]{
|
||||||
|
|
||||||
|
Creates a new floating-point value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_float
|
||||||
|
[float d])]{
|
||||||
|
|
||||||
|
Creates a new single-precision floating-point value. The procedure is
|
||||||
|
available only when PLT Scheme is compiled with single-precision
|
||||||
|
numbers enabled.}
|
||||||
|
|
||||||
|
@function[(double scheme_real_to_double
|
||||||
|
[Scheme_Object* o])]{
|
||||||
|
|
||||||
|
Converts a Scheme real number to a double-precision floating-point
|
||||||
|
value.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_pair
|
||||||
|
[Scheme_Object* carv]
|
||||||
|
[Scheme_Object* cdrv])]{
|
||||||
|
|
||||||
|
Makes a \scmi{cons} pair.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_byte_string
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Makes a Scheme byte string from a nul-terminated C string. The
|
||||||
|
@var{bytes} string is copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_byte_string_without_copying
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_byte_string}, but the string is not copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_byte_string
|
||||||
|
[char* bytes]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Makes a byte string value with size @var{len}. A copy of @var{bytes}
|
||||||
|
is made if @var{copy} is not 0. The string @var{bytes} should
|
||||||
|
contain @var{len} bytes; @var{bytes} can contain the nul byte at any
|
||||||
|
position, and need not be nul-terminated if @var{copy} is
|
||||||
|
non-zero. However, if @var{len} is negative, then the nul-terminated
|
||||||
|
length of @var{bytes} is used for the length, and if @var{copy} is
|
||||||
|
zero, then @var{bytes} must be nul-terminated.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_offset_byte_string
|
||||||
|
[char* bytes]
|
||||||
|
[long d]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_sized_byte_string}, except the @var{len}
|
||||||
|
characters start from position @var{d} in @var{bytes}. If @var{d} is
|
||||||
|
non-zero, then @var{copy} must be non-zero.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_alloc_byte_string
|
||||||
|
[int size]
|
||||||
|
[char fill])]{
|
||||||
|
|
||||||
|
Allocates a new Scheme byte string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_append_byte_string
|
||||||
|
[Scheme_Object* a]
|
||||||
|
[Scheme_Object* b])]{
|
||||||
|
|
||||||
|
Creates a new byte string by appending the two given byte strings.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_locale_string
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Makes a Scheme string from a nul-terminated byte string that is a
|
||||||
|
locale-specific encoding of a character string; a new string is
|
||||||
|
allocated during decoding. The ``locale in the name of this function
|
||||||
|
thus refers to @var{bytes}, and not the resulting string (which is
|
||||||
|
internally stored as UCS-4).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_utf8_string
|
||||||
|
[char* bytes])]{
|
||||||
|
|
||||||
|
Makes a Scheme string from a nul-terminated byte string that is a
|
||||||
|
UTF-8 encoding. A new string is allocated during decoding. The
|
||||||
|
``utf8'' in the name of this function thus refers to @var{bytes}, and
|
||||||
|
not the resulting string (which is internally stored as UCS-4).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_utf8_string
|
||||||
|
[char* bytes]
|
||||||
|
[long len])]{
|
||||||
|
|
||||||
|
Makes a string value, based on @var{len} UTF-8-encoding bytes (so the
|
||||||
|
resulting string is @var{len} characters or less). The string
|
||||||
|
@var{bytes} should contain at least @var{len} bytes; @var{bytes} can
|
||||||
|
contain the nul byte at any position, and need not be
|
||||||
|
null-terminated. However, if @var{len} is negative, then the
|
||||||
|
nul-terminated length of @var{bytes} is used for the length.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_offset_utf8_string
|
||||||
|
[char* bytes]
|
||||||
|
[long d]
|
||||||
|
[long len])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_sized_char_string}, except the @var{len} characters
|
||||||
|
start from position @var{d} in @var{bytes}.}
|
||||||
|
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_char_string
|
||||||
|
[mzchar* chars])]{
|
||||||
|
|
||||||
|
Makes a Scheme string from a nul-terminated UCS-4 string. The
|
||||||
|
@var{chars} string is copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_char_string_without_copying
|
||||||
|
[mzchar* chars])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_char_string}, but the string is not copied.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_char_string
|
||||||
|
[mzchar* chars]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Makes a string value with size @var{len}. A copy of @var{chars} is
|
||||||
|
made if @var{copy} is not 0. The string @var{chars} should
|
||||||
|
contain @var{len} characters; @var{chars} can contain the nul
|
||||||
|
character at any position, and need not be nul-terminated
|
||||||
|
if @var{copy} is non-zero. However, if @var{len} is negative, then
|
||||||
|
the nul-terminated length of @var{chars} is used for the length, and
|
||||||
|
if @var{copy} is zero, then the @var{chars} must be nul-terminated.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_sized_offset_char_string
|
||||||
|
[mzchar* chars]
|
||||||
|
[long d]
|
||||||
|
[long len]
|
||||||
|
[int copy])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_make_sized_char_string}, except the @var{len}
|
||||||
|
characters start from position @var{d} in @var{chars}. If @var{d} is
|
||||||
|
non-zero, then @var{copy} must be non-zero.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_alloc_char_string
|
||||||
|
[int size]
|
||||||
|
[mzchar fill])]{
|
||||||
|
|
||||||
|
Allocates a new Scheme string.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_append_char_string
|
||||||
|
[Scheme_Object* a]
|
||||||
|
[Scheme_Object* b])]{
|
||||||
|
|
||||||
|
Creates a new string by appending the two given strings.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_char_string_to_byte_string
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme character string into a Scheme byte string via UTF-8.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_byte_string_to_char_string
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme byte string into a Scheme character string via UTF-8.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_char_string_to_byte_string_locale
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme character string into a Scheme byte string via the locale's encoding.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_byte_string_to_char_string_locale
|
||||||
|
[Scheme_Object* s])]{
|
||||||
|
|
||||||
|
Converts a Scheme byte string into a Scheme character string via the locale's encoding.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_intern_symbol
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Finds (or creates) the symbol matching the given nul-terminated, ASCII
|
||||||
|
string (not UTF-8). The case of @var{name} is (non-destructively) normalized
|
||||||
|
before interning if @cppi{scheme_case_sensitive} is 0.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_intern_exact_symbol
|
||||||
|
[char* name]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Creates or finds a symbol given the symbol's length in UTF-8-encoding
|
||||||
|
bytes. The the case of @var{name} is not normalized.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_intern_exact_char_symbol
|
||||||
|
[mzchar* name]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_intern_exact_symbol}, but given a character array
|
||||||
|
instead of a UTF-8-encoding byte array.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_symbol
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Creates an uninterned symbol from a nul-terminated, UTF-8-encoding
|
||||||
|
string. The case is not normalized.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_exact_symbol
|
||||||
|
[char* name]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Creates an uninterned symbol given the symbol's length in
|
||||||
|
UTF-8-encoded bytes.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_intern_exact_keyword
|
||||||
|
[char* name]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Creates or finds a keyword given the keywords length in UTF-8-encoding
|
||||||
|
bytes. The the case of @var{name} is not normalized, and it should
|
||||||
|
not include the leading hash and colon of the keyword's printed form.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_intern_exact_char_keyword
|
||||||
|
[mzchar* name]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Like @cpp{scheme_intern_exact_keyword}, but given a character array
|
||||||
|
instead of a UTF-8-encoding byte array.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_vector
|
||||||
|
[int size]
|
||||||
|
[Scheme_Object* fill])]{
|
||||||
|
|
||||||
|
Allocates a new vector.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_box
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Creates a new box containing the value @var{v}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_weak_box
|
||||||
|
[Scheme_Object* v])]{
|
||||||
|
|
||||||
|
Creates a new weak box containing the value @var{v}.}
|
||||||
|
|
||||||
|
@function[(Scheme_Type scheme_make_type
|
||||||
|
[char* name])]{
|
||||||
|
|
||||||
|
Creates a new type (not a Scheme value).}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_cptr
|
||||||
|
[void* ptr]
|
||||||
|
[const-Scheme_Object* typetag])]{
|
||||||
|
|
||||||
|
Creates a C-pointer object that encapsulates @var{ptr} and uses
|
||||||
|
@var{typetag} to identify the type of the pointer. The
|
||||||
|
@cppi{SCHEME_CPTRP} macro recognizes objects created by
|
||||||
|
@cpp{scheme_make_cptr}. The @cppi{SCHEME_CPTR_VAL} macro extracts
|
||||||
|
the original @var{ptr} from the Scheme object, and
|
||||||
|
@cppi{SCHEME_CPTR_TYPE} extracts the type tag.
|
||||||
|
The @cppi{SCHEME_CPTR_OFFSETVAL} macro returns @cpp{0}
|
||||||
|
for the result Scheme object.}
|
||||||
|
|
||||||
|
@function[(Scheme_Object* scheme_make_offset_cptr
|
||||||
|
[void* ptr]
|
||||||
|
[long offset]
|
||||||
|
[const-Scheme_Object* typetag])]{
|
||||||
|
|
||||||
|
Creates a C-pointer object that encapsulates both @var{ptr} and @var{offset}.
|
||||||
|
The @cppi{SCHEME_CPTR_OFFSETVAL} macro returns @var{offset}
|
||||||
|
for the result Scheme object (and the macro be used to change the offset,
|
||||||
|
since it also works on objects with no offset).}
|
||||||
|
|
||||||
|
@function[(void scheme_set_type_printer
|
||||||
|
[Scheme_Type type]
|
||||||
|
[Scheme_Type_Printer printer])]{
|
||||||
|
|
||||||
|
Installs a printer to be used for printing (or writing or displaying)
|
||||||
|
values that have the type tag @var{type}.
|
||||||
|
|
||||||
|
The type of @var{printer} is defined as follows:\cppIndex{scheme_Type_Printer}
|
||||||
|
%
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef void (*Scheme_Type_Printer)(Scheme_Object *v, int dis,
|
||||||
|
Scheme_Print_Params *pp);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
%
|
||||||
|
Such a printer must print a representation of the value using
|
||||||
|
@cppi{scheme_print_bytes} and @cppi{scheme_print_string}. The
|
||||||
|
first argument to the printer, @var{v}, is the value to be printed.
|
||||||
|
The second argument indicates whether @var{v} is printed via
|
||||||
|
@scheme[write] or @scheme[display]. The last argument is to be passed
|
||||||
|
on to @cppi{scheme_print_bytes} or @cppi{scheme_print_string} to
|
||||||
|
identify the printing context.}
|
||||||
|
|
||||||
|
@function[(void scheme_print_bytes
|
||||||
|
[Scheme_Print_Params* pp]
|
||||||
|
[const-char* str]
|
||||||
|
[int offset]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Writes the content of @var{str} --- starting from @var{offset} and
|
||||||
|
running @var{len} bytes --- into a printing context determined by
|
||||||
|
@var{pp}. This function is for use by a printer that is installed
|
||||||
|
with @cpp{scheme_set_type_printer}.}
|
||||||
|
|
||||||
|
@function[(void scheme_print_string
|
||||||
|
[Scheme_Print_Params* pp]
|
||||||
|
[const-mzchar* str]
|
||||||
|
[int offset]
|
||||||
|
[int len])]{
|
||||||
|
|
||||||
|
Writes the content of @var{str} --- starting from @var{offset} and
|
||||||
|
running @var{len} characters --- into a printing context determined
|
||||||
|
by @var{pp}. This function is for use by a printer that is installed
|
||||||
|
with @cpp{scheme_set_type_printer}.}
|
||||||
|
|
||||||
|
@function[(void scheme_set_type_equality
|
||||||
|
[Scheme_Type type]
|
||||||
|
[Scheme_Equal_Proc equalp]
|
||||||
|
[Scheme_Primary_Hash_Proc hash1]
|
||||||
|
[Scheme_Secondary_Hash_Proc hash2])]{
|
||||||
|
|
||||||
|
Installs an equality predicate and associated hash functions for
|
||||||
|
values that have the type tag @var{type}. The @var{equalp} predicate is
|
||||||
|
only applied to values that both have tag @var{type}.
|
||||||
|
|
||||||
|
The type of @var{equalp}, @var{hash1}, and @var{hash2} are defined as follows:
|
||||||
|
|
||||||
|
@verbatim[#<<EOS
|
||||||
|
typedef int (*Scheme_Equal_Proc)(Scheme_Object *obj1,
|
||||||
|
Scheme_Object *obj2);
|
||||||
|
typedef long (*Scheme_Primary_Hash_Proc)(Scheme_Object *obj,
|
||||||
|
long base);
|
||||||
|
typedef long (*Scheme_Secondary_Hash_Proc)(Scheme_Object *obj);
|
||||||
|
EOS
|
||||||
|
]
|
||||||
|
|
||||||
|
The two hash functions are use to generate primary and secondary keys
|
||||||
|
for double hashing in an @scheme[equal?]-based hash table. The result
|
||||||
|
of the primary-key function should depend on both @var{obj} and
|
||||||
|
@var{base}.}
|
|
@ -165,11 +165,12 @@ handler}.
|
||||||
|
|
||||||
An @tech{extension-load handler} takes the same arguments as a
|
An @tech{extension-load handler} takes the same arguments as a
|
||||||
@tech{load handler}, but the file should be a platform-specific
|
@tech{load handler}, but the file should be a platform-specific
|
||||||
@deftech{dynamic extension}, typically with the file suffix @filepath{.so}
|
@deftech{dynamic extension}, typically with the file suffix
|
||||||
(Unix), @filepath{.dll} (Windows), or @filepath{.dylib} (Mac OS X). The file
|
@filepath{.so} (Unix), @filepath{.dll} (Windows), or @filepath{.dylib}
|
||||||
is loaded using internal, OS-specific primitives. See
|
(Mac OS X). The file is loaded using internal, OS-specific
|
||||||
@secref["inside-mzscheme"] for more information on @tech{dynamic
|
primitives. See @italic{@secref[#:doc '(lib
|
||||||
extensions}.}
|
"scribblings/inside/inside.scrbl") "top"]} for more information on
|
||||||
|
@tech{dynamic extensions}.}
|
||||||
|
|
||||||
|
|
||||||
@defproc[(load-extension [file path-string?]) any]{
|
@defproc[(load-extension [file path-string?]) any]{
|
||||||
|
|
|
@ -41,7 +41,6 @@ where @schememodname[scheme] includes all of
|
||||||
|
|
||||||
This chapter provides some temporary hyper-link targets.
|
This chapter provides some temporary hyper-link targets.
|
||||||
|
|
||||||
@subsection[#:tag "inside-mzscheme"]{Inside MzScheme}
|
|
||||||
@subsection[#:tag "running-sa"]{Running MzScheme}
|
@subsection[#:tag "running-sa"]{Running MzScheme}
|
||||||
@subsection[#:tag "async-channel"]{Asynchronous Channels}
|
@subsection[#:tag "async-channel"]{Asynchronous Channels}
|
||||||
@subsection[#:tag "honu"]{Honu}
|
@subsection[#:tag "honu"]{Honu}
|
||||||
|
|
|
@ -142,11 +142,12 @@ which must be bound as a @tech{top-level variable} or
|
||||||
@tech{module-level variable}.
|
@tech{module-level variable}.
|
||||||
|
|
||||||
The result is useful to low-level extensions; see
|
The result is useful to low-level extensions; see
|
||||||
@secref["inside-mzscheme"]. It can also be used with
|
@italic{@secref[#:doc '(lib "scribblings/inside/inside.scrbl")
|
||||||
|
"top"]}. It can also be used with
|
||||||
@scheme[variable-reference->empty-namespace],
|
@scheme[variable-reference->empty-namespace],
|
||||||
@scheme[variable-reference->resolved-module-path], and
|
@scheme[variable-reference->resolved-module-path], and
|
||||||
@scheme[variable-reference->top-level-namespace], but facilities
|
@scheme[variable-reference->top-level-namespace], but facilities like
|
||||||
like @scheme[define-namespace-anchor] and
|
@scheme[define-namespace-anchor] and
|
||||||
@scheme[namespace-anchor->namespace] wrap those to provide an clearer
|
@scheme[namespace-anchor->namespace] wrap those to provide an clearer
|
||||||
interface.}
|
interface.}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,4 @@
|
||||||
(define list-mutable/c #t)
|
(define list-mutable/c #t)
|
||||||
(define cons-mutable/c #t)
|
(define cons-mutable/c #t)
|
||||||
|
|
||||||
(define arity? #f)
|
|
||||||
|
|
||||||
(provide (all-defined)))
|
(provide (all-defined)))
|
||||||
|
|
|
@ -171,16 +171,18 @@ Like @scheme[index], but the word to index is determined by applying
|
||||||
@scheme[content->string] on the parsed @scheme[pre-content] list.}
|
@scheme[content->string] on the parsed @scheme[pre-content] list.}
|
||||||
|
|
||||||
|
|
||||||
@defproc[(section-index [word string?] ...)]{
|
@defproc[(section-index [word string?] ...)
|
||||||
|
part-index-decl?]{
|
||||||
|
|
||||||
Creates a @scheme[part-index-decl] to be associated with the enclosing
|
Creates a @scheme[part-index-decl] to be associated with the enclosing
|
||||||
section by @scheme[decode]. The @scheme[word]s serve as both the keys
|
section by @scheme[decode]. The @scheme[word]s serve as both the keys
|
||||||
and as the rendered forms of the keys.}
|
and as the rendered forms of the keys.}
|
||||||
|
|
||||||
|
|
||||||
@defproc[(index-section [#:tag tag (or/c false/c string?) "doc-index"])]{
|
@defproc[(index-section [#:tag tag (or/c false/c string?) "doc-index"])
|
||||||
|
part?]{
|
||||||
|
|
||||||
Produces a section that shows the index the enclosing document. The
|
Produces a part that shows the index the enclosing document. The
|
||||||
optional @scheme[tag] argument is used as the index section's tag.}
|
optional @scheme[tag] argument is used as the index section's tag.}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user