Olin Shivers (original author), John Cowan (editor and shepherd), Harold Ancell (editor)


This SRFI is currently in draft status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-170@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.


The host environment is the set of resources, such as the filesystem, network and processes, that are managed by the operating system on top of which a Scheme program is executing. This SRFI specifies how the host environment can be accessed from within a Scheme program. It does so by leveraging widespread support for POSIX, the Portable Operating System Interface standardized by the IEEE. Not all of the functions of this SRFI are available on all operating systems.


None at present.


The I/O and other environmental procedures provided by the various Scheme standards were designed at a time when operating systems were far more diverse than they are today, and therefore portability was difficult or impossible to achieve. In addition, Scheme has historically focused on programming-language features rather than the practical needs of mainstream software development. Consequently, none of the standards provide more than a limited set of operations. Individual implementations often provide much more, but in incompatible ways.

This SRFI uses the IEEE 1003 POSIX.1-2017 standard to provide maximally portable access to the services of the operating system on which typical Scheme implementations run. Almost all operating systems today support all or part of POSIX, so the use of this SRFI is mostly portable, but implementations are definitely not portable. However, an implementation of this SRFI can be layered over many existing implementation-specific interfaces, or directly over a C FFI. It is even possible to implement it on top of the JVM or CLR virtual machines.

This SRFI describes a specific POSIX API for Scheme. Rather than attempting to compromise between existing implementations, the scsh system call specification was chosen as a base document. Consequently, this SRFI is a reduced version of Chapter 3, "System Calls" of version 0.6.7 of the Scsh Reference Manual. The numbered headers are aligned with those used in the Reference Manual.

Scsh 0.6.7 was chosen for two main reasons. It is fairly old, so most of its operations, even those which were non-Posix at the time (2006) are now included in Posix, and it has few or no operations that aren't Posix at all. In addition, it is politically fairly neutral, being tied to an obsolete version of Scheme 48, which is not being actively developed. Scsh 0.7 exists (see Implementation section), but was not used in creating this SRFI because it is incompletely documented.

This SRFI makes no effort to provide all 81 headers, 1191 interfaces, and 51 data types of full POSIX. Instead it provides access to a reasonable number of highly portable interfaces (many of them even available on Windows) with wrappers to make them more Scheme-like. In particular, this SRFI excludes:

The use of colons to join record names and fields into the name of a record accessor is a convention of Scheme 48, on which scsh is built.


Implementations of this SRFI on non-POSIX systems, especially Windows, must provide all the procedure names and syntax keywords. However, if the specified action is not possible, the procedure should either take no action and return some reasonable default value, or raise an exception.

A Scheme implementation that supports both this SRFI and multiple threads of control must ensure that when a thread invokes a blocking I/O procedure defined below, only that thread is blocked and not any other concurrently running ones. Because Scheme threads may be multiplexed on top of POSIX threads, the per-thread POSIX functions may not do the right thing.

3.1  [Intentionally omitted]

3.2  I/O

Dealing with POSIX file descriptors in a Scheme environment is difficult. In POSIX, open files are part of the process environment, and are referenced by small exact integers called file descriptors. Open file descriptors are the fundamental way I/O redirections are passed to subprocesses and executed programs, since file descriptors are preserved across fork and exec operations.

Scheme, on the other hand, uses ports for specifying I/O sources and sinks. Ports are garbage-collected Scheme objects, not integers. When a port is garbage collected, it is effectively closed, but whether the underlying file descriptor is closed is left as an implementation detail. Because file descriptors are just integers, it's impossible to garbage collect them — you wouldn't be able to close file descriptor 3 unless there were no 3's in the system, and you could further prove that your program would never again compute a 3. This is difficult at best.

If a Scheme program only used Scheme ports, and never actually used file descriptors, this would not be a problem. But Scheme code needs to descend to the file descriptor level in at least two circumstances: when interfacing to foreign code, and when interfacing to a subprocess.

This causes a problem. Suppose we have a Scheme port constructed on top of file descriptor 3. We intend to execute a successor program that will expect this file descriptor. If we drop references to the port, the garbage collector may prematurely close file 3 before we fork the subprocess.

Unfortunately, there is no even vaguely portable solution to this problem. Scsh and Guile undertake heroic measures to open new file descriptors for ports when the old file descriptors are repurposed for something else, and to track when closing a port implies closing its file descriptor or not. But doing so involves more changes than an implementation should have to make in order to provide this SRFI.

