Go to the first, previous, next, last section, table of contents.

Input/Output

This chapter describes the procedures that are used for input and output (I/O). The chapter first describes ports and how they are manipulated, then describes the I/O operations. Finally, some low-level procedures are described that permit the implementation of custom ports and high-performance I/O.

Ports

Scheme uses ports for I/O. A port, which can be treated like any other Scheme object, serves as a source or sink for data. A port must be open before it can be read from or written to. The standard I/O port, console-i/o-port, is opened automatically when you start Scheme. When you use a file for input or output, you need to explicitly open and close a port to the file (with procedures described in this chapter). Additional procedures let you open ports to strings.

Many input procedures, such as read-char and read, read data from the current input port by default, or from a port that you specify. The current input port is initially console-i/o-port, but Scheme provides procedures that let you change the current input port to be a file or string.

Similarly, many output procedures, such as write-char and display, write data to the current output port by default, or to a port that you specify. The current output port is initially console-i/o-port, but Scheme provides procedures that let you change the current output port to be a file or string.

All ports read or write only ASCII characters.

Every port is either an input port, an output port, or both. The following predicates distinguish all of the possible cases.

procedure+: port? object
Returns #t if object is a port, otherwise returns #f.

procedure: input-port? object
Returns #t if object is an input port, otherwise returns #f. Any object satisfying this predicate also satisfies port?.

procedure: output-port? object
Returns #t if object is an output port, otherwise returns #f. Any object satisfying this predicate also satisfies port?.

procedure+: i/o-port? object
Returns #t if object is both an input port and an output port, otherwise returns #f. Any object satisfying this predicate also satisfies port?, input-port?, and output-port?.

procedure+: guarantee-input-port object
procedure+: guarantee-output-port object
procedure+: guarantee-i/o-port object
These procedures check the type of object, signalling an error of type condition-type:wrong-type-argument if it is not an input port, output port, or I/O port, respectively. Otherwise they return object.

The next five procedures return the runtime system's standard ports. All of the standard ports are dynamically bound by the REP loop; this means that when a new REP loop is started, for example by an error, each of these ports is dynamically bound to the I/O port of the REP loop. When the REP loop exits, the ports revert to their original values.

procedure: current-input-port
Returns the current input port. This is the default port used by many input procedures. Initially, current-input-port returns the value of console-i/o-port.

procedure: current-output-port
Returns the current output port. This is the default port used by many output procedures. Initially, current-output-port returns the value of console-i/o-port.

procedure+: notification-output-port
Returns an output port suitable for generating "notifications", that is, messages to the user that supply interesting information about the execution of a program. For example, the load procedure writes messages to this port informing the user that a file is being loaded. Initially, notification-output-port returns the value of console-i/o-port.

procedure+: trace-output-port
Returns an output port suitable for generating "tracing" information about a program's execution. The output generated by the trace procedure is sent to this port. Initially, trace-output-port returns the value of console-i/o-port.

procedure+: interaction-i/o-port
Returns an I/O port suitable for querying or prompting the user. The standard prompting procedures use this port by default (see section Prompting). Initially, interaction-i/o-port returns the value of console-i/o-port.

procedure+: with-input-from-port input-port thunk
procedure+: with-output-to-port output-port thunk
procedure+: with-notification-output-port output-port thunk
procedure+: with-trace-output-port output-port thunk
procedure+: with-interaction-i/o-port i/o-port thunk
Thunk must be a procedure of no arguments. Each of these procedures binds one of the standard ports to its first argument, calls thunk with no arguments, restores the port to its original value, and returns the result that was yielded by thunk. This temporary binding is performed the same way as fluid binding of a variable, including the behavior in the presence of continuations (see section Fluid Binding).

with-input-from-port binds the current input port, with-output-to-port binds the current output port, with-notification-output-port binds the "notification" output port, with-trace-output-port binds the "trace" output port, and with-interaction-i/o-port binds the "interaction" I/O port.

procedure+: set-current-input-port! input-port
procedure+: set-current-output-port! output-port
procedure+: set-notification-output-port! output-port
procedure+: set-trace-output-port! output-port
procedure+: set-interaction-i/o-port! i/o-port
Each of these procedures alters the binding of one of the standard ports and returns an unspecified value. The binding that is modified corresponds to the name of the procedure.

variable+: console-i/o-port
console-i/o-port is an I/O port that communicates with the "console". Under unix, the console is the controlling terminal of the Scheme process. Under MS-DOS, the console is a combination of the keyboard and the display. Under Windows, the console is the window that is created when Scheme starts up.

This variable is rarely used; instead programs should use one of the standard ports defined above. This variable should not be modified.

For compatibility with old code, console-input-port and console-output-port are synonyms for this variable.

procedure+: close-port port
procedure: close-input-port port
procedure: close-output-port port
Closes port and returns an unspecified value. If port is a file port, the file is closed. close-input-port and close-output-port are synonyms for close-port that are defined for compatibility with standard Scheme.

File Ports

Before Scheme can access a file for reading or writing, it is necessary to open a port to the file. This section describes procedures used to open ports to files. Such ports are closed (like any other port) by close-port. File ports are automatically closed if and when they are reclaimed by the garbage collector.

Before opening a file for input or output, by whatever method, the filename argument is converted to canonical form by calling the procedure merge-pathnames with filename as its sole argument. Thus, filename can be either a string or a pathname, and it is merged with the current pathname defaults to produce the pathname that is then opened.

