Home

GEONius.com
10-Dec-2012
E-mail

TinyScheme with I/O Event Dispatcher and Network Extensions (TSION)

Introduction
The Software
Licensing
TSION on a Nintendo DS
Network-Lookup Functions
Socket Functions
TCP/IP Functions
LF-Terminated Communications Functions
I/O Event Dispatcher Functions
   
Scheme, Meet Forth! Directory Scanning Functions
Regular Expression Functions
Miscellaneous Functions

 
[TinyScheme Logo]

TSION adds C-coded foreign functions to TinyScheme for TCP/IP networking and I/O event dispatching. The latter capability allows you to build programs structured on an event loop: the program is idle until an I/O event (e.g., data received on a network connection) is detected, at which time the "dispatcher" calls a Scheme "callback" function to handle the event (e.g., read and process input from the network connection).

libtsion.a - I/O Event Dispatcher and Network Extensions (library)

This library has the actual TSION extensions and can be linked with any TinyScheme-based program (along with the CSOFT library mentioned below). Groups of functions can be left in or left out by calling or not calling the routines that register the functions:

    #include  "tsion.h"			/* TinyScheme I/O Network functions. */

    ...

    /* Create the Scheme engine. */

        scheme  sc = scheme_init_new ();

    /* Load the initialization file. */

        FILE  *file = fopen ("init.scm", "r") ;
        scheme_load_file (sc, file) ;
        fclose (file) ;

    /* Add the TSION extensions. */

        addFuncsDRS (sc) ;
        addFuncsIOX (sc) ;
        addFuncsLFN (sc) ;
        addFuncsMISC (sc) ;
        addFuncsNET (sc) ;
        addFuncsREX (sc) ;
        addFuncsSKT (sc) ;
        addFuncsTCP (sc) ;

        ...

The TinyScheme code base and existing extensions focus on dynamic libraries. My library is static, but it's not that big. The size(1) command shows a text size of 60K bytes for tinyscheme versus 110K bytes for my tsion. If you're running on a machine that supports dynamic loading, I don't think you'll notice a shortage of memory. IMHO!

tsion - TinyScheme I/O Event Dispatching Networking (executable)

tsion (description and command-line invocation) is the basic stand-alone tinyscheme intepreter with network extensions.

tsiond - Network TSION Server (executable)

tsiond (description and command-line invocation) is a network server that provides each client with its own tinyscheme interpreter with network extensions.

echod - an Echo Daemon in TinyScheme

ECHOD (source) is an example of a brief, event-loop-based network server that simultaneously handles multiple clients. When a client connects to ECHOD, any data written to ECHOD is echoed back to the client.

echold - a Line-Oriented Echo Daemon in TinyScheme

ECHOLD (source), like ECHOD, is an example of a brief, event-loop-based network server that simultaneously handles multiple clients. When a client connects to ECHOLD, any data written to ECHOLD is echoed back to the client. Whereas ECHOD uses the TCP extensions to handle raw TCP/IP I/O, ECHOLD uses the LFN extensions to handle I/O on a line-by-line basis.

 

The Software

TinyScheme

TinyScheme, easily downloaded from the TinyScheme website, is not so easily built. Source file scheme.c doubles as the basis for the libraries and also for the main executable. Furthermore, there is a single Makefile for all platforms and it can be difficult to figure out how to tweak it for your target platform. To make (no pun intended) life easier for you, here are some Makefiles for different platforms. All of them create a separate tinyscheme.c source file from scheme.c and all of them install the distribution into the /usr/local directory tree.

Makefile.linux - a starting point for any gcc-based platform.
Makefile.solaris - identical to Makefile.linux.
Makefile.freebsd - doesn't need "-ldl" since the dynamic loading library has been merged into the C library.
Makefile.cygwin - doesn't use TinyScheme's built-in strlwr() function.

See the Nintendo DS installation instructions for information on building TinyScheme for the DS. There are a lot of "switch(){}" statements in "scheme.c" without catch-all "default: break ;" statements, so the "-Wall" compiler option in the Makefiles generates a lot of warning messages. You may want to delete the "-Wall" option if the messages bother you - and to make it easier to spot error messages!

On Windows with Visual C++ 6.0 or Visual Studio, place the following workspace/solution files in the main TinyScheme directory and the project files in subdirectories libtinyscheme and tinyscheme. (The Visual Studio files were converted to their Visual C++ 6.0 counterparts using Stephane Rodriguez's "VC++7 to VC++6 Project Converter". I no longer have Visual C++ 6.0 installed, so I can't vouch for the correctness of the conversion.)

