# Gray streams

## Overview

This interface permits the definition of new classes of streams, and programming their behavior by defining methods for the elementary stream operations. It is based on the proposal &gray-streams; of David N. Gray to X3J13 and is supported by most &cl; implementations currently in use.

All symbols defined by this interface, starting with the prefix `FUNDAMENTAL-` or `STREAM-`, are exported from the package &gray-pac; and &re-export;ed from &ext-pac;.

Defined classes

&fu-st;

  This is a superclass of all user-defined streams. It is a subclass of &stream-t; and of &standard-object-t;. Its metaclass is &standard-class;.

&fu-st-in;

  This is a superclass of all user-defined &in-s;s. It is a subclass of &fu-st;. The built-in function &input-stream-p; returns true on instances of this class. This means that when you define a new stream class capable of doing input, you have to make it a subclass of &fu-st-in;.

&fu-st-out;

  This is a superclass of all user-defined &out-s;s. It is a subclass of &fu-st;. The built-in function &output-stream-p; returns true on instances of this class. This means that when you define a new stream class capable of doing output, you have to make it a subclass of &fu-st-out;.

&fu-st-char;

  This is a superclass of all user-defined streams whose &stream-element-type; is &character-t;. It is a subclass of &fu-st;. It defines a method on &stream-element-type; that returns &character-t;.

&fu-st-bin;

  This is a superclass of all user-defined streams whose &stream-element-type; is a subtype of &integer-t;. It is a subclass of &fu-st;. When you define a subclass of &fu-st-bin;, you have to provide a method on &stream-element-type;.

GRAY:FUNDAMENTAL-CHARACTER-INPUT-STREAM

  This is a convenience class inheriting from both &fu-st-char; and &fu-st-in;.

GRAY:FUNDAMENTAL-CHARACTER-OUTPUT-STREAM

  This is a convenience class inheriting from both &fu-st-char; and &fu-st-out;.

GRAY:FUNDAMENTAL-BINARY-INPUT-STREAM

  This is a convenience class inheriting from both &fu-st-bin; and &fu-st-in;.

GRAY:FUNDAMENTAL-BINARY-OUTPUT-STREAM

  This is a convenience class inheriting from both &fu-st-bin; and &fu-st-out;.

General generic functions defined on streams

`(&stream-element-type; &stream-r;)`

  Returns the stream's element type, normally a subtype of &character-t; or &integer-t;.

  The method for &fu-st-char; returns &character-t;.

`((&setf; &stream-element-type;) new-element-type &stream-r;)`

  Changes the stream's element type.

  The default method &signal;s an &error-t;.

  This function is a &clisp; extension (see ).

`(&close; &stream-r; &key-amp; &abort-k;)`

  Closes the stream and flushes any associated buffers.

  When you define a primary method on this function, do not forget to &call-next-method;.

`(&open-stream-p; &stream-r;)`

  Returns true before the stream has been closed, and &nil; after the stream has been closed.

  You do not need to add methods to this function.

`(`GRAY:STREAM-POSITION` &stream-r; position)`

  Just like &file-position;, but &nil; position means inquire.

  &need-defmethod;

generic functions for character input

`(&st-rc; &stream-r;)`

  If a character was pushed back using &st-uc;, returns and consumes it. Otherwise returns and consumes the next character from the stream. Returns &eof-k; if the &eos; is reached.

  &need-defmethod;
`(&st-uc; &stream-r; &ch-r;)`

  Pushes &ch-r;, which must be the last character read from the &stream-r;, back onto the front of the &stream-r;.

  &need-defmethod;
`(&st-rcnh; &stream-r;)`

  Returns a character or &eof-k;, like &st-rc;, if that would return immediately. If &st-rc;'s value is not available immediately, returns &nil; instead of waiting.

  The default method simply calls &st-rc;; this is sufficient for streams whose &st-rc; method never blocks.

