-- JaMStreamImpl.mesa -- Last changed by Doug Wyatt, 7-Oct-81 17:14:51 DIRECTORY JaMBasic USING [Object, Root, Tag], JaMInternal USING [Frame], JaMOps, JaMStorage, Ascii USING [CR], Inline USING [BITAND, LowHalf], StreamDefs; JaMStreamImpl: MONITOR IMPORTS JaMOps, JaMStorage, Inline, StreamDefs EXPORTS JaMOps = { OPEN StreamDefs, JaMStorage, JaMOps, JaMInternal, JaMBasic; -- Types and Constants streamMax: CARDINAL = 10; StreamEntry: TYPE = RECORD[index: CARDINAL, handle: StreamHandle]; StreamTable: TYPE = ARRAY[0..streamMax) OF StreamEntry; -- Globals zone: UNCOUNTED ZONE = JaMStorage.Zone[]; streamLen: CARDINAL ← 0; streamIndex: CARDINAL ← 0; -- next stream index streams: LONG POINTER TO StreamTable; deadstream,badname: name Object; -- Streams MakeStream: PUBLIC PROC[s: StreamHandle, tag: Tag] RETURNS[stream Object] = { New: ENTRY PROC[s: StreamHandle] RETURNS[CARDINAL] = INLINE { i: CARDINAL ← 0; IF streamLen<streamMax THEN { streamIndex ← streamIndex + 1; i ← streamIndex; streams[streamLen] ← [i,s]; streamLen ← streamLen + 1 }; RETURN[i]; }; i: CARDINAL ← New[s]; IF i=0 THEN ERROR Error[limitchk]; -- *** fix this? RETURN[[tag,stream[index: i, stamp: root.stamp]]]; }; GetStream: PUBLIC PROC[ob: stream Object] RETURNS[StreamHandle] = { Get: ENTRY PROC[index: CARDINAL] RETURNS[StreamHandle] = INLINE { FOR i: CARDINAL DECREASING IN[0..streamLen) DO entry: StreamEntry ← streams[i]; IF entry.index=index THEN RETURN[entry.handle]; ENDLOOP; RETURN[NIL]; }; s: StreamHandle ← NIL; IF ob.stamp=root.stamp THEN s ← Get[ob.index]; IF s=NIL THEN ERROR Error[deadstream] ELSE RETURN[s]; }; KillStream: PUBLIC PROC[ob: stream Object] = { Kill: ENTRY PROC[index: CARDINAL] RETURNS[StreamHandle] = { FOR i: CARDINAL DECREASING IN[0..streamLen) DO entry: StreamEntry ← streams[i]; IF entry.index=index THEN { streamLen ← streamLen - 1; FOR j: CARDINAL IN[i..streamLen) DO streams[j] ← streams[j+1] ENDLOOP; streams[streamLen] ← [0,NIL]; RETURN[entry.handle] }; ENDLOOP; RETURN[NIL]; }; s: StreamHandle ← NIL; IF ob.stamp=root.stamp THEN s ← Kill[ob.index]; IF s#NIL THEN s.destroy[s]; }; PBData: TYPE = LONG POINTER TO PBDataRecord; PBDataRecord: TYPE = RECORD[handle: StreamHandle, back: BOOLEAN, item: UNSPECIFIED]; MakeFileStream: PROC[string: string Object, access: AccessOptions, items: {bytes,words}] RETURNS[stream Object] = { name: STRING ← [100]; s: StreamHandle ← NIL; IF string.length>name.maxlength THEN GOTO BadName; StringText[string,name]; s ← (SELECT items FROM bytes => NewByteStream, words => NewWordStream, ENDCASE => ERROR)[name,access ! FileNameError => GOTO BadName]; IF Inline.BITAND[access,Read]#0 THEN s ← NewStreamWithPutback[s]; RETURN[MakeStream[s,L]]; EXITS BadName => ERROR Error[badname]; }; NewStreamWithPutback: PROC[f: StreamHandle] RETURNS[StreamHandle] = { d: PBData ← zone.NEW[PBDataRecord ← [handle: f, back: FALSE, item: 0]]; s: StreamHandle ← zone.NEW[StreamObject ← [reset: PBReset, get: PBGet, putback: PBPutback, endof: PBEndof, put: PBPut, destroy: PBDestroy, data: d]]; RETURN[s]; }; PBReset: PROC[s: StreamHandle] = { d: PBData ← s.data; f: StreamHandle ← d.handle; f.reset[f]; }; PBGet: PROC[s: StreamHandle] RETURNS[UNSPECIFIED] = { d: PBData ← s.data; item: UNSPECIFIED; IF d.back THEN { item ← d.item; d.back ← FALSE } ELSE { f: StreamHandle ← d.handle; item ← f.get[f] }; RETURN[item]; }; PBPutback: PROC[s: StreamHandle, item: UNSPECIFIED] = { d: PBData ← s.data; d.item ← item; d.back ← TRUE; }; PBEndof: PROC[s: StreamHandle] RETURNS[BOOLEAN] = { d: PBData ← s.data; IF d.back THEN RETURN[FALSE] ELSE { f: StreamHandle ← d.handle; RETURN[f.endof[f]] }; }; PBPut: PROC[s: StreamHandle, item: UNSPECIFIED] = { d: PBData ← s.data; f: StreamHandle ← d.handle; f.put[f,item]; }; PBDestroy: PROC[s: StreamHandle] = { d: PBData ← s.data; f: StreamHandle ← d.handle; f.destroy[f]; zone.FREE[@d]; zone.FREE[@s]; }; -- Intrinsics JRun: PROC[frame: Frame] = { string: string Object ← PopString[frame.opstk]; stream: stream Object ← MakeFileStream[string,Read,bytes]; stream.tag ← X; Execute[frame,stream]; }; JByteStream: PROC[frame: Frame] = { access: AccessOptions ← PopCardinal[frame.opstk]; string: string Object ← PopString[frame.opstk]; stream: stream Object ← MakeFileStream[string,access,bytes]; Push[frame.opstk,stream]; }; JWordStream: PROC[frame: Frame] = { access: AccessOptions ← PopCardinal[frame.opstk]; string: string Object ← PopString[frame.opstk]; stream: stream Object ← MakeFileStream[string,access,words]; Push[frame.opstk,stream]; }; JReadItem: PROC[frame: Frame] = { stream: stream Object ← PopStream[frame.opstk]; s: StreamHandle ← GetStream[stream]; ok: BOOLEAN ← NOT s.endof[s]; IF ok THEN { item: INTEGER ← s.get[s]; PushInteger[frame.opstk,item] } ELSE KillStream[stream]; PushBoolean[frame.opstk,ok]; }; JWriteItem: PROC[frame: Frame] = { item: LONG INTEGER ← PopInteger[frame.opstk]; stream: stream Object ← PopStream[frame.opstk]; s: StreamHandle ← GetStream[stream]; s.put[s,Inline.LowHalf[item]]; }; JReadLine: PROC[frame: Frame] = { stream: stream Object ← PopStream[frame.opstk]; s: StreamHandle ← GetStream[stream]; localline: STRING ← [256]; line: TextObject ← TextNew[localline]; found: BOOLEAN ← FALSE; string: string Object; { ENABLE UNWIND => TextFree[@line]; UNTIL s.endof[s] DO c: CHARACTER ← s.get[s]; TextPut[@line,c]; found ← TRUE; IF c=Ascii.CR THEN EXIT; ENDLOOP; IF found THEN string ← MakeString[TextRead[@line]]; }; TextFree[@line]; IF found THEN Push[frame.opstk,string] ELSE KillStream[stream]; PushBoolean[frame.opstk,found]; }; JWriteBytes: PROC[frame: Frame] = { string: string Object ← PopString[frame.opstk]; stream: stream Object ← PopStream[frame.opstk]; s: StreamHandle ← GetStream[stream]; Put: PROC[c: CHARACTER] RETURNS[BOOLEAN] = { s.put[s,c]; RETURN[FALSE] }; StringForAll[string,Put]; }; JKillStream: PROC[frame: Frame] = { stream: stream Object ← PopStream[frame.opstk]; KillStream[stream]; }; -- Initialization InstallStream: PROC[why: InstallReason, frame: Frame] = { SELECT why FROM init => { streams ← zone.NEW[StreamTable ← ALL[[0,NIL]]]; streamLen ← 0; streamIndex ← 0; }; free => { zone.FREE[@streams]; }; register => { deadstream ← MakeName[".deadstream"L]; badname ← MakeName[".badname"L]; RegisterExplicit[frame,".run"L,JRun]; RegisterExplicit[frame,".bytestream"L,JByteStream]; RegisterExplicit[frame,".wordstream"L,JWordStream]; RegisterExplicit[frame,".readitem"L,JReadItem]; RegisterExplicit[frame,".writeitem"L,JWriteItem]; RegisterExplicit[frame,".readline"L,JReadLine]; RegisterExplicit[frame,".writebytes"L,JWriteBytes]; RegisterExplicit[frame,".killstream"L,JKillStream]; }; ENDCASE; }; Install[InstallStream]; }.