diff --git a/collects/scribblings/inside/contmarks.scrbl b/collects/scribblings/inside/contmarks.scrbl new file mode 100644 index 0000000000..8dbd87a41b --- /dev/null +++ b/collects/scribblings/inside/contmarks.scrbl @@ -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}.} diff --git a/collects/scribblings/inside/custodians.scrbl b/collects/scribblings/inside/custodians.scrbl new file mode 100644 index 0000000000..614f85cd51 --- /dev/null +++ b/collects/scribblings/inside/custodians.scrbl @@ -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[#<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[#<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[#<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[#<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[#<= 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[#<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[#<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}. diff --git a/collects/scribblings/inside/params.scrbl b/collects/scribblings/inside/params.scrbl new file mode 100644 index 0000000000..f9b0eb99c8 --- /dev/null +++ b/collects/scribblings/inside/params.scrbl @@ -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).} \ No newline at end of file diff --git a/collects/scribblings/inside/ports.scrbl b/collects/scribblings/inside/ports.scrbl new file mode 100644 index 0000000000..3a492ef8a0 --- /dev/null +++ b/collects/scribblings/inside/ports.scrbl @@ -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}.} diff --git a/collects/scribblings/inside/procedures.scrbl b/collects/scribblings/inside/procedures.scrbl new file mode 100644 index 0000000000..c7d24e064b --- /dev/null +++ b/collects/scribblings/inside/procedures.scrbl @@ -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[#<list] consumes a unit of fuel for each created cons +cell: + +@verbatim[#<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[#< . + 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))) diff --git a/collects/scribblings/inside/values.scrbl b/collects/scribblings/inside/values.scrbl new file mode 100644 index 0000000000..3068089dbb --- /dev/null +++ b/collects/scribblings/inside/values.scrbl @@ -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[#<empty-namespace], @scheme[variable-reference->resolved-module-path], and -@scheme[variable-reference->top-level-namespace], but facilities -like @scheme[define-namespace-anchor] and +@scheme[variable-reference->top-level-namespace], but facilities like +@scheme[define-namespace-anchor] and @scheme[namespace-anchor->namespace] wrap those to provide an clearer interface.} diff --git a/collects/scribblings/reference/to-do.ss b/collects/scribblings/reference/to-do.ss index d94d5bf0de..0731e6a7cc 100644 --- a/collects/scribblings/reference/to-do.ss +++ b/collects/scribblings/reference/to-do.ss @@ -5,6 +5,4 @@ (define list-mutable/c #t) (define cons-mutable/c #t) - (define arity? #f) - (provide (all-defined))) diff --git a/collects/scribblings/scribble/basic.scrbl b/collects/scribblings/scribble/basic.scrbl index 57c1592e61..71025cce44 100644 --- a/collects/scribblings/scribble/basic.scrbl +++ b/collects/scribblings/scribble/basic.scrbl @@ -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.} -@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 section by @scheme[decode]. The @scheme[word]s serve as both 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.}