192: Port Positioning

by The R6RS editors; John Cowan (shepherd); Shiro Kawai (implementation; requires a hook)

Status

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

Abstract

This is an extract from the R6RS that documents its support for positioning ports. Binary ports can be positioned to read or write at a specific byte; textual ports at a specific character, although character positions can't be synthesized portably. It has been lightly edited to fit R7RS style.

Rationale

The procedures documented in this SRFI allow reading bytes or characters from a port, especially a port associated with a file, in arbitrary order. By setting the port position before reading or writing, it is possible to jump to the nth record in a flat file of fixed-length records, or to rewind a file and process it repeatedly, or to discover the length of a file, or to append to it (though in the presence of multiple writers, this technique for appending is not reliable). While these abilities are not as important as they once were, they still have their uses.

Note that transcoded ports do not always support the port-position and set-port-position! operations. The position of a transcoded port may not be well-defined, and may be hard to calculate even when defined, especially when transcoding operations are done in bulk.

Similarly, although custom ports have provisions for supporting port positioning, it is not appropriate for all custom ports to do so.

Specification

(port-has-port-position? port)
(port-position port)

The port-has-port-position? procedure returns #t if the port supports the port-position operation, and #f otherwise. If the port does not support the operation, port-position signals an error.

The port-position procedure returns some implementation-dependent object representing as much of the state of the port at its current position as is necessary to save and restore that position. This is at a minimum the position itself. This value may be useful only as the pos argument to set-port-position!, if the latter is even supported on the port (see below). However, if the port is binary and the object is an exact integer, then it is the position measured in bytes, and can be used to compute a new position some specified number of bytes away.

(port-has-set-port-position!? port)
(set-port-position! port pos)

For a textual port, it is implementation-defined what happens if pos is not the return value of a call to port-position on port. However, a binary port will also accept an exact integer, in which case the port position is set to the specified number of bytes from the beginning of the port data. If this is not sufficient information to specify the port state, or the specified position is uninterpretable by the port, an error satisfying i/o-invalid-position-error? is signaled.

The port-has-set-port-position!? procedure returns #t if the port supports the set-port-position! operation, and #f otherwise.

If set-port-position! procedure is invoked on a port that does not support the operation or if pos is not in the range of valid positions of port, set-port-position! signals an error. Otherwise, it sets the current position of the port to pos. If port is an output port, set-port-position! first flushes port (even if the port position will not change).

If port is a binary output port and the current position is set beyond the current end of the data in the underlying data sink, the object is not extended until new data is written at that position. The contents of any intervening positions are unspecified. It is also possible to set the position of a binary input port beyond the end of the data in the data source, but a read will fail unless the data has been extended by other means. File ports can always be extended in this manner within the limits of the underlying operating system. In other types of ports, if an attempt is made to set the position beyond the current end of data in the underlying object, and the object does not support extension, an error satisfying i/o-invalid-position-error? is signaled.

(make-i/o-invalid-position-error pos)

Returns a condition object which satisfies i/o-invalid-position-error?. The pos argument represents a position passed to set-position!.

(i/o-invalid-position-error? obj)

Returns #t if obj is an object created by make-i/o-invalid-position-error? or an object raised in the circumstances described in this SRFI, or #f if it is not.

Implementation

Every conforming R6RS implementation, including at least Chez, Guile, IronScheme, Larceny, Racket, and Vicare, provides these procedures in the (rnrs io ports) library. R6RS binary ports always return the port position as an exact integer.

There is a sample implementation for R7RS that depends on overriding the built-in port procedures. It illustrates both SRFI 181 and SRFI 192, and it can be found in the Git repository for SRFI 192.

There is also a second sample implementation for Gauche using its native facilities, though it is incomplete.

Acknowledgements

This would have been much more difficult without the R6RS team, who produced a good-enough (as opposed to perfect) design that John was happy to adopt.

Copyright

Much of the content of this SRFI is drawn from R6RS, which does not have a copyright notice. It does, however, contain the following copyright license:

We intend this report to belong to the entire Scheme community, and so we grant permission to copy it in whole or in part without fee.

For the remaining content, the standard SRFI license applies:

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 (including the next paragraph) shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Editor: Arthur A. Gleckler