-- PDRemoteStreamImpl.mesa -- Copyright (C) 1984, Xerox Corporation. All rights reserved. -- Michael Plass, September 11, 1984 4:00:48 pm PDT -- DIRECTORY IO, Stream, STP, Rope, PDRemoteStream, String; PDRemoteStreamImpl: PROGRAM IMPORTS Rope, STP, String, Stream EXPORTS PDRemoteStream = BEGIN Error: PUBLIC ERROR [expl: LONG STRING, retryable: BOOL] = CODE; RopeFromString: PROC [string: LONG STRING] RETURNS [Rope.ROPE] = { i: INTEGER ← -1; fet: SAFE PROC RETURNS [CHAR] = TRUSTED {RETURN [string[i←i+1]]}; IF string = NIL THEN RETURN [NIL]; RETURN [Rope.FromProc[string.length, fet]]; }; Rs: PROC [string: LONG STRING] RETURNS [Rope.ROPE] = RopeFromString; AppendRope: PROC [string: LONG STRING, rope: Rope.ROPE] = { action: Rope.ActionType = TRUSTED { string[string.length] ← c; string.length ← string.length + 1; }; [] ← rope.Map[action: action]; }; Retryable: PROC [code: STP.ErrorCode] RETURNS [BOOL] = { RETURN [SELECT code FROM connectionTimedOut, connectionRejected, connectionClosed, noConnection, noNameLookupResponse => TRUE, ENDCASE => FALSE] }; Lookup: PUBLIC PROC [fileName: LONG STRING, createDate: LONG STRING, name, password: LONG STRING] RETURNS [bytes: INT] = { bytes ← MyLookup[fileName, createDate, name, password ! STP.Error => TRUSTED { expl: LONG STRING ← [80]; AppendRope[expl, error]; ERROR Error[expl: expl, retryable: Retryable[code]] }; ]; }; ParseTest: PROC [fileName: Rope.ROPE] RETURNS [server, rest: Rope.ROPE] = { f: LONG STRING ← [80]; s: LONG STRING ← [80]; r: LONG STRING ← [80]; AppendRope[f, fileName]; ParseName[f, s, r]; server ← Rs[s]; rest ← Rs[r]; }; ParseName: PUBLIC PROC [fileName, server, rest: LONG STRING] = { state: NAT ← 0; server.length ← 0; rest.length ← 0; FOR i: NAT IN [0..fileName.length) DO c: CHAR ← fileName[i]; charType: NAT ← SELECT c FROM '[ => 0, '/ => 1, '] => 2, '< => 3, '> => 4, '! => 5, IN ['0..'9], IN ['a..'z], IN ['A..'Z] => 6, '-, '+, '$, '., '' => 6 ENDCASE => Error[expl: "Illegal character in filename", retryable: FALSE]; SELECT state*7+charType FROM 0*7+0 => state ← 1; 0*7+1 => state ← 7; 1*7+6 => {server[server.length] ← c; server.length ← server.length + 1}; 1*7+2 => state ← 2; 2*7+3 => {state ← 3; rest[rest.length] ← '<; rest.length ← rest.length + 1}; 3*7+6, 3*7+4 => {rest[rest.length] ← c; rest.length ← rest.length + 1}; 3*7+5 => {state ← 4; rest[rest.length] ← c; rest.length ← rest.length + 1}; 4*7+6 => { rest[rest.length] ← c; rest.length ← rest.length + 1; IF c IN ['0..'9] THEN state ← 5 ELSE IF c = 'l OR c = 'L OR c = 'h OR c='H THEN state ← 6 ELSE state ← 9 }; 5*7+6 => { rest[rest.length] ← c; rest.length ← rest.length + 1; IF c NOT IN ['0..'9] THEN state ← 9 }; 7*7+6 => {server[server.length] ← c; server.length ← server.length + 1}; 7*7+1 => {state ← 8; rest[rest.length] ← '<; rest.length ← rest.length + 1}; 7*8+6 => {rest[rest.length] ← c; rest.length ← rest.length + 1}; 7*8+1 => {rest[rest.length] ← '>; rest.length ← rest.length + 1}; 7*8+5 => {state ← 4; rest[rest.length] ← c; rest.length ← rest.length + 1}; ENDCASE => Error[expl: "Illegal filename", retryable: FALSE]; ENDLOOP; SELECT state FROM 3, 8 => {rest[rest.length] ← '!; rest[rest.length+1] ← 'H; rest.length ← rest.length + 2}; 5, 6 => NULL; ENDCASE => Error[expl: "Illegal filename", retryable: FALSE]; }; MyLookup: PROC [fileName, createDate, name, password: LONG STRING] RETURNS [bytes: INT ← 0] = { server: LONG STRING ← [80]; rest: LONG STRING ← [80]; stp: STP.Handle ← STP.Create[]; open: BOOL ← FALSE; BEGIN ENABLE UNWIND => { -- IF open THEN stp.Close[ ! STP.Error => TRUSTED {CONTINUE}]; -- stp ← stp.Destroy }; expandedName: LONG STRING ← [80]; success: BOOLEAN ← FALSE; NoteFileProc: STP.NoteFileProcType = TRUSTED { fileInfo: STP.FileInfo ← stp.GetFileInfo[]; continue ← no; success ← TRUE; AppendRope[expandedName, file]; bytes ← fileInfo.size; createDate.length ← 0; AppendRope[createDate, fileInfo.create]; }; desiredProps: STP.DesiredProperties ← ALL[FALSE]; desiredProps[directory] ← TRUE; desiredProps[nameBody] ← TRUE; desiredProps[version] ← TRUE; desiredProps[createDate] ← TRUE; desiredProps[size] ← TRUE; ParseName[fileName, server, rest]; String.AppendChar[expandedName, '[ ]; String.AppendString[expandedName, server]; String.AppendChar[expandedName, '] ]; [] ← stp.Open[Rs[server]]; open ← TRUE; stp.Login[Rs[name], Rs[password]]; stp.SetDesiredProperties[desiredProps]; stp.Enumerate[Rs[rest], NoteFileProc]; stp.Close[ ! STP.Error => TRUSTED {CONTINUE}]; -- stp ← stp.Destroy; IF success THEN {String.Copy[to: fileName, from: expandedName]} ELSE Error[expl: "File not found", retryable: FALSE]; END; }; Read: PUBLIC PROC [fileName: LONG STRING, name, password: LONG STRING, action: PROC[Stream.Handle]] = { MyRead[fileName, name, password, action ! STP.Error => TRUSTED { expl: LONG STRING ← [80]; AppendRope[expl, error]; ERROR Error[expl: expl, retryable: Retryable[code]] }; ]; }; MyRead: PROC [fileName: LONG STRING, name, password: LONG STRING, action: PROC[Stream.Handle]] = { server: LONG STRING ← [80]; rest: LONG STRING ← [80]; stp: STP.Handle ← STP.Create[]; open: BOOL ← FALSE; stream: Stream.Handle; BEGIN ENABLE UNWIND => { -- IF open THEN stp.Close[ ! STP.Error => TRUSTED {CONTINUE}]; -- stp ← stp.Destroy IF stream # NIL THEN {stream.Delete; stream ← NIL}; }; ParseName[fileName, server, rest]; [] ← stp.Open[Rs[server]]; open ← TRUE; stp.Login[Rs[name], Rs[password]]; stream ← Stream.FromIOStreams[stp.CreateRemoteStream[Rs[rest], read], NIL]; action[stream]; stp.Close[ ! STP.Error => TRUSTED {CONTINUE}]; -- stp ← stp.Destroy; stream.Delete; stream ← NIL END; }; END.