<> <> <> <> <> <> DIRECTORY Atom USING [MakeAtom, PutProp], Basics USING [LowByte], Convert USING [RealFromRope, RopeFromReal], FS USING [Error, StreamOpen], IO, PascalBasic, PascalNoviceFiles, PrincOpsUtils USING [LongCopy], Real USING [DefaultSinglePrecision], RefText USING [TrustTextAsRope], Rope USING [Cat, Equal, Fetch, FromChar, Length], ViewerIO USING [CreateViewerStreams]; PascalNoviceFilesImpl: CEDAR PROGRAM IMPORTS Atom, Basics, Convert, FS, IO, PascalBasic, PrincOpsUtils, RefText, Rope, ViewerIO EXPORTS PascalNoviceFiles = BEGIN OPEN PascalBasic, PascalNoviceFiles; <> Control: PascalTextFile; Input: PUBLIC PascalTextFile; Output: PUBLIC PascalTextFile; Tty: PUBLIC PascalTextFile; openFiles: MesaFilePtr _ NIL; nilStream: IO.STREAM _ IO.CreateStream[ streamProcs: IO.CreateStreamProcs[ variety: inputOutput, class: $NilStream, getChar: NilGetChar, putChar: NilPutChar, endOf: NilEndOf, unsafeGetBlock: NilUnsafeGetBlock, unsafePutBlock: NilUnsafePutBlock, close: NilClose], streamData: NIL]; anonNo, ttyNo: PascalInteger _ 0; <