TinyScheme.sln - Visual Studio 2003 and later.
libtinyscheme.vcproj
tinyscheme.vcproj
TinyScheme.dsw - Visual C++ 6.0.
libtinyscheme.dsp
tinyscheme.dsp

Remember, the project files go into subdirectories!

TSION

The source code for TSION (the library and the application) is included in my CSOFT distribution. Building the software is a simple matter:

  1. Download csoft.tgz or csoft.zip, whichever archive type you feel most comfortable with. Extract the archive contents to your desired directory.

  2. Build the General Purpose Library (libgpl):


  3. Build TSION:

In all cases, you might need to modify TSION's Makefiles or Visual C++/Studio project files to point to where the TinyScheme header files and libraries are found. The UNIX Makefiles assume the header files are in "/usr/local/include/tinyscheme/" and the libraries are in "/usr/local/lib/". The Windows project files assume the TinyScheme header files are found in a TinyScheme source directory at the same level as the csoft directory; the TinyScheme library is found somewhere below the libtinyscheme subdirectory (in a Debug or Release subdirectory).

Before running TinyScheme or tsion or tsiond , you need to set environment variable TINYSCHEMEINIT to point to the TinyScheme initialization file, "init.scm". On the UNIX-based platforms, I use "/usr/local/share/tinyscheme/init.scm"; under Windows, I use the "init.scm" in TinyScheme's source code directory.

 

Licensing

The CSOFT library and the TSION library and application are covered by the MIT License. (Also see the TinyScheme License.) Basically, you are free to use the software however you see fit, in commercial or non-commerical applications. I only ask that, if your time permits, you report any bugs or portability problems you encounter. Suggestions for improvements and enhancements are welcome, but I do not guarantee I will act upon them.

 

Network-Lookup Functions

The NET group defines functions for translating IP addresses, host names, and service ports.

Source: funcs_net.c

— Scheme Function: (net-addr "host")
Lookup host and return its IP address as an integer in network-byte-order.
— Scheme Function: (net-host IP-address [dotted?])
Lookup IP-address (an integer in network-byte-order) and return the corresponding host name string. If dotted? is present and #f, the address is returned in dotted IP format; otherwise, the host name is returned.
— Scheme Function: (net-port "service" [udp?])
Lookup service in the network services database (the "/etc/services" file) and return the corresponding port number. If udp? is present and #t, the UDP port is returned; otherwise, the TCP port is returned.
 

Socket Functions

The SKT group defines functions for monitoring sockets:

Source: funcs_skt.c

— Scheme Function: (skt-startup)
— Scheme Function: (skt-cleanup)
Startup and shutdown the socket library; return #t upon success and #f otherwise. These functions are not needed on most platforms.
— Scheme Function: (skt-peer fd)
Determine the host at the other end of network socket connection fd and returns its IP address as an integer in network-byte-order; #f is returned in the event of an error.
— Scheme Function: (skt-port fd)
Get the number of the port to which socket fd is bound; #f is returned in the event of an error.
— Scheme Function: (skt-readable? fd)
— Scheme Function: (skt-up? fd)
— Scheme Function: (skt-writeable? fd)
Check if Return #t if the predicate is true and #f otherwise.
— Scheme Function: (skt-setbuf fd recvSize sendSize)
Set the size of socket fd's receive buffer to recvSize bytes and the size of its send buffer to sendSize bytes. If a buffer size is less than zero, the respective buffer retains its current size. Return #t if the buffer sizes were modified successfully and #f otherwise.
 

TCP/IP Functions

The TCP group defines functions for establishing and communicating over TCP/IP network connections.

Source: funcs_tcp.c