Consequently, this SRFI assumes that file descriptors will only be used at the edges of the program, and that most I/O operations will be performed on ports.

The following routines allow conversion between ports and file descriptors.

(fdes->textual-input-port fd)    →    port       (procedure) 
(fdes->binary-input-port fd)    →    port       (procedure) 
(fdes->textual-output-port fd)    →    port       (procedure) 
(fdes->binary-output-port fd)    →    port       (procedure) 

These procedures wrap a newly created port around the specified file descriptor, effectively importing it into the Scheme world. In particular, the textual ports use the same character encoding applied by default in the underlying implemenation.

(port-fdes port)    →    exact integer       (procedure) 
This procedure exposes the file descriptor of a port, effectively exporting it from the Scheme world. Alternatively, #f is returned if port does not have a file descriptor (a string port, e.g.).

(close-fdes fd)    →    undefined       (procedure)       POSIX close() 

Closes the file descriptor fd.

If fd is associated with a port, it is an error to do any further operations on that port. The same is true of calls to close-port on a file descriptor, if the implementation permits them.

3.3  File system

The following procedures allow access to the computer's file system.

(create-directory fname [permission-bits [override?]])    →    undefined       (procedure)       POSIX mkdir() 
(create-fifo fname [permission-bits [override?]])    →    undefined       (procedure)       POSIX mkfifo() 
(create-hard-link old-fname new-fname [override?])    →    undefined       (procedure)       POSIX link() 
(create-symlink old-fname new-fname [override?])    →    undefined       (procedure)       POSIX symlink() 

These procedures create objects of various kinds in the file system.

The override? argument controls the action if there is already an object in the file system with the new name. If it is #f, which is the default, then an error is signaled. If it is #t, the old object is deleted with R7RS-small delete-file or this SRFI's delete-directory as appropriate before creating the new object. The effect of passing any other value is implementation-dependent.

The permission-bits for create-directory default to #o775, and for create-fifo #o664, but are masked by the current umask.

If you try to create a hard link and old-fname and new-fname refer to the same file, it is an error (and your file may be destroyed).

(read-symlink fname)    →    string       (procedure)       POSIX readlink() 
Return the filename referenced by the symlink fname.
(rename-file old-fname new-fname [override?])    →    undefined       (procedure)       POSIX rename() 
If you override an existing object, then old-fname and new-fname must type-match -- either both directories, or both non-directories. This is required by the semantics of POSIX rename().

Remark: There is an unfortunate atomicity problem with the rename-file procedure: if you do not specify override?, but create file new-fname sometime between rename-file's existence check and the actual rename operation, your file will be clobbered with old-fname. There is no way to prevent this problem; at least it is highly unlikely to occur in practice.

(delete-directory fname)    →    undefined       (procedure)       POSIX rmdir() 
This procedure deletes directories from the file system. It is an error if fname is not a non-empty directory.

(set-file-mode fname mode-bits)    →    undefined       (procedure)       POSIX chmod() 
(set-file-owner fname uid)    →    undefined       (procedure)       POSIX chown() 
(set-file-group fname gid)    →    undefined       (procedure)       POSIX chown() 
These procedures set the mode bits, owner id, and group id of a file, respectively, specified by supplying the file name. Setting file user ownership usually requires root privileges. These procedures follows symlinks and changes the files to which they refer.

(set-file-timespecs fname [access-timespec modify-timespec])    →    undefined       (procedure)       POSIX utimensat() 
This procedure sets the access and modified times for the file fname to the supplied SRFI 174 timespec values. If neither time argument is supplied, they are both taken to be the current time. The special values timespec/now and timespec/omit set their respective times to the current time, or do not change the time. It is an error if exactly one time is provided. This procedure follows symlinks and sets the times of the file to which it refers. If the procedure completes successfully, the file's time of last status-change (ctime) is set to the current time.

(truncate-file fname/port len)    →    undefined       (procedure)       POSIX truncate() 
The specified file is truncated to len bytes in length.

