1(*	$Id: IO.Mod,v 1.15 2004/11/21 20:31:50 mva Exp $	*)
2MODULE IO;
3(*  Defines common behaviour of I/O channel and selector.
4    Copyright (C) 2003, 2004  Michael van Acken
5
6    This module is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public License
8    as published by the Free Software Foundation; either version 2 of
9    the License, or (at your option) any later version.
10
11    This module is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with OOC. If not, write to the Free Software Foundation,
18    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19*)
20
21(**
22
23   This set of modules defines a set of input/output abstractions for files,
24   sockets, pipes, and so on.  The modules are not related to the library
25   modules @omodule{*Channel}, @omodule{*Files}, and derivates.  Their goals
26   are quite different:
27
28   @itemize @bullet
29   @item
30   Provide an thin and efficient layer on top of the operation system's I/O
31   features.
32   @item
33   Use exceptions to propagate errors to the application that are reported by
34   the C library.
35   @item
36   Provide an abstraction for I/O multiplexing that allows to use different
37   mechanisms besides @code{select()}.
38   @item
39   The level of abstraction should be high-level enough to care for slighty
40   different I/O primitives, most notably under Windows.
41   @end itemize
42
43   The roots of the interface are partially the Java IO package, Python, and
44   the Oberon-2 standard I/O modules.  Eventually, the modules will replace the
45   @samp{IO:*} inherited from the old @samp{libxml} package.  *)
46
47IMPORT
48  SYSTEM, Object, Exception, C;
49
50TYPE
51  Channel* = POINTER TO ChannelDesc;
52  SelectionKey* = POINTER TO SelectionKeyDesc;
53  SelectionKeyList = POINTER TO ARRAY OF SelectionKey;
54  ChannelDesc* = RECORD [ABSTRACT]
55  (**A channel is a means by which a program can perform I/O operations.
56     Examples for channels are @otype{*IO:FileChannel.Channel},
57     @otype{*IO:SocketChannel.Channel}, and
58     @otype{*IO:SocketChannel.ServerChannel}.  *)
59    readyOps*: SET;
60    (* Set of operations that can be performed on the channel without blocking.
61       Valid elements are @oconst{opRead}, @oconst{opWrite}, @oconst{opAccept},
62       and @oconst{opConnect}.
63
64       This field is used in conjunction with a @oproc{Selector}.  It should
65       only be modified by I/O operations of extensions of @otype{Channel}.  *)
66
67    keys: SelectionKeyList;
68    (* List of selection keys for each selector for which this channel has
69       been registered.  The last entry is followed by NIL.  *)
70  END;
71
72TYPE
73  ByteChannel* = POINTER TO ByteChannelDesc;
74  ByteChannelDesc* = RECORD [ABSTRACT]
75    (ChannelDesc)
76    (**Common base type of channels supporting the @oproc{ByteChannel.Read} and
77       @oproc{ByteChannel.Write} methods.  *)
78  END;
79
80TYPE
81  Selector* = POINTER TO SelectorDesc;
82  SelectorDesc* = RECORD [ABSTRACT]
83  (**A mechanism to discover channels that are ready for I/O operations.  For
84     example, a selector can be used to find out for which channels input
85     data is available.
86
87     Note: The definition of this class covers both selectors that report the
88     current state of a channel, and those that only report an event if a
89     channel becomes ready.  @oproc{Selector.Select} only adds new ready flags,
90     but never clears them.  I/O operations like @oproc{ByteChannel.Read},
91     @oproc{ByteChannel.Write}, @oproc{*SocketChannel.Channel.Connect}, and
92     @oproc{*SocketChannel.ServerChannel.Accept} clear the corresponding flag
93     if the channel is in non-blocking mode and they get an @samp{EWOULDBLOCK}
94     error from the libc function.  *)
95    (Object.ObjectDesc)
96    keys-: SelectionKey;
97    (**A list of selection keys registered for this selector.  The keys are
98       linked via @ofield{SelectionKey.nextKey}.  *)
99    cancel: BOOLEAN;
100  END;
101
102TYPE
103  FileDescriptor* = C.int;
104  SelectionKeyDesc* = RECORD
105  (**Association between a @otype{Channel} and @otype{Selector}.  *)
106    (Object.ObjectDesc)
107    fd-: FileDescriptor;
108    interestOps-: SET;
109    attachment-: Object.Object;
110    selector-: Selector;
111    channel-: Channel;
112
113    nextKey-: SelectionKey;
114    cancel: BOOLEAN;
115  END;
116
117CONST
118  opRead* = 0;
119  (**Used to signal interest in new input data, or to indicate that some
120     input data has become available for processing.  *)
121  opWrite* = 1;
122  (**Used to signal interest to produce output on a channel, or to indicate
123     that there is room for more data to be passed to the operating system.  *)
124  opAccept* = 2;
125  (**Used to signal interest in connection requests, or to indicate that there
126     are pending requests.  *)
127  opConnect* = 3;
128  (**Used to signal interest in completion of a currently pending connection
129     attempt, or to indicate that a pending connect has been completed.  *)
130
131TYPE
132  Error* = POINTER TO ErrorDesc;
133  ErrorDesc* = RECORD
134  (**Base class of all I/O exceptions raised by channel implementations.  *)
135    (Exception.CheckedDesc)
136  END;
137  FileNotFound* = POINTER TO FileNotFoundDesc;
138  FileNotFoundDesc = RECORD
139  (**This exception is raised if a C function returns a @samp{ENOENT} error. *)
140    (ErrorDesc)
141  END;
142  AccessDenied* = POINTER TO AccessDeniedDesc;
143  AccessDeniedDesc = RECORD
144  (**This exception is raised if a C function returns a @samp{EACCES} error. *)
145    (ErrorDesc)
146  END;
147  FileExists* = POINTER TO FileExistsDesc;
148  FileExistsDesc = RECORD
149  (**This exception is raised if a C function returns a @samp{EEXIST} error. *)
150    (ErrorDesc)
151  END;
152  FileBusy* = POINTER TO FileBusyDesc;
153  FileBusyDesc = RECORD
154  (**This exception is raised if a C function returns a @samp{EBUSY} error. *)
155    (ErrorDesc)
156  END;
157  InvalidArgument* = POINTER TO InvalidArgumentDesc;
158  InvalidArgumentDesc = RECORD
159  (**This exception is raised if a C function returns a @samp{EINVAL} error. *)
160    (ErrorDesc)
161  END;
162  OutOfRange* = POINTER TO OutOfRangeDesc;
163  OutOfRangeDesc = RECORD
164  (**This exception is raised if a C function returns a @samp{ERANGE} error. *)
165    (ErrorDesc)
166  END;
167
168TYPE
169  NotImplemented* = POINTER TO NotImplementedDesc;
170  NotImplementedDesc = RECORD
171  (**Raised when a method is called that is not implemented for a particular
172     channel.  Note: This should be moved into module @omodule{Exception} and
173     marked as an unchecked exception.  *)
174    (ErrorDesc)
175  END;
176  FormatError* = POINTER TO FormatErrorDesc;
177  FormatErrorDesc = RECORD
178  (**Raised if input data does not satisfy the expected format.  For example,
179     because the required number of bytes cannot be read from the channel,
180     or because the data is syntactically wrong.  *)
181    (ErrorDesc)
182  END;
183  ProtocolError* = POINTER TO ProtocolErrorDesc;
184  ProtocolErrorDesc* = RECORD
185  (**Raised if malformed data is received from the remote side of a
186     conversation.  This is @emph{not} used for responses that indicate failure
187     to process a request.  An example for a protocol error is an NNTP response
188     message that does not begin with a three digit status code.  After such an
189     error, the connection should be closed immediately.  *)
190    (ErrorDesc)
191  END;
192  ErrorResponse* = POINTER TO ErrorResponseDesc;
193  ErrorResponseDesc* = RECORD
194  (**Raised if the remote side of a conversation sends a reply with an error
195     status code.  *)
196    (ErrorDesc)
197  END;
198
199
200PROCEDURE (e: Error) INIT*(msg: STRING);
201  BEGIN
202    e.INIT^(msg);
203  END INIT;
204
205PROCEDURE NewFormatError*(msg: STRING): FormatError;
206  BEGIN
207    RETURN NEW(FormatError, msg);
208  END NewFormatError;
209
210PROCEDURE RaiseFormatError*(msg: STRING)
211RAISES FormatError;
212  BEGIN
213    RAISE(NewFormatError(msg));
214  END RaiseFormatError;
215
216PROCEDURE RaiseNotImplemented*()
217RAISES NotImplemented;
218  BEGIN
219    RAISE(NEW(NotImplemented, NIL));
220  END RaiseNotImplemented;
221
222PROCEDURE (k: SelectionKey) INIT*(fd: FileDescriptor;
223                                  selector: Selector; channel: Channel;
224                                  ops: SET; attachment: Object.Object);
225  BEGIN
226    k.fd := fd;
227    k.interestOps := ops;
228    k.attachment := attachment;
229    k.selector := selector;
230    k.channel := channel;
231    k.cancel := FALSE;
232  END INIT;
233
234PROCEDURE (k: SelectionKey) Attach*(obj: Object.Object);
235(**Set @ofield{k.attachment} to @oparam{obj}.  *)
236  BEGIN
237    k.attachment := obj;
238  END Attach;
239
240PROCEDURE (k: SelectionKey) Cancel*;
241(**Mark key @oparam{k} as canceled.  The key is immediately eliminated from the
242   channels's list of keys.  It is removed from the selector's key list with
243   the next call to @oproc{Selector.Select}.  Closing a channel cancels all its
244   selection keys.  *)
245  BEGIN
246    IF ~k.cancel THEN
247      k.cancel := TRUE;
248      k.selector.cancel := TRUE;
249    END;
250  END Cancel;
251
252PROCEDURE (k: SelectionKey) SetInterestOps*(ops: SET);
253(**Set @ofield{k.interestOps} to @oparam{ops}.  *)
254  BEGIN
255    k.interestOps := ops;
256  END SetInterestOps;
257
258
259PROCEDURE (s: Selector) INIT*();
260  BEGIN
261    s.keys := NIL;
262    s.cancel := FALSE;
263  END INIT;
264
265PROCEDURE (s: Selector) Close*();
266(**Cancel all selection keys registered for the selector @oparam{s} and close
267   the selector.  *)
268  VAR
269    k: SelectionKey;
270  BEGIN
271    k := s.keys;
272    WHILE (k # NIL) DO
273      k.Cancel();
274      k := k.nextKey;
275    END;
276    s.keys := NIL;
277  END Close;
278
279PROCEDURE (s: Selector) [ABSTRACT] Select*(sec, usec: LONGINT): LONGINT
280RAISES Error;
281(**Determine if operations on registered channels are ready.  The function
282   returns the number of channels with a non-empty ready set.  Result is
283   @samp{0} if no channels are ready or have become ready until the time the
284   specified timeout expires.  If this function is called with a channel
285   already being ready, then it behaves as if a timeout of zero had been
286   requested.
287
288   After a call to @oproc{Selector.Select}, the method @oproc{Selector.NextKey}
289   iterates over all ready channels.  *)
290  END Select;
291
292PROCEDURE (s: Selector) [ABSTRACT] NextKey*(): SelectionKey;
293(**Return the next selection key of selector @oparam{s} with a non-empty
294   intersection of @ofield{SelectionKey.interestOps} and
295   @ofield{Channel.readyOps}.  Result is @code{NIL} if no such channel exists.  *)
296  END NextKey;
297
298PROCEDURE (s: Selector) [ABSTRACT] AddSelectionKey*(fd: FileDescriptor;
299                                                    channel: Channel;
300                                                    ops: SET;
301                                                    attachment: Object.Object): SelectionKey;
302(**Private method of the selector.  Create and initialize a selection key.
303   The caller is responsible for adding the key to the selector.  *)
304  END AddSelectionKey;
305
306PROCEDURE (s: Selector) [ABSTRACT] RemoveSelectionKey*(k: SelectionKey);
307(**Private method of the selector.  Do any bookkeeping require to eliminate the
308   selection key.  The caller is responsible for removing the key from the
309   selector's list of keys.  *)
310  END RemoveSelectionKey;
311
312PROCEDURE (s: Selector) RemoveCanceled*();
313(**Removes all keys that have been marked as ``canceled'' from the selector.
314   This is a private method, and should only be called from
315   @oproc{Selector.Select}.  *)
316  VAR
317    prev, k: SelectionKey;
318  BEGIN
319    IF s.cancel THEN
320      prev := NIL;
321      k := s.keys;
322      WHILE (k # NIL) DO
323        IF k.cancel THEN
324          s.RemoveSelectionKey(k);
325          IF (prev = NIL) THEN
326            s.keys := k.nextKey;
327          ELSE
328            prev.nextKey := k.nextKey;
329          END;
330        ELSE
331          prev := k;
332        END;
333        k := k.nextKey;
334      END;
335    END;
336  END RemoveCanceled;
337
338
339PROCEDURE (ch: Channel) INIT*();
340  BEGIN
341    ch.readyOps := {};
342    NEW(ch.keys, 2);
343    ch.keys[0] := NIL;
344  END INIT;
345
346PROCEDURE (ch: Channel) [ABSTRACT] FileDescriptor*(): FileDescriptor;
347(**Return the file descriptor of the channel.  This is the integer number
348   that is used to identify the channel on the level of the C library.
349   If the channel is not associated with a file descriptor, result is
350   @samp{-1}.  *)
351  END FileDescriptor;
352
353PROCEDURE (ch: Channel) RegisterWithSelector*(sel: Selector;
354                                              ops: SET;
355                                              attachment: Object.Object): SelectionKey;
356(**Register the channel @oparam{ch} with the selector @oparam{sel}.  If such a
357   registration already exists, then return the old selection key.  Otherwise,
358   create a new key with an interest set @oparam{ops} and attachment
359   @oparam{attachment} and return it.  *)
360  VAR
361    k: SelectionKey;
362    n: SelectionKeyList;
363    i, j: LONGINT;
364  BEGIN
365    i := 0;
366    WHILE (ch.keys[i] # NIL) DO
367      IF (ch.keys[i].selector = sel) THEN (* key already exists: return it *)
368        RETURN ch.keys[i];
369      END;
370      INC(i);
371    END;
372    IF (i+1 = LEN(ch.keys^)) THEN
373      NEW(n, LEN(ch.keys^)*2);
374      FOR j := 0 TO i DO
375        n[i] := ch.keys[i];
376      END;
377      ch.keys := n;
378    END;
379    ch.keys[i+1] := NIL;
380    k := sel.AddSelectionKey(ch.FileDescriptor(), ch, ops, attachment);
381    ch.keys[i] := k;
382    RETURN k;
383  END RegisterWithSelector;
384
385PROCEDURE (ch: Channel) KeyForSelector*(sel: Selector): SelectionKey;
386(**Return selection key of @oparam{ch} for selector @oparam{sel}.  Result is
387   @code{NIL} if the channel is not registered with the selector.  *)
388
389  VAR
390    i: LONGINT;
391  BEGIN
392    i := 0;
393    WHILE (ch.keys[i] # NIL) & (ch.keys[i].selector # sel) DO
394      INC(i);
395    END;
396    RETURN ch.keys[i];
397  END KeyForSelector;
398
399PROCEDURE (ch: Channel) [ABSTRACT] SetBlocking*(block: BOOLEAN)
400RAISES Error;
401(**Change the channel's blocking mode.  Channels typically default to
402   blocking mode on creation.
403
404   If a channel does not support non-blocking operation, then any call to this
405   method is ignored.  Rider implementations from @omodule{*IO:BinaryRider} and
406   @omodule{*IO:TextRider} only work with blocking channels.  *)
407  END SetBlocking;
408
409PROCEDURE (ch: Channel) Close*()
410RAISES Error;
411(**Cancel all selection keys registered for the channel @oparam{ch} and close
412   the channel.  *)
413  VAR
414    i: LONGINT;
415  BEGIN
416    i := 0;
417    WHILE (ch.keys[i] # NIL) DO
418      ch.keys[i].Cancel();
419      INC(i);
420    END;
421  END Close;
422
423PROCEDURE (ch: Channel) CloseAndRegister*()
424RAISES Error;
425(**Like @oproc{Channel.Close}, but register the channel's target with its
426   naming service once done.  Right now, only @omodule{*IO:FileChannel}
427   supports this feature; see @oconst{*IO:FileChannel.tmpFile} for details.
428   By default, this method simply calls @oproc{Channel.Close}.  *)
429  BEGIN
430    ch.Close();
431  END CloseAndRegister;
432
433PROCEDURE (ch: ByteChannel) INIT*();
434  BEGIN
435    ch.INIT^();
436  END INIT;
437
438PROCEDURE (ch: Channel) SetPos*(pos: LONGINT)
439RAISES Error;
440(**Change the channels position to @oparam{pos}.  *)
441  BEGIN
442    RaiseNotImplemented();
443  END SetPos;
444
445PROCEDURE (ch: ByteChannel) [ABSTRACT] Read*(VAR buffer: ARRAY OF SYSTEM.BYTE;
446                                             start, length: LONGINT): LONGINT
447RAISES Error;
448(**Read a sequence of bytes from the channel into the buffer.
449
450   An attempt is made to read up to @oparam{length} bytes from the channel.
451   The bytes are written to @oparam{buffer}, starting at position
452   @oparam{start}.  Result is the number of bytes actually read, or @samp{-1}
453   if the read position is at the end of the channel, and @oparam{length}
454   is not zero.
455
456   A read operation might not read @oparam{length} bytes, and in fact it might
457   not read any bytes at all.  Whether or not it does so depends upon the
458   nature and state of the channel.  A socket channel in non-blocking mode, for
459   example, cannot read any more bytes than are immediately available from the
460   socket's input buffer; similarly, a file channel cannot read any more bytes
461   than remain in the file.  It is guaranteed, however, that if a channel is in
462   blocking mode and there is at least one byte remaining in the buffer then
463   this method will block until at least one byte is read.
464
465   @precond
466   @samp{0 <= @oparam{start} <= @oparam{start}+@oparam{length} <=
467   LEN(@oparam{buffer})} and @samp{@oparam{length} >= 0}.
468   @end precond  *)
469  END Read;
470
471PROCEDURE (ch: ByteChannel) [ABSTRACT] Write*(buffer[NO_COPY]: ARRAY OF SYSTEM.BYTE;
472                                              start, length: LONGINT): LONGINT
473RAISES Error;
474(**Write a sequence of bytes to this channel from the buffer.
475
476   An attempt is made to write up to @oparam{length} bytes to the channel.  The
477   bytes are taken from @oparam{buffer}, beginning at position @oparam{start}.
478
479   A write operation can return after writing less than @oparam{length} bytes.
480   That is, some types of channels, depending upon their state, may write only
481   some of the bytes or possibly none at all.  A socket channel in non-blocking
482   mode, for example, cannot write any more bytes than are free in the socket's
483   output buffer.  Result is the number of bytes actually written.
484
485   @precond
486   @samp{0 <= @oparam{start} <= @oparam{start}+@oparam{length} <=
487   LEN(@oparam{buffer})} and @samp{@oparam{length} >= 0}.
488   @end precond  *)
489  END Write;
490
491PROCEDURE (ch: ByteChannel) Flush*()
492RAISES Error;
493(**Flush all buffers associated with channel @oparam{ch}.  *)
494  END Flush;
495
496PROCEDURE (ch: ByteChannel) TransferTo*(length: LONGINT;
497                                        target: ByteChannel): LONGINT
498RAISES Error;
499(**Transfer upto @oparam{length} bytes from channel @oparam{ch} to
500   @oparam{target}.  Result is the number of bytes actually copied.  *)
501  CONST
502    sizeBuffer = 8*1024;
503  VAR
504    buffer: ARRAY sizeBuffer OF SYSTEM.BYTE;
505    i, j, rd, wd: LONGINT;
506  BEGIN
507    i := 0;
508    WHILE (i # length) DO
509      rd := ch.Read(buffer, 0, sizeBuffer);
510      IF (rd = -1) THEN                   (* end of channel *)
511        RETURN i;
512      ELSE
513        j := 0;
514        WHILE (j # rd) DO
515          wd := target.Write(buffer, j, rd-j);
516          IF (wd = -1) THEN
517            RETURN i+j;
518          ELSE
519            INC(j, wd);
520          END;
521        END;
522        INC(i, rd);
523      END;
524    END;
525    RETURN i;
526  END TransferTo;
527
528END IO.
529