Any file can be opened in one of two modes, normal or binary. Normal mode is for accessing text files, and binary mode is for accessing other files. Some operating systems, e.g. unix, do not distinguish these modes. MS-DOS is an example of an operating system that does distinguish these modes: in normal mode, MS-DOS file ports perform newline translation, mapping between the carriage-return/linefeed sequence that terminates text lines in files, and the #\newline that terminates lines in Scheme. In binary mode, MS-DOS ports do not perform newline translation. Unless otherwise mentioned, the procedures in this section open files in normal mode.

procedure: open-input-file filename
Takes a filename referring to an existing file and returns an input port capable of delivering characters from the file. If the file cannot be opened, an error of type condition-type:file-operation-error is signalled.

procedure: open-output-file filename [append?]
Takes a filename referring to an output file to be created and returns an output port capable of writing characters to a new file by that name. If the file cannot be opened, an error of type condition-type:file-operation-error is signalled.

The optional argument append? is an MIT Scheme extension. If append? is given and not #f, the file is opened in append mode. In this mode, the contents of the file are not overwritten; instead any characters written to the file are appended to the end of the existing contents. If the file does not exist, append mode creates the file and writes to it in the normal way.

procedure+: open-i/o-file filename
Takes a filename referring to an existing file and returns an I/O port capable of both reading and writing the file. If the file cannot be opened, an error of type condition-type:file-operation-error is signalled.

This procedure is often used to open special files. For example, under unix this procedure can be used to open terminal device files, PTY device files, and named pipes.

procedure+: open-binary-input-file filename
procedure+: open-binary-output-file filename [append?]
procedure+: open-binary-i/o-file filename
These procedures open files in binary mode. In all other respects they are identical to open-input-file, open-output-file, and open-i/o-file, respectively.

procedure+: close-all-open-files
This procedure closes all file ports that are open at the time that it is called, and returns an unspecified value.

procedure: call-with-input-file filename procedure
procedure: call-with-output-file filename procedure
These procedures call procedure with one argument: the port obtained by opening the named file for input or output, respectively. If the file cannot be opened, an error of type condition-type:file-operation-error is signalled. If procedure returns, then the port is closed automatically and the value yielded by procedure is returned. If procedure does not return, then the port will not be closed automatically unless it is reclaimed by the garbage collector.(20)

procedure+: call-with-binary-input-file filename procedure
procedure+: call-with-binary-output-file filename procedure
These procedures open files in binary mode. In all other respects they are identical to call-with-input-file and call-with-output-file, respectively.

procedure: with-input-from-file filename thunk
procedure: with-output-to-file filename thunk
Thunk must be a procedure of no arguments. The file is opened for input or output, an input or output port connected to it is made the default value returned by current-input-port or current-output-port, and the thunk is called with no arguments. When the thunk returns, the port is closed and the previous default is restored. with-input-from-file and with-output-to-file return the value yielded by thunk. If an escape procedure is used to escape from the continuation of these procedures, their behavior is implementation-dependent; in that situation MIT Scheme leaves the files open.

procedure+: with-input-from-binary-file filename thunk
procedure+: with-output-to-binary-file filename thunk
These procedures open files in binary mode. In all other respects they are identical to with-input-from-file and with-output-to-file, respectively.

String Ports

This section describes the simplest kinds of ports: input ports that read their input from given strings, and output ports that accumulate their output and return it as a string. It also describes "truncating" output ports, which can limit the length of the resulting string to a given value.

procedure+: string->input-port string [start [end]]
Returns a new string port that delivers characters from string. The optional arguments start and end may be used to specify that the string port delivers characters from a substring of string; if not given, start defaults to 0 and end defaults to (string-length string).

procedure+: with-input-from-string string thunk
Thunk must be a procedure of no arguments. with-input-from-string creates a new input port that reads from string, makes that port the current input port, and calls thunk. When thunk returns, with-input-from-string restores the previous current input port and returns the result yielded by thunk.

(with-input-from-string "(a b c) (d e f)" read)  =>  (a b c)

Note: this procedure is equivalent to:

(with-input-from-port (string->input-port string) thunk)

procedure+: with-string-output-port procedure
Procedure is called with one argument, an output port. The value yielded by procedure is ignored. When procedure returns, with-string-output-port returns the accumulated output to the port as a newly allocated string.

procedure+: with-output-to-string thunk
Thunk must be a procedure of no arguments. with-output-to-string creates a new output port that accumulates output, makes that port the default value returned by current-output-port, and calls thunk with no arguments. When thunk returns, with-output-to-string restores the previous default and returns the accumulated output as a newly allocated string.