(file-info fname/port follow?)    →    file-info-record       (procedure)       POSIX stat() 
The file-info procedure returns a file-info record containing useful information about a file. If the follow? flag is true the procedure follows symlinks and reports on the files to which they refer. If follow? is false the procedure checks the actual file itself, even if it's a symlink. The follow? flag is ignored if the file argument is a port.
(file-info? obj)    →    boolean       (procedure) 
Returns #t if obj is a file-info object and #f otherwise.
(file-info:device file-info)    →    integer       (procedure) 
(file-info:inode file-info)    →    integer       (procedure) 
(file-info:mode file-info)    →    integer       (procedure) 
(file-info:nlinks file-info)    →    integer       (procedure) 
(file-info:uid file-info)    →    integer       (procedure) 
(file-info:gid file-info)    →    integer       (procedure) 
(file-info:rdev file-info)    →    integer       (procedure) 
(file-info:size file-info)    →    integer       (procedure) 
(file-info:blksize file-info)    →    integer       (procedure) 
(file-info:blocks file-info)    →    integer       (procedure) 
(file-info:atime file-info)    →    timespec       (procedure) 
(file-info:mtime file-info)    →    timespec       (procedure) 
(file-info:ctime file-info)    →    timespec       (procedure) 
Returns the device number, inode number, mode (permission and file type bits), number of hard links, user id, group id, device ID if file is special, size in bytes, optimal blocksize for I/O, number of 512B blocks allocated, last access time, last modification time, and last change of status times in SRFI 174 timespecs stored in file-info respectively.

Although POSIX does not standardize bit positions in the file mode, the following assignments are de facto standards (all except the socket, symlink, and fifo bits have been unchanged since the Sixth Edition of Research Unix):

#o140000   local domain socket
#o120000   symbolic link
#o100000   regular file
#o40000    directory
#o10000    fifo
#o4000     setuid file
#o2000     setgid file
#o1000     sticky directory (restrictions on deletion)
#o400      user read permission
#o200      user write permission
#o100      user execute permission
#o40       group read permission
#o20       group write permission
#o10       group execute permission
#o4        other user read permission
#o2        other user write permission
#o1        other user execute permission

Note that to distinguish between non-directories it is necessary to examine several bits.

(file-info-directory? file-info)    →    boolean       (procedure)       POSIX S_ISDIR() 
(file-info-fifo? file-info)    →    boolean       (procedure)       POSIX S_ISFIFO() 
(file-info-symlink? file-info)    →    boolean       (procedure)       POSIX S_ISLNK() 
(file-info-regular? file-info)    →    boolean       (procedure)       POSIX S_ISREG() 
These procedures are file-type predicates that test the file type stored in file-info.

This SRFI does not provide a special means for checking the permission bits in a file-info record, though they are available in file-info:mode. There are several problems with such procedures. First, there's an atomicity issue. In between checking permissions for a file and then trying an operation on the file, another process could change the permissions, so a return value from these functions guarantees nothing. Second, Posix special-cases permission checking when the uid is 0 (root) — if the file exists, root is assumed to have the requested permission. However, not even root can write a file stored on a read-only file system, such as a CD-ROM.

