1 (* SeqFile.mod implement the ISO SeqFile specification.
3 Copyright (C) 2008-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
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)
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.
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.
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/>. *)
27 IMPLEMENTATION MODULE SeqFile
;
29 FROM RTgen
IMPORT ChanDev
, DeviceType
,
30 InitChanDev
, doLook
, doSkip
, doSkipLook
, doWriteLn
,
31 doReadText
, doWriteText
, doReadLocs
, doWriteLocs
,
34 FROM RTfio
IMPORT doreadchar
, dounreadchar
, dogeterrno
, dorbytes
,
35 dowbytes
, dowriteln
, iseof
, iseoln
, iserror
;
37 FROM IOLink
IMPORT DeviceId
, DeviceTablePtr
, IsDevice
, MakeChan
, UnMakeChan
,
38 DeviceTablePtrValue
, RAISEdevException
, AllocateDeviceId
,
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
;
47 IMPORT FIO
, SYSTEM
, RTio
, errno
, ErrnoCategory
;
55 PROCEDURE look (d
: DeviceTablePtr
;
56 VAR ch
: CHAR; VAR r
: ReadResults
) ;
62 PROCEDURE skip (d
: DeviceTablePtr
) ;
68 PROCEDURE skiplook (d
: DeviceTablePtr
;
69 VAR ch
: CHAR; VAR r
: ReadResults
) ;
71 doSkipLook(dev
, d
, ch
, r
)
75 PROCEDURE lnwrite (d
: DeviceTablePtr
) ;
81 PROCEDURE textread (d
: DeviceTablePtr
;
84 VAR charsRead
: CARDINAL) ;
86 doReadText(dev
, d
, to
, maxChars
, charsRead
)
90 PROCEDURE textwrite (d
: DeviceTablePtr
;
92 charsToWrite
: CARDINAL);
94 doWriteText(dev
, d
, from
, charsToWrite
)
98 PROCEDURE rawread (d
: DeviceTablePtr
;
101 VAR locsRead
: CARDINAL) ;
103 doReadLocs(dev
, d
, to
, maxLocs
, locsRead
)
107 PROCEDURE rawwrite (d
: DeviceTablePtr
;
108 from
: SYSTEM.ADDRESS
;
109 locsToWrite
: CARDINAL) ;
111 doWriteLocs(dev
, d
, from
, locsToWrite
)
115 PROCEDURE getname (d
: DeviceTablePtr
;
116 VAR a
: ARRAY OF CHAR) ;
118 FIO.
GetFileName(RTio.
GetFile(d^.cid
), a
)
122 PROCEDURE flush (d
: DeviceTablePtr
) ;
124 FIO.
FlushBuffer(RTio.
GetFile(d^.cid
))
129 checkOpenErrno - assigns, e, and, res, depending upon file result of opening,
133 PROCEDURE checkOpenErrno (file
: FIO.File
; VAR e
: INTEGER; VAR res
: OpenResults
) ;
135 IF FIO.
IsNoError(file
)
139 e
:= errno.
geterrno()
141 res
:= ErrnoCategory.
GetOpenResults(e
)
146 newCid - returns a ChanId which represents the opened file, name.
147 res is set appropriately on return.
150 PROCEDURE newCid (fname
: ARRAY OF CHAR;
152 VAR res
: OpenResults
;
153 toRead
, toAppend
: BOOLEAN;
154 whichreset
: ResetProc
) : ChanId
;
163 file
:= FIO.
OpenForRandom (fname
, NOT toRead
, NOT FIO.
Exists (fname
))
166 file
:= FIO.
OpenToRead (fname
)
168 file
:= FIO.
OpenToWrite (fname
)
170 checkOpenErrno (file
, e
, res
) ;
172 IF FIO.
IsNoError (file
)
175 RTio.
SetFile (c
, file
) ;
176 p
:= DeviceTablePtrValue (c
, did
) ;
182 doSkipLook
:= skiplook
;
183 doLnWrite
:= lnwrite
;
184 doTextRead
:= textread
;
185 doTextWrite
:= textwrite
;
186 doRawRead
:= rawread
;
187 doRawWrite
:= rawwrite
;
188 doGetName
:= getname
;
189 doReset
:= whichreset
;
195 RETURN( IOChan.
InvalidChan () )
201 Attempts to obtain and open a channel connected to a stored rewindable
202 file of the given name. The write flag is implied; without the raw
203 flag, text is implied. If successful, assigns to cid the identity of
204 the opened channel, assigns the value opened to res, and selects
205 output mode, with the write position at the start of the file (i.e.
206 the file is of zero length). If a channel cannot be opened as required,
207 the value of res indicates the reason, and cid identifies the
211 PROCEDURE OpenWrite (VAR cid
: ChanId
; name
: ARRAY OF CHAR; flags
: FlagSet
;
212 VAR res
: OpenResults
) ;
214 INCL(flags
, ChanConsts.writeFlag
) ;
215 IF NOT (ChanConsts.rawFlag
IN flags
)
217 INCL(flags
, ChanConsts.textFlag
)
219 cid
:= newCid(name
, flags
, res
, FALSE, FALSE, resetWrite
)
224 Attempts to obtain and open a channel connected to a stored rewindable
225 file of the given name. The read and old flags are implied; without
226 the raw flag, text is implied. If successful, assigns to cid the
227 identity of the opened channel, assigns the value opened to res, and
228 selects input mode, with the read position corresponding to the start
229 of the file. If a channel cannot be opened as required, the value of
230 res indicates the reason, and cid identifies the invalid channel.
233 PROCEDURE OpenRead (VAR cid
: ChanId
; name
: ARRAY OF CHAR; flags
: FlagSet
;
234 VAR res
: OpenResults
) ;
236 flags
:= flags
+ ChanConsts.read
+ ChanConsts.old
;
237 IF NOT (ChanConsts.rawFlag
IN flags
)
239 INCL(flags
, ChanConsts.textFlag
)
241 cid
:= newCid(name
, flags
, res
, TRUE, FALSE, resetRead
)
246 OpenAppend - attempts to obtain and open a channel connected
247 to a stored rewindable file of the given name.
248 The write and old flags are implied; without
249 the raw flag, text is implied. If successful,
250 assigns to cid the identity of the opened channel,
251 assigns the value opened to res, and selects output
252 mode, with the write position corresponding to the
253 length of the file. If a channel cannot be opened
254 as required, the value of res indicates the reason,
255 and cid identifies the invalid channel.
258 PROCEDURE OpenAppend (VAR cid
: ChanId
; name
: ARRAY OF CHAR;
259 flags
: FlagSet
; VAR res
: OpenResults
) ;
261 flags
:= flags
+ ChanConsts.write
+ ChanConsts.old
;
262 IF NOT (ChanConsts.rawFlag
IN flags
)
264 INCL (flags
, ChanConsts.textFlag
)
266 cid
:= newCid (name
, flags
, res
, FALSE, TRUE, resetAppend
) ;
269 FIO.
SetPositionFromEnd (RTio.
GetFile (cid
), 0) ;
270 checkErrno (dev
, RTio.
GetDevicePtr (cid
))
276 resetAppend - ensures that +write and -read and seeks to
280 PROCEDURE resetAppend (d
: DeviceTablePtr
) ;
285 flags
:= flags
+ write
- read
;
286 FIO.
SetPositionFromEnd(RTio.
GetFile(cid
), 0) ;
296 PROCEDURE resetRead (d
: DeviceTablePtr
) ;
306 PROCEDURE resetWrite (d
: DeviceTablePtr
) ;
313 IsSeqFile - tests if the channel identified by cid is open to a
314 rewindable sequential file.
317 PROCEDURE IsSeqFile (cid
: ChanId
) : BOOLEAN ;
319 RETURN( (cid #
NIL) AND (IOChan.
InvalidChan() # cid
) AND
320 (IsDevice(cid
, did
)) AND
321 ((ChanConsts.readFlag
IN IOChan.
CurrentFlags(cid
)) OR
322 (ChanConsts.writeFlag
IN IOChan.
CurrentFlags(cid
))) )
327 Reread - if the channel identified by cid is not open
328 to a rewindable sequential file, the exception
329 wrongDevice is raised; otherwise attempts to set
330 the read position to the start of the file, and
331 to select input mode. If the operation cannot
332 be performed (perhaps because of insufficient
333 permissions) neither input mode nor output
337 PROCEDURE Reread (cid
: ChanId
) ;
343 d
:= DeviceTablePtrValue(cid
, did
) ;
345 EXCL(flags
, writeFlag
) ;
348 FIO.
SetPositionFromBeginning(RTio.
GetFile(cid
), 0) ;
351 EXCL(flags
, readFlag
)
355 RAISEdevException(cid
, did
, IOChan.wrongDevice
,
356 'SeqFile.' + __FUNCTION__
+
357 ': channel is not a sequential file')
363 Rewrite - if the channel identified by cid is not open to a
364 rewindable sequential file, the exception wrongDevice
365 is raised; otherwise, attempts to truncate the
366 file to zero length, and to select output mode.
367 If the operation cannot be performed (perhaps
368 because of insufficient permissions) neither input
369 mode nor output mode is selected.
372 PROCEDURE Rewrite (cid
: ChanId
) ;
378 d
:= DeviceTablePtrValue(cid
, did
) ;
380 EXCL(flags
, readFlag
) ;
381 IF writeFlag
IN flags
383 FIO.
SetPositionFromBeginning(RTio.
GetFile(cid
), 0) ;
386 EXCL(flags
, writeFlag
)
390 RAISEdevException(cid
, did
, IOChan.wrongDevice
,
391 'SeqFile.' + __FUNCTION__
+
392 ': channel is not a sequential file')
401 PROCEDURE handlefree (d
: DeviceTablePtr
) ;
408 f
:= RTio.
GetFile(RTio.
ChanId(cid
)) ;
419 Close - if the channel identified by cid is not open to a sequential
420 stream, the exception wrongDevice is raised; otherwise
421 closes the channel, and assigns the value identifying
422 the invalid channel to cid.
425 PROCEDURE Close (VAR cid
: ChanId
) ;
429 UnMakeChan(did
, cid
) ;
430 cid
:= IOChan.
InvalidChan()
432 RAISEdevException(cid
, did
, IOChan.wrongDevice
,
433 'SeqFile.' + __FUNCTION__
+
434 ': channel is not a sequential file')
447 AllocateDeviceId(did
) ;
448 gen
:= InitGenDevIF(did
, doreadchar
, dounreadchar
,
449 dogeterrno
, dorbytes
, dowbytes
,
451 iseof
, iseoln
, iserror
) ;
452 dev
:= InitChanDev(streamfile
, did
, gen
)