UNSAFE MODULE PathNameStream_ux EXPORTS PathNameStream, PathNameStream_ux; (***************************************************************************) (* Copyright (C) Olivetti 1989 *) (* All Rights reserved *) (* *) (* Use and copy of this software and preparation of derivative works based *) (* upon this software are permitted to any person, provided this same *) (* copyright notice and the following Olivetti warranty disclaimer are *) (* included in any copy of the software or any modification thereof or *) (* derivative work therefrom made by any person. *) (* *) (* This software is made available AS IS and Olivetti disclaims all *) (* warranties with respect to this software, whether expressed or implied *) (* under any law, including all implied warranties of merchantibility and *) (* fitness for any purpose. In no event shall Olivetti be liable for any *) (* damages whatsoever resulting from loss of use, data or profits or *) (* otherwise arising out of or in connection with the use or performance *) (* of this software. *) (***************************************************************************) IMPORT Text, Word; IMPORT IO, IO_impl; IMPORT Stream_ux, Unix, Ustat, Uerror, UnixMutex, Ctypes, M3toC; TYPE T = Stream_ux.T OBJECT OVERRIDES implDescribeError := Error; END; PROCEDURE Error(t: T): Text.T RAISES {}= BEGIN IF t.rc = 0 THEN CASE IO.WhyErrant(t) OF | IO.Fault.Open => (* In the 'ModeOpen' procedure we force the raising of an 'Error' with class 'Errors.Open' for several reasons. Only one reason leavesopen 's.rc' at zero though *) RETURN "not a regular file"; | IO.Fault.Read => (* If 'rc' is zero the Unix read call did not return an error; it must just have returned less characters than expected; as file streams are mapped, this is an error. *) RETURN "file has been truncated"; ELSE END; END; RETURN Stream_ux.Error(t); END Error; PROCEDURE UnixFlags(mode: IO.OpenMode): Ctypes.int RAISES {}= CONST ReadWriteAndCreate = Unix.O_RDWR + Unix.O_CREAT; BEGIN CASE mode OF | IO.OpenMode.Read => RETURN Unix.O_RDONLY; | IO.OpenMode.Write => RETURN Unix.O_WRONLY + Unix.O_CREAT + Unix.O_TRUNC; | IO.OpenMode.Append => RETURN Unix.O_WRONLY + Unix.O_CREAT; | IO.OpenMode.Update => RETURN ReadWriteAndCreate; | IO.OpenMode.WriteAndRead => RETURN ReadWriteAndCreate + Unix.O_TRUNC; | IO.OpenMode.AppendAndRead => RETURN ReadWriteAndCreate; END; END UnixFlags; CONST RW_RW_R__ = Ustat.S_IREAD + Ustat.S_IWRITE + Ustat.S_GREAD + Ustat.S_GWRITE + Ustat.S_OREAD; (* rw-rw-r-- *) PROCEDURE Open( name: Text.T; mode: IO.OpenMode := IO.OpenMode.Update; quiet: BOOLEAN := FALSE) : IO.Stream RAISES {IO.Error} = BEGIN RETURN ModeOpen(name, mode, RW_RW_R__, quiet); END Open; PROCEDURE ModeOpen( name: Text.T; mode: IO.OpenMode := IO.OpenMode.Update; unixMode: Ctypes.int; quiet: BOOLEAN := FALSE) : IO.Stream RAISES {IO.Error}= CONST StartAtZero = IO_impl.AllModes - IO_impl.AppendModes; VAR d: Ctypes.int; rc: Ctypes.int := 0; s: T; statBuf: Ustat.struct_stat; buffer: REF ARRAY OF CHAR := NIL; length: CARDINAL; BEGIN LOCK UnixMutex.errno DO d := Unix.open(M3toC.TtoS(name), UnixFlags(mode), unixMode); IF d < 0 OR Ustat.fstat(d, ADR(statBuf)) < 0 THEN rc := Uerror.errno; END; END; IF rc = Uerror.ENOENT AND quiet THEN RETURN NIL; ELSE s := NEW(T, d := d, rc := rc); END; IF rc = 0 AND Word.And(statBuf.st_mode, Ustat.S_IFREG) # 0 AND (mode IN StartAtZero OR Stream_ux.Seek(s, statBuf.st_size)) THEN length := statBuf.st_size; buffer := NEW(REF ARRAY OF CHAR, statBuf.st_blksize); ELSE (* we have an error; clean up and leave 'buffer' at NIL to force 'IO_impl.Init' to raise an error *) IF d >= 0 THEN EVAL Unix.close(d) END; END; IO_impl.Init(s, buffer, length, mode, name := name); RETURN s; END ModeOpen; BEGIN END PathNameStream_ux.