File: PosixFileDescr.Mod

package info (click to toggle)
oo2c32 1.5.0-1
  • links: PTS
  • area: main
  • in suites: potato
  • size: 8,748 kB
  • ctags: 5,415
  • sloc: ansic: 95,007; sh: 473; makefile: 344; perl: 57; lisp: 21
file content (304 lines) | stat: -rw-r--r-- 13,944 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
(*	$Id: PosixFileDescr.Mod,v 1.10 1999/10/31 13:58:05 ooc-devel Exp $	*)
MODULE PosixFileDescr [FOREIGN "C"; LINK FILE "PosixFileDescr.c" END];
(*  Generalized access to POSIX-style file descriptors.
    Copyright (C) 1997-1999  Michael van Acken

    This module is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public License
    as published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.

    This module is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with OOC. If not, write to the Free Software Foundation,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
<* Warnings := FALSE; ConformantMode := FALSE *>

(*
Warning:
This module is not part of the "official" OOC suit of library modules.  It
provides an abstract class containing the features that are used by all channel
implementations based on Unix-style file descriptors.  It will not be available
for all implementations of OOC.  Usage of of this module should be restricted 
to derived modules like StdChannels or Files.  It should never be used directly
by a programmer.
*)

IMPORT
  SYSTEM, C, Time, CharClass, Ch := Channel, Msg, LongStrings;


TYPE
  Result* = Ch.Result;
  
CONST  (* NOTE: refer to module Channel for the meaning of the various codes *)
  noLength* = Ch.noLength;
  noPosition* = Ch.noPosition;
  
  (* the following values may appear in the `res' (or `res.code')
     field of `Channel', `Reader', or `Writer': *)
  done* = Ch.done;
  invalidChannel* = Ch.invalidChannel;
  writeError* = Ch.writeError;
  noRoom* = Ch.noRoom; 

  (* symbolic values for error codes in `Reader.res' resp. `Writer.res': *)
  outOfRange* = Ch.outOfRange;
  readAfterEnd* = Ch.readAfterEnd;
  channelClosed* = Ch.channelClosed;
  readError* = Ch.readError;
  invalidFormat* = Ch.invalidFormat;
  
  (* symbolic values for error code in `Ch.res': *)
  noReadAccess* = Ch.noReadAccess;
  noWriteAccess* = Ch.noWriteAccess;
  closeError* = Ch.closeError;
  noModTime* = Ch.noModTime;
  noTmpName* = Ch.noTmpName;
  
  freeErrorCode* = Ch.freeErrorCode;


CONST  (* values for field `buffering parameter `mode' of procedure `Init': *)
  readOnly* = 0;
  writeOnly* = 1;
  readWrite* = 2;
  
CONST  (* standard file descriptor ids *)
  stdinFileno* = 0;
  stdoutFileno* = 1;
  stderrFileno* = 2;

CONST  (* accepted values for parameter `buffering' in `ChannelDesc: *)
  noBuffer* = 0;
  lineBuffer* = 1;  (* only applicable to terminals *)
  blockBuffer* = 2;
  
TYPE
  Channel* = POINTER TO ChannelDesc;
  Reader* = POINTER TO ReaderDesc;
  Writer* = POINTER TO WriterDesc;

TYPE
  ChannelDesc* = RECORD
    (Ch.ChannelDesc)
    fd-: C.int;
    (* file descriptor; set with the Init procedure *)
    pos: C.int;
    (* current reading/writing position of the channel; this may differ from
       a reader or writer position if more than one of them are attached *)
    positionable: BOOLEAN;
    (* TRUE iff Length and SetPos are available for the attached riders *)
    append: BOOLEAN;
    (* TRUE iff writers will always append to the file *)
    dirty: BOOLEAN;
    (* TRUE iff buffer needs to be written back; this also serves to 
       distinguish between the buffers access mode: TRUE means write, FALSE
       is read *)
    buffering: SHORTINT;
    (* mode of buffering (none, line, block); for reading line buffering is 
       only applicable for canonical terminal input *)
    buf: POINTER TO ARRAY [NO_LENGTH_INFO, NO_DESCRIPTOR] OF CHAR;
    sizeBuffer: LONGINT;
    (* buffer of length sizeBuffer; sizeBuffer=0 is equivalent to buf=NIL *)
    bufStart, 
    bufEnd: LONGINT;
    (* describe the interval for which the buffer holds valid data from the
       file; the interval contains the character at bufStart, but excludes
       the one at bufEnd, i.e., it is [bufStart..bufEnd[; bufStart<=bufEnd
       always holds, bufStart=bufEnd means an empty buffer; a dirty buffer
       is never emtpy *)
    reader: Reader;
    (* holds the single reader if the channel isn't positionable *)
    writer: Writer;
    (* holds the single writer if the channel isn't positionable *)
  END;
  ReaderDesc* = RECORD
    (Ch.ReaderDesc)
    pos: C.int;
  END;
  WriterDesc* = RECORD
    (Ch.WriterDesc)
    pos: C.int;
  END;

TYPE
  FileDescriptor = C.int;

VAR
  (* these variables have nothing to do with file descriptors; since nobody
     should use this module anyway I stuck them here; they are used by the
     module ProgramArgs *)
  argc- ["_program_argc"]: C.int;
  argv- ["_program_argv"]: C.charPtr2d;


TYPE
  ErrorContext = POINTER TO ErrorContextDesc;
  ErrorContextDesc* = RECORD
     (* this record is exported, so that extensions of Channel can access the
        error descriptions by extending `ErrorContextDesc' *)
    (Ch.ErrorContextDesc)
  END;


PROCEDURE (context: ErrorContext) GetTemplate* (msg: Msg.Msg; VAR templ: Msg.LString);

PROCEDURE InitReader* (r: Reader; ch: Channel);

PROCEDURE InitWriter* (w: Writer; ch: Channel);


(* Reader methods 
   ------------------------------------------------------------------------ *)

PROCEDURE (r: Reader) Pos*(): LONGINT;
(* Returns the current reading position associated with the reader `r' in
   channel `r.base', i.e. the index of the first byte that is read by the
   next call to ReadByte resp. ReadBytes.  This procedure will return 
   `noPosition' if the reader has no concept of a reading position (e.g. if it
   corresponds to input from keyboard), otherwise the result is not negative.*)
  
PROCEDURE (r: Reader) Available*(): LONGINT;
(* Returns the number of bytes available for the next reading operation.  For
   a file this is the length of the channel `r.base' minus the current reading
   position, for an sequential channel (or a channel designed to handle slow
   transfer rates) this is the number of bytes that can be accessed without
   additional waiting.  The result is -1 if the channel has been closed.  
   Note that the number of bytes returned is always a lower approximation of
   the number that could be read at once; for some channels or systems it might
   be as low as 1 even if tons of bytes are waiting to be processed.  *)
  
PROCEDURE (r: Reader) SetPos* (newPos: LONGINT);
(* Sets the reading position to `newPos'.  A negative value of `newPos' or 
   calling this procedure for a reader that doesn't allow positioning will set
   `r.res' to `outOfRange'.  A value larger than the channel's length is legal,
   but the following read operation will most likely fail with an 
   `readAfterEnd' error unless the channel has grown beyond this position in 
   the meantime.
   Calls to this procedure while `r.res # done' will be ignored, in particular
   a call with `r.res = readAfterEnd' error will not reset `res' to `done'. *)
  
PROCEDURE (r: Reader) ReadByte* (VAR x: SYSTEM.BYTE);
(* Reads a single byte from the channel `r.base' at the reading position 
   associated with `r' and places it in `x'.  The reading position is moved 
   forward by one byte on success, otherwise `r.res' is changed to indicate 
   the error cause.  Calling this procedure with the reader `r' placed at the 
   end (or beyond the end) of the channel will set `r.res' to `readAfterEnd'.
   `r.bytesRead' will be 1 on success and 0 on failure.
   Calls to this procedure while `r.res # done' will be ignored.  *)
  
PROCEDURE (r: Reader) ReadBytes* (VAR x: ARRAY OF SYSTEM.BYTE; 
                                  start, n: LONGINT);
(* Reads `n' bytes from the channel `r.base' at the reading position associated
   with `r' and places them in `x', starting at index `start'.  The 
   reading position is moved forward by `n' bytes on success, otherwise 
   `r.res' is changed to indicate the error cause.  Calling this procedure with
   the reader `r' placed less than `n' bytes before the end of the channel will
   will set `r.res' to `readAfterEnd'.  `r.bytesRead' will hold the number of
   bytes that were actually read (being equal to `n' on success).
   Calls to this procedure while `r.res # done' will be ignored.
   pre: (n >= 0) & (0 <= start) & (start+n <= LEN (x)) *)

(* Writer methods 
   ------------------------------------------------------------------------ *)

PROCEDURE (w: Writer) Pos*(): LONGINT;
(* Returns the current writing position associated with the writer `w' in
   channel `w.base', i.e. the index of the first byte that is written by the
   next call to WriteByte resp. WriteBytes.  This procedure will return 
   `noPosition' if the writer has no concept of a writing position (e.g. if it
   corresponds to output to terminal), otherwise the result is not negative. *)
  
PROCEDURE (w: Writer) SetPos* (newPos: LONGINT);
(* Sets the writing position to `newPos'.  A negative value of `newPos' or 
   calling this procedure for a writer that doesn't allow positioning will set
   `w.res' to `outOfRange'.  A value larger than the channel's length is legal,
   the following write operation will fill the gap between the end of the 
   channel and this position with zero bytes.
   Calls to this procedure while `w.res # done' will be ignored.  *)
  
PROCEDURE (w: Writer) WriteByte* (x: SYSTEM.BYTE);
(* Writes a single byte `x' to the channel `w.base' at the writing position 
   associated with `w'.  The writing position is moved forward by one byte on 
   success, otherwise `w.res' is changed to indicate the error cause.
   `w.bytesWritten' will be 1 on success and 0 on failure.
   Calls to this procedure while `w.res # done' will be ignored.  *)
  
PROCEDURE (w: Writer) WriteBytes* (VAR x: ARRAY OF SYSTEM.BYTE; start, n: LONGINT);
(* Writes `n' bytes from `x', starting at position `start', to the channel 
   `w.base' at the writing position associated with `w'.  The writing position
   is moved forward by `n' bytes on success, otherwise `w.res' is changed to 
   indicate the error cause.  `w.bytesWritten' will hold the number of bytes 
   that were actually written (being equal to `n' on success).
   Calls to this procedure while `w.res # done' will be ignored.
   pre: (n >= 0) & (0 <= start) & (start+n <= LEN (x))  *)

(* Channel methods 
   ------------------------------------------------------------------------ *)

PROCEDURE (ch: Channel) Length*(): LONGINT;
(* Result is the number of bytes of data that this channel refers to.  If `ch'
   represents a file, then this value is the file's size.  If `ch' has no fixed
   length (e.g. because it's interactive), the result is `noLength'.  *)
  
PROCEDURE (ch: Channel) GetModTime* (VAR mtime: Time.TimeStamp);
(* Retrieves the modification time of the data accessed by the given channel.
   If no such information is avaiblable, `ch.res' is set to `noModTime', 
   otherwise to `done'.  *)

PROCEDURE (ch: Channel) NewReader*(): Reader;
(* Attaches a new reader to the channel `ch'.  It is placed at the very start 
   of the channel, and its `res' field is initialized to `done'.  `ch.res' is
   set to `done' on success and the new reader is returned.  Otherwise result 
   is NIL and `ch.res' is changed to indicate the error cause.
   Note that always the same reader is returned if the channel does not support
   multiple reading positions.  *)
  
PROCEDURE (ch: Channel) NewWriter*(): Writer;
(* Attaches a new writer to the channel `ch'.  It is placed at the very start 
   of the channel, and its `res' field is initialized to `done'.  `ch.res' is
   set to `done' on success and the new writer is returned.  Otherwise result 
   is NIL and `ch.res' is changed to indicate the error cause.
   Note that always the same reader is returned if the channel does not support
   multiple writing positions.  *)
  
PROCEDURE (ch: Channel) Flush*;
(* Flushes all buffers related to this channel.  Any pending write operations
   are passed to the underlying OS and all buffers are marked as invalid.  The
   next read operation will get its data directly from the channel instead of 
   the buffer.  If a writing error occurs during flushing, the field `ch.res'
   will be changed to `writeError', otherwise it's assigned `done'.  Note that
   you have to check the channel's `res' flag after an explicit flush yourself,
   since none of the attached writers will notice any write error in this 
   case.  *)
  
PROCEDURE (ch: Channel) Close*;
(* Flushes all buffers associated with `ch', closes the channel, and frees all
   system resources allocated to it.  This invalidates all riders attached to
   `ch', they can't be used further.  On success, i.e. if all read and write 
   operations (including flush) completed successfully, `ch.res' is set to 
   `done'.  An opened channel can only be closed once, successive calls of 
   `Close' are undefined.  *)

PROCEDURE Init* (ch: Channel; fd: FileDescriptor; mode: SHORTINT);
(* Attach channel `ch' to file descriptor `fd'.  `mode' specifies whether the
   descriptor should be treated as read only, write only, or read/write.  
   It's a bad idea to pass a duplicated file descriptor to `fd', all kinds 
   of unexpected things might happen.  *)

PROCEDURE Truncate* (w: Writer; newLength: LONGINT);
(* Causes the file associated with `w' to have the specified length.  If the 
   file was previously larger than `newLength', the extra data is lost.  If it
   was previously shorter, bytes between the old and new lengths are read as 
   zeros.  The writer's position is not modified.
   Note: On systems that do not support shortening files directly it is 
   implemented as a partial file copy.
   This procedure should always be called through Files.Writer.Truncate.  *)

END PosixFileDescr.