`(`GRAY:STREAM-PEEK-CHAR` &stream-r;)`

  If a character was pushed back using &st-uc;, returns it. Otherwise returns the next character from the stream, avoiding any side effects &st-rc; would do. Returns &eof-k; if the &eos; is reached.

  The default method calls &st-rc; and &st-uc;; this is sufficient for streams whose &st-rc; method has no side-effects.

`(`GRAY:STREAM-LISTEN` &stream-r;)`

  If a character was pushed back using &st-uc;, returns it. Otherwise returns the next character from the stream, if already available. If no character is available immediately, or if &eos; is reached, returns &nil;.

  The default method calls &st-rcnh; and &st-uc;; this is sufficient for streams whose &st-rc; method has no side-effects.

`(`GRAY:STREAM-READ-CHAR-WILL-HANG-P` &stream-r;)`

  Returns &nil; if &st-rc; will return immediately. Otherwise it returns true.

  The default method calls &st-rcnh; and &st-uc;; this is sufficient for streams whose &st-rc; method has no side-effects.

  This function is a &clisp; extension (see &rcwhp;).

`(`GRAY:STREAM-READ-CHAR-SEQUENCE` &stream-r; &sequence-r; &optional-amp; [&start-r; [&end-r;]])`

  Fills the subsequence of &sequence-r; specified by &start-k; and &end-k; with characters consecutively read from &stream-r;. Returns the index of the first element of &sequence-r; that was not updated (&areq; &end-r;, or &lst; &end-r; if the stream reached its end).

  &sequence-r; is an &array-t; of &character-t;s, i.e. a &string-t;. &start-r; is a nonnegative &integer-t; and defaults to &zero;. &end-r; is a nonnegative &integer-t; or &nil; and defaults to &nil;, which stands for `(&length; &sequence-r;)`.

  The default method repeatedly calls &st-rc;; this is always sufficient if speed does not matter.

  This function is a &clisp; extension (see &rd-ch-seq;).

`(`GRAY:STREAM-READ-LINE` &stream-r;)`

  Reads a line of characters, and return two values: the line (a &string-t;, without the terminating &nl-s; character), and a &boolean-t; value which is true if the line was terminated by &eos; instead of &nl-s;.

  The default method repeatedly calls &st-rc;; this is always sufficient.

`(`GRAY:STREAM-CLEAR-INPUT` &stream-r;)`

  Clears all pending interactive input from the &stream-r;, and returns true if some pending input was removed.

  The default method does nothing and returns &nil;; this is sufficient for non-interactive streams.

generic functions for character output

`(&st-wc; &stream-r; &ch-r;)`

  Writes &ch-r;.

  &need-defmethod;
`(&st-lc; &stream-r;)`

  Returns the column number where the next character would be written (&zero; stands for the first column), or &nil; if that is not meaningful for this stream.

  &need-defmethod;
`(`GRAY:STREAM-START-LINE-P` &stream-r;)`

  Returns true if the next character would be written at the start of a new line.

  The default method calls &st-lc; and compares its result with 0; this is sufficient for streams whose &st-lc; never returns &nil;.

