TJaMStreamImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, 7-Oct-81 17:14:51
Russ Atkinson, July 22, 1983 7:18 pm
Michael Plass, February 14, 1985 12:57:19 pm PST
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 = {
Types and Constants
streamMax: CARDINAL = 10;
StreamEntry: TYPE = RECORD[index: CARDINAL, handle: TJaMStreamDefs.StreamHandle];
StreamTable: TYPE = ARRAY[0..streamMax) OF StreamEntry;
Globals
zone: UNCOUNTED ZONE = TJaMStorage.Zone[];
streamLen: CARDINAL ← 0;
streamIndex: CARDINAL ← 0; -- next stream index
streams: LONG POINTER TO StreamTable;
deadstream,badname: name TJaMBasic.Object;
Streams
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 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 TJaMOps.Error[TJaMOps.limitchk]; -- *** fix this?
RETURN[[tag,stream[index: i, stamp: TJaMOps.root.stamp]]];
};
GetStream: PUBLIC PROC[ob: stream TJaMBasic.Object] RETURNS[TJaMStreamDefs.StreamHandle] = {
Get: ENTRY PROC[index: CARDINAL] RETURNS[TJaMStreamDefs.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: TJaMStreamDefs.StreamHandle ← NIL;
IF ob.stamp=TJaMOps.root.stamp THEN s ← Get[ob.index];
IF s=NIL THEN ERROR TJaMOps.Error[deadstream] ELSE RETURN[s];
};
KillStream: PUBLIC PROC[ob: stream TJaMBasic.Object] = {
Kill: ENTRY PROC[index: CARDINAL] RETURNS[TJaMStreamDefs.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: TJaMStreamDefs.StreamHandle ← NIL;
IF ob.stamp=TJaMOps.root.stamp THEN s ← Kill[ob.index];
IF s#NIL THEN s.destroy[s];
};
PBData: TYPE = LONG POINTER TO PBDataRecord;
PBDataRecord: TYPE = RECORD[handle: TJaMStreamDefs.StreamHandle, back: BOOLEAN, item: UNSPECIFIED];
MakeFileStream: PROC[string: string TJaMBasic.Object, access: TJaMStreamDefs.AccessOptions,
items: {bytes,words}] RETURNS[stream TJaMBasic.Object] = {
name: STRING ← [100];
s: TJaMStreamDefs.StreamHandle ← NIL;
IF string.length>name.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];
};
Intrinsics
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: BOOLEANNOT 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: BOOLEANFALSE; 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];
};
Initialization
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];
}.