File: Files.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 (279 lines) | stat: -rw-r--r-- 12,739 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
(*	$Id: Files.Mod,v 1.8 1999/10/31 13:59:23 ooc-devel Exp $	*)
MODULE Files [FOREIGN "C"; LINK FILE "Files.c" END]; <* Warnings := FALSE *>
(*  Access to files and file attributes.
    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.
*)

(* 
Note 1:
This text describes only the additional features of files beyond the standard
channels.  Please refer to Channel.Mod for the semantics of all items that are
inherited from Channel without modifications.

Note 2:
Most Unix systems only allow a fixed number of files (and sockets) to
be open simultaneously.  If this limit is reached, no new file can be
opened or socket be created until an old file/socket is closed.  For
any POSIX compliant system at least 16 open files are supported, most
implementations provide a much larger number.
*)
<* ConformantMode := FALSE *>  (* for NewReader/NewWriter *)

IMPORT
  Ch0 := Channel, Ch := PosixFileDescr, Time, Termination,
  CharClass, LongStrings, Msg;


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;

  (* these values report problems when opening or modifying a file: *)
  accessDenied* = Ch.freeErrorCode;
  (* access to the channel was denied, e.g. because a file's permissions don't
     permit the requested access method, or because the given URL isn't 
     publically readable *)
  isDirectory* = Ch.freeErrorCode+1;
  (* the `flags' argument specified write access, and the file is a 
    directory *)
  tooManyFiles* = Ch.freeErrorCode+2;
  (* the process or the entire system has too many files open *)
  noSuchFile* = Ch.freeErrorCode+3;
  (* the named file in a call to `Old' does not exist; or the directory part of
     a file name passed to `New' or `Tmp' does not exist *)
  directoryFull* = Ch.freeErrorCode+4;
  (* the directory or the file system that would contain the new file cannot be
     extended, either because there is no space left or the directory has a 
     fixed upper limit *)
  readOnlyFileSystem* = Ch.freeErrorCode+5;
  (* the file resides on a read-only file system and it is attempted to create
     a new file or to gain write access for an existing one  *)
  invalidTime* = Ch.freeErrorCode+6;
  (* the time passed to procedure SetModTime is no valid time stamp; either the
     millisecond part isn't valid, or the time value is too large or too small
     to be mapped to the time value of the underlying OS *)
  notOwner* = Ch.freeErrorCode+7;
  (* only the owner of a file can change its modification time *)
  anonymousFile* = Ch.freeErrorCode+8;
  (* a file can only be registered if a file name was passed to the initial 
    call to Tmp() *)
  dirWriteDenied* = Ch.freeErrorCode+9;
  (* you need to have write permission for the directory you want to add a new
     file to *)
  fileError* = Ch.freeErrorCode+10;
  (* unspecified error when opening/creating a file; this usually means that
     this module doesn't know how to interpret the error code delivered by 
     the OS *)
  nameTooLong* = Ch.freeErrorCode+11;
  (* either the total length of the file name or of an individual file name
     component is too large; the operating system can impose such limits (see
     PATH_MAX and NAME_MAX in /usr/include/limits.h), or the file system itself
     restricts the format of names on it *) 
  notDirectory* = Ch.freeErrorCode+12;
  (* a file that is referenced as a directory component of the file name 
     exists, but is not a directory *)
  linkLoop* = Ch.freeErrorCode+13;
  (* too many symbolic links were resolved while trying to look up the file
     name; the operating system has an arbitrary limit on the number of 
     symbolic links that may be resolved in looking up a single file name,
     as a primitive way to detect loops *)
     
  
CONST
  (* possible elements for `flags' parameter of New/Old/Tmp: *)
  read* = 0;
  (* if the file cannot be opened for reading access, then it isn't opened at
     all; in this case the error code is set to `noReadAccess' *)
  write* = 1;
  (* if the file cannot be opened for writing access, then it isn't opened at
     all; in this case the error code is set to `noWriteAccess' *)
  tryRead* = 2;
  (* try to open this file for reading access; if the file permissions don't 
     permit reading the file is opened nevertheless, but the file descriptor's
     attribute `readable' is set to FALSE *)
  tryWrite* = 3;
  (* try to open this file for writing access; if the file permissions don't 
     permit writing the file is opened nevertheless, but the file descriptor's
     attribute `writable' is set to FALSE *)
  (* note: at least one of the above flags has to be set; otherwise you'll 
     always get an `access denied' error *)

TYPE
  File* = POINTER TO FileDesc;
  FileDesc* = RECORD 
    (Ch.ChannelDesc)
    next: File;
    tmpName, name: POINTER TO ARRAY [NO_LENGTH_INFO, NO_DESCRIPTOR] OF CHAR;
    anonymous: BOOLEAN;
  END;

TYPE
  Reader* = POINTER TO ReaderDesc;
  ReaderDesc* = RECORD
    (Ch.ReaderDesc)
  END;

TYPE
  Writer* = POINTER TO WriterDesc;
  WriterDesc* = RECORD 
    (Ch.WriterDesc)
  END;


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;

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


(* type-bound procedures from Channel.Channel:
   Length, NewReader, NewWriter, Flush, Close *)

PROCEDURE (f: File) Register*;
(* Registers the file `f' in the directory structure if it has been created 
   with the `Tmp' procedure below.  Registration happens atomically, i.e., it
   is guaranteed that any previously existing file is replaced by the newly 
   registered one without any "in between" state.  If the operation is 
   interrupted, then either the old file still exists on the file system, or
   it has been replaced completely by the new one.
     Calling `Tmp' and `Register' successively  has the same effect as calling
   `New'.  Calling this procedure has no effect if the file `f' has been 
   created with `New' or has been registered previously.  Registration fails
   with an `anonymousFile' error if it was created by calling `Tmp' with an
   empty file name, and with a `channelClosed' error if `f' is closed.  *)
  
PROCEDURE (f: File) NewReader*(): Reader;
(* Attaches a new reader to the file `f'.  It is placed at the very start 
   of the file, and its `res' field is initialized to `done'.  `f.res' is
   set to `done' on success and the new reader is returned.  Otherwise result 
   is NIL and `f.res' is changed to indicate the error cause.  *)
  
PROCEDURE (f: File) NewWriter*(): Writer;
(* Attaches a new writer to the file `f'.  It is placed at the very start 
   of the file, and its `res' field is initialized to `done'.  `f.res' is
   set to `done' on success and the new writer is returned.  Otherwise result 
   is NIL and `f.res' is changed to indicate the error cause.  *)
  
PROCEDURE (f: File) Close*;
(* Flushes all buffers associated with `f', closes the file, and frees all
   system resources allocated to it.  This invalidates all riders attached to
   `f', they can't be used further.  On success, i.e. if all read and write 
   operations (including flush) completed successfully, `f.res' is set to 
   `done'.  An opened file can only be closed once, successive calls of 
   `Close' are undefined.  
   Note that unlike the Oberon System all opened files have to be closed
   explicitly.  Otherwise resources allocated to them will remain blocked.  *)
  

(* type-bound procedures from Channel.Reader:
   Pos, Available, SetPos, ReadByte, ReadBytes, ClearError *)

(* type-bound procedures from Channel.Writer:
   Pos, SetPos, WriteByte, WriteBytes, ErrorDescr, ClearError *)

PROCEDURE (w: Writer) Truncate* (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.  *)


(* specialized file access; these procedures allow finer grained control than 
   the standard type-bound procedures Filename.New/Old *)
   
PROCEDURE New* (file: ARRAY OF CHAR; flags: SET; VAR res: Result): File;
(* Creates a new file under the given name.  On success the new file handle is
   returned and `res' is set to `done'.  Otherwise result is NIL and `res'
   and will indicate the problem.
   Note that in terms of the Oberon System this procedure combines the 
   procedures New and Register.  *)
  
PROCEDURE Old* (file: ARRAY OF CHAR; flags: SET; VAR res: Result): File;
(* Opens an existing file.  On success the new file handle is returned and
   `res' is set to `done'.  Otherwise result is NIL and `res' will indicate the
   problem.  *)
  
PROCEDURE Tmp* (file: ARRAY OF CHAR; flags: SET; VAR res: Result): File;
(* Creates a temporary file that can be registered later on.  On success the 
   new file handle is returned and `res' is set to `done'.  Otherwise result
   is NIL and `res' will indicate the problem.
     Temporary files are created with an empty permission list, the 
   permissions are extended upon registration.  The files are deleted if they
   haven't been registered and are closed or the program terminates.  
     An unique temporary file name is created if the given file name is the 
   empty string.  Such a file can't be registered later.  Note that some 
   systems are said to have a very low limit for the number of temporary file 
   names.  The limit is never less than 25.  To be on the safe side you should
   never have more than 25 anonymous temporary files open simultaneously, or 
   check that the TMP_MAX macro in /usr/include/stdio.h is large enough for 
   your purposes.
     With oo2c if `file' isn't empty, the new name is derived from the old one
   by appending "^", "^1", "^2", etc. in turn, until a file name is found that
   doesn't exist already.  If such call to `Tmp' returns `nameTooLong', then 
   this refers to the constructed temporary name, not the one in `file'.  
     This function corresponds to Oberon System's New.  *)
  
PROCEDURE SetModTime* (file: ARRAY OF CHAR; mtime: Time.TimeStamp; VAR res: Result);
(* Sets the modification time of the given file to `mtime'.  On success `res'
   will contain `done', otherwise an error code that'll indicate the problem.
   Note that under Unix this procedure will also change the access time to the
   value of `mtime'.  *)

PROCEDURE GetModTime* (file: ARRAY OF CHAR; VAR mtime: Time.TimeStamp; VAR res: Result);
(* Gets the modification time of the given file to `mtime'.  On success `res'
   will contain `done', otherwise an error code indicating the problem.*)

PROCEDURE Exists* (file: ARRAY OF CHAR): BOOLEAN;
(* Returns TRUE if a file `file' exists, FALSE otherwise. 
   ... will be changed to give more useful information on failure *)

END Files.