DIRECTORY UXIO, Atom USING [PutPropOnList], Basics USING [UnsafeBlock], BasicTime USING [GMT], HostTime USING [ExtendedGMTFromHostTime], IO USING [STREAM, CreateStream, CreateStreamProcs, EndOfStream, StreamProcs], List USING [Assoc, AList], ProcessProps USING [GetPropList], RefText USING [AppendChar, AppendRope, ObtainScratch, ReleaseScratch], Rope USING [Concat, Equal, Fetch, Flatten, IsEmpty, ROPE, Length], UnixEnviron USING [GetEnv], UnixErrno USING [GetErrno, Errno], UnixSysCalls USING [Close, FStat, FSync, LSeek, Open, Read, Unlink, Write], UnixTypes USING [CHARPtr, FD, FileFlags, Flag, Mode, RES, Stat]; UXIOImpl: CEDAR PROGRAM IMPORTS Atom, HostTime, IO, List, ProcessProps, Rope, RefText, UnixEnviron, UnixErrno, UnixSysCalls EXPORTS UXIO SHARES IO ~ BEGIN ROPE: TYPE = Rope.ROPE; GMT: TYPE = BasicTime.GMT; OpenFile: TYPE = UXIO.OpenFile; FD: TYPE = UnixTypes.FD; RES: TYPE = UnixTypes.RES; CHARPtr: TYPE = UnixTypes.CHARPtr; Error: PUBLIC ERROR [error: UXIO.ErrorDesc] = CODE; StreamData: TYPE ~ RECORD [ fd: FD, fileName: ROPE, isReset: BOOL ¬ FALSE -- used only as hack in standard input stream case ]; stdInputProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[ variety: $input, class: $UXStdIO, getChar: GetChar, endOf: EndOfInput, reset: ResetInput, charsAvail: InputCharsAvail ]; stdOutputProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[ variety: $output, class: $UXStdIO, putChar: PutChar, unsafePutBlock: UnsafePutBlock ]; fileInputProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[ variety: $input, class: $UXFileIO, getChar: GetChar, unsafeGetBlock: UnsafeGetBlock, endOf: EndOf, backup: Backup, getIndex: GetIndex, setIndex: SetIndex, getLength: GetLength, close: Close ]; fileOutputProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[ variety: $output, class: $UXFileIO, putChar: PutChar, unsafePutBlock: UnsafePutBlock, getIndex: GetIndex, getLength: GetLength, setIndex: SetIndex, flush: Flush, close: Close ]; CreateStandardStream: PUBLIC PROC [kind: UXIO.Kind] RETURNS [stream: IO.STREAM] ~ { SELECT kind FROM input => stream ¬ IO.CreateStream[streamProcs: stdInputProcs, streamData: NEW[StreamData ¬ [stdin, NIL]]]; output => stream ¬ IO.CreateStream[streamProcs: stdOutputProcs, streamData: NEW[StreamData ¬ [stdout, NIL]]]; trace => stream ¬ IO.CreateStream[streamProcs: stdOutputProcs, streamData: NEW[StreamData ¬ [stdtrc, NIL]]]; ENDCASE; }; magicFlags: ARRAY UXIO.Access OF UnixTypes.FileFlags ~ [ read: [access: RDONLY], -- read only append: [creat: true, append: true, access: WRONLY], -- create, append, write only write: [trunc: true, creat: true, access: WRONLY] -- truncate, create, write only ]; Flag: TYPE ~ UnixTypes.Flag; Solaris5FileFlags: TYPE ~ MACHINE DEPENDENT RECORD [ fill0: [0..0FFFFFH] ¬ 0, fill1: Flag ¬ false, excl: Flag ¬ false, -- error if already created trunc: Flag ¬ false, -- truncate to zero length creat: Flag ¬ false, -- create if nonexistant [sic] nonblk: Flag ¬ false, -- signal pgrp when data ready fill2: [0..7] ¬ 0, append: Flag ¬ false, -- append on each write ndelay: Flag ¬ false, -- non-blocking reads access: MACHINE DEPENDENT { RDONLY(0), WRONLY(1), RDWR(2), (3)} ]; solaris5MagicFlags: ARRAY UXIO.Access OF Solaris5FileFlags ~ [ read: [access: RDONLY], -- read only append: [creat: true, append: true, access: WRONLY], -- create, append, write only write: [trunc: true, creat: true, access: WRONLY] -- truncate, create, write only ]; CreateFileStream: PUBLIC PROC [name: Rope.ROPE, access: UXIO.Access, mode: UnixTypes.Mode ¬ UXIO.defaultMode] RETURNS [stream: IO.STREAM] ~ { fileFlags: UnixTypes.FileFlags ~ LOOPHOLE[solaris5MagicFlags[access]]; fd: FD ~ RopeOpen[name, fileFlags, mode]; stream ¬ IO.CreateStream[ streamProcs: IF access=read THEN fileInputProcs ELSE fileOutputProcs, streamData: NEW[StreamData ¬ [fd, name]] ]; stream.propList ¬ Atom.PutPropOnList[stream.propList, $FileName, Rope.Flatten[name]]; stream.propList ¬ Atom.PutPropOnList[stream.propList, $FD, NEW[FD ¬ fd]]; }; charsPerWord: CARD ~ BITS[WORD]/BITS[CHAR]; WordOfPackedChars: TYPE ~ PACKED ARRAY [0..charsPerWord) OF CHAR; GetChar: PROC [self: IO.STREAM] RETURNS [CHAR] ~ { data: REF StreamData ~ NARROW[self.streamData]; charsRead: INT; chars: WordOfPackedChars; -- @chars points to chars[0] TRUSTED {charsRead ¬ UnixSysCalls.Read[data.fd, LOOPHOLE[@chars], 1]}; IF charsRead = 0 THEN { ERROR IO.EndOfStream[self]; }; IF charsRead < 0 THEN { errno: UnixErrno.Errno ¬ UnixErrno.GetErrno[]; ERROR Error[[client, NIL, "read failed to return any bytes in GetChar"]]; }; RETURN[chars[0]]; }; EndOfInput: PROC [self: IO.STREAM] RETURNS [BOOL] = { backing: IO.STREAM ¬ self.backingStream; IF backing # NIL THEN RETURN[backing.streamProcs.endOf[backing]] ELSE RETURN[FALSE]; -- not a concept for stdin }; PutChar: PROC [self: IO.STREAM, char: CHAR] ~ { data: REF StreamData ~ NARROW[self.streamData]; charsWritten: INT; chars: WordOfPackedChars; -- @chars points to chars[0] chars[0] ¬ char; TRUSTED {charsWritten ¬ UnixSysCalls.Write[data.fd, LOOPHOLE[@chars], 1]}; }; UnsafeGetBlock: UNSAFE PROC [self: IO.STREAM, block: Basics.UnsafeBlock] RETURNS [nBytesRead: INT] ~ UNCHECKED { data: REF StreamData ~ NARROW[self.streamData]; pointer: CHARPtr ~ LOOPHOLE[LOOPHOLE[block.base, POINTER]+CARD[block.startIndex]]; -- byte address! n: INT ~ UnixSysCalls.Read[data.fd, pointer, CARD[block.count]]; IF n<0 THEN { errno: UnixErrno.Errno ¬ UnixErrno.GetErrno[]; ERROR Error[[client, NIL, "read failed to return any bytes in UnsafeGetBlock"]]; }; RETURN[n]; }; UnsafePutBlock: PROC [self: IO.STREAM, block: Basics.UnsafeBlock] ~ { data: REF StreamData ~ NARROW[self.streamData]; start: INT ¬ CARD[block.startIndex]; stop: INT ~ start+CARD[block.count]; WHILE start probelms with SetIndex a grand hack: helps out the command tool when running with the standard input stream. Nobody else uses it, I hope. DirPointer: TYPE ~ POINTER TO READONLY DirectStruct; DirProc: TYPE ~ PROC [d: DirPointer] RETURNS [quit: BOOL _ FALSE]; DirEnumerate: PROC [fd: FD, proc: DirProc] ~ TRUSTED { nbytes: INT ~ GetStat[fd].blksize; scratch: REF TEXT ~ RefText.ObtainScratch[nbytes]; buf: POINTER ~ LOOPHOLE[scratch, POINTER]+SIZE[TEXT[0]]; base: INT; DO cc: INT ~ Xgetdirentries[fd, buf, nbytes, @base]; index: INT _ 0; IF cc<0 THEN ERROR Error; IF cc=0 THEN GOTO Quit; WHILE index NULL; ENDLOOP; RefText.ReleaseScratch[scratch]; }; EnumerateForNames: PUBLIC PROC [dir: Rope.ROPE, proc: UXIOExtras.NameProc] ~ { fd: FD ~ RopeOpen[dir, magicFlags[read]]; dirProc: DirProc ~ TRUSTED { i: NAT _ 0; p: SAFE PROC RETURNS [c: CHAR] ~ TRUSTED { c _ d.name[i]; i _ i+1 }; rope: Rope.ROPE ~ Rope.FromProc[d.namlen, p]; RETURN[proc[rope]]; }; DirEnumerate[fd, dirProc]; }; Handling of working directories is as in UFSImpl.mesa (not used to Returns the actual working directory implied by wDir. If wDir is empty, gets the current $WorkingDirectory property from the process property list; if that too is empty, uses the default working directory []<>. The result is expressed in brackets syntax, with a final "/". CHauser February 16, 1989: added mode parameter to CreateFileStream and RopeOpen. Moved defaultMode to the interface. ΚB–(cedarcode) style•NewlineDelimiter ™šœ ™ Icodešœ Οeœ7™BK™-K™(K™"K™7K™+K™#K™%J™—šΟk ˜ Kšžœ˜Kšœžœ˜Kšœžœ˜Kšœ žœžœ˜Kšœ žœ˜)Kšžœžœžœ=˜MKšœžœ˜Kšœ žœ˜!Kšœžœ9˜FKšœžœ*žœ ˜BKšœ žœ ˜Kšœ žœ˜"Kšœ žœ9˜KKšœ žœ žœžœ˜@K˜—K˜šΟnœžœž˜KšžœžœI˜cKšžœž˜ Kšžœž˜ Kšœžœ˜K˜—Kšžœžœžœ˜Kšžœžœ žœ˜Kšœ žœžœ ˜Kšžœžœ žœ˜Kšžœžœ žœ˜Kšœ žœ˜"K˜KšŸœžœžœžœ˜3K˜šœ žœžœ˜Kšœžœ˜Kšœ ž˜Kšœ žœžœΟc2˜HKšœ˜K˜—šœžœžœžœ˜9Kšœ!˜!Kšœ$˜$K˜.Kšœ˜K˜—šœžœžœžœ˜:Kšœ"˜"Kšœ˜Kšœ˜Kšœ˜K˜—šœžœžœžœ˜:Kšœ"˜"K˜OKšœJ˜JKšœ˜K˜—šœžœžœžœ˜;Kšœ#˜#K˜1KšœX˜XKšœ˜K˜—šŸœžœžœžœžœ žœžœ˜Sšžœž˜šœžœ*˜>Kšœ žœžœ˜,—šœžœ*˜?Kšœ žœžœ˜-—šœžœ*˜>Kšœ žœžœ˜-—Kšžœ˜—K˜K˜—šœ žœžœžœ˜8Kšœžœ  ˜$Kšœ,žœ ˜RKšœ*žœ ˜QK˜K˜—šœžœ˜K˜—š œœ žœžœž œžœ˜4K˜K˜Kšœ ˜/Kšœ ˜/Kšœ ˜3Kšœ ˜4K˜Kšœ ˜-Kšœ ˜+Kš œžœž œžœžœžœ ˜?Kšœ˜K˜—š œœœ žœžœžœ˜>Kšœžœ  ˜$Kšœ,žœ ˜RKšœ*žœ ˜QK˜K˜—šŸœžœžœ žœ žœ žœžœ žœžœ˜Kšœžœ,™2Kšœœ žœ˜FKšœžœ#˜)šœ žœ˜Kšœ žœ žœžœ˜EKšœ žœ˜(Kšœ˜—KšœU˜UKšœ;žœžœ˜IK˜K˜—Kš œžœžœžœžœžœ˜+š œžœžœžœžœžœ˜AKšœ)žœ žœ™VK˜—š Ÿœžœžœžœžœžœ˜2Kšœžœžœ˜/Kšœ žœ˜Kšœ ˜6Kšžœ)žœ˜Fšžœžœž˜Kšžœžœ˜K˜—šžœžœž˜Kšœ.˜.KšžœD˜IK˜—Kšžœ ˜K˜K˜—š Ÿ œžœž œžœžœ˜5Kšœ ž œ˜(Kšžœ žœžœžœ$žœžœžœ ˜pK˜K˜—š Ÿœžœžœžœžœ˜/Kšœžœžœ˜/Kšœžœ˜Kšœ ˜6K˜Kšžœ-žœ˜JK˜K˜—šŸœžœžœžœžœžœžœž œ˜pKšœžœžœ˜/Kš œžœžœ žœžœ ˜cKšœžœ'žœ˜@šžœžœž˜ Kšœ.˜.KšžœK˜PK˜—Kšžœ˜ K˜K˜—šŸœžœžœžœ ˜EKšœžœžœ˜/Kšœžœžœ˜$Kšœžœ žœ˜$šžœ ž˜Kšœžœžœ žœ  ˜RKšœžœ˜Kšžœ:˜Ašžœžœ˜ Kšœ.˜.KšžœK˜PK˜—K˜Kšžœ˜—K˜K˜—š Ÿœžœžœžœžœžœ˜2Kšœžœžœ˜/Kšœžœ)˜3šžœ žœž˜Kšœ.˜.Kšžœ2˜7K˜—Kšžœ˜K˜K˜—š Ÿœžœžœžœ žœ˜0Kšœžœžœ˜/Kšœ žœ,˜9šžœ žœž˜Kšœ.˜.Kšžœ2˜7K˜—K˜K˜—š Ÿœžœžœžœžœ˜AKšœžœ!˜,šžœžœ˜Kšœ.˜.Kšžœ1˜6K˜—K˜K˜—š Ÿ œžœžœžœžœžœ˜3Kšœžœžœ˜/Kšžœ˜K˜K˜—š Ÿœžœžœžœžœžœ˜0K™$Kšœžœžœ˜/Kšœžœ˜"Kšœžœ)˜3šžœ žœ˜Kšœ.˜.Kšžœ/˜4K˜—Kšžœžœ ˜K˜K˜—š Ÿœžœžœžœžœ˜.K™=Kšœžœžœ˜/Kšœžœ*˜4šžœ žœž˜Kšœ.˜.Kšžœ0˜5K˜—K˜K˜—šŸœžœžœžœ˜!Kšœžœžœ˜/Kšœžœ˜*šžœžœž˜Kšœ.˜.Kšžœ/˜4K˜—K˜K˜—š Ÿœžœžœžœ žœ˜.Kšœžœžœ˜/Kšœžœ˜*šžœžœž˜Kšœ.˜.Kšžœ&˜+K˜—K˜K˜—šŸ œžœžœžœ˜&Kšœžœžœ˜/Kšœžœ˜K˜K˜—šŸœžœžœžœžœžœžœ˜DK™sKšœžœžœ˜/šžœžœ˜Kšœžœ˜Kšžœ˜ K˜—Kšžœžœžœžœ˜K˜K˜K˜—šŸœž œ žœ˜)K˜K˜—K˜šŸœž œž œžœ˜HKšœžœžœ˜/Kšžœžœ+˜6K˜—šŸ œž œžœžœ˜PKšœžœžœ˜$KšœR˜RK˜K˜—šŸœž œžœ ž œ˜HKšœžœžœ˜$K˜K˜—˜K˜—Kš œ žœžœžœžœ™4Kš œ žœžœžœžœžœ™BšŸ œžœžœžœ™6Kšœžœ™"Kšœ žœžœ!™2Jš œžœžœ žœžœžœ™8Jšœžœ™ šž™Jšœžœ*™1Jšœžœ™Jšžœžœžœ™Jšžœžœžœ™šžœ ž™Jšœžœ ™$Jšžœ žœžœ™J™Jšžœ™—Jšžœ žœ™Jšžœ™—J™ K™K™—šŸœžœžœ žœ ™NKšœžœ#™)šœžœ™Kš œžœ žœžœžœžœžœ™PKšœ žœ™-Kšžœ ™K™—K™K™K™—K˜K™CIcode2šœ žœ˜"š Ÿ œžœžœžœ žœ˜;š žœžœžœžœžœ˜OKšžœ.žœ ˜?—Kšœ˜K˜—š Ÿœžœžœžœžœžœ˜4J™’šžœžœ˜Lšœ2˜2šžœ+žœž˜:Lšœžœ˜Lšžœ˜—L˜—Kšžœžœ˜3Kšžœ˜ Kšœ˜K˜—šŸœžœžœ žœ˜2Kšžœ.˜4K˜K˜—š Ÿœžœ žœ4žœžœ˜gKšžœžœžœžœ˜Qšžœ˜Kšœžœ˜&Kšœ žœžœ6˜GKšœ žœžœH˜ZKš œžœžœ žœžœžœ˜KKšœžœ˜ Kšžœ:˜AK˜ šžœžœ˜Kšœ.˜.Kšžœ1˜6K˜—Kšžœ ˜K˜—K˜K˜—šŸ œžœ žœ˜&Kšžœžœžœ1˜Ršžœ˜Kšœžœ˜&Kšœ žœžœ6˜GKšœ žœžœH˜ZKš œžœžœ žœžœžœ˜KKšœžœ˜ Kšžœ/˜6K˜ šžœžœ˜Kšœ.˜.Kšžœ5˜:K˜—K˜—K˜K˜—Kšžœ˜K˜Kšœv™v—…—+^D