UNSAFE MODULE StdIO_ux EXPORTS StdIO; (***************************************************************************) (* 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 Thread, Text; IMPORT IO, IO_impl, Stop; IMPORT Ctypes, Ustat, Unix, UnixMutex, Stream_ux; VAR in_g, out_g, err_g: IO.Stream; <*INLINE*> PROCEDURE In(): IO.Stream RAISES {}= BEGIN RETURN in_g END In; <*INLINE*> PROCEDURE Out(): IO.Stream RAISES {}= BEGIN RETURN out_g END Out; <*INLINE*> PROCEDURE Err(): IO.Stream RAISES {}= BEGIN RETURN err_g END Err; <*INLINE*> PROCEDURE StdIn(): IO.Stream RAISES {}= BEGIN RETURN in_g END StdIn; <*INLINE*> PROCEDURE StdOut(): IO.Stream RAISES {}= BEGIN RETURN out_g END StdOut; <*INLINE*> PROCEDURE StdErr(): IO.Stream RAISES {}= BEGIN RETURN err_g END StdErr; TYPE T = Stream_ux.T OBJECT OVERRIDES implClose := Close; implDescribeError := Error; END; PROCEDURE Close(t: T): BOOLEAN RAISES {}= (* fault attempts to close standard streams unless the stream is errant in which case we do nothing but don't complain *) BEGIN RETURN IO.WhyErrant(t) # IO.Fault.None; END Close; PROCEDURE Error(t: T): Text.T RAISES {}= BEGIN IF IO.WhyErrant(t) = IO.Fault.Close AND t.rc = 0 THEN RETURN "Cannot close standard stream"; ELSE RETURN Stream_ux.Error(t); END; (* if *) END Error; EXCEPTION InvalidStandardStream; PROCEDURE Open( d: Ctypes.int; name: Text.T; dontBuffer := FALSE; mode := IO.OpenMode.Write) : T RAISES {} = VAR statBuf: Ustat.struct_stat; BEGIN LOCK UnixMutex.errno DO IF Ustat.fstat(d, ADR(statBuf)) < 0 THEN <* FATAL InvalidStandardStream *> BEGIN RAISE InvalidStandardStream; END; END; END; VAR s := NEW(T, d := d); bufferSize := 1; properties := IO.PropertySet{}; BEGIN IF NOT dontBuffer THEN bufferSize := MAX(statBuf.st_blksize, 256); IF Unix.isatty(d) # 0 THEN (* tty - line buffer output *) properties := properties + IO.PropertySet{IO.Property.LineBuffered}; END; END; WITH buffer = NEW(REF ARRAY OF CHAR, bufferSize) DO <* FATAL IO.Error *> BEGIN IO_impl.Init(s, buffer, IO.UnknownLength, mode, properties, name); END; END; RETURN s; END; END Open; PROCEDURE FlushStdOut() RAISES {}= BEGIN (*IF Thread.TestAcquire(out_g) THEN*) TRY Thread.Acquire(out_g); TRY IO.Flush(out_g); EXCEPT | IO.Error => (* not much can be done at this point *) END; FINALLY Thread.Release(out_g); END; (*END;*) END FlushStdOut; BEGIN in_g := Open(0, "standard input", mode := IO.OpenMode.Read); out_g := Open(1, "standard output"); err_g := Open(2, "standard error", dontBuffer := TRUE); EVAL Stop.Register(Stop.BasicClosure(FlushStdOut)); END StdIO_ux.