(directory-files [dir [dotfiles?]])    →    string list       (procedure) 
Return a list of file names in directory dir, which defaults to the current working directory. The dotfiles? flag (default #f) causes dot files to be included in the list. Regardless of the value of dotfiles?, the two files . and .. are never returned.

The directory dir is not prepended to each file name in the result list. That is,

(directory-files "/etc")
("chown" "exports" "fstab" ...)
("/etc/chown" "/etc/exports" "/etc/fstab" ...)
To use the file names in the returned list, the programmer can either manually prepend the directory, or change to the directory before using the file names.

(make-directory-files-generator dir [dotfiles?])    →    generator       (procedure) 
Return a SRFI 158 generator of the file names in directory dir. The dotfiles? flag (default #f) causes dot files to be included in the list. Regardless of the value of dotfiles?, the two files . and .. are never returned.

Like directory-files above, the directory dir is not prepended to each file name in the results the generator returns.

The generator approach is particularly useful when the number of items in a directory might be "huge", which has been a common paradigm when using a file system as a document database.

(open-directory dir [dot-files?])    →    directory-object       (procedure)       POSIX opendir() 
(read-directory directory-object)    →    string or eof-object       (procedure)       POSIX readdir() 
(close-directory directory-object)    →    undefined       (procedure)       POSIX closedir() 

These functions implement an interface to the opendir()/ readdir()/ closedir() family of functions for processing directories.

The open-directory procedure opens the directory with the specified pathname for reading, returning an opaque directory object. Then read-directory returns the name of the next available file, or the end of file object if there are no more files. The dot-files? argument controls whether file names beginning with "." are returned. If it is #f, which is the default, they are not. The file names . and .. are never returned. Finally, close-directory closes a directory object.

(real-path path)    →    string       (procedure)       POSIX realpath() 
Returns an absolute pathname derived from pathname that names the same file and whose resolution does not involve ., .., or symlinks.
temp-file-prefix        string parameter 

A SRFI 39 or R7RS parameter that returns a string when invoked. Its initial value is the value of the environment variable TMPDIR concatenated with "/pid" if TMPDIR is set and to "/tmp/pid" otherwise, where pid is the id of the current process.
(create-temp-file [prefix])    →    string       (procedure) 
Creates a new temporary file and returns its name. The optional argument specifies the filename prefix to use, and defaults to the result of invoking temp-file-prefix. The procedure generates a sequence of filenames that have prefix as a common prefix, looking for a filename that doesn't already exist in the file system. When it finds one, it creates it with permission #o600 and returns the filename. (The file permission can be changed to a more permissive permission with set-file-mode after being created).

This file is guaranteed to be brand new. No other process will have it open. This procedure does not simply return a filename that is very likely to be unused. It returns a filename that definitely did not exist at the moment create-temp-file created it.

It is not necessary for the process's pid to be a part of the filename for the uniqueness guarantees to hold. The pid component of the default prefix simply serves to scatter the name searches into sparse regions, so that collisions are less likely to occur. This speeds things up, but does not affect correctness.

(call-with-temporary-filename maker [prefix])    →    object+       (procedure) 
This procedure can be used to perform certain atomic transactions on the file system involving filenames. Some examples:

This procedure uses prefix to generate a series of trial file names. Prefix is a string, and defaults to the value of invoking temp-file-prefix. File names are generated by concatenating prefix with a varying string.

The maker procedure is called serially on each file name generated. It must return at least one value; it may return multiple values. If the first return value is #f or if maker raises an exception indicating that the file exists call-with-temporary-filename will loop, generating a new file name and calling maker again. If the first return value is true, the loop is terminated, returning whatever value(s) maker returned.

After a number of unsuccessful trials, call-with-temporary-filename may give up and signal an error.

To rename a file to a temporary name:

(call-with-temporary-filename (lambda (backup)
                        (create-hard-link old-file backup)
                        ".temp.") ; Keep link in current working directory.
(delete-file old-file)
Recall that this SRFI reports procedure failure by raising an error exception, not by returning an error code. This is critical for this example — the programmer can assume that if the call-with-temporary-filename call returns, it returns successfully. So the following delete-file call can be reliably invoked, safe in the knowledge that the backup link has definitely been established.

To create a unique temporary directory:

(call-with-temporary-filename (lambda (dir) (create-directory dir) dir)
Similar operations can be used to generate unique fifos, or to return values other than the new filename (e.g., an open port).

(real-path path)     →     string         (procedure) 
Returns an absolute pathname derived from pathname that names the same file and whose resolution does not involve ., .., or symbolic links.

3.4  [Intentionally omitted]

3.5  Process state

(umask)    →    exact integer       (procedure)       POSIX umask() 
(set-umask perms)    →    exact integer       (procedure)       POSIX umask() 
The process's current umask is retrieved with umask, and set with (set-umask perms), e.g., (set-umask #o2), which returns the previous umask.

(working-directory)    →    string       (procedure)       POSIX getcwd() 
(set-working-directory [fname])    →    undefined       (procedure)       POSIX chdir() 
Get and set the current working directory. If set-working-directory is called with no arguments, it changes the current working directory to the user's home directory.

(pid)    →    exact integer       (procedure)       POSIX getpid() 
(parent-pid)    →    exact integer       (procedure)       POSIX getppid() 
(process-group)    →    exact integer       (procedure)       POSIX getpgid() 
These procedures retrieve the process id for the current process, the process id for the parent of this process, and the process group for this process, respectively.
(nice [delta])     --->    exact integer       (procedure)       POSIX nice() 

Increments the niceness of the current process by delta. The lower the niceness value is, the more the process is favored during scheduling. If delta is not specified, the increment is 1.

Real-time processes are not affected by nice.

(user-uid)    →    exact integer       (procedure)       POSIX getuid() 
(user-gid)    →    exact integer       (procedure)       POSIX getgid() 
(user-effective-uid)    →    exact integer       (procedure)       POSIX geteuid() 
(user-effective-gid)    →    exact integer       (procedure)       POSIX getegid() 
(user-supplementary-gids)    →    exact integer list       (procedure)       POSIX getgroups() 
For the calling process, these routines get the specified data. The scsh proceedure user-login-name that uses getlogin() or getlogin_r() can be simulated with (user-info:name (user-info (user-uid))), the outer procedures are described in the next section:

3.6  User and group database access

These procedures are used to access the user and group databases (e.g., the ones traditionally stored in /etc/passwd and /etc/group).

(user-info uid/name)    →    record       (procedure)       POSIX getpwuid/getpwnam() 
Return a user-info record giving the recorded information for a particular user. The uid/name argument is either an exact integer uid or a string user name.

(user-info? obj)    →    boolean       (procedure) 
Returns #t if obj is a user info object and #f otherwise.
(user-info:name user-info)    →    string       (procedure) 
(user-info:uid user-info)    →    exact integer       (procedure) 
(user-info:gid user-info)    →    exact integer       (procedure) 
(user-info:home-dir user-info)    →    string       (procedure) 
(user-info:shell user-info)    →    string       (procedure) 
Returns the user name, user id, group id, home directory, and shell path stored in user-info respectively. Windows returns #f for any items it doesn't have.

(user-info:full-name user-info)    →    string       (procedure) 
Returns the contents of the pw_gecos field stored in user-info. Although this field is not part of POSIX, it has been part of all Unix variants since at least the Sixth Edition of Research Unix. It normally contains the user's full name, but may contain additional system-specific information; on Windows, it contains exactly the full name.

(user-info:parsed-full-name user-info)    →    string list       (procedure) 

Returns a parsed and expanded version of the raw string returned by user-info:full-name. The raw value is split on commas, creating a list of strings to be returned. All ampersands in the first element of the list are replaced by user-info:name, which is capitalized if it starts with an ASCII lowercase letter.

However, on Windows the implementation is completely different: user-info:parsed-full-name returns a list with a single element, the result of user-info:full-name. No comma splitting or ampersand substitution is performed.

The meaning of the first element of the returned list is the user's full name on all known systems. The remaining elements have varying meaning. For example, on BSD systems, the second through fourth elements are the user's work location, the user's work phone number, and the user's home phone number, respectively. On Cygwin, the second element is the Windows SID corresponding to this user; further elements depend on Cygwin-specific entries in the /etc/nsswitch.conf file.

(group-info gid/name)    →    record       (procedure)       POSIX getgrgid/getgrnam() 
Return a group-info record giving the recorded information for a particular group. The gid/name argument is either an exact integer gid or a string group name.
(group-info? obj)    →    boolean       (procedure) 
Returns #t if obj is a group info object and #f otherwise.
(group-info:name user-info)    →    string       (procedure) 
(group-info:gid user-info)    →    exact integer       (procedure) 
Returns the group name and group id stored in group-info. The list of group member ids can be retrieved with the above (user-supplementary-gids)

3.7  [Intentionally omitted]

3.7  [Intentionally omitted]

3.8  [Intentionally omitted]

3.9  [Intentionally omitted]

3.10  Time

A SRFI 174 timespec is an object containing two values, the number of elapsed seconds since a POSIX epoch, and the number of elapsed nanoseconds since the beginning of the current second. The system clock is not required to report time at full nanosecond resolution, nor is anything guaranteed about accuracy.

(posix-time)     --->    timespec       (procedure)       POSIX clock_gettime() 

The posix-time procedure returns the current time as a timespec since the POSIX epoch (midnight January 1, 1970 Universal Time), excluding leap seconds.

(monotonic-time)     --->    timespec       (procedure)       POSIX clock_gettime() 

The same as posix-time, except that the epoch is arbitrary. This epoch cannot change after the current program begins to run. It is guaranteed that a call to monotonic-time cannot return a time earlier than a previous call to monotonic-time. This is not guaranteed for posix-time because the system's POSIX clock is sometimes turned either forward or backward.

3.11  [Intentionally omitted]

3.12  Terminal device control

POSIX provides a complete set of routines for manipulating terminal devices — putting them in "raw" mode, changing and querying their special characters, modifying their I/O speeds, and so forth. However, now that terminal emulators have almost completely displaced terminals, very little of this is useful except for directly controlling serial-line hardware, which itself is increasingly rare. Therefore, this SRFI provides only the functions that are still in common use by command-line programs.

(terminal? port)    →    boolean       (procedure)       POSIX isatty() 
Return true if the argument is a terminal. Raises an error if port is not a port, or if the underlying call to isatty() returns an error other than ENOTTY.

(terminal-file-name port)    →    string       (procedure)       POSIX ttyname() 
The argument port must be open on a terminal. Return the file name of the terminal.

The following procedures use dynamic-wind when executing their proc procedure argument; if proc's dynamic extent is escaped, the terminal mode changes of the containing with-or without- procedure are undone, but if proc's dynamic extent is re-entered, the terminal mode changes of the containing procedure are re-enabled. They all use POSIX tcgetattr() and tcsetattr(), see also the stty command.

The general paradigm for using the following procedures is to set up your application, then run it in the proc provided to them, a procedure that takes the same port arguments in the same order as the containing with- or without- procedure. The without-echo procedure is an exception in that it's generally used to enter a password or passphrase. The procedures return the values that proc returns.

(with-raw-mode input-port output-port min time proc)    →    [values]       (procedure)       POSIX stty -ECHO -ICANON -IEXTEN -ISIG -BRKINT -ICRNL -INPCK -ISTRIP -IXON -CSIZE -PARENB CS8 -OPOST VMIN=min VTIME=time 
The port arguments must be opened on a terminal. The terminal is set to raw mode during the dynamic execution of proc and then is restored to canonical "cooked" mode. The effect of the min and time arguments is that any reads done on the terminal while raw mode is in effect will return to the caller after min bytes have been read or time deciseconds (1/10ths of a second) have elapsed, whichever comes first. Therefore, it makes no sense to use any read operation on the terminal except read-char or read-string, which read a fixed number of characters. No character is given special handling; all are passed to the application exactly as received. Echoing of input is disabled on the terminal during the execution of proc and then is re-enabled.

(with-rare-mode input-port output-port proc)    →    [values]       (procedure)       POSIX stty -ICANON -ECHO VMIN=1 VTIME=0 
The port arguments must be opened on a terminal. The terminal is set to "rare", also known as cbreak mode during the dynamic execution of proc, and then is restored to canonical "cooked" mode. Just as in canonical mode, any read operation on the terminal will wait until characters are received, unlike raw mode. However, no characters are given special interpretation except the characters that send signals (by default, Ctrl-C and Ctrl-\). Echoing of input is disabled on the terminal during the execution of proc and then is re-enabled.

(without-echo input-port output-port proc)    →    [values]       (procedure)       POSIX stty -ECHO -ECHOE -ECHOK -ECHONL 
The port arguments must be opened on a terminal. Echoing of input is disabled on the terminal during the execution of proc and then is re-enabled.


There are two implementations of this SRFI, Scsh version 0.7, which can be found at GitHub in the scsh repository of scheme, and a Chibi Scheme (srfi 170) library (see build notes scsh here, and the Chibi Scheme example implementation in its srfi subdirectory). They have the following exceptions and deviations, in which Bionic Beaver refers to x86-64 Ubuntu 18.04 Linux kernel 4.15.0, gcc v7.4.1, OpenBSD refers to x86-64 OpenBSD 6.5, clang v7.0.1.

3.1  [Intentionally omitted]

3.2  I/O

3.3  File system

3.4  [Intentionally omitted]

3.5  Process state

3.6  User and group database access

3.7  [Intentionally omitted]

3.8  [Intentionally omitted]

3.9  [Intentionally omitted]

3.10  Time

3.11  [Intentionally omitted]

3.12  Terminal device control


Thanks to Olin Shivers, sine quo non, and all the Scheme implementors who have followed his work. Thanks also to all the participants in the SRFI mailing list.


Copyright © 2019 by John Cowan.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.


This SRFI is derived from the documentation for scsh, whose copyright notice, from the COPYING file, is reprinted here:

Copyright (c) 1993-2003 Richard Kelsey and Jonathan Rees

Copyright (c) 1994-2003 by Olin Shivers and Brian D. Carlstrom.

Copyright (c) 1999-2003 by Martin Gasbichler.

Copyright (c) 2001-2003 by Michael Sperber.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. The name of the authors may not be used to endorse or promote products derived from this software without specific prior written permission.


Editor: Arthur A. Gleckler