<> <> <> <> <> <<>> DIRECTORY Ascii USING [CR], Basics USING [BITAND, LowHalf], TJaMBasic USING [Object, Root, Tag], TJaMInternal USING [Frame], TJaMOps, TJaMStorage, TJaMStreamDefs; TJaMStreamImpl: MONITOR IMPORTS TJaMOps, TJaMStorage, Basics, TJaMStreamDefs EXPORTS TJaMOps = { <> streamMax: CARDINAL = 10; StreamEntry: TYPE = RECORD[index: CARDINAL, handle: TJaMStreamDefs.StreamHandle]; StreamTable: TYPE = ARRAY[0..streamMax) OF StreamEntry; <> zone: UNCOUNTED ZONE = TJaMStorage.Zone[]; streamLen: CARDINAL _ 0; streamIndex: CARDINAL _ 0; -- next stream index streams: LONG POINTER TO StreamTable; deadstream,badname: name TJaMBasic.Object; <> MakeStream: PUBLIC PROC[s: TJaMStreamDefs.StreamHandle, tag: TJaMBasic.Tag] RETURNS[stream TJaMBasic.Object] = { New: ENTRY PROC[s: TJaMStreamDefs.StreamHandle] RETURNS[CARDINAL] = INLINE { i: CARDINAL _ 0; IF streamLenname.maxlength THEN GOTO BadName; TJaMOps.StringText[string,name]; s _ (SELECT items FROM bytes => TJaMStreamDefs.NewByteStream, words => TJaMStreamDefs.NewWordStream, ENDCASE => ERROR)[name,access ! TJaMStreamDefs.FileNameError => GOTO BadName]; IF Basics.BITAND[access,TJaMStreamDefs.Read]#0 THEN s _ NewStreamWithPutback[s]; RETURN[MakeStream[s,L]]; EXITS BadName => ERROR TJaMOps.Error[badname]; }; NewStreamWithPutback: PROC[f: TJaMStreamDefs.StreamHandle] RETURNS[TJaMStreamDefs.StreamHandle] = { d: PBData _ zone.NEW[PBDataRecord _ [handle: f, back: FALSE, item: 0]]; s: TJaMStreamDefs.StreamHandle _ zone.NEW[TJaMStreamDefs.StreamObject _ [reset: PBReset, get: PBGet, putback: PBPutback, endof: PBEndof, put: PBPut, destroy: PBDestroy, data: d]]; RETURN[s]; }; PBReset: PROC[s: TJaMStreamDefs.StreamHandle] = { d: PBData _ s.data; f: TJaMStreamDefs.StreamHandle _ d.handle; f.reset[f]; }; PBGet: PROC[s: TJaMStreamDefs.StreamHandle] RETURNS[UNSPECIFIED] = { d: PBData _ s.data; item: UNSPECIFIED; IF d.back THEN { item _ d.item; d.back _ FALSE } ELSE { f: TJaMStreamDefs.StreamHandle _ d.handle; item _ f.get[f] }; RETURN[item]; }; PBPutback: PROC[s: TJaMStreamDefs.StreamHandle, item: UNSPECIFIED] = { d: PBData _ s.data; d.item _ item; d.back _ TRUE; }; PBEndof: PROC[s: TJaMStreamDefs.StreamHandle] RETURNS[BOOLEAN] = { d: PBData _ s.data; IF d.back THEN RETURN[FALSE] ELSE { f: TJaMStreamDefs.StreamHandle _ d.handle; RETURN[f.endof[f]] }; }; PBPut: PROC[s: TJaMStreamDefs.StreamHandle, item: UNSPECIFIED] = { d: PBData _ s.data; f: TJaMStreamDefs.StreamHandle _ d.handle; f.put[f,item]; }; PBDestroy: PROC[s: TJaMStreamDefs.StreamHandle] = { d: PBData _ s.data; f: TJaMStreamDefs.StreamHandle _ d.handle; f.destroy[f]; zone.FREE[@d]; zone.FREE[@s]; }; <> JRun: PROC[frame: TJaMInternal.Frame] = { string: string TJaMBasic.Object _ TJaMOps.PopString[frame.opstk]; stream: stream TJaMBasic.Object _ MakeFileStream[string,TJaMStreamDefs.Read,bytes]; stream.tag _ X; TJaMOps.Execute[frame,stream]; }; JByteStream: PROC[frame: TJaMInternal.Frame] = { access: TJaMStreamDefs.AccessOptions _ TJaMOps.PopCardinal[frame.opstk]; string: string TJaMBasic.Object _ TJaMOps.PopString[frame.opstk]; stream: stream TJaMBasic.Object _ MakeFileStream[string,access,bytes]; TJaMOps.Push[frame.opstk,stream]; }; JWordStream: PROC[frame: TJaMInternal.Frame] = { access: TJaMStreamDefs.AccessOptions _ TJaMOps.PopCardinal[frame.opstk]; string: string TJaMBasic.Object _ TJaMOps.PopString[frame.opstk]; stream: stream TJaMBasic.Object _ MakeFileStream[string,access,words]; TJaMOps.Push[frame.opstk,stream]; }; JReadItem: PROC[frame: TJaMInternal.Frame] = { stream: stream TJaMBasic.Object _ TJaMOps.PopStream[frame.opstk]; s: TJaMStreamDefs.StreamHandle _ GetStream[stream]; ok: BOOLEAN _ NOT s.endof[s]; IF ok THEN { item: INTEGER _ s.get[s]; TJaMOps.PushInteger[frame.opstk,item] } ELSE KillStream[stream]; TJaMOps.PushBoolean[frame.opstk,ok]; }; JWriteItem: PROC[frame: TJaMInternal.Frame] = { item: LONG INTEGER _ TJaMOps.PopInteger[frame.opstk]; stream: stream TJaMBasic.Object _ TJaMOps.PopStream[frame.opstk]; s: TJaMStreamDefs.StreamHandle _ GetStream[stream]; s.put[s,Basics.LowHalf[item]]; }; JReadLine: PROC[frame: TJaMInternal.Frame] = { stream: stream TJaMBasic.Object _ TJaMOps.PopStream[frame.opstk]; s: TJaMStreamDefs.StreamHandle _ GetStream[stream]; localline: STRING _ [256]; line: TJaMStorage.TextObject _ TJaMStorage.TextNew[localline]; found: BOOLEAN _ FALSE; string: string TJaMBasic.Object; { ENABLE UNWIND => TJaMStorage.TextFree[@line]; UNTIL s.endof[s] DO c: CHARACTER _ s.get[s]; TJaMStorage.TextPut[@line,c]; found _ TRUE; IF c=Ascii.CR THEN EXIT; ENDLOOP; IF found THEN string _ TJaMOps.MakeString[TJaMStorage.TextRead[@line]]; }; TJaMStorage.TextFree[@line]; IF found THEN TJaMOps.Push[frame.opstk,string] ELSE KillStream[stream]; TJaMOps.PushBoolean[frame.opstk,found]; }; JWriteBytes: PROC[frame: TJaMInternal.Frame] = { string: string TJaMBasic.Object _ TJaMOps.PopString[frame.opstk]; stream: stream TJaMBasic.Object _ TJaMOps.PopStream[frame.opstk]; s: TJaMStreamDefs.StreamHandle _ GetStream[stream]; Put: PROC[c: CHARACTER] RETURNS[BOOLEAN] = { s.put[s,c]; RETURN[FALSE] }; TJaMOps.StringForAll[string,Put]; }; JKillStream: PROC[frame: TJaMInternal.Frame] = { stream: stream TJaMBasic.Object _ TJaMOps.PopStream[frame.opstk]; KillStream[stream]; }; <> InstallStream: PROC[why: TJaMOps.InstallReason, frame: TJaMInternal.Frame] = { SELECT why FROM init => { streams _ zone.NEW[StreamTable _ ALL[[0,NIL]]]; streamLen _ 0; streamIndex _ 0; }; free => { zone.FREE[@streams]; }; register => { deadstream _ TJaMOps.MakeName[".deadstream"L]; badname _ TJaMOps.MakeName[".badname"L]; TJaMOps.RegisterExplicit[frame,".run"L,JRun]; TJaMOps.RegisterExplicit[frame,".bytestream"L,JByteStream]; TJaMOps.RegisterExplicit[frame,".wordstream"L,JWordStream]; TJaMOps.RegisterExplicit[frame,".readitem"L,JReadItem]; TJaMOps.RegisterExplicit[frame,".writeitem"L,JWriteItem]; TJaMOps.RegisterExplicit[frame,".readline"L,JReadLine]; TJaMOps.RegisterExplicit[frame,".writebytes"L,JWriteBytes]; TJaMOps.RegisterExplicit[frame,".killstream"L,JKillStream]; }; ENDCASE; }; TJaMOps.Install[InstallStream]; }.