`(`GRAY:STREAM-WRITE-CHAR-SEQUENCE` &stream-r; &sequence-r; &optional-amp; [&start-r; [&end-r;]])`

  Outputs the subsequence of &sequence-r; specified by &start-k; and &end-k; to &stream-r;.

  &sequence-r; is an &array-t; of &character-t;s, i.e. a &string-t;. &start-r; is a nonnegative &integer-t; and defaults to 0. &end-r; is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; &sequence-r;)`.

  The default method repeatedly calls &st-wc;; this is always sufficient if speed does not matter.

  This function is a &clisp; extension (see &wr-ch-seq;).

`(`GRAY:STREAM-WRITE-STRING` &stream-r; &string-r; &optional-amp; [&start-r; [&end-r;]])`

  Outputs the subsequence of &string-r; specified by &start-k; and &end-k; to &stream-r;. Returns &string-r;.

  &string-r; is a string. &start-r; is a nonnegative integer and default to 0. &end-r; is a nonnegative integer or &nil; and defaults to &nil;, which stands for `(&length; &string-r;)`.

  The default method calls `GRAY:STREAM-WRITE-CHAR-SEQUENCE`; this is always sufficient.

`(`GRAY:STREAM-TERPRI` &stream-r;)`

  Outputs a &nl-s; character.

  The default method calls &st-wc;; this is always sufficient.

`(`GRAY:STREAM-FRESH-LINE` &stream-r;)`

  Possibly outputs a &nl-s; character, so as to ensure that the next character would be written at the start of a new line. Returns true if it did output a &nl-s; character.

  The default method calls `GRAY:STREAM-START-LINE-P` and then `GRAY:STREAM-TERPRI` if necessary; this is always sufficient.

`(`GRAY:STREAM-FINISH-OUTPUT` &stream-r;)`

  Ensures that any buffered output has reached its destination, and then returns.

  The default method does nothing.

`(`GRAY:STREAM-FORCE-OUTPUT` &stream-r;)`

  Brings any buffered output on its way towards its destination, and returns without waiting until it has reached its destination.

  The default method does nothing.

`(`GRAY:STREAM-CLEAR-OUTPUT` &stream-r;)`

  Attempts to discard any buffered output which has not yet reached its destination.

  The default method does nothing.

`(`GRAY:STREAM-ADVANCE-TO-COLUMN` &stream-r; &col-r;)`

  Ensures that the next character will be written at least at &col-r;.

  The default method outputs an appropriate amount of space characters; this is sufficient for non-proportional output.

generic functions for binary input

`(&st-rb; &stream-r;)`

  Returns and consumes the next integer from the stream. Returns &eof-k; if the &eos; is reached.

  &need-defmethod;
`(&st-rbla; &stream-r;)`

  To be called only if &stream-r;'s &stream-element-type; is &ubyte-8; or &sbyte-8;. Returns &t; if &st-rb; would return immediately with an &integer-t; result. Returns &eof-k; if the &eos; is already known to be reached. If &st-rb;'s value is not available immediately, returns &nil; instead of waiting.

  &need-defmethod;

  This function is a &clisp; extension (see &rbla;).

`(`GRAY:STREAM-READ-BYTE-WILL-HANG-P` &stream-r;)`

  To be called only if &stream-r;'s &stream-element-type; is &ubyte-8; or &sbyte-8;. Returns &nil; if &st-rb; will return immediately. Otherwise it returns true.

  The default method calls &st-rbla;; this is always sufficient.

  This function is a &clisp; extension (see &rbwhp;).

`(`GRAY:STREAM-READ-BYTE-NO-HANG` &stream-r;)`

  To be called only if &stream-r;'s &stream-element-type; is &ubyte-8; or &sbyte-8;. Returns an &integer-t; or &eof-k;, like &st-rb;, if that would return immediately. If &st-rb;'s value is not available immediately, returns &nil; instead of waiting.

  The default method calls &st-rb; if &st-rbla; returns true; this is always sufficient.

  This function is a &clisp; extension (see &rbnh;).

`(`GRAY:STREAM-READ-BYTE-SEQUENCE` &stream-r; &sequence-r; &optional-amp; [&start-r; [&end-r; [&no-hang; [&interactive-r;]]]])`

  Fills the subsequence of &sequence-r; specified by &start-k; and &end-k; with integers consecutively read from &stream-r;. Returns the index of the first element of &sequence-r; that was not updated (&areq; &end-r;, or &lst; &end-r; if the stream reached its end).

  &sequence-r; is an &array-t; of &integer-t;s. &start-r; is a nonnegative &integer-t; and defaults to 0. &end-r; is a nonnegative &integer-t; or &nil; and defaults to &nil;, which stands for `(&length; &sequence-r;)`. If &no-hang; is true, the function should avoid blocking and instead fill only as many elements as are immediately available. If &no-hang; is false and &interactive-r; is true, the function can block for reading the first byte but should avoid blocking for any further bytes.

  The default method repeatedly calls &st-rb;; this is always sufficient if speed does not matter.

  This function is a &clisp; extension (see &rd-by-seq;).

generic functions for binary output

`(`GRAY:STREAM-WRITE-BYTE` &stream-r; &int-r;)`

  Writes &int-r;.

  &need-defmethod;
`(`GRAY:STREAM-WRITE-BYTE-SEQUENCE` &stream-r; &sequence-r; &optional-amp; [&start-r; [&end-r; [&no-hang; [&interactive-r;]]]])`

  Outputs the subsequence of &sequence-r; specified by &start-k; and &end-k; to &stream-r;

  &sequence-r; is an &array-t; of &integer-t;s. &start-r; is a nonnegative &integer-t; and defaults to 0. &end-r; is a nonnegative &integer-t; or &nil; and defaults to &nil;, which stands for `(&length; &sequence-r;)`. If &no-hang; is true, the function should avoid blocking and instead output only as many elements as it can immediately proceed. If &no-hang; is false and &interactive-r; is true, the function can block for writing the first byte but should avoid blocking for any further bytes.

  The default method repeatedly calls `GRAY:STREAM-WRITE-BYTE`; this is always sufficient if speed does not matter.

  This function is a &clisp; extension (see &wr-by-seq;).

## Class &fill-stream;

As an example of the use of &gray-pac; &stream-t;s, &clisp; offers an additional class, &fill-stream;. An instance of this class is a formatting &stream-t;, which makes the final output to the underlying stream look neat: indented and filled. An instance of &fill-stream; is created like this:

    (&make-instance; '&fill-stream; :stream &stream-r;
                   [:text-indent symbol-or-number]
                   [:sexp-indent symbol-or-number-or-function])

where

&stream-r;

  is the target &stream-t; where the output actually goes.

symbol-or-number

  is the variable whose value is the &integer-t; text indentation or the indentation itself (defaults to 0).

symbol-or-number-or-function

  When &format; writes an S-expression to a &fill-stream; using &format-s;, and the expression's printed representation does not fit on the current line, it is printed on separate lines, ignoring the prescribed text indentation and preserving spacing. When this argument is non-&nil;, the S-expression &is-e; indented by:

  &t;

    the text indentation above;

  &symbol-t;

    &symbol-value; is the indentation;

  &integer-t;

    the indentation itself;

  &function-t;

    called with one argument, the text indentation, and the value is used as S-expression indentation; thus &identity; is equivalent to &t; above.

  Defaults to &fill-indent-sexp;, whose initial value is &pl1;.

Note that, due to buffering, one must call &force-output; when done with the &fill-stream; (and before changing the indent variable). The former is done automatically by the macro `(with-fill-stream (fill target-stream ...) ...)`.

Example of &fill-stream; usage

    (defvar *my-indent-level*)
    (with-output-to-string (out)
      (let ((*print-right-margin* 20)
            (*print-pretty* t)
            (*my-indent-level* 2))
        (with-fill-stream (fill out :text-indent '*my-indent-level*)
          (format fill "~%this is some long sentence which will      be broken at spaces")
          (force-output fill)
          (let ((*my-indent-level* 5))
            (format fill "~%and    properly indented to the level specified by the ~S argument which can be a ~S or an ~S - cool!"
                    :TEXT-INDENT 'symbol 'integer))
          (format fill "~%Don't forget  to call ~S on it, and/or use ~S   Pretty formatting of the  S-expressions    printed with ~~S is  preserved: ~S"
                  'force-output 'with-fill-stream '(defun foo (x y z) (if x (+ y z) (* y z)))))))
    "
      this is some long
      sentence which
      will be broken at
      spaces
         and properly
         indented to
         the level
         specified by
         the :TEXT-INDENT
         argument which
         can be a
    SYMBOL
         or an INTEGER
         - cool!
      Don't forget to
      call FORCE-OUTPUT
      on it, and/or use
    WITH-FILL-STREAM
      Pretty formatting
      of the
      S-expressions
      printed with ~S
      is preserved:
    (DEFUN FOO (X Y Z)
     (IF X (+ Y Z)
      (* Y Z)))
    "