> <> PrepareForTextRead: UNSAFE PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN IF file.baseFile = NIL OR file.baseFile.in = NIL THEN PascalAttachFile[file: @file.baseFile, dir: in, type: text]; END; PrepareForTextWrite: UNSAFE PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN IF file.baseFile = NIL OR file.baseFile.out = NIL THEN PascalAttachFile[file: @file.baseFile, dir: out, type: text]; END; PascalTextBREAK: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN NULL; -- !! Should do some sort of flush END; PascalTextGET: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN IF NOT file.validElement THEN PascalTextFinishGet[file]; file.validElement _ FALSE; END; PascalTextElement: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [PascalChar] = TRUSTED BEGIN IF NOT file.validElement THEN PascalTextFinishGet[file]; RETURN[file.element]; END; PascalTextFinishGet: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN PrepareForTextRead[file]; file.element _ file.baseFile.in.GetChar[ ! IO.EndOfStream => GOTO EOF]; file.eoln _ FALSE; SELECT file.element FROM IN ['A..'Z] => IF NOT file.control.readUpperCase THEN file.element _ file.element - 'A + 'a; IN ['a..'z] => IF NOT file.control.readLowerCase THEN file.element _ file.element - 'a + 'A; '\N --CR-- => { file.eoln _ TRUE; file.lineNo _ file.lineNo + 1; file.element _ ' }; IN [0C..' ) => IF NOT file.control.readAllControlChars THEN file.element _ ' ; 'Z - 100B --Ctrl-Z-- => GOTO EOF; ENDCASE => NULL; file.validElement _ TRUE; EXITS EOF => { file.baseFile.eof _ file.eoln _ file.validElement _ TRUE; file.element _ ' }; END; PascalTextPUT: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN c: PascalChar; PrepareForTextWrite[file]; SELECT file.element FROM IN ['A..'Z] => IF NOT file.control.writeUpperCase THEN c _ file.element - 'A + 'a; IN ['a..'z] => IF NOT file.control.writeLowerCase THEN c _ file.element - 'a + 'A; '\N --CR-- => c _ file.element; IN [0C..' ) => IF NOT file.control.writeAllControlChars THEN file.element _ ' ; ENDCASE => c _ file.element; file.baseFile.out.PutChar[c]; END; PascalTextRESET: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN PrepareForTextRead[file]; file.baseFile.in.Reset[]; file.baseFile.eof _ FALSE; file.eoln _ TRUE; file.lineNo _ 1; file.element _ ' ; file.validElement _ FALSE; END; PascalTextREWRITE: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN PrepareForTextWrite[file]; file.baseFile.out.Reset[]; file.baseFile.out.SetLength[0 ! IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}]; file.baseFile.eof _ file.baseFile.in # nilStream; END; PascalTextPAGE: PUBLIC PROCEDURE [file: PascalTextFilePtr] = BEGIN PascalWriteLn[file: file]; PascalWriteChar[file: file, item: '\F --form feed--]; PascalWriteLn[file: file] END; PascalTextEOF: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [BOOLEAN] = TRUSTED BEGIN IF NOT file.validElement THEN PascalTextFinishGet[file]; RETURN[file.baseFile.eof] END; PascalTextEOLN: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [BOOLEAN] = TRUSTED BEGIN IF NOT file.validElement THEN PascalTextFinishGet[file]; RETURN[file.eoln] END; <> PascalBREAK: PUBLIC PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER] = {NULL}; -- !! Should be some form of Flush PascalGET: PUBLIC UNSAFE PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --] = UNCHECKED BEGIN PrepareForRead[file]; IF length = 1 THEN element^ _ file.in.GetChar[ ! IO.EndOfStream => {file.eof _ TRUE; CONTINUE}] ELSE IF length # file.in.UnsafeGetBlock[[base: element, startIndex: 0, count: length]] THEN file.eof _ TRUE; END; PascalPUT: PUBLIC PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --] = TRUSTED BEGIN PrepareForWrite[file]; IF length = 1 THEN file.out.PutChar[LOOPHOLE[Basics.LowByte[LOOPHOLE[element^]]]] ELSE file.out.UnsafePutBlock[[base: element, startIndex: 0, count: length]]; END; PascalRESET: PUBLIC UNSAFE PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER -- TO ARRAY[0..length) OF UNSPECIFIED --] = UNCHECKED BEGIN PrepareForRead[file]; file.in.SetIndex[0]; file.eof _ FALSE; PascalGET[file, length, element]; END; PascalREWRITE: PUBLIC PROCEDURE [ file: PascalFilePtr, length: CARDINAL _ 0, element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED -- _ NIL] = TRUSTED BEGIN PrepareForWrite[file]; file.out.Reset[]; file.out.SetLength[0 ! IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}]; file.eof _ TRUE; END; PascalRead, PascalReadLong: PUBLIC UNSAFE PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --, item: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --] = UNCHECKED BEGIN IF length = 1 THEN item^ _ element^ ELSE PrincOpsUtils.LongCopy[from: element, nwords: length/2, to: item]; PascalGET[file: file, length: length, element: element]; END; PascalWrite, PascalWriteLong: PUBLIC UNSAFE PROCEDURE [ file: PascalFilePtr, length: CARDINAL, element: LONG POINTER TO -- ARRAY[0..length/2) OF -- UNSPECIFIED, item: LONG POINTER TO -- ARRAY[0..length/2) OF -- UNSPECIFIED] = UNCHECKED BEGIN IF length = 1 THEN element^ _ item^ ELSE PrincOpsUtils.LongCopy[from: item, nwords: length/2, to: element]; PascalPUT[file: file, length: length, element: element]; END; PascalEOF: PUBLIC PROCEDURE [file: PascalFilePtr] RETURNS [BOOLEAN] = TRUSTED { RETURN[IF file^ = NIL THEN TRUE ELSE file.eof]}; <> PascalReadLn: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN WHILE NOT PascalTextEOLN[file] DO PascalTextGET[file] ENDLOOP; PascalTextGET[file]; END; PascalWriteLn: PUBLIC PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN PrepareForTextWrite[file]; file.baseFile.out.PutChar[('\N -- CR -- )]; IF file.baseFile.in = nilStream THEN file.element _ ' ; END; PascalReadInteger: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [PascalInteger] = TRUSTED BEGIN PrepareForTextRead[file]; SkipBlanks[file]; SELECT file.element FROM '- => {PascalTextGET[file]; RETURN[-ReadDecimal[file].n]}; '+ => {PascalTextGET[file]; RETURN[ReadDecimal[file].n]}; ENDCASE => RETURN[ReadDecimal[file].n]; END; SkipBlanks: PROCEDURE [file: PascalTextFilePtr] = TRUSTED BEGIN WHILE NOT PascalTextEOF[file] AND (SELECT file.element FROM '-, '+, IN ['0..'9], '., IN ['a..'z], IN ['A..'Z] => FALSE, ENDCASE => TRUE) DO PascalTextGET[file] ENDLOOP; END; ReadDecimal: PROCEDURE [file: PascalTextFilePtr] RETURNS [n, digitCount: PascalInteger] = TRUSTED BEGIN n _ 0; digitCount _ 0; IF NOT PascalTextEOF[file] AND file.element NOT IN ['0..'9] THEN SIGNAL NumericInputError; WHILE file.element IN ['0..'9] DO n _ 10*n + (file.element - '0); digitCount _ digitCount + 1; PascalTextFinishGet[file]; ENDLOOP; END; PascalWriteInteger: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: PascalInteger, fieldMinLength: PascalInteger _ -1] = TRUSTED BEGIN sayMinus: BOOLEAN _ FALSE; digits: ARRAY [0..15] OF [0..9]; nDigits: [0..15] _ 0; i: PascalInteger; stream: IO.STREAM; PrepareForTextWrite[file]; stream _ file.baseFile.out; IF NOT fieldMinLength IN [0..1] THEN stream.PutChar[' ]; IF sayMinus _ item < 0 THEN { item _ -item; fieldMinLength _ fieldMinLength - 1}; IF item = 0 THEN {digits[0] _ 0; nDigits _ 1} ELSE WHILE item # 0 DO digits[nDigits] _ item MOD 10; nDigits _ nDigits + 1; item _ item/10; ENDLOOP; FOR i IN [1..fieldMinLength - nDigits] DO stream.PutChar[' ] ENDLOOP; IF sayMinus THEN stream.PutChar['-]; FOR i DECREASING IN [0..nDigits) DO stream.PutChar['0 + digits[i]] ENDLOOP; IF file.baseFile.in = nilStream THEN file.element _ '0 + digits[0]; END; PascalReadReal: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [PascalReal] = TRUSTED BEGIN s: REF TEXT _ NEW[TEXT[50]]; s.length _ 0; PrepareForTextRead[file]; SkipBlanks[file]; WHILE (SELECT file.element FROM IN ['a..'z], IN ['A..'Z], '+, '-, '., IN ['0..'9] => TRUE, ENDCASE => FALSE) DO s[s.length] _ file.element; s.length _ s.length + 1; PascalTextFinishGet[file]; ENDLOOP; RETURN[Convert.RealFromRope[RefText.TrustTextAsRope[s]]]; END; PascalWriteReal: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: PascalReal, fieldMinLength, fracLength: PascalInteger _ -1] = TRUSTED BEGIN shortFracLength: INTEGER _ fracLength; PrepareForTextWrite[file]; IF NOT fieldMinLength IN [0..1] THEN file.baseFile.out.PutChar[' ]; PascalWriteString[file, Convert.RopeFromReal[ from: item, precision: IF fracLength < 0 THEN Real.DefaultSinglePrecision ELSE shortFracLength], fieldMinLength]; END; PascalReadChar: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [PascalChar] = TRUSTED BEGIN c: PascalChar; PrepareForTextRead[file]; c _ PascalTextElement[file]; PascalTextGET[file]; RETURN[c]; END; PascalWriteChar: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: PascalChar, fieldMinLength: PascalInteger _ -1] = TRUSTED BEGIN i: PascalInteger; PrepareForTextWrite[file]; FOR i IN [1..fieldMinLength) DO file.baseFile.out.PutChar[' ] ENDLOOP; IF fieldMinLength#0 THEN BEGIN IF file.baseFile.in = nilStream THEN file.baseFile.out.PutChar[item]; file.element _ item; END; END; PascalReadBoolean: PUBLIC PROCEDURE [file: PascalTextFilePtr] RETURNS [PascalBoolean] = TRUSTED BEGIN b: PascalBoolean; PrepareForTextRead[file]; SkipBlanks[file]; SELECT file.element FROM 'T, 't => b _ TRUE; 'F, 'f => b _ FALSE; ENDCASE => {SIGNAL NumericInputError; b _ FALSE}; WHILE (SELECT file.element FROM IN ['a..'z], IN ['A..'Z] => TRUE, ENDCASE => FALSE) DO PascalTextFinishGet[file] ENDLOOP; RETURN[b]; END; PascalWriteBoolean: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: PascalBoolean, fieldMinLength: PascalInteger _ -1] = TRUSTED BEGIN IF NOT fieldMinLength IN [0..1] THEN PascalWriteChar[file, ' ]; PascalWriteString[file, IF item THEN "TRUE" ELSE "FALSE", fieldMinLength]; END; PascalReadArrayOfChar, PascalReadLongArrayOfChar: PUBLIC UNSAFE PROCEDURE [ file: PascalTextFilePtr, item: CharArrayPtr, arrayBound: PascalInteger] = UNCHECKED BEGIN v: CharArrayConcretePtr _ item; i: PascalInteger; PrepareForTextRead[file]; FOR i IN [1..arrayBound] DO v[i] _ PascalTextElement[file]; PascalTextGET[file]; ENDLOOP; END; PascalWriteArrayOfChar, PascalWriteLongArrayOfChar: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: CharArrayPtr, arrayBound: PascalInteger, fieldMinLength: PascalInteger _ -1] = TRUSTED BEGIN v: CharArrayConcretePtr _ LOOPHOLE[item]; i, arrayLim: PascalInteger; PrepareForTextWrite[file]; FOR i IN [arrayBound..fieldMinLength) DO file.baseFile.out.PutChar[' ] ENDLOOP; arrayLim _ IF fieldMinLength < 0 THEN arrayBound ELSE MIN[fieldMinLength, arrayBound]; FOR i IN [1..arrayLim] DO file.baseFile.out.PutChar[v[i]] ENDLOOP; IF file.baseFile.in = NIL AND ((fieldMinLength < 0 AND arrayLim > 0) OR fieldMinLength>0) THEN file.element _ IF arrayLim > 0 THEN v[arrayLim] ELSE ' ; END; ReadString: PRIVATE PROCEDURE [file: PascalTextFilePtr] RETURNS [r: ROPE]= TRUSTED BEGIN PrepareForTextRead[file]; IF file.baseFile.in = NIL THEN PascalTextRESET[file]; r _ ""; WHILE NOT PascalTextEOLN[file] AND NOT file.baseFile.eof DO r _ Rope.Cat[r, Rope.FromChar[file.element]]; PascalTextGET[file]; ENDLOOP; END; PascalWriteString, PascalWriteLongString: PUBLIC PROCEDURE [ file: PascalTextFilePtr, item: ROPE, fieldMinLength: PascalInteger _ -1] = TRUSTED BEGIN i, len, stringLim: PascalInteger; PrepareForTextWrite[file]; len _ item.Length[]; FOR i IN [len..fieldMinLength) DO file.baseFile.out.PutChar[' ] ENDLOOP; stringLim _ IF fieldMinLength < 0 THEN len ELSE MIN[fieldMinLength, len]; FOR i IN [0..stringLim) DO file.baseFile.out.PutChar[Rope.Fetch[item, i]] ENDLOOP; IF file.baseFile.in = NIL AND ((fieldMinLength < 0 AND stringLim > 0) OR fieldMinLength>0) THEN file.element _ IF stringLim > 0 THEN Rope.Fetch[item, stringLim-1] ELSE ' ; END; <