— Scheme Function: (tcp-listen "service"|port [backlog])
— Scheme Function: (tcp-answer endpoint [timeout])
The first function creates a "listening" endpoint bound to the named service port at which the application will listen for connection requests from clients. (Alternatively, you may specify the port number directly.) At most backlog requests may be pending; if this argument is not specified, a platform-specific maximum is used. An opaque handle for the listening endpoint is returned for use in subsequent calls to tcp-answer; #f is returned in the event of an error.
The second function, tcp-answer, waits at most timeout seconds for a connection request to be received on the listening endpoint (previously returned by tcp-listen). If a request is received, accept the request. The operating system automatically creates a new endpoint (the "data" endpoint) through which the server can talk to the client. An opaque handle is returned for the new data endpoint; #f is returned in the event of an error.
— Scheme Function: (tcp-call "service[@host]"|port [noWait?])
— Scheme Function: (tcp-complete endpoint [timeout [destroy?])
The first function, tcp-call, requests a network connection to the server at "service[@host]". (Alternatively, you may specify a port number on the local host.) If the noWait? flag is not present or is #f, tcp-call waits until the connection is established (or refused) before returning. If the noWait? flag is #t, tcp-call initiates the connection attempt and returns immediately; the application should subsequently invoke tcp-complete to complete the connection. In all cases, an opaque handle for the data endpoint is returned; #f is returned in the event of an error.
The second function, tcp-complete, waits for an asynchronous, network connection attempt to complete (if it is fated to complete).
The function will wait at most timeout seconds for the call to complete. If this argument is not present or is negative, tcp-complete will wait as long as necessary. A timeout of zero seconds causes an immediate return if the connection is not yet established.
If the connection attempt times out or otherwise fails and destroy? is not present or is #t, endpoint will automatically be destroyed. This mode is useful when the application plans to make a single go/no-go call to tcp-complete.
If, under the same circumstances, destroy? is #f, endpoint will not be destroyed; the application is responsible for executing tcp-destroy explicitly in the event of an error. This mode is useful when the application plans to periodically call tcp-complete (perhaps with a timeout of zero) until the connection is successfully established.
If a connection is not (or not yet) successfully established, #f is returned.
— Scheme Function: (tcp-debug value)
Set the TCP/IP networking debug flag to value, an integer number. A value of 0 disables debug; a non-zero value enables debug. Debug is written to standard output.
— Scheme Function: (tcp-destroy endpoint)
Close a listening or data endpoint; endpoint should no longer be referenced.
— Scheme Function: (tcp-fd endpoint)
Get endpoint's socket; endpoint may be a listening or a data endpoint. The socket is an integer; in the event of an error, #f is returned.
— Scheme Function: (tcp-name endpoint)
Return endpoint's name as a string. The name is in one of three formats:
— Scheme Function: (tcp-pending? endpoint)
— Scheme Function: (tcp-readable? endpoint)
— Scheme Function: (tcp-up? endpoint)
— Scheme Function: (tcp-writeable? endpoint)
Check if Return #t if the predicate is true and #f otherwise.
— Scheme Function: (tcp-read endpoint length [timeout])
Read length bytes of arbitrary data from endpoint into a string buffer and return the buffer to the caller. The data can be arbitrary binary data and can contain embedded NULs.
Because of the way network I/O works, a single record written to a connection by one task may be read in multiple "chunks" by the task at the other end of the connection. This is taken into account by tcp-read and, if you ask it for 100 bytes, it will automatically perform however many network reads are necessary to collect the 100 bytes.
If length is negative, tcp-read returns after reading the first "chunk" of input received; the number of bytes read from that first "chunk" is limited to the absolute value of length. The actual string of bytes read is returned to the caller.
The function will wait at most timeout seconds for the first data to arrive. If timeout is not present or is negative, tcp-read will wait as long as necessary to read the requested amount of data. A timeout of zero allows a read only if input is immediately available. If timeout is specified and is greater than zero, tcp-read will return the amount of data actually read when timeout expires. Finally, in the event of an error, #f is returned.
— Scheme Function: (tcp-write endpoint string [timeout])
Write arbitrary data from a string to endpoint.
Because of the way network I/O works, attempting to output a given amount of data to a network connection may require multiple network writers. This is taken into account by tcp-write and, if you ask it to output 100 bytes, it will perform however many network writes are necessary to output the full 100 bytes of data to the connection.
The funcction will wait at most timeout seconds for the data to be output. If this argument is not present or is negative, tcp-write will wait as long as necessary to output all of the data. A zero timeout specifies no wait: if endpoint is not ready for writing, tcp-write returns immediately. If the connection is ready for writing, tcp-write returns after outputting whatever it can.
If timeout is present and positive, tcp-write outputs whatever it can in the given time interval. In all cases, the number of bytes actually written is returned to the caller; #f is returned in the event of an error.
 

LF-Terminated Communications Functions

The LFN group defines functions for sending and receiving carriage-return/line-feed (CR/LF)-terminated text over a network connection:

Source: funcs_lfn.c

— Scheme Function: (lfn-create endpoint [options])
Create a LF-terminated network stream on top of the previously-created TCP/IP endpoint. The stream takes ownership of endpoint, which will automatically be destroyed when the stream is destroyed. The stream is returned as an opaque handle to the caller.
The optional options string contains zero or more of the following UNIX command line-style options:
"-input size"
specifies the size of the stream's internal input buffer; the default is 2048 bytes. NOTE that this is only a limit on the input buffer, not on incoming strings.
"-output length"
specifies the maximum output message size for the stream; the default is 2047 bytes.
— Scheme Function: (lfn-debug value)
Set the LF-terminated networking debug flag to value, an integer number. A value of 0 disables debug; a non-zero value enables debug. Debug is written to standard output.
— Scheme Function: (lfn-destroy stream)
Close LF-terminated network stream and its underlying TCP/IP endpoint; stream should no longer be referenced.
— Scheme Function: (lfn-fd stream)
Get stream's socket. The socket is an integer; in the event of an error, #f is returned.
— Scheme Function: (lfn-name stream)
Return stream's name as a string. The name is in one of two formats:
— Scheme Function: (lfn-readable? stream)
— Scheme Function: (lfn-up? stream)
— Scheme Function: (lfn-writeable? stream)
Check if Return #t if the predicate is true and #f otherwise. NOTE that LF-terminated input is buffered, so an application must keep reading and processing lines of input until lfn-readable? returns #f.
— Scheme Function: (lfn-getline stream [timeout])
Read the next CR/LF-delimited line of input from stream and return the input as a string with the line terminators removed; #f is returned in the event of an error.
The function will wait at most timeout seconds for buffered or pending socket data to be available. If timeout is not present or is negative, lfn-getline will wait as long as necessary to read the next line of input; a timeout of zero allows a read only if input is immediately available. If timeout is specified and is greater than zero, lfn-getline will wait that many seconds for the first piece of data to become available. Once the first data arrives, lfn-getline will take as long as necessary to read a full line of input, regardless of the timeout.
— Scheme Function: (lfn-putline stream string [crlf [timeout]])
Write a line of output, string, to stream; #t is returned if the write is successful and #f otherwise.
Optional bit mask crlf specifies line terminators to be appended to the output string: 0 = no terminator, 1 = LF only, 2 = CR only, and 3 = CR/LF. Zero (the default if this argument is not present) is typically used if the application explicitly puts the line terminators in the output string.
The funcction will wait at most timeout seconds to begin writing string. If this argument is not present or is negative, lfn-putline will wait as long as necessary to output all of the data. A zero timeout specifies no wait: if stream is not ready for writing, lfn-putline returns immediately. If the connection is ready for writing, lfn-putline returns after writing the entire string.
If timeout is present and positive, lfn-putline will wait that many seconds to begin writing string. Once output begins, lfn-putline will continue to write the entire string, regardless of the timeout value.
— Scheme Function: (lfn-read stream length [timeout])
Read length bytes of arbitrary data from stream into a string buffer and return the buffer to the caller. The data can be arbitrary binary data and can contain embedded NULs.
Because of the way network I/O works, a single record written to a connection by one task may be read in multiple "chunks" by the task at the other end of the connection. This is taken into account by lfn-read and, if you ask it for 100 bytes, it will automatically perform however many network reads are necessary to collect the 100 bytes.
If length is negative, lfn-read returns after reading the first "chunk" of input received; the number of bytes read from that first "chunk" is limited to the absolute value of length. The actual string of bytes read is returned to the caller.
The function will wait at most timeout seconds for the first data to arrive. If timeout is not present or is negative, lfn-read will wait as long as necessary to read the requested amount of data. A timeout of zero allows a read only if input is immediately available. If timeout is specified and is greater than zero, lfn-read will return the amount of data actually read when timeout expires. Finally, in the event of an error, #f is returned.
— Scheme Function: (lfn-write stream string [timeout])
Write arbitrary data from string to stream.
Because of the way network I/O works, attempting to output a given amount of data to a network connection may require multiple network writers. This is taken into account by lfn-write and, if you ask it to output 100 bytes, it will perform however many network writes are necessary to output the full 100 bytes of data to the connection.
The funcction will wait at most timeout seconds for the data to be output. If this argument is not present or is negative, lfn-write will wait as long as necessary to output all of the data. A zero timeout specifies no wait: if stream is not ready for writing, lfn-write returns immediately. If the connection is ready for writing, lfn-write returns after outputting whatever it can.
If timeout is present and positive, lfn-write outputs whatever it can in the given time interval. In all cases, the number of bytes actually written is returned to the caller; #f is returned in the event of an error.
 

I/O Event Dispatcher Functions

The IOX group defines functions for monitoring and responding to network I/O events.

There are 4 functions - iox-after, iox-every, iox-onio, and iox-whenidle - used to register "callbacks" in response to different types of events. When a monitored event occurs, the registered callback function is executed with three arguments:

    (function callback userData reason)

where callback is the handle returned when the callback was registered, userData is arbitrary data supplied by the application when the callback was registered, and reason is a bit mask specifying the reason(s) for the callback (0x1=readable, 0x2=writeable, 0x4=OOB, 0x8=timer, 0x10=idle). Constants are predefined for the reasons:

IOX_READ - socket is readable.
IOX_WRITE - socket is writeable.
IOX_EXCEPT - socket has out-of-bound input available for reading.
IOX_IO - the bit-wise OR of the three conditions above.
IOX_FIRE - timer has fired.
IOX_IDLE - dispatcher is idle.
IOX_CANCEL - callback is canceled.

Source: funcs_iox.c

— Scheme Function: (iox-create)
Create an I/O event dispatcher. An opaque handle is returned for the dispatcher; #f is returned in the event of an error.
— Scheme Function: (iox-debug value)
Set the I/O event dispatcher debug flag to value, an integer number. A value of 0 disables debug; a non-zero value enables debug. Debug is written to standard output.
— Scheme Function: (iox-destroy dispatcher)
Invoke each of dispatcher's registered callbacks with reason IOX_CANCEL and then destroy the dispatcher.
— Scheme Function: (iox-monitor dispatcher [timeout])
Monitor and dispatch I/O events, timers, and idle tasks for timeout seconds using dispatcher. If the timeout argument is not present or is less than zero, the dispatcher will monitor events forever. When the timeout interval is complete, iox-monitor returns #t. In the event of an error (usually no more events to monitor), #f is returned.
— Scheme Function: (iox-after dispatcher function userData delay)
Register a single-shot timer of delay seconds duration with dispatcher. The timer interval can include a fractional number of seconds; e.g., 2.75 seconds. An opaque handle for the registered callback is returned to the caller and can be used to cancel the callback with iox-cancel before the timer fires. When delay seconds have elapsed, function is called with 3 arguments: the callback handle, the application-supplied userData, and the reason (IOX_FIRE) the callback is being invoked. After being invoked, the single-shot timer is automatically canceled.
— Scheme Function: (iox-every dispatcher function userData delay interval)
Register a periodic timer with dispatcher. The timer fires after an initial delay number of seconds and then every interval seconds after that. The time durations can include fractional numbers of seconds; e.g., 2.75 seconds. An opaque handle for the registered callback is returned to the caller and can be used to cancel the callback with iox-cancel when the timer is no longer needed.
When the timer fires, function is called with 3 arguments: the callback handle, the application-supplied userData, and the reason (IOX_FIRE) the callback is being invoked. To stop the timer, it must be explicitly canceled by calling iox-cancel.
— Scheme Function: (iox-onio dispatcher function userData reason fd)
Register I/O file descriptor fd with dispatcher. Mask reason is the bit-wise OR of the types of I/O events to monitor: IOX_READ for input-pending, IOX_WRITE for output-ready, and IOX_EXCEPT for OOB-input-pending. An opaque handle for the registered callback is returned to the caller and can be used to cancel the callback with iox-cancel.
When an event of the monitored types is detected on the I/O source, function is called with 3 arguments: the callback handle, the application-supplied userData, and the reason (IOX_READ, IOX_WRITE, or IOX_EXCEPT) the callback is being invoked.
To register a callback for a TCP/IP listening socket (created by tcp-listen), specify IOX_READ as the event type to be monitored. When a connection request is received from a client, the listening socket becomes readable. The callback should then execute tcp-answer to accept the connection request.
— Scheme Function: (iox-whenidle dispatcher function userData)
Register an idle task with dispatcher. An opaque handle for the registered callback is returned to the caller and can be used to cancel the callback with iox-cancel. When the dispatcher is idle (i.e., no I/O or timers immediately pending), function is called with 3 arguments: the callback handle, the application-supplied userData, and the reason (IOX_IDLE) the callback is being invoked. After function completes, dispatcher re-queues the idle task for later processing. The application is responsible for explicitly canceling the callback using iox-cancel.
— Scheme Function: (iox-cancel callback)
Cancel callback, where callback is the opaque handle returned when the callback was registered. The status of canceling the callback, #t or #f, is returned to the caller.
— Scheme Function: (iox-dispatcher callback)
Get callback's dispatcher, where callback is the opaque handle returned when the callback was registered. This capability is useful when a callback needs to access its dispatcher. For example, a callback that answers a network connection request may wish to register an I/O callback for the new data connection.
 

Directory Scanning Functions

The DRS group consists of functions used to scan lists of files in directories.

Source: funcs_drs.c

— Scheme Function: (drs-create "pathname")
Create a directory scan for the directory specified in pathname. The pathname must contain wildcard characters for the files in the directory, "*" at a minimum. If the scan is successfully created, an opaque handle is returned for use in other DRS functions; #f is returned in the event of an error.
— Scheme Function: (drs-destroy scan)
Destroy the specified directory scan.
— Scheme Function: (drs-first scan)
Get the first matching file in a directory scan. The file's full pathname is returned as a string; #f is returned if there are no matching files.
— Scheme Function: (drs-next scan)
Get the next matching file in a directory scan. The file's full pathname is returned as a string; #f is returned if there are no more matching files.
— Scheme Function: (drs-count scan)
Get the number of files in a directory scan that matched the wildcard file specification supplied to DRS-CREATE.
— Scheme Function: (drs-get scan index)
Get the indexed, index, matching file in a directory scan. Indices are numbered from 1 to the value returned by DRS-COUNT. The file's full pathname is returned as a string; #f is returned if the index is out of range. Getting a file name by index does not affect the sequence of file names returned by DRS-FIRST and DRS-NEXT.
 

Regular Expression Functions

The REX group is a collection of functions for matching and replacing patterns of text using regular expressions. The underlying regular expression package (REX_UTIL) used to implement the Scheme functions was written circa 1990, before the advent of POSIX and Perl regular expressions. Consequently, the syntax for matching expressions and replacing text is slightly different than what you might expect; for example, subexpressions are explicitly labeled in regular expressions and don't require you to parse parentheses. Different, but in a sensibly consistent way. (And portable to a variety of operating systems and platforms.)

Source: funcs_rex.c

— Scheme Function: (rex-create "regexp")
Compile a regular expression into a form suitable for matching with REX-MATCH and REX-REPLACE. An opaque handle is returned for the compiled pattern; #f is returned in the event of an error.
See LIBGPL's REX_UTIL package for the syntax of regular expressions recognized by REX-CREATE.
— Scheme Function: (rex-debug value)
Set the regular expression debug flag to value, an integer number. A value of 0 disables debug; a non-zero value enables debug. Debug is written to standard output.
— Scheme Function: (rex-destroy pattern)
Destroy compiled regular expression pattern.
— Scheme Function: (rex-error)
Get more error information after REX-CREATE fails to compile a regular expression. The information is returned as a string; #f is returned if there is no error information.
— Scheme Function: (rex-match pattern "text")
Attempt to match compiled regular expression pattern in target string text. If the match is successful, a Scheme list is returned whose first element is the entire string of text matched by the regular expression and whose remaining elements are the strings matched by the subexpresions ("$n"), if any, in the regular expression:
("full match" "subexp0" "subexp1" ...))
If no match is found, #f is returned.
— Scheme Function: (rex-replace pattern "text" "replacement" global?)
Perform a search-and-replace operation on string text. The search string (specified by previously-compiled regular expression pattern) is located in the source string and replaced by the substitution text, replacement. This process may be done once or, if global? is #t, repeatedly throughout the whole string. REX-REPLACE is intended to perform ex(1)-style subsitutions on a line of text:
s/regexp/replacement/[g]
REX-REPLACE returns a Scheme pair whose car is the new text after substitutions have been made and whose cdr is the number of substitutions that were made:
("newText" . numSubstitutions)
If no substitutions were made, REX-REPLACE returns the old text and zero for the number of substitutions.
See LIBGPL's REX_UTIL package for the special character sequences used to control the replacement process; e.g., inserting matched subexpressions, etc.
 

Miscellaneous Functions

The MISC group is a miscellaneous collection of unrelated functions.

Source: funcs_misc.c

— Scheme Function: (getenv "name")
Get the value of environment variable name. The value is returned as a string to the caller. If the environment variable is not defined, then #f is returned.
— Scheme Function: (grab value)
This function stores a pointer to value internally for use by C code. The function is not especially useful otherwise and simply returns its input, value.
— Scheme Function: (tv-tod)
Return the current time of day (GMT) as a pair consisting of the number of seconds and microseconds since the start of January 1, 1970.