(with-output-to-string
  (lambda ()
    (write 'abc)))                    =>  "abc"

Note: this procedure is equivalent to:

(with-string-output-port
 (lambda (port)
   (with-output-to-port port thunk)))

procedure+: with-output-to-truncated-string k thunk
Similar to with-output-to-string, except that the output is limited to k characters. If thunk attempts to write more than k characters, it will be aborted by invoking an escape procedure that returns from with-output-to-truncated-string.

The value of this procedure is a pair; the car of the pair is #t if thunk attempted to write more than k characters, and #f otherwise. The cdr of the pair is a newly allocated string containing the accumulated output.

This procedure is helpful for displaying circular lists, as shown in this example:

(define inf (list 'inf))
(with-output-to-truncated-string 40
  (lambda ()
    (write inf)))                       =>  (#f . "(inf)")
(set-cdr! inf inf)
(with-output-to-truncated-string 40
  (lambda ()
    (write inf)))
        =>  (#t . "(inf inf inf inf inf inf inf inf inf inf")

procedure+: write-to-string object [k]
Writes object to a string output port, and returns the resulting newly allocated string. If k is supplied and not #f, this procedure is equivalent to

(with-output-to-truncated-string k
  (lambda ()
    (write object)))

otherwise it is equivalent to

(with-output-to-string
 (lambda ()
   (write object)))

Input Procedures

This section describes the procedures that read input. Input procedures can read either from the current input port or from a given port. Remember that to read from a file, you must first open a port to the file.

Input ports can be divided into two types, called interactive and non-interactive. Interactive input ports are ports that read input from a source that is time-dependent; for example, a port that reads input from a terminal or from another program. Non-interactive input ports read input from a time-independent source, such as an ordinary file or a character string.

All optional arguments called input-port, if not supplied, default to the current input port.

procedure: read-char [input-port]
Returns the next character available from input-port, updating input-port to point to the following character. If no more characters are available, an end-of-file object is returned.

In MIT Scheme, if input-port is an interactive input port and no characters are immediately available, read-char will hang waiting for input.

procedure: peek-char [input-port]
Returns the next character available from input-port, without updating input-port to point to the following character. If no more characters are available, an end-of-file object is returned.(21)

In MIT Scheme, if input-port is an interactive input port and no characters are immediately available, peek-char will hang waiting for input.

procedure: char-ready? [input-port]
Returns #t if a character is ready on input-port and returns #f otherwise. If char-ready? returns #t then the next read-char operation on input-port is guaranteed not to hang. If input-port is a file port at end of file then char-ready? returns #t.(22)

procedure: read [input-port]
Converts external representations of Scheme objects into the objects themselves. read returns the next object parsable from input-port, updating input-port to point to the first character past the end of the written representation of the object. If an end of file is encountered in the input before any characters are found that can begin an object, read returns an end-of-file object. The input-port remains open, and further attempts to read will also return an end-of-file object. If an end of file is encountered after the beginning of an object's written representation, but the written representation is incomplete and therefore not parsable, an error is signalled.

procedure: eof-object? object
Returns #t if object is an end-of-file object; otherwise returns #f.

procedure+: read-char-no-hang [input-port]
If input-port can deliver a character without blocking, this procedure acts exactly like read-char, immediately returning that character. Otherwise, #f is returned, unless input-port is a file port at end of file, in which case an end-of-file object is returned. In no case will this procedure block waiting for input.

procedure+: read-string char-set [input-port]
Reads characters from input-port until it finds a terminating character that is a member of char-set (see section Character Sets) or encounters end of file. The port is updated to point to the terminating character, or to end of file if no terminating character was found. read-string returns the characters, up to but excluding the terminating character, as a newly allocated string. However, if end of file was encountered before any characters were read, read-string returns an end-of-file object.

On many input ports, this operation is significantly faster than the following equivalent code using peek-char and read-char:

(define (read-string char-set input-port)
  (let ((char (peek-char input-port)))
    (if (eof-object? char)
        char
        (list->string
         (let loop ((char char))
           (if (or (eof-object? char)
                   (char-set-member? char-set char))
               '()
               (begin
                 (read-char input-port)
                 (cons char (loop (peek-char input-port))))))))))

Output Procedures

Output ports may or may not support buffering of output, in which output characters are collected together in a buffer and then sent to the output device all at once. (Most of the output ports implemented by the runtime system support buffering.) Sending all of the characters in the buffer to the output device is called flushing the buffer. In general, output procedures do not flush the buffer of an output port unless the buffer is full.

However, the standard output procedures described in this section perform what is called discretionary flushing of the buffer. Discretionary output flushing works as follows. After a procedure performs its output (writing characters to the output buffer), it checks to see if the port implements an operation called discretionary-output-flush. If so, then that operation is invoked to flush the buffer. At present, only the console port defines discretionary-output-flush; this is used to guarantee that output to the console appears immediately after it is written, without requiring calls to flush-output.

All optional arguments called output-port, if not supplied, default to the current output port.

procedure+: flush-output [output-port]
If output-port is buffered, this causes the contents of its buffer to be written to the output device. Otherwise it has no effect. Returns an unspecified value.

procedure: write-char char [output-port]
Writes char (the character itself, not a written representation of the character) to output-port, performs discretionary output flushing, and returns an unspecified value.

procedure+: write-string string [output-port]
Writes string to output-port, performs discretionary output flushing, and returns an unspecified value. This is equivalent to writing the contents of string, one character at a time using write-char, except that it is usually much faster.

procedure: write object [output-port]
Writes a written representation of object to output-port, and returns an unspecified value. If object has a standard external representation, then the written representation generated by write shall be parsable by read into an equivalent object. Thus strings that appear in the written representation are enclosed in doublequotes, and within those strings backslash and doublequote are escaped by backslashes. write performs discretionary output flushing and returns an unspecified value.

procedure: display object [output-port]
Writes a representation of object to output-port. Strings appear in the written representation as if written by write-string instead of by write. Character objects appear in the representation as if written by write-char instead of by write. display performs discretionary output flushing and returns an unspecified value.(23)

procedure: newline [output-port]
Writes an end-of-line to output-port, performs discretionary output flushing, and returns an unspecified value. Equivalent to (write-char #\newline output-port).

procedure+: fresh-line [output-port]
Some output ports are able to tell whether or not they are at the beginning of a line of output. If output-port is such a port, this procedure writes an end-of-line to the port only if the port is not already at the beginning of a line. If output-port is not such a port, this procedure is identical to newline. In either case, fresh-line performs discretionary output flushing and returns an unspecified value.

procedure+: write-line object [output-port]
Like write, except that it writes an end-of-line to output-port before writing object's representation. This procedure performs discretionary output flushing and returns an unspecified value.

procedure+: beep [output-port]
Performs a "beep" operation on output-port, performs discretionary output flushing, and returns an unspecified value. On the console port, this usually causes the console bell to beep, but more sophisticated interactive ports may take other actions, such as flashing the screen. On most output ports, e.g. file and string output ports, this does nothing.

procedure+: clear [output-port]
"Clears the screen" of output-port, performs discretionary output flushing, and returns an unspecified value. On a terminal or window, this has a well-defined effect. On other output ports, e.g. file and string output ports, this does nothing.

procedure+: pp object [output-port [as-code?]]
pp prints object in a visually appealing and structurally revealing manner on output-port. If object is a procedure, pp attempts to print the source text. If the optional argument as-code? is true, pp prints lists as Scheme code, providing appropriate indentation; by default this argument is false. pp performs discretionary output flushing and returns an unspecified value.

The following variables may be dynamically bound to change the behavior of the write and display procedures.

variable+: *unparser-radix*
This variable specifies the default radix used to print numbers. Its value must be one of the exact integers 2, 8, 10, or 16; the default is 10. If *unparser-radix* is not 10, numbers are prefixed to indicate their radix.

variable+: *unparser-list-breadth-limit*
This variable specifies a limit on the length of the printed representation of a list or vector; for example, if the limit is 4, only the first four elements of any list are printed, followed by ellipses to indicate any additional elements. The value of this variable must be an exact non-negative integer, or #f meaning no limit; the default is #f.

(fluid-let ((*unparser-list-breadth-limit* 4))
  (write-to-string '(a b c d)))
                                => "(a b c d)"
(fluid-let ((*unparser-list-breadth-limit* 4))
  (write-to-string '(a b c d e)))
                                => "(a b c d ...)"

variable+: *unparser-list-depth-limit*
This variable specifies a limit on the nesting of lists and vectors in the printed representation. If lists (or vectors) are more deeply nested than the limit, the part of the representation that exceeds the limit is replaced by ellipses. The value of this variable must be an exact non-negative integer, or #f meaning no limit; the default is #f.

(fluid-let ((*unparser-list-depth-limit* 4))
  (write-to-string '((((a))) b c d)))
                                => "((((a))) b c d)"
(fluid-let ((*unparser-list-depth-limit* 4))
  (write-to-string '(((((a)))) b c d)))
                                => "((((...))) b c d)"

variable+: *unparser-string-length-limit*
This variable specifies a limit on the length of the printed representation of strings. If a string's length exceeds this limit, the part of the printed representation for the characters exceeding the limit is replaced by ellipses. The value of this variable must be an exact non-negative integer, or #f meaning no limit; the default is #f.

(fluid-let ((*unparser-string-length-limit* 4))
  (write-to-string "abcd"))
                                => "\"abcd\""
(fluid-let ((*unparser-string-length-limit* 4))
  (write-to-string "abcde"))
                                => "\"abcd...\""

variable+: *unparse-with-maximum-readability?*
This variable, which takes a boolean value, tells the printer to use a special printed representation for objects that normally print in a form that cannot be recognized by read. These objects are printed using the representation #@n, where n is the result of calling hash on the object to be printed. The reader recognizes this syntax, calling unhash on n to get back the original object. Note that this printed representation can only be recognized by the Scheme program in which it was generated, because these hash numbers are different for each invocation of Scheme.

Format

The procedure format is very useful for producing nicely formatted text, producing good-looking messages, and so on. MIT Scheme's implementation of format is similar to that of Common Lisp, except that Common Lisp defines many more directives.(24)

format is a run-time-loadable option. To use it, execute

(load-option 'format)

once before calling it.

procedure+: format destination control-string argument ...
Writes the characters of control-string to destination, except that a tilde (~) introduces a format directive. The character after the tilde, possibly preceded by prefix parameters and modifiers, specifies what kind of formatting is desired. Most directives use one or more arguments to create their output; the typical directive puts the next argument into the output, formatted in some special way. It is an error if no argument remains for a directive requiring an argument, but it is not an error if one or more arguments remain unprocessed by a directive.

The output is sent to destination. If destination is #f, a string is created that contains the output; this string is returned as the value of the call to format. In all other cases format returns an unspecified value. If destination is #t, the output is sent to the current output port. Otherwise, destination must be an output port, and the output is sent there.

This procedure performs discretionary output flushing (see section Output Procedures).

A format directive consists of a tilde (~), optional prefix parameters separated by commas, optional colon (:) and at-sign (@) modifiers, and a single character indicating what kind of directive this is. The alphabetic case of the directive character is ignored. The prefix parameters are generally integers, notated as optionally signed decimal numbers. If both the colon and at-sign modifiers are given, they may appear in either order.

In place of a prefix parameter to a directive, you can put the letter `V' (or `v'), which takes an argument for use as a parameter to the directive. Normally this should be an exact integer. This feature allows variable-width fields and the like. You can also use the character `#' in place of a parameter; it represents the number of arguments remaining to be processed.

It is an error to give a format directive more parameters than it is described here as accepting. It is also an error to give colon or at-sign modifiers to a directive in a combination not specifically described here as being meaningful.

~A
The next argument, which may be any object, is printed as if by display. ~mincolA inserts spaces on the right, if necessary, to make the width at least mincol columns. The @ modifier causes the spaces to be inserted on the left rather than the right.
~S
The next argument, which may be any object, is printed as if by write. ~mincolS inserts spaces on the right, if necessary, to make the width at least mincol columns. The @ modifier causes the spaces to be inserted on the left rather than the right.
~%
This outputs a #\newline character. ~n% outputs n newlines. No argument is used. Simply putting a newline in control-string would work, but ~% is often used because it make the control string look nicer in the middle of a program.
~~
This outputs a tilde. ~n~ outputs n tildes.
~newline
Tilde immediately followed by a newline ignores the newline and any following non-newline whitespace characters. With an @, the newline is left in place, but any following whitespace is ignored. This directive is typically used when control-string is too long to fit nicely into one line of the program:
(define (type-clash-error procedure arg spec actual)
  (format #t
          "~%Procedure ~S~%requires its %A argument ~
           to be of type ~S,~%but it was called with ~
           an argument of type ~S.~%"
          procedure arg spec actual))
(type-clash-error 'vector-ref "first" 'integer 'vector) prints:
Procedure vector-ref
requires its first argument to be of type integer,
but it was called with an argument of type vector.
Note that in this example newlines appear in the output only as specified by the ~% directives; the actual newline characters in the control string are suppressed because each is preceded by a tilde.

Custom Output

MIT Scheme provides hooks for specifying that certain kinds of objects have special written representations. There are no restrictions on the written representations, but only a few kinds of objects may have custom representation specified for them, specifically: records (see section Records), vectors that have special tags in their zero-th elements (see section Vectors), and pairs that have special tags in their car fields (see section Lists). There is a different procedure for specifying the written representation of each of these types.

procedure+: set-record-type-unparser-method! record-type unparser-method
Changes the unparser method of the type represented by record-type to be unparser-method, and returns an unspecified value. Subsequently, when the unparser encounters a record of this type, it will invoke unparser-method to generate the written representation.

procedure+: unparser/set-tagged-vector-method! tag unparser-method
Changes the unparser method of the vector type represented by tag to be unparser-method, and returns an unspecified value. Subsequently, when the unparser encounters a vector with tag as its zero-th element, it will invoke unparser-method to generate the written representation.

procedure+: unparser/set-tagged-pair-method! tag unparser-method
Changes the unparser method of the pair type represented by tag to be unparser-method, and returns an unspecified value. Subsequently, when the unparser encounters a pair with tag in its car field, it will invoke unparser-method to generate the written representation.

An unparser method is a procedure that is invoked with two arguments: an unparser state and an object. An unparser method generates a written representation for the object, writing it to the output port specified by the unparser state. The value yielded by an unparser method is ignored. Note that an unparser state is not an output port, rather it is an object that contains an output port as one of its components. Application programs generally do not construct or examine unparser state objects, but just pass them along.

There are two ways to create an unparser method (which is then registered by one of the above procedures). The first, and easiest, is to use standard-unparser-method. The second is to define your own method using the procedure with-current-unparser-state. We encourage the use of the first method, as it results in a more uniform appearance for objects. Many predefined datatypes, for example procedures and environments, already have this appearance.

procedure+: standard-unparser-method name procedure
Returns a standard unparser method. Name may be any object, and is used as the name of the type with which the unparser method is associated; name is usually a symbol. Procedure must be #f or a procedure of two arguments.

If procedure is #f, the returned method generates an external representation of this form:

#[name hash]

Here name is the external representation of the argument name, as generated by write,(25) and hash is the external representation of an exact non-negative integer unique to the object being printed (specifically, it is the result of calling hash on the object). Subsequently, the expression

#@hash

is notation for the object.

If procedure is supplied, the returned method generates a slightly different external representation:

#[name hash output]

Here name and hash are as above, and output is the output generated by procedure. The representation is constructed in three stages:

  1. The first part of the format (up to output) is written to the output port specified by the unparser state. This is "#[", name, " ", and hash.
  2. Procedure is invoked on two arguments: the object and an output port.
  3. The closing bracket is written to the output port.

The following procedure is useful for writing more general kinds of unparser methods.

procedure+: with-current-unparser-state unparser-state procedure
This procedure calls procedure with one argument, the output port from unparser-state. Additionally, it arranges for the remaining components of unparser-state to be given to the printer when they are needed. The procedure generates some output by writing to the output port using the usual output operations, and the value yielded by procedure is returned from with-current-unparser-state.

The port passed to procedure should only be used within the dynamic extent of procedure.

Prompting

This section describes procedures that prompt the user for input. Why should the programmer use these procedures when it is possible to do prompting using ordinary input and output procedures? One reason is that the prompting procedures are more succinct. However, a second and better reason is that the prompting procedures can be separately customized for each user interface, providing more natural interaction. The interfaces for Edwin and for GNU Emacs have already been customized in this fashion; because Edwin and Emacs are very similar editors, their customizations provide very similar behavior.

Each of these procedure accepts an optional argument called port, which must be an I/O port if given. If not given, this port defaults to the value of (interaction-i/o-port); this is initially the console I/O port.

The required argument prompt must be a string.

procedure+: prompt-for-command-expression prompt [port]
Prompts the user for an expression that is to be executed as a command. This is the procedure called by the REP loop to read the user's expressions.

The prompt string is formed by appending a space to prompt, unless prompt already ends in a space or is an empty string.

The default behavior of this procedure is to print two newlines, the current REP loop "level number", a space, and the prompt string; flush the output buffer; then read an object and return it.

Under Edwin and Emacs, before the object is read, the interaction buffer is put into a mode that allows expressions to be edited and submitted for input using specific editor commands. The first expression that is submitted is returned as the value of this procedure.

procedure+: prompt-for-command-char prompt [port]
Prompts the user for a single character that is to be executed as a command; the returned character is guaranteed to satisfy char-graphic?. If at all possible, the character is read from the user interface using a mode that reads the character as a single keystroke; in other words, it should not be necessary for the user to follow the character with a carriage return or similar rubbish.

This is the procedure called by debug and where to read the user's commands.

The prompt string is formed by appending a space to prompt, unless prompt already ends in a space or is an empty string.

The default behavior of this procedure is to print two newlines, the current REP loop "level number", a space, and the prompt string; flush the output buffer; read a character in raw mode, echo that character, and return it.

Under Edwin and Emacs, instead of reading a character, the interaction buffer is put into a mode in which graphic characters submit themselves as input. After this mode change, the first such character submitted is returned as the value of this procedure.

procedure+: prompt-for-expression prompt [port]
Prompts the user for an expression.

The prompt string is formed by appending a colon and a space to prompt, unless prompt already ends in a space.

The default behavior of this procedure is to print two newlines and the prompt string; flush the output buffer; then read an object and return it.

Under Edwin and Emacs, the expression is read in the minibuffer.

procedure+: prompt-for-evaluated-expression prompt [environment [port]]
Prompts the user for an evaluated expression. Calls prompt-for-expression to read an expression, then evaluates the expression using environment; if environment is not given, the REP loop environment is used.

procedure+: prompt-for-confirmation prompt [port]
Prompts the user for confirmation. The result yielded by this procedure is a boolean.

The prompt string is formed by appending the string " (y or n)? " to prompt, unless prompt already ends in a space.

The default behavior of this procedure is to print two newlines and the prompt string; flush the output buffer; then read a character in raw mode. If the character is #\y, #\Y, or #\space, the procedure returns #t; If the character is #\n, #\N, or #\rubout, the procedure returns #f. Otherwise the prompt is repeated.

Under Edwin or Emacs, the confirmation is read in the minibuffer.

Port Primitives

This section describes the low-level operations that can be used to build and manipulate I/O ports.

The purpose of these operations is twofold: to allow programmers to construct new kinds of I/O ports, and to provide faster I/O operations than those supplied by the standard high level procedures. The latter is useful because the standard I/O operations provide defaulting and error checking, and sometimes other features, which are often unnecessary. This interface provides the means to bypass such features, thus improving performance.

The abstract model of an I/O port, as implemented here, is a combination of a set of named operations and a state. The state is an arbitrary object, the meaning of which is determined by the operations. The operations are defined by a mapping from names to procedures. Typically the names are symbols, but any object that can be discriminated by eq? may be used.

The operations are divided into two classes:

Standard operations
There is a specific set of standard operations for input ports, and a different set for output ports. Applications can assume that the standard input operations are implemented for all input ports, and likewise the standard output operations are implemented for all output ports.
Custom operations
Some ports support additional operations. For example, ports that implement output to terminals (or windows) may define an operation named y-size that returns the height of the terminal in characters. Because only some ports will implement these operations, programs that use custom operations must test each port for their existence, and be prepared to deal with ports that do not implement them.

Constructors and Accessors for Ports

The procedures in this section provide means for constructing ports with custom operations, accessing their operations, and manipulating their internal state.

procedure+: make-input-port operations object
procedure+: make-output-port operations object
procedure+: make-i/o-port operations object
Operations must be a list; each element is a list of two elements, the name of the operation and the procedure that implements it. A new port is returned with the given operations and a state component of object.

Operations need not contain definitions for all of the standard operations; the procedure will provide defaults for any standard operations that are not defined. At a minimum, the following operations must be defined: for input ports, read-char, peek-char, and char-ready?; for output ports, either write-char or write-substring; I/O ports must supply the minimum operations for both input and output.

procedure+: port/copy port object
Returns a new copy of port, identical to the original except that its state component is object. Port is not modified.

port/copy is normally used to speed up creation of ports. This is done by creating a template using one of the port constructors make-input-port, make-output-port, or make-i/o-port, as appropriate; a dummy state component is supplied for the template. Then port/copy is used to make a copy of the template, supplying the copy with the correct state. This is useful because the port constructors are somewhat slow, as they must parse the operations list, provide defaulting for missing operations, etc.

For compatibility with old code, input-port/copy and output-port/copy are synonyms for this procedure.

procedure+: port/state port
Returns the state component of port.

For compatibility with old code, input-port/state and output-port/state are synonyms for this procedure.

procedure+: set-port/state! port object
Changes the state component of port to be object. Returns an unspecified value.

For compatibility with old code, set-input-port/state! and set-output-port/state! are synonyms for this procedure.

procedure+: port/operation port object
Returns the operation named object in port. If port has no such operation, returns #f.

For compatibility with old code, input-port/operation and output-port/operation are similar to port/operation. They differ in that they translate certain old operation names to new equivalents before calling port/operation. input-port/custom-operation and output-port/custom-operation are synonyms for input-port/operation and output-port/operation, respectively.

procedure+: port/operation-names port
Returns a list whose elements are the names of the operations supported by port. The list is not newly allocated and must not be modified.

For compatibility with old code, input-port/operation-names and output-port/operation-names are synonyms for this procedure.

procedure+: make-eof-object input-port
Returns an object that satisfies the predicate eof-object?. This is sometimes useful when building input ports.

Blocking Mode

An interactive port is always in one of two modes: blocking or non-blocking. This mode is independent of the terminal mode: each can be changed independent of the other. Furthermore, if it is an interactive I/O port, there are separate blocking modes for input and for output.

If an input port is in blocking mode, attempting to read from it when no input is available will cause Scheme to "block", i.e. suspend itself, until input is available. If an input port is in non-blocking mode, attempting to read from it when no input is available will cause the reading procedure to return immediately, indicating the lack of input in some way (exactly how this situation is indicated is separately specified for each procedure or operation).

An output port in blocking mode will block if the output device is not ready to accept output. In non-blocking mode it will return immediately after performing as much output as the device will allow (again, each procedure or operation reports this situation in its own way).

Interactive ports are initially in blocking mode; this can be changed at any time with the procedures defined in this section.

These procedures represent blocking mode by the symbol blocking, and non-blocking mode by the symbol nonblocking. An argument called mode must be one of these symbols. A port argument to any of these procedures may be any port, even if that port does not support blocking mode; in that case, the port is not modified in any way.

procedure+: port/input-blocking-mode port
Returns the input blocking mode of port.

procedure+: port/set-input-blocking-mode port mode
Changes the input blocking mode of port to be mode. Returns an unspecified value.

procedure+: port/with-input-blocking-mode port mode thunk
Thunk must be a procedure of no arguments. port/with-input-blocking-mode binds the input blocking mode of port to be mode, executes thunk, restores the input blocking mode of port to what it was when port/with-input-blocking-mode was called, and returns the value that was yielded by thunk. This binding is performed by dynamic-wind, which guarantees that the input blocking mode is restored if thunk escapes from its continuation.

procedure+: port/output-blocking-mode port
Returns the output blocking mode of port.

procedure+: port/set-output-blocking-mode port mode
Changes the output blocking mode of port to be mode. Returns an unspecified value.

procedure+: port/with-output-blocking-mode port mode thunk
Thunk must be a procedure of no arguments. port/with-output-blocking-mode binds the output blocking mode of port to be mode, executes thunk, restores the output blocking mode of port to what it was when port/with-output-blocking-mode was called, and returns the value that was yielded by thunk. This binding is performed by dynamic-wind, which guarantees that the output blocking mode is restored if thunk escapes from its continuation.

Terminal Mode

A port that reads from or writes to a terminal has a terminal mode; this is either cooked or raw. This mode is independent of the blocking mode: each can be changed independent of the other. Furthermore, a terminal I/O port has independent terminal modes both for input and for output.

A terminal port in cooked mode provides some standard processing to make the terminal easy to communicate with. For example, under unix, cooked mode on input reads from the terminal a line at a time and provides rubout processing within the line, while cooked mode on output might translate linefeeds to carriage-return/linefeed pairs. In general, the precise meaning of cooked mode is operating-system dependent, and furthermore might be customizable by means of operating system utilities. The basic idea is that cooked mode does whatever is necessary to make the terminal handle all of the usual user-interface conventions for the operating system, while keeping the program's interaction with the port as normal as possible.

A terminal port in raw mode disables all of that processing. In raw mode, characters are directly read from and written to the device without any translation or interpretation by the operating system. On input, characters are available as soon as they are typed, and are not echoed on the terminal by the operating system. In general, programs that put ports in raw mode have to know the details of interacting with the terminal. In particular, raw mode is used for writing programs such as text editors.

Terminal ports are initially in cooked mode; this can be changed at any time with the procedures defined in this section.

These procedures represent cooked mode by the symbol cooked, and raw mode by the symbol raw. Additionally, the value #f represents "no mode"; it is the terminal mode of a port that is not a terminal. An argument called mode must be one of these three values. A port argument to any of these procedures may be any port, even if that port does not support terminal mode; in that case, the port is not modified in any way.

procedure+: port/input-terminal-mode port
Returns the input terminal mode of port.

procedure+: port/set-input-terminal-mode port mode
Changes the input terminal mode of port to be mode. Returns an unspecified value.

procedure+: port/with-input-terminal-mode port mode thunk
Thunk must be a procedure of no arguments. port/with-input-terminal-mode binds the input terminal mode of port to be mode, executes thunk, restores the input terminal mode of port to what it was when port/with-input-terminal-mode was called, and returns the value that was yielded by thunk. This binding is performed by dynamic-wind, which guarantees that the input terminal mode is restored if thunk escapes from its continuation.

procedure+: port/output-terminal-mode port
Returns the output terminal mode of port.

procedure+: port/set-output-terminal-mode port mode
Changes the output terminal mode of port to be mode. Returns an unspecified value.

procedure+: port/with-output-terminal-mode port mode thunk
Thunk must be a procedure of no arguments. port/with-output-terminal-mode binds the output terminal mode of port to be mode, executes thunk, restores the output terminal mode of port to what it was when port/with-output-terminal-mode was called, and returns the value that was yielded by thunk. This binding is performed by dynamic-wind, which guarantees that the output terminal mode is restored if thunk escapes from its continuation.

Input Port Operations

This section describes the standard operations on input ports.

operation+: input port read-char input-port
Removes the next character available from input-port and returns it. If input-port has no more characters and will never have any (e.g. at the end of an input file), this operation returns an end-of-file object. If input-port has no more characters but will eventually have some more (e.g. a terminal where nothing has been typed recently), and it is in non-blocking mode, #f is returned; otherwise the operation hangs until input is available.

operation+: input port peek-char input-port
Reads the next character available from input-port and returns it. The character is not removed from input-port, and a subsequent attempt to read from the port will get that character again. In other respects this operation behaves like read-char.

operation+: input port discard-char input-port
Discards the next character available from input-port and returns an unspecified value. In other respects this operation behaves like read-char.

operation+: input port char-ready? input-port k
char-ready? returns #t if at least one character is available to be read from input-port. If no characters are available, the operation waits up to k milliseconds before returning #f, returning immediately if any characters become available while it is waiting.

operation+: input port read-string input-port char-set
operation+: input port discard-chars input-port char-set
These operations are like read-char and discard-char, except that they read or discard multiple characters at once. This can have a marked performance improvement on buffered input ports. All characters up to, but excluding, the first character in char-set (or end of file) are read from input-port. read-string returns these characters as a newly allocated string, while discard-chars discards them and returns an unspecified value. These operations hang until sufficient input is available, even if input-port is in non-blocking mode. If end of file is encountered before any input characters, read-string returns an end-of-file object.

procedure+: input-port/operation/read-char input-port
procedure+: input-port/operation/peek-char input-port
procedure+: input-port/operation/discard-char input-port
procedure+: input-port/operation/char-ready? input-port
procedure+: input-port/operation/read-string input-port
procedure+: input-port/operation/discard-chars input-port
Each of these procedures returns the procedure that implements the respective operation for input-port. Each is equivalent to, but faster than, input-port/operation on the respective operation name:

(input-port/operation/read-char input-port)
(input-port/operation input-port 'read-char)

procedure+: input-port/read-char input-port
procedure+: input-port/peek-char input-port
procedure+: input-port/discard-char input-port
procedure+: input-port/char-ready? input-port k
procedure+: input-port/read-string input-port char-set
procedure+: input-port/discard-chars input-port char-set
Each of these procedures invokes the respective operation on input-port. For example, the following are equivalent:

(input-port/read-string input-port char-set)
((input-port/operation/read-string input-port) input-port char-set)

Output Port Operations

This section describes the standard operations on output ports. Following that, some useful custom operations are described.

operation+: output port write-char output-port char
Writes char to output-port and returns an unspecified value.

operation+: output port write-substring output-port string start end
Writes the substring specified by string, start, and end to output-port and returns an unspecified value. Equivalent to writing the characters of the substring, one by one, to output-port, but is often implemented more efficiently.

operation+: output port write-string output-port string
Writes string to output-port and returns an unspecified value.

operation+: output port flush-output output-port
If output-port is buffered, this causes its buffer to be written out. Otherwise it has no effect. Returns an unspecified value.

operation+: output port discretionary-flush-output output-port
If output-port is buffered, this causes its buffer to be written out. Otherwise it has no effect. Returns an unspecified value.

This operation, if defined, is normally identical to flush-output. However, it is not normally defined, and even when it is, it is invoked at different times (see section Output Procedures).

procedure+: output-port/operation/write-char output-port
procedure+: output-port/operation/write-substring output-port
procedure+: output-port/operation/write-string output-port
procedure+: output-port/operation/flush-output output-port
procedure+: output-port/operation/discretionary-flush-output output-port
Each of these procedures returns the procedure that implements the respective operation for output-port. Each is equivalent to, but faster than, output-port/operation on the respective operation name:

(output-port/operation/write-char output-port)
(output-port/operation output-port 'write-char)

procedure+: output-port/write-char output-port char
procedure+: output-port/write-substring output-port string start end
procedure+: output-port/write-string output-port string
procedure+: output-port/flush-output output-port
procedure+: output-port/discretionary-flush-output output-port
Each of these procedures invokes the respective operation on output-port. For example, the following are equivalent:

(output-port/write-char output-port char)
((output-port/operation/write-char output-port) output-port char)

The following custom operations are generally useful.

operation+: output port x-size output-port
Returns an exact positive integer that is the width of output-port in characters. If output-port has no natural width, e.g. if it is a file port, #f is returned.

operation+: output port y-size output-port
Returns an exact positive integer that is the height of output-port in characters. If output-port has no natural height, e.g. if it is a file port, #f is returned.

procedure+: output-port/x-size output-port
This procedure invokes the custom operation whose name is the symbol x-size, if it exists. If the x-size operation is both defined and returns a value other than #f, that value is returned as the result of this procedure. Otherwise, output-port/x-size returns a default value (currently 79).

output-port/x-size is useful for programs that tailor their output to the width of the display (a fairly common practice). If the output device is not a display, such programs normally want some reasonable default width to work with, and this procedure provides exactly that.

procedure+: output-port/y-size output-port
This procedure invokes the custom operation whose name is the symbol y-size, if it exists. If the y-size operation is defined, the value it returns is returned as the result of this procedure; otherwise, #f is returned.


Go to the first, previous, next, last section, table of contents.