> <<(and hence, intended to be called as external procedures by the Pascal>> <> <> PascalCleanupFiles: PUBLIC PROCEDURE [] = BEGIN ENABLE IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}; FOR f: MesaFilePtr _ openFiles, f.openFileLink WHILE f#NIL DO IF f.in # NIL THEN f.in.Flush[]; IF f.out # NIL THEN f.out.Flush[]; IF f.inSource # NIL THEN f.inSource.Flush[]; IF f.inSource2 # NIL THEN f.inSource2.Flush[]; IF f.outDest # NIL THEN f.outDest.Flush[]; IF f.outDest2 # NIL THEN f.outDest2.Flush[]; ENDLOOP; END; CloseMesaFile: PROCEDURE [f: MesaFilePtr] = BEGIN IF f.in # NIL THEN {f.in.Close[]; f.in _ NIL}; IF f.out # NIL THEN {f.out.Close[]; f.out _ NIL}; IF f.inSource # NIL THEN {f.inSource.Close[]; f.inSource _ NIL}; IF f.inSource2 # NIL THEN {f.inSource2.Close[]; f.inSource2 _ NIL}; IF f.outDest # NIL THEN {f.outDest.Close[]; f.outDest _ NIL}; IF f.outDest2 # NIL THEN {f.outDest2.Close[]; f.outDest2 _ NIL}; END; PascalInventFileName: PUBLIC PROCEDURE [name: ROPE _ NIL] RETURNS [PascalFile] = BEGIN openFiles _ z.NEW[MesaFile _ [name: name, openFileLink: openFiles]]; RETURN[LOOPHOLE[openFiles]]; END; -- end of PascalInventFileName PascalAttachFile: PUBLIC PROCEDURE [ file: PascalFilePtr, dir: PascalFileDirection _ in, type: PascalFileType _ text] = TRUSTED BEGIN name: ROPE _ NIL; mFile: MesaFilePtr; RequestFileName: PROCEDURE[] = TRUSTED BEGIN PascalWriteLn[file: @Control]; PascalWriteString[file: @Control, item: "** File name = "]; name _ ReadString[file: @Control]; PascalReadLn[file: @Control]; END; BEGIN -- for EXITS IF file^ = NIL THEN {RequestFileName[]; file^ _ PascalInventFileName[name]} ELSE name _ file.name; <> <> <> mFile _ LOOPHOLE[file^]; Atom.PutProp[Atom.MakeAtom[name], $PascalFile, mFile]; CloseMesaFile[mFile]; SELECT TRUE FROM Rope.Equal[s1: name, s2: "Tty", case: FALSE] => BEGIN h: IO.STREAM _ IO.ROS[]; h.Put[[rope["PascalTty"]], [integer[ttyNo]]]; name _ h.RopeFromROS[]; h.Close[]; ttyNo _ ttyNo+1; GOTO UseWindow; END; Rope.Equal[s1: name, s2: "Nil", case: FALSE] => {mFile.in _ mFile.out _ nilStream}; ENDCASE => BEGIN IF Rope.Length[name]=0 THEN BEGIN h: IO.STREAM _ IO.ROS[]; h.Put[[rope["PascalAnonymous"]], [integer[anonNo]]]; name _ h.RopeFromROS[]; h.Close[]; anonNo _ anonNo+1; GOTO UseWindow; END; SELECT dir FROM in, both => BEGIN mFile.in _ FS.StreamOpen[name, $write ! FS.Error => IF error.group=user THEN GOTO UseWindow]; mFile.out _ nilStream; <<--following code commented out due to laziness of Cedar 5.0 converter:>> <> <> <> <<[in: mFile.inSource, out: mFile.outDest] _>> <> <> <> <> END; ENDCASE => -- out -- BEGIN mFile.out _ FS.StreamOpen[name, $create ! FS.Error => IF error.group=user THEN GOTO UseWindow]; mFile.in _ nilStream; <<--following code commented out due to laziness of Cedar 5.0 converter:>> <> <> <> <<[in: mFile.inSource, out: mFile.outDest] _>> <> <> <> <> END; END; EXITS UseWindow => BEGIN [in: mFile.in, out: mFile.out] _ ViewerIO.CreateViewerStreams[name: name]; END; END; END; -- of PascalAttachFile PrepareForRead: UNSAFE PROCEDURE [file: PascalFilePtr] = TRUSTED BEGIN IF file^ = NIL OR file^.in = NIL THEN PascalAttachFile[file: file, dir: in, type: binary]; END; PrepareForWrite: UNSAFE PROCEDURE [file: PascalFilePtr] = TRUSTED BEGIN IF file^ = NIL OR file^.out = NIL THEN PascalAttachFile[file: file, dir: out, type: binary]; END; <> NilGetChar: PROCEDURE [self: IO.STREAM] RETURNS [CHARACTER] = BEGIN ERROR IO.EndOfStream[self]; END; NilPutChar: PROCEDURE [self: IO.STREAM, char: CHARACTER] = {NULL}; NilEndOf: PROCEDURE [self: IO.STREAM] RETURNS [BOOLEAN] = {RETURN[TRUE]}; NilUnsafeGetBlock: PROCEDURE [self: IO.STREAM, block: IO.UnsafeBlock] RETURNS [INT] = {RETURN[0]}; NilUnsafePutBlock: PROCEDURE [self: IO.STREAM, block: IO.UnsafeBlock] = {NULL}; NilClose: PROCEDURE[self: IO.STREAM, abort: BOOLEAN _ FALSE] = {NULL}; <> Input _ PascalTextFile[baseFile: PascalInventFileName[name: "PascalInput"]]; Output _ PascalTextFile[baseFile: PascalInventFileName[name: "PascalOutput"]]; Tty _ PascalTextFile[baseFile: PascalInventFileName[name: "Tty"]]; Control _ PascalTextFile[baseFile: PascalInventFileName[name: "PascalControl"]]; TRUSTED {[in: Control.baseFile.in, out: Control.baseFile.out] _ ViewerIO.CreateViewerStreams[name: "PascalControl"]}; anonNo _ ttyNo _ 0; TRUSTED { PascalWriteString[file: @Control, item: "Pascal Cedar Runtime of May 9, 1985"]; PascalWriteLn[file: @Control]}; END. -- PascalNoviceFilesImpl