In-memory Streams

## 10.3 In-memory Streams

- String Streams
- Queue streams

There are two kinds of in-memory streams, string streams and queues. String streams behave much like files, they can be read, written, positioned etc, but they are implemented as buffer in memory. Queues are intended mainly for message-passing-style communication between ECLiPSeand a host language, and they are also implemented as memory buffers.

### 10.3.1 String Streams

In ECLiPSe it is possible to associate a stream with a Prolog string in its memory, and this string is then used in the same way as a file for the input and output operations. A string stream is opened like a file by the open/3 predicate call

>     open(string(InitString), Mode, Stream)

where InitString can be a ECLiPSe string or a variable and represents the initial contents of the string stream. If a variable is supplied for InitString, the initial value of the string stream is the empty string and the variable is bound to this value:

>     [eclipse 1]: open(string(S), update, s).
>     S = ""
>     yes.

Once a string stream is opened, all predicates using streams can take it as argument and perform I/O on it. In particular the predicates seek/2 and at/2 can be used with them.
While writing into a stream changes the stream contents destructively, the initial string that has been opened will never be affected. The new stream contents can be retrieved either by reading from the string stream, or as a whole by using get_stream_info/3:

>     [eclipse 1]: S = "abcdef", open(string(S), write, s), write(s, ---).

>     S = "abcdef"
>     yes.
>     [eclipse 2]: get_stream_info(s, name, S).

>     S = "---def"
>     yes.
>     [eclipse 3]: seek(s, 1), write(s, .), get_stream_info(s, name, S).

>     S = "-.-def"
>     yes.
>     [eclipse 4]: seek(s, end_of_file), write(s, ine),
>                  get_stream_info(s, name, S).

>     S = "-.-define"
>     yes.

### 10.3.2 Queue streams

A queue stream is opened by the open/3 predicate

>     open(queue(InitString), Mode, Stream)

The initial queue contents is InitString. It can be seen as a string which gets extended at its end on writing and consumed at its beginning on reading.

>     [eclipse 11]: open(queue(""), update, q), write(q, hello), write(q, " wo").
>     yes.
>     [eclipse 12]: read_string(q, " ", _, X).
>     S = "hello"
>     yes.
>     [eclipse 13]: write(q, "rld"), read(q, X).
>     S = world
>     yes.
>     [eclipse 14]: at_eof(q).
>     yes.

It is not allowed to seek on a queue. Therefore, once something is read from a queue, it is no longer accessible. A queue is considered to be at its end-of-file position when it is currently empty, however this is no longer the case when the queue is written again.
A useful feature of queues is that they can raise a synchronous event when data arrives on the empty queue. To create such an event-raising queue, this has to be specified as an option when opening the queue with open/4. In the example we have chosen the same name for the stream and for the event, which is not necessary but convenient when the same handler is going to be used for different queues:

>     [eclipse 1]: [user].
>      handle_queue_event(Q) :-
>             read_string(Q, "", _, Data),
>             printf("Queue %s received data: %s\n", [Q,Data]).
>     yes.
>     [eclipse 2]: set_event_handler(eventq, handle_queue_event/1).
>     yes.
>     [eclipse 3]: open(queue(""), update, eventq, [event(eventq)]).
>     yes.
>     [eclipse 4]: write(eventq, hello).
>     Queue eventq received data: hello
>     yes.