]>
Commit | Line | Data |
---|---|---|
1eee94d3 GM |
1 | (* SeqFile.mod implement the ISO SeqFile specification. |
2 | ||
83ffe9cd | 3 | Copyright (C) 2008-2023 Free Software Foundation, Inc. |
1eee94d3 GM |
4 | Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
5 | ||
6 | This file is part of GNU Modula-2. | |
7 | ||
8 | GNU Modula-2 is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3, or (at your option) | |
11 | any later version. | |
12 | ||
13 | GNU Modula-2 is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | General Public License for more details. | |
17 | ||
18 | Under Section 7 of GPL version 3, you are granted additional | |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
21 | ||
22 | You should have received a copy of the GNU General Public License and | |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. *) | |
26 | ||
27 | IMPLEMENTATION MODULE SeqFile ; | |
28 | ||
29 | FROM RTgen IMPORT ChanDev, DeviceType, | |
30 | InitChanDev, doLook, doSkip, doSkipLook, doWriteLn, | |
31 | doReadText, doWriteText, doReadLocs, doWriteLocs, | |
32 | checkErrno ; | |
33 | ||
34 | FROM RTfio IMPORT doreadchar, dounreadchar, dogeterrno, dorbytes, | |
35 | dowbytes, dowriteln, iseof, iseoln, iserror ; | |
36 | ||
37 | FROM IOLink IMPORT DeviceId, DeviceTablePtr, IsDevice, MakeChan, UnMakeChan, | |
38 | DeviceTablePtrValue, RAISEdevException, AllocateDeviceId, | |
39 | ResetProc ; | |
40 | ||
41 | FROM RTgenif IMPORT GenDevIF, InitGenDevIF ; | |
42 | FROM FIO IMPORT File ; | |
43 | FROM errno IMPORT geterrno ; | |
44 | FROM IOConsts IMPORT ReadResults ; | |
45 | FROM ChanConsts IMPORT readFlag, writeFlag ; | |
46 | ||
47 | IMPORT FIO, SYSTEM, RTio, errno, ErrnoCategory ; | |
48 | ||
49 | ||
50 | VAR | |
51 | dev: ChanDev ; | |
52 | did: DeviceId ; | |
53 | ||
54 | ||
55 | PROCEDURE look (d: DeviceTablePtr; | |
56 | VAR ch: CHAR; VAR r: ReadResults) ; | |
57 | BEGIN | |
58 | doLook(dev, d, ch, r) | |
59 | END look ; | |
60 | ||
61 | ||
62 | PROCEDURE skip (d: DeviceTablePtr) ; | |
63 | BEGIN | |
64 | doSkip(dev, d) | |
65 | END skip ; | |
66 | ||
67 | ||
68 | PROCEDURE skiplook (d: DeviceTablePtr; | |
69 | VAR ch: CHAR; VAR r: ReadResults) ; | |
70 | BEGIN | |
71 | doSkipLook(dev, d, ch, r) | |
72 | END skiplook ; | |
73 | ||
74 | ||
75 | PROCEDURE lnwrite (d: DeviceTablePtr) ; | |
76 | BEGIN | |
77 | doWriteLn(dev, d) | |
78 | END lnwrite ; | |
79 | ||
80 | ||
81 | PROCEDURE textread (d: DeviceTablePtr; | |
82 | to: SYSTEM.ADDRESS; | |
83 | maxChars: CARDINAL; | |
84 | VAR charsRead: CARDINAL) ; | |
85 | BEGIN | |
86 | doReadText(dev, d, to, maxChars, charsRead) | |
87 | END textread ; | |
88 | ||
89 | ||
90 | PROCEDURE textwrite (d: DeviceTablePtr; | |
91 | from: SYSTEM.ADDRESS; | |
92 | charsToWrite: CARDINAL); | |
93 | BEGIN | |
94 | doWriteText(dev, d, from, charsToWrite) | |
95 | END textwrite ; | |
96 | ||
97 | ||
98 | PROCEDURE rawread (d: DeviceTablePtr; | |
99 | to: SYSTEM.ADDRESS; | |
100 | maxLocs: CARDINAL; | |
101 | VAR locsRead: CARDINAL) ; | |
102 | BEGIN | |
103 | doReadLocs(dev, d, to, maxLocs, locsRead) | |
104 | END rawread ; | |
105 | ||
106 | ||
107 | PROCEDURE rawwrite (d: DeviceTablePtr; | |
108 | from: SYSTEM.ADDRESS; | |
109 | locsToWrite: CARDINAL) ; | |
110 | BEGIN | |
111 | doWriteLocs(dev, d, from, locsToWrite) | |
112 | END rawwrite ; | |
113 | ||
114 | ||
115 | PROCEDURE getname (d: DeviceTablePtr; | |
116 | VAR a: ARRAY OF CHAR) ; | |
117 | BEGIN | |
118 | FIO.GetFileName(RTio.GetFile(d^.cid), a) | |
119 | END getname ; | |
120 | ||
121 | ||
122 | PROCEDURE flush (d: DeviceTablePtr) ; | |
123 | BEGIN | |
124 | FIO.FlushBuffer(RTio.GetFile(d^.cid)) | |
125 | END flush ; | |
126 | ||
127 | ||
128 | (* | |
129 | checkOpenErrno - assigns, e, and, res, depending upon file result of opening, | |
130 | file. | |
131 | *) | |
132 | ||
133 | PROCEDURE checkOpenErrno (file: FIO.File; VAR e: INTEGER; VAR res: OpenResults) ; | |
134 | BEGIN | |
135 | IF FIO.IsNoError(file) | |
136 | THEN | |
137 | e := 0 ; | |
138 | ELSE | |
139 | e := errno.geterrno() | |
140 | END ; | |
141 | res := ErrnoCategory.GetOpenResults(e) | |
142 | END checkOpenErrno ; | |
143 | ||
144 | ||
145 | (* | |
146 | newCid - returns a ChanId which represents the opened file, name. | |
147 | res is set appropriately on return. | |
148 | *) | |
149 | ||
150 | PROCEDURE newCid (fname: ARRAY OF CHAR; | |
151 | f: FlagSet; | |
152 | VAR res: OpenResults; | |
153 | toRead: BOOLEAN; | |
154 | whichreset: ResetProc) : ChanId ; | |
155 | VAR | |
156 | c : RTio.ChanId ; | |
157 | file: FIO.File ; | |
158 | e : INTEGER ; | |
159 | p : DeviceTablePtr ; | |
160 | BEGIN | |
161 | IF toRead | |
162 | THEN | |
163 | file := FIO.OpenToRead(fname) | |
164 | ELSE | |
165 | file := FIO.OpenToWrite(fname) | |
166 | END ; | |
167 | checkOpenErrno(file, e, res) ; | |
168 | ||
169 | IF FIO.IsNoError(file) | |
170 | THEN | |
171 | MakeChan(did, c) ; | |
172 | RTio.SetFile(c, file) ; | |
173 | p := DeviceTablePtrValue(c, did) ; | |
174 | WITH p^ DO | |
175 | flags := f ; | |
176 | errNum := e ; | |
177 | doLook := look ; | |
178 | doSkip := skip ; | |
179 | doSkipLook := skiplook ; | |
180 | doLnWrite := lnwrite ; | |
181 | doTextRead := textread ; | |
182 | doTextWrite := textwrite ; | |
183 | doRawRead := rawread ; | |
184 | doRawWrite := rawwrite ; | |
185 | doGetName := getname ; | |
186 | doReset := whichreset ; | |
187 | doFlush := flush ; | |
188 | doFree := handlefree | |
189 | END ; | |
190 | RETURN( c ) | |
191 | ELSE | |
192 | RETURN( IOChan.InvalidChan() ) | |
193 | END | |
194 | END newCid ; | |
195 | ||
196 | ||
197 | (* | |
198 | Attempts to obtain and open a channel connected to a stored rewindable | |
199 | file of the given name. The write flag is implied; without the raw | |
200 | flag, text is implied. If successful, assigns to cid the identity of | |
201 | the opened channel, assigns the value opened to res, and selects | |
202 | output mode, with the write position at the start of the file (i.e. | |
203 | the file is of zero length). If a channel cannot be opened as required, | |
204 | the value of res indicates the reason, and cid identifies the | |
205 | invalid channel. | |
206 | *) | |
207 | ||
208 | PROCEDURE OpenWrite (VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; | |
209 | VAR res: OpenResults) ; | |
210 | BEGIN | |
211 | INCL(flags, ChanConsts.writeFlag) ; | |
212 | IF NOT (ChanConsts.rawFlag IN flags) | |
213 | THEN | |
214 | INCL(flags, ChanConsts.textFlag) | |
215 | END ; | |
216 | cid := newCid(name, flags, res, FALSE, resetWrite) | |
217 | END OpenWrite ; | |
218 | ||
219 | ||
220 | (* | |
221 | Attempts to obtain and open a channel connected to a stored rewindable | |
222 | file of the given name. The read and old flags are implied; without | |
223 | the raw flag, text is implied. If successful, assigns to cid the | |
224 | identity of the opened channel, assigns the value opened to res, and | |
225 | selects input mode, with the read position corresponding to the start | |
226 | of the file. If a channel cannot be opened as required, the value of | |
227 | res indicates the reason, and cid identifies the invalid channel. | |
228 | *) | |
229 | ||
230 | PROCEDURE OpenRead (VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; | |
231 | VAR res: OpenResults) ; | |
232 | BEGIN | |
233 | flags := flags + ChanConsts.read + ChanConsts.old ; | |
234 | IF NOT (ChanConsts.rawFlag IN flags) | |
235 | THEN | |
236 | INCL(flags, ChanConsts.textFlag) | |
237 | END ; | |
238 | cid := newCid(name, flags, res, TRUE, resetRead) | |
239 | END OpenRead ; | |
240 | ||
241 | ||
242 | (* | |
243 | OpenAppend - attempts to obtain and open a channel connected | |
244 | to a stored rewindable file of the given name. | |
245 | The write and old flags are implied; without | |
246 | the raw flag, text is implied. If successful, | |
247 | assigns to cid the identity of the opened channel, | |
248 | assigns the value opened to res, and selects output | |
249 | mode, with the write position corresponding to the | |
250 | length of the file. If a channel cannot be opened | |
251 | as required, the value of res indicates the reason, | |
252 | and cid identifies the invalid channel. | |
253 | *) | |
254 | ||
255 | PROCEDURE OpenAppend (VAR cid: ChanId; name: ARRAY OF CHAR; | |
256 | flags: FlagSet; VAR res: OpenResults) ; | |
257 | BEGIN | |
258 | flags := flags + ChanConsts.write + ChanConsts.old ; | |
259 | IF NOT (ChanConsts.rawFlag IN flags) | |
260 | THEN | |
261 | INCL(flags, ChanConsts.textFlag) | |
262 | END ; | |
263 | cid := newCid(name, flags, res, FALSE, resetAppend) ; | |
264 | IF IsSeqFile(cid) | |
265 | THEN | |
266 | FIO.SetPositionFromEnd(RTio.GetFile(cid), 0) ; | |
267 | checkErrno(dev, RTio.GetDevicePtr(cid)) | |
268 | END | |
269 | END OpenAppend ; | |
270 | ||
271 | ||
272 | (* | |
273 | resetAppend - ensures that +write and -read and seeks to | |
274 | the end of the file. | |
275 | *) | |
276 | ||
277 | PROCEDURE resetAppend (d: DeviceTablePtr) ; | |
278 | VAR | |
279 | f: FIO.File ; | |
280 | BEGIN | |
281 | WITH d^ DO | |
282 | flags := flags + write - read ; | |
283 | FIO.SetPositionFromEnd(RTio.GetFile(cid), 0) ; | |
284 | END ; | |
285 | checkErrno(dev, d) | |
286 | END resetAppend ; | |
287 | ||
288 | ||
289 | (* | |
290 | resetRead - | |
291 | *) | |
292 | ||
293 | PROCEDURE resetRead (d: DeviceTablePtr) ; | |
294 | BEGIN | |
295 | Reread(d^.cid) | |
296 | END resetRead ; | |
297 | ||
298 | ||
299 | (* | |
300 | resetWrite - | |
301 | *) | |
302 | ||
303 | PROCEDURE resetWrite (d: DeviceTablePtr) ; | |
304 | BEGIN | |
305 | Rewrite(d^.cid) | |
306 | END resetWrite ; | |
307 | ||
308 | ||
309 | (* | |
310 | IsSeqFile - tests if the channel identified by cid is open to a | |
311 | rewindable sequential file. | |
312 | *) | |
313 | ||
314 | PROCEDURE IsSeqFile (cid: ChanId) : BOOLEAN ; | |
315 | BEGIN | |
316 | RETURN( (cid # NIL) AND (IOChan.InvalidChan() # cid) AND | |
317 | (IsDevice(cid, did)) AND | |
318 | ((ChanConsts.readFlag IN IOChan.CurrentFlags(cid)) OR | |
319 | (ChanConsts.writeFlag IN IOChan.CurrentFlags(cid))) ) | |
320 | END IsSeqFile ; | |
321 | ||
322 | ||
323 | (* | |
324 | Reread - if the channel identified by cid is not open | |
325 | to a rewindable sequential file, the exception | |
326 | wrongDevice is raised; otherwise attempts to set | |
327 | the read position to the start of the file, and | |
328 | to select input mode. If the operation cannot | |
329 | be performed (perhaps because of insufficient | |
330 | permissions) neither input mode nor output | |
331 | mode is selected. | |
332 | *) | |
333 | ||
334 | PROCEDURE Reread (cid: ChanId) ; | |
335 | VAR | |
336 | d: DeviceTablePtr ; | |
337 | BEGIN | |
338 | IF IsSeqFile(cid) | |
339 | THEN | |
340 | d := DeviceTablePtrValue(cid, did) ; | |
341 | WITH d^ DO | |
342 | EXCL(flags, writeFlag) ; | |
343 | IF readFlag IN flags | |
344 | THEN | |
345 | FIO.SetPositionFromBeginning(RTio.GetFile(cid), 0) ; | |
346 | checkErrno(dev, d) | |
347 | ELSE | |
348 | EXCL(flags, readFlag) | |
349 | END | |
350 | END | |
351 | ELSE | |
352 | RAISEdevException(cid, did, IOChan.wrongDevice, | |
353 | 'SeqFile.' + __FUNCTION__ + | |
354 | ': channel is not a sequential file') | |
355 | END | |
356 | END Reread ; | |
357 | ||
358 | ||
359 | (* | |
360 | Rewrite - if the channel identified by cid is not open to a | |
361 | rewindable sequential file, the exception wrongDevice | |
362 | is raised; otherwise, attempts to truncate the | |
363 | file to zero length, and to select output mode. | |
364 | If the operation cannot be performed (perhaps | |
365 | because of insufficient permissions) neither input | |
366 | mode nor output mode is selected. | |
367 | *) | |
368 | ||
369 | PROCEDURE Rewrite (cid: ChanId) ; | |
370 | VAR | |
371 | d: DeviceTablePtr ; | |
372 | BEGIN | |
373 | IF IsSeqFile(cid) | |
374 | THEN | |
375 | d := DeviceTablePtrValue(cid, did) ; | |
376 | WITH d^ DO | |
377 | EXCL(flags, readFlag) ; | |
378 | IF writeFlag IN flags | |
379 | THEN | |
380 | FIO.SetPositionFromBeginning(RTio.GetFile(cid), 0) ; | |
381 | checkErrno(dev, d) | |
382 | ELSE | |
383 | EXCL(flags, writeFlag) | |
384 | END | |
385 | END | |
386 | ELSE | |
387 | RAISEdevException(cid, did, IOChan.wrongDevice, | |
388 | 'SeqFile.' + __FUNCTION__ + | |
389 | ': channel is not a sequential file') | |
390 | END | |
391 | END Rewrite ; | |
392 | ||
393 | ||
394 | (* | |
395 | handlefree - | |
396 | *) | |
397 | ||
398 | PROCEDURE handlefree (d: DeviceTablePtr) ; | |
399 | VAR | |
400 | f: File ; | |
401 | BEGIN | |
402 | WITH d^ DO | |
403 | doFlush(d) ; | |
404 | checkErrno(dev, d) ; | |
405 | f := RTio.GetFile(RTio.ChanId(cid)) ; | |
406 | IF FIO.IsNoError(f) | |
407 | THEN | |
408 | FIO.Close(f) ; | |
409 | END ; | |
410 | checkErrno(dev, d) | |
411 | END | |
412 | END handlefree ; | |
413 | ||
414 | ||
415 | (* | |
416 | Close - if the channel identified by cid is not open to a sequential | |
417 | stream, the exception wrongDevice is raised; otherwise | |
418 | closes the channel, and assigns the value identifying | |
419 | the invalid channel to cid. | |
420 | *) | |
421 | ||
422 | PROCEDURE Close (VAR cid: ChanId) ; | |
423 | BEGIN | |
424 | IF IsSeqFile(cid) | |
425 | THEN | |
426 | UnMakeChan(did, cid) ; | |
427 | cid := IOChan.InvalidChan() | |
428 | ELSE | |
429 | RAISEdevException(cid, did, IOChan.wrongDevice, | |
430 | 'SeqFile.' + __FUNCTION__ + | |
431 | ': channel is not a sequential file') | |
432 | END | |
433 | END Close ; | |
434 | ||
435 | ||
436 | (* | |
437 | Init - | |
438 | *) | |
439 | ||
440 | PROCEDURE Init ; | |
441 | VAR | |
442 | gen: GenDevIF ; | |
443 | BEGIN | |
444 | AllocateDeviceId(did) ; | |
445 | gen := InitGenDevIF(did, doreadchar, dounreadchar, | |
446 | dogeterrno, dorbytes, dowbytes, | |
447 | dowriteln, | |
448 | iseof, iseoln, iserror) ; | |
449 | dev := InitChanDev(streamfile, did, gen) | |
450 | END Init ; | |
451 | ||
452 | ||
453 | BEGIN | |
454 | Init | |
455 | END SeqFile. |