Oberon || Library || Module Index || Search Engine || Definition || Module


Ulm's Oberon Library:
CrPipes


NAME

CrPipes - coroutine pipes

SYNOPSIS

TYPE Filter = PROCEDURE (in, out: Streams.Stream);
TYPE CrPipe = POINTER TO CrPipeRec;
TYPE CrPipeRec = RECORD (Streams.StreamRec) END;

PROCEDURE Open(VAR out, in: Streams.Stream; bufmode: Streams.BufMode);
PROCEDURE Spawn(filter: Filter; in, out: Streams.Stream);

DESCRIPTION

CrPipes realizes pipelines of arbitrary length on a coroutine base. Each coroutine is represented by a filter. A filter is defined to be a procedure which reads from an input stream, does some processing, and writes to an output stream. The streams are of type CrPipe inside the pipeline and may be of any stream type at the two ends of the pipeline.

Open creates a pipeline with two streams (similar to pipe(2)). Both streams remain unconnected until they are connected to filters by Spawn. Input/output operations to unconnected pipeline streams are illegal. Transfer of control mainly depends on the buffering mode of the inner streams:

Streams.onebuf
is useful for byte-oriented filters, else every Streams.ReadByte or Streams.WriteByte would cause a CRSWITCH-operation.
Streams.nobuf
is useful for record-oriented filters, especially if the calculation of a record needs a long time and not all records are needed, e.g. backtracking algorithms
Streams.linebuf
should be taken if line oriented output to a terminal device is filtered.
out is opened for writing and in for reading. Streams.Seek and Streams.Tell are illegal for CrPipe streams.

Spawn passes in and out to filter and starts the procedure as coroutine. At least one of the two streams should be a pipeline stream. Pipeline streams which are passed to Spawn are connected to filter. Pipeline constructions must be linear: cycles would cause deadlocks.

The pipeline starts working either by reading from the end or by writing to the start of the pipeline. A filter has three ways of returning/closing:

(1)
calling Streams.Close(out). If out is a pipe this is an operation of no return; (2) can be used instead of (1) to be sure about returning.
(2)
executing RETURN; this causes out and in to be closed automatically if they are of type CrPipe.
(3)
implicitly if the consumer calls Streams.Close.

EXAMPLE

The example following causes any output written to Streams.stdout to be filtered by UpperToLower.
PROCEDURE UpperToLower(in, out: Streams.Stream);
   CONST diff = ORD("a") - ORD("A");
   VAR ch: CHAR;
BEGIN
   WHILE Streams.ReadByte(in, ch) DO
      IF (ch >= "A") & (ch <= "Z") THEN
         ch := CHR(ORD(ch) - diff);
      END;
      IF ~Streams.WriteByte(out, ch) THEN
         RETURN
      END;
   END;
END UpperToLower;

PROCEDURE Setup;
   VAR
      out, in: Streams.Stream;
      oldstdout: Streams.Stream;
BEGIN
   CrPipes.Open(out, in, Streams.linebuf);
   oldstdout := Streams.stdout;
   Streams.stdout := out;
   CrPipes.Spawn(UpperToLower, in, oldstdout);
END Setup;

SEE ALSO

Coroutines
global variables Coroutines.current and Coroutines.source
Streams
stream operations

Edited by: borchert, last change: 1999/04/15, revision: 1.4, converted to HTML: 1999/04/15

Oberon || Library || Module Index || Search Engine